I need to manipulate each line of a cfhttp.filecontent I got from a get:
<cfhttp url="www.internet.com/file.html" method="GET" resolveurl="false"></cfhttp>
<cfoutput>
#cfhttp.FileContent#
</cfoutput>
How would I loop through cfhttp.filecontent line by line?
Thanks!
Typically you can use list functions with some combination of chr(10) and/or chr(13) as the list delimiter. But it all depends on how "lines" are defined in your content.
<cfoutput>
<cfloop list="#cfhttp.FileContent#" delimiters="#chr(10)#" index="line">
#line#<br>
</cfloop>
</cfoutput>
Another option (if you're using ColdFusion 9) is to write the content of the CFHTTP request to a file on disk, and then use the file attribute of cfloop to loop over the file line by line.
Related
I'm using <cfhttp> to pull in content from another site (coldfusion) and resolveurl="true" so all the links work. The problem I'm having is resolveurl is making the anchor links (href="#search") absolute links as well breaking them. My question is is there a way to make resolveurl="true" bypass anchor links somehow?
For starters, let's use the tutorial code from Adobe.com posted in the comments. You'll want to do something similar.
<cfhttp url="https://www.adobe.com"
method="get" result="httpResp" timeout="120">
<cfhttpparam type="header" name="Content-Type" value="application/json" />
</cfhttp>
<cfscript>
// Find all the URLs in a web page retrieved via cfhttp
// The search is case sensitive
result = REMatch("https?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?", httpResp.Filecontent);
</cfscript>
<!-- Now, Loop through those URLs--->
<cfoutput>
<cfloop array="#result#" item="item" index="index">
<cfif LEFT(item, 1) is "##">
<!---Your logic if it's just an anchor--->
<cfelse>
<!---Your logic if it's a full link--->
</cfif>
<br/>
</cfloop>
</cfoutput>
If it tries to return a full URL before the anchor as you say, (I've been getting inconsistent results with resolveurl="true") hit it with this to only grab the bit you want.
<cfoutput>
<cfloop array="#result#" item="item" index="index">
#ListLast(item, "##")#
</cfloop>
</cfoutput>
What this code does is grab all the URLs, and parse them for anchors.
You'll have to decide what to do next inside your loop. Maybe preserve the values and add them to a new array, so you can save it somewhere with the links fixed?
It's impossible to assume in a situation like this.
There does not appear to be a way to prevent CF from resolving the hashes. In our usage of it the current result is actually beneficial since when we present content from another site we usually want the user to be sent there.
Here is a way to replace link href values with just anchor if one is present using regular expressions. I'm sure there are combinations of issues that could occur here if really malformed html.
<cfsavecontent variable="testcontent">
<strong>test</strong>
go to google
go to section
</cfsavecontent>
<cfset domain = replace("current.domain", ".", "\.", "all") />
<cfset match = "(href\s*=\s*(""|'))\s*(http://#domain#[^##'""]+)(##[^##'""]+)\s*(""|')" />
<cfset result = reReplaceNoCase(testcontent, match, "\1\4\6", "all") />
<cfoutput><pre>#encodeForHTML(result)#</pre></cfoutput>
Output
<strong>test</strong>
go to google
<a href="#section>go to section</a>
Another option if you are displaying the content in a normal page with js/jquery available is to run through each link on display and update it to just be the anchor. This will be less likely error with malformed html. Let me know if you have any interest in that approach.
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
I am trying to read a csv file that is using a | delimiter instead of ,.
I am using
<cffunction name="loadCSVfile" access="public" returntype="string">
<cfargument name="filename" required="yes" default="">
<cffile action="read" file="#filename#" variable="csvData">
<cfreturn csvData>
</cffunction>
which works fine with files that are , delimiter but does not work with |. Is there anything else that I need to do for this function to work?
This is how I'm calling the function:
<cfscript>
csvloaderCFC = CreateObject("component","AlscCSVloader");
</cfscript>
<cfset csvfilename = DataDirectory&q_DataDirectory.name>
<!--- backup CSV file ---->
<cffile action= "copy" source = "#csvfilename#"
destination = "#DataDirectorybackup#">
<!--- Load CSV data ---->
<cfscript>
csvData = csvloaderCFC.loadCSVfile(csvfilename);
</cfscript>
<cfdump var="#csvData#">
The cfdump in the end it doesn't show at all
Pipe-delimitted sample
Location|patient_ID|First Name|Last Name|
111|468454|Eric |Gallegos |
111|468457|kelsey|anderson|
10|468459|Rivenda|Kaur|
Comma-delimitted sample
Location,patient_ID,First Name,Last Name,
111,468454,Eric ,Gallegos ,
111,468457,kelsey,anderson,
10,468459,Rivenda,Kaur,
There is quite a bit more you have do do than just a CFFile call to get a CSV as a struct of some kind. CFFile foes not do this on it's own. (although strangely CFHttp does) Honestly your best bet may be to be to use a Java library. There are several available from Apache: http://commons.apache.org/csv/
These should give you back something fairly easy to deal with.
If you want a "pure" coldfusion CSV option you can look at this blog post for a specific impl:
http://www.bennadel.com/blog/483-Parsing-CSV-Data-Using-ColdFusion.htm
basically you need to read the entire content and then parse it.
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. :)
is there a way to set a variable with cfset that acts more like a cdata tag
or is there another way of having a page with some basic variables set and a couple of longer variables set for the main content;
ie.
<cfoutput>
<CFSET page_title = "TITLE">
<CFSET examplevariable = "ABC">
<CFSET content>
<!--something like this-->
<div>
bunch of content without any cf tags
</div>
</CFSET>
<cfinclude template="include/layout.cfm">
</cfoutput>
<cfsavecontent variable="header">
<cfoutput>
I can be HTML, javascript anything text.
remember to escape pound sysmbols ie: ##FF0000 instead of #FF0000
I can even <cfinclude template="headerpage.cfm"> and will be stored in variable
called header
</cfoutput>
</cfsavecontent>
<cfoutput>#header#</cfoutput>