Change filename of attachments on Coldfusion - coldfusion

I'm using cfmailparam to attach files to an email. I'm getting the filenames and paths from my database. Normally, the attached files have unique names, but I can get their original filenames by querying the following columns in a database table:
ASSET_FILE_NAME: unique name
ASSET_REAL_NAME: original_name_before_upload.pdf
When I send the e-mail with cfmail, the attachments still use the unique names, but I really need to rename them. I've searched and tried also:
<cfloop from="1" to="#assetfiles.RecordCount#" index="i">
<cfmailparam
file="C:\files\#assetfiles.ASSET_FILE_NAME[i]#"
type="application/pdf"
disposition="attachment; filename=""#assetfiles.ASSET_REAL_NAME[i]#"""
/>
</cfloop>
But this is not working for all attachment files. It changes just 1 filename and the other ones still use the unique names.
Is there anyway to make this possible?

There are a few ways you could do this
You could rename the files themselves
Create duplicates and then use the remove="true" attribute of cfmailparam
Read the files with the odd names and attach them with a new name <cfmailparam file="niceName.pdf" content="#fileRead(oddName.pdf)#">

Related

Duplicate filenames when writing files in ColdFusion

I am trying to fix some code for a client. The issue is, we have .CSV files that are being written in ColdFusion but duplicates are constantly being generated for some reason, even with nameConflict = "Overwrite" in there. I am seeing that nameConflict may not even work with cffile action="write", how could I add maybe just an ascending number to the end of a duplicate file name every time it is generated? The CSV files simply show customer renewal information.
<cfif arguments.isRenewal EQ "Y">
<cffile action="write" file="#filename#" nameconflict="overwrite" output='"Capital","#custName#","","#getCustomer.fname#","#getCustomer.lname#","#getCustomer.serviceAddress1#","#getCustomer.serviceAddress2#","#getCustomer.serviceCity#","#getCustomer.serviceState#","#getCustomer.serviceZip#","#cleanPhone#","#cleanMobilePhone#","#getCustomer.email#","#getCustomer.billingAddress1#","#getCustomer.billingAddress2#","#getCustomer.billingCity#","#getCustomer.billingState#","#getCustomer.billingZip#","0","N/A","Electric","#getCustomer.sdi#","#getCustomer.sdi#","#getProvider.utilityCode#","#getOffer.rateSchedule#","#getOffer.productCode#","#getOffer.rate/100#","kWh","$","#getOffer.rackRateName#","#DateFormat(now(), "yyyy-mm-dd")#","#startDate#","#getOffer.term#","Internet","","","","","","","","","","","","","M2M","#getOffer.evergreenProduct#","Y"'>
<cfelse>
<cffile action="write" file="#filename#" nameconflict="overwrite" output='"Capital","#custName#","","#getCustomer.fname#","#getCustomer.lname#","#getCustomer.serviceAddress1#","#getCustomer.serviceAddress2#","#getCustomer.serviceCity#","#getCustomer.serviceState#","#getCustomer.serviceZip#","#cleanPhone#","#cleanMobilePhone#","#getCustomer.email#","#getCustomer.billingAddress1#","#getCustomer.billingAddress2#","#getCustomer.billingCity#","#getCustomer.billingState#","#getCustomer.billingZip#","0","N/A","Electric","#getCustomer.sdi#","#getCustomer.sdi#","#getProvider.utilityCode#","#getOffer.rateSchedule#","#getOffer.productCode#","#getOffer.rate/100#","kWh","$","#getOffer.rackRateName#","#DateFormat(now(), "yyyy-mm-dd")#","#startDate#","#getOffer.term#","Internet","","","","","","","","","","","","","M2M","#getOffer.evergreenProduct#","N"'>
duplicates snapshot

Duplicating and Renaming a file and storing name in Database

I have a register page that asks for information like employee_number, user_name, user_pass, firstname, lastname, position, email, phone_extension, department, picture. Once they fill this information out and they hit register it all gets uploaded into a database.
Is it possible to have it create a profile page specific to that user based on the information in the database?
For example, if I registered to have it create DavidBriertonProfile.cfm from my template Profile.cfm and have it add DavidBriertonProfile.cfm in the database so I can use that name to reference later. But is it possible to take my template Profile.cfm and rename it based on there name and have it added to profiles/(TherenameProfile).cfm
I have been playing with cffile in order to create a path but I need it to be behind the scenes selecting my template file where the user never sees any of this.
<cffile
action = "upload"
file = "#expandPath("/webapps/dash/profiles/profile.cfm")#"
destination = "#expandPath("/webapps/dash/profiles/")#"
nameConflict = "MakeUnique"
result = "myfile"
/>
There are two primary options
Create a static file from a coldfusion template...
<cfsavecontent variable="filecontent">
<cfinclude template="profile.cfm" />
</cfsavecontent>
<cffile action="write" file="profiles/#FirstNameLastName#Profile.html" output="#filecontent#" />
<!--- it looks like the "nameconflict" option is only available for upload action so will have to deal with that --->
Create a file just for setting the userid and including profile.cfm
<cffile action="write"
file="profiles/#FirstNameLastName#.cfm"
output="<cfset userid ='#UserID' /><cfinclude template='../profile.cfm' />"
/>
Some other options include
Save the name of the unique cfm file you would create (ex: DavidSmith12Profile) but don't actually create it and instead use the OnMissingTemplate function in Application.cfc to take the name supplied and perform a database lookup and then show the profile result
Peform a URL rewrite on the webserver to transform any request to paths of format /profiles/(.+) to /profile.cfm?filename={\1} and then do a database lookup by the filename directly in profile.cfm
enjoy

How to add attributes ColdFusion tags in bulk

I was curious if there is a way to force a ColdFusion tag to hold an attribute as default, such as the datasource in cfquery.
For example instead of writing
<cfquery datasource="mydatasource">
I can write
<cfquery>
and the system automatically knows that the datasource is "mydatasource".
Would be really cool if this was possible.
It is actually possible for datasource, but not for everything.
You may set a this.datasource="mydatasource" as the default datasource in your Application.cfc
https://wikidocs.adobe.com/wiki/display/coldfusionen/Application+variables
The practical answer to your question are the custom tags. You can extend the features of ColdFusion tags to match your needs.
Taking into example the cfquery tag and wrapping a custom tag around it. Provide all the default values you want for the parameters of the cfquery into the tag's attribute default.
So essentially your custom tag page would be something like:
flexiquery.cfm
<cfif THISTAG.ExecutionMode EQ 'end'>
<cfparam name="Attributes.datasource" default="someDSN">
<cfparam name="Attributes.cacheWithin" default="#CreateTimeSpan(0,6,0,0)#">
<cfparam name="Attributes.maxRows" default="25">
<cfparam name="Attributes.timeOut" default="600">
<!--- some logic you want to perform --->
<cfquery datasource="#Attributes.datasource#"
cacheWithin="#Attributes.cacheWithin#"
maxRow="#Attributes.maxRows#"
timeOut="#Attributes.timeOut#"
<cfoutput>#THISTAG.GeneratedContent#</cfoutput>
</cfquery>
<!--- Caller assignment and other processing --->
</cfif>
And now you can use it and re-use it across your project, the way you wanted and even overriding the value you want to be different:
<cf_flexiquery>
<!--- you query here --->
</cf_flexiquery>
or
<cf_flexiquery maxRows="100" timeOut="1200">
<!--- you query here --->
</cf_flexiquery>
It gives you a fair idea of how to go with it. I have extended the custom tags features to leverage the features of cfhttp, cfpdf, cffile etc.
This is only way you can adopt the flexibility you want with ColdFusion tags and it works perfectly.

Pass queried parameters to ColdFusion file multiple times?

I have an cfmail function set-up in a particular file, email_output.cfm, which requires an ID passed to it to work properly, like email_output.cfm?ID=1. I want to set up a cron job that runs through a query returning the various needed IDs to pass. In testing, I can do the following:
<cflocation url="email_output.cfm?ID=10" >
But, since cflocation stops all other execution and opens another page, I can't loop through it. How would I pass parameters from a query to a single CF page multiple times?
Thanks - Joe
A custom tag sample implementation of this...
If this is your first time using a custom tag, it's easiest to put it in the same folder as the page calling it. There are a few options for putting it in a different directory, but let's start simple.
EmailMembers.cfm
<cfquery name="GetUIDs">
select userid from users
</cfquery>
<cfoutput query="GetUIDs">
<cf_maileach uid="#userID#">
</cfoutput>
Notice how I called my tag cf_maileach?
In the same directory, place maileach.cfm, see how the names match?
maileach.cfm
<cfif StructKeyExists(attributes,"uid") and val(attributes.uid) gt 0>
<cfquery name="getinfo">
select fname,lname,email
from users
where userID = <cfqueryparam cfsqltype="cf_sql_integer" value="#attributes.uid#">
</cfquery>
<cfmail to="#getinfo.email#" subject="Hi #getinfo.fname#">...</cfmail>
</cfif>
Notes
Depending on your version of cf, and whether you're using application.cfc or not, there are several ways to place a custom tag in an outside directory. There is also <cfmodule>
This is a sample only, something this basic is redundant, I was just trying to mimic what asker outlined. In this sample, I'm calling a query that could get all the data, only to use it to query row by row.
If you're not familiar with <cfqueryparam>, look it up, use it, love it.
Edit: While a CFHTTP method can serve this purpose, it suffers a few problems
Sessions are not automatically passed (even if the requesting server and destination server are the same.).
The page is accessed like a browser request. Application/OnRequestEnd are processed (and since session info is passed as well, this can cause problems trying to access files in secured areas.
Because of the above, the page would need to be in a folder with its own Application file to negate any application files above it in the directory hierarchy.
To combat 1, 2, and 3, You'd need to code in a layer of security, similar to your application's own security, so that the file is not vulnerable should the url be found.
Each call to the file via cfhttp would need to invoke some extra security checking.
It is significantly slower. In a very simple test with a zero-content application.cfc, the custom tag method was executing in literally <= 1/100th of the time. As actual function is added to the method, the difference in results would change.
Here is some sample code to test this yourself.
Contents of folder "safe":
Application.cfc
[ blank file, to negate my testing site's actual application.cfc ]
Testrun.cfm
<cfoutput><cfset starttick = GetTickCount()>
<cfloop from="1" to="20" index="i">
<cfhttp url="http://mysamesite.com/safe/http.cfm?u=#i#" method="get" result="test">
#test.filecontent#<br>
</cfloop>
CFHTTP Execution Time: #(GetTickCount() - starttick)#<br><br>
<cfset starttick = GetTickCount()>
<cfloop from="1" to="20" index="i">
<cf_testtag u="#i#"><br>
</cfloop>
CustomTag Execution Time: #(GetTickCount() - starttick)#<br><br>
</cfoutput>
testtag.cfm
<cfoutput>The ID entered was #attributes.u#</cfoutput>
http.cfm
<cfoutput>The ID entered was #url.u#</cfoutput>
Results (in milliseconds)
Each test was 20 passes at HTTP and 20 Passes at the custom tag.
CFHTTP Tag
661ms 6ms
1624 5
616 5
460 4
522 6
816 4
You can do this by using cfhttp also
<cfquery name="GetUIDs">
select userid from users
</cfquery>
<cfloop query="GetUIDs">
<cfhttp url="http://localhost:8500/cf10/test.cfm?id=#userid#" method="get" result="test">
</cfloop>

CFFILE - Uploading a file using a component

I have a form that I would like to submit to a component for processing (CRUD behaviors), the problem is it seems passing multipart/form-data to a component somehow looses the file location. When it gets to the part of the component that should be uploading the file I get the infamous form field did not contain a file error.
I am not 100% sure why this happening but if I submit the form directly to a .cfm page that performs the cffile action everything works as expected, but if the .cfm page does something like:
<cfobject name="process_form" component="processor" />
<cfset result = process_form.upload( form ) />
and the component "processor" tries to do the upload, I get the form field did not contain a file.
My processor looks like:
<cfcomponent name="processor">
<cffunction name="upload" returntype="string">
<cfargument name="form_data" type="struct" />
<cffile action="upload" filefield="#arguments.form_data.file_1#" ...>
[ ... ]
</cffunction>
</cfcomponent>
One thing to note, is if I try use the variable arguments.form_data.file_1 without the # signs around it, I get the error:
The form field arguments.form_data.file_1 did not contain a file.
If I put the # signs around the variable I get:
The form field C:\JRun4\servers\cfusion\SERVER-INF\temp\cfusion-war-tmp\neotmp7350969777287007477.tmp did not contain a file.
Any idea on how to fix this issue? I would rather have all my processing actions inside a component, but right now I can't seem to make that work.
Thanks!
Will
You shouldn't need to use the full variable name when using a cffile tag--you just need the form field name, so something like:
<cffile action="upload" filefield="file_1" ...>
should suffice. The FORM struct field holds the location of the temporary file, but the cffile tag doesn't need that (I'd image that id directly accesses the FORM struct on the backend based on the fieldname you've provided).