Solved

CFCONTENT tag does not parse filenames that contain "&" or "#", and does not allow download of DOCX or XLSX files

Posted on 2010-08-28
24
1,766 Views
Last Modified: 2012-05-10
I use the CFCONTENT tag to move files from a folder outside of web root, to a browser page where a user may click on the files to download them.

For example, here: http://ebwebwork.com/cep/index.cfm?DocumentTopicID=6

I have two problems with this CFCONTENT method and need to ask an expert's advice.

The CFCONTENT tag is contained in template "cfcontent_file.cfm"; the only code in cfcontent_file.cfm is:

<cfif listfindnocase('doc,docx,pdf,ppt,pptx,xls,xlsx,txt',url.FileType)>
    <CFCONTENT type="application/#FileType#" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">
<cfelse>
      <CFCONTENT type="image/#FileType#" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">
</cfif>

I invoke cfcontent_file.cfm from index.cfm, like this:

<a href="cfcontent_file.cfm?Attachment=#FileName#&FileType=#FileExtension#">#FileLinkText#</a>
(#FileExtension#, #FileSize# bytes)

My two problems are:

1. if the variable #FileName# contains a character like "&" or "#" then ColdFusion tries to parse the character as a query or a variable, which causes a File Not Found error

2. if #FileExtension# is a DOCX or a XLSX file, then ColdFusion prompts me to download the cfcontent_file.cfm template, rather than the DOCX or XLSX file. (If #FileExtension# is a PDF or GIF file, then the file downloads correctly.)

It looks like maybe ColdFusion has trouble parsing a Microsoft MIME type? (My guess.)

May I get some advice about these two problems? I have been trying different solutions but it is time I asked for some help. Thank you!

Eric
cfcontent_file.cfm:

<cfif listfindnocase('doc,docx,pdf,ppt,pptx,xls,xlsx,txt',url.FileType)>

    <cfcontent type="application/#FileType#" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">

<cfelse>

      <cfcontent type="image/#FileType#" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">

</cfif>



relevant part of index.cfm that pertains to this problem:



<!--- begin output from query getDocumentsandFiles; list Document Title, Author, Abstract, Publication Date; and CEP Files associated with those documents; and download links to those files --->

<cfoutput query="getDocumentsandFiles" group="DocumentTitle">



<cfif bgColor neq "##ffffff">

    <cfset bgcolor="##ffffff">

  <cfelse>

    <cfset bgcolor="##f7f5f5">

  </cfif>





<!--- set bgcolor --->

<div style="background-color:#bgcolor#;">



<!--- set padding --->

<div style="padding:5px;">







<!--- output group on DocumentID --->

<cfoutput group="DocumentID">

<h3>#DocumentTitle#</h3>

<p class="documentText">

<em>Author(s):</em> <span class="black">#DocumentAuthor#</span><br />

<em>Published:</em> <span class="black">#DateFormat(DocumentPublicationDate, "mmmm d, yyyy")#</span><br />

#DocumentAbstract#

<h4>Download files:</h4>



<!--- output of query filename --->

 <cfoutput group="FileName">

 

 <a href="cfcontent_file.cfm?Attachment=#FileName#&FileType=#FileExtension#">#FileLinkText#</a>

(#FileExtension#, #FileSize# bytes)<br />







<!--- /output of query filename --->

</cfoutput>

</p>





</div>

<!--- /set padding --->







</div>

<!--- /set bgcolor --->



<!--- /output group on DocumentID --->

    </cfoutput>

    

<!--- /output from query getDocumentsandFiles --->

</cfoutput>

Open in new window

0
Comment
Question by:Eric Bourland
  • 10
  • 9
  • 4
  • +1
24 Comments
 
LVL 82

Accepted Solution

by:
Dave Baldwin earned 168 total points
Comment Utility
"&" or "#" aren't legal characters in a filename or URL for the internet. http://en.wikipedia.org/wiki/Percent-encoding   MIME types have to be declared on the server and DOCX and XLSX probably arent.
0
 
LVL 3

Author Comment

by:Eric Bourland
Comment Utility
>>>"&" or "#" aren't legal characters in a filename or URL for the internet. http://en.wikipedia.org/wiki/Percent-encoding

I agree with this! =)

But the client insists on using them in filenames ~sigh~

Is there a workaround for this problem? Besides ~headdesk~? =)
0
 
LVL 3

Author Comment

by:Eric Bourland
Comment Utility
>>>MIME types have to be declared on the server and DOCX and XLSX probably arent.

Good observation. I was wondering the same.
0
 
LVL 82

Assisted Solution

by:Dave Baldwin
Dave Baldwin earned 168 total points
Comment Utility
I wouldn't do that to myself... but I have been known to fire a client.  It doesn't matter whether he insists or not, it's not his choice or even yours.  All you can tell him is that those characters aren't allowed in file name on the internet.  Trying to use them will cause the download to fail.
0
 
LVL 15

Expert Comment

by:myselfrandhawa
Comment Utility
Hi Eric!


for your this trouble >> if the variable #FileName# contains a character like "&" or "#" then ColdFusion tries to parse the character as a query or a variable, which causes a File Not Found error

I suggest you use the Rename the file using the CreateUUID or Randrange so that Coldfusion Parses it correctly

As per DOCX and XLSX, are u trying to do in the IE or Mozilla, Yes it has some issues with it i also gets sometimes but exact cause i do not know maybe someone else can help here!

but if u will open it they get opened in correct like word or excel. this i have tried and it works
0
 
LVL 52

Assisted Solution

by:_agx_
_agx_ earned 332 total points
Comment Utility
To expand on the previous comments ...


Special Characters

>> <a href="cfcontent_file.cfm?Attachment=#FileName#

Ignoring the issue of what file names should be allowed for a moment .....

I know we discussed this code on another thread ;-)  and I mentioned I prefer NOT to pass large strings as url parameters.  However, if you really have to use this method, you MUST properly encode those string first.  Otherwise, the browser will evaluate any special character it finds and mangle the string in the process.   For example, if your file name is

      <a href="otherPage.cfm?attachment=Before & After School Care">Test</a>
The browser will interpret "&" as the beginning of another url parameter. So what you're actually passing is 2 parameters: one named "attachment" and another named "after school care". ie Totally wrong.

         AFTER SCHOOL CARE [empty string]  
          ATTACHMENT Before  
To prevent that from happening, you need to encode the parameter VALUE first using the URLEncodedFormat() function.

<cfoutput>
<cfset fileName = "Before & After School Care">
<a href="somePage.cfm?attachment=#URLEncodedFormat(fileName)#">Test</a>
</cfoutput>
You'll may also need to use CFHEADER to properly encode the file name again when downloading.  

>>  <cfcontent type="application/#FileType#"

Mime Types
A few problems with mime types:

1) I don't think that code is actually generating a valid mime type in all cases. One example, the mime type for DOCX files is:

       application/vnd.openxmlformats-officedocument.wordprocessingml.document

2) I believe they also have to be registered with the web server

      http://www.bram.us/2007/05/25/office-2007-mime-types-for-iis/


File Names
But back to the issue of file names ...

Every operating system has restricted characters.  As  @DaveBaldwin mentioned, you obviously can't allow every and any  character  in file names, even if you wanted to
http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx

But there's no reason you can't enforce your own naming convention for files internally, while still displaying a "user friendly name" when downloading the files.  Just store both values in your database table. Then use the internal file name for locating files,  and the user friendly name for downloading.


0
 
LVL 52

Assisted Solution

by:_agx_
_agx_ earned 332 total points
Comment Utility
>> You may also need to use CFHEADER to properly encode the file
>> name again when downloading.  

The more I think about it, I'd say @DaveBaldwin's 1st comment is right on the money.  While you can use CFHEADER to present a more user friendly file name for downloads

ie      
      <cfheader name="Content-Disposition" value="attachment;fileName=""#fileName#""">
      <cfcontent type="application/msword" file="c:\somePath\#fileName#">

.... certain file characters may still be problematic in some browsers  
http://greenbytes.de/tech/tc2231/
0
 
LVL 3

Author Comment

by:Eric Bourland
Comment Utility
>>><cfheader name="Content-Disposition" value="attachment;fileName=""#fileName#""">
      <cfcontent type="application/msword" file="c:\somePath\#fileName#">

I am thinking about this a lot right now. More in a while.
0
 
LVL 52

Expert Comment

by:_agx_
Comment Utility
Keep in mind, there's at 3 potential problems in the code:
1. How the file name is passed TO the download page (ie corrupted)
2. Wrong mime types used in the download page
3. How file name is presented in the download page
0
 
LVL 3

Author Comment

by:Eric Bourland
Comment Utility
Hi friends. Here's where I am.

1. I added the MS Office 2007 mime types to C:\WINDOWS\system32\inetsrv\MetaBase.xml, per the helpful link that _agx_ provided:  http://www.bram.us/2007/05/25/office-2007-mime-types-for-iis/

So now, I believe, IIS 6 knows how to handle these MIME types.

2. I implemented the URLEncodedFormat() function -- I was wondering if ColdFusion had a function like that! It seems to be working fine. Thank you! That is one problem solved.

The other problem persists; ColdFusion still does not let me download DOCX files, but prompts me to download the cfcontent_file.cfm template. Hmm.

I would like to use the cfheader solution that DaveBaldwin and _agx_ suggest but I do not see how it would work. (I wrestled with this same problem before -- _agx_ and myselfrandhawa helped me to set up the CFCONTENT tag that delivers files from the c:\upload\cep-dc.org directory to a web page.

I am keeping in mind the three potential problems that _agx_ identifies immediately above.

>>>and I mentioned I prefer NOT to pass large strings as url parameters.
I agree 100%. I would like to find a better solution.

So, currently my CFCONTENT tag is set up inside file: cfcontent_file.cfm

And the code in index.cfm that invokes cfcontent_file.cfm is:

<a href="cfcontent_file.cfm?Attachment=#URLEncodedFormat(FileName)#&FileType=#FileExtension#">#FileLinkText#</a>
(#FileExtension#, #FileSize# bytes)

So, now I am experimenting with CFHEADER to see how else I can set up the download link (#FileLinkText#). The variables that I need to account for are:

FileName
FileType
FileExtension
FileLinkText
FileSize

These variables are different for every file that is downloaded.

I believe also that somewhere, I need to tell ColdFusion to allow downloading of the MIME type for DOCX and XLSX files ... and I am not sure where to do that.

But I am trying different ideas and will reply here will some results! In a little while. Thank you all, again, for your advice.

Eric
cfcontent_file.cfm:

<cfif listfindnocase('doc,docx,pdf,ppt,pptx,xls,xlsx,txt',url.FileType)>

    <cfcontent type="application/#FileType#" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">

<cfelse>

      <cfcontent type="image/#FileType#" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">

</cfif>

Open in new window

0
 
LVL 52

Assisted Solution

by:_agx_
_agx_ earned 332 total points
Comment Utility
>> <cfif listfindnocase('doc,docx,pdf,ppt,pptx,xls,xlsx,txt',url.FileType)>
>>    <cfcontent type="application/#FileType#"

I could be wrong, but the problem I see with that code is it doesn't produce valid mime types.  I'm assuming url.FileType is a value like "DOCX". Which means the result would be:

       <cfcontent type="application/DOCX" ...>

That's not a real mime type.  The actual mime type for DOCX is:

 <cfcontent type="application/vnd.openxmlformats-officedocument.wordprocessingml.document" ...>

So that may be part of the problem.
0
 
LVL 3

Author Comment

by:Eric Bourland
Comment Utility
>>>the problem I see with that code is it doesn't produce valid mime types.

I think you are right.
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 52

Expert Comment

by:_agx_
Comment Utility
>> I would like to use the cfheader solution ...
>> but I do not see how it would work.

It's similar to the current code.  Just add a header named "Content-Disposition".  There are 2 parts to the Content-Disposition header value: 1) how to present the file AND 2) what file name to display.  A file can be presented "inline" (or opened directly within the browser .. if allowed)

     <cfheader name="Content-Disposition" value="inline; fileName=""my File.doc""">
    <cfcontent type="application/msword" file="c:\realPathTo\my File.doc">

... OR presented as an "attachment" (user is prompted to download the file).

     <cfheader name="Content-Disposition" value="attachment; fileName=""my File.doc""">
    <cfcontent type="application/msword" file="c:\realPathTo\my File.doc">


You can find most of the common mime types here.  (For Office 2007 types, see the previous link)  
        http://www.w3schools.com/media/media_mimeref.asp

0
 
LVL 3

Author Comment

by:Eric Bourland
Comment Utility
_agx_,

Sorry it has taken me so long to get back to this question. It's been a very busy Monday.

I believe, in template cfcontent_file.cfm, you want me to set up a series of conditions to accommodate different MIME types. Like the attached code. Is this what you had in mind?

Eric
cfcontent_file.cfm:



<cfheader name="Content-Disposition" value="attachment;fileName=""#fileName#""">



<cfif listfindnocase('doc,pdf,ppt,xls,txt',url.FileType)>

    <cfcontent type="application/#FileType#" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">



<cfelseif listfindnocase('docx',url.FileType)>

      <cfcontent type="application/vnd.openxmlformats-officedocument.wordprocessingml.document" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">

      

<cfelseif listfindnocase('xlsx',url.FileType)>

      <cfcontent type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">

      

<cfelseif listfindnocase('pptx',url.FileType)>

      <cfcontent type="application/vnd.openxmlformats-officedocument.presentationml.presentation" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">

      

<cfelseif listfindnocase('jpg,jpeg,gif,png',url.FileType)>

 <cfcontent type="image/#FileType#" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">

 

</cfif>

Open in new window

0
 
LVL 52

Assisted Solution

by:_agx_
_agx_ earned 332 total points
Comment Utility
>> <cfif listfindnocase('doc,pdf,ppt,xls,txt',url.FileType)>
>> <cfcontent type="application/#FileType#"

Personally I use a db table. But really the "how" (cfif conditions, or db query, etc. ...) doesn't matter. All that's important is the page return a valid mime type.  The 1st CFIF still doesn't do that.  You can either create your code or use a prebuilt function like getMimeType() from cflib
http://www.cflib.org/udf/getMimeType

Then the code would be something like the lines below.  As I mentioned, some characters are still problematic. So you may still want to scrub the user file names. But that's easy enough to do on file upload.

<!---
      assuming #URL.Attachment# is a full file name like ....
      my Document.doc, somepressRelase.pdf, etc....
--->
<cfset theMimeType = getMimeType(URL.Attachment)>
<cfheader name="Content-Disposition" value="attachment;fileName=""#URL.Attachment#""">
<cfcontent type="#theMimeType #" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">







0
 
LVL 52

Expert Comment

by:_agx_
Comment Utility
>> You can either create your code ...

Correction:  You can either create your OWN code that returns the right mime types (cfif statements, etc..) or use a prebuilt function like getMimeType() from cflib
0
 
LVL 3

Author Comment

by:Eric Bourland
Comment Utility
The getMimeType function looks really cool. I am going to work on that now. Also I've convinced the client to scrub file names. By the way, good morning. =)
0
 
LVL 82

Expert Comment

by:Dave Baldwin
Comment Utility
Good morning, and glad to see you got one issue resolved.!
0
 
LVL 3

Author Comment

by:Eric Bourland
Comment Utility
I included the getMimeType() function in my cfcontent_file.cfm template. This looks really useful; thank you for pointing me to this function.

In index.cfm, I still use this code to request template cfcontent_file.cfm:

<a href="cfcontent_file.cfm?Attachment=#URLEncodedFormat(FileName)#&FileType=#FileExtension#">#FileLinkText#</a>
(#FileExtension#, #FileSize# bytes)

but I think now I can simply use:

<a href="cfcontent_file.cfm?Attachment=#URLEncodedFormat(FileName)#">#FileLinkText#</a>
(#FileExtension#, #FileSize# bytes)

Correct?

Eric
cfcontent_file.cfm:



<cfscript>

/**

* Returns mime type and subtype for a file.

* 

* @param filename      File name to examine. (Required)

* @return Returns a string. 

* @author Kenneth Rainey (kip.rainey@incapital.com) 

* @version 1, April 21, 2004 

*/

function getMimeType(filename) {

    var mimeStruct=structNew();

    var fileExtension ="";

    //extract file extension from file name

    fileExtension = Reverse(SpanExcluding(Reverse(fileName),"."));

    //build mime type array

    mimeStruct.ai="application/postscript";

    mimeStruct.avi="video/x-msvideo";

    mimeStruct.css="text/css";

    mimeStruct.doc="application/msword";

    mimeStruct.gif="image/gif";

    mimeStruct.htm="text/html";

    mimeStruct.html="text/html";

    mimeStruct.jpe="image/jpeg";

    mimeStruct.jpeg="image/jpeg";

    mimeStruct.jpg="image/jpeg";

    mimeStruct.js="application/x-javascript";

    mimeStruct.mime="www/mime";

    mimeStruct.mov="video/quicktime";

    mimeStruct.pdf="application/pdf";

    mimeStruct.png="image/png";

    mimeStruct.ppt="application/mspowerpoint";

    mimeStruct.ps="application/postscript";

    mimeStruct.qt="video/quicktime";

    mimeStruct.rtf="text/rtf";

    mimeStruct.rtx="text/richtext";

    mimeStruct.swf="application/x-shockwave-flash";

    mimeStruct.tif="image/tiff";

    mimeStruct.tiff="image/tiff";

    mimeStruct.tsv="text/tab-separated-values";

    mimeStruct.txt="text/plain";

    mimeStruct.xls="application/vnd.ms-excel";

    mimeStruct.docx="application/vnd.openxmlformats-officedocument.wordprocessingml.document";

	mimeStruct.xlsx="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

	mimeStruct.pptx="application/vnd.openxmlformats-officedocument.presentationml.presentation";

    if(structKeyExists(mimeStruct,fileExtension)) return mimeStruct[fileExtension];

    else return "unknown/unknown";

}

</cfscript>





<cfset theMimeType = getMimeType(URL.Attachment)>

<cfheader name="Content-Disposition" value="attachment;fileName=""#URL.Attachment#""">

<cfcontent type="#theMimeType #" file="c:\upload\cep-dc.org\#URL.Attachment#" deletefile="no">

Open in new window

0
 
LVL 52

Expert Comment

by:_agx_
Comment Utility
I'm just getting back to this after a hectic day.

>> but I think now I can simply use:

Yep, exactly!
0
 
LVL 3

Author Comment

by:Eric Bourland
Comment Utility
My sympathies. Hectic day here too. =)

It's working like a charm.
0
 
LVL 3

Author Closing Comment

by:Eric Bourland
Comment Utility
This is working like a charm. Thanks to DaveBaldiwn, myselfrandhawa, and always _agx_. I learned a ton from this task. I'm very grateful and the client is pleased. Actually the client is blissfully unaware. Same difference! =)

Eric
0
 
LVL 82

Expert Comment

by:Dave Baldwin
Comment Utility
Haha.  That's a good result!
0
 
LVL 52

Expert Comment

by:_agx_
Comment Utility
That's a great way of putting it ;-)
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

PROBLEM:  How to open a cfwindow or run a function on double click of a cfgrid row. One of my clients wanted to be able to double click on a row item to get more detailed information about a transaction and to be able to modify the line items i…
Sometimes databases have MILLIONS of records and we need a way to quickly query that table to return the results me need. Sure you could use CFQUERY but it takes too long when there are millions of records. That is why SOLR was invented. Please …
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now