I have an issue with client variables in ColdFusion 10. When I create client variables in one page it is effecting that page only and I am not able to access the variables in another page in my application. Here is code from Application.cfc:
this.Name = "test";
this.ApplicationTimeout = CreateTimeSpan(0,0,0,0);
this.ClientManagement= "yes";
this.ClientStorage = "clientstorage";
this.SessionManagement = true;
this.SessionTimeout = CreateTimeSpan( 0, 0, 20, 0 );
this.SetClientCookies = "yes";
this.SetDomainCookies = "no";
this.ScriptProtect = "all";
I was having the same problem on a site and fixed it by using setdomaincookies="yes"
Related
I have a function utilizing an include, of a JSP file, to retrieve thread information which is then converted into a query object. The function returns an empty query Lucee, but it executes properly in ColdFusion.
CFML:
<cffunction name="mainThreads" output="false" returntype="query" access="public">
<cfargument name="filterPages" type="boolean" required="true">
<cfscript>
var threadStackDump = "";
var thread = 0;
var stackTrace = "";
request.threads = arraynew(1);
GetPageContext().include("putParentThreadInRequestScope.jsp");
ThreadQuery = QueryNew("id, name, group, stacktrace, alive", "Integer, VarChar, VarChar, VarChar, Bit");
QueryAddRow(ThreadQuery, arrayLen(request.threads));
for ( thread = 1; thread lte arrayLen(request.threads); thread = thread + 1 )
{
QuerySetCell(ThreadQuery, "id", request.threads[thread].getId(), thread);
QuerySetCell(ThreadQuery, "name", request.threads[thread].getName(), thread);
QuerySetCell(ThreadQuery, "group", request.threads[thread].getThreadGroup().getName(), thread);
QuerySetCell(ThreadQuery, "alive", request.threads[thread].isAlive(), thread);
threadStackDump = "";
stackTrace = request.threads[thread].getStackTrace();
for ( element = 1; element lte arrayLen(stackTrace); element = element + 1 )
if ( arguments.filterPages )
{
if ( findNoCase('runPage',stackTrace[element]) neq 0 or findNoCase('runFunction',stackTrace[element]) neq 0 )
threadStackDump = threadStackDump & stackTrace[element] & "#chr(13)#";
}
else
threadStackDump = threadStackDump & stackTrace[element] & "#chr(13)#";
QuerySetCell(ThreadQuery, "stacktrace", threadStackDump, thread);
}
return ThreadQuery;
</cfscript>
</cffunction>
JSP
<%
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
Thread threadList[]=new Thread[Thread.activeCount()];
threadGroup.enumerate(threadList);
request.setAttribute("threads", threadList);
%>
The code is not working in Lucee, but I'm not sure why. Does it have something to do with the java versions?
I'd guess you forgot to enable handling of .jsp in your web.xml, but ... you're not aware of it because the problem code executes inside a cffunction that suppresses all output!
Take a leaf out of Troubleshooting 101 and test the problem code in small chunks. Start by executing the JSP include separately. If it displays the JSP code on screen, instead of executing it, then you know JSP handling isn't enabled, and that's your problem.
<cfscript>
GetPageContext().include("putParentThreadInRequestScope.jsp");
writeDump( request );
</cfscript>
I would like to loop over query and compare column values. Here is example of CFML code:
<cfquery name="qryUserPerm" datasource="#Application.dsn#">
SELECT AccessType, AccessLevel, State, City, Building
FROM Permissions
WHERE AccountID = <cfqueryparam cfsqltype="cf_sql_integer" value="#trim(session.AccountID)#">
</cfquery>
<cfset local.permissionType = "">
<cfset local.permissionLevel = "">
<cfset local.permissionList = "">
<cfif qryUserPerm.AccessLevel EQ "S">
<cfset local.permissionType = qryUserPerm.AccessType>
<cfset local.permissionLevel = qryUserPerm.AccessLevel>
<cfset local.permissionList = qryUserPerm.State>
<cfelseif qryUserPerm.AccessLevel EQ "C">
<cfset local.permissionType = qryUserPerm.AccessType>
<cfset local.permissionLevel = qryUserPerm.AccessLevel>
<cfset local.permissionList = ListRemoveDuplicates(ValueList(permissionList,qryUserPerm.City))>
<cfelseif qryUserPerm.AccessLevel EQ "B">
<cfset local.permissionType = qryUserPerm.AccessType>
<cfset local.permissionLevel = qryUserPerm.AccessLevel>
<cfset local.permissionList = ListRemoveDuplicates(ValueList(permissionList,qryUserPerm.Building))>
</cfif>
Code above should be translated to cfscript, I got this far but can't figure it out how to access column values.
<cfscript>
public string function permissionList(required string AccountID) {
local.fnResults = "";
local.permissionList = "";
try{
local.qryPermissions = new Query();
local.qryPermissions.setDatasource("#Application.dsn#");
local.qryPermissions.setSQL("SELECT AccessType, AccessLevel, State, City, Building FROM Permissions WHERE AccountID = :AccountID");
local.qryPermissions.addParam(name="AccountID",value="#trim(arguments.AccountID)#",cfsqltype="cf_sql_idstamp");
local.qryRes = qryPermissions.execute();
for ( i = 1 ; i <= qryRes.getResult().recordCount ; i++ ) {
if(qryRes["AccessLevel"][i] EQ "S"){
local.permissionList = "";
}else if(qryRes["AccessLevel"][i] EQ "S"){
local.permissionList = ListRemoveDuplicates(ValueList(qryRes.Agency,","));
}else if(qryRes["AccessLevel"][i] EQ "C"){
local.permissionList = ListRemoveDuplicates(ValueList(qryRes.District,","));
}else if(qryRes["AccessLevel"][i] EQ "B"){
local.permissionList = ListRemoveDuplicates(ValueList(qryRes.Building,","));
}
}
local.fnResults = permissionList;
}catch(any e){
local.fnResults = e.message;
//writeOutput(e.message);
}
return fnResults;
}
writeOutput(permissionList(AccountID));
</cfscript>
If anyone can help please let me know.
(From comments ...)
The issue is local.qryRes doesn't actually contain a query object. Confusingly, calling execute() doesn't return a query, but calling execute().getResult() does. Try changing the assignment from:
local.qryRes = qryPermissions.execute();
To:
local.qryRes = qryPermissions.execute().getResult();
A few other observations:
It is important to local scope ALL function variables, including your loop index i. Otherwise, you may get some bizarre and unpredictable results if the component is stored in a shared scope.
Although I don't think a loop is necessary, if you do loop, consider the simpler for..in syntax, instead of an indexed loop:
for (local.row in local.qryPermissions ) {
if (local.row.AccessType eq "S") {
//... code here
}
....
}
Since the access fields are so closely related, I'd probably have the function return a structure containing all three keys (AccessType, AccessLevel, PermissionList) rather than having three separate functions.
Rather than using a loop, consider going with one of the suggestions on your other thread,
Best way to store permissions for the user account?
You can also use :
local.qryPermissions = queryExecute(
"SELECT AccessType, AccessLevel, State, City, Building
FROM Permissions
WHERE AccountID = :AccountID" ,
{AccountID={value="#trim(arguments.AccountID)#", cfsqltype="cf_sql_idstamp"}} // Or "?" and "[value=xxx,cfsqltype=xxx]"
) ;
And then just build out your permissions pieces without the loop:
local.permissionType = qryPermissions.AccessType ;
local.permissionLevel = qryPermissions.AccessLevel ;
switch( qryPermissions.AccessLevel ) {
case "S" : local.permissionList = qryPermissions.State ;
break ;
case "C" : local.permissionList = ListRemoveDuplicates(ValueList(qryPermissions.City)) ;
break ;
case "B" : local.permissionList = ListRemoveDuplicates(ValueList(qryPermissions.Building)) ;
break ;
}
Also see my notes on the other question about potential for unintentional, semi-related data.
I want to reduce the overhead of spider/crawler traffic. I'm not expecting to catch all of it, but if I can catch 90% of it then it's a win.
What's the best way to conditionally turn on/off session or client management in application.cfc? I'm thinking something along the lines of this, but I'm not sure if the CGI scope is always defined and initialized when application.cfc is instantiated.
this.sessionManagement = !isSpiderRequest();
and:
private boolean function isSpiderRequest() {
if (REFindNoCase("googlebot|msnbot|crawler|crawling|spider|wget|curl|baidu|robot|slurp|Gigabot|ia_archiver|libwww-perl|lwp-trivial|Mediapartners-Google", CGI.HTTP_USER_AGENT))
return(true);
return(false);
}
We set the session timeout to 10 seconds for bots. They don't get errors, but don't consume any (much) memory.
<!--- SET UP THE APP --->
<cfscript>
THIS.Name = "ASDF";
THIS.ApplicationTimeout = createTimeSpan( 0, 0, 60, 0 );
THIS.SetClientCookies = true;
THIS.Datasource = "ASDF";
THIS.SessionManagement = true;
// TEST WHETHER USER IS A BOT
THIS.IsBot = THIS.checkUserAgent();
// VISITOR IS A BOT ~ SET FAST TIMEOUT
if (THIS.IsBot == true) {
//abort;
THIS.SessionTimeout = createTimeSpan( 0, 0, 0, 10 );
// VISITOR IS A NOT A BOT ~ SET SLOW TIMEOUT
} else {
THIS.SessionTimeout = createTimeSpan( 0, 0, 60, 10 );
}
</cfscript>
<cffunction name="checkUserAgent">
<cfscript>
// QUERY THE CURRENT LIST OF BOT WORDS
LOCAL.BotWordList = THIS.getBotWords();
// GET THE VISITORS CURRENT USER AGENT IN LOWER CASE
LOCAL.ThisAgent = trim(lCase(CGI.HTTP_USER_AGENT));
// look at the user agent to see if the browser
// browser's user agent contains a banned word
// return true or false
</cfscript>
</cffunction>
Alternative answer... I haven't tried this, but I don't see why it won't work.
<!--- SET UP THE APP --->
<cfscript>
THIS.Name = "ASDF";
THIS.ApplicationTimeout = createTimeSpan( 0, 0, 60, 0 );
THIS.Datasource = "ASDF";
THIS.SetClientCookies = true;
// TEST WHETHER USER IS A BOT
THIS.IsBot = THIS.checkUserAgent();
// VISITOR IS A BOT ~ SET FAST TIMEOUT
if (THIS.IsBot == true) {
THIS.SessionManagement = false;
// VISITOR IS NOT A BOT
} else {
THIS.SessionManagement = true;
THIS.SessionTimeout = createTimeSpan( 0, 0, 60, 10 );
}
</cfscript>
I have a function that should check the date of a file. If the file is greater than sixty seconds, a query should run and create a new file. The query takes sixty seconds to run.
This process works perfectly when it's not wrapped in a CFTHREAD. When CFTHREAD is used, nothing seems to happen. I get no errors. What I expect to see, is a new file being made. I never see that new file.
Where should I look for an error? What am I missing? Why is CFTHREAD not working?
<!--- GET CATEGORIES --->
<cffunction name="getCategories" access="remote">
<cfscript>
LOCAL.MaxFileAge = 60;
LOCAL.MaxFileUnits = 's';
// THE FILE
LOCAL.TheFileDaily = "#VARIABLES.JSDir#\#VARIABLES.DayMonth#-categories.json";
// THE FILE DOES NOT EXIST
if (fileExists(LOCAL.TheFileDaily) == false) {
LOCAL.MakeNewFile = true;
// THE FILE EXISTS
} else {
// GET THE DATE OF THE FILE
LOCAL.LastModified = getFileInfo(LOCAL.TheFileDaily).LastModified;
// GET FILE AGE
LOCAL.FileAge = dateDiff(LOCAL.MaxFileUnits, LOCAL.LastModified, now());
// FILE IS OLD
if (LOCAL.FileAge > LOCAL.MaxFileAge) {
LOCAL.MakeNewFile = true;
} else {
LOCAL.MakeNewFile = false;
}
}
</cfscript>
<cfif LOCAL.MakeNewFile eq true>
<cfthread action="run" priority="HIGH">
<cfquery name="Q">
SELECT Stuff
FROM Tables
</cfquery>
<!--- MAKE THE DAILY FILE --->
<cffile action="write" file="#LOCAL.TheFileDaily#" output="#serializeJSON(Q)#">
</cfthread>
</cfif>
</cffunction>
You can't write to and share the local scope to a seperate thread, you need to share them via the request scope (request is the ideal scope for this as developers have very tight control over what data is contained within). You might try something like this:
Create a struct within the request scope and write to that.
In fairness, only variables you need to transfer need be in the request scope's struct. This is just a generic update because I don't know what the contents of your CFTHREAD really looks like. In this case, it actually looks like TheFileDaily is the only variable you're sharing, so that would be the only thing that needed to be in the request scope.
<!--- GET CATEGORIES --->
<cffunction name="getCategories" access="remote">
<cfscript>
request.lData = StructNew();
request.lData.MaxFileAge = 60;
request.lData.MaxFileUnits = 's';
// THE FILE
request.lData.TheFileDaily = "#VARIABLES.JSDir#\#VARIABLES.DayMonth#-categories.json";
// THE FILE DOES NOT EXIST
if (fileExists(request.lData.TheFileDaily) == false) {
request.lData.MakeNewFile = true;
// THE FILE EXISTS
} else {
// GET THE DATE OF THE FILE
request.lData.LastModified = getFileInfo(request.lData.TheFileDaily).LastModified;
// GET FILE AGE
request.lData.FileAge = dateDiff(request.lData.MaxFileUnits, request.lData.LastModified, now());
// FILE IS OLD
if (request.lData.FileAge > request.lData.MaxFileAge) {
request.lData.MakeNewFile = true;
} else {
request.lData.MakeNewFile = false;
}
}
</cfscript>
<cfif request.lData.MakeNewFile eq true>
<cfthread action="run" priority="HIGH">
<cfquery name="Q">
SELECT Stuff
FROM Tables
</cfquery>
<!--- MAKE THE DAILY FILE --->
<cffile action="write" file="#request.lData.TheFileDaily#" output="#serializeJSON(Q)#">
</cfthread>
</cfif>
</cffunction>
Useful sources:
Working with Threads
Adam Cameron's post on the topic
I have a ColdFusion application that reads a list of files from a directory, and then converts each MSOffice document in the list to a PDF using the JODConverter library and OpenOffice.org 3.4.1.
I wrote this application and setup my development PC according the instructions in the two articles here:
http://cfsearching.blogspot.com/search/label/JODConverter
The only difference is that I installed the necessary JARs outside of cf_root.
<cffunction name="convertNonPDFFiles" returntype="Void" output="false">
<cfscript>
// CONSTANTs
var _NON_PDF_PATH = APPLICATION.PDFSource & "\NonPDFs";
var _PDF_PATH = APPLICATION.PDFSource & "\PDFs";
var _VALID_FILE_EXTENSIONS = "doc,docx,ppt,pptx";
// Set defaults for private variables
var _qNonPDFDir = QueryNew("");
var _fileName = "";
var _documentId = 0;
var _sourceFilePath = "";
var _destinationFilePath = "";
var _fileExtension = "";
var _isConversionSuccessful = true;
var _tempSourceFilePath = "";
var _tempImageFilePath = "";
// Initialize Open Office Conversion Manager
var _openOfficeManager =
CreateObject(
"java",
"org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration"
).setOfficeHome(
APPLICATION.OpenOfficeProgramPath // Location of the OpenOffice.org 3.4.1 application directory on the server
).setTaskExecutionTimeout(60000).buildOfficeManager();
_openOfficeManager.start();
</cfscript>
<!--- Retrieve a list of file names in the directory of unprocessed
non-PDF files --->
<cfdirectory
action="list"
directory="#_NON_PDF_PATH#"
name="_qNonPDFDir"
type="file"
listinfo="name"
sort="datelastmodified DESC" />
<cfoutput query="_qNonPDFDir">
<cfscript>
_fileName = _qNonPDFDir.name;
_fileExtension =
REQUEST.UDFLib.File.getFileExtension(_fileName);
_sourceFilePath = _NON_PDF_PATH & "\" & _fileName;
// File is a valid format for conversion
if (ListFindNoCase(_VALID_FILE_EXTENSIONS, _fileExtension)) {
_documentId =
REQUEST.UDFLib.File.getFileNameWithoutExtension(
_fileName
);
_destinationFilePath =
_PDF_PATH
& "\"
& REQUEST.UDFLib.File.getFileNameWithoutExtension(
_fileName
)
& ".pdf";
_isConversionSuccessful = true;
_tempSourceFilePath =
APPLICATION.TempDir
& "\"
& _documentId
& "." & _fileExtension;
/*
Create of the copy of the original file in the temp
directory
*/
FileCopy(
APPLICATION.of_aprimo_root & "\" & _documentId & ".dat",
_tempSourceFilePath
);
// Attempt to convert the file to PDF
try {
// See convertFile() method below
convertFile(
openOfficeManager = _openOfficeManager,
inputFilePath = _tempSourceFilePath,
outputFilePath = _destinationFilePath
);
}
catch (any e) {
_isConversionSuccessful = false;
}
if (_isConversionSuccessful)
FileMove(
_sourceFilePath,
_NON_PDF_PATH & "\Processed\"
);
else
FileMove(
_sourceFilePath,
_NON_PDF_PATH & "\NonFunctioning\"
);
}
// File is not a valid format for conversion
else {
FileDelete(_sourceFilePath);
}
</cfscript>
</cfoutput>
<cfscript>
_openOfficeManager.stop();
return;
</cfscript>
</cffunction>
<cfscript>
function convertFile(openOfficeManager, inputFilePath, outputFilePath) {
CreateObject(
"java",
"org.artofsolving.jodconverter.OfficeDocumentConverter"
).init(ARGUMENTS.OpenOfficeManager).convert(
CreateObject(
"java",
"java.io.File"
).init(ARGUMENTS.inputFilePath),
CreateObject(
"java",
"java.io.File"
).init(ARGUMENTS.outputFilePath)
);
return;
}
</cfscript>
This application works perfectly on my development machine, but as soon as I move it to one of my web servers, it doesn't work there.
Dev PC Setup:
OS: Windows 7 Professional SP1
IIS: 7
ColdFusion: 8.0.1
Server Setup:
OS: Windows 2003 R2 Standard Edition SP2
IIS: 6.0
ColdFusion: 8.0.1
When I attempt to run the application on the server - either directly in a browser or via Scheduled Tasks, it throws no exceptions. It simply appears to run until it times out after 60 minutes. In Task Manager, I can see soffice.bin start running when the application starts, but after a few seconds, soffice.bin simply disappears from the Task Manager.
Any ideas what might be the problem?
After some troubleshooting, I was finally able to get this to work with a few minor changes to the programming (all credit to cfSearching - I found the answer to my problem in the comments at http://cfsearching.blogspot.com/search/label/JODConverter).
Original code that configured and started the OpenOfficeManager instance:
CreateObject(
"java",
"org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration"
).setOfficeHome(
APPLICATION.OpenOfficeProgramPath
).setTaskExecutionTimeout(60000).buildOfficeManager();
Updated (fixed) to add setConnectionProtocol() and setPortNumber():
CreateObject(
"java",
"org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration"
).setOfficeHome(
APPLICATION.OpenOfficeProgramPath
).setConnectionProtocol(
CreateObject(
"java",
"org.artofsolving.jodconverter.office.OfficeConnectionProtocol"
).SOCKET
).setPortNumber(
8100
).setTaskExecutionTimeout(
60000
).buildOfficeManager();
It may be as simple as OpenOffice needing to be re-installed on the server where as it is on your dev machine.