Quantcast
Channel: Adam Cameron's Dev Blog
Viewing all 1332 articles
Browse latest View live

Encourage Adobe to relocate /CFIDE/scripts

$
0
0
G'day:
I was listening to CFHour just now - another good podcast, fellas - and Scott mentioned that ColdFusion doesn't help its case keeping itself secure/locked down because assets for CFUI tags are homed in /CFIDE/scripts, and /CFIDE really mustn't be exposed to the outside world.

Whilst there are various options to move / rehome these, I've raised a ticket to get /CFIDE/scripts to somewhere else "Isolate the /CFIDE/scripts directory from the rest of /CFIDE" (3732913), which says this:


This has come up repeatedly over a number of years.

ColdFusion exposes /CFIDE by default, which is bad, and absolutely should not be the case.

However because Adobe have homed the resources for CFUI tags (<cfform> etc) in /CFIDE, a lot of people think they "need" to have that exposed to use these tags. Obviously the - poorly named - <cfajaximport> tag can be used to point these tags at a different location for their resources, but this is a poor approach to dealing with an issue that shouldn't really need to exist.

Just put the stuff for CFUI tags somewhere else! Move them outside /CFIDE. But them in /cfresources or something. Basically follow good web practices and only expose things to the outside world that are supposed to be exposed to the outside world.

I think Adobe needs to step up and be a bit more of a facilitator when it comes to streamlining people's efforts to secure their servers.

This should not be too hard to achieve, and not have many knock-on effects? I'm just wondering about any "backwards compat" issues Adobe might claim as grounds to not do this. I think in this case, product stability and reputation, and being seen to be doing something about ColdFusion's security perceptions should quite possibly trump "backwards compat" concerns?

I'm raising this as a bug not an E/R as it's just wrong to have this stuff coupled with the administrator / API / etc
Thoughts? Please go vote for it if you agree. Or comment here or there (or both) if you have any other things that might need to be considered.


--
Adam

Railo: help me replicate a bug I'm seeing on one of my machines

$
0
0
G'day:
A few days back I raised a bug with Railo - "Bug with scoping inside iterator functions" (RAILO-3000) - which only happens on one of my Railo installs (out of six installs, on four different machines). Micha can't replicate it either. I'm trying to get to the bottom of what's going on, and what's different about my install. Here's the code:



On my machine at work, this outputs:

1
1
1
1


1
2
3
4


On all my Railo instances at home, it outputs:

1
2
3
4


1
2
3
4


And this is what Micha gets too. All my instances are fully patched to 4.2.0.006.

I've just run this code on cflive.net, and - whaddya know... it displays the buggy behaviour too. So that's a relief: there is a bug, and it's not down to weirdness on my machine.

I tried to run it on trycf.com (that's a link straight to the Gist... that is cool) and the code gives a bogus error:

 Error:
key [ITERATIONS] doesn't exist on line 10

Which is obviously nonsense. I'll hit-up Abram about that one. If, however, I exit on the line about that, it runs the first loop correctly, outputting 1,2,3,4.

Anyway, can you please try running that code on your Railo install, and lemme know which version of the output you see (and if you see the bung version, what exact version / install type / platform your Railo install is)? Cheers.

Oh yeah, and my environment is various Windows versions:
  • 7 Starter 32-bit, Railo Express
  • 7 Home Premium 64-bit, Railo Express
  • 7 (not sure of flavour: probably Professional or Enterprise) 64-bit, Railo Express (this is the one showing the buggy behaviour)
  • 8 Standard 64-bit, both Railo on Tomcat and Railo Express
They are all - as far as I can recall - completely vanilla Railo installs.

--
Adam

Query.cfc / queryExecute() have a good feature cfquery lacks

$
0
0
G'day:
<cfquery> has been one of the mainstays of CFML for longer than I have been aware of CFML as a language. I presume it existed in some way, shape, or form in Cold Fusion 1.0. Up until ColdFusion 9, there was no way to perform a DB query in CFScript, unless one was to write a wrapper to do so. And I think we all had, at some stage or another.

Along came ColdFusion 9. It was during the development of ColdFusion 9 that Adobe first made the promise to implement all tag functionality in a scriptable way (note: it's taken them until CF11 to actually follow through on this promise), and when the first attempt at providing DB querying support in CFScript. I think it is astounding that it took until version 9 of the language before such a fundamental piece of functionality was available in CFScript, but there you go.

They did a very poor job of implementing <cfquery> in CFScript. Instead of doing what would have been sensible - adding a queryExecute() function - they just followed the CFML community's lead and added a CFML-written wrapper function to wrap around <cfquery>: Query.cfc (yes, it's a CFC... it's not a Java implementation like the rest of CFML is). In an enterprise product this is nothing short of embarrassing in how amateurish it is (both in general approach, and even more so in the code within the CFC... go have a look: it's not encrypted). I did point this out to Adobe at the time, but their response was just a blank, uncomprehending stare.

In tags, to run a query one just needs to do this:

<cfquery name="colours" datasource="scratch_mssql">
SELECT en AS english, mi AS maori
FROM colours
WHERE id BETWEEN <cfqueryparam value="#URL.low#">
AND <cfqueryparam value="#URL.high#">
</cfquery>

Via Query.cfc, Adobe's idea is one does this:

queryService = new Query();
queryService.setSql("
SELECT en AS english, mi AS maori
FROM colours
WHERE id BETWEEN :low AND :high
");
queryService.setDataSource("scratch_mssql");
queryService.addParam(name="low", value=URL.low);
queryService.addParam(name="high", value=URL.high);
queryResult = queryService.execute();
coloursViaQueryCfc = queryResult.getResult();

Unbelievable: we've gone from one statement to seven.

Thankfully if one reads between the lines, one can get it down to something more manageable via judicious argument passing, and method chaining:

coloursViaQueryCfcShorthand = new Query(
datasource = "scratch_mssql",
parameters = [
{name="low", value=URL.low},
{name="high", value=URL.high}
],
sql = "
SELECT en AS english, mi AS maori
FROM colours
WHERE id BETWEEN :low AND :high
"
).execute().getResult();

But - whilst it seems more like "proper code" to me - it still lacks the brevity of a <cfquery> call. It seems fundamentally irksome to me that something in script code is more verbose than its tag equivalent, but oh well.

Along comes ColdFusion 11 and we finally get the solution we should have had from the outset: queryExecute():

coloursViaQueryExecute = queryExecute("
SELECT en AS english, mi AS maori
FROM colours
WHERE id BETWEEN :low
AND :high
",
{low=URL.low, high=URL.high},
{datasource="scratch_mssql"}
);

One function call. three arguments. Not bad.

So we can just close the chapter of ColdFusion's history that is Query.cfc, and move on.

However in all of this, we've actually picked up a feature in the function-based solutions that <cfquery> itself doesn't have. One no longer needs to have a specific piece of functionality to pass a parameter (ie: there is no equivalent of <cfqueryparam> in these functions). One can simply put a placeholder in the SQL string. the placeholder can either be a named label as per these examples, or simply a ? for positional parameters (pass an array instead of a struct in this case).

I think this is a much nicer approach to passing parameters: it completely decouples the parameter value from the SQL string, which is how it should be. The whole idea of parameters is that they are passed separately to the SQL string. The SQL string is the instructions; the parameters are the values. The values should not be hard-coded in the instructions. That's just bad programming.

So what I would like to have back-ported into <cfquery> is this:

<cfset params = {
low = URL.low,
high = URL.high
}>
<cfquery name="colours" datasource="mssql_scratch" parameters="#params#">
SELECT en AS english, mi AS maori
FROM colours
WHERE id BETWEEN :low AND :high
</cfquery>

Or for positional parameters:

<cfset params = [URL.low, URL.high]>
<cfquery name="colours" datasource="mssql_scratch" parameters="#params#">
SELECT en AS english, mi AS maori
FROM colours
WHERE id BETWEEN ? AND ?
</cfquery>

The conceit here being that parameters are passed separately to the SQL, via a parameters attribute: same as with queryExecute().

I think this approach makes the <cfquery> statement much clearer, and closer to an SQL statement's intent.

Thoughts? I've raised an E/R for this anyhow. ColdFusion: 3732993. It seems there is already a partially implemented feature covering this in Railo: RAILO-2203.I must check it out (I'll report back...)

--
Adam

Railo: it already supports separating parameters from the SQL string

$
0
0
G'day:
This is a very quick  update to my previous article: "Query.cfc / queryExecute() have a good feature cfquery lacks". Railo already supports this (although it's apparently undocumented?).

Whilst raising the ticket for ColdFusion, I found an already-raised (and resolved) ticket in the Railo bugbase: RAILO-2203.

Micha has added a comment to the bottom of it: "added as hidden feature", but it is there and it does work:

<cfset params = [
{value=URL.low},
{value=URL.high}
]>
<cfquery name="numbersViaPositionalParams" params="#params#">
SELECT en AS english, mi AS maori
FROM colours
WHERE id BETWEEN ? AND ?
</cfquery>

<cfset params = {
low=URL.low,
high=URL.high
}>
<cfquery name="numbersViaNamedParams" params="#params#">
SELECT en AS english, mi AS maori
FROM colours
WHERE id BETWEEN :low AND :high
</cfquery>

Cool! Go Railo!

I shall update the ticket I raised with Adobe to encourage them to follow Railo's lead here.

--
Adam

Railo: I've got to the bottom of that code I asked you to test for me

$
0
0
G'day:
Thanks to everyone who helped out with my challenge in this article: "Railo: help me replicate a bug I'm seeing on one of my machines". I think the reason I was seeing the difference in behaviour is twofold:
  1. I'm a dropkick;
  2. Railo's setting "Local scope mode" (which I can't find docs to link to [grumble], so I'll need to explain it).
The reason why I suspect I'm a dropkick is that I think this is all down to my machine at work having "local scope mode" set to "modern", whereas every other instance I have been looking at is set to "classic". I do not recall switching my work machine to use this setting (and I'll be switching it off as soon as I sit down at it on Monday), but it seems like this is what the difference is.

Thanks to Gert for pointing me in the direction of the various Railo "make Railo work differently from ColdFusion" settings that Railo has.


Local Scope Mode

Railo has a setting which messes with how function-local variables work. In CFML by default, to declare a variable as local to a function, one needs to either var it, or explicitly declare it in the local scope (eg: local.one = "tahi"). If one doesn't do either of these, then an unscoped variable will go in the calling-code's variables scope. So either the main variables scope of the request if the function is declared in a CFM, or in the CFC's shared variables scope if it's a function in a CFC. This was a poor decision on the part of Macromedia when they first implemented functions, but now we're stuck with it. Well we are in ColdFusion, anyhow.

In Railo they've added a setting to enable unscoped variables within functions to default to being put in the function-local scope by default. I think I might write a separate article on this so there's some documentation for it somewhere (if someone can find the actual docs, let me know: it'll save me some time).

Anyway, I cannot check the machine I'm seeing the "odd" behaviour on as it's my work PC and I am at home at the moment. I'll check it tomorrow. But I can replicate the behaviour I'm seeing on this Railo instance if I switch that setting from "classic" to "modern".

However.

There is still a coupla bugs here. Or it might be one and a half bugs, I'm not sure.

First Bug

"Modern" mode breaks closure. Consider this code:

counter = 0;
incrementCounter = function(){
return ++counter;
};
writeOutput("incrementCounter() returned: #incrementCounter()# (current value of counter: #counter#)<br>");
writeOutput("incrementCounter() returned: #incrementCounter()# (current value of counter: #counter#)<br>");

Here I set a variable counter to zero, then I use a function expression to enclose that variable so that the function expression's code references the mainline variable. So in this context, the reference to counter within the function is - by definition - supposed to be the one in the calling code. it's not supposed to be a function-local one. I can work around this by using variables.counter in the function, but I shouldn't have to: Railo should see the calling-code variable and realise I'm referencing that.

I can understand if it was a completely new variable that it would park it in the function-local scope, but not with an existing variable.

I could conceivably see that if I had another one of these "make it work differently" options Railo has - "cascading" - set to "strict" that behaviour here might be different, but even then, it's still supposed to scan the variables scope for variable references (according to the on-screen comment in the administrator where the setting is managed).

Second Bug

Even if the behaviour in the first bug was "expected behaviour", then this is still broken. If the reference to counter inside the function is function-local, then ++counter should break. Because I haven't actually created counter yet, so I can't increment it. Consider this variation of the function by way of example:

incrementCounter = function(){
return ++localcounter;
};

This outputs:

Railo 4.2.0.006 Error (expression)
Messagevariable [localcounter] doesn't exist
StacktraceThe Error Occurred inx
/shared/git/blogExamples/railo/bugs/iterationmethods/scopingIssueSimplified.cfm: line 4 
2: counter = 0;
3: incrementCounter = function(){
4: return ++localcounter;
5: };

Which is true, and entirely fair enough.

So it seems to me that Railo is partially spotting the variables-scoped version of counter, but then doing some weirdness and also creating a function-local version of it.

Which is wrong.

I shall update RAILO-3000 to reflect this information.

And I am now not entirely sure that these "change how CFML works" settings are a very good idea. If Railo wanna do their own language... go for it... do whatever you like. However if they have decided to do CFML, then they should accept that it has quirks like this, and leave it be. By adding ths sort of optionality in, all they're achieving is creating uncertainty. We might not like the way CFML works in regards to function-local variable scoping and scope look-ups; but we all know how it works. Unless of course Railo offers a setting to make it work differently. [Eye roll].

At least the settings are off (ie: compatibile with ColdFusion) by default.

--
Adam

ColdFusion 11: calling a stored procedure from script. And can we please stop wearing out our "c" and "f" keys?

$
0
0
G'day:
I'm not sure what's got into me today... I'm supposed to be completing a Backbone.js course @ Code School, but I keep finding things to look at in Railo / ColdFusion instead. This is the fourth article I've written this afternoon. And it's only 3pm.

I'm looking at two things in this article. Calling a stored procedure from CFScript, and how I really don't think our code needs to scream "cf""cf""cf" at us the whole time. We get it. It's a CFM file. It's got CFML in it. We don't also need every single line of code in it reminding us of this. But this is what we will have if Adobe get their way.


Firstly... stored procs. Here's a tag-based proc call:

<cfstoredproc procedure="uspGetColours" datasource="scratch_mssql" result="tags.result" clientinfo="true" returncode="true">
<cfprocparam value="#URL.low#" cfsqltype="CF_SQL_INTEGER">
<cfprocparam value="#URL.high#" cfsqltype="CF_SQL_INTEGER">
<cfprocparam type="out" variable="tags.inclusiveCount" cfsqltype="CF_SQL_INTEGER">
<cfprocparam type="out" variable="tags.exclusiveCount" cfsqltype="CF_SQL_INTEGER">
<cfprocresult resultset="1" name="tags.inclusive">
<cfprocresult resultset="2" name="tags.exclusive">
</cfstoredproc>

And to contextualise this, this is the proc's code (this is like the second T-SQL proc I've ever written, and I needed to google the entire thing, so don't take this as a way to achieve anything sensible in T-SQL; it's simply good enough to fulfil my requirements on the CFML side of things):

ALTER PROCEDURE [dbo].[uspGetColours] 
@low int,
@high int,
@countInclusive int OUTPUT,
@countExclusive int OUTPUT
AS
BEGIN
SET NOCOUNT ON;

SELECT id, en AS english, mi AS maori
FROM colours
WHERE id BETWEEN @low AND @high

SELECT @countInclusive = @@ROWCOUNT

SELECT id, en AS english, mi AS maori
FROM colours
WHERE id NOT BETWEEN @low AND @high

SELECT @countExclusive = @@ROWCOUNT
END

And the underlying data:

query
ENIDMI
1red1whero
2orange2karaka
3yellow3kowhai
4green4karariki
5blue5kikorangi
6purple6tawatawa
7pink7mawhero

So the proc takes a low/high ID value and returns the following:
  • the records within that range;
  • how many of those there are;
  • the records outwith that range;
  • how many of those records there are.
It's very contrived, but it returns multiple recordsets and has multiple input and output parameters. It's about as complex as a proc call can get in CFML (barring adding more of the same).

Adobe have claimed they've finally got 100% of CFML's functionality directly usable from CFScript. They already have a StoredProc.cfc lying around which was added in CF9, but that was a shit way about going about adding functionality to script (if you read this blog with any regularity... of even just today... you'll know my opinion of these CFCs).

For completeness, here's an example of it in action (this is the same proc call as above):

result =  new StoredProc(
procedure = "uspGetColours",
datasource = "scratch_mssql",
result = "anyOldShitYouLike", // seriously. It doesn't matter what value this has
fetchclientinfo = true,
returncode = true,
parameters = [
{value=URL.low, cfsqltype="CF_SQL_INTEGER"},
{value=URL.high, cfsqltype="CF_SQL_INTEGER"},
{type="out", variable="inclusiveCount", cfsqltype="CF_SQL_INTEGER"},
{type="out", variable="exclusiveCount", cfsqltype="CF_SQL_INTEGER"}
],
procResults = [
{resultset=1, name="inclusive"},
{resultset=2, name="exclusive"}
]
).execute();


writeDump(var=[
result.getPrefix(),
result.getProcResultSets(),
result.getProcOutVariables()
]);

This results in:

array
1
struct
CACHEDfalse
CLIENTINFO
struct
AccountingInfo[empty string]
ApplicationName[empty string]
ClientHostName[empty string]
ClientUser[empty string]
ProgramID[empty string]
EXECUTIONTIME2
STATUSCODE0
2
struct
exclusive
query
ENGLISHIDMAORI
1red1whero
2orange2karaka
3purple6tawatawa
4pink7mawhero
inclusive
query
ENGLISHIDMAORI
1yellow3kowhai
2green4karariki
3blue5kikorangi
3
struct
exclusiveCount4
inclusiveCount3


That's all right I guess. It is a bit odd that I have to pass the proc results in to the call, but hey.

So as to make less work for themselves at the expense of CFML and the CFML developers, instead of taking a case-by-case approach to implementing previously tag-only functionality in a scriptable fashion, Adobe have just taken a generic approach to solving the problem. And it's awful.

Here's the new generic CFScript approach to a stored proc call:

cfstoredproc(procedure="uspGetColours", datasource="scratch_mssql",result="script.result", fetchclientinfo=true, returncode=true) {
cfprocparam(value=URL.low, cfsqltype="CF_SQL_INTEGER");
cfprocparam(value=URL.high, cfsqltype="CF_SQL_INTEGER");
cfprocparam(type="out", variable="script.inclusiveCount", cfsqltype="CF_SQL_INTEGER");
cfprocparam(type="out", variable="script.exclusiveCount", cfsqltype="CF_SQL_INTEGER");

cfprocresult(resultset=1, name="script.inclusive");
cfprocresult(resultset=2, name="script.exclusive");
}

That is just repugnant. What awful bloody code. All Adobe have done is to go "right... the CFScript version of a tag is just the tag without the angle brackets. And if it's a nestable tag set (like with proc params and proc results), we'll put some curly braces around it. Oh, and make it kinda like a function, with parentheses and commas instead of space-delimited attributes".

What's worse (yes, it gets worse), is that this is contrary to the way Railo already set out to do the same thing. Their approach also lopped off the "cf" bit too. And doesn't have the parentheses or commas (I think).

But here's the thing. Simply chopping the angle brackets (and/or the "cf" tag prefix) does not result in a well-thought-out implementation of script functionality. The two approaches to coding syntax are quite different. So simply doing what amounts to be a global search and replace isn't an adequate solution.

It's just a lazy cop out.

And, FFS Adobe: do we need to start everything with "CF"? It makes sense in tags, but it makes no sense whatsoever in the context of script code.

What Adobe should have done is to sit down with a given tag and go "right... what functionality does this tag fulfil? Right, now that we know that, let's forget about tag syntax, and come up with a way to implement that functionality in script". It's not an exercise in syntax translation, it's an exercise in functionality provision.

So what does a stored proc call do? It takes some inputs:
  • the procedure name
  • some parameters
  • some options (datasource, etc)
And what does it do?
  • returns recordset(s)
  • returns metadata
  • returns values in some of the parameters
Takes inputs and returns results? Sounds like a function to me.

options = {
datasource = "scratch_mssql",
fetchclientinfo = true,
returncode = true
};
params = [
{value=URL.low, type="INTEGER"},
{value=URL.high, type="INTEGER"},
{type="out", variable="inclusiveCount", type="INTEGER"},
{type="out", variable="exclusiveCount", type="INTEGER"}
];

result = executeProcedure("uspGetColours", params, options);

Where result would yield this:

struct
METADATA
struct
CACHEDfalse
CLIENTINFO
struct
AccountingInfo[empty string]
ApplicationName[empty string]
ClientHostName[empty string]
ClientUser[empty string]
ProgramID[empty string]
EXECUTIONTIME3
STATUSCODE0
OUTPARAMETERS
struct
exclusiveCount4
inclusiveCount3
RECORDSETS
array
1
query
ENGLISHIDMAORI
1yellow3kowhai
2green4karariki
3blue5kikorangi
2
query
ENGLISHIDMAORI
1red1whero
2orange2karaka
3purple6tawatawa
4pink7mawhero

That is a hell of a lot clearer than what Adobe have offered, and gets rid of an awful lot of boilerplate code that makes sense in tags, but is unnecessary in script code. It just gets to the point and does the work.

Adobe ought to shit-can all this generic CFScript stuff they've done, and revisit each piece of functionality that is currently implemented as tag-only, and then implement the functionality in a way sensible to be implemented in script. Which will generally be a function. They mustn't tackle this as a syntax issue, they need to tackle it as a functionality issue.

And, seriously, the current approach in CF11 beta needs to be binned and started again. Bad luck. You should have focused on doing the job properly, not quickly.

Bug raised: 3733001.

Believe it or not... the idea for my fifth article of the day just popped into my head...

--
Adam

How about this for savecontent?

$
0
0
G'day:
The approach that CFML has taken for the CFScript implementation of <cfsavecontent> has always annoyed me, because it doesn't follow the normal syntax for doing processing and returning a result. Plus there was the need to add a new syntax construct as well. It's just occurred to me that this was not necessary. A simple function would have done the trick.

To contextualise things, let's have a look at the <cfsavecontent> tag:

<cfset days = ["Rāhina","Rātū","Rāapa","Rāpare","Rāmere","Rāhoroi","Rātapu"]>
<cfsavecontent variable="contentViaTags">
<ul>
<cfloop index="day" array="#days#">
<cfoutput><li>#day#</li></cfoutput>
</cfloop>
</ul>
</cfsavecontent>
<cfoutput>#contentViaTags#</cfoutput>

I'm just capturing the output from some simple CFML processing there, and then outputting it. It's a dumb usage of <cfsavecontent>, but it demonstrates it OK. The syntax here is entirely reasonable, and completely clear as to what's going on. It's a handy tag.

ColdFusion and Railo had already both had a go at implementing this for CFScript. And both failed (well: they came up with the same solution):

savecontent variable="contentViaScript"{
writeOutput(days.reduce(function(previousResult, thisValue){
return previousResult & "<li>#thisValue#</li>";
},"<ul>") & "</ul>");
}
writeOutput(contentViaScript);

The problem here is twofold.
  1. CFML syntax for setting a variable to be the result of some processing is:
    variable = process
    Not:
    process variable="nameOfVariable"
    So it's at odds with out CFML works to approach functionality that way.
  2. We need to add this new {} syntax to enclose the code we're saving the output of. This is a new syntax construct implemented solely to emulate opening/closing tags. This is script code, so we should not be thinking in terms of opening and closing tags.
So that syntax is a loser IMO.

ColdFusion 11 has just managed to make this worse. Now we're going back to basically using tags:

cfsavecontent(variable="contentViaScriptNew") {
writeOutput("<ul>");
days.each(function(v){
writeOutput("<li>#v#</li>");
});
writeOutput("</ul>");
}
writeOutput(contentViaScriptNew);

It also means we have two separate - and mostly the same but slightly different - constructs for doing a savecontent operation in CFScript. This is a double fail. How long will it be before we start forgetting which syntax takes the parentheses and the commas, and which just takes spaces?

But this is what's just occurred to me today. We never needed any special syntax at all to achieve savecontent in CFScript:

contentViaFunction = savecontent(function(){
var decoratedDays = days.map(function(v){
return "<li>#v#</li>";
});
writeOutput("<ul>#decoratedDays.toList('')#</ul>");
});
writeOutput(contentViaFunction);

It's just a function call. A plain old function call. We call the savecontent() function, it takes a callback which contains the code which we want to capture the output of, and returns that in its return value.

Isn't that a better approach than messing about with new syntax and weirdo ways of assigning values?

What's more... the implementation is piss-easy. It's just this:

function saveContent(required function content){
savecontent variable="local.saved" {
content();
}
return local.saved;
}

Obviously because I'm implementing this with CFML I need to reuse one of the other constructs, but it demonstrates what a simple concept to implement it is.

This is another example of what I mean that rather than taking a generic approach to implementing previously tag-only functionality in CFScript, it needs a bespoke approach. CFScript is now a first class citizen of CFML, and it deserves to have its functionality implemented carefully and thoughtfully. Not just in an automated/generic way that makes the life of the engineers and Adobe and Railo a bit easier.

--
Adam

Open Letter to site admins I might be contacting in the near future about the security of your ColdFusion site

$
0
0
Hi:
If you are reading this article, it's probably down to one of two reasons:
  1. you're one of my regular blog readers, in which case this will have just found its way in front of you just like anything else I write;
  2. you are a person I have successfully contacted who - hopefully - the administrator of a ColdFusion-driven website that I have noticed as having some security issues.
The article is targeted at the second group of people. If I have contacted you directly, it is vitally important you read this, and follow-up on it.

For obvious reason I will not go into how I came to be contacting you. But via commonplace, publicly-accessible resources on the internet, I was able to determine that you have at least one non-trivial security problem on your website. Here is some information for you to follow-up on.

ColdFusion Patching

Please make sure your ColdFusion application server is fully patched and up to date. There is a good chance it is not. At time of writing versions 9 and 10 of ColdFusion are still being actively patched. Patching details can be found on the Adobe website:

If you are running a version of ColdFusion older than ColdFusion 9, you really ought to upgrade it. If you are on ColdFusion 9, you really ought to be in the process of upgrading it, as it reaches the end of its support life at the end of 2014. No more security patches will be released for it after that time.

There is a great service called HackMyCF which can help you to more formally and rigorously identify issues with your website. the service is provided by Foundeo, who are stalwarts in our community, and can be trusted. I have no tie to them, I just know them from the community.

ColdFusion Security

A ColdFusion install is not - by default - terribly secure. There are a number of additional steps that are absolutely vital for you to undertake on any public-facing ColdFusion server. These are detailed in the ColdFusion Lockdown Guide:

I cannot find a ColdFusion 8 (or older) lockdown guide, but most of the points raised in the docs above will apply to older versions of ColdFusion too.

General site / code security

  • You must block external access to http://yourdomain.com/CFIDE/administrator. It is absolutely critical that that URL cannot be accessed from the outside world. It is a vector for known, real-world, site hacking.
  • Always use an error template and a global error handler. Website errors happen, but you do not want to be exposing the error message to the outside world. Error messages often show areas in which a website can be exploited.
  • Make sure that if you browse to http://yourdomain.com/Application.cfm that your error template displays, rather than a generic ColdFusion error message. Unless configured properly, that URL generally bypasses a site's error template.
  • This is a bit technical, but all dynamic values being passed to a database must be done via parameters, not via hard-coded values. This is a non-trivial security vector (and one that is obvious if your error pages aren't configured properly!)
  • [there's plenty of other stuff to consider too]

Community

Please join the online ColdFusion / CFML community. By this I mean read some blogs, sign up to some forums, follow people on Twitter. We discuss security stuff all the time, and it's the best and fastest way to find out if any new security issues crop up. The internet is not an environment in which one can set up a website and then just leave it and it'll be OK. One needs to stay on top of what's going on in the industry, and be aware of security concerns.

We can also help you with problems you have (either just for free, or we can provide consultancy for bigger jobs).

Why am I telling you this?

I can go into more details via email (or however I made contact with you), but I've spotted a problem on your website.

I've been in the ColdFusion community for years, and have got to the point where I figure I should be giving something back to the community. I maintain this blog for one, and more recently have become concerned about lax security (and the exploitation thereof) in our community. So have decided to try to help tighten up security around the place. Adobe has got a lot of bad press recently (some fair, some not so fair) about ColdFusion exploits, and ColdFusion's reputation in the marketplace affects us all. I don't do consultancy so I'm not looking to gain anything from this other than trying to help out. And I am legit... read the blog or ask people.

Cheers for reading this. I hope you follow up.

--
Adam

Survey follow-up (no results yet sorry): need some more input

For the non-Firefox users amongst my readers

$
0
0
G'day:
Inspired by OKCupid's move today, I am displaying a popover on this blog when a Firefox user first visits:



The text states this:

Hi:
Sorry about the "WTF?" moment going on here. I am posting this notice in front of anyone accessing my blog from Firefox.

As I say in my communications policy for this blog, everything here is my opinion. Generally I stick to my opinions about stuff relating to CFML, but I reserve the right to express my opinion on any topic.

Something I have a strong opinion on is the topic of prejudice and bigotry. I won't conscion it. I do not simply mean racial bigotry, I mean bigotry of any stripe, including homophobia.

I was very disappointed to see that Mozilla have appointed a "card-carrying" bigot to the position of CEO. As we have all heard by now, Brendan Eich is so prejudiced against homosexual people he has financially invested in attempts to underwrite homophobia into United States law.

In my opinion, this is completely unacceptable. I can't have a say in whether he should be stood down from this position, but the longer he retains it, the dimmer is my view of Mozilla as a company.

As my own small protest I have deinistalled Firefox from my computer, and I am also now inviting you to do the same.

I'll only be displaying this banner to you once... I've popped a cookie on your browser so it should not display again. Sorry for the interruption.

Cheers.
Unlike OKCupid, I will display it only once.

But, hey... if you're like-minded, please consider voting with your feet.

If you're not like-minded, please do (oh please do) post comments on my blog like this:

Mark:
Really? You're giving a "Yeah, Fuck that guy" a well said? I think Adam may have had a few cocktails before posting this non-CFML related message, or maybe it was click bait Huffington Post style (worked on me). So what's the issue here guys/gals? The man can't have traditional values and or beliefs without getting told to go fuck himself? Real mature.
I doubt he's anti-gay but who knows maybe he dreamt of strangling queers while creating that god awful javascript mess, that's what everyone should be boycotting, not Firefox but js. Just a quick question, would there be this much rage, ranting, pissing and moaning if Mozilla named a... umm... I don't know.... a Muslim as CEO? Didn't think so.

Whose "traditional values" are prejudice and intolerance? I like the fact you assumed someone would need to be drunk to not be a bigoted prick. And I loved the fact that you manage to squeeze some latent racism into that penultimate sentence mate.

Can't wait to see what Matthew, [...], Luke and John have to say.

--
Adam

Survey results: lists in CFML, and the naming of list member functions

$
0
0
G'day:
I didn't quite get 50 results for this survey, but so be it. It wasn't a terribly interesting one, granted. So, what do people think about lists, list functions, and what the approach to the naming of list member functions should be?

The subject line of the survey was:
ColdFusion 11 and Railo 4 have added "member functions" to CFML, so one can call a method on an object, rather than pass an object to a function. ColdFusion has implemented list functions as member functions of a string, and in the process have blurred the distinction between what's a list function and what's a string function. There is conversation about this on the Railo Google Group, and this has lead me to wonder what the community participants think about Adobe's approach here.
There were five questions.

1. Do you chiefly use/concern yourself with ColdFusion or Railo?

This was just to gauge where people were coming from.

I think 30% is pretty good for Railo. However the readership here would be a niche segment of the CFML community (not because this blog is high brow - far bloody from it!), but because most CFML developers don't really participate in our community.

I checked to see if people saying "ColdFusion" as opposed to "Railo" significantly trended their answers a certain way, but nothing really stood out.

2. Which best reflects your opinion on the concept of "lists" as a CFML "data type"?

It's interesting that people erred more towards lists being a good thing. Although the sample size is so small that's a bit meaningless.

There were quite a number of additional comments with this question:

Never gave it much thought until you brought it up. They are there, I use them occasionally for short sets of data

I know lists exist, but i typically use array

They have long been a part of CFML, and are present in a number of places (e.g., HTML form attributes for checkboxes come through as lists, query.columnList) within the language. We use them. They are a simple and useful data structure. Can they be abused or used in situations that other data structures would make more sense? Sure.

These are just 'strings', but then again, so is a JSON structure. To me, there is very little difference between: "one,two,three" and '["one","two","three"]'. I've always thought that when I wanted to perform any list function, CF converted my string to an array, performed it's action, and then popped it back to a string.
I suspect it doesn't do that.

A list in many languages is a proper data type on its own with specific benefits. CFML lists, being just strings, I cannot condone.

They aren't a data type, but I think it is ok to have them as a concept. Many of the list functions are useful when manipulating strings.

I think lists are great, but because they are also strings, it makes it difficult to explain the differences between lists and strings. In CFML, a list is a string (given a delimiter), and any string can be a list, and each can be treated as the other. This has the benefit of allowing quick loops over strings, outputting lists (in most languages, a more difficult task), and easily specifying custom delimiters to break up a string, but if CFML had a true list construct (akin to an ArrayList, on the level of Structs and Arrays, but would toString() just by outputting), I think things could be improved dramatically. Right now, it's a sloppy mess.

Works well for simple handling of data. Lists are far quicker to define than structures and there is a place for lists in my heart. Lots of times I've been supplied with lists and it's nice to work with them in this form just by pasting them into my code. Lists are a great feature of CFML and like most things you should choose the right tool for each job. Sometimes you just have to use arrays or structs if things get slightly complicated. Viva lists!

I can see the benefit of a "list" data type, remembering back when I was a junior level, I had used them quite a bit. Having "lists" helps with adoption for new developers just starting out that may struggle with arrays and is somewhat unique to the language. However since CF is very loose with data types, overall I'm not sure they make sense. Issue now is they are part of the language and not going anywhere.
You see I think that newbies' reliance on lists is the cause of often CFML developers never becoming comfortable with arrays / structs. It's another example of where dumbing-down the language is - long-term - counterproductive.


I use list functions as a quick way to split up strings. I also use it to sent list of things to arrays as in listToArray.

I'm neutral. I think of them in the manner ColdFusion does because, well, ColdFusion looks at them as such. However, if lists were to be no more and I had to look at it as a string, it's no bother. 9 times out of 10 I end of converting them to arrays for manipulation etc. anyway.

It's an artifact of the "Let's make CFML simple so non-programmers can use it." days - and it was made worse by the ridiculous handling of empty elements in the "list"!
The "empty elements don't count" thing made lists unusable for many situations, in my experience. It was a frickin' stupid idea from the outset. They should always have respected empty elements, and simply provided a listCompact() (or something) function to get rid of empty elements if that's what someone wanted to do.

Personally, I love list data types and that their are specific functions for working with them. Sure, it's really just a wrapper for working with strings and/or simple arrays, but we use List functions a lot and like them.

I find lists to be very useful. I know it can be easily done as an array, but I do find the list functions useful.

I use them all the time to extract directories from paths, names/extensions from files, etc... Very handy in my book. Now, that could be done via listToArray, but not having to do that is a convenience that I don't think hurts anything/anyone.

I don't really consider lists to be a cfml datatype. in the past, we've just had list aware functions that have worked on strings. I've found it to be a convenience factor to use string as list, though I mostly turn them into arrays because I've found arrays to be more reliable. the ability to treat a string as a list has some useful side benefits in that string parsing/manipulation is easier



3. Some ColdFusion "list" member functions[...]

[...] where there is no string-centric function of the same name - drop the "list" prefix from the function name. EG: the listAppend(list) member function is simply string.append(). Whereas where there is already a string-3. centric function, the list prefix is maintained, eg: listFind(list) => string.listFind(). What is your opinion of this?

A couple of the options are truncated on the chart here. They read:

1) this is a poor approach: list functions should always have the "list" prefix in their name
5) this approach is fine: there is insufficient ambiguity here for it to be a problem

My own answer was (1), so I'm pleased three quarters of people tend to agree. This might suggest Adobe need to rethink their approach in ColdFusion 11.

And some comments:

They should all be prefixed with list, not only for the reasons given, consistency, new name is often misleading etc, but also because the new 'list' less names are taking names that could be useful string functions that do what the name suggests.

I really like the idea of having member functions available to simplify the language syntax. Where lists in CFML really are just strings, I think the only thing that makes sense is to use the list...() prefix.

With all of the other random inconsistencies within CF, I'm not too surprised. But I'd rather that everything be named the same way and start with list

I would expect "a".append("b") to return "ab", not "a,b", having it as listAppend() avoids this confusion.

Language consistency is powerful. Take a look at PHP to see how inconsistencies have turned out.

Function names should be as consistent as possible. Coldfusion right now is a huge hodgepodge of naming conventions.

I think there needs to be something to indicate that these functions will be acting on the string as if it was a list. Also if they wanted to add an append method that just appended to a string that name would already be taken. You probably wouldn't do that but there could be other cases where that would come up.

string.append() means you are adding one string to another. string.listAppend() means you are adding an item to a list, where the string is a list.

Clarity and consistency are paramount. I hate inconsistencies, it makes things more difficult to remember and bashing out code is more prone to error. It's illogical. Coding is all about logic and if the language is lacking in naming logic then that's a pretty crappy start, especially for people looking at CFML for the first time.

Since the base class of both string and list is really "string", I almost think prefixing with "list" is a requirement to prevent any confusion for future functionality. What I personally would like to see is having to explicitly define a variable as a "list"; otherwise a similar member function would act like a string. Not sure how feasible this is, as I'm sure the underlying class of a list is really a string, but I'm sure it's not beyond possibilities. Things would look like this. param name="mYList" default="x,y,z" type="list"; myList.append(); myList.find(); myList.last(); ... and beyond cfscript, maybe having a cflist tag. .... To me this is essentially the same as cfimage, cfquery and other tags that return explicit types.

It's indicative of Adobe's slap-dash approach to language "design" (i.e., they don't think stuff through properly).

I do agree that they should be clearly delineated versus this blending described - one of my biggest frustration with some other languages, like PHP, is this sort of confusing mix. One thing I've always liked about CF is consistency in function names, and this messes that up.

It's a poor approach to be inconsistent. I personally like not having the "list" prefix as its obvious by the intent. If I was to do "string".first(), I would know I'm working with the string as a list (or an array). "string".find()* should probably be renamed to "string".indexOf().


The - almost ubiquitous - gist of the comments is that the list-specific methods should be prefixed with list. I agree.

To the people answering "it's fine" (from the multi-choice options; no-one who commented suggested it was fine), can you please tell me what you'd expect from this code:

options = "1) first; 2) second";
options.replace("1,2", "i,ii");


4. Railo are giving thought to adding list-oriented member functions. What are your thoughts on this?


Again, SurveyMonkey has truncated the options here:
1) don't bother. Don't encourage list usage;
5) it's essential to add list-oriented member functions.

I suppose general ambivalence here is fair enough. I suppose one can just opt to not use list member functions if they are there, and just ignoring something causes no harm. That said, I see an awful lot of code torturously relying on lists where arrays would be a better fit, and if I was around when CFML was being planned, I'd veto the idea of lists as "a thing".

5. Anything else to add?

If Railo are to maintain some level of syntax parity with Adobe, I think they must add these (regardless of how stupid the ACF implementation is). List functions are not the type of functionality that I would expect to be the force driving a wedge between the two platforms - compatibility wise.
This is a good point. "Implemented them but don't encourage them", perhaps?

Personally, I do think Railo should support all functions/tags from CFML, regardless of whether they "like" them or not. Yes, I get that some people are of the opinion that some tags/functions are stupid, useless, etc and that there is no official "standard" for CFML, but IMHO Railo cannot be seen as a valid alternative to Adobe's CF if it will not actually support the full breath of current CFML tags/functions.
On the other hand, what if they are positioning themselves as the leader of the direct that CFML takes, these days? Which I think is accurate.

I've seen a lot of code in the wild that does horrible crap like this: cfloop index="i" from="1" to="#listlen(s)#" cfset x = listGetAt(s,i) ... do stuff with x ... /cfloop Inefficient and ugly! No wonder CFML devs have such a bad reputation and everyone thinks CFML is really slow!
Yeah, list usage should definitely - in general - be actively discourage, I think.

So many other ways to do "lists" without JSONizing the language.
"JSONizing"?

Personally, I would like to see the name qualifiers removed from all member functions. Simplify the syntax. In general: move the language toward something like Ruby's "everything's an object" while we're at it. When coding in pure Ruby I find that I love so much of the "object-ness" but dislike the look of some of the syntax. When coding in CFML, I feel the opposite... in general I would like a mixture of the two.
My thoughts are much the same.

I think if Railo wants to tout itself as a CF replacement, it should follow the Adobe road map and feature set as closely as possible. Especially when it comes to basic core functionality, which I think member functions fall into. That being said, I don't have a problem with Railo taking the lead and implementing them right. Meaning either require explicit definition of a variable as a "list" and implementing names without a "list" prefix, or option 2, implementing member functions all prefixed with "list". Maybe an even better option for Railo would be to require the explicit variable definition, and then implement member functions with and without a prefix. This would make migration from CF to Railo a matter of the parameter initialization with either of these: or param name="myList" default="x,y,z" type='list';
Hmmm... one cannot win a race by playing follow the leader though. That'll always just land you in second.

So long as it doesn't break any compatibility if code is moved off a CF server and put onto a Railo server. I guess the other way around isn't a huge concern. :-)

Thanks, Adam -@nathanstrutz
No worries mate.

Lists can easily be replaced with Arrays. That being said, I often find myself using lists when working with strings simply because they're available in the language.
So do I, sometimes. If I am given a string - like a file path - I'm completely fine with using listLast() to get the filename.

I see no real benefit to them. I've heard examples of their usage for handy things such as splitting extensions from file names and such. But here we can take cues from languages like Python: fileName, fileExtension = os.path.splitext("/path/to/file.jpg")
Aha! "Great minds [etc]".

We've moved off of lists in the vast majority of cases for arrays, so in the rare cases that we do need listAppend, we can use the BIF if there is no equivalent member function.
This is a good point. It's not like the procedural-oriented functions are going away.

If every other 'tag based' function is going to have a member function, then skipping a set for some reason just seems wrong.
The premise is that "lists" don't really exist. They're just strings.

For the sake of the language consistency, lists should have member functions... but as you note, they need to be clearly named to avoid collisions with string member functions.
I think this is actually the most pragmatic approach, yes.

As usual, Railo is damned if they do and damned if they don't. They have to copy the ill thought out crap that comes out of Adobe to stay compatible. We all know it's wrong (well.. except Adobe) but what else can they do, perhaps they could implement them and immediately deprecate them and recommend they are not used.
Hopefully Adobe can be encouraged to rethink how they've tackled these. On the basis of the comments here, I will be raising a ticket to get this addressed in ColdFusion 11: 3735413.

I think the general gist is that Railo should implement the list member functions, but they should be prefixed with "list", yes?

I'd go with that.

Cheers for the input, everyone!.

--
Adam

Cracking good news regarding list member functions from Adobe

Just

$
0
0
G'day:
This is ubiquitous news just now, but I would just like to share how I found out about it:


Cheers for the heads-up Gavin.

Well done IT. This is a good day for social equality.

--
Adam










CF(Hour) is dead :-(

$
0
0
G'day:
Well that's a shame.

I've really enjoyed listening to the CFHour podcast since I first discovered a it a year or so ago. If you haven't listened to them, "do a Gavin" and work your way through their back catalogue.

Quite often I don't agree with what the guys say, but generally in a good way: it's always good to hear other people's opinions on things, and give it a mulling-over. And they both have a natural and engaging way of delivering the material.

I think the ColdFusion community has lost a great resource today.

Cheers lads.

--
Adam

Closed:Deferred:EnhancementRequired:CantBeArsed

$
0
0
G'day:
Very disappointing action from Adobe today, regarding securing /CFIDE. Adobe have followed-up the ticket I discuss in "Encourage Adobe to relocate /CFIDE/scripts", 3732913:






And they've done this without any hint of an explanation - you know, having the professionalism (even the civility) to pop an explanatory comment in on the ticket.

So it all sounds like they just couldn't be arsed. I mean... "enhancement required"? Basically they're actually saying "we won't do this because it would require us doing some work". Heaven forbid.

Slack.

--
Adam

I am one step closer to being unshackled from ColdFusion

$
0
0
G'day:
Note that that is ColdFusion, not CFML. I'm still onboard with CFML, and that's not likely to change in the mid-term. Today I switched all my hosted code from ColdFusion to Railo. So now my only connection to the Adobe product is my day job.

I have a few bits and pieces of code hosted with CFMLDeveloper, which is a bloody good CFML hosting service, and is for free for non-production code.

Russ really knows his stuff when it comes to CFML hosting. A good case in point is that to switch my hosted environment from ColdFusion to Railo, all I had to do is to update my web.config file (it's simply a copy and paste from a FAQ page), and my CFML environment was instantly running Railo instead of ColdFusion. That's pretty impressive.

There were a few code incompatibilities I needed to fix:

  1. I had a method which took an argument url, which conflicted with the URL scope.
  2. Railo's CFScriptable <cffeed> equivalent has different syntax to ColdFusion's.
  3. In some places I was using the full path to the ColdFusion CFCs, eg: com.adobe.coldfusion.Http, which obviously isn't valid on Railo.
  4. I was having problems with <cfcache> in Railo, so I cached some stuff by hand. I have not yet got to the bottom of this (quick update: this seems to be a bug: RAILO-3016).
It took me about one hour to find and iron out those.

Now I can leverage all the excellent improved language constructs in Railo that ColdFusion doesn't have yet. Plus my code runs faster. Plus because of the way Railo works, having a separate Server Admin and Web Admin, I even have access to the admin UI for configuring my Railo "instance".

Railo is - all round - just a better experience for me.

--
Adam

Predictable but perhaps unexpected behaviour with unscoped variables and shorthand operators

$
0
0
G'day:
I've nothing earth-shattering to declare here (so "same ol', same ol'" then perhaps ;-), but here's a follow-up to a puzzling thing I observed during this adventure: "Railo: help me replicate a bug I'm seeing on one of my machines". It turns out there's... um... well I'm not sure what to make of it yet. It could be a bug; it could be expected behaviour.

Consider this code:

URL.firstVariable = 17;
someOtherVariable = firstVariable;

URL.secondVariable = 19;
secondVariable = 23;

URL.thirdVariable = 29;
thirdVariable++;
writeDump(var={URL=URL,variables=variables});

Here we have three demonstrations.

Firstly if an unscoped variable reference is on the right-hand-side of an assignment expression, then CFML server will look through a number of different scopes to find a variable of this name (see "About scopes: Evaluating unscoped variables" in the docs). So in this case firstVariable will be resolved as being a reference to URL.firstVariable.

Secondly, if an unscoped variable reference is on the left-hand-side of an assignment expression (ie: it's the variable being set to a value), then it's assumed to be a reference to a variable in the variables scope, even if other scopes in the look-up process as per above have a variable of that name. IE: the CFML server does not try to do a look-up in this case.

Thirdly: with a short-hand operator such as ++ or -= etc is used... what happens? Well the results here demonstrate some "unexpected" (kinda) behaviour:

struct
URL
struct
FIRSTVARIABLE17
SECONDVARIABLE19
THIRDVARIABLE29
VARIABLES
struct
SECONDVARIABLE23
SOMEOTHERVARIABLE17
THIRDVARIABLE30

Or, to focus more:

struct
URL.thirdVariable29
variables.thirdVariable30

So here we don't increment URL.thirdVariable, but we create a new variable variables.thirdVariable. Huh? Superficially this seems wrong. But if one things about what happens under the hood, it makes sense (note: I am not sure it's "correct" behaviour, but it makes sense). Because under the hood this expands out to:

thirdVariable = thirdVariable + 1

And if we introduce that statement into our test:

URL.fourthVariable = 31;
fourthVariable = fourthVariable + 1;
writeDump(var={
"URL.fourthVariable" = URL.fourthVariable,
"variables.fourthVariable" = variables.fourthVariable
});

Output:
struct
URL.fourthVariable31
variables.fourthVariable32

It all becomes a lot clearer as to what is going on. Remember the first two examples above? If the variable reference is on the right-hand-side of the assignment: a scope look-up is done (so fourthVariable resolves to URL.fourthVariable); however on the left-hand-side of the assignment, an unscoped reference simply means "the variables scope".

So if one is to base one's expectations on the under-the-hood logic, then what we see is what we should expected.

However I'm not sure the behaviour we see in CFML (and I checked OpenBD too, just for a laugh, and it behaves the same way as the other two) is what we really expect here?

It's one of these situations in which I find myself thinking I really wish CFML stopped trying to be 'helpful' and do all this scope-look-up nonsense. It was a bloody stupid and unnecessary thing to add to the language from the outset. Fortunately at least in Railo there's a way to switch it off.

Anyway... I'm divided as to whether this should be considered a bug or simply "expected behaviour". Before I thought sufficiently about it, I raised it as a bug (3737577), although I'm now not sure it is. I think the position should be not to worry about how the logic expands out under the hood, but it should concern itself with what "expected behaviour" is, in the given situation. And I'm not so sure what my expectations here are any more.

This impacts all of the prefix (++myVar), postfix (myVar--) and compound assignment (eg: +=) operators.

What do you think?

--
Adam

Balls I say!

$
0
0
G'day:
Sorry Rakshith, I know you deleted this message, but it's too amusing for me to not keep for posterity.




 
 
 Heidi Striker@heidi_striker
 Follow Follow 
   
Enter to win @coldfusion balls in our Striker Golf GPS Sweepstakesstrikergolfgps.com/enter-to-win-a… #golf #sports #sweepstakespic.twitter.com/TYZEp6Ufba - 02 Apr
  More Tweets
 Adam Cameron@dacCfml
   
@seancorfield @boyzoid "Enter to win @coldfusion balls" Poor old Rakshith. He'll sacrifice *anything* for #ColdFusion - 02 Apr
Rakshith Naresh@rakshithn
 
@dacCfml Since you seem to be after *mine*, I can sacrifice one to make up for your *none* - for your contribution to#ColdFusion
  
 02:50 PM - 07 Apr 14
  
 

Reply to @rakshithn
Retweet Favorite


That's hilarious. Thanks for the offer, but things'd be a bit crowded down there if I had an extra. And people would talk.

I'd like to make it very clear that Rakshith simply misread my previous message and thought I was having a go at him (which I was not: I was paying him a compliment!), and at no point did I take offence at this.

I think it's good we can horse around.

And I think we probably owe each other a beer next time we're in the same place at the same time.

Anyway... ballocks to this.

--
Adam

listContains() is almost certainly not what you mean to be using

$
0
0
G'day:
This topic is fished from a "conversation" (if one will permit it to be called that) from Twitter yesterday. I'm writing this so that it will show up in Google results if people are wondering about the function. Bottom line: if ever you find yerself using listContains(), there's a very very good chance you actually ought to be using listFind(), and you are overlooking a subtle difference between the two.


Here's some code:

days = "Tuesday,yesterday,day,another day"
containedAt = listContains(days, "day")
foundAt = listFind(days, "day")

dump({
"Using listContains()" = containedAt,
"Using listFind()" = foundAt
})

And its result:

Struct
Using listContains()
number1
Using listFind()
number3

As per the docs - the things that people seldom read, it seems - listContains() returns the index of the first list element which contains the sought-after string; listFind() returns the index of the first list element which equals the sought-after string. It's a subtle difference.

Once seldom wants to perform the operation the functionality of listContains() caters for. So if you find yourself using it... think again. It could be appropriate, but it seldom is (and, yes, I know sometimes it's appropriate, you don't need to comment to tell me this).

The problem here is one of function-naming. Without already knowing the difference, the names of the functions listFind() and listContains() do not really distinguish themselves. If anything one might guess the difference is one of return type: listFind() returns a numeric index; listContains() a boolean. listContains() really ought to have been called listFindInElement() or something like that. It's too late in the piece to be suggesting a deprecation of listContains() in favour of that though. What do you think?

As an exercise, why not go have a look in your codebase to see if you have any misuse of listContains()? I just spotted a like 32 misuses of it out of a today of 67 in our codebase (which has around 100k lines of code, to put it in context).

--
Adam

Cool CFML open source project I just spotted

$
0
0
G'day:
Just a heads-up really. MisterDai (David Boyer) has a project on GitHub, cfbackport. The description in the readme says:

This project aims to make at least some functions from newer versions of Adobe
ColdFusion avilable in older versions.  For example, SessionInvalidate() is new
to CF10 but undocumented features make it possible in at least CF8+, possibly
even CF7.
Each set of functions is wrapped within an "if" statement to make sure they
aren't loaded if the version already supports them.

How cool is that idea? He's just uploaded a backport of queryExecute(), and there's a bunch of other stuff there too. This is definitely something the CFML community will benefit from, so would be good to get some more community participation going.

That's it. Nice work David.

--
Adam
Viewing all 1332 articles
Browse latest View live