Search Folders in ColdFusion 9 - coldfusion

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>

Related

Excluding items from a list in coldfusion by type

Is there a way to exclude certain items by filetype in a list in Coldfusion?
Background: I just integrated a compression tool into an existing application and ran into the problem of the person's prior code would automatically grab the file from the upload destination on the server and push it to the Network Attached Storage. The aim now is to stop their NAS migration code from moving all files to the NAS, only those which are not PDF's. What I want to do is loop through their variable that stores the names of the files uploaded, and exclude the pdf's from the list then pass the list onto the NAS code, so all non pdf's are moved and all pdf's uploaded remain on the server. Working with their code is a challenge as no one commented or documented anything and I've been trying several approaches.
<cffile action="upload" destination= "c:\uploads\" result="myfiles" nameconflict="makeunique" >
<cfset fileSys = CreateObject('component','cfc.FileManagement')>
<cfif Len(get.realec_transactionid)>
<cfset internalOnly=1 >
</cfif>
**This line below is what I want to loop through and exclude file names
with pdf extensions **
<cfset uploadedfilenames='#myfiles.clientFile#' >
<CFSET a_insert_time = #TimeFormat(Now(), "HH:mm:ss")#>
<CFSET a_insert_date = #DateFormat(Now(), "mm-dd-yyyy")#>
**This line calls their method from another cfc that has all the file
migration methods.**
<cfset new_file_name = #fileSys.MoveFromUploads(uploadedfilenames)#>
**Once it moves the file to the NAS, it inserts the file info into the
DB table here**
<cfquery name="addFile" datasource="#request.dsn#">
INSERT INTO upload_many (title_id, fileDate, filetime, fileupload)
VALUES('#get.title_id#', '#dateTimeStamp#', '#a_insert_time#', '#new_file_name#')
</cfquery>
<cfelse>
<cffile action="upload" destination= #ExpandPath("./uploaded_files/zip.txt")# nameconflict="overwrite" >
</cfif>
Update 6/18
Trying the recommended code helps with the issue of sorting out filetypes when tested outside of the application, but anytime its integrated into the application to operate on the variable uploadedfilenames the rest of the application fails and the multi-file upload module just throws a status 500 error and no errors are reported in the CF logs. I've found that simply trying to run a cfloop on another variable not related to anything in the code still causes it to error.
As per my understanding, you want to filter-out file names with a specific file type/extension (ex: pdf) from the main list uploadedfilenames. This is one of the easiest ways:
<cfset lFileNames = "C:\myfiles\proj\icon-img-12.png,C:\myfiles\proj\sample-file.ppt,C:\myfiles\proj\fin-doc1.docx,C:\myfiles\proj\fin-doc2.pdf,C:\myfiles\proj\invoice-temp.docx,C:\myfiles\proj\invoice-final.pdf" />
<cfset lResultList = "" />
<cfset fileExtToExclude = "pdf" />
<cfloop list="#lFileNames#" index="fileItem" delimiters=",">
<cfif ListLast(ListLast(fileItem,'\'),'.') NEQ fileExtToExclude>
<cfset lResultList = ListAppend(lResultList,"#fileItem#") />
</cfif>
</cfloop>
Using only List Function provided by ColdFusion this is easily done, you can test and try the code here. I would recommend you to wrap this code around a function for easy handling. Another way to do it would be to use some complex regular expression on the list (if you're looking for a more general solution, outside the context of ColdFusion).
Now, applying the solution to your problem:
<cfset uploadedfilenames='#myfiles.clientFile#' >
<cfset lResultList = "" />
<cfset fileExtToExclude = "pdf" />
<cfloop list="#uploadedfilenames#" index="fileItem" delimiters=",">
<cfif ListLast(ListLast(fileItem,'\'),'.') NEQ fileExtToExclude>
<cfset lResultList = ListAppend(lResultList,fileItem) />
</cfif>
</cfloop>
<cfset uploadedfilenames = lResultList />
<!--- rest of your code continues --->
The result list lResultList is copied to the original variable uploadedfilenames.
I hope I'm not misunderstanding the question, but why don't you just wrap all of that in an if-statement that reads the full file name? Whether the files are coming one by one or through a delimited list, it should be easy to work around.
<cfif !listContains(ListName, '.pdf')>
OR
<cfif FileName does not contain '.pdf'>
then
all the code you posted

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.

ColdFusion = OnRequest Error

Looking through the logs, we're getting hundreds of the following
"Error","jrpp-185","08/21/12","10:05:43","PATH","www.domain.com
Agent:Mozilla/4.0 (compatible; Synapse)
Error: An exception occurred when invoking a event handler method from Application.cfc.
The method name is: onRequest.
They seem to be mostly search bots. The on place on APplication.cfc that I can see reference to the function is below
<cffunction name="onRequest" returnType="void">
<cfargument name="targetPage" type="String" required=true/>
<cfsetting enablecfoutputonly="yes" requesttimeout="20">
<cfparam name="url.refresh" default="0">
<cfset request.strMember = Duplicate(session.strMember)/>
<cfset request.tNow = GetTickCount()>
<cfif url.refresh EQ 0>
<cfset request.iCacheHr = 12/>
<cfelse>
<cfset request.iCacheHr = 0/>
</cfif>
<cflogin>
<cfif IsDefined("session.strMember.sRoles")>
<cfloginuser name="#session.strMember.sFirstName##session.strMember.sLastName#"
password="12345"
roles="#session.strMember.sRoles#"/>
</cfif>
</cflogin>
<cfinclude template="core/incl/SessionLogger.cfm">
<cfinclude template="core/incl/LinkTranslator.cfm">
<cfinclude template="core/incl/udf.cfm">
<cfinclude template="urlcheck.cfm"/>
<cfinclude template="#Arguments.targetPage#">
</cffunction>
From that, can anyone please advise on what's wrong and how to fix it? I'm fairly new to CF and this is making me pull out what little hair I have left
1) You use two different coding styles
<cfparam name="url.refresh" default="0">
<cfset request.strMember = Duplicate(session.strMember)/>
Invalid/left open XML tags in first line and valid (closed) XML tags in the second line.
Try to stick to one (preferably the last one).
2) You are using old way of checking variable being defined
IsDefined("session.strMember.sRoles")
read about newer (and better and faster)
StructKeyExists(session.strMember, "sRoles")
3) Most likely your code is calling
<cfloginuser ... >
at every page request
4) Make sure that paths for all includes are correct and they themselves don't have any errors.
Simplify your method until you stop getting an error and then investigate what exactly is causing it
Are the bots hitting a page that doesn't exist?
Maybe try changing the last line to:
<cfif fileExists(expandPath(Arguments.targetPage))>
<cfinclude template="#Arguments.targetPage#">
<cfelse>
<cfabort>
</cfif>
Maybe you could detect if they are a bot and server them something else? depends on how search friendly you want your site to be:
http://www.bennadel.com/blog/1083-ColdFusion-Session-Management-And-Spiders-Bots.htm

cffile not working at all

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.

Uploading Multiple Files

I have a form where users are to upload at least three documents and up to seven. In its current state, I have all the error checking and validation functioning. What I want to happen is for the visitor's forms to get renamed a specified name once they are uploaded and placed into a specified directory. My code is here: http://pastebin.com/V5ThWe7M
I believe the issue occurs around line 456. I believe I need to have the file name stored in a variable then use the variable to process the renaming function. The first file gets uploaded but not the second as they are assigned the same names. I'm trying to figure out how to use the variables that store the individual file names and then use that variable to rename the file. I'd like to have another set of eyes check it out for me and point me in the right direction.
Thank you
As already mentioned, the CFFILE structure is overwritten each time you upload. So any values you wish to preserve, you must save to another variable. But since you are already saving the full file names to a variable, you could easily extract their extensions using list functions. For example:
<cfset nomExt = listLast(clientNominationLetter, ".")>
A few other observations
Consider a more unique naming scheme for your folders than "/firstName_lastName/". Otherwise, you may end up overwriting someone's files if you receive multiple submissions under the same name, like two different "John Smith's".
The cffile values are separated into two categories: cffile.serverXX and cffile.clientXX (ie user system). They are not interchangeable. So be sure you are using the correct variables and be consistent.
FILE is deprecated. Use CFFILE or the result attribute instead.
EDIT: Adding some new code into the mix... :)
Here's some functions, just slap these in the top of your page...
<cffunction name="uploadFile">
<cfargument name="formField" hint="Form field name that holds the file to be uploaded" required="yes">
<cfargument name="renameTo" hint="What to rename the file, ex: 01_nominationLetter" required="yes">
<cfargument name="uploadErrorMessage" required="no" default="Error uploading file"/>
<cfargument name="allowedExtensions" required="no" default="doc,docx,pdf,txt,rt">
<cfargument name="extensionErrorMessage" required="no" default="Only doc, docx, pdf, txt, and rtf file formats are accepted">
<cfset var dir = expandPath("./nominationUploads/#trim(form.fname)#_#trim(form.lname)#/")>
<cfparam name="request.filesUploaded" default="#arrayNew(1)#">
<cftry>
<cffile action="upload" filefield="#arguments.formField#" nameconflict="makeunique" destination="#dir#">
<cfcatch type="any"><cfset ArrayAppend(arrErrors, arguments.uploadErrorMessage )></cfcatch>
</cftry>
<cfif not listFindNoCase(arguments.allowedExtensions, cffile.ServerFileExt)>
<cfset ArrayAppend(arrErrors, arguments.extensionErrorMessage )>
</cfif>
<cffile action="rename" file="#dir##cffile.serverFile#" destination="#dir##renameTo#.#cffile.ServerFileExt#">
<cfset ArrayAppend(request.filesUploaded, dir & arguments.renameTo & "." & cffile.ServerFileExt )>
</cffunction>
<cffunction name="removeFilesOnError">
<cfloop from="1" to="#arrayLen(request.filesUploaded)#" index="i">
<cftry><cffile action="delete" file="#request.filesUploaded[i]#"/><cfcatch type="any"></cfcatch></cftry>
</cfloop>
</cffunction>
Then in your existing validation script, get rid of all the file stuff, instead you'll only need to use those functions above, something like this :
<cfset uploadFile('myFileField', 'renameToThis' )>
<cfset uploadFile('myFileField2', 'renameToThat' , 'My custom upload error!')>
<cfset uploadFile('anotherFile', 'differentName', 'Another custom upload msg!', 'doc,docx', 'This one only lets you upload word docs!')>
<cfif arrayLen( arrErrors ) >
<cfset removeFilesOnError()>
</cfif>
I don't have time to test the above, but I believe it to be frighteningly close. If you encounter an issue, let me know and I'll help you debug it out. :)