cffile not working at all - coldfusion

cffile is giving a head ache now.
My cfm is like this -
`
<cfif session.ismac and session.browsermake eq "firefox">
<cfset size = "55">
</cfif>
<cfset onChange = "document.frmMain.submit1.disabled = true;setdisplayname(this,this.form.dummy);">
<cfif displayname EQ "">
<cfset size = "document.frmMain.submit1.disabled = true;setdisplayname(this,this.form.displayname);">
</cfif>
<cfinput type="file" name="File#thisUploader#" id="File#thisUploader#" size="#size#" onKeyPress="return false;" onchange="#onChange#">
`
and in my cfc the code is like this -
<cffile accept="image/*" action="upload" destination="#application.artworkfilepath#\bulkuploads\#session.loginname#\#form.category#\" filefield="form.File#thisUploader#" nameconflict="makeunique">
and if I dump - <cfoutput>
You uploaded #cffile.ClientFileName#.#cffile.ClientFileExt#
successfully to #cffile.ServerDirectory#.
</cfoutput>
<cfabort>
I get corrct things and no error.
But when i look into the folder there is nothing.
Anyidea? I have added the dump of cffile now. What do you make out of it?
cfform code is like this <cfform id="frmMain" name="frmMain" action="process_multi.cfm" enctype="multipart/form-data" target="_self" method="post">

do a fileExists() directly after the statement and let us know what that says...
you don't have a directorywatcher on the directory do you?

Your cffile nameconfict attribute is set to makeunique, which tells ColdFusion to rename the file to something new when it arrives at the server--if the file already exists.
However, you are using cffile.ClientFileName and cffile.ClientFileExt to refer to the file file--which maps to the unchanged file name as it was received during upload.
Change your code references to cffile.ServerFileName and cffile.ServerFileExt for the final renamed result.

Related

ColdFusion: how to get the filename of failed upload

I am trying to put the filename of a failed upload into an email, inside a try / catch, but I am not having any luck.
Based on this documentation - FileUploadAll() - I decided I am going to use error.
<cftry>
<cffile destination="#FULLPATH#" action="upload" nameconflict="ERROR" continueOnError="true" filefield="FileName" />
<cfcatch type="Any" >
<cf_EmailHandler from="testmail#gmail.com" to="testmail#gmail.com" subject="Attachment Error - #BUILD_SEARCH.PROJECT_VERSION# #BUILD_SEARCH.BUILD_NUMBER#">
<CFOUTPUT>
Attachment Error - #BUILD_SEARCH.PROJECT_VERSION# #BUILD_SEARCH.BUILD_NUMBER#
Cannot upload the following file:
#FULLPATH# #ArrayLen(cffile.uploadAllErrors)#
</CFOUTPUT>
</cf_EmailHandler>
<b>Error:</b>File already exists.
<cfabort>
</cfcatch>
</cftry>
I get the following error:
Element UPLOADALLERRORS is undefined in CFFILE
So I try to fix that:
<cftry>
<cffile destination="#FULLPATH#" action="upload" nameconflict="ERROR" Errors="errorResult" continueOnError="true" filefield="FileName" />
<cfcatch type="Any" >
<cf_EmailHandler from="testmail#gmail.com" to="testmail#gmail.com" subject="Attachment Error - #BUILD_SEARCH.PROJECT_VERSION# #BUILD_SEARCH.BUILD_NUMBER#">
<CFOUTPUT>
Attachment Error - #BUILD_SEARCH.PROJECT_VERSION# #BUILD_SEARCH.BUILD_NUMBER#
Cannot upload the following file:
#FULLPATH# #ArrayLen(errorResult.uploadAllErrors)#
</CFOUTPUT>
</cf_EmailHandler>
<b>Error:</b>File already exists.
<cfabort>
</cfcatch>
</cftry>
Then I am getting:
Element UPLOADALLERRORS is undefined in ERRORRESULT.
Any idea on what I am doing wrong or another way to display the name of failed upload? Also I am using ColdFusion 11.
Update:
Bug report CF-4204290 currently lists this issue as "To Fix".
TL;DR;
It's a documentation bug. The continueOnError attribute isn't supported with action=upload. Use action=uploadAll instead. Keep in mind "uploadAll" supports multiple files, so results will be returned as an array of structures.
The reason it's not working is because the code is using the wrong "action". It should be action="uploadAll". Since you're using continueOnError="true", CF populates a structure with any errors that occur. By default it uses CFFILE, but you can specify a different variable name by using the errors attribute.
<cffile destination="c:/some/path/"
action="uploadAll"
nameconflict="ERROR"
continueOnError="true"
filefield="file_path" />
Update:
As pointed out in the comments, the documentation does saycontinueOnError is a supported attribute for action=upload. However, IMO it's a documentation bug. Adobe probably just copied the text from the action=uploadAll description.
Interestingly, the documentation for FileUpload(), doesn't list that attribute at all. Bug report CF-4199503 confirms the function version doesn't support it. Based on my tests below with CF11 and CF2016, I've concluded it's not supported in either version.
Test Action=UploadAll
Uploading a file that already exists in the destination directory, doesn't cause a hard error. CF populates the specified variable with error details and dumps them on screen:
<cfif structKeyExists(FORM, "submit")>
<cffile destination="c:/temp"
action="uploadAll"
nameconflict="ERROR"
continueOnError="true"
errors="myErrors"
filefield="file_path" />
<cfdump var="#cffile#" label="cffile">
<cfdump var="#myErrors#" label="errors">
</cfif>
<form method="POST"
enctype="multipart/form-data">
<input type="file" name="file_path">
<input type="submit" name="test">
</form>
Results:
Test Action=Upload
Change the action to action="upload" and the code fails. ColdFusion does NOT:
Continue processing after the error .. or
Populate cffile with error information ... or
Create a result variable named by the errors attribute
Results:
Note, omitting the optional errors attribute produces the same results. It works as expected when using action=uploadAll and fails with an error when using action=upload
In the form page, I captured the filename using JavaScript
<Input Name="FileName" type="file" size="#TEXT_AREA_WIDTH#"><br><br>
<Input type="Hidden" id="READ_FILE_NAME" name="READ_FILE_NAME" value="">
<Input type="Submit" name="Operation" value="Save" onclick="return validateAttachmentForm(this.form.FileName.value)">
function validateAttachmentForm(file_name)
{
if (file_name.lastIndexOf("\\" != -1)) {
var file_name = file_name.substring(file_name.lastIndexOf("\\") + 1, file_name.length);
}
document.getElementById("READ_FILE_NAME").value = file_name;
if(file_name != "")
{
return true;
} else{
alert('Please select a file to upload.')
return false;
}
}
In the next page, I just display the filname passed in
<cftry>
<cffile destination="#FULLPATH#" action="upload" nameconflict="ERROR" Errors="errorResult" continueOnError="true" filefield="FileName" />
<cfcatch type="Any" >
<cf_EmailHandler from="testmail#gmail.com" to="testmail#gmail.com" subject="Attachment Error - #BUILD_SEARCH.PROJECT_VERSION# #BUILD_SEARCH.BUILD_NUMBER#">
<CFOUTPUT>
Attachment Error - #BUILD_SEARCH.PROJECT_VERSION# #BUILD_SEARCH.BUILD_NUMBER#
Cannot upload the following file:
#FULLPATH#\#form.READ_FILE_NAME#
</CFOUTPUT>
</cf_EmailHandler>
<b>Error:</b>File already exists.
<cfabort>
</cfcatch>
</cftry>

Picture Preview page in coldfusion

I know how to upload an image file to a server and show the image file to a page.
But what if I want a preview on a confirmation page?
I can probably generate a temp file that isn't saved in the database but is a file in a physical location, but what if I decided to hit the "no" button. How would this temp file be deleted?
The code below shrinks the image and shows it on the page. But it also creates an image within the directory, that will stay there after I hit OK or NO. The NO is button, while the OK naturally is a submit.
<!--- Make Temp Image as Preview --->
<cfset mediapath = expandpath('../images/about')>
<cfif structKeyExists(form,"image") and len(form.image)>
<cffile action="upload"
filefield="image"
destination="#MediaPath#"
nameconflict="makeunique">
<cfimage name="uploadedImage"
source="#MediaPath#/#file.serverFile#" >
<cfset imagesize = 320>
<cfif uploadedImage.width gt uploadedImage.height>
<cfset percentage = (imagesize / uploadedImage.width)>
<cfelse>
<cfset percentage = (imagesize / uploadedImage.height)>
</cfif>
<cfset newWidth = round(uploadedImage.width * percentage)>
<cfset newHeight = round(uploadedImage.height * percentage)>
<!--- Show Image --->
<cfoutput>
<img src="../images/about/#file.serverFile#" style="height:#newHeight#; width:#newWidth#;">
I assume I may have to do URL Passing or do some sort of CFScript. On the Return buttons Onclick event.
Here is my approach take it for what you will.
Ok this is probably more than you need but this should get you somewhere on this image delete problem thing.
Here is your code. But I broke it into two pages. Of course I cannot see what else is going on this page and your form handling stuff so we will start with what you are giving us.
<cfset mediapath = expandpath('../images/about')>
nice use of structKeyExists() :)
<cfif structKeyExists(form,"image") and len(form.image)>
Here I would pause and suggest you limit
your uploads to just .gif, .jpeg, .jpg, .png
(your main image types) to prevent uploading any
and everyfile type. I added an accept parameter below.
<cffile action="upload"
filefield="image"
destination="#MediaPath#"
nameconflict="makeunique"
accept="image/*">
<cfimage name="uploadedImage"
source="#MediaPath#/#file.serverFile#" >
Ok the file is uploaded lets seperate concerns
At this point I would ask them if they want to preview the file. If they click 'preview' take them to a preview.cfm page.
Then you have a file name you need to pass if you have nothing else (like an ID or some primary key).
So I pulled this handy-dandy script out of the Adobe Coldfusion docs on their website and I am going to use this to turn your filename into 'something else' ;)
<cfscript>
theKey="123abc";
theKey=generateSecretKey("AES")
superDuperSecretSoDontTell=encrypt(file.serverFile, theKey, "AES", "hex");
</cfscript>
Let's send this piggy!
and off you go to the preview page...
<cfoutput>
(pointing up) This is pageA.cfm
(pointing down) This is pageB.cfm
Now I have the rest of your code below and lets pull your file based on the pass through querystring variable/value pairs.
<cfscript>
IWannaKnowTheSecret=decrypt(url.fileName, url.theKey, "AES", "hex");
</cfscript>
Here I would pause and suggest you limit
your uploads to just .gif, .jpeg, .jpg, .png
(your main image types) to prevent uploading any
and everyfile type. I added an accept parameter below.
<cffile action="read" file="#MediaPath##IWannaKnowTheSecret#" variable="uploadedImage">
<cfset imagesize = 320>
Interesting handle here. So you are taking the
larger of the two values and using that
to percentage down the size. Neat.
<cfif uploadedImage.width GT uploadedImage.height>
<cfset percentage = (imagesize / uploadedImage.width)>
<cfelse>
<cfset percentage = (imagesize / uploadedImage.height)>
</cfif>
<cfset newWidth = round(uploadedImage.width * percentage)>
<cfset newHeight = round(uploadedImage.height * percentage)>
Then do a form like this:
<form action="" method="post" enctype="multipart/form-data">
Your current Image:
<cfoutput>
Name: #uploadedImage#<br>
<img src="../images/about/#uploadedImage#" style="height:#newHeight#; width:#newWidth#;">
</cfoutput>
Do you want to remove this?<br>
<input type="checkbox"
name="removeImage"
value="1" />: Remove the logo image</cfif><br />
Wnat to replace your image?<br>
<input type="file" name="replacementImage"> (
<input type="hidden"
name="uploadedImage"
value="<cfoutput>#uploadedImage#</cfoutput>">
<input type="submit" value="submit" name="submit"
</form>
Cancel and go back
If they continue and want to fix the image or replace it. Submit then you can use something like this.
Then we delete...
And if the replacementImage file filed is populated then we add that file.
And there you have it...
You are seperating some concerns.
You are giving improved options.
You are allowing a change or no change.
You are giving them an out to go back to where ever you want.
Edit: Here is proof for the encoding and decoding stuff (if you wanted to play with it:
<cfscript>
theKey="123abc";
theKey=generateSecretKey("AES");
superDuperSecretSoDontTell=encrypt("monkeytoots", theKey, "AES", "hex");
</cfscript>
<cfoutput>Let's send this piggy!</cfoutput>
<cfif isdefined("url.fileName") and isdefined("url.theKey")>
<cfscript>
IWannaKnowTheSecret=decrypt(url.fileName, url.theKey, "AES", "hex");
</cfscript>
<cfoutput>
#IWannaKnowTheSecret#
</cfoutput>
</cfif>
This answer is in response to Adam Cameron's comment. It illustrates some potentially unexpected results that can occur with two submit buttons. Start with this code.
<cfdump var="#form#">
<form action="abc.cfm" method="post">
<input type="text" name="text1" />
<input type="submit" name="submit1" value="no" />
<input type="submit" name="submit2" value="yes" />
</form>
The default behaviour of most, if not all browsers is that there are occasions whereby a form will be submitted when the user presses the enter key. What would you expect to see with this form if you had your curser in the text box and pressed Enter? Try it and see if you were right.

ColdFusion searching robots.txt for specific page exception

We're adding some functionality to our CMS whereby when a user creates a page, they can select an option to allow/disallow search engine indexing of that page.
If they select yes, then something like the following would apply:
<cfif request.variables.indexable eq 0>
<cffile
action = "append"
file = "C:\websites\robots.txt"
output = "Disallow: /blocked-page.cfm"
addNewLine = "yes">
<cfelse>
<!-- check if page already disallowed in robots.txt and remove line if it does --->
</cfif>
It's the <cfelse> clause I need help with.
What would be the best way to parse robots.txt to see if this page had already been disallowed? Would it be a cffile action="read", then do a find() on the read variable?
Actually, the check on whether the page has already been disallowed would probably go further up, to avoid double-adding.
You keep the list of pages in database and each page record has a indexable bit, right? If yes, simpler and more reliable approach would be to generate new robots.txt each time some page is added/deleted/changes indexable bit.
<!--- TODO: query for indexable pages ---->
<!--- lock the code to prevent concurrent changes --->
<cflock name="robots.txt" type="exclusive" timeout="30">
<!--- flush the file, or simply start with writing something --->
<cffile
action = "write"
file = "C:\websites\robots.txt"
output = "Sitemap: http://www.mywebsite.tld/sitemap.xml"
addNewLine = "yes">
<!--- append indexable entry to the file --->
<cfloop query="getPages">
<!--- we assume that page names are not entered by user (= safe names) --->
<cffile
action = "append"
file = "C:\websites\robots.txt"
output = "Disallow: /#getPages.name#.cfm"
addNewLine = "yes">
</cfloop>
</cflock>
Sample code is not tested, be aware of typos/bugs.
Using the Robots.txt files for this purpose is a bad idea. Robots.txt is not a security measure and you're handing "evildoers" a list of pages that you don't want indexed.
You're much better off using the robots meta tag, which will not provide anyone with a list of pages that you don't want indexed, and gives you greater control of the individual actions a robot can perform.
Using the meta tags, you would simply output the tags when generating the page as usual.
<!--- dummy page to block --->
<cfset request.pageToBlock = "/blocked-page.cfm" />
<!--- read in current robots.txt --->
<cffile action="read" file="#expandPath('robots.txt')#" variable="data" />
<!--- build a struct of all blocked pages --->
<cfset pages = {} />
<cfloop list="#data#" delimiters="#chr(10)#" index="i">
<cfset pages[listLast(i,' ')] = '' />
</cfloop>
<cfif request.variables.indexable eq 0>
<!--- If the page is not yet blocked add it --->
<cfif not structKeyExists(pages,pageToBlock)>
<cffile action="append" file="C:\websites\robots.txt"
output="Disallow: #request.pageToBLock#" addNewLine="yes" />
<!--- not sure if this is in a loop but if it is add it to the struct for nex iteration --->
<cfset pages[request.pageToBlock] = '' />
</cfif>
</cfif>
This should do it. Read in the file, loop over it and build a struct of the bloocked pages. Only add a new page if it's not already blocked.

Search Folders in ColdFusion 9

I am trying to create a search method to attach files on my outbound emails. I need to search inside a folder and find all the files that begin with a certain character and then attach them to the email. I just need a head start on how you could create such a search method so any pointers or links to references will be appreciated.
This is What I have so far but it does not seem to work correct when I use a path instead of GetBaseTemplatePath()
<cfscript>
attributes.attachments = 2011093475839213;
</cfscript>
<cfset Directory = "E:\sites\Example.com\FileFolder\#attributes.attachments#">
<cfset CurrentDirectory=Directory>
<cfset CurrentDirectory=ListDeleteAt(CurrentDirectory,ListLen(CurrentDirectory,"/\"),"/\")>
<cfoutput>
<b>Current Directory:</b> #CurrentDirectory#
<br />
</cfoutput>
<cfdirectory action="list" directory="#CurrentDirectory#" name="result">
<cfdump var="#result#">
When I change the code slightly by
<cfset CurrentDirectory=GetBaseTemplatePath()>
My code works and I get the list of all the files in my current directory. Do I have a mistake on my path that I cannot see?
This is my CFMAIL part which I do have an issue with.
When I dump my #result# query I get all the files inside the folder. Then I get this error:
The resource 2011093475839213.pdf was not found.
The root cause was: ''.
I do receive an email despite the error, just not the attached files.
<!--- Email Test --->
<CFMAIL FROM="user1#example.com" TO="user2#example.com" SUBJECT="Test" type="HTML">
<P> This is the attachment test</P>
<p> For this test to be successful, we need to receive some file attachments with this email</p>
<cfloop query="result">
<cfmailparam file="#result.name#" disposition="attachment">
</cfloop>
</cfmail>
<!--- Email Test Ends --->
The cfdirectory tag will allow you to search through folder(s) with a specific pattern. Using the query it returns, you can loop over it and attach all the files you need to the email.
http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7f99.html
Something like this:
<cfdirectory action="list" directory="#myDirectory#" name="myDir">
<cfmail subject="My Subject" to="yourAddress" from="myAddress">
My Message
<cfsilent>
<cfloop query="myDir">
<cfif Left(myDir.name,1) eq "Z">
<cfmailparam file="#myDirectory & myDir.name#">
</cfif>
</cfloop>
</cfsilent>
</cfmail>

<cffile action="Read"> not getting the desired up-load loaction

I am using CF-8,windows-XP and IE 5.5.
I am using simple tag namely . but the output i am getting is pure gibberih along witht the text of the file(word document)
upld.cfm
<cffile action="read" file="C:\ColdFusion8\wwwroot\Proj\updl\fileDisk\SOL.doc" variable="fileDisk" >
<cfoutput>#fileDisk#
</cfoutput>
<cfoutput>
<form name="upload" method="post" action="actionUpld.cfm?form_Num=#form_Num#" enctype="multipart/form-data">
<input name="uplForm" id="uplForm" type="file" >
<input type="submit" name="submitUpld" value="Save" onclick="" >
</form>
</cfoutput>
actionUpld.cfm
<cftry>
<cfscript>
newUPL = CreateCFC('cfcs.projDB');
newUPL.Implementation_Num = url.form_Num;
newUPL.uplForm = form.uplForm;
newUPL.putUPL();
</cfscript>
<cfcatch type="any" >
<cfoutput >
<hr>
<h4>Other Error: #cfcatch.Type#</h4>
<li><b>Message:</b> #cfcatch.Message#
<li><b>Detail:</b> #cfcatch.Detail#
<li><b>Error Code:</b> #cfcatch.ErrorCode#
</cfoutput>
</cfcatch>
</cftry>
<cflocation url="upld.cfm??form_Num=#form_Num#" >
How best to use the cffile to output the file ?
Also when i look at the DB, i am getting the file name as
"C:\ColdFusion8\runtime\servers\coldfusion\SERVER-INF\temp\wwwroot-tmp\qeq344.tmp"
How to correct it?
Is there any better way.
Also when i look at the DB, i am
getting the file name as C:\ColdFusion8\runtime\servers\coldfusion\SERVER-INF\temp\wwwroot-tmp\qeq344.tmp
That is a temporary file name assigned to newly uploaded files. On your action page, you need to use cffile action="upload" ... to move that temporary file to the desired location. That will populate a structure called CFFILE with details about the uploaded file, such as CFFILE.serverFile and CFFILE.serverDirectory. (Or use the "result" attribute to output the details to whatever structure name you choose.)
How best to use the cffile to output
the file ?
You cannot display binary files (like *.doc) with cfoutput. To display/download such files in a browser use cfcontent