convert html special character code in string coldfusion [duplicate] - html

I need a way to transform numeric HTML entities into their plain-text character equivalent. For example, I would like to turn the entity:
é
into the character:
é
Through some googling around I found a function called HtmlUnEditFormat, but this function only transforms named entities. Is there a way to decode numeric entities in ColdFusion?

Updated Answer:
Thanks to Todd Sharp for pointing out a very simple way to do this, using the Apache Commons StringEscapeUtils library, which is packaged with CF (and Railo), so you can just do:
<cfset Entity = "&##0233;" />
<cfset StrEscUtils = createObject("java", "org.apache.commons.lang.StringEscapeUtils") />
<cfset Character = StrEscUtils.unescapeHTML(Entity) />
Original Answer:
That linked function is icky - there's no need to name them explicitly, and as you say it doesn't do numerics.
Much simpler is to let CF do the work for you - using the XmlParse function:
<cffunction name="decodeHtmlEntity" returntype="String" output="false">
<cfargument name="Entity" type="String" hint="&##<number>; or &<name>;" />
<cfreturn XmlParse('<xml>#Arguments.Entity#</xml>').XmlRoot.XmlText />
</cffunction>
That one works with Railo, I can't remember if CF supports that syntax yet though, so you might need to change it to:
<cffunction name="decodeHtmlEntity" returntype="String" output="false">
<cfargument name="Entity" type="String" hint="&##<number>; or &<name>;" />
<cfset var XmlDoc = XmlParse('<xml>#Arguments.Entity#</xml>') />
<cfreturn XmlDoc.XmlRoot.XmlText />
</cffunction>

Here's another function that will decode all the numeric html character entities in a string. It doesn't rely on xml parsing so it will work on strings that contain unbalanced xml tags. It's not efficient if the string has a large number of entities, but it's pretty good if there are none/few. I have only tested this on Railo, not AdobeCF.
<cffunction name="decodeHtmlEntities" returntype="String" output="false">
<cfargument name="s" type="String"/>
<cfset var LOCAL = {f = ReFind("&##([0-9]+);", ARGUMENTS.s, 1, true), map={}}>
<cfloop condition="LOCAL.f.pos[1] GT 0">
<cfset LOCAL.map[mid(ARGUMENTS.s, LOCAL.f.pos[1], LOCAL.f.len[1])] = chr(mid(ARGUMENTS.s, LOCAL.f.pos[2], LOCAL.f.len[2]))>
<cfset LOCAL.f = ReFind("&##([0-9]+);", ARGUMENTS.s, LOCAL.f.pos[1]+LOCAL.f.len[1], true)>
</cfloop>
<cfloop collection=#LOCAL.map# item="LOCAL.key">
<cfset ARGUMENTS.s = Replace(ARGUMENTS.s, LOCAL.key, LOCAL.map[LOCAL.key], "all")>
</cfloop>
<cfreturn ARGUMENTS.s />
</cffunction>

It should be quite easy to code one up yourself. Just edit the HtmlUNEditFormat() func you found, to include them to the end of the lEntities & lEntitiesChars.

I found this question while working with a method that, by black-box principle, can't trust that an incoming string is either HTML entity encoded or that it is not.
I've adapted Peter Boughton's function so that it can be used safely on strings that haven't already been treated with HTML entities. (The only time this seems to matter is when loose ampersands - i.e. "Cats & Dogs" - are present in the target string.) This modified version will also fail somewhat gracefully on any unforseen XML parse error.
<cffunction name="decodeHtmlEntity" returntype="string" output="false">
<cfargument name="str" type="string" hint="&##<number>; or &<name>;" />
<cfset var XML = '<xml>#arguments.str#</xml>' />
<cfset var XMLDoc = '' />
<!--- ampersands that aren't pre-encoded as entities cause errors --->
<cfset XML = REReplace(XML, '&(?!(\##\d{1,3}|\w+);)', '&', 'all') />
<cftry>
<cfset XMLDoc = XmlParse(XML) />
<cfreturn XMLDoc.XMLRoot.XMLText />
<cfcatch>
<cfreturn arguments.str />
</cfcatch>
</cftry>
</cffunction>
This would support the following use case safely:
<cffunction name="notifySomeoneWhoCares" access="private" returntype="void">
<cfargument name="str" type="string" required="true"
hint="String of unknown preprocessing" />
<cfmail from="process#domain.com" to="someoneWhoCares#domain.com"
subject="Comments from Web User" format="html">
Some Web User Spoke Thus:<br />
<cfoutput>#HTMLEditFormat(decodeHTMLEntity(arguments.str))#</cfoutput>
</cfmail>
</cffunction>
This function is now incredibly useful for ensuring web-submitted content is entity-safe (think XSS) before it's sent out by email or submitted into a database table.
Hope this helps.

Related

cffunction: second argument based on first argument

I have following code that first creates an object and afterwards it calls a function called init.
<cfset SESSION.objWatchlist = createObject("component", "path") />
<cfset SESSION.objWatchlist.init(session.addressid) />
So far so good. The init function looks like this:
<cffunction name="init" access="remote" output="false">
<cfargument name="addressID" type="numeric" required="true" />
<cfset THIS.ADDRESSID = arguments.addressID />
<cfset THIS.WATCHLIST = arrayNew(1) />
<cfset initWatchlistArray() />
<cfreturn this />
</cffunction>
Now I want to add another argument to the cffunction. I will call it like this:
<cfset SESSION.objWatchlist.init("addressid", session.addressid) />
and
<cfset SESSION.objWatchlist.init("sessionid", session.sessionid) />
I add some new lines in the cffunction:
<cffunction name="init" access="remote" output="false">
<cfargument name="typeOfID" type="string" required="true" />
<cfif arguments.typeOfID eq "addressid">
<cfargument name="addressID" type="numeric" required="true" />
<cfset THIS.ADDRESSID = arguments.addressID />
<cfelseif arguments.typeOfID eq "sessionid">
<cfargument name="sessionID" type="string" required="true" />
<cfset THIS.SESSIONID = arguments.sessionID />
</cfif>
<cfset THIS.WATCHLIST = arrayNew(1) />
<cfset initWatchlistArray() />
<cfreturn this />
</cffunction>
But everytime I get the error "The tag must be nested inside a CFFUNCTION tag".
Now my question is how can I write a function in which the second argument is based on the first one?
Is this even possible?
Thank you.
At the end I have found a solution that looks like that:
First I call the function:
<cfset SESSION.objWatchlist.init(addressID=session.addressid) />
<cfset SESSION.objWatchlist.init(sessionID=session.sessionid) />
I changed the function to following:
<cffunction name="init" access="remote" output="false">
<cfargument name="addressID" type="numeric" required="false" />
<cfargument name="sessionID" type="string" required="false" />
<cfif isDefined("arguments.addressid")>
<cfset THIS.ADDRESSID = arguments.addressID />
<cfelseif isDefined("arguments.sessionid")>
<cfset THIS.SESSIONID = arguments.sessionid />
</cfif>
<cfset THIS.WATCHLIST = arrayNew(1) />
<cfset initWatchlistArray() />
<cfreturn this />
</cffunction>
When calling the function I can call them with the name of the argument in the cffunction.
Afterwards I can check which one is defined.
This is too long for a comment, but I have a little cleanup on this
SESSION.objWatchlist.init(addressID=session.addressid);
SESSION.objWatchlist.init(sessionID=session.sessionid);
any function init(numeric addressID, string sessionid) access="remote" output="false" {
if (arguments.keyexists(("addressid")) { THIS.ADDRESSID = arguments.addressID; }
else if (arguments.keyexists("sessionid") { THIS.SESSIONID = arguments.sessionid; }
THIS.WATCHLIST = [];
initWatchlistArray();
return this;
}
Note: the use of .keyexists(). This is a faster check because it does not have to look through every scope that could have something that matches.
Also note it is easier to blank out an array.

Coldfusion Lucee 4.5.2.018 (Linux) - REST service (can't cast String) JSON

working on REST web-service, i don't have much experience coldfusion web-services.It is very basic web-service.Please if you guys can point me, what im doing wrong. it will be great help.
Application Server : Lucee 4.5.2.018 (Linux)
Please find below my code.
Component-Function/ Web-Service.
<cfcomponent rest="true" restpath="/hello">
<cffunction name="formPost" access="remote" returnType="struct" httpMethod="POST" restPath="/name" hint="POST Method" produces="application/json">
<cfargument name="firstname" type="String" restArgSource="Form">
<cfargument name="lastname" type="String" restArgSource="Form">
<cfset myStruct = structnew()>
<cfset myStruct.FirstName = firstname>
<cfset myStruct.LastName = lastname>
<cfquery name="Qry" datasource="myDSN">
select col1,col2 from myTableData
</cfquery>
<cfset myJsonVar = serializeJSON(Qry) />
<cfreturn myJsonVar>
</cffunction>
</cfcomponent>
Calling web-service
<cfhttp url="http://mydev:8888/rest/Example/hello/name" method="POST" result="res" port="8888" >
<cfhttpparam type="header" name="Accept" value="application/json">
<cfhttpparam type="formfield" name="firstname" value="Dan">
<cfhttpparam type="formfield" name="lastname" value="Gates">
</cfhttp>
<cfdump var="#res#">
Problem:
When defining returnType="struct" Error string can't cast String [{"COLUMNS":["COL1","COL2"],"DATA":[["0","7777777"],["0","888888"]]}] to a value of type [struct]
When defining returnType="string" No error coming "{\"COLUMNS\":[\"COL1\",\"COL2\"],\"DATA\":[[\"0\",\"7777777\"],[\"0\",\"888888\"]]}"
Trying get [DATA] values in loop
<cfloop from="1" to="#ArrayLen(d.DATA)#" index="i">
<cfloop from="1" to=#ArrayLen(d.DATA[i])# index="j">
<cfset resultSrt =d.COLUMNS[j]&" = " &d.DATA[i][j]>
#resultSrt#<br>
</cfloop>
</cfloop>
Message: No matching property [DATA] found in [string]
Stacktrace:The Error Occurred in
/opt/lucee/tomcat/webapps/ROOT/calling.cfm: line 52
50:
51:
52: <cfloop from="1" to="#ArrayLen(d.DATA)#" index="i">
53: <cfloop from="1" to=#ArrayLen(d.DATA[i])# index="j">
54: <cfset resultSrt =d.COLUMNS[j]&" = " &d.DATA[i][j]>
First of all since you are returning a query, you should set returnType to Query.
If you have set produces attribute of cffunction to application/json, in that case you don't need to perform explicit JSON serialization while returning data. ColdFusion will automatically do it for you. You can just write:
<cfreturn Qry />
To read the result returned from the service you need to deserialize the data. Like this:
<cfdump var="#deserializeJson(res.filecontent)#">

Can I pass a struct to a function and have it translated to multiple parameters?

In ColdFusion, is there any way to pass in a struct of parameters to a function with multiple optional parameters?
For example, I want to do something like this:
<cfset myResults = myFunction(myStruct) />
<cffunction name="myFunction" ... >
<cfargument name="myArg1" type="numeric" required="no" default="" />
<cfargument name="myArg2" type="string" required="no" default="" />
<cfargument name="myArg3" type="numeric" required="no" default="" />
.....
</cffunction>
Where "myStruct" has a random combination of key-value pairs - for example, "myArg3":222 and "myArg2":"hello".
Is this possible, or do I have to specifically list each argument (with a check of "isDefined" for each one)?
Ok, I haven't tested this yet, but I just realized I might be able to do this using a <cfinvoke argumentCollection="#myStruct#">. Will try that now...
Edit:
This did work! And Sergii's suggestion for my original syntax without a cfinvoke works as well.

Coldfusion ENCRYPT and MySQL AES_DECRYPT Working together?

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 ...

how to get Exception details from CFC file

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());
}