I am creating a PDF document using ColdFusion cfdocument tag. Works fine, however instead of showing the document name in browser Title - it shows the .cfc file that I call to create the PDF.
Here is how I'm calling it.
<cfdocument format="pdf" marginbottom=".5" margintop=".25" marginright=".5" marginleft=".5" saveAsName="#filename#.pdf">
<cfdocumentitem type="footer">
<p style="font-size:11px; text-align:right; font-style:italic;">Page #cfdocument.currentpagenumber# of #cfdocument.totalpagecount#</p>
</cfdocumentitem>
<html>
<head><title>#filename#.pdf</title></head>
<body><img src="file:///#application.tempFolder#\#thisFilename#" /></body>
</html>
</cfdocument>
What the heck am I missing? Why does it still show the filename.cfc file that I'm calling in the browser title instead of the filename I give to the PDF???
Figured it out. Had to create the document using CFDOCUMENT, then add a "Title" attribute to it using the CFPDF tag. Then output it to the browser.
<!--- Create the PDF --->
<cfdocument format="pdf" marginbottom=".5" margintop=".25" marginright=".5" marginleft=".5" filename="#application.tempFolder#\#thisSaveAsFilename#" overwrite="yes">
<cfdocumentitem type="footer">
<p style="font-size:11px; text-align:right; font-style:italic;">Page #cfdocument.currentpagenumber# of #cfdocument.totalpagecount#</p>
</cfdocumentitem>
<html>
<head><title>#thisSaveAsFilename#</title></head>
<body><img src="file:///#application.tempFolder#\#thisFilename#" /></body>
</html>
</cfdocument>
<!--- Use CFPDF to add attributes to it --->
<cfset thisInfo = StructNew()>
<cfset thisInfo.Title = "pdf title goes here...">
<cfpdf action="setinfo" info="#thisInfo#" source="#application.tempFolder#\#thisSaveAsFilename#" />
<!--- Send it to the browser --->
<cfcontent file="#application.tempFolder#\#thisSaveAsFilename#" type="application/pdf" />A
How can I create a pop up that allows the user to "open with" or to save file as when dealing with coldfusion pdf's?
I am trying to figure out how to create it when this form is not actually mine and I am just using and prefilling a form that already exists.
<cfpdfform source="82040.pdf" action="populate">
<cfpdfformparam name="cust ##" value=""> <!---Section1 Customer Number--->
</cfpdfform>
I was able to create this pop up by doing something like this:
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/pdf">
<cfheader name="Content-Disposition" value="attachment;filename=test.pdf">
<cfdocument format="PDF" localurl="yes"
marginTop=".25" marginLeft=".25" marginRight=".25" marginBottom=".25"
pageType="custom" pageWidth="8.5" pageHeight="10.2">
<cfoutput><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>PDF Export Example</title>
</head>
<body>
</body>
</html>
</cfoutput>
</cfdocument>
But am not sure how I can combine these two. Any help is greatly appreciated!
Per Request What I have tried:
<cfset tempFilePath = "c:/path/to/someUniqueFileName.pdf">
<cfpdfform source="82040.pdf" action="populate" destination="#tempFilePath#">
<cfpdfformparam name="org" value="Yes"> <!---Above Section1 Original ---> <!---On--->
</cfpdfform>
<cfheader name="Content-Disposition" value="attachment;filename=Testme.pdf">
<cfcontent type="application/pdf" file="#tempFilePath#" deleteFile="false">
By default, cfpdfform renders the result in the browser ie "inline". To return it as an attachment instead, save the content to a file or a variable. Then use cfheader/cfcontent to return it as an attachment.
File:
Use the "destination" attribute to save it to a file. To avoid conflicts with other threads be sure use unique file names. To automatically remove the temporary file when finished, set deleteFile="true"
<cfset tempFilePath = "c:/path/to/someUniqueFileName.pdf">
<cfpdfform source="82040.pdf" action="populate" destination="#tempFilePath#">
...
<cfheader name="Content-Disposition" value="attachment;filename=test.pdf">
<cfcontent type="application/pdf" file="#tempFilePath#" deleteFile="false">
Variable:
Use the "name" attribute to save the content to a variable. Though "name" is not listed in the documentation, this bug report suggests it is just a documentation error.
<cfpdfform source="82040.pdf" action="populate" name="pdfContent">
... etcetera ...
<cfheader name="Content-Disposition" value="attachment;filename=test.pdf">
<cfcontent type="application/pdf" variable="#toBinary(pdfContent)#">
Update: I'm rewriting with all my code for each page as well as my error message... keep in mind I am very new and honestly don't know some of this code...
productlist.cfm 1st page: (hard coded product list code built from select statement)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/style.css" type="text/css" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/style.css" type="text/css" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/bootstrap.css" type="text/css" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/bootstrap-theme.min.css" type="text/css" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/bootstrap.min.css" type="text/css" />
<script type = "text/javascript" src="http://students.uwf.edu/jeb48/week8/assignments/scripts/jbrown.js"></script>
<script type = "text/javascript" src="http://students.uwf.edu/jeb48/week8/assignments/scripts/jbrown2.js"></script>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type = "text/javascript" src = "http://code.jquery.com/jquery-latest.js" ></script>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<title>Scuba Diving is Fun!</title>
</head>
<body>
<div class="container">
<cfquery name = "getlist" datasource="jeb48_shoppingcart">
SELECT ProductID, ProductName, ProductQty, ProductPrice, ProductDescription, ProductPhoto
FROM Products;
</cfquery>
<div class="row">
<div class="col-md-2"><b>Product Photo</b></div>
<div class="col-md-2"><b>Product ID</b></div>
<div class="col-md-2"><b>Product Name</b></div>
<div class="col-md-2"><b>Quantity in Inventory</b></div>
<div class="col-md-2"><b>Product Description</b></div>
<div class="col-md-2"><b>Unit Price</b></div>
</div !--row>
<cfoutput query ="getlist">
<div class="row equallist">
<div class="col-md-2">#getlist.ProductPhoto#</div>
<div class="col-md-2">#getlist.ProductID#</div>
<div class="col-md-2">#getlist.ProductName#</div>
<div class="col-md-2"><div style="text-align:center">#getlist.ProductQty#</div></div>
<div class="col-md-2"><div style="text-align:left">#getlist.ProductDescription#</div></div>
<div class="col-md-2"><div style="text-align:left">#DollarFormat(getlist.ProductPrice)#
<cfif #getlist.ProductQty# gt 0>
<br>Add to Cart
<cfelse>
<br>Out of Stock!
</cfif>
</div></div>
</div !--row>
</cfoutput>
</div !--container>
</body>
</html>
scart.cfm Page 2: This is the page I'm having trouble with... I know my code is messed up but I do not know how to fix it... the error I'm getting is on this page... the error is "Parameter validation error for the ARRAYAPPEND function." I'm trying to build a cart based on the link in the previous page.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/style.css" type="text/css" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/bootstrap.css" type="text/css" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/bootstrap-theme.min.css" type="text/css" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/bootstrap.min.css" type="text/css" />
<link rel="stylesheet" href="http://students.uwf.edu/jeb48/css/style.css" type="text/css" />
<script type = "text/javascript" src="http://students.uwf.edu/jeb48/week8/assignments/scripts/jbrown.js"></script>
<script type = "text/javascript" src="http://students.uwf.edu/jeb48/week8/assignments/scripts/jbrown2.js"></script>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type = "text/javascript" src = "http://code.jquery.com/jquery-latest.js" ></script>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<title>Scuba Diving is Fun!</title>
</head>
<body>
<div class="container">
<h3><center>Your Shopping Cart</center></h3>
<cfparam name="url.productid" default="">
<cfparam name="url.qty" default="">
<cfquery name = "getCartItem" datasource="jeb48_shoppingcart">
SELECT ProductID, ProductName, ProductQty, ProductPrice, ProductDescription, ProductPhoto
FROM Products
WHERE ProductID = #url.productid#;
</cfquery>
<cfset arrShoppingCart = arrayNew(1) />
<cfparam name="session.cart" default="arrayNew()">
<cfset arrayAppend( "session.cart", structNew() )>
< cfset session.cart = arrayNew(1) >
< cfset thisCartItem = arraylen( session.cart )>
<cfset arrayAppend( session.cart, structNew() )>
< cfset thisCartItem = arraylen( session.cart )>
< cfset session.cart[thisCartItem].itemID = url.productid>
< cfset session.cart[thisCartItem].quantity = url.qty>
</body>
</html>
application.cfc
<cfcomponent>
<cfset this.name = "jeb48SC">
<cfset this.datasource = "jeb48_shoppingcart">
<cfset this.loginstorage="Session">
<cfset this.sessionmanagement="Yes">
<cfset this.sessiontimeout="#createtimespan(0,0,45,0)#">
</cfcomponent>
Once I get this working I can begin working on getting the output built... thanks for taking a look.
The details of the question have significantly changed, so editing my answer.
1: <cfset arrShoppingCart = arrayNew(1) />
2: <cfparam name="session.cart" default="arrayNew()">
3: <cfset arrayAppend( "session.cart", structNew() )>
4: < cfset session.cart = arrayNew(1) >
5: < cfset thisCartItem = arraylen( session.cart )>
6: <cfset arrayAppend( session.cart, structNew() )>
7: < cfset thisCartItem = arraylen( session.cart )>
8: < cfset session.cart[thisCartItem].itemID = url.productid>
9: < cfset session.cart[thisCartItem].quantity = url.qty>
There are a few problems with this code. I'll ignore the spaces after some opening brackets, you're clearly experimenting and canceling out some experiments.
On line 2, you're not creating an array, you're creating a string with the default value of "ArrayNew()". You need to add hashes around each end. "#ArrayNew()#".
On line 3, you have the array name quoted, which is invalid. Most cold fusion functions that require a variable name, want it unquoted. Some exceptions are StructkeyExists() and isDefined(), which serve similar purposes. They check if a variable exists so they ask for the variable name as a string, rather than raw.
Line 4, this is how you properly set an array. Good Job. The only thing is every time someone visits this page, this happens. This line should be when a session is first initiated and it should go something like this <cfif not isDefined("session.cart")><cfset session.cart=ArrayNew(1)></cfif>.
As I said before, you need to maintain data types across your application. One quick fix is to address your code problems and then create a page that has nothing but this <Cfset structclear(session)>. That gets rid of all your old session data.
You're on the right track after this. It can be tough when you're trying to debug something that you don't (yet!) understand several aspects of, but you'll get it.
Okay something else we need to talk about. You're new to CF? That's great, time to start an important habit early.
Any Time you're using a #variable# in a query, use a tag called <cfqueryparam. There's a mischievious thing called SQL injection, where a user can modify a url to cause havoc on the website. This tag is your primary defense against this
(There are occasions where some people don't feel it's necessary but you really cannot over-param your variables and as you're new, it's better to be safe than sorry).
Suppose I'm on scart.cfm?productID=7. If I change the url to scart.cfm?productID=7; DROP TABLE Products, your products table disappears. Or maybe I just want cheap goodies. scart.cfm?productID=7; UPDATE Products SET PRICE = 1 (I'd have to guess at column names here), but I could reset all your product prices.
Further CFQueryParam makes your queries slightly faster, and one of my favorite parts, is that when you provide the type, it handles the quoting for you.
Adobe was a bit silly when designing the tag and it's a little long-winded, but you get used to it.
You query above should look like this:
<cfquery name = "getCartItem" datasource="jeb48_shoppingcart">
SELECT ProductID, ProductName, ProductQty, ProductPrice, ProductDescription, ProductPhoto
FROM Products
WHERE ProductID = <cfqueryparam cfsqltype="cf_sql_integer" value="#url.productID#">
</cfquery>
Oh, because you're using this.datasource in application.cfc, providing a datasource here is not necessary. so your queries can just look like, which makaes your application more mobile.
<cfquery name="..."> or <cfquery> for queries where name isn't useful.
If you ever find yourself using additional datasources, you can store their names in the request scope, and then you can reference them like datasource="#request.db1#" or #request.db2#', etc. There are some applications people have designed that might have particular users using different databases so they have setups like #session.db#.
If I was searching for something by say a string value, the where could look like this WHERE ProductID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#form.productName#'>
See, the tag takes care of the quoting, and it lets other developers know your data types at a glance.
In the future, please provide more of the error.
From what you've shown, it looks like either:
A cfparam declares session.sCartItems somewhere, probably as a basic string. (<cfparam name="session.sCartItems" default=""> which basically just says, "If not defined, define it". In other words, a cfparam on a variable will make an isDefined() check pass.
In development, you've formerly declared session.sCartItems as a string, and that action is still alive. If that is the case, the not-isDefined() check fails, and the variable is not re-set as an array.
You should resolve the source of this problem. Data types of variables should remain consistent across your application, otherwise you will always constantly be trying to check data types.
However, changing this should bandaid-fix your problem.
<cfif not isDefined("session.scartItems")>
to:
<cfif not isDefined("session.scartItems") or not isArray(session.sCartItems)>
The way this is works is if your variable is not defined, the check stops there. If you variable is defined, the check continues to verify that it is an array.
I am using cfcontent for creating a Word Document.
Example :
<cfsavecontent variable="sStr">
part1
part2
part3
</cfsavecontent>
<cfheader name="content-disposition" value="attachment; filename=wordDoc.doc">
<cfcontent type="application/msword" variable="#sStr#">
I want page break after each part.
The output should be in landscape format. How can I do this?
For a page break you should be using:
<cfdocumentitem type="pagebreak" />
And landscape you can set by:
<cfdocument orientation = "portrait|landscape>
As far as I know it's not possible to change the orientation of an individual page.
For cfcontent of a file you've saved to create an MS Word document:
<br clear=3Dall style=3D'page-break-before:always;mso-break-type:section-break'>
Got Page orientation to work with ms word by using the following style and making sure in cfcontent reset="no";
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<title>Work Order Report</title>
<style>
#page Section1
{ size:11.0in 8.5in;
mso-page-orientation:landscape;
}
body.section1 {page:section1;}
</style>
<body class="section1">
<cfcontent type="application/msword" reset="no">
I have an test.cfm where I dynamically build a pdf-File and output it with <cfheader> and <cfcontent> to the browser, but I still want the page to load and show "test html":
<CFFILE action="readbinary" file="#expandpath("./test.cfm")#" variable="testcontent" />
<CFHEADER name="Content-Disposition" value="attachment; filename=""test.txt""; charset=utf-8">
<CFCONTENT type="text/plain" reset="yes" variable="#testcontent#">
<CFCONTENT type="text/html" reset="yes" /><!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Testdoc</title>
</head>
<body>test html</body>
</html>
(outputting the file itself is just for the example)
Is there a way to accomplish this?
You can't trigger what happens after a download, but you can do it the other way round - load the page you want, then redirect to the file to download using a HTML meta redirect:
<meta http-equiv="refresh" content="5; url=http://domain.com/path/to/download" />
(If necessary, you can use cfhtmlhead to insert that into the relevant part of an existing HTML page.)
The 5 is the number of seconds to wait - setting to 0 will redirect immediately. (When using with other pages, using an instant redirect can cause issues with the back button; should be less of an issue for downloads though.)