A little ReReplace CFConfusion (solved)
Feb/100
The following two snippets are only different in regard to the iSomeVal string which is used in a Regex replacement string. The first is a string that starts with a character (‘fortytwo’) the second is a string that starts with a number (‘42′). The first example is working fine, whereas the second is somewhat lacking something quite essential:
<cfscript> variables.strSource = 'The answer is: Hmm.'; variables.iSomeVal = 'fortytwo'; variables.strTarget = ReReplace(variables.strSource,'^(.*:\s).*$','\1'&variables.iSomeVal,'ALL'); writeOutput('~~' & variables.strTarget & '~~'); </cfscript>
Output: ~~The answer is: fortytwo~~
<cfscript> variables.strSource = 'The answer is: Hmm.'; variables.iSomeVal = '42'; variables.strTarget = ReReplace(variables.strSource,'^(.*:\s).*$','\1'&variables.iSomeVal,'ALL'); writeOutput('~~' & variables.strTarget & '~~'); </cfscript>
Output: ~~The answer is:~~
WTF?
A few brain processor cycles later you realize what’s going on: The replacement string now reads ‘\142′ – and there’s no back reference with that number.
So we need a little ugly trick because slash-escaping won’t help us here either. We’ll use the \u operator which usually would indicate to uppercase the following character (which in our case is an integer, so this doesn’t harm us):
<cfscript> variables.strSource = 'The answer is: Hmm.'; variables.iSomeVal = '42'; variables.strTarget = ReReplace(variables.strSource,'^(.*:\s).*$','\1\u'&variables.iSomeVal,'ALL'); writeOutput('~~' & variables.strTarget & '~~'); </cfscript>
Output: ~~The answer is: 42~~
Now in this case we’re lucky. Any suggestions on what could be done if we don’t actually know if the variable replacement bit after the first back reference would begin with a character or a number? I don’t want to hack around it with a separating space or something similar – which could of course be removed in a second pass, but this doesn’t seem elegant… Feels like I’m missing something extremely obvious here…
Update: Seems like I’m not missing anything ColdFusion-wise. There’s actually a RegEx feature described on regular-expression.info as ‘$10 through $99 treated as $1 through $9 (and a literal digit) if fewer than 10 groups’. There’s no clue as to the implementation in ColdFusion here, but judging from what I’ve seen in my example code, I’d say it’s fair to assume that CF does not deliver the desired result in this category. But alas, all is not lost as we’re running on top of Java, which I cannot ever shout out happily quite often enough under such circumstances. For behold:
<cfscript> variables.objRegex = createObject('component','JavaRegExp'); variables.strSource = 'The answer is: Hmm.'; variables.iSomeVal = '42'; variables.strTarget = variables.objRegex.regExpReplace('^(.*:\s).*$',variables.strSource,'$1'&variables.iSomeVal,true); writeOutput('~~' & variables.strTarget & '~~'); </cfscript>
Output: ~~The answer is: 42~~
Yay! This snipped doesn’t use ReReplace but the Java RegEx Component by massimocorner.com I mentioned in an earlier post UDF to strip certain chars, but leave UBB tags alone.
Using client-side caching in ColdFusion
Jan/100
The cheapest request you can think of is the one where you actually don’t need to provide an answer – because you have answered it before and you know that facts haven’t changed. Now server-side caching is one approach, but in that case you just save yourselves the actual computing, you still have to retrieve your answer from the cache and deliver it to the client. Client-side caching is much more elegant.
ColdFusion UDF to test if a Java Class implements a method
Sep/090
I recently started implementing a couple of our full text search requirements using Sphinx. I am extremely happy with this search engine, as it’s lightning fast and provides some quite easy integration with the data we store in our PostgreSQL databases, is highly scalable and fairly easy to implement in ColdFusion via the Sphinx Client API.
FYI: Function returning Void kills Variables
Sep/091
I recently discovered some interesting behaviour in Coldfusion. If you ask for a result of a function in a variable and you set returntype void, the variable is destroyed and cant be found after this.
Example:
<cffunction name="getSomething" returntype="void"> Do something here, like updating a database or increasing a counter value </cffunction> <cfset VARIABLES.RecieveSomething = ""> <cfset VARIABLES.RecieveSomething= getSomeThing()> <cfif IsDefined("VARIABLES.RecieveSomething")> still there <cfelse> cant found this variable anymore </cfif>
Returntype Void is kinda tricky, so use it well-considered.
UDF to grab a frame from an FLV to JPG
Sep/090
This requires FFMPEG to be installed on your server. Here’s the UDF:
<cffunction name="flvgrabber" access="public" output="no" returntype="void" hint="grabs a frame from an FLV at a specified second and renders it as a JPG"> <cfargument name="strPathToFLV" type="string" required="yes" hint="absolute path to the source flv"> <cfargument name="strPathToJPG" type="string" required="yes" hint="absolute path to the target JPG; if file exists and is writeable, it will be overwritten"> <cfargument name="strFrameAtTime" type="string" required="no" default="00:00:05" hint="time at which frame should be grabbed in format hh:mm:ss"> <cfscript> var strTMPPath = '/tmp/'; var strUniqueFname = CreateUUID(); var strPathToFFMPEG = '/usr/bin/ffmpeg'; var strArguments = ''; var qTempFile = ''; </cfscript> <cfif not DirectoryExists(getDirectoryFromPath(arguments.strPathToJPG))> <cfthrow message="target directory does not exist"> </cfif> <cfif not FileExists(arguments.strPathToFLV)> <cfthrow message="source FLV does not exist"> </cfif> <cfif not RefindNoCase('\.flv$',arguments.strPathToFLV)> <cfthrow message="source file must be an .flv"> </cfif> <cfif not RefindNoCase('\.jpg$',arguments.strPathToJPG)> <cfthrow message="target file must be a .jpg"> </cfif> <cfif not RefindNoCase('^\d\d:\d\d:\d\d$',arguments.strFrameAtTime)> <cfthrow message="time must be set as hh:mm:ss"> </cfif> <cfset strArguments = "-i ""#arguments.strPathToFLV#"" -an -ss #arguments.strFrameAtTime# -an -r 1 -vframes 1 -y #strTMPPath##strUniqueFname#-%d.jpg"> <cfexecute name="#strPathToFFMPEG#" arguments="#strArguments#" timeout="30"></cfexecute> <cfdirectory name="qTempFile" action="list" directory="#strTMPPath#" filter="#strUniqueFname#-*.jpg" listinfo="name" recurse="no" type="file"> <cffile action="move" source="#strTMPPath##qTempFile.name#" destination="#arguments.strPathToJPG#"> </cffunction>
And here’s how to use it:
<cfscript> flvgrabber(strPathToFLV='/some/path/some.flv',strPathToJPG='/some/path/some.jpg',strFrameAtTime='00:00:03'); </cfscript>
Have fun!
Useful RegEx: Check if list contains only integers
Aug/090
Trivial, but useful… For 0 and positive integers only:
^[0-9]+(?:\,[0-9]+)*$
If you wish to include negative integers:
^(?:-?[0-9]+)(?:\,(?:-?[0-9]+))*$
So this might be a useful validity checker function:
<cffunction name="lstContainsIntegersOnly" output="no" returntype="boolean" access="private"> <cfargument name="lstI" required="yes" type="string"> <cfargument name="bNegativeAllowed" required="no" type="boolean" default="false"> <cfscript> var bIntegersOnly = FALSE; if (arguments.bNegativeAllowed) { if (ReFind('^(?:-?[0-9]+)(?:\,(?:-?[0-9]+))*$',arguments.lstI)) { bIntegersOnly = TRUE; } } else { if (ReFind('^[0-9]+(?:\,[0-9]+)*$',arguments.lstI)) { bIntegersOnly = TRUE; } } return bIntegersOnly; </cfscript> </cffunction>
UDF to strip certain chars, but leave UBB tags alone
Jul/091
We are developing a commenting system which is supposed to discourage comment spam by making comments more or less unreadable when they crossed a certain threshold of negative ratings. We decided that we’d like to strip all vowels from the text, though we’d like to keep the UBB-style tags inside the comment unchanged.
You’ll find that this last bit makes the whole task a little more complicated than just a simple Regex-Replace. We’ll need to use a negative lookbehind, then mark the characters we do not wish to strip, then remove any “unmarked” characters and finally remove our marker.
CF Instance Hangs, “too many open files” in Log
Jul/090
This is really quite trivial, but may be of some interest to people who don’t know too much about Linux OS tweaking. Today our dev-server instance was hanging – again. Only this time I took the liberty to make our developers wait a little longer before I restarted it, so I could actually diagnose the issue and resolve it for good. As only one of our two instances was hanging, I took a peek into its logfiles first – but couldn’t find anything out of the ordinary. And the Enterprise Manager reported the instance to be running, too.
ColdFusion 8 and Symlinks – Hell Awaits? (solved)
Jul/093
UPDATE: The issue seems to be fixed with ColdFusion Hotfix hf801-71648 (see technote kb403629). The fix is included in the Cumulative Hot Fix 2 for ColdFusion 8.0.1 (see technote kb403781). My bad – I thought I had deployed the hotfix when all I had in fact done was upload the zip-file instead of the jar. Epic fail. Anyway, the technote is a bit misleading as well – it’s talking about Application.cfm path resolution when the same issue applies to cfinclude, too.
I recently stumbled over an issue when using symbolic links on a couple of ColdFusion applications. I intended to use symlinks to keep duplicate code between different applications to a minimum. I’m running Apache 2.2 with ColdFusion 8.0.1 on 64-bit Debian Etch. Each of our web-applications needs a “connector” while retaining an include with some site-specific config.
BuddyPress – Activity comments plugin
Sep/0910
This plugin will enable posting comments on activity stream items, similar to Facebook. By default, comments are limited to 150 characters.
Only logged in users can leave comments on activities and delete that comments. Also, if user is “owner” of the activity stream he/she will be able to delete all unwanted comments on that activity no matter who posted a comment. Admins can delete any comments.