Execute Arbitrary Blocks of CFML Code

24 views
Skip to first unread message

Peter J. Farrell

unread,
Sep 7, 2010, 5:17:26 PM9/7/10
to cfml-convent...@googlegroups.com
Hi Guys,

I'm working on a system where some code is dynamically generated and
then rendered. The only caveat is that you have write a file to the
disk and call cfinclude on it to get it to execute for ACF / Railo.
OpenBD has a "render()" function to works like evaluate() does but works
on blocks of code (including tags) whereas evaluate() only evals
expressions. I'd like my solution to be cross engine compatible so I'm
going to have to write to disk for ACF / Railo for now. However this
begs the question -- why isn't this feature construct part of the core
CFML language? Before submitting tickets to ACF / Railo it would be
nice to discuss this futher, but it seems like a feature defect to not
have the ability to execute arbitrary blocks of CFML code. Discuss!

Best,
.Peter

Alan Williamson (aw2.0 ltd)

unread,
Sep 7, 2010, 6:06:26 PM9/7/10
to cfml-convent...@googlegroups.com
To add to that, we also have the <nocfml> tag to help building of
dynamic code.

http://www.openbluedragon.org/manual/?/cfmlmanipulation

This is something we use a __lot__ when we are building solutions. The
render() function has been in the bluedragon family since pretty much
day one, where as <nocfml> is a recent addition.

Todd Rafferty

unread,
Sep 7, 2010, 6:22:42 PM9/7/10
to cfml-convent...@googlegroups.com
I don't have an answer as to why it's not in Railo other than it was never part of the core language. I do have an alternative, that being that render() can be easily added with the magic directories that Railo has that you can write your own function / tags and include them into Railo.

I'll point someone from the team here and perhaps a push can be made. Even if Railo did include this, you'd still be incompatible with ACF? Is this acceptable?

Sean Corfield

unread,
Sep 7, 2010, 6:29:23 PM9/7/10
to cfml-convent...@googlegroups.com
I think this was discussed on the CFML Advisory Committee at point and
the thinking was: if you have the ram:// protocol for file operations
(which Railo has had since 2.0 and Adobe introduced in CF9), then the
easiest / fastest way to execute arbitrary code is write to a 'file'
in memory and include it.

Matthew Woodward

unread,
Sep 7, 2010, 6:30:44 PM9/7/10
to cfml-convent...@googlegroups.com
On Tue, Sep 7, 2010 at 3:29 PM, Sean Corfield <seanco...@gmail.com> wrote:
I think this was discussed on the CFML Advisory Committee at point and
the thinking was: if you have the ram:// protocol for file operations
(which Railo has had since 2.0 and Adobe introduced in CF9), then the
easiest / fastest way to execute arbitrary code is write to a 'file'
in memory and include it.

Doesn't cover pulling code from a database though, which is handy in some cases. Guess you could pull from the DB and then write to "file" but still a bit of a round-about solution.

--
Matthew Woodward
ma...@mattwoodward.com
http://blog.mattwoodward.com
identi.ca / Twitter: @mpwoodward

Please do not send me proprietary file formats such as Word, PowerPoint, etc. as attachments.
http://www.gnu.org/philosophy/no-word-attachments.html

Alan Williamson (aw2.0 ltd)

unread,
Sep 7, 2010, 6:38:48 PM9/7/10
to cfml-convent...@googlegroups.com
OpenBD supports ram:// using the FileXXX() functions.

It feels a little clunky though; the render() method definitely more
efficient with a lot less layers going on.

But at least there is at one path forward that all the engines support.

Peter Boughton

unread,
Sep 7, 2010, 6:45:12 PM9/7/10
to cfml-convent...@googlegroups.com
I'm undecided on render() function... I dynamically generate code, but
I can't currently think up a situation where I'd not want that code in
a file anyway, so not seeing where the function might help?


> Doesn't cover pulling code from a database though, which is handy in some
> cases. Guess you could pull from the DB and then write to "file" but still a
> bit of a round-about solution.

Hmm, can you give an example of when storing code in a db would be a good idea?
(as opposed to storing the code in a file and the filename in the db)


Also, is there a reason for having a separate render() function,
rather than letting evaluate() handle tags (and script) too?

Matthew Woodward

unread,
Sep 7, 2010, 6:56:32 PM9/7/10
to cfml-convent...@googlegroups.com
On Tue, Sep 7, 2010 at 3:45 PM, Peter Boughton <boug...@gmail.com> wrote:
Hmm, can you give an example of when storing code in a db would be a good idea?
(as opposed to storing the code in a file and the filename in the db)

Last time I ran into this was years ago when I was rolling my own CMS, so maybe it's an indefensible position now, but boy would I have loved to have been able to do that at the time. ;-)

Kym Kovan

unread,
Sep 7, 2010, 7:00:41 PM9/7/10
to cfml-convent...@googlegroups.com
On 8/09/2010 08:45, Peter Boughton wrote:
> I'm undecided on render() function... I dynamically generate code, but
> I can't currently think up a situation where I'd not want that code in
> a file anyway, so not seeing where the function might help?

A lot of CMSs generate the final HTML from templates with content being
dropped in via CMS tags. In ours we read the template via an include and
wrap the whole thing in a <cfsavecontent > to be able to then manipulate
it. It would be much easier to do it all in one go on the fly.

>> Doesn't cover pulling code from a database though, which is handy in some
>> cases. Guess you could pull from the DB and then write to "file" but still a
>> bit of a round-about solution.
> Hmm, can you give an example of when storing code in a db would be a good idea?
> (as opposed to storing the code in a file and the filename in the db)

A reporting engine where the user is generating the query?

--

Yours,

Kym

Peter J. Farrell

unread,
Sep 7, 2010, 7:09:00 PM9/7/10
to cfml-convent...@googlegroups.com
Todd Rafferty said the following on 09/07/2010 05:22 PM:

> I'll point someone from the team here and perhaps a push can be
> made. Even if Railo did include this, you'd still be incompatible with
> ACF? Is this acceptable?
Yeah, it's acceptable to me. I brought this up because I see this as
deficiency in CFML as whole. It's up to the engines if they want fill
this gap. I hope each engine decides to follow suit in a compatible way
(i.e I hope Railo implements Render() function and not named something
else), however I do know that it may not be possible in all cases. I
know there are a couple of Adobe representatives on the list. It's
there call if they want to implement something like this suggestion. In
this case, using a different function name is just being mean to
framework developers and any developer that needs to write cross-engine
compat applications.

.pjf


Peter Bell

unread,
Sep 7, 2010, 7:07:39 PM9/7/10
to cfml-convent...@googlegroups.com

On Tue, Sep 7, 2010 at 3:45 PM, Peter Boughton <boug...@gmail.com> wrote:
Hmm, can you give an example of when storing code in a db would be a good idea?
(as opposed to storing the code in a file and the filename in the db)

If you want to treat the code as content, leveraging all of the functionality you have for working with other content types. If it's just another object and you have a versioning cms, you can roll back, see audit trails, see who made each change, you can fairly easily display diffs, and instead of having to tie into a file based vcs you can leverage the code you've already written for doing the same for pages, FAQs, products, product categories, new stories, etc. 

Also, in some cases it's easier to have the data in a database when restoring, saving, making it available to multiple web servers, etc. It's not that you can't do this equally well with files, but if you've got the infrastructure for doing it with the database, sometimes it is nice to leverage that infrastructure for all of your content types - including arbitrary code blocks.

Best Wishes,
Peter
\

Baz

unread,
Sep 7, 2010, 7:13:30 PM9/7/10
to cfml-convent...@googlegroups.com
Is there any reason why evaluate() wasn't originally made, or extended, to evaluate any cfml rather than just expressions?


Matthew Woodward

unread,
Sep 7, 2010, 7:35:23 PM9/7/10
to cfml-convent...@googlegroups.com
On Tue, Sep 7, 2010 at 4:13 PM, Baz <b...@thinkloop.com> wrote:
Is there any reason why evaluate() wasn't originally made, or extended, to evaluate any cfml rather than just expressions?

There's always a trade-off in doing this. In most situations you wind up having to do something like add a parameter to indicate the behavior should be different than the existing behavior for the function, e.g.:
Evaluate("<cfset foo = 'bar' />", "code")

Or something along those lines. That gets pretty ugly IMO, not to mention it can be more confusing in some cases to overload an existing function with new behavior, so a separate function makes sense.

Always a good discussion to have for brand-new functionality though. Since CFML is a flat namespace we always have to walk the line between overloading existing functions/tags and adding new stuff to the flat namespace.

For example, IMO all the image and spreadsheet functions that were added to CF 8 and CF 9 should have been added to an Image and Spreadsheet *object*, so you'd do:
ss = new Spreadsheet();
ss.read('/path/to/foo.xls');

Instead of:
ss = SpreadsheetRead('/path/to/foo.xls');

That would be a bit of a mindshift compared to how other stuff in CFML works, but throwing 80-100 new functions to the base namespace for image and spreadsheet-specific stuff doesn't make sense to me.

Anyway, fun discussions to have. :-)

Sean Corfield

unread,
Sep 8, 2010, 1:48:01 AM9/8/10
to cfml-convent...@googlegroups.com
On Tue, Sep 7, 2010 at 3:38 PM, Alan Williamson (aw2.0 ltd)
<al...@aw20.co.uk> wrote:
> OpenBD supports ram:// using the FileXXX() functions.

Good to know, thanx Alan. I wasn't sure how quickly OpenBD was
adopting stuff like that. I know you've been very aggressive about
adding the cfscript enhancements. It's great to see such a high level
of compatibility, so quickly!
--
Sean A Corfield -- (904) 302-SEAN
Railo Technologies, Inc. -- http://getrailo.com/
An Architect's View -- http://corfield.org/

"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood

Sean Corfield

unread,
Sep 8, 2010, 1:57:40 AM9/8/10
to cfml-convent...@googlegroups.com
On Tue, Sep 7, 2010 at 4:13 PM, Baz <b...@thinkloop.com> wrote:
> Is there any reason why evaluate() wasn't originally made, or extended, to
> evaluate any cfml rather than just expressions?

I must admit, when I learned about OpenBD's render() function, I did
wonder why they didn't just enhance evaluate() to allow 'any' CFML as
the argument. From a language design point of view, I would rather
evaluate() accepted ANY CFML and returned the last value - if any - of
the evaluated code. Thoughts?

Mark Drew

unread,
Sep 8, 2010, 4:33:20 AM9/8/10
to cfml-convent...@googlegroups.com
I am with Sean on this one. If you have Render() and Evaluate() , explain the difference to me, as a non CFMLer. Sounds confusing, but if you say Evaluate() evaluates *ANY* code within it, it makes sense.

Regards

MD

Mark Drew
Railo Technologies UK
Professional Open Source
skype: mark_railo
email: ma...@getrailo.com
gtalk: ma...@getrailo.com
tel: +44 7971 85 22 96
web: http://www.getrailo.com

Alan Williamson

unread,
Sep 8, 2010, 5:28:16 AM9/8/10
to CFML Conventional Wisdom
They are different.

How does the engine know what to do with:

"X+Y"

With Evaluate it will of course perform it.

but if you are throwing in tags as well then it does not make sense. So say:

"Here is the result of x+y <Cfoutput>#x+y#</cfoutput>"

Its about context. So Evaluate in its raw form does not make sense.

When I first implement render() I played out these scenarios. As Matt says, better to add a new function.

Personnally I would ditch evaluate and go exclusively with render.
--
aw2.0 ltd www.aw20.co.uk

Peter J. Farrell

unread,
Sep 8, 2010, 9:41:44 AM9/8/10
to cfml-convent...@googlegroups.com
Mark Drew said the following on 09/08/2010 03:33 AM:

> I am with Sean on this one. If you have Render() and Evaluate() ,
> explain the difference to me, as a non CFMLer. Sounds confusing, but
> if you say Evaluate() evaluates *ANY* code within it, it makes sense.

Evaluate() does expressions. Render() does blocks of code. Inheritly,
evaluate() is going to a bit more "secure". Consider expressions that
are derived from user input -- evaluate would choke on anything injected
whereas you have to way more careful when using render(). What if
somebody injects a <cfquery> with drop tables into a string used in
Evaluate()? So just the "restriction" of scope in what evaluate
inherently can do is good thing in my mind.

.pjf

Peter Boughton

unread,
Sep 8, 2010, 9:48:27 AM9/8/10
to cfml-convent...@googlegroups.com
What stops someone evaluating render() ?

Mark Jones

unread,
Sep 8, 2010, 10:13:39 AM9/8/10
to cfml-convent...@googlegroups.com
One more point on the difference, :

<cfset myvar = 3>
<cfset blah = evaluate("#myvar#+4")>

Is "silent" in that nothing is sent to the browser and blah ends up with the value of 7.

<cfset myvar = 3>
<cfset blah = render("#myvar#+4")>

Sends the text "3+4" to the browser and blah ends up with... well, actually, I don't know. Possibly nothing?  [ Or am I misunderstanding and render() *returns* the output, which can then be output by the programmer at his leisure.  Honestly, either way, the difference still works. ]

One problem of merging the two behaviors into a single function as suggested above, where all code is "rendered" and the last generated value is returned, is that suddenly the first example sends output to the browser... which is not what is wanted at all.

In once sense, the difference between evaluate() and render() is the same as the difference between <cfset /> and <cfoutput></cfoutput>.  It's whether you're sending the output to a variable or to the browser.

Baz

unread,
Sep 8, 2010, 1:28:41 PM9/8/10
to cfml-convent...@googlegroups.com
(Render) sends the text "3+4" to the browser

Hmm, I'm not sure that's my favorite - why have render() automatically output to screen on your behalf, rather than just cfoutputting a moment later if that's what you want? What about if you needed to use it as an intermediate step, rather than the final destination? Or what if you needed to evaluate non display stuff? Or perhaps you needed to use the result of a render() in another render()? Or what if you dynamically generated your model from a config file and now needed to instantiate the objects for use in the system? Seems like all that should be legal.

Baz



Mark Jones

unread,
Sep 8, 2010, 2:33:36 PM9/8/10
to cfml-convent...@googlegroups.com
On Wed, Sep 8, 2010 at 12:28 PM, Baz <b...@thinkloop.com> wrote:
(Render) sends the text "3+4" to the browser

Hmm, I'm not sure that's my favorite - why have render() automatically output to screen on your behalf, rather than just cfoutputting a moment later if that's what you want? What about if you needed to use it as an intermediate step, rather than the final destination? Or what if you needed to evaluate non display stuff? Or perhaps you needed to use the result of a render() in another render()? Or what if you dynamically generated your model from a config file and now needed to instantiate the objects for use in the system? Seems like all that should be legal.

As I said, I'm not actually familiar with how the existing render() function works, and I agree with everything you just said.  I used that language because it was simpler than "generates text as if it were contained within a <cfsavecontent><cfoutput/></cfsavecontent> structure".  Whether it goes into a variable or directly to the output buffer is a different issue than how it is functionality different from evaluate().

Sean Corfield

unread,
Sep 8, 2010, 9:50:13 PM9/8/10
to cfml-convent...@googlegroups.com
On Wed, Sep 8, 2010 at 2:28 AM, Alan Williamson <al...@aw20.co.uk> wrote:
> How does the engine know what to do with:
>
> "X+Y"
>
> With Evaluate it will of course perform it.
>
> but if you are throwing in tags as well then it does not make sense.   So say:
>
> "Here is the result of x+y <Cfoutput>#x+y#</cfoutput>"

Just so I'm clear on how render() actually works, can you confirm the following:

<cfset x = 3 />
<cfset y = 4 />

evaluate( 'x+y' ) == 7
evaluate( '#x+y#' ) == 7 <!--- evaluated before calling evaluate() --->
evaluate( '##x+y##' ) == 7 <!--- evaluates #x+y# or is this illegal? --->

render( 'x+y' ) == ? The string "x+y" ?
render( '#x+y#' ) == 7 <!--- because #x+y# is evaluated before the call --->
render( '##x+y##' ) == 7 <!--- ? --->
render( '<cfoutput>##x+y##</cfoutput>' ) == 7

> Personnally I would ditch evaluate and go exclusively with render.

Did you consider extending evaluate() with an optional argument to
indicate code vs expression? Either a boolean or a string.

Alan Williamson (aw2.0 ltd)

unread,
Sep 8, 2010, 10:10:11 PM9/8/10
to cfml-convent...@googlegroups.com
render is "nearly" same as a cfinclude. so basically if you do:

<cfset aa = render( '##x+y##' )>

then aa will be : "#x+y#". If you do:

<cfset aa = render( '<cfoutput>##x+y##</cfoutput>' )>

then aa will be : "7". Now i say "nearly" because any output is not
sent to the request output stream, but caught, and given back as a
string. If that was a true CFINCLUDE then it would of course make it
back to the browser (or whatever the client was).

So Render() is more controlled. Like i said early, the vast majority
of my CFML apps has render() in it somewhere, its been a very powerful
addition.

Jamie Krug

unread,
Sep 8, 2010, 10:11:27 PM9/8/10
to cfml-convent...@googlegroups.com
On Wed, Sep 8, 2010 at 9:50 PM, Sean Corfield <seanco...@gmail.com> wrote:
Just so I'm clear on how render() actually works, can you confirm the following:

<cfset x = 3 />
<cfset y = 4 />

evaluate( 'x+y' ) == 7
evaluate( '#x+y#' ) == 7 <!--- evaluated before calling evaluate() --->
evaluate( '##x+y##' ) == 7 <!--- evaluates #x+y# or is this illegal? --->

I'd agree on the first two and really unsure on the last--I'd expect either the string "#x+y#" or it's illegal.

render( 'x+y' ) == ? The string "x+y" ?

I'd assume yes.
 
render( '#x+y#' ) == 7 <!--- because #x+y# is evaluated before the call --->
render( '##x+y##' ) == 7 <!--- ? --->

My understanding is that this would be treated just like a block of code in any other CFML, in which case I'd expect these to produce the very strings you show as the argument--exactly what would occur if that argument was the only content of a .cfm file.
 
render( '<cfoutput>##x+y##</cfoutput>' ) == 7

I'd expect this to render the string "#x+y#" but I assume this would render "7":
render( '<cfoutput>#x+y#</cfoutput>' )

Did you consider extending evaluate() with an optional argument to
indicate code vs expression? Either a boolean or a string.

Personally, I like the idea of evaluate() for evaluating expressions and render() to render a block of CFML, basically returning something like this for a render( code ) call, imagining that the code.cfm file has the same content of the 'code' argument to render():
<cfsavecontent variable="result" trim="true">
    <cfinclude template="code.cfm" />
</cfsavecontent>

...just my minuscule two cents ;-)

Cheers,
Jamie

Jamie Krug

unread,
Sep 8, 2010, 10:14:45 PM9/8/10
to cfml-convent...@googlegroups.com
Sorry folks. Alan's comment crossed paths with mine, but he was much more succinct... and accurate :)

Alan, I'm surprised render( '<cfoutput>##x+y##</cfoutput>' ) wouldn't render the string "#x+y#" to aa, no?

Also, just out of curiosity, if you're at liberty to share, would you share a couple example scenarios in which you leveraged render() in your CFML apps?

Thanks,
Jamie

Alan Williamson

unread,
Sep 8, 2010, 10:31:54 PM9/8/10
to CFML Conventional Wisdom
Jamie,

We build a lot of tools that are in themselves tools. So we have a system for example that let's users build webservices and we store their code snippets in a db before it gets published to a farm of machines. This is for a large internal app and has a lot of workflow/process associated with it. That's but one example.

Hope that helps.

a
--
aw2.0 ltd www.aw20.co.uk

Reply all
Reply to author
Forward
0 new messages