I am trying to dynamically create an inline PDF that, when the user chooses to save it, prompts with my custom filename. According to the documentation, the saveasname attribute should do what I want.
(format="PDF" only) The filename that appears in the SaveAs dialog when a user saves a PDF file written to the browser.
However, what is happening in both IE 9 and in Firefox 13.0.1 is that the filename that appears in the SaveAs dialog is the same as my CF template, but with a PDF extension. (In other words, my code is in makepdf.cfm and the SaveAs prompts me to save makepdf.pdf.) In Chrome, however, it works perfectly. (All on Windows 7.)
Here is my code to create the PDF:
<cfdocument format="pdf" bookmark="true" saveasname="MyReport.pdf">
If I explicitly declare the content disposition and content type, like so
<cfheader name="Content-Disposition" value="inline; filename=MyReport.pdf">
<cfcontent type="application/x-pdf">
<cfdocument format="pdf" bookmark="true" saveasname="MyReport.pdf">
Chrome tells me that "Content-Disposition" has been declared twice
Firefox tells me the PDF file is corrupt
IE just ignores it (and still doesn't show the right filename)
If I just rely on the header
<cfheader name="Content-Disposition" value="inline; filename=MyReport.pdf">
<cfcontent type="application/x-pdf">
<cfdocument format="pdf" bookmark="true">
I get the same behavior as the first snippet of code.
I know how to get the browser to prompt for download rather than displaying inline, and everything works as expected then, but that's not the desired behavior.
I need to use times and dates in filenames and the end users are not savvy enough to keep from overwriting their files (should they choose to save them).
Is there something I'm missing that will get IE and Firefox to do what they're supposed to? What other browsers are going to do this? Mobile Safari?
The problem seems to be that "filename=xxx" was really intended for the "attachment" disposition, and not all the browser PDF plugins recognise it as a mechanism for specifying the inline "save as", as you've discovered.
A different approach to getting them all to use your preferred filename would be to manipulate the URL using web server rewrite rules. As a simple example you'd have your script for generating the pdfs and serving them inline: pdf.cfm
<cfheader name="Content-Disposition" value="inline">
<cfdocument format="PDF" mimetype="application/pdf">Test</cfdocument>
Then create a re-write rule which matches URLs in the form /pdf/myfilename and passes them to pdf.cfm. On IIS7 this might be:
<rule name="Inline PDF SaveAs" stopProcessing="true">
<match url="^/pdf/[\w-]+$" ignoreCase="true" />
<action type="Rewrite" url="/pdf.cfm" appendQueryString="false" />
</rule>
This will match filenames containing alphanumeric, underscore and hyphen characters only. You wouldn't want to allow spaces, or invalid filename characters.
When you access /pdf/myreport the PDF will be displayed inline by the plugin, and when you save it, the default filename will be myreport.pdf.
If you're using a framework which supports Search Engine Safe URLs or "routes", you could do the same without needing web server rewrites.
UPDATE: In fact you don't need to use URL rewriting: simply append a forward slash and then the desired filename to the CF script URL, e.g.
/pdf.cfm/myreport
The plugin will use whatever comes after the final slash as the "Save As..." name.
Make sure you use ATTACHMENT and not INLINE.
IE does NOT like INLINE and will open a word document as READ ONLY as well as not assuming the filename you give it.
Example:
<cfheader name="content-disposition" value="attachment; filename=#filename#.doc" charset="utf-8">
NOT
<cfheader name="content-disposition" value="inline; filename=#filename#.doc" charset="utf-8">
I would use the name attribute of the cfdocument tag which will store the contents in a variable. Then use the cfheader and cfcontent tags as you have above with the exception of replacing "inline;" with "attachment;"
I use code like this:
<cfdocument name="pdf"> ... </cfdocument>
<cfheader name="Content-Disposition" value="attachment;filename=MyReport.pdf;" />
<cfcontent type="application/pdf" variable="#pdf#" />
Related
i don't know if this is possible, but with coldfusion could i display a pdf in the browser thats kept outside of the webroot?
so you can embed a pdf on a page like;
<object data="mypdf.pdf" type="application/pdf">
could i do something like;
<object data="displaymypdf.cfm" type="application/pdf">
where displaymypdf.cfm would return that pdf? kinda like we do for downloads with cfheader/cfcontent?
thanks for any help/pointers
In the CFHEADER tag, use the value: 'inline' and then use CFCONTENT. This should load the pdf into the browser.
<cfheader name="Content-Disposition" value="inline; filename=mypdf.pdf">
<cfcontent file="#yourDirectoryPathHere#mypdf.pdf" type="application/pdf">
I am invoking a ColdFusion webservice through cfinvoke
<cfinvoke
method="getUsers"
returnvariable="rawXMLUserList"
webservice="http://www.xyz.com/getusers.cfc?wsdl"
>
<cfinvokeargument name="userid" value="123">
</cfinvoke>
And I am storing XML returnvariable into userList variable
<cfset userList = XmlParse(rawXMLUserLis)><br/>
how to save abc.xml on user's computer, using cffile it is saving on server's computer, i have to save it on user's computer who invokes this "getUsers" method.
Thanks
Kishor
When you run XMLParse(), you're turning it into a CF XML Document Object. You need to use ColdFusion's toString(xmlObject) function when outputting it.
<cfheader name="content-disposition" value="attachment;filename=abc.xml">
<cfcontent type="application/xml;charset=utf-8" reset="true">
<cfoutput>#toString(userList)#</cfoutput>
Another way is to write the file to a web directory (cffile action=write) and then cflocation the user to the file.
You need to tell the user's browser to download the file, not display it. Generally with something like this (not tested):
<cfheader name="content-disposition" value="attachment;filename=abc.xml">
<cfcontent type="application/xml;charset=utf-8" reset="true">
<cfoutput>#userList#</cfoutput>
cfheader generates a custom HTTP header.
cfcontent sets the MIME content encoding header for the page.
I have a ColdFusion page calling a cfm page as a popup through window.open(..). The target page is a cfm that loads a PDF file. The called page code is the following:
<cfcontent type="application/pdf" file="/deploy/cfusion.ear/cfusion.war/myPDF.pdf"/>
<cfflush>
<script language="javascript">
window.location.reload();
</script>
Unfortunately, I am getting only a blank page unless I manually refresh the page (going to the popup URL bar and hitting Enter) to have its contents displayed by the browser.
What is strange is that if I replace the caller page code from window.open() to document.url = the PDF is displayed without the need of refreshing the page.
Do you have any suggestions here how to call the target page as a popup and having it load without the need of a manual refresh?
Thanks.
The problem is that you are mixing javascript and PDF content together. It should really just be this:
<cfcontent type="application/pdf" file="/deploy/cfusion.ear/cfusion.war/myPDF.pdf"/>
This will return the full contents of that PDF to the browser.
What were you trying to do with the javascript code?
edit It sounds like it could be something to do with caching. To prevent that, try adding some cache control headers to your file:
<cfheader name="expires" value="#getHttpTimeString(now())#">
<cfheader name="pragma" value="no-cache">
<cfheader name="cache-control" value="no-cache, no-store, must-revalidate">
<cfcontent type="application/pdf" file="/deploy/cfusion.ear/cfusion.war/myPDF.pdf"/>
If that doesn't work, try adding this one too:
<cfheader name="Content-Disposition" value="attachment; filename=myPDF.pdf">
The solution I adopted was that of calling a proxy page and then that proxy page generates the PDF file. So:
window.open('2') // open in a popup the PDF
document.location = '3' // proxy
cfcontent type='application/pdf' file='...' // generate PDF
Why I cannot have 1 and 3 only is for now a mystery but in my case it works perfectly.
What would be the correct way to stop the white space that ColdFusion outputs?
I know there is cfcontent and cfsetting enableCFoutputOnly. What is the correct way to do that?
In addition to <cfsilent>, <cfsetting enablecfoutputonly="yes"> and <cfprocessingdirective suppressWhiteSpace = "true"> is <cfcontent reset="true" />. You can delete whitespaces at the beginning of your document with it.
HTML5 document would then start like this:
<cfcontent type="text/html; charset=utf-8" reset="true" /><!doctype html>
XML document:
<cfcontent reset="yes" type="text/xml; charset=utf-8" /><CFOUTPUT>#VariableHoldingXmlDocAsString#</CFOUTPUT>
This way you won't get the "Content is not allowed in prolog"-error for XML docs.
If you are getting unwanted whitespaces from a function use the output-attribute to suppress any output and return your result as string - for example:
<cffunction name="getMyName" access="public" returntype="string" output="no">
<cfreturn "Seybsen" />
</cffunction>
You can modify the ColdFusion output by getting access to the ColdFusion Outpout Buffer. James Brown recently demo'd this at our user group meeting (Central Florida Web Developers User Group).
<cfscript>
out = getPageContext().getOut().getString();
newOutput = REreplace(out, 'regex', '', 'all');
</cfscript>
A great place to do this would be in Application.cfc onRequestEnd(). Your result could be a single line of HTML which is then sent to the browser. Work with your web server to GZip and you'll cut bandwidth a great deal.
In terms of tags, there is cfsilent
In the administrator there is a setting to 'Enable whitespace management'
Futher reading on cfsilent and cfcontent reset.
If neither <cfsilent> nor <cfsetting enablecfoutputonly="yes"> can satisfy you, then you are probably over-engineering this issue.
When you are asking solely out of aesthetic reasons, my recommendation is: Ignore the whitespace, it does not do any harm.
Alternatively, You can ensure your entire page is stored within a variable and all this processing is done within cfsilent tags. e.g.
<cfsilent>
<!-- some coldfusion -->
<cfsavecontent variable="pageContent">
<html>
<!-- some content -->
</html>
</cfsavecontent>
<!-- reformat pageContent if required -->
</cfsilent><cfoutput>#pageContent#</cfoutput>
Finally, you can perform any additional processing after you've generated the pagecontent but before you output it e.g. a regular expression to remove additional whitespace or some code tidying.
Here's a tip if you use CFC.
If you're not expecting your method to generate any output, use output="false" in <cffunction> and <cfcomponent> (not needed only if you're using CF9 script style). This will eliminate a lot of unwanted whitespaces.
If you have access to the server and want to implement it on every page request search for and install trimflt.jar. It's a Java servlet filter that will remove all whitespace and line breaks before sending it off. Drop the jar in the /WEB-INF/lib dir of CF and edit the web.xml file to add the filter. Its configurable as well to remove comments, exclude files or extensions, and preserve specific strings. Been running it for a few years without a problem. A set it and forget it solution.
I've found that even using every possible way to eliminate whitespace, your code may still have some unwanted spaces or line breaks. If you're still experiencing this you may need to sacrifice well formatted code for desired output.
for example, instead of:
<cfprocessingdirective suppressWhiteSpace = "true">
<cfquery ...>
...
...
...
</cfquery>
<cfoutput>
Welcome to the site #query.userName#
</cfoutput>
</cfprocessingdirective>
You may need to code:
<cfprocessingdirective suppressWhiteSpace = "true"><cfquery ...>
...
...
...
</cfquery><cfoutput>Welcome to the site #query.UserName#</cfoutput></cfprocessingdirective>
This isn't CF adding whitespace, but you adding whitespace when formatting your CF.
HTH
I am using <cfdocument> tag of coldfusion 7. Using CFEclipse and working on MacOS.
I have written the following code:
<cfdocument format="pdf">
SitePoint.com - Introduction to ColdFusion 7
PDF Generation
This is an example of PDF generation using ColdFusion 7.
</cfdocument>
But instead of asking me to save this file in .pdf format, its trying to open it in .cfm format.
How can I save it in .pdf format? Thanks!
Unless you tell it otherwise, the webserver returns the results of a CFM call as text. You need to use CFContent with CFHeader to alert the browser that the results it will be recieving are of a different type. Something like:
<cfheader name="Content-Disposition" value="inline; filename=document.pdf">
<cfcontent type="application/x-pdf">
<cfdocument>...</cfdocument>
I may have the MIME type wrong there. I'm doing this from memory. Check the docs for more help.
If you are on CF8 or higher then use the saveAsName attribute:
<cfdocument saveAsName=""
Either that or the method suggested by Ben above should work
You might also need to import the style sheet as well. So you can get the desired formatting. It needs to be imported after cfdocument.
<cfdocument
format="pdf"
filename = "canwriteurfile.pdf"
overwrite = "yes"
marginBottom = ".2"
marginLeft = ".4"
marginRight = ".4"
marginTop = ".2">
<style type="text/css">#import "pdf.css";</style>
BLAHHH BLAHHH PDF FORMATTING STUFF
</cfdocument>
Try:
<cfdocument format="PDF" name="myPDF">
<html>
<body>
SitePoint.com - Introduction to ColdFusion 7
PDF Generation
This is an example of PDF generation using ColdFusion 7.
</body>
</html>
</cfdocument>
<cfpdf action = "write" destination = "pdf_path" source = "myPDF" overwrite = "yes"/>
<cflocation url="pdf_path"/>
Whis this you save the PDF on disk