ColdFusion 10 cffile action="upload" accept attribute wildcards don't work - coldfusion

This code used to work fine with ColdFusion 9:
<cfif form.btnSaveImage EQ "Upload">
<cftry>
<cffile accept="image/*" action="upload" destination="C:\T" filefield="vcImageFile" nameconflict="overwrite">
<cfcatch type="Any">
<cfdump var="#cfcatch#" label="cfcatch">
</cfcatch>
</cftry>
</cfif>
<form action="<cfoutput>#cgi.SCRIPT_NAME#</cfoutput>" method="post" name="frmImagesAdd" id="frmImagesAdd" enctype="multipart/form-data">
<label for="vcImageFile">Image File*:</label><br>
<input type="file" name="vcImageFile" id="vcImageFile" size="40" maxlength="255" message="Image file is required to upload."><br>
<input type="hidden" name="btnSubmit" value="Add Image">
<input name="btnSaveImage" type="submit" value="Upload">
</form>
The issue is the accept="image/*" attribute of the cffile tag. In ColdFusion 9, this wildcard used to accept any file with a MIME type that started with "image/". In ColdFusion 10, I get the following error message:
"The MIME type or the Extension of the uploaded file image/jpeg was
not accepted by the server."
The MimeType value is "image/jpeg", so it should work with the wildcard.
I looked at the wikidocs for the cffile tag and it says this:
ColdFusion 10: Modifications to the attribute accept}}
However, it doesn't elaborate what those modifications are!
Looking at the upload action docs, it says that it will accept a comma delimited list of mime types. Does this mean that wildcards are no longer accepted?

FYI, this blog post has indicated the same problem same time last year:
http://www.cutterscrossing.com/index.cfm/2013/2/21/ColdFusion-10-File-Uploads-and-MIME-Types
Now, I remembered that there were changes to MIME type checking in CF
10, but I wasn't entirely sure. This code, written by one of our
developer's several months ago, would allow any "image" MIME type.
What we discovered is that we couldn't do this kind of wildcard
mapping under CF 10, that we now had to list out each accepted MIME
type as a comma delimited list.

Related

Converting Word Doc to PDF in Coldfusion

Working on a page that displays the Standard Operating Procedures (SOP) and allows a non-Admin to download the SOP in a PDF file. Clients decided they didn't want admins to be limited to uploading just PDF files, and they want the option to upload .doc and .docx files. I need the download link to produce a PDF though.
Right now uploading either a .doc/.docx or a .pdf will display as I want it to using the Google Viewer. But when I attempt to download the test file it cant be opened if the files uploaded was a .doc/.docx. I've looked over this, and I'm sure I'm missing something stupid.
I'm using cfdocumnet as was suggested on another question.
Download link:
<cfoutput>
<li class="active">
<ahref="/files/SOP/SOP.pdf"
download="SOP.pdf" target="_blank">Download SOP</a>
</li>
</cfoutput>
Check for Admin (variable is created elsewhere) and form to upload file:
<cfif isAdmin>
<h3>Upload New SOP</h3>
<cfparam name="form.fileUpload" default="">
<cftry>
<cffile action="upload"
fileField="fileUpload"
destination="#expandPath('.')#\files\SOP\"
accept="application/pdf,
application/msword,
application/vnd.openxmlformats-officedocument.wordprocessingml.document,
application/x-tika-msoffice"
nameconflict="OVERWRITE">
<cfset fileName=CFFILE.serverfile>
<cfdocument
format="PDF"
srcfile="#expandPath('.')#\files\SOP\#fileName#"
filename="#expandPath('.')#\files\SOP\SOP.pdf"
overwrite="YES">
</cfdocument>
<p>Thank you, your file has been uploaded.</p>
<cfoutput>#fileName#</cfoutput>
<form enctype="multipart/form-data" method="post">
<input type="file" name="fileUpload"/>
<input type="submit" name="submit" value="Upload File"/>
</form>
<cfcatch type="any">
<!--- file is not written to disk if error is thrown --->
<!--- prevent zero length files --->
<cfif FindNoCase("No data was received in the uploaded", cfcatch.message)>
<p>No data was received in the uploaded file.</p>
<!--- prevent invalid file types --->
<cfelseif FindNoCase("The MIME type or the Extension of the uploaded file", cfcatch.message)>
<p>Invalid file type. Please upload file as a PDF or Word Doc</p>
<!--- prevent empty form field --->
<cfelseif FindNoCase("did not contain a file.", cfcatch.message)>
<p>Please seclect a PDF to upload.</p>
<!---all other errors --->
<cfelse>
<p>Unhandled File Upload Error</p>
<cflog type="Error" file="#application.applicationname#_dcnsopupload_error" text="#cfcatch.Message# - #cfcatch.Detail#" />
<cfoutput>#cfcatch.Detail#</cfoutput>
</cfif>
</cfcatch>
</cftry>
</cfif>
And on a side note, because I want the downloadable .pdf to be the given name "SOP.pdf" is there a way I can delete the user-uploaded file after renaming it and converting it? Just so there aren't 30 different outdated SOP documents on the server.
The form upload code looks wrong. Due to the cfparam, it's probably trying run the upload/conversion before the form is even submitted. Remove the cfparam and use structKeyExists() to verify the file field was submitted before trying to process it.
Try a simplified example first, with only the form and upload code (no error handling).
<!--- If file was uploaded, process it --->
<cfif structKeyExists(FORM, "fileUpload")>
<cffile action="upload"
fileField="fileUpload"
destination="#GetTempDirectory()#"
accept="application/pdf,application/msword,
application/vnd.openxmlformats-officedocument.wordprocessingml.document,
application/x-tika-msoffice"
nameconflict="makeunique">
<cfset savedFilePath = cffile.serverDirectory &"/"& cffile.serverFile>
<!---
more file validation here ...
--->
<!--- convert file --->
<cfdocument format="PDF"
srcfile="#savedFilePath#"
filename="#expandPath('.')#\files\SOP\SOP.pdf"
overwrite="YES">
</cfdocument>
<!--- cleanup temp file --->
<cfif fileExists(uploadedFile)>
<cfset fileDelete(uploadedFile)>
</cfif>
<!--- Otherwise, just display the form --->
<cfelse>
<form enctype="multipart/form-data" method="post">
<input type="file" name="fileUpload"/>
<input type="submit" name="submit" value="Upload File"/>
</form>
</cfif>
Also, though a bit dated, some of these tips on securing file uploads are still valid (such as not uploading files to the web root):
http://www.learncfinaweek.com/week1/File_Uploads/
https://www.petefreitag.com/item/701.cfm

Upload Files from web url using Coldfusion

I have been allowing user to upload file via a form online like this:
<form action="upload.htm" enctype="multipart/form-data" name="upload_form" method="post">
<input type="file" name="upfile">
<input type="submit" name="upload" value="Upload Photos">
</form>
Then on the back end the cffile would upload the file:
<cffile action="upload" destination="#currentpath#" accept="image/jpeg, image/gif, image/png" fileField="form.upfile" nameconflict="makeunique">
Now I want to do automation so that the image file does not have to be sitting in the user's computer but rather from a web destination e.g. http://www.sample.com/images/myimage.jpg instead of c:/images/myimage.jpg
I have tried this:
<cfhttp method="get" url="http://www.example.com/images/myimage.jpg" resolveurl="Yes" throwOnError="Yes">
<cfif cfhttp.mimeType eq "image/jpeg">
<cfset currentpath = expandpath('/test/')>
<cffile action="upload" destination="#currentpath#" accept="image/jpeg, image/gif, image/png" fileField="#cfhttp.fileContent#" nameconflict="makeunique">
</cfif>
However, it is giving me an error:
Invalid content type: ''. The files upload action requires forms to
use enctype="multipart/form-data"
I am not using a form to upload but it seems to require a form field.
So I tried this:
<cfhttp method="get" url="http://www.example.com/images/myimage.jpg" resolveurl="Yes" throwOnError="Yes">
<cfif cfhttp.mimeType eq "image/jpeg">
<cfset currentpath = expandpath('/test/')>
<cffile action="write" output="#cfhttp.fileContent#" file="#currentpath#/someimage.jpg">
</cfif>
This one writes out a "file" called someimage.jpg but the output is NOT a jpg file, but something unrecognizable. With the cffile "write", it doesn't allow to check for image type or same file name.
Any help is appreciated. Thank you in advance.
Assuming the call was successful, the current code may be retrieving and/or saving the response as text, instead of binary, which would corrupt the image. To ensure you get back a binary image, use getAsBinary="yes".
Having said that, it is simpler to save the response to a file directly within the cfhttp call:
<cfhttp url="http://www.example.com/images/myimage.jpg"
method="get"
getAsBinary="yes"
path="#currentpath#"
file="someimage.jpg"
resolveurl="Yes"
throwOnError="Yes" />

Coldfusion form submission multiple fields with same name in CF8 & CF11

I am getting different output when dumping results of a form submission with multiple fields with the same name. In CF8 I got only first html element value in output result but in CF11 I got value as a list. Is this specific to server running in CF8 & CF11. Below is the prototype of code I am using
<cfform method="post" action="">
<select name="test">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<input type="hidden" name="test" value="0">
<input type="submit" name="btnsubmit" />
</cfform>
<cfif structKeyExists(form,"btnsubmit")>
<cfdump var="#form#">
</cfif>
In CF8 I got results as '1' but in CF11 I got result as '1,0'.
Please let me know if this is specific to my server upgrade. I just want to know that in CF8 server multiple fields with same name returns value as list or only returns value of first element.

HTML form is sending valid content, but CF script is claiming to receive undefined values

I have a simple email form and CF script backing it. It should all be obvious, but the script is throwing up with valid input. I've verified that the expected values are in the header and I can output the values in the script, but it's not liking the values for anything beyond output.
This is my HTML:
<form id="email" name="email" method="post" action="scripts/email.cfm">
<fieldset>
<legend>Email Student Government:</legend>
<!-- PASS NAME (to query email) to the script -->
<input type="hidden" name="who" id="who" value="Example User">
<label for="from">Your Email:</label><br>
<input type="email" id="from" name="from"><br>
<label for="message">Message:</label><br>
<textarea id="message" name="message" rows="4"></textarea>
<input type="submit" name="send" id="send" value="Send Email">
</fieldset>
</form>
The ColdFusion (including debugging script at top):
<!--- member email addresses, hashed by name --->
<cfinclude template="emailHash.cfm">
<cfoutput>
#FORM.SEND#
#FORM.WHO#
#FORM.FROM#
#FORM.MESSAGE#
</cfoutput>
<cfif isdefined("FORM.SEND") and FORM.SEND eq "Send Email">
<cfmail from="Example User <example#example.com>"
to="#FORM.WHO# <#emailHash['FORM.WHO']#>"
bcc="Example User <example#example.com>"
replyto="#FORM.FROM#"
subject="Email Form Submission">
Message: #FORM.MESSAGE#
Date / Time Sent: #dateformat(now(), "yyyy/mm/dd")# at #timeformat(now(), "HH:mm:ss tt")#
</cfmail>
</cfif>
If I run the script, the logical output is printed, but then this error follows even though the FORM.WHO value is clearly defined and printed just fine in the output directly prior:
Element FORM.WHO is undefined in a CFML structure referenced as part of an expression.
I'm pretty annoyed at what I thought was an easy project so any nudges in the right direction would be greatly appreciated!
PS: I thought the HTML5 input types might be causing issues so I tried trading them for a plain text type, but that didn't do any good.
The problem isn't with your form variables, it's with this:
#emailHash['FORM.WHO']#
Your error is saying that that variables doesn't exist (the rest of the error message should point to the line number that that code is on? You didn't post that bit...). And from what you've posted, there's no evidence to suggest that it does.
What goes on in emailHash.cfm?

ColdFusion: get the name of a file before uploading

How can I get the filename of a file before I call the
<cffile action = "upload">
? I can get the filename of the temp file, but not of the actual filename. In PHP land I can use the $_FILES superglobal to get what I want - but as far as I can tell no such thing exists in ColdFusion.
I can get the filename client-side but would really want to do this server side.
Thanks
Yes this is possible. You can use this function to grab the client file name before using the cffile tag:
<cffunction name="getClientFileName" returntype="string" output="false" hint="">
<cfargument name="fieldName" required="true" type="string" hint="Name of the Form field" />
<cfset var tmpPartsArray = Form.getPartsArray() />
<cfif IsDefined("tmpPartsArray")>
<cfloop array="#tmpPartsArray#" index="local.tmpPart">
<cfif local.tmpPart.isFile() AND local.tmpPart.getName() EQ arguments.fieldName> <!--- --->
<cfreturn local.tmpPart.getFileName() />
</cfif>
</cfloop>
</cfif>
<cfreturn "" />
</cffunction>
More info here: http://www.stillnetstudios.com/get-filename-before-calling-cffile/
I'm using Railo and found the original filenames with:
GetPageContext().formScope().getUploadResource('your_file_input_form_name').getName();
maybe this works on an adobe server as well? its quite handy if you want to rename your uploaded file somehow and don't want it to get moved through two temp dirs (see Renaming Files As They Are Uploaded (how CFFILE actually works))
I don't know of a way to find out before calling cffile, but there may be a workaround.
When you call <cffile action="upload"> you can specify a result using result="variable". So, call the upload with the destination as a temp file. Your result variable is a struct which contains the member clientFile, which is the name of the file on the client's computer.
Now, you can use <cffile action="move"> to do whatever it is you need to do with the original filename.
WOW, i found a great and easy solution! with a little javascript
In this way you get the temp filename for the cffile upload and the actual file.jpg name for the database
<html>
<head>
<script type="text/javascript">
function PassFileName()
{
document.getElementById("fileName").value=document.getElementById("fileUp").value;
}
</script>
</head>
<body>
<form name="form1" method="post" enctype="multipart/form-data" >
File: <input type="file" name="fileUp" id="fileUp" size="20" onchange="PassFileName()" /> <br />
Title: <input type="text" name="Title" id="Title"><br />
<input type="hidden" id="fileName" size="20" name="fileName" />
<input type="submit" name="submit">
</form>
</body>
</html>
If you have the name attribute defined on the input control, the file name will be in the FORM scope. For example:
<cfif not structIsEmpty(form)>
<cfdump var="#form#">
<cfelse>
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="POST" action="#cgi.SCRIPT_NAME#">
<input type="file" name="fileIn" />
<input type="Submit" name="formSubmit">
</form>
</body>
</html>
</cfif>
Another option might be to have client-side code populate a hidden form field with the filename, which you would then have server-side.
Ben Doom's answer is generally how I would approach it, though.
Here's how we do it. Basically, there is a file field, and a string field. JavaScript grabs the filename from the browser before the form is submitted. Obviously, you need to verify that the filename on the other end is actually present (it'll be blank if the user has JavaScript disabled, for example) and you'll need to parse the string to handle platform differences (/users/bob/file.jpg versus C:\Documents and Settings\bob\file.jpg)
<script>
function WriteClientFileName(){
$('ClientFileName').value = $('ClientFile').value;
}
</script>
<form enctype="multipart/form-data" onsubmit="WriteClientFileName();">
<input type="File" name="ClientFile" id="ClientFile">
<input type="hidden" name="ClientFileName" id="ClientFileName" value="">
<input type="submit">
</form>
Incidentally, this technique is cross-language. It'll work equally well in RoR, PHP, JSP, etc.
Edit: If a user is "wielding a fierce FireBug" what's the issue? Even if they don't have Firebug, they can still rename the file on their end and change the input. Plus, you're validating your inputs, right?
There is no way to know the file name for uploaded files before saving to the server in ColdFuson, Railo or OpenBD. I typically generate 'my' new filename using the createUUID() function in advance of saving the file.