Link to home
Start Free TrialLog in
Avatar of Eric Bourland
Eric BourlandFlag for United States of America

asked on

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

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

ASKER CERTIFIED SOLUTION
Avatar of Dave Baldwin
Dave Baldwin
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Eric Bourland

ASKER

>>>"&" 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~? =)
>>>MIME types have to be declared on the server and DOCX and XLSX probably arent.

Good observation. I was wondering the same.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>><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.
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
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

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>>the problem I see with that code is it doesn't produce valid mime types.

I think you are right.
>> 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

_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

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>> 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
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. =)
Good morning, and glad to see you got one issue resolved.!
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

I'm just getting back to this after a hectic day.

>> but I think now I can simply use:

Yep, exactly!
My sympathies. Hectic day here too. =)

It's working like a charm.
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
Haha.  That's a good result!
That's a great way of putting it ;-)