I'm trying to delete the file if not a spreadsheet, but keep getting the following error when I uploaded testFile.text:
ColdFusion could not delete the file D:\ColdFusion10\cfusion\runtime\work\Catalina\localhost\tmp\testFile.text
I verified its not a permission issue, because if I go back and execute the code to try to delete the file again, it will work.
<cffile action="upload" destination="#dest#" filefield="xlsfile" result="upload" nameconflict="makeunique">
<cfif upload.fileWasSaved>
<cfset theFile = dest & upload.serverFile>
<cfif isSpreadsheetFile(theFile)>
<cfspreadsheet action="read" src="#theFile#" query="data" headerrow="1">
<cfset showForm = false>
<cfelse>
<cfscript>
thisFile = theFile;
fileRead = createObject("java", "java.io.FileInputStream");
thisThread = CreateObject("java", "java.lang.Thread");
loopCT = 1;
while(1 EQ 1)
{
try
{
fileRead.init(thisFile);
break;
}
catch(any ecpt)
{
thisThread.sleep(1000);
}
incrementValue(loopCT);
if(loopCT GT 60)
{
fileRead.close();
return;
}
}
loopCT = 1;
while(1 EQ 1)
{
sizeA = fileRead.available();
thisThread.sleep(1000);
sizeB = fileRead.available();
if(sizeA EQ sizeB)
{
thisThread.sleep(1000);
sizeC = fileRead.available();
if(sizeC EQ sizeB)
{
break;
}
}
incrementValue(loopCT);
if(loopCT GT 60)
{
fileRead.close();
return;
}
}
fileRead.close();
<script type="text/javascript">
</script>
</cfscript>
<!--cffile action="delete" file="#theFile#"-->
<cfset errors = "The file was not an Excel file.">
<span style="font-size:medium;font-weight:bold; color:red"><p>The file was not an excel file!<p></span>
<input type="button" value="TRY AGAIN" class="button" onClick="window.location='bulk_upload.cfm'">
<br><br><br>
</cfif>
<cfset errors = "The file was not properly uploaded.">
</cfif>
I ran into the exact same issue with regards to cfimage locking the file and preventing deletion. The solution I came up with follows. Maybe someone can adapt to their situation:
<cflock name="[lockName]" timeout="5" >
<cfcache action="flush">
<!---[] Replace cfimage read function (CF BUG work around) --->
<cfscript>
imageObj = createObject( "java", "java.awt.Toolkit" );
imagetools = imageObj.getDefaultToolkit();
objImage = imagetools.getImage( "#fullpath#" );
<!---Whatever image I need from the image, or file...--->
<!---such as ---- myImageStruct["width"] = objImage.getWidth();--->
<!--- and then flush the object--->
objImage.flush();
</cfscript>
</cflock>
Related
After upgrading from CF11 to CF2018, Update 3, none of my editable cfgrids are working. When I make an edit and then submit the form, the columns seem to get jumbled. I created the simplest cfgrid I could (below) but am still getting the same behavior.
<cfif isDefined("form.submitname")>
<cfdump var="#form#">
<cfelse>
<cfform action="test.cfm" method="post" name="testform" id="testformId">
<cfinput type="Submit" name="submitname" id="submitid">
<cfgrid name="TestGrid" format="html" selectmode="edit">
<cfgridcolumn name="A">
<cfgridcolumn name="B">
<cfgridrow data="john,doe">
<cfgridrow data="steve,anon">
</cfgrid>
</cfform>
</cfif>
The grid displays correctly, but what I change 'john' to 'peter' and submit, I get the following dump:
enter image description here
As you can see, it thinks 'peter' was entered as both the first and last name, and it also thinks that 'peter' was the original first name.
When I modify any of the fields in the second column, I get the following javascript error in the console:
TypeError: _dd.values[_de] is undefined.
The error is thrown by cfgrid.js
If I submit only a change in the second column, the dump is completely empty.
It seems like the cfgrid is mixing up columns or something.
Your thoughts?
Ultimately the solution here is to move away from ColdFusion's implementation of <cfgrid> and roll your own grid-UI or.... wait for a patch from Adobe.
This is definitely a bug in ColdFusion, the error you are seeing is specifically a bug in the function ColdFusion.Grid.Actions.afterEdit()
I spent a little bit of time fiddling around with the JS generated with <cfgrid> and found that they index into the columns incorrectly
You can override ColdFusion's implementation of ColdFusion.Grid.Actions.afterEdit() with your own to create a possible workaround ( I ran on Solaris 11.4 - Apache - ColdFusion 2018 : Update 3 )
<Body>
<cfif isDefined("form.submitname")>
<cfdump var="#form#">
<cfelse>
<cfform action="test.cfm" method="post" name="testform" id="testformId">
<cfinput type="Submit" name="submitname" id="submitid">
<cfgrid name="TestGrid" format="html" selectmode="edit">
<cfgridcolumn name="A">
<cfgridcolumn name="B">
<cfgridrow data="john,doe">
<cfgridrow data="steve,anon">
</cfgrid>
</cfform>
</cfif>
<script>
ColdFusion.Grid.Actions.afterEdit = function(_d8, _d9, _da) {
var _db = _d9.value;
if (_db == this.editOldValue) {
return;
}
if (this.insertInProgress == false && this.onChangeFunction) {
this.onChangeHandler("U", this.selectedRow, _d9);
} else {
if (!this.dynamic) {
rowidx = _d9.rowIdx;
if (!rowidx && rowidx != 0) {
rowidx = _d9.row;
}
var _dc = ColdFusion.Grid.computeActualRow_editField(this.editFieldState, _d9.record.data.CFGRIDROWINDEX);
var _dd = this.editFieldState[_dc - 1];
var _de = _d9.colIdx;
if (!_de && _de != 0) {
_de = _d9.column;
}
_de = _de + 1;
if (_dd) {
if (this.multiRowSelection === true && this.insertInProgress == true) {
_de = _de - 1;
}
//-------------------------------------------------------------------
//Subtracted 1 from column index to correctly index array
//-------------------------------------------------------------------
_dd.values[_de -1][1] = _db;
} else {
var _df = this.grid.getStore().getById(_d9.record.data.CFGRIDROWINDEX);
_dd = ColdFusion.Grid.Actions.initEditState(this, "U", _df, _dc);
var _e0 = this.editOldValue + "";
if (_d9.column.type == "date") {
if (_e0 && typeof _e0 == "string") {
_e0 = new Date(_e0);
}
var _e1 = "F, j Y H:i:s";
if (_d9.column && _d9.column.format) {
_e1 = _d9.column.format;
}
_dd.values[_de][1] = Ext.Date.format(_db, _e1);
_dd.values[_de][0] = _e0 ? Ext.Date.format(_e0, _e1) : _e0;
} else {
//-------------------------------------------------------------------
//Subtracted 1 from column index to correctly index array
//-------------------------------------------------------------------
_dd.values[_de -1][0] = _e0;
_dd.values[_de -1][1] = _db;
}
}
ColdFusion.Grid.Actions.computeEditField(this);
}
}
this.editOldValue = null;
this.fireSelectionChangeEvent();
}
;
</script>
</BODY>
There are definitely a ton of other bugs plaguing this tag ... and its definitely worth noting that Lucee ( opensource ColdFusion engine) DOES NOT support this tag
I have the following function, inherited from some CF code. It works, but only in ColdFusion version 10 and 11. I am not concerned with 2016 as no plans for upgrade. I'm trying to run it under Lucee, but it is not working.
<cffunction name="QueryToArray" access="public" returntype="array" output="false" hint="This turns a query into an array of structures.">
<!--- Define arguments. --->
<cfargument name="Data" type="query" required="yes" />
<cfscript>
var LOCAL = StructNew(); // Define the local scope.
LOCAL.Columns = data.getMetaData().getColumnLabels(); // Get the column names as an array.
LOCAL.QueryArray = ArrayNew(1); // Create an array that will hold the query equivalent.
for (LOCAL.RowIndex = 1 ; LOCAL.RowIndex LTE ARGUMENTS.Data.RecordCount;
LOCAL.RowIndex = (LOCAL.RowIndex + 1)){
LOCAL.Row = StructNew();
for (LOCAL.ColumnIndex = 1 ; LOCAL.ColumnIndex LTE ArrayLen(LOCAL.Columns);
LOCAL.ColumnIndex = (LOCAL.ColumnIndex + 1)){
LOCAL.ColumnName = LOCAL.Columns[LOCAL.ColumnIndex];
LOCAL.Row[LOCAL.ColumnName] = ARGUMENTS.Data[LOCAL.ColumnName][LOCAL.RowIndex];
}
ArrayAppend(LOCAL.QueryArray, LOCAL.Row);
}
return(LOCAL.QueryArray);
</cfscript>
</cffunction>
In Lucee, I tried making these changes:
<cffunction name="QueryToArray" access="public" returntype="array" output="false" hint="This turns a query into an array of structures.">
<!--- Define arguments. --->
<cfargument name="Data" type="query" required="yes" />
<cfscript>
var LOCAL = StructNew(); // Define the local scope.
LOCAL.Columns = data.getColumnlist(false); // Get the column names as an array.
LOCAL.QueryArray = ArrayNew(1); // Create an array that will hold the query equivalent.
for (LOCAL.RowIndex = 1 ; LOCAL.RowIndex LTE ARGUMENTS.Data.RecordCount;
LOCAL.RowIndex = (LOCAL.RowIndex + 1)){
LOCAL.Row = StructNew();
for (LOCAL.ColumnIndex = 1 ; LOCAL.ColumnIndex LTE ArrayLen(LOCAL.Columns);
LOCAL.ColumnIndex = (LOCAL.ColumnIndex + 1)){
LOCAL.ColumnName = LOCAL.Columns[LOCAL.ColumnIndex];
LOCAL.Row[LOCAL.ColumnName] = ARGUMENTS.Data[LOCAL.ColumnName][LOCAL.RowIndex];
}
ArrayAppend(LOCAL.QueryArray, LOCAL.Row);
}
return(LOCAL.QueryArray);
</cfscript>
</cffunction>
but I'm getting this error:
Message: Can't cast String [name,value] to a value of type [Array]
Detail: Java type of the object is java.lang.String
Stacktrace:
The Error Occurred in
C:\home\website\wwwroot\controller\production\cfc\kernel.cfc: line 12
10: LOCAL.RowIndex = (LOCAL.RowIndex + 1)){
11: LOCAL.Row = StructNew();
12: for (LOCAL.ColumnIndex = 1 ; LOCAL.ColumnIndex LTE ArrayLen(LOCAL.Columns);
13: LOCAL.ColumnIndex = (LOCAL.ColumnIndex + 1)){
14: LOCAL.ColumnName = LOCAL.Columns[LOCAL.ColumnIndex];
To get your code to work, all you need to do is change line 6 from
LOCAL.Columns = data.getColumnlist(false); // Get the column names as an array.
to this
LOCAL.Columns = data.getColumnNames(); // Get the column names as an array.
However I found a gist here that works in both ColdFusion and Lucee. I decided to create some sample code and test it at https://trycf.com/. I verified that it works in Lucee 4.5 and 5. It also works in ColdFusion 10, 11, 2016 as well. Hope this helps!
<!--- Create a new three-column query, specifying the column data types --->
<cfset myQuery = QueryNew("Name, Time, Advanced", "VarChar, Time, Bit")>
<!--- Make two rows in the query --->
<cfset QueryAddRow(MyQuery, 2)>
<!--- Set the values of the cells in the query --->
<cfset QuerySetCell(myQuery, "Name", "The Wonderful World of CMFL", 1)>
<cfset QuerySetCell(myQuery, "Time", "9:15 AM", 1)>
<cfset QuerySetCell(myQuery, "Advanced", False, 1)>
<cfset QuerySetCell(myQuery, "Name", "CFCs for Enterprise
Applications", 2)>
<cfset QuerySetCell(myQuery, "Time", "12:15 PM", 2)>
<cfset QuerySetCell(myQuery, "Advanced", True, 2)>
<h4>The query</h4>
<cfdump var="#myQuery#">
<h4>The array of objects</h4>
<cfset myArray = QueryToArray(myQuery)>
<cfdump var="#myArray#">
<cfscript>
/**
* #hint Returns reasonable array of objects from a cfquery
*/
public function queryToArray(
required query query,
string excludeColumns = ""
){
if (server.coldfusion.productName == "ColdFusion Server") {
local.columns = arguments.query.getMetaData().getColumnLabels();
} else if (server.coldfusion.productName == "Lucee") {
local.columns = arguments.query.getColumnNames();
} else {
local.columns = [];
}
local.response = arrayNew(1);
for (local.rowIndex=1; local.rowIndex<=arguments.query.recordCount; local.rowIndex++) {
local.response[local.rowIndex] = structNew();
for (local.columnIndex=1; local.columnIndex<=arrayLen(local.columns); local.columnIndex++) {
local.columnName = local.columns[local.columnIndex];
if(local.columnName != "" && (arguments.excludeColumns == "" || !listFindNoCase(arguments.excludeColumns, local.columnName))) {
local.response[local.rowIndex][local.columnName] = arguments.query[local.columnName][local.rowIndex];
}
}
}
return local.response;
}
</cfscript>
I'm trying to write a savecontent in cfscript.
I have it in CFML:
<cfsavecontent variable="errortext">
<cfoutput>
An error occurred: http://#cgi.server_name##cgi.script_name#?#cgi.query_string#<br />
Time: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br />
<cfdump var="#session#" label="Session">
<cfdump var="#error#" label="Error">
<cfdump var="#form#" label="Form">
<cfdump var="#url#" label="URL">
</cfoutput>
</cfsavecontent>
I need it in cfscript, but how can I do it? Can I put everything inside WriteOuput()?
Thanks
Example not working:
<cfscript>
local.test = "TEST";
local.OK = "OK";
savecontent variable="contentViaScript" {
writeOutput(
"String Message: <br />"
writeDump(local);
);
}
writeOutput(contentViaScript);
</cfscript>
<cfdump var = '#contentViaScript#' />
You don't need to wrap writedump in writeoutput.
<cfscript>
local.test = "TEST";
local.OK = "OK";
savecontent variable="contentViaScript" {
writeOutput("String Message: <br />");
writeDump(local);
}
writeOutput(contentViaScript);
</cfscript>
<cfdump var = '#contentViaScript#' />
DEMO
Try this:
<cfscript>
local.test = "TEST";
local.OK = "OK";
savecontent variable="contentViaScript" {
writeOutput(
"String Message: <br />
#writeDump(local)#"
);
}
writeOutput(contentViaScript);
</cfscript>
<cfdump var = '#contentViaScript#' />
I have a txt file and would like to order all the rows according to a value in each row.
What is the best and fastest possible way to achieve this?
Below is the code that I use to compile my txt documents:
<!---CSV FILE--->
<cffile action="read" file="C:/ColdFusion10/cfusion/wwwroot/kelly2/debitorders.csv" variable="csvfile">
<cfoutput>
<!---LOOP THROUGH CSV FILE--->
<cfloop index="index" list="#csvfile#" delimiters="#chr(10)##chr(13)#">
<!---SET VALUES--->
<cfset accountholder = "#listgetAt('#index#',1)# #listgetAt('#index#',2)#">
<cfset accountholderlname = "#listgetAt('#index#',2)#">
<cfset accountnumber = "#listgetAt('#index#',3)#">
<cfset accounttype = "#listgetAt('#index#',4)#">
<cfset bankname = "#listgetAt('#index#',5)#">
<cfset branch = "#listgetAt('#index#',6)#">
<cfset amount = "#listgetAt('#index#',7)#">
<cfset date = "#listgetAt('#index#',8)#">
<!---SET INITIAL--->
<cfset initial = "#left(accountholder,1)#">
<!---SET LAST NAME--->
<cfset lname_final = "#replace("#accountholderlname#"," ","","all")#">
<!---GET AND SET ACC TYPE--->
<cfif accounttype eq "cheque">
<cfset accounttype_final = "CH">
<cfelseif accounttype eq "savings">
<cfset accounttype_final = "SAV">
<cfelseif accounttype eq "credit">
<cfset accounttype_final = "CR">
<cfelse>
<cfset accounttype_final = "OTH">
</cfif>
<!---SET AMOUNT--->
<cfset amount_final = #round(amount * 100)#>
<cfset amount_final = #NumberFormat(amount_final,"0000000")#>
<!---SET DATE--->
<cfset date_final = "#DateFormat(Date,"ddyyyymm")#">
<!---TRIM VALUES--->
<cfset initial = "#Left(initial, 1)#">
<cfset lname_final = "#Left(lname_final, 14)#">
<cfset accountnumber = "#Left(accountnumber, 13)#">
<cfset accounttype_final = "#Left(accounttype_final, 3)#">
<cfset branch = "#Left(branch, 9)#">
<cfset amount_final = "#Left(amount_final, 7)#">
<cfset date_final = "#Left(date_final, 8)#">
<!---SET STRING LENGTH FOR EACH--->
<cfset initial = "#LJustify(initial, 1)#">
<cfset lname_final = "#LJustify(lname_final, 15)#">
<cfset accountnumber = "#LJustify(accountnumber, 14)#">
<cfset accounttype_final = "#LJustify(accounttype_final, 3)#">
<cfset branch = "#LJustify(branch, 10)#">
<cfset amount_final = "#LJustify(amount_final, 7)#">
<cfset date_final = "#LJustify(date_final, 8)#">
<!---SET TOTAL STRING--->
<cfset total_string = "#initial##lname_final##accountnumber##accounttype_final##branch##amount_final##date_final#">
<pre>
#accountholder#<br>
#accountnumber#<br>
#accounttype#<br>
#bankname#<br>
#branch#<br>
#amount#<br>
#date#<br>
#initial#<br>
#lname_final#<br />
#accounttype_final#<br>
#amount_final#<br />
#date_final#<br>
123456789012345678901234567890123456789012345678901234567890<br />
#total_string#<br>
<br />
<br />
</pre>
<!---IF FILE FOR BANK EXISTS--->
<cfif FileExists(ExpandPath("#listgetAt('#index#',5)#.txt"))>
<!---READ EXISTING FILE HEADER--->
<cffile action="read" file="C:/ColdFusion10/cfusion/wwwroot/kelly2/#bankname#.txt" variable="bankheader">
<!---SPLIT UP THE HEADER TO ADD NEW VALUES ONTO IT--->
<cfset numericvalue = listfirst(bankheader,chr(13))>
<cfset numericvalue = #Right(numericvalue, 13)#>
<cfset RecordCountvalue = #Left(numericvalue, 3)#>
<cfset RecordCountvalue = #RecordCountvalue# + 1>
<cfset RecordCountvalue = #NumberFormat(RecordCountvalue,"000")#>
<cfset RecordCountvalue = #Left(RecordCountvalue, 3)#>
<cfset RecordCountvalue = #RJustify(RecordCountvalue, 3)#>
<cfset TotalRecordvalue = #Right(numericvalue, 10)#>
<cfset TotalRecordvalue = (#TotalRecordvalue# + #amount#) * 100000>
<cfset TotalRecordvalue = #NumberFormat(TotalRecordvalue,"0000000000")#>
<cfset TotalRecordvalue = #Left(TotalRecordvalue, 10)#>
<cfset TotalRecordvalue = #RJustify(TotalRecordvalue, 10)#>
<!---SET HEADER FOR FILE--->
<cfset fileheader_bank = "#UCase(bankname)#">
<cfset fileheader_bank = "#Left(fileheader_bank, 15)#">
<cfset fileheader_bank = "#LJustify(fileheader_bank, 16)#">
<cfset newfile_header = "#fileheader_bank##RecordCountvalue##TotalRecordvalue#">
<pre>
#numericvalue#<br />
#RecordCountvalue#<br />
#TotalRecordvalue#<br />
#newfile_header#
</pre>
<!---APPEND FILE AND ADD UPDATED HEADER--->
<cfset bankheader = listSetAt(bankheader,1,"#newfile_header#","#chr(13)#")>
<cffile action="write"
fixnewline="no"
addnewline="no"
file="#getDirectoryFromPath(getTemplatePath())#/#listgetAt('#index#',5)#.txt"
output="#bankheader#">
<!---APPEND FILE AND ADD NEW ENTRY--->
<cffile action = "append"
fixnewline="no"
file = "C:/ColdFusion10/cfusion/wwwroot/kelly2/#listgetAt('#index#',5)#.txt"
output = "#total_string#">
<!---IF FILE FOR BANK DOES NOT EXIST--->
<cfelse>
<!---SET HEADER FOR FILE--->
<cfset fileheader_bank = "#UCase(bankname)#">
<cfset fileheader_bank = "#Left(fileheader_bank, 15)#">
<cfset fileheader_bank = "#LJustify(fileheader_bank, 16)#">
<cfset newfile_header = "#fileheader_bank#001000#amount_final#">
<!---CREATE NEW FILE WITH BANK NAME--->
<cffile action = "write"
fixnewline="no"
file = "C:/ColdFusion10/cfusion/wwwroot/kelly2/#listgetAt('#index#',5)#.txt"
output = "#newfile_header#">
<!---APPEND FILE AND ADD NEW ENTRY--->
<cffile action = "append"
fixnewline="no"
file = "C:/ColdFusion10/cfusion/wwwroot/kelly2/#listgetAt('#index#',5)#.txt"
output = "#total_string#">
</cfif>
</cfloop>
</cfoutput>
I am not sure if it would be better if I start using an Array to do this, if so please advise.
I am not sure if it is possible to check as I insert each row to insert it into the correct place, I have never heard of this before.
I could also loop through the txt files at the end of the process if need be.
Read the csv file using cfhttp. The name attribute creates a query object. You can use Q of Q to do your sort and then carry on.
The details are in the documentation for cfhttp.
My JSON contains special characters like: new line, double quotes etc.
I am creating the JSON using Coldfusion server side script. But in case of special chars I get error due to wrongly formatted JSON. What should I do in such a case?
<cfoutput>
[
<cfset loopIndex=0>
<cfloop query="qEvents">
<cfif loopIndex NEQ 0>,</cfif>
<cfif is_allday EQ 1>
<cfset isallDayEvent = "true">
<cfelse>
<cfset isallDayEvent = "false">
</cfif>
{
"title": "#title#",
"start": "#DateFormat(start_date_time,'mm/dd/yyyy')# #TimeFormat(start_date_time,'hh:mm tt')#",
"end": "#DateFormat(end_date_time,'mm/dd/yyyy')# #TimeFormat(end_date_time,'hh:mm tt')#",
"allDay": #isallDayEvent#,
"eventID": "#event_id#",
"duration": "#duration#",
"note": "#note#",
"location": "#location#"
}
<cfset loopIndex=loopIndex+1>
</cfloop>
]
</cfoutput>
Rather than writing the JSON by hand, you should generate an array of structs and then use serializeJSON() to convert it to a valid JSON string:
<cfset thisArrayBecomesJSON = [] />
<cfloop query="qEvents">
<cfif is_allday EQ 1>
<cfset isAllDayEvent = "true" />
<cfelse>
<cfset isAllDayEvent = "false" />
</cfif>
<cfset thisEvent = {
'title' = title,
'start' = dateFormat( start_date_time, 'mm/dd/yyyy' ) & timeFormat( start_date_time, 'hh:mm tt' ),
'end' = dateFormat( end_date_time, 'mm/dd/yyyy' ) & timeFormat( end_date_time, 'hh:mm tt' ),
'allDay' = isAllDayEvent,
'eventID' = event_id,
'duration' = duration,
'note' = note,
'location' = location
} />
<cfset arrayAppend( thisArrayBecomesJSON, thisEvent ) />
</cfloop>
<cfset myJSON = serializeJSON( thisArrayBecomesJSON ) />
<cfoutput>#myJSON#</cfoutput>
This is untested, but I think it should work ok - there may be some syntax errors.