I have a query running to gather an adjacency list and then generate an XML object of that list as a tree. Next I need to output that tree as a simple HTML.
I would like my output of XML document to be:
<ul>
<li margin="5">Title
<ul>
<li margin="10">Title</li>
</ul>
</li>
</ul>
Here is what I have coded so far:
<cfquery name="nodeTable" datasource="#database.ds#">
SELECT [mc_location].[id],[mc_location].[title], [mc_location].[parent_id] FROM [mc_location]
LEFT JOIN [mc_location_type] ON [mc_location].[id] = [mc_location_type].[location_id]
WHERE [mc_location_type].[category] = 'staff'
</cfquery>
<cffunction name="outputChildNodes" access="public" returntype="void" output="true">
<cfargument name="nodeTable" type="query" required="true" hint="I am the node query object."/>
<cfargument name="parent_id" type="numeric" required="false" default="0"/>
<cfset var local = {}/>
<cfquery name="local.childNodes" dbtype="query">
SELECT id, parent_id, title
FROM arguments.nodeTable
WHERE parent_id = <cfqueryparam value="#arguments.parent_id#" cfsqltype="cf_sql_integer" />
ORDER BY id ASC
</cfquery>
<cfloop query="local.childNodes">
<child id="#local.childNodes.id#" parent-id="#local.childNodes.parent_id#" name="#local.childNodes.title#">
<cfset outputChildNodes(arguments.nodeTable, local.childNodes.id)/>
</child>
</cfloop>
<cfreturn/>
</cffunction>
<!--- Build the node XML document recursively. --->
<cfxml variable="nodeTree">
<childern>
<!--- Output the root-level nodes. --->
<cfset outputChildNodes( nodeTable ) />
</childern>
</cfxml>
<!--- Render the XML document. --->
<cfloop index="childern" array="#nodeTree.childern#">
<cfloop index="child" array="#childern#">
<cfif isStruct(child.XmlAttributes)>
<cfdump var="#child[1].XmlAttributes#"/>
</cfif>
</cfloop>
</cfloop>
Thank you!
The problem I was experiencing had to do with not properly defining variable scopes (e.g. using "var" in cfset, using arguments.parameter, etc.), which was necessary in order to recursively call a function. Presented below is a brief solution.
<!--- query for parent child tree --->
<cfquery name="tree_nodes" datasource="#sonis.ds#">
SELECT [location].[id],[location].[title], [location].[parent_id] FROM [location]
LEFT JOIN [location_category] ON [location].[id] = [location_category].[location_id]
WHERE [location_category].[category] = 'staff'
</cfquery>
<!--- build tree from adjacency list function --->
<cffunction name="build_tree" access="public" output="true">
<cfargument var name="tree_nodes" type="query" required="true"/>
<cfargument var name="parent_id" type="numeric" required="false" default="0"/>
<cfargument var name="depth" type="numeric" required="false" default="0"/>
<cfset var local = {}/>
<cfquery name="local.child_node" dbtype="query">
SELECT id, parent_id, title
FROM arguments.tree_nodes
WHERE parent_id = <cfqueryparam value="#arguments.parent_id#" cfsqltype="cf_sql_integer" />
ORDER BY id ASC
</cfquery>
<cfset var branch = {}/>
<cfset var counter = 1/>
<cfloop query="local.child_node">
<cfset local.depth = arguments.depth/>
<cfset branch[counter++] = {
'id' = '#local.child_node.id#',
'title' = '#local.child_node.title#',
'parent_id' = '#local.child_node.parent_id#',
'depth' = local.depth,
'children' = build_tree(arguments.tree_nodes, local.child_node.id,++local.depth)
} />
</cfloop>
<cfreturn branch/>
</cffunction>
<!--- print tree as select box function --->
<cffunction name="print_tree_select" access="public" output="true">
<cfargument var name="tree" type="struct" required="true"/>
<cfargument var name="selected" type="numeric" required="false" default="0"/>
<cfargument var name="child" type="numeric" required="false" default="0"/>
<cfif child eq '0'><select name="select_tree"><option value="null"></option></cfif>
<cfloop from="1" to="#StructCount(arguments.tree)#" index="a">
<option value="#arguments.tree[a]['id']#"<cfif #arguments.selected# eq #arguments.tree[a]['id']#> selected</cfif>>
<cfif #arguments.tree[a]['depth']# GT 0>
#RepeatString('--', arguments.tree[a]['depth'])#
</cfif>
#arguments.tree[a]['title']#
</option>
<cfif StructKeyExists(arguments.tree[a], 'children') AND StructCount(arguments.tree[a]['children']) GT 0>
#print_tree_select(arguments.tree[a]['children'],arguments.selected, 1)#
</cfif>
</cfloop>
<cfif child eq '0'></select></cfif>
</cffunction>
<!--- print tree as list function --->
<cffunction name="print_tree_list" access="public" output="true">
<cfargument var name="tree" type="struct" required="true"/>
<ul style="list-style-type: circle;">
<cfloop from="1" to="#StructCount(arguments.tree)#" index="local.i">
<li>
<cfform method="post" name="edit">
#arguments.tree[local.i]['title']#
<cfinput type="hidden" name="id" value="#arguments.tree[local.i]['id']#"/>
<cfinput type="Submit" name="command" value="Edit"/>
</cfform>
<cfif StructKeyExists(arguments.tree[local.i], 'children') AND StructCount(arguments.tree[local.i]['children']) GT 0>
#print_tree_list(arguments.tree[local.i]['children'])#
</cfif>
</li>
</cfloop>
</ul>
</cffunction>
Using a AJAX Based Triple Chained/Related Selects in Cold Fusion
I am getting Error Invoking CFC : Internal Server Error Adding cfdebug tag doesn't help
The Triple Chained/Related Select works fine, but generates the error. How can I make stop it from happening. I believe my CFC is coded correctly
Any help will be appreciated
Already Tried bindonload=false for Second Select Does not help Also Tried bindonload=false for First Select Options dont load
Here is my code
CFC:
<!--- Get array of media types --->
<cffunction name="getDevice" access="remote" returnType="array">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="#dsn#">
SELECT device_id, device_list
FROM pa_device
ORDER BY device_list
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.device_id[i]>
<cfset result[i][2]=data.device_list[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
<!--- Get art by media type --->
<cffunction name="getProblem" access="remote" returnType="array">
<cfargument name="device_id" type="numeric" required="true">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="#dsn#">
SELECT problem_id, problem_list
FROM pa_problem
WHERE device_id = #ARGUMENTS.device_id#
ORDER BY problem_list
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.problem_id[i]>
<cfset result[i][2]=data.problem_list[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
<!--- Get art by media type --->
<cffunction name="getdescription" access="remote" returnType="array">
<cfargument name="device_id" type="numeric" required="true">
<cfargument name="problem_id" type="numeric" required="true">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="#dsn#">
SELECT description_id, description_list, device_id
FROM pa_description
WHERE device_id = #ARGUMENTS.device_id# and problem_id =#arguments.problem_id#
ORDER BY description_list
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.description_id[i]>
<cfset result[i][2]=data.description_list[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
CFM
<cfform>
<table>
<tr>
<td>Select Device Type:</td>
<td><cfselect name="device"
bind="cfc:art.getDevice()"
bindonload="true" /></td>
</tr>
<tr>
<td>Select Problem Type:</td>
<td><cfselect name="problem"
bind="cfc:art.getProblem({device})"
bindonload="false" /></td>
</tr>
<tr>
<td>Select Description Type:</td>
<td><cfselect name="description"
bind="cfc:art.getdescription({device},{problem})"
bindonload="false"/></td>
</tr>
</table>
I have a simple CFC page which output data in a JSON format:
<cffunction name="test" access="remote" returnformat="plain" output="true">
<cfquery datasource="#dns#" name="rs.q" maxrows="5">
select text
from table
</cfquery>
<cfreturn serializeJSON( rs.q ) />
</cffunction>
The text outputted by the query can contain images, e.g., /webimages/1.jpg. Now for the webservice I want to search for images and replace them with http://domain.com/webimages/1.jpg.
Can that be done in the CFC file?
<cffunction name="test" access="remote" returnformat="json" output="false">
<cfquery datasource="#dns#" name="local.rs.q" maxrows="5">
select replace(text, "/webimages/", "http://domain.com/webimages/") as text
from table
</cfquery>
<cfreturn rs.q>
</cffunction>
or
<cffunction name="test" access="remote" returnformat="plain" output="false">
<cfquery datasource="#dns#" name="local.rs.q" maxrows="5">
select text
from table
</cfquery>
<cfreturn replace(serializeJSON(rs.q),
"\/webimages\/",
"http:\/\/domain.com\/webimages\/",
"all")>
</cffunction>
I am using ColdFusion 9, and MySQL 5.1. I am trying to align the ColdFusion encrypt/decrypt functions and mySQL AES_ENCRYPT/AES_DECRYPT so I can use them interchangeably depending on the situation. Not having much luck with that.
First I created an AES string with ColdFusion:
<cfset theKey = generateSecretKey("AES") />
<cfoutput>#theKey#</cfoutput>
Example key: 4OFWUiuqFEkGrSRFm8sLlg==
I use this key to encrypt with MySQL. Note, encrypt_test is an existing table, and fld is a varchar column.
INSERT INTO encrypt_test
SET fld = aes_encrypt('the text to encrypt', '4OFWUiuqFEkGrSRFm8sLlg==')
Next I try to decrypt with ColdFusion:
<cfset theKey = "4OFWUiuqFEkGrSRFm8sLlg=="
<cfset theAlgorithm = "AES" />
Then run a cfquery to get the data (Only 1 record in the table),
<cfquery name="testDecrypt">
SELECT fld FROM encrypt_test
</cfquery`
And finally decrypt
<cfoutput>#Decrypt(testDecrypt.fld, theKey, theAlgorithm)#</cfoutput>
This results in a Null. I suspect its a padding issue or some other mismatch, anyone have an idea what I am doing wrong, or how to make this work?
I know this thread is old, but the answer came up on a recent thread. So I am posting it for posterity. As explained in this blog entry, the reason for the difference is:
.. the MySQL algorithm just or’s the bytes of a given passphrase
against the previous bytes if the password is longer than 16 chars and
just leaves them 0 when the password is shorter than 16 chars.
So you need to perform the same manipulations on the key value, before passing it into encrypt/decrypt.
I would stick with just using CF's functions. That way you can add all kinds of layers of security processes, to include things like iterations and multiple keys, to build a custom solution with ease. THe amount of overhead it adds is not much at all for that as well.
Why don't you use ColdFusion's encrypt function instead of MySQL's?
In fact that would be one way to test where the problem might lie : try outputting both the encrypted value from your database and what CF's encrypt function would produce and see if they're identical.
Alternatively just use the aes_decrypt function in your query instead of using ColdFusion's decrypt.
Hmmm, from the docs:
Because AES is a block-level algorithm, padding is used to encode uneven length strings and so the result string length may be calculated using this formula:
16 * (trunc(string_length / 16) + 1)
If AES_DECRYPT() detects invalid data or incorrect padding, it returns NULL.
So assuming CFML doesn't do that padding, you'd have to figure out the reverse of this yourself or something.
I know it's quite an old post but here is what you should do:
Before storing into the DB:
<cfset crypt_fld = #encrypt('the text to encrypt', thekey, 'AES')#>
Then:
INSERT INTO encrypt_test
SET fld = crypt_fld
It worked for me
Use jBCrypt :: bCrypt is the strongest encryption available ... with the assistance of Mark Mandel's Fantastic JavaLoader
implementing jBCrypt is a snap in ColdFusion ...
As far as the password field it really doesn't matter what kind of database you're using ... the field could be varchar(60) or nvarchar(60) if you're dealing with locale support too...
<cfcomponent title="bcrypt (strong; recommended)" hint="I encode passwords using a popular secure password hashing algorithm called bcrypt. I am very slow, but that makes me very secure!" extends="PasswordHash"
alias="bcrypt" seq="9001" workFactor="10">
<cfset variables.loadPaths = [expandPath( "/PATHTOLIBDIR/lib/jbcrypt/jbcrypt-0.3m.jar" )]/>
<cffunction name="init" access="public" output="true" returntype="any" hint="constructor">
<cfset super.init( )/>
<!--- Allow java loader to fail silently: we can report the failure via isAvailable() --->
<cftry>
<cfset variables.oBCryptClass = createJavaClass( "org.mindrot.jbcrypt.BCrypt" )/>
<cfcatch></cfcatch>
</cftry>
<cfreturn this/>
</cffunction>
<cffunction name="isAvailable" hint="Is the hashing agorithm available in this environment?" access="public" returntype="boolean">
<cfreturn structKeyExists( variables, "oBCryptClass" )/>
</cffunction>
<cffunction name="matchesHashFormat" hint="Does the string match the format for this hash?" access="public" returntype="boolean">
<cfargument name="input" type="string" hint="String that may be a password hash" required="true"/>
<cfreturn REFind( "^\$2a\$\d+\$[\./A-Za-z0-9]+$", arguments.input )/>
</cffunction>
<cffunction name="encode" hint="Convert a clear password to its encoded value" access="public" returntype="string">
<cfargument name="password" type="string" hint="Input password" required="true"/>
<cfset var salt = variables.oBCryptClass.gensalt( JavaCast( "int", this.workFactor ) )/>
<cfreturn variables.oBCryptClass.hashpw( arguments.password, salt )/>
</cffunction>
<cffunction name="getHashWorkFactor" hint="Retrieve the work factor from a hashed string" access="public" returntype="numeric">
<cfargument name="hashedPassword" type="string" hint="Previously encoded password string" required="true"/>
<cfset var stMatch = ReFind( "^\$2a\$(\d+)\$([\./A-Za-z0-9]+)$", arguments.hashedPassword, 1, "true" )/>
<cfif stMatch.pos[1] eq 0>
<cfreturn 0>
<cfelse>
<cfreturn mid( arguments.hashedPassword, stMatch.pos[2], stMatch.len[2] )>
</cfif>
</cffunction>
<cffunction name="passwordMatch" hint="Compare a plain password against an encoded string" access="public" returntype="boolean">
<cfargument name="password" type="string" hint="Input password" required="true"/>
<cfargument name="hashedPassword" type="string" hint="Previously encoded password string" required="true"/>
<cfargument name="bCheckHashStrength" type="boolean" default="false" hint="If true, the hash strength of the hashed password must also match those generated by encode()"/>
<cfset var bMatch = variables.oBCryptClass.checkpw( arguments.password, arguments.hashedPassword )/>
<cfif bMatch and bCheckHashStrength>
<!--- Hash matched but we also need to match the bCrypt work factor --->
<cfreturn getHashWorkFactor( arguments.hashedPassword ) eq this.workFactor/>
<cfelse>
<cfreturn bMatch/>
</cfif>
</cffunction>
The PasswordHash.cfc ...
<cfcomponent hint="I am an abstract component for encoding passwords for storage and comparing passwords against previously encoded strings">
<!--- Array of Java class paths required for this component. Leave empty if no special Java libraries are needed. --->
<cfset variables.loadPaths = []/>
<cffunction name="init" access="public" output="true" returntype="any" hint="constructor">
<cfset var stMetadata = getMetadata( this )/>
<cfset var attr = ""/>
<cfloop condition="not structisempty(stMetadata)">
<!--- Get attributes --->
<cfloop collection="#stMetadata#" item="attr">
<cfif issimplevalue( stMetadata[attr] ) and not listcontains( "bindingname,extends,fullname,functions,hint,name,namespace,output,path,porttypename,serviceportname,style,type,wsdlfile", attr ) and not structkeyexists( this, attr )>
<cfset this[attr] = stMetadata[attr]/>
</cfif>
</cfloop>
<!--- Do the same for ancestors --->
<cfif structkeyexists( stMetadata, "extends" )>
<cfset stMetadata = stMetadata.extends/>
<cfelse>
<cfset stMetadata = structnew( )/>
</cfif>
</cfloop>
<cfset stMetadata = getMetadata( this )/>
<!--- If key isn't specified, use the name of the component --->
<cfif not structkeyexists( this, "alias" )>
<cfset this.alias = listlast( stMetadata.name, "." )/>
</cfif>
<!--- If title isn't specified, use the displayname --->
<cfif not structkeyexists( this, "title" )>
<cfset this.title = this.displayname/>
</cfif>
<!--- If seq isn't specified, use 9999 --->
<cfif not structkeyexists( this, "seq" )>
<cfset this.seq = 9999/>
</cfif>
<cfreturn this/>
</cffunction>
<cffunction name="isAvailable" hint="Is the hashing agorithm available in this environment?" access="public" returntype="boolean">
<cfreturn true/>
</cffunction>
<cffunction name="matchesHashFormat" hint="Does the string match the format for this hash?" access="public" returntype="boolean">
<cfargument name="input" type="string" required="true" hint="String that may be an encoding of a password"/>
<cfthrow message="The #this.alias# password encoding needs to implement the matchesHashFormat function"/>
<cfreturn ""/>
</cffunction>
<cffunction name="encode" hint="Convert a clear password to its encoded value" access="public" returntype="string">
<cfargument name="password" type="string" required="true" hint="Input password"/>
<cfthrow message="The #this.alias# password encoding needs to implement the encode function"/>
<cfreturn ""/>
</cffunction>
<cffunction name="passwordMatch" hint="Compare a plain password against an encoded string" access="public" returntype="boolean">
<cfargument name="password" type="string" required="true" hint="Input password"/>
<cfargument name="hashedPassword" type="string" required="true" hint="Previously encoded password string"/>
<cfargument name="bCheckHashStrength" type="string" default="false" hint="If true, the hash strength of the hashed password must also match those generated by encode()"/>
<cfthrow message="The #this.alias# password encoding needs to implement the passwordMatch function"/>
<cfreturn false/>
</cffunction>
<!--- Private Java library helper functions --->
<cffunction access="private" name="getJavaLoader" returntype="any" output="false">
<!--- Lazy-loading the JavaLoader makes it easier for plugins/projects to add custom crypto libraries --->
<cfif not structKeyExists( variables, "loader" )>
<cfset variables.loader = createObject( "component", "PATH.TO.JavaLoader" ).init( variables.loadPaths )/>
</cfif>
<cfreturn variables.loader/>
</cffunction>
<cffunction access="private" name="createJavaClass" returntype="any" output="false" hint="Return a java class from the crypto libraries">
<cfargument name="className" type="string" required="true"/>
<cfreturn getJavaLoader( ).create( arguments.className )/>
</cffunction>
... yada yada ... more code ...
I have a Function in CFC file, which will be called from .cfm file like below
<cffunction name="cftest" access="public" returntype="query" output="true" hint="Function returns Records">
<cfquery name="qryTest" datasource="DBTest">
select * from emp_tab;
</cfquery>
<cfreturn selectRecordsResultSet />
</cffunction>
How can I handle DB Exception using cftry? as this is returning Query, Is it possible to catch the DB Exception and pass the Details to the other page from where it is called?
Thanks
Here is an example of my usual implementation of this:
<cffunction name="getCurrentRecordsCount" access="public" output="false" returntype="any" hint="Get total history records count">
<cfargument name="filters" type="struct" required="false" default="#StructNew()#" hint="Filtering rules">
<cfset var qGetRecordCount = "" />
<cftry>
<cfquery datasource="#variables.dsn#" name="qGetRecordCount">
SELECT COUNT(*) AS cnt FROM ....
</cfquery>
<cfreturn qGetRecordCount.cnt />
<cfcatch type="any">
<cfreturn error(cfcatch.message, cfcatch.detail) />
</cfcatch>
</cftry>
</cffunction>
If you want to handle only database errors, change type to the database.
Errors handling and reporting performed using these three methods:
<cffunction name="error" access="private" output="false" returntype="boolean" hint="Set error status and message">
<cfargument name="message" type="string" required="true" hint="Error message text" />
<cfargument name="detail" type="string" required="false" default="" hint="Error detail text" />
<cfset variables.fError = true />
<cfset variables.fErrorText = arguments.message />
<cfif Len(arguments.detail)>
<cfset variables.fErrorText = variables.fErrorText & " [" & arguments.detail & "]" />
</cfif>
<cfreturn false />
</cffunction>
<cffunction name="gotError" access="public" output="false" returntype="boolean" hint="Return latest error flag state">
<cfreturn variables.fError />
</cffunction>
<cffunction name="getError" access="public" output="false" returntype="string" hint="Return latest error text and reset the flag">
<cfset var txt = variables.fErrorText />
<cfset variables.fError = false />
<cfset variables.fErrorText = "" />
<cfreturn txt />
</cffunction>
Please note that for methods with returntype="void" I use cfset instead of cfreturn:
<cfset error(cfcatch.message, cfcatch.detail) />
So in code I can do the following (cfscript):
// calculate filtered records count
totalLogCount = request.loggingService.getCurrentRecordsCount(filters);
// check if error was thrown
if (request.loggingService.gotError()) {
// report the error details somehow
WriteOutput(request.loggingService.getError());
}