Can I use Coldfusions cffile action="upload" with an image destination url? - file-upload

I need to loop over a list of pathnames and image names and verify that the file exists and is a jpg/png, before changing it's size and storing it to the server.
I want to use this:
<cffile result="upload" action="upload" accept="image/jpeg, image/png" destination="#tempDirectory#" nameconflict="overwrite" />
<cfset testFilePath = tempDirectory & upload.serverFile>
<cfimage name="tempFile" action="read" source="#testFilePath#" />
<cfif NOT isImageFile( testFilePath ) >
<cfset fileDelete( testFilePath ) />
<cfthrow type="FileNotFound" message="#tx_settings_icons_error_img#" />
<cfelseif NOT listfindnocase(allow, upload.serverfileext) >
<cfset fileDelete( testFilePath ) />
<cfthrow type="FileNotFound" message="#tx_settings_icons_error_file#" />
</cfif>
But my problem is, I don't know how to upload a file from a path like
http://www.some.com/folder/image.jpg
Question:
Can I just read the image, perform my validation and then store to disk or do I need to upload the image first. I will have to loop through a list of 500 images and am reading cffile action="read" shouldn't be used with large files. What would be an alternative to check image files for correct type, isImageand file extension?

I generally use cfhttp to read the image and verify that I have it, then convert to a valid cfimage object and do my manipulations then. You can see my process in the answer to this question.

Use cfimage to read the file from a URL. Set the source to be that URL. Then, you can write that to disk locally.
Code example:
<cfset imageData = ImageRead("http://tutorial28.learncf.com/img/bgHead.png") />
<cfimage action="write" source="#imageData#" destination="#expandPath('test.png')#" />

Related

cfthread object empty inside of a cfthread tag in Lucee 5.2

In Lucee v5.2.9.31, the following code throws an error inside of the checkTest thread when I request the status of the test_thread thread from the cfthread object. The error I get is key [test_thread] doesn't exist.
<cfthread action="run" name="test_thread">
<cfloop index='i' from='1' to='50'>
<cffile action="append" file="./test_thread.txt" addNewLine="yes" output="Index: #i#" />
<cfset sleep(500) />
</cfloop>
</cfthread>
<cfthread action="run" name="checkTest">
<cfset test_thread_complete = false />
<cfloop condition="test_thread_complete eq false">
<cfset test_thread_status = cfthread['test_thread'].status />
<cffile action="append" file="./checkTestThread.txt" addNewLine="yes" output="#test_thread_status#" />
<cfif test_thread_status eq 'COMPLETED'>
<cfset test_thread_complete = true />
</cfif>
<cfset sleep(1000) />
</cfloop>
</cfthread>
<cfdump var="#cfthread#" />
<cfdump var="#cfthread['test_thread']#" />
However in an older version of Lucee (v4.5.5.015), the code works as expected and generated 2 files: test_thread.txt with the incrementing index, and checkTestThread.txt which contains the status of test_thread.
In both versions, the cfdumps return the cfthread object. The first dump contains both threads and the 2nd dump contains just the test_thread object as expected.
Is this a bug in Lucee 5 or was the code exploiting a bug in earlier versions of Lucee/Railo?
This was caused by an update that was made to Lucee.
According to Michael Offner (The maintainer of Lucee):
The reason is this no longer works in Lucee, because we added support
of having threads inside threads, since then "cfthread" only shows the
children of the current thread, in a tree (see key "childThreads"
inside "cfthread"). We cannot show all threads on one level that would
create a mess, because we would show the tree of threads at the same
time.
Issue is fixed in v5.3.4.37, however the code will need to be updated as their solution adds a threadData function which returns the root cfthread object.
In my code changing the following: <cfset test_thread_status = cfthread['test_thread'].status /> to <cfset test_thread_status = threadData()['test_thread'].status /> fixes the error and properly returns the status of a sibling thread.
More Information:
Git commit of the fix: https://github.com/lucee/Lucee/commit/576ff5f7e2556c1cc8298154d40006a158da9270
Jira Issue: https://luceeserver.atlassian.net/browse/LDEV-2150

cf9 cffileupload - uploads file but progress par shows error

I am having issues with the cffileupload function in ColdFusion9. I when I select upload, it uploads the first files to the correct location, but the progress bar shows in red and says error. If I hit upload again, it does the exact same thing with the next file. In the browse console it shows Status: 500. I have googled this issue and have not found a answer. Has anyone been able to get this to work correctly?
submission.cfm:
<cfset session.myuploadroot = "\\coldfusion\devl\uploads\cfeis_redbook\">
<form action="submission.cfm" method="post">
<cffileupload extensionfilter="xls,xlsx,doc,docx,pdf" name="bfiles" maxfileselect="3" title="Portfolio Images" url="fileupload.cfm?#urlEncodedFormat(session.urltoken)#" oncomplete="handleComplete">
</form>
fileupload.cfm
<cfif structKeyExists(form, "filedata")>
<cffile action="upload" filefield="filedata" destination="#session.myuploadroot#" nameconflict="overwrite" result="result">
</cfif>
<cfset str.STATUS = 200>
<cfset str.MESSAGE = "passed">
<cfoutput>#serializeJSON(str)#</cfoutput>

Storing file name when uploading using Coldfusion

I am trying to store the filename of the selected file to be uploaded into a hidden input field on the form. my form looks like this
<form id="uploadattachment" enctype="multipart/form-data"
method="post" action="/governance/attachmentfilestore">
<cfif isDefined("fileUpload")>
<cffile action="upload"
fileField="fileUpload"
accept="application/pdf"
nameconflict="makeunique"
destination="#ExpandPath( '/files/governance/upr/' )#">
<input type="hidden" name="filename" id="filename" value="">
<input type="hidden" readonly id="uprUUID" name="uprUUID"
style="width: 400px" value="<cfoutput>#params.key#</cfoutput>"/>
<input type="hidden" readonly id="status" name="status"
style="width: 400px" value="1"/>
<input name="fileUpload" type="file" style="width: 200px;" />
<button type="submit" name="action"
class="submitBtn primary rightSubmitBtnSpace">Upload</button>
</form>
This is then sent to the controller which writes it to the database how ever I cannot work out a way to get the name of the file to store in the "filename" field.
Does anyone have a solution on how you can populate a field with the name of the file that is selected to be uploaded?
I have added the CFFILE.serverFile in and it worked once, but I'm guessing thats because it grabbed the previously uploaded files name.
Now when loading the page I get Serverfile is undefined in CFFILE and so it does not let me populate the form with the files name.
My code looks like this now to try and work around it how ever this doesn't seem to work either.
<cfif isDefined("CFFILE.serverFile")>
<cfset form.filename = CFFILE.serverFile>
<cfelse>
<cfset form.filename = "null">
</cfif>
<input type="hidden" name="filename" id="filename"
value="<cfoutput>#CFFILE.serverFile#</cfoutput>"/>
The filename does not become available until the file is uploaded. This happens after the form is posted. The only way around this is to try posting the fileupload via AJAX and then returning the filename.
Otherwise, you can assign the value to the field after the file is upload and the form is posted.
<cfset form.filename = CFFILE.serverfile>
You can find the file name before saving.
Railo:
GetPageContext().formScope().getUploadResource("myFormField").getName()
Adobe:
function getClientFileName(fieldName) {
var tmpPartsArray = Form.getPartsArray();
var clientFileName = "";
if (IsDefined("tmpPartsArray")) {
for (local.tmpPart in tmpPartsArray) {
if (local.tmpPart.isFile() AND local.tmpPart.getName() EQ arguments.fieldName) {
return local.tmpPart.getFileName();
}
}
}
return "";
}
Source: http://www.stillnetstudios.com/get-filename-before-calling-cffile/
As lvmisooners said,
GetPageContext().formScope().getUploadResource("myFormField").getName()
works for Railo (and Lucee) but I noticed an interesting wrinkle: if the browser is IE than this returns the full source path including the filename. Firefox and Chrome on the other hand, return only the filename.
For my application I need the full path, but haven't been able to find that if the browser is FireFox or Chrome. If anyone has any ideas I would be most grateful!
(Sorry for not replying to lvmisooners but I don't have the reputation points to reply.)

How can I include mappings into Application.cfc from external property file?

I have trouble with setting mappings in Application.cfc
We have diverent Server (dev,QS,prod)
Each with a little different Pathes.
I want to set serverspecific pathes and variables via configuration file.
On ApplicationStart you read the ini file and setup your system.
http://www.raymondcamden.com/index.cfm/2005/8/26/ColdFusion-101-Config-Files-AGoGo
This works fine.
Normaly you set mappings in Applcation.cfc like this:
<!--- in Application.cfc --->
<cfset this.mappings['/components'] = "D:\Inetpub\wwwroot\myApp\components">
Somewhere in a normal cfm File I instatiate a cfc named test via:
<cfset t = createObject("component", "components.test")>
I want to set the mappings only once at onApplicationsStart
<cffunction
name="OnApplicationStart"
access="public"
returntype="boolean"
output="false"
hint="Fires when the application is first created.">
<!---create structure to hold configuration settings--->
<cfset ini = structNew()>
<cfset ini.iniFile = expandPath("./ApplicationProperties.ini")>
<cfset application.ini = ini>
<!--- read ini file --->
<cfset sections = getProfileSections(application.ini.iniFile)>
<cfloop index="key" list="#sections.mappings#">
<cfset this.mappings[key] = getProfileString(application.ini.iniFile, "mappings", key)>
</cfloop>
But this don't work because this.mappings is empty and next request. :(
Putting this to OnRequestStart
<!--- read ini file --->
<cfset sections = getProfileSections(application.ini.iniFile)>
<cfloop index="key" list="#sections.mappings#">
<cfset this.mappings[key] = getProfileString(application.ini.iniFile, "mappings", key)>
</cfloop>
I get an error that the component can't be found.
This is strange.
Putting the struct into Application scope
<cfloop index="key" list="#sections.mappings#">
<cfset APPLICATION.mappings[key] = getProfileString(application.ini.iniFile, "mappings", key)>
</cfloop>
How to call my Component?
<cfset t = createObject("component", "application.components.test")>
Doesn't work.
So I have 3 targets.
reading all pathes and mappings from ini file
reading them once at ApplicationStart
easy usage in sourcecode.
Mappings can't be set in onApplicationStart(), they must be set in the pseudo constructor of Application.cfc, and they must be set on every request.
It's also important to note that the application scope is not available at this point, therefore if you need to cache anything you'll need to use the server scope. You can cache your mapping struct to the server scope and just set it into this.mappings each request.
<cfcomponent>
<cfset this.name = "myapp" />
<!--- not cached so create mappings --->
<cfif NOT structKeyExists(server, "#this.name#_mappings")>
<cfset iniFile = getDirectoryFromPath(getCurrentTemplatePath()) & "/ApplicationProperties.ini" />
<cfset sections = getProfileSections(iniFile) />
<cfset mappings = structnew() />
<cfloop index="key" list="#sections.mappings#">
<cfset mappings[key] = getProfileString(iniFile, "mappings", key)>
</cfloop>
<cfset server["#this.name#_mappings"] = mappings />
</cfif>
<!--- assign mappings from cached struct in server scope --->
<cfset this.mappings = server["#this.name#_mappings"] />
<cffunction name="onApplicationStart">
<!--- other stuff here --->
</cffunction>
</cfcomponent>
If you intend to keep you ini file in the webroot, you should make it a .cfm template and start it with a <cfabort>. It will work just the same but will not be readable
ApplicationProperties.ini.cfm
<cfabort>
[mappings]
/foo=c:/bar/foo

ColdFusion Component to Variable

I have a coldfusion component that is uneditable, only echos strings, and does not return a variable(and there is no return * statement). How can I grab this echoed string and place it in a variable before it is displayed directly on screen?
So :
<cfcomponent displayname="Helpz">
<cffunction name="OutputString" returnType="void" output="yes">
I love Stack overflow
</cffunction>
The outputted string needs to be stored into a variable.
CFSavecontent is what you need.
<cfsavecontent variable="myString"><cfset object.outputString() /></cfsavecontent>
Then you can do anything you want with #myString#.
<cfsavecontent variable="foo">
<cfset myComponent.outputString()>
</cfsavecontent>
It's probably a better practice to avoid that kind of output from within a function. An alternative solution would be:
<cfcomponent displayname="Helpz">
<cffunction name="getString" returnType="string" output="no">
<cfset var myString = "">
<cfsavecontent variable="myString">I love Stack overflow</cfsavecontent>
<cfreturn myString>
</cffunction>
</cfcomponent>
and then in you're template or wherever:
<cfoutput>#myCfc.getString()#</cfoutput>