<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michael Born</title>
    <description>The latest articles on DEV Community by Michael Born (@mikeborn).</description>
    <link>https://dev.to/mikeborn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F22823%2F4721a180-e702-4888-a78e-94a1364cef6e.jpg</url>
      <title>DEV Community: Michael Born</title>
      <link>https://dev.to/mikeborn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mikeborn"/>
    <language>en</language>
    <item>
      <title>How to Get the Version of Any Java Package from CFML</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Wed, 21 Sep 2022 15:18:20 +0000</pubDate>
      <link>https://dev.to/mikeborn/how-to-get-the-version-of-any-java-package-from-cfml-1064</link>
      <guid>https://dev.to/mikeborn/how-to-get-the-version-of-any-java-package-from-cfml-1064</guid>
      <description>&lt;p&gt;The &lt;a href="https://poi.apache.org/"&gt;Apache POI library&lt;/a&gt; is an awesome tool for messing with spreadsheets. You can read spreadsheet data, get header rows, total row count, all sorts of wacky stuff. Julian Halliwell's excellent &lt;a href="https://github.com/cfsimplicity/spreadsheet-cfml"&gt;spreadsheet-cfml library&lt;/a&gt; uses it to great effect.&lt;/p&gt;

&lt;p&gt;But when I try to use Apache POI standalone, I got an error that a method didn't exist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;No matching Method/Function &lt;span class="k"&gt;for &lt;/span&gt;org.apache.poi.hssf.usermodel.HSSFSheet.getTables&lt;span class="o"&gt;()&lt;/span&gt; found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It would seem that Lucee bundles an older version of Apache POI by default. (UPDATE: &lt;a href="https://twitter.com/cfsimplicity/status/1572226273870778376"&gt;Turns out this is only present due to the Apache Tika bundle, which &lt;em&gt;is&lt;/em&gt; shipped with Lucee. Thanks Julian Halliwell for that tip!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But what version would that be?&lt;/p&gt;

&lt;p&gt;We could easily find out from the Lucee admin page, of course. Provided it is enabled.&lt;/p&gt;

&lt;p&gt;But why not try to grab the POI bundle version in code? From our CFML?&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading a Java Package Version in Lucee
&lt;/h2&gt;

&lt;p&gt;It all starts with the java class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.poi.hssf.usermodel.HSSFSheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then grab the java classloader tied to this class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.poi.hssf.usermodel.HSSFSheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getClassLoader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have that, we need to grab the OSGI bundle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.poi.hssf.usermodel.HSSFSheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getClassLoader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getBundle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, grab the version as a string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.poi.hssf.usermodel.HSSFSheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getClassLoader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getBundle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voila! We have our package version! It seems Lucee ships with Apache POI 2.5.1, released in November 2005. &lt;em&gt;&lt;strong&gt;Wow&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  UPDATE: Using Lucee's BundleInfo() method
&lt;/h3&gt;

&lt;p&gt;Julian Halliwell (author of the awesome Spreadsheet CFML library) pointed out that Lucee has a &lt;code&gt;bundleInfo()&lt;/code&gt; function which does the same thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Great post! Lucee has a BundleInfo() BIF which also returns other useful info. - &lt;em&gt;Julian Halliwell, @cfsimplicity&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using bundleInfo() would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.logging.log4j.LogManager&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Honestly, this is much nicer than my implemen&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading a Java Package Version from Adobe ColdFusion
&lt;/h2&gt;

&lt;p&gt;However, in Adobe CF (ACF) this fails because ACF does not architecture packages via OSGI. (Not to my knowledge, that is.) We need to find another method… and it turns out reading package details is even simpler in Adobe.&lt;/p&gt;

&lt;p&gt;First, we instantiate the Java Package library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java.lang.Package&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, we get the Apache POI package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java.lang.Package&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getPackage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.poi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have the POI package, we can grab the implementation version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java.lang.Package&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getPackage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.poi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getImplementationVersion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it!&lt;/p&gt;

&lt;h2&gt;
  
  
  A Cross-Engine Solution
&lt;/h2&gt;

&lt;p&gt;Sadly, neither of these solutions work in both Lucee and Adobe ColdFusion due to the differences in Java package bundling approaches between the two engines.&lt;/p&gt;

&lt;p&gt;The best we can get would be something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Grab installed version of the bundled Apache POI library.
 */&lt;/span&gt;
&lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getApachePOIVersion&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keyExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lucee&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.poi.hssf.usermodel.HSSFSheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getClassLoader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getBundle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java.lang.Package&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getPackage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.poi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getImplementationVersion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sadly, I see little hope for a cross-engine solution that works &lt;em&gt;generically&lt;/em&gt; on package names. In Adobe you can grab the package version by package name… but in Lucee you must search for a specific package class.&lt;/p&gt;

&lt;h2&gt;
  
  
  The POI Version Class
&lt;/h2&gt;

&lt;p&gt;Caveat: Apache POI ships with a “Version” class in versions 3.x. So my example is a bit pointless for Apache POI v3 and newer. If you’re on ACF 10+, you can use the provided Version class to grab the version - no Java Package gymnastics required:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.poi.Version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;getVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s not the point of this blog post, though. This post aims to assist you in reading the installed version of &lt;strong&gt;any Java package&lt;/strong&gt; - not just those with a handy &lt;code&gt;my.package.Version&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;Till next time!&lt;/p&gt;

</description>
      <category>cfml</category>
      <category>coldfusion</category>
      <category>java</category>
    </item>
    <item>
      <title>Redirecting Hibernate Logs to the CommandBox Console</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Mon, 30 Aug 2021 13:41:20 +0000</pubDate>
      <link>https://dev.to/mikeborn/redirecting-hibernate-logs-to-the-commandbox-console-1l7p</link>
      <guid>https://dev.to/mikeborn/redirecting-hibernate-logs-to-the-commandbox-console-1l7p</guid>
      <description>&lt;p&gt;In my last blog post, I covered how to adjust the Hibernate log level with Log4j.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--M3bczibK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1124335569486712832/CwHHT16-_normal.jpg" alt="Michael Born profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Michael Born
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @michaelborn_me
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Another quick blog post, this time about resolving a Concurrent Modification Exception in Lucee Hibernate. Kudos to &lt;a href="https://twitter.com/jclausen"&gt;@jclausen&lt;/a&gt; for the fix! 💪&lt;br&gt;&lt;br&gt;&lt;a href="https://t.co/60MieIsvui"&gt;michaelborn.me/entry/resolvin…&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      12:00 PM - 20 Aug 2021
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1428688490259271687" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1428688490259271687" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1428688490259271687" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;This helped us avoid a concurrent modification exception due to logging certain database entities with the &lt;code&gt;DEBUG&lt;/code&gt; logger, but it also sets us up for further interaction with log4j configuration. This week we're going a step farther to take all log4j messages emitted by the HIbernate logger and redirect them to the console. This console is what is shown when you run &lt;code&gt;box server log --follow&lt;/code&gt; in CommandBox.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Not sure what Log4j is? &lt;a href="https://twitter.com/michaelborn_me"&gt;Tweet at me&lt;/a&gt; and I'll happily cover basic Log4j usage in a blog post.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To begin, we need a Log4j "Logger" object which we can use to grab the Hibernate logger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.log4j.Logger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;hibernateLog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.hibernate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;log&lt;/code&gt; variable now contains a reference to the root hibernate logger. All log messages emitted from any class in Hibernate will pass through this logger.&lt;/p&gt;

&lt;p&gt;We can set the logging level - for development, we may want &lt;code&gt;WARN&lt;/code&gt; or &lt;code&gt;DEBUG&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.log4j.Level&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;hibernateLog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEBUG&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; Be aware that the &lt;code&gt;DEBUG&lt;/code&gt; log level may cause issues on entity save - see &lt;a href="https://michaelborn.me/entry/resolving-concurrent-exceptions-in-hibernate-logger"&gt;Resolving Concurrent Exceptions in Hibernate Logger&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that we have the logger we can reuse one of Lucee's existing log4j appenders to configure log output. This is basically piggybacking on Lucee to pass all &lt;code&gt;org.hibernate&lt;/code&gt; logs through the "console" appender to &lt;code&gt;System.Out&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;printWriter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPageContext&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;getOutWriter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lucee.commons.io.log.log4j.layout.ClassicLayout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;consoleAppender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lucee.commons.io.log.log4j.appender.ConsoleAppender&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;printWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then finally, we can tell log4j to use Lucee's console appender for all Hibernate logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;hibernateLog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addAppender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;consoleAppender&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put it all together, and here's what you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;setHibernateLogging&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="cm"&gt;/**
   * Resolves Hibernate ConcurrentModificationException when flushing an entity save with one-to-many relationships.
   * 
   * @see https://access.redhat.com/solutions/29774
   * @see https://michaelborn.me/entry/resolving-concurrent-exceptions-in-hibernate-logger
   */&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.log4j.Logger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.apache.log4j.Level&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;hibernateLog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;org.hibernate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;hibernateLog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WARN&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Redirect all Hibernate logs to system.out
   */&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;listFindNoCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Lucee&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coldfusion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productname&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;printWriter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPageContext&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;getOutWriter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lucee.commons.io.log.log4j.layout.ClassicLayout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;consoleAppender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lucee.commons.io.log.log4j.appender.ConsoleAppender&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;printWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;hibernateLog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addAppender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;consoleAppender&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method should be placed in &lt;code&gt;Application.cfc&lt;/code&gt; early in the application lifecycle. If this method is run during the page request or in &lt;code&gt;onRequestStart()&lt;/code&gt;, then Hibernate has already initialized and you have lost a lot of valuable output.&lt;/p&gt;

&lt;p&gt;Once this method is in place, we can take advantage of it from CommandBox:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;box&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;follow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is fantastically great for picking up better log details on, say, an invalid ORM entity.&lt;/p&gt;

</description>
      <category>cfml</category>
      <category>coldfusion</category>
      <category>hibernate</category>
      <category>log4j</category>
    </item>
    <item>
      <title>Resolving Concurrent Exceptions in Hibernate Logger</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Thu, 19 Aug 2021 20:55:21 +0000</pubDate>
      <link>https://dev.to/mikeborn/resolving-concurrent-exceptions-in-hibernate-logger-56o7</link>
      <guid>https://dev.to/mikeborn/resolving-concurrent-exceptions-in-hibernate-logger-56o7</guid>
      <description>&lt;p&gt;Recently while working on a Hibernate ORM project, I ran into an interesting issue when an entity with relationships is saved inside a transaction.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transaction{
  var myEntity = entityLoadByPK( "Person", theEntityID );

  myEntity.setAddress( otherEntity );
  myEntity.save();

  // throws "ConcurrentModificationException" on transaction end.
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Note this is not a complete test case - simply an example of when the issue occurs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When the transaction completes, Lucee tries to flush the entity modifications, but this fails with the following error:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lucee.runtime.exp.NativeException: java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493)
at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1526)
at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1524)
at org.hibernate.internal.util.EntityPrinter.toString(EntityPrinter.java:112)
at org.hibernate.event.internal.AbstractFlushingEventListener.logFlushResults(AbstractFlushingEventListener.java:128)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:104)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:93)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1362)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1349)
at org.lucee.extension.orm.hibernate.HibernateORMTransaction.end(HibernateORMTransaction.java:57)
at lucee.runtime.orm.ORMConnection.setAutoCommit(ORMConnection.java:213)
at lucee.runtime.orm.ORMDatasourceConnection.setAutoCommit(ORMDatasourceConnection.java:336)
at lucee.runtime.db.DatasourceManagerImpl.end(DatasourceManagerImpl.java:350)
at lucee.runtime.db.DatasourceManagerImpl.end(DatasourceManagerImpl.java:330)
at lucee.runtime.tag.Transaction.doFinally(Transaction.java:160)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It turns out this issue is related to the Hibernate debug logger. In Lucee, Hibernate's log4j logger is set to a &lt;code&gt;DEBUG&lt;/code&gt; level by default. That's fine, but it seems the logger actually &lt;em&gt;mutates&lt;/em&gt; the logged entities during logging. Thus we get a concurrent modification exception.&lt;/p&gt;

&lt;p&gt;To resolve this, all we have to do is de-escalate the logging level from &lt;code&gt;DEBUG&lt;/code&gt; to &lt;code&gt;WARN&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Resolves Hibernate ConcurrentModificationException when flushing an entity save with one-to-many relationships.
 * 
 * @see https://access.redhat.com/solutions/29774
 */
var Logger = createObject( "java", "org.apache.log4j.Logger" );
var level = createObject( "java", "org.apache.log4j.Level" );
var log = Logger.getLogger( "org.hibernate" );
log.setLevel( level.WARN );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This should be done in the &lt;code&gt;Application.cfc&lt;/code&gt; before ORM initializes - say, just below the &lt;code&gt;this.ormSettings{}&lt;/code&gt; configuration block.&lt;/p&gt;

&lt;p&gt;All thanks to &lt;a href="https://twitter.com/jclausen"&gt;@jclausen&lt;/a&gt; for this awesome find and easy fix!&lt;/p&gt;

</description>
      <category>cfml</category>
      <category>coldfusion</category>
      <category>hibernate</category>
      <category>orm</category>
    </item>
    <item>
      <title>Cross-engine transaction detection in Hibernate v3+</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Thu, 12 Aug 2021 02:38:55 +0000</pubDate>
      <link>https://dev.to/mikeborn/cross-engine-transaction-detection-in-hibernate-v3-540n</link>
      <guid>https://dev.to/mikeborn/cross-engine-transaction-detection-in-hibernate-v3-540n</guid>
      <description>&lt;h3&gt;
  
  
  UPDATE: Now with Adobe support!
&lt;/h3&gt;

&lt;p&gt;So, this is embarrassing. This article &lt;em&gt;claimed&lt;/em&gt; to offer a one-liner with Adobe and Lucee compatibility, but I completely neglected to actually &lt;em&gt;test&lt;/em&gt; it on ACF before I wrote the blog post. (I thought I'd tested it... evidently not.) I realized this week after attempting to use my "cross-compatible" transaction detection code that &lt;strong&gt;it's not cross-compatible at all!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bottom line: I updated the article with a properly-tested, fully cross-engine-compatible snippet to detect transactional context &lt;strong&gt;on both Adobe CF and Lucee&lt;/strong&gt;. You're welcome.&lt;/p&gt;




&lt;p&gt;We do a lot of ORM work at Ortus, and recently I have been on a bit of a Hibernate binge. One of the important things to note when working with Hibernate is that ORM queries may behave differently &lt;em&gt;inside&lt;/em&gt; a transaction block than they do &lt;em&gt;outside&lt;/em&gt; a transaction block. More importantly, the transactional handling in, say, Lucee 5.3 begins to break down when working with nested transactions.&lt;/p&gt;

&lt;p&gt;I digress, but let's just say it's important to know when the current code is inside a transaction context.&lt;/p&gt;

&lt;p&gt;Previously, the best knowledge we had said to run this on Adobe:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ADOBE ONLY!
var isInTransaction = createObject(“java”, “coldfusion.tagext.sql.TransactionTag”).getCurrent()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and something like this on Lucee:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// LUCEE ONLY!
var isInTransaction = getPageContext().getDataSourceManager().isAutoCommit() ? false : true;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But digging through the &lt;a href="https://docs.jboss.org/hibernate/stable/core/javadocs/org/hibernate/engine/spi/SharedSessionContractImplementor.html#isTransactionInProgress--"&gt;Hibernate Session docs&lt;/a&gt;, I found a wonderful little method called &lt;code&gt;isTransactionInProgress&lt;/code&gt;. And just like that, here's a CFML method to wrap it and consistently detect the transactional context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boolean function isInTransaction(){
    if ( listFindNoCase( "Lucee", server.coldfusion.productname ) ) {
        return ORMGetSession().isTransactionInProgress();
    } else {
        return ORMGetSession().getActualSession().isTransactionInProgress();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That little beauty works&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; across CFML engines from Lucee to Adobe ColdFusion&lt;/li&gt;
&lt;li&gt; across multiple Hibernate versions from v3.x through v5.x&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, to be fair, I haven't really stress-tested this. It's &lt;em&gt;possible&lt;/em&gt; there are a few situations where Hibernate doesn't yet know a transaction has begun. But so far... it works, and works well!&lt;/p&gt;

&lt;p&gt;Until next time!&lt;/p&gt;

</description>
      <category>cfml</category>
      <category>coldfusion</category>
      <category>hibernate</category>
      <category>orm</category>
    </item>
    <item>
      <title>Five Things I'd Like To Learn in 2020</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Mon, 13 Jan 2020 12:49:52 +0000</pubDate>
      <link>https://dev.to/mikeborn/five-things-i-d-like-to-learn-in-2020-2o94</link>
      <guid>https://dev.to/mikeborn/five-things-i-d-like-to-learn-in-2020-2o94</guid>
      <description>&lt;h2&gt;
  
  
  One: How to Debug Slow Execution Times In FusionReactor
&lt;/h2&gt;

&lt;p&gt;I know what &lt;a href="https://www.fusion-reactor.com"&gt;Fusion Reactor&lt;/a&gt; is, and I know what it does. I even know a little how it works and how to look at a slow-running request.&lt;/p&gt;

&lt;p&gt;What I &lt;strong&gt;don't&lt;/strong&gt; know is how to make it useful after that.&lt;/p&gt;

&lt;p&gt;FR is really good at breaking down a request, method by method, to show you exactly how long each method call took. What I can't figure out is &lt;em&gt;exactly what those breakdowns mean&lt;/em&gt;. You know, the important part of debugging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vk5-xoD---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6tu7ttg0qwjs850hno89.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vk5-xoD---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6tu7ttg0qwjs850hno89.jpg" alt="FR profiler page showing the request exection breakdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So until I learn how to read the above breakdown, I'm only half a debugger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two: The Basics of ContentBox
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://contentboxcms.org/"&gt;ContentBox&lt;/a&gt; is awesome! I think...&lt;/p&gt;

&lt;p&gt;See, I know nothing about it. I've tried spinning it up once just for kicks, and immediately got confused with &lt;code&gt;install contentbox-site&lt;/code&gt; - like, shouldn't this actually create a working ContentBox site? You'd think so, from the name. But nope - you need to install the installer before you can install the site. Or something.&lt;/p&gt;

&lt;p&gt;Regardless, I &lt;em&gt;love&lt;/em&gt; that we have a decent option for a CFML-powered Content Management System.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vKzPac2A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1irmzeexvhcvif5983w5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vKzPac2A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1irmzeexvhcvif5983w5.png" alt="The ContentBox CMS admin looks pretty clean and, you know, useful!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd be happy to start developing new sites on ContentBox this year, if only I knew how to use it. The more devs and sites use ContentBox, obviously, the more love and attention ContentBox will get. If nothing else, this year I'd like to put some new site on ContentBox, learn it enough to operate and build the site, and submit a few PRs for documentation typos... one thing I'm good at!&lt;/p&gt;

&lt;h2&gt;
  
  
  Three: How to Configure WireBox for Vanilla CF Apps
&lt;/h2&gt;

&lt;p&gt;WireBox is awesome. It powers dependency injection in ColdBox and makes it simple to instantiate a component on the fly, or share a singleton across multiple uses per request.&lt;/p&gt;

&lt;p&gt;WireBox can also be used standalone to add dependency injection (DI) to a legacy app. In my (uneducated) opinion, this is the best first step towards modernizing your legacy / spaghetti code. Once you have DI set up it becomes easier to rename, refactor, or reorganize your app to fit an MVC framework (such as ColdBox) or simply to make improvements.&lt;/p&gt;

&lt;p&gt;Right now, I only know how to use WireBox within the context of ColdBox. This year I'd love to dig deep into WireBox and figure out &lt;strong&gt;how&lt;/strong&gt; it works and how to configure it for a vanilla CF app. If I knew that I could teach it to others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four: CB Streams
&lt;/h2&gt;

&lt;p&gt;This one's kinda, you know... deep. Like, intellectually deep, and I confess I have no idea how to use it. I know what cbStreams &lt;strong&gt;is&lt;/strong&gt; and I know vaguely what it's supposed to &lt;strong&gt;do&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The whole idea of streams is to enable functional-style operations on streams of elements. A stream is an abstraction, it’s not a data structure. It’s not a collection where you can store elements. The most important difference between a stream and a structure is that a stream doesn’t hold the data. For example you cannot point to a location in the stream where a certain element exists. You can only specify the functions that operate on that data. A stream is an abstraction of a non-mutable collection of functions applied in some order to the data.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;quote from the &lt;a href="https://forgebox.io/view/cbstreams"&gt;cbStreams README&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What I &lt;em&gt;think&lt;/em&gt; this means, in a nutshell, is that cbStreams helps you efficiently manipulate large amounts of data in a concise, easy syntax.&lt;/p&gt;

&lt;p&gt;To me, that sounds like a useful tool to know!&lt;/p&gt;

&lt;h2&gt;
  
  
  Five: Ant and Maven Build Tools
&lt;/h2&gt;

&lt;p&gt;I know Ant and Maven are not strictly CF-specific tools. Regardless, the &lt;a href="https://github.com/lucee/lucee"&gt;Lucee core&lt;/a&gt;, &lt;a href="https://github.com/lucee?utf8=%E2%9C%93&amp;amp;q=extension&amp;amp;type=&amp;amp;language="&gt;Lucee extensions&lt;/a&gt;, and many open-source CFML libraries use Ant or Maven (or both!?) for building their source code.&lt;/p&gt;

&lt;p&gt;This is important to me because I'd like to contribute to the Lucee platform. Yet without knowing how to build and run the tests, I won't be able to do that.&lt;/p&gt;

&lt;p&gt;And no, only knowing how to &lt;code&gt;ant build fast&lt;/code&gt; or something is not good enough. Ideally I should know:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; What ant and maven do&lt;/li&gt;
&lt;li&gt; What the difference is between the two&lt;/li&gt;
&lt;li&gt; How to run tasks&lt;/li&gt;
&lt;li&gt; How to define extra tasks (e.g. for adding a test step or build step)&lt;/li&gt;
&lt;li&gt; How to debug a failed build.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;2020 is going to be an awesome year. I've listed out five CF-related tools I'd &lt;em&gt;ideally&lt;/em&gt; like to learn this year - what about you?&lt;/p&gt;

</description>
      <category>2020</category>
      <category>cfml</category>
      <category>coldfusion</category>
      <category>contentbox</category>
    </item>
    <item>
      <title>Three ColdBox Features I Learned While Building A URL Shortener</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Wed, 18 Dec 2019 02:40:29 +0000</pubDate>
      <link>https://dev.to/mikeborn/three-coldbox-features-i-learned-while-building-a-url-shortener-5api</link>
      <guid>https://dev.to/mikeborn/three-coldbox-features-i-learned-while-building-a-url-shortener-5api</guid>
      <description>&lt;p&gt;Last night I did another live-stream where I finished the first draft of a URL shortener I'm calling "cfShorty". During live-streams I typically end up searching the ColdBox docs for help, but this time &lt;a href="https://twitter.com/gpickin"&gt;Gavin Pickin&lt;/a&gt; watched and commented with some cool tips, most of which I'd never used before.&lt;/p&gt;

&lt;p&gt;Here are the three ColdBox features I learned while building my URL shortener last night.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resourceful Routes
&lt;/h2&gt;

&lt;p&gt;This one was cool. Rather than define and tweak my URL routes manually in &lt;code&gt;/config/Router.cfc&lt;/code&gt;, Gavin told me how to use the &lt;a href="https://coldbox.ortusbooks.com/the-basics/routing/routing-dsl/resourceful-routes"&gt;resourceful routing feature&lt;/a&gt; to auto-generate my CRUD routes for me.&lt;/p&gt;

&lt;p&gt;By simply adding &lt;code&gt;resources( "photos" )&lt;/code&gt; to my ColdBox Router config file (that's &lt;code&gt;/config/Router.cfc&lt;/code&gt;), ColdBox will set up all the routes necessary for a CRUD management screen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  List resources page (aka table of entries with Edit/Delete button) via &lt;code&gt;GET /resource&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Show individual resource (aka readonly view of a single entry) via &lt;code&gt;GET /resource/:id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Show "New Resource" form to create a new resource entry via &lt;code&gt;GET /resource/new&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Show edit form for an existing resource via &lt;code&gt;GET /resource/:id/edit&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As well as the three main routes necessary for creating, updating and deleting entries from the database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Create new resource entry via &lt;code&gt;POST /resource&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Update an existing resource entry via &lt;code&gt;PUT /resource/:id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Delete an existing resource entry via &lt;code&gt;DELETE /resource/:id&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obviously, I still had to write the code to handle each event, but ColdBox even makes that party easy by offering a CommandBox CLI command which can quickly build out your event handler, HTML view files, a model object, and even base test specs in your &lt;code&gt;tests/specs&lt;/code&gt; directory:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xPmwbdTy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zedt6vnhpx2icliqcvzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xPmwbdTy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zedt6vnhpx2icliqcvzp.png" alt='Running "coldbox create resource Users" inside the commandbox shell to build handlers, views, models and test files'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://coldbox.ortusbooks.com/the-basics/routing/routing-dsl/resourceful-routes#scaffolding-resources"&gt;"Scaffolding Resources" ColdBox docs&lt;/a&gt; outline this, but it's as easy as running:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coldbox create resource Users
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  ColdBox Route Visualizer Module
&lt;/h2&gt;

&lt;p&gt;This module is super handy for debugging your ColdBox routes. Here's what I see when I browse the &lt;code&gt;/route-visualizer&lt;/code&gt; page to debug my routes in cfShorty:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GglvuCw0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ytbye9gtkpkae9zx0ikl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GglvuCw0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ytbye9gtkpkae9zx0ikl.png" alt="ColdBox Route Visualizer debug page shows list of ColdBox routes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install and use Route Visualizer, all it takes is these three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Run &lt;code&gt;install route-visualizer --saveDev&lt;/code&gt; from your CommandBox shell&lt;/li&gt;
&lt;li&gt; &lt;a href="https://coldbox.ortusbooks.com/getting-started/configuration#reinitializing-an-application"&gt;Reinitialize ColdBox&lt;/a&gt; by browsing:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;/?fwreinit=mypass&lt;/code&gt; if you have a reinit password set in &lt;code&gt;config/Coldbox.cfc&lt;/code&gt;, OR&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;/?fwreinit=1&lt;/code&gt; if no reinit password is configured.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; Head to &lt;code&gt;/route-visualizer&lt;/code&gt; in your ColdBox app.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One thing to note: Make sure to add the &lt;code&gt;--saveDev&lt;/code&gt; flag when you install Route Visualizer. You might notice in the live-stream recording that I neglected to do this, causing ColdBox to (by default) install this module as a production dependency in &lt;code&gt;box.json&lt;/code&gt;. &lt;strong&gt;I do not want production users viewing my ColdBox routes&lt;/strong&gt;, so I came back later and moved the dependency to &lt;code&gt;devDependencies&lt;/code&gt; in my &lt;code&gt;box.json&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  HTTP Method Spoofing
&lt;/h2&gt;

&lt;p&gt;This is a small tip, but still super useful for my project. Since my cfShorty is a rough draft/prototype, I am not using any frontend JS like Vue. And since I am not using frontend JS, I have no way to edit a route via &lt;code&gt;PUT /resource/:id&lt;/code&gt; because &lt;a href="https://stackoverflow.com/a/8054241"&gt;HTML forms do not support the PUT method&lt;/a&gt;. (This is something I was shocked to learn when Gavin told me. I guess I'm used to using &lt;code&gt;PUT&lt;/code&gt; inside AJAX calls, and never actually tried it in a plain &lt;code&gt;&amp;lt;form method="PUT"&amp;gt;&lt;/code&gt; before.) Likewise, I can't delete any resource entries via &lt;code&gt;DELETE /resource/:id&lt;/code&gt; because HTML forms do not support the DELETE method either. (And besides - I wanted to use a link tag!)&lt;/p&gt;

&lt;p&gt;ColdBox (and Gavin) to the rescue, once again. ColdBox supports &lt;a href="https://coldbox.ortusbooks.com/the-basics/routing/http-method-spoofing"&gt;spoofing the HTTP method&lt;/a&gt;. All you need to do is add a &lt;code&gt;_method&lt;/code&gt; url or form parameter which passes your desired HTTP method as the value, like &lt;code&gt;_method=delete&lt;/code&gt; or &lt;code&gt;_method=PUT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With HTTP method spoofing, hitting the ColdBox &lt;code&gt;PUT /resource/:id&lt;/code&gt; route is as simple as this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;form action="#event.buildLink( 'resource.#prc.id#')#" method="POST"&amp;gt;
  &amp;lt;input type="hidden" name="_method" value="PUT" /&amp;gt;
  &amp;lt;!--- my form goes here ---&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since HTML forms only support &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt;, I opted to send the form data via &lt;code&gt;POST&lt;/code&gt; to hide the data in the request payload (as opposed to in the URL, which is kinda ugly). Then adding a hidden input to my form which passed &lt;code&gt;_method=PUT&lt;/code&gt; causes ColdBox to execute my &lt;code&gt;PUT&lt;/code&gt; route, and as easy as that I'm done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I learned some cool ColdBox tips this session. If you missed the live-stream, you can catch up with &lt;a href="https://www.youtube.com/watch?v=71uxK3mRYhg"&gt;the recording on YouTube&lt;/a&gt; or simply ask me on Twitter. :)&lt;/p&gt;

</description>
      <category>coldfusion</category>
      <category>cfml</category>
      <category>coldbox</category>
    </item>
    <item>
      <title>Adobe, You Piece of Work, I'm Through</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Mon, 23 Sep 2019 12:51:08 +0000</pubDate>
      <link>https://dev.to/mikeborn/adobe-you-piece-of-work-i-m-through-52b1</link>
      <guid>https://dev.to/mikeborn/adobe-you-piece-of-work-i-m-through-52b1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;When in the course of human events it becomes necessary for one [developer] to dissolve the bands which have connected them with [Adobe].&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lest that title and opening surprise or scare you, let me put it simply: I am fed up with Adobe's handling of Adobe ColdFusion. The product stinks (compared to Lucee), the support and marketing stinks, and this recent "bait and switch" pricing tactic is the last straw.&lt;/p&gt;

&lt;p&gt;Consider this camel's back broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terrible Language Support
&lt;/h2&gt;

&lt;p&gt;The first annoyance about Adobe ColdFusion is the poor (excuse me, &lt;strong&gt;terrible&lt;/strong&gt;) language support. ACF has been largely outpaced by Lucee in ease of development. Lucee supports datasource structs, lambda expressions, a cleaner and more useful debugger, tag or function defaults, and on and on. Lucee is now the one who defines and expands the boundaries of the language, while Adobe merely plays catchup - or not.&lt;/p&gt;

&lt;p&gt;But even if Adobe never improved the language features (and that's not off by much), the product would hold up for a long time with just a little well-managed support. Unfortunately, ACF has had nothing but the worst sort of language support for a long time now. Ask any ACF developer and they'll inform you that Adobe has a long history of ignoring bugs, declining feature requests, or mismanaging tickets in every way possible. Here is just a short sampling I found in the Adobe bugbase:&lt;/p&gt;

&lt;h3&gt;
  
  
  fixing tickets without documenting new behavior
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;The functionality is fixed, but the docs have not been updated. This needs to be an integral part of any work done to the language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://tracker.adobe.com/#/view/CF-3941602"&gt;ticket CF-3941602&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  silently fixing tickets with no further description or notice
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I notice this is marked as fixed now. When can we expect to see this fix?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://tracker.adobe.com/#/view/CF-3865461"&gt;ticket CF-3865461&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I notice this is marked as fixed?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://tracker.adobe.com/#/view/CF-3941602"&gt;ticket CF-3941602&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  refusing to release hotfixes for obvious, blatant regressions
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;What is the point of adding an automated update system - with so much fanfare - if you're not going to release bug fixes throughout the year via that channel?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From &lt;a href="https://tracker.adobe.com/#/view/CF-3910529"&gt;ticket CF-3910529&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  refusing to backport bugs to "supported" versions of ColdFusion
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Why is ColdFusion 11 even supported? Why not just mark it as End of Life and kill if off if you are refusing to fix bugs? It seems Adobe has a different definition of "Support" than the rest of the world.&lt;/p&gt;

&lt;p&gt;This is why developers are getting fed up with the product.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From &lt;a href="https://tracker.adobe.com/#/view/CF-3952818"&gt;ticket CF-3952818&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Poor Marketing and Customer Outreach
&lt;/h2&gt;

&lt;p&gt;The second major concern with Adobe ColdFusion is the shoddy marketing job Adobe has done with their own product. It's as if Adobe cares more about milking the money from their existing customers than they are about acquiring new ones.&lt;/p&gt;

&lt;p&gt;First, Adobe failed to list the Adobe ColdFusion product in the main menu of the site. This is a small thing (yet so easy to fix), but the many requests on this subject have &lt;strong&gt;never&lt;/strong&gt; been addressed by any Adobe employee that I know of.&lt;/p&gt;

&lt;p&gt;Second, take a look at the new &lt;a href="https://community.adobe.com/"&gt;Adobe Support Community forum&lt;/a&gt;. Where is ColdFusion listed? Under the "Print &amp;amp; Publishing" category, of course! WHAT?! This is a clear indication that Adobe does not understand their own product.&lt;/p&gt;

&lt;p&gt;Third, any public outcry concerning these items or any others is ignored. I've never seen an official response from Adobe on pretty much anything. &lt;/p&gt;

&lt;p&gt;Check out this little nugget from a &lt;a href="https://coldfusion.adobe.com/2016/02/coldfusion-marketing/"&gt;ColdFusion Marketing blog post&lt;/a&gt; by Adobe:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Customer Outreach – We have been having 1:1 discussion with some of our large customers to let them know about what are the features in the new version of ColdFusion and working with them in case they have any issues.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aha! This all makes sense now - "large customers" are heard, large customers are informed of upcoming ACF features, and large customers get bug fixes or support. Gee - now what on earth am I &lt;a href="https://www.adobe.com/products/coldfusion-standard.html"&gt;paying &lt;strong&gt;twenty-five hundred dollars&lt;/strong&gt; for&lt;/a&gt; if not the privilege of Adobe support on Adobe products? This is a slap in the face to every non-large customer who has ever purchased Adobe ColdFusion.&lt;/p&gt;

&lt;p&gt;Adobe says they listen to feedback, but their actions seem clear: &lt;em&gt;You (ColdFusion folks) are not the favorite child, and only favorite children deserve attention&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You too, Adobe. You too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Last Straw: Alligator Pricing Tactics
&lt;/h2&gt;

&lt;p&gt;It would seem that Adobe is pursuing a place in the dictionary, right under "&lt;a href="https://www.google.com/search?q=adobe+bait+switch+coldfusion"&gt;Bait and Switch&lt;/a&gt;". Check this out:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We were sent a questionnaire earlier this year under the guise of getting a "better deal" for our existing 3 perpetual Enterprise licenses.  As a result of what was clearly a bait and switch tactic, Adobe is now claiming we are in violation of the EULA and requiring us to sign a custom agreement that is increasing our costs nearly 10-fold. If we don’t sign it, they are threatening to sue us for years of back-license fees.  Our solution does not provide coding access or delivery of ColdFusion itself. And it is not ColdFusion server dependent.  (It runs in open source environment like Lucee).  They say that ANY company using CF in any B2B capacity is a service bureau and subject to a custom agreement with annual auditing/repricing, using some arbitrary and unknown formula for determining the cost.  Clearly they are trying to convert their perpetual licensed customers to a special license where they’ll ultimately demand a portion of their revenues.  They are also bypassing their resellers by doing this.  If you have dealt with this I’d like to find out what your resolution was.  If you have not – just wait – they are coming for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can &lt;a href="https://forums.adobe.com/thread/2648828"&gt;read the full thread on the Adobe Forum&lt;/a&gt;, but this is &lt;a href="https://community.adobe.com/t5/ColdFusion/ColdFusion-license-doesn-t-allow-for-SaaS-solution/td-p/10133205#11230719"&gt;not&lt;/a&gt; the &lt;a href="https://community.adobe.com/t5/ColdFusion/What-the-heck-is-Adobe-thinking/td-p/8163818"&gt;first&lt;/a&gt; complaint. Adobe has always charged ridiculously high licensing fees &lt;em&gt;because they can&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;What's more, Adobe won't lower their prices. Ever. When the last CF customer is gone, they will simply fire their ACF employees (you know, &lt;em&gt;all three&lt;/em&gt; of them) and focus their awful tactics on wrecking another customer-loved product, like Photoshop. Why? Because there is not a single person in Adobe management who loves ColdFusion. Not a single one who cares. Remember, Adobe did not &lt;em&gt;create&lt;/em&gt; ColdFusion - they &lt;strong&gt;purchased&lt;/strong&gt; it.&lt;/p&gt;

&lt;p&gt;Ultimately, this is the reason for ACF's demise and my denouncement in this very blog post. No matter what Adobe did to ColdFusion, if they actually attempted to improve the product, or listen to developers, or design a sane pricing model, or show that they care in any way at all I would still be a fan.&lt;/p&gt;

&lt;p&gt;But here I am, because Adobe couldn't care less what their own product is or does. Adobe ColdFusion is dying because Adobe. Period.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Response
&lt;/h2&gt;

&lt;p&gt;I'm not just here to rain on the parade! (Sorry for the negativity, though.) I have an Answer - a Cause - and I'm not abandoning CFML. I'm just preferring the open-source, light-weight, so-much-better, listens-to-devs implementation called &lt;a href="https://lucee.org/"&gt;Lucee&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's what that means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I will assume that &lt;strong&gt;if&lt;/strong&gt; there is an official stance of Adobe on any topic, it is directly contrary to the wishes and needs of the ColdFusion community.&lt;/li&gt;
&lt;li&gt;I refuse to support any version of Adobe in my open source products.&lt;/li&gt;
&lt;li&gt;I refuse to document ACF "gotchas" when blogging or tweeting about CFML features.&lt;/li&gt;
&lt;li&gt;I will avoid the term "ColdFusion" in favor of prefer "CFML" going forward.&lt;/li&gt;
&lt;li&gt;I will take great pleasure in promoting Lucee as a lighter, more secure, and more performant ACF alternative.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PS. The above list only applies to my freelance/open-source work!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I'm not just annoyed. I'm done. I'm not gonna throw hate at Adobe or any Adobe employee - that's both a waste of time and just not nice, but what I &lt;strong&gt;will&lt;/strong&gt; do is prefer Lucee over all things ACF.&lt;/p&gt;

</description>
      <category>coldfusion</category>
      <category>cfml</category>
      <category>lucee</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Getting Started In CFML: A Resource List for Newbies</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Wed, 11 Sep 2019 12:57:18 +0000</pubDate>
      <link>https://dev.to/mikeborn/getting-started-in-cfml-a-resource-list-for-newbies-1mkh</link>
      <guid>https://dev.to/mikeborn/getting-started-in-cfml-a-resource-list-for-newbies-1mkh</guid>
      <description>&lt;p&gt;If you are going to learn CFML in 2019, you need the best resources available. In this post I'll share tutorials, video channels, and even podcasts you can use to help you begin learning CFML.&lt;/p&gt;

&lt;p&gt;I will do my best to keep this list up to date - feel free to comment or message me with links or updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tutorials
&lt;/h2&gt;

&lt;p&gt;These tutorials are (currently) the best way to get started with CFML. You can learn all about the syntax, see plenty of examples, and be off and running quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn Modern CFML In 100 Minutes
&lt;/h3&gt;

&lt;p&gt;This is a fantastic resource for new CFML devs, and covers the gamut from CF's underlying architecture (Java, compilation vs. interpretation, etc.) to the basic &lt;a href="https://modern-cfml.ortusbooks.com/cfml-language/syntax"&gt;syntax    &lt;/a&gt;, &lt;a href="https://modern-cfml.ortusbooks.com/cfml-language/arrays"&gt;data&lt;/a&gt; &lt;a href="https://modern-cfml.ortusbooks.com/cfml-language/structures"&gt;structures&lt;/a&gt;, and &lt;a href="https://modern-cfml.ortusbooks.com/cfml-language/null-and-nothingness"&gt;concepts&lt;/a&gt; of the language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://modern-cfml.ortusbooks.com"&gt;https://modern-cfml.ortusbooks.com&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  LearnCFInAWeek
&lt;/h3&gt;

&lt;p&gt;I did my share of reading on this website when I was first learning CFML, and I still use it for some topics now and then. While these tutorials are a little aged, they are helpful in that they focus on specific topics such as &lt;a href="http://www.learncfinaweek.com/week1/Cross_Site_Scripting__XSS_/"&gt;XSS protection&lt;/a&gt;, &lt;a href="http://www.learncfinaweek.com/week1/Caching/"&gt;Caching&lt;/a&gt; and &lt;a href="http://www.learncfinaweek.com/week1/OOP/"&gt;OOP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.learncfinaweek.com"&gt;http://www.learncfinaweek.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Language References
&lt;/h2&gt;

&lt;p&gt;When you're learning a language, it is vital that you be able to learn about the exact function you're using - is it &lt;code&gt;arrayFind()&lt;/code&gt; or &lt;code&gt;arraySearch()&lt;/code&gt;? These reference sites help you know which functions do what and exactly what the syntax is, and even provide some examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  CFDocs.org
&lt;/h3&gt;

&lt;p&gt;This is hands down the best reference website out there for CFML syntax and functionality. Every tag or function is documented with notes on engine support, deprecation notices and even some examples. These docs are entirely open-source and community supported, so if something is missing you can send in a pull request or shoot me an email and I'll update it myself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cfdocs.org"&gt;https://cfdocs.org&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Lucee Reference Docs
&lt;/h3&gt;

&lt;p&gt;The Lucee docs focus on syntax for Lucee's CFML implementation and tends to be more accurate and up-to-date than CFDocs. (After all, it is maintained by the Lucee Foundation as well as open source contributions.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.lucee.org/reference/functions.html"&gt;https://docs.lucee.org/reference/functions.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Communities
&lt;/h2&gt;

&lt;p&gt;The CF community is awesome and always willing to help a newbie out. Check out these resources to get started learning from the community.&lt;/p&gt;

&lt;h3&gt;
  
  
  CFML Slack
&lt;/h3&gt;

&lt;p&gt;This Slack group is the epicenter of the nicest, handiest, most helpful programming community I know of. When I can no longer bang my head against the wall, I come to this Slack chat to get help from devs whom constantly answer questions from noobs like me!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To sign up: &lt;a href="http://cfml-slack.herokuapp.com"&gt;http://cfml-slack.herokuapp.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;To log in: &lt;a href="https://cfml.slack.com"&gt;https://cfml.slack.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lucee Forum
&lt;/h3&gt;

&lt;p&gt;The Lucee Forum is a great place for Lucee-specific discussions, whether that be concerning the language, the roadmap, documentation or other general issues. I've been browsing this forum a lot lately and joined fairly recently because I like to stay up on the Lucee news.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.lucee.org"&gt;https://dev.lucee.org&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Podcasts
&lt;/h2&gt;

&lt;p&gt;Sometimes you don't know what you don't know. Listening to a good podcast will bring you in contact with other ideas, tools and programming techniques that &lt;em&gt;you didn't know you didn't know&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modernize Or Die Podcast
&lt;/h3&gt;

&lt;p&gt;Ortus is tackling the CFML podcast space with their Modernize Or Die podcasts, and they're doing an awesome job of it. For news and tips, check out the &lt;a href="https://cfmlnews.modernizeordie.io"&gt;CFML News edition&lt;/a&gt;. The VS Code tips are especially useful for beginners. The &lt;a href="https://soapbox.modernizeordie.io"&gt;Soapbox edition&lt;/a&gt; is great for wider discussion-type stuff, and may help you keep your overall goals and focus tuned for success.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cfmlnews.modernizeordie.io"&gt;https://cfmlnews.modernizeordie.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://soapbox.modernizeordie.io"&gt;https://soapbox.modernizeordie.io&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Video Channels
&lt;/h2&gt;

&lt;p&gt;Sometimes it's just easier to learn from video. These tutorials should help you get started with CFML in 2019.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started with Adobe ColdFusion (2016 Release)
&lt;/h3&gt;

&lt;p&gt;This is a great selection of video tutorials showing how to program in CFML. This tutorial focuses on programmers with very little experience, so you may find the pace a little slow in the earlier videos. Still, it is fairly comprehensive and does a good job of explaining concepts and tag syntax.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=9viMI8f4myM&amp;amp;list=PL3iywAijqFoUD31CQBLsHvJn4WAonNA7r&amp;amp;index=1"&gt;https://www.youtube.com/watch?v=9viMI8f4myM&amp;amp;list=PL3iywAijqFoUD31CQBLsHvJn4WAonNA7r&amp;amp;index=1&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adobe Coldfusion 11 Tutorials
&lt;/h3&gt;

&lt;p&gt;This playlist tutorial may be useful to you, but based on its age (created in 2014), its focus on tag syntax, and its left-ear-only audio, you'll probably have more luck elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=xelAelbSJqs&amp;amp;list=PLPZ2BdpyPMq7zRHFbNwwt4l5oOj54GYan&amp;amp;index=3"&gt;https://www.youtube.com/watch?v=xelAelbSJqs&amp;amp;list=PLPZ2BdpyPMq7zRHFbNwwt4l5oOj54GYan&amp;amp;index=3&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  My Twitch Channel
&lt;/h3&gt;

&lt;p&gt;Yep, this is a shameless plug for my live streaming channel. I live code every Friday evening, and I may work on anything from writing a CFML URL shortener to building a ContentBox blog. This would be a great place to see how I write CFML and ask me why I do X instead of Y.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twitch.tv/michaelborn_me"&gt;https://www.twitch.tv/michaelborn_me&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;CFML is a very easy language to learn in terms of syntax, but there are differences in how the language is structured and configured that take time to sink in. Hopefully this big list helps you get started&lt;/p&gt;

</description>
      <category>cfml</category>
      <category>coldfusion</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Localizing Dates In Sql Server</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Tue, 20 Aug 2019 03:13:11 +0000</pubDate>
      <link>https://dev.to/mikeborn/localizing-dates-using-ms-sql-server-1cje</link>
      <guid>https://dev.to/mikeborn/localizing-dates-using-ms-sql-server-1cje</guid>
      <description>&lt;p&gt;Several months ago I added timezone handling to a CF app. This post is my best effort to document how to localize dates using MSSQL timezone functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving Timezones from MSSQL
&lt;/h2&gt;

&lt;p&gt;First, we need to know what time zones we can use. &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-time-zone-info-transact-sql?view=sql-server-2017"&gt;MSSQL uses the Windows timezones as stored in the registry&lt;/a&gt;, and they can be retrieved from the &lt;code&gt;sys.time_zone_info&lt;/code&gt; system view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time_zone_info&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Do not try to interact with these time zones using a CFML timezone - the underlying Java timezones use a different timezone format and do not match the MSSQL/Windows timezone format.&lt;/p&gt;

&lt;p&gt;Also, you may notice that the timezone list &lt;em&gt;does not include different timezones for daylight saving time&lt;/em&gt;. For example, there is a single timezone record for &lt;code&gt;Eastern Standard Time&lt;/code&gt;, or EST. &lt;code&gt;Eastern Daylight Time&lt;/code&gt; is nowhere to be found, because this view automatically updates the &lt;code&gt;current_utc_offset&lt;/code&gt; and &lt;code&gt;is_currently_dst&lt;/code&gt; values based on the current time in that timezone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieve Current UTC Offset From a Known Timezone
&lt;/h2&gt;

&lt;p&gt;Next we use these time zones to get the &lt;strong&gt;current&lt;/strong&gt; utc offset. Note I said &lt;strong&gt;current&lt;/strong&gt; - do &lt;strong&gt;not&lt;/strong&gt; store the UTC offset, because it will change for a given time zone twice a year at minimum. (e.g. daylight saving time.)&lt;/p&gt;

&lt;p&gt;For this reason, we'll need to store the user's time zone and retrieve the UTC offset when you need the user's local time.&lt;/p&gt;

&lt;p&gt;Here's a simple way to retrieve the current UTC offset for a known time zone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;current_utc_offset&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time_zone_info&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'US Eastern Standard Time'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Obviously, in order to know which time zone to use you will need to allow the user to select their time zone so you can store that timezone with the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Localize Dates To a Timezone Using AT TIME ZONE
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dzone.com/articles/dates-and-times-in-sql-server-at-time-zone"&gt;Use &lt;code&gt;AT TIME ZONE&lt;/code&gt;&lt;/a&gt; if you need to indicate the UTC offset of a datetime value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'US Eastern Standard Time'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Basically, this lets us select a date which was stored with no UTC offset and add a UTC offset to it - provided we know the original time zone. This paves the way for us to then convert the date from its original timezone - using &lt;code&gt;AT TIME ZONE&lt;/code&gt; - to another timezone - using &lt;a href="https://database.guide/switchoffset-examples-in-sql-server/"&gt;the &lt;code&gt;SWITCHOFFSET&lt;/code&gt; function&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  SWITCHOFFSET
&lt;/h2&gt;

&lt;p&gt;Once we have a &lt;code&gt;DATETIMEOFFSET&lt;/code&gt; value, we can use &lt;code&gt;SWITCHOFFSET(DATETIMEOFFSET, time_zone)&lt;/code&gt; to switch that datetime to match a user's local time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;SWITCHOFFSET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'US Eastern Standard Time'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;current_utc_offset&lt;/span&gt;
        &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time_zone_info&lt;/span&gt;
        &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Central European Standard Time'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Unfortunately, this is not a full timezone localization writeup. Localization is very complex, and &lt;a href="//julianstodd.wordpress.com/2011/12/21/the-more-i-learn-the-less-i-know-learning-about-ignorance/"&gt;the more I learn the less I know&lt;/a&gt;. But hopefully this brief overview of timezone handling using built-in MSSQL functionality will come in useful for &lt;em&gt;someone&lt;/em&gt; - enjoy!&lt;/p&gt;

</description>
      <category>sql</category>
      <category>localization</category>
    </item>
    <item>
      <title>Form Processing in CFScript Part Three: Sending Email Notifications</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Wed, 14 Aug 2019 12:48:27 +0000</pubDate>
      <link>https://dev.to/mikeborn/form-processing-in-cfscript-sending-form-notifications-via-email-lil</link>
      <guid>https://dev.to/mikeborn/form-processing-in-cfscript-sending-form-notifications-via-email-lil</guid>
      <description>&lt;p&gt;In this series so far, we've looked at how to validate a form entry and how to save that form entry to the database. Today we'll see how we can notify a person (usually a site admin or editor) that a new form entry has been submitted and processed by simply sending an email.&lt;/p&gt;

&lt;p&gt;Email works well for form notifications because the entire entry will usually fit in a single email, and replying to an email can send a message to the original user who filled out the form. Contrast that with SMS messages, which are limited in content length and do not support rich formatting or reply-to functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Emails via Configured SMTP Server
&lt;/h2&gt;

&lt;p&gt;If your web server also has an SMTP server installed (Postfix, anyone?) and configured in your ColdFusion or Lucee administrator, sending the email is as easy as specifying the to address, from address, and subject.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cfmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noreply@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission from #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// email contents go here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Sending Emails via Mailgun SMTP
&lt;/h2&gt;

&lt;p&gt;If you don't have an SMTP server installed or configured, you can use the &lt;code&gt;server&lt;/code&gt;, &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; arguments to send via the Mailgun SMTP server, for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cfmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noreply@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission from #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SMTP_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SMTP_PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SMTP_USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SMTP_PASSWORD&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// email contents go here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here I'm using &lt;a href="https://blog.simplicityweb.co.uk/109/lucee-5-simpler-access-to-environment-variables"&gt;environment variables stored in Lucee's &lt;code&gt;server.system.environment&lt;/code&gt; struct&lt;/a&gt; to send via Mailgun's SMTP server. These environment variables could be set in the &lt;code&gt;/env/environment&lt;/code&gt; file or your bash profile to look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SMTP_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;smtp.mailgun.org
&lt;span class="nv"&gt;SMTP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;587
&lt;span class="nv"&gt;SMTP_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postmaster@mail.mysite.com
&lt;span class="nv"&gt;SMTP_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123A923BCB6BGA7B&lt;span class="k"&gt;*&lt;/span&gt;3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The exact functionality depends on your system, but generally these variables will be loaded into your environment on system startup or on profile startup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting the Email Reply To
&lt;/h2&gt;

&lt;p&gt;Setting the &lt;code&gt;replyto&lt;/code&gt; email address will let us reply to the user who filled out the form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cfmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;replyto&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#form.email#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noreply@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission from #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// email contents go here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is awesome because it allows admins to quickly respond to the original user. You simply can't do this when delivering via other mediums like SMS or Slack.&lt;/p&gt;

&lt;h2&gt;
  
  
  CFMail Body Output
&lt;/h2&gt;

&lt;p&gt;Here's where we output (or &lt;em&gt;render&lt;/em&gt;) the form submission in the body of the email. This is pretty simple - we use the &lt;code&gt;writeOutput()&lt;/code&gt; function to output HTML and the form values right in the email body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cfmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;replyto&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#form.email#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noreply@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission from #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission by #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#form.message#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that the MIME type of the email will be &lt;code&gt;text/plain&lt;/code&gt; by default. For rendering HTML in our email we'll need to set the mime type via &lt;code&gt;type="text/html"&lt;/code&gt; or even just &lt;code&gt;type="html"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cfmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;replyto&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#form.email#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noreply@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission from #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission by #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#form.message#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Avoiding XSS in Emails
&lt;/h2&gt;

&lt;p&gt;Please don't output user-submitted data (form variables) without encoding them! The last thing you want to do is send a spammer's script tag (think &lt;code&gt;&amp;lt;script src="http://badwebsite.com/js/payload.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; tag) to your client's email address. That's what you call &lt;a href="https://www.acunetix.com/websitesecurity/cross-site-scripting/"&gt;Cross-Site-Scripting&lt;/a&gt;, and in CFML it's easy to avoid - just wrap every &lt;code&gt;#form.field#&lt;/code&gt; with &lt;code&gt;encodeForHTML()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cfmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;replyto&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#form.email#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noreply@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission from #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission by #encodeForHTML( form.name )#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#encodeForHTML( form.message )#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are a bunch of &lt;code&gt;encodeFor*()&lt;/code&gt; functions designed for certain contexts, such as &lt;a href="https://cfdocs.org/encodeforurl"&gt;&lt;code&gt;encodeForURL()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://cfdocs.org/encodeforhtmlattribute"&gt;&lt;code&gt;encodeForHTMLAttribute()&lt;/code&gt;&lt;/a&gt;. I can't demo all those, but I can write a more detailed XSS blog post if you'd like me to!&lt;/p&gt;

&lt;p&gt;Note that our email templates are looking larger and more complex. Real-world code can be large, complex and messy, so let's clean it up by &lt;strong&gt;not using CFScript&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Best Dang Template Syntax
&lt;/h2&gt;

&lt;p&gt;Outputting HTML from a scripting language is - &lt;em&gt;lets be honest&lt;/em&gt; - &lt;strong&gt;awkward&lt;/strong&gt;. It's awkward in Javascript (though much improved lately with template literals), it's awkward in PHP and it's certainly awkward in CFScript. Template engines like Twig, Jade, and Mustache solve this for other languages, but in ColdFusion we have the &lt;strong&gt;best dang template syntax in the world&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So why not use it? &lt;/p&gt;

&lt;p&gt;CFML lets us switch between script syntax and tag syntax as necessary - no libraries, no extra compiling and no need to learn a funky template syntax.&lt;/p&gt;

&lt;p&gt;I recommend creating a &lt;code&gt;views/emails/&lt;/code&gt; directory for email templates. Then each new email can be a separate file named after the contact form, like &lt;code&gt;views/emails/donate-thankyou.cfm&lt;/code&gt; or &lt;code&gt;views/forms/forgotpassword.cfm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's a quick example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cfmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noreply@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission from #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/views/forms/contact/email.cfm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this setup, our email-sending code looks much cleaner and the email template looks much better as well.&lt;/p&gt;

&lt;p&gt;We can even create a standardized email header and footer in &lt;code&gt;_head.cfm&lt;/code&gt; and &lt;code&gt;_foot.cfm&lt;/code&gt; and include those from the main email template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;cfinclude&lt;/span&gt; &lt;span class="na"&gt;template=&lt;/span&gt;&lt;span class="s"&gt;"./_head.cfm"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!---

        EMAIL BODY GOES HERE

---&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cfinclude&lt;/span&gt; &lt;span class="na"&gt;template=&lt;/span&gt;&lt;span class="s"&gt;"./_foot_.cfm"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Formatting Form Entries In An Email
&lt;/h2&gt;

&lt;p&gt;For a quick get-er-done notification email, you can loop over &lt;code&gt;form.fieldnames&lt;/code&gt; to dynamically output each form field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cfloop&lt;/span&gt; &lt;span class="na"&gt;list=&lt;/span&gt;&lt;span class="s"&gt;"#form.fieldnames#"&lt;/span&gt; &lt;span class="na"&gt;index=&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;#encodeForHTML( field )#:&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
    #encodeForHTML( form[ field ] )#&lt;span class="nt"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/cfloop&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you want high quality email templates, you might want something more like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;New form submission by #encodeForHTML( form.email )#&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Message: #encodeForHTML( form.message )#&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    Name: #encodeForHTML( form.name )#&lt;span class="nt"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    Email: #encodeForHTML( form.email )#
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Email Attachments
&lt;/h2&gt;

&lt;p&gt;Let's say we have a job application form with a place to upload a resume file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;enctype=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"processApplication.cfm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"resumeFile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Please add your resume in PDF format&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"resumeFile"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"resume"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!--- more form here ---&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Files sent via a POST request are stored in the server's temp directory. To attach the file to the email, we first need to save the file to a semi-permanent location so it doesn't get cleaned up (i.e. deleted) before the spooled email is sent out. The &lt;a href="https://cfdocs.org/fileupload"&gt;&lt;code&gt;fileUpload()&lt;/code&gt;&lt;/a&gt; function works well for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;uploadedFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileUpload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/files/resume/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resume&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;makeunique&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once we have the file saved we can attach the file to our email by using &lt;a href="https://cfdocs.org/cfmailparam"&gt;&lt;code&gt;cfmailparam()&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cfmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noreply@mysite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New form submission from #form.name#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Email body here&lt;/span&gt;
    &lt;span class="nx"&gt;cfmailparam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#uploadedFile.serverfile#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Emails are fantastic for form notifications. CFML is fantastic for emails. This guide ended up much longer than I expected - hopefully you enjoyed it and can use it as a handy reference for your first CF app!&lt;/p&gt;

</description>
      <category>coldfusion</category>
      <category>lucee</category>
      <category>cfml</category>
    </item>
    <item>
      <title>Form Processing in CFScript Part Two: Saving Form Entries to the Database</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Thu, 01 Aug 2019 13:02:30 +0000</pubDate>
      <link>https://dev.to/mikeborn/form-processing-in-cfscript-part-two-saving-form-entries-to-the-database-4ko1</link>
      <guid>https://dev.to/mikeborn/form-processing-in-cfscript-part-two-saving-form-entries-to-the-database-4ko1</guid>
      <description>&lt;p&gt;If a tree falls in a woods with no one to hear, did it actually fall? Likewise, if a user submits a form but it is not persisted in some form, that form submission is &lt;strong&gt;worthless&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Saving Form Submissions to the Database

&lt;ul&gt;
&lt;li&gt;Method One: Storing the Form With a Hard-Coded Table Design&lt;/li&gt;
&lt;li&gt;Method Two: Storing a Form as a JSON Packet&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Today we'll go over a very important, perhaps the &lt;strong&gt;most&lt;/strong&gt; important step in form processing: saving the submitted form to a database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Saving Form Submissions to the Database &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When processing form submissions, the first and most important step is to &lt;strong&gt;persist&lt;/strong&gt; the data - to make sure that form data is saved and available for future reference. This post will show you how to store form data in a SQL database using two main approaches. Neither approach is difficult, but I found each useful in their own way and worthy of different use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method One: Storing the Form With a Hard-Coded Table Design &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Here's the simple method - simply save each form submission to a new row with a separate column for each form field.&lt;/p&gt;

&lt;p&gt;After you build the HTML form, create a database table with an appropriate column for each form field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;contactForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dateSubmitted&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then in your form handler, it's as easy as using &lt;code&gt;queryExecute()&lt;/code&gt; to insert the row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;
    INSERT INTO contactForm(id, name, email, message, dateSubmitted)
    VALUES(:id, :name, :email, :message, :dateSubmitted)
&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;createUUID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;cfsqltype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;queryExecute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I'm personally a fan of declaring &lt;code&gt;sql&lt;/code&gt; and &lt;code&gt;params&lt;/code&gt; variables like this, but if you're an inline-only kind of guy you could write it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;queryExecute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;
    INSERT INTO contactForm(id, name, email, message, dateSubmitted)
    VALUES(:id, :name, :email, :message, :dateSubmitted)
&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;createUUID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;cfsqltype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The cool thing about this approach is that Fixinator will now catch your SQLi vulnerabilities&lt;/p&gt;

&lt;p&gt;This approach is simple and works well enough. The benefit to building a table schema to match the form is that storing and retrieving the data is simple and powerful thanks to good database integration. Basically, having our table design match the form design gives us powerful search, sort and query capabilities with no extra work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method Two: Storing a Form as a JSON Packet &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;For larger forms, creating that table schema can be a pain. If that large form changes frequently, we're talking a &lt;strong&gt;real&lt;/strong&gt; pain. I can't tell you how many table schemas I've created to match a contact or donation form, just to alter those tables when the form inevitably changes.&lt;/p&gt;

&lt;p&gt;So for larger, more complex forms, I recommend storing the form submission as a JSON string. It's still useful to have the main fields (name and email) in dedicated table columns for sorting and searching, but JSON will be more than adequate for most other fields. Saving as JSON means that we don't need to create a custom field for every form input, and we can store form submissions &lt;em&gt;generically&lt;/em&gt; - less setup and less maintenance.&lt;/p&gt;

&lt;p&gt;The storage table is much simpler to create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;formSubmissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dateSubmitted&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And inserting the form data as JSON is as simple as using &lt;code&gt;serializeJSON(form)&lt;/code&gt;. When reading the form submission out of the table, we can use &lt;code&gt;deserializeJSON()&lt;/code&gt; to decode the JSON string back to a CF struct. On Lucee, you may need to &lt;a href="https://www.bennadel.com/blog/3667-understanding-struct-key-casing-using-serializejson-in-lucee-5-3-2-77.htm"&gt;enable "Preserve key case" in the Lucee admin&lt;/a&gt;. Note that Adobe &lt;a href="https://coldfusion.adobe.com/2014/04/language-enhancements-in-coldfusion-splendor-improved-json-serialization/"&gt;ColdFusion 11 and up maintains key casing by default&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;
    INSERT INTO formSubmissions(id, form, dateSubmitted)
    VALUES(:id, :form, :dateSubmitted)
&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;createUUID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;form&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;serializeJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;cfsqltype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;queryExecute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One significant downside of this approach is that sorting and searching natively in the database becomes harder - perhaps significantly harder, depending on your database software. If you're using MySQL 5.7.8 or newer, though, the &lt;code&gt;JSON&lt;/code&gt; data type makes sorting or filtering fairly easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JSON_EXTRACT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'$.name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JSON_EXTRACT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'$.email'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;formSubmissions&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;ASC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I must note that this method is not perfect. Storing data as a big old JSON string does not exactly conform to &lt;a href="https://en.wikipedia.org/wiki/First_normal_form"&gt;first normal form&lt;/a&gt;, and attempting to sort or search by an extracted JSON field will likely come with a non-negligable performance hit. Regardless, I find this method handy due to the minimal maintenance. It's generally easier to edit an HTML form than the SQL table structure, and this approach means that a change in the first does not require a change in the second.&lt;/p&gt;

&lt;p&gt;For more info, check out &lt;em&gt;&lt;a href="https://www.sitepoint.com/use-json-data-fields-mysql-databases/"&gt;How to Use JSON Data Fields in MySQL Databases&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Persistence is not hard. This blog post was meant to highlight an easier approach to storing form entries; if you put a little thought into your form processing you can save a lot of maintenance time through the life of the form.&lt;/p&gt;

</description>
      <category>coldfusion</category>
      <category>cfml</category>
      <category>cfscript</category>
      <category>mysql</category>
    </item>
    <item>
      <title>Form Processing in CFScript Part One: Form Validation</title>
      <dc:creator>Michael Born</dc:creator>
      <pubDate>Tue, 23 Jul 2019 13:21:38 +0000</pubDate>
      <link>https://dev.to/mikeborn/form-processing-in-cfscript-part-one-form-validation-5d33</link>
      <guid>https://dev.to/mikeborn/form-processing-in-cfscript-part-one-form-validation-5d33</guid>
      <description>&lt;p&gt;This series will teach you how to process form submissions using ColdFusion's CFScript syntax. In Part One I'll show you the basics of validating form submissions on the backend!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This article (and entire series) assumes you are not using a frontend framework like Vue or ReactJS to generate and validate the form. If you are, great, but &lt;strong&gt;do not&lt;/strong&gt; rely on client-side validation as it is too easily bypassed. See section on backend vs. frontend validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Intro to Form Validation&lt;/li&gt;
&lt;li&gt;Form Validation: Backend Vs. Frontend&lt;/li&gt;
&lt;li&gt;Validating Field Length (Required Fields)&lt;/li&gt;
&lt;li&gt;
Validating Field Type

&lt;ul&gt;
&lt;li&gt;Static Type Checking&lt;/li&gt;
&lt;li&gt;Iterative Type Checking&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Dealing with Validation Errors&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intro to Form Validation &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When validating form submissions, there are two main things to keep in mind which should guide your overall validation strategy.&lt;/p&gt;

&lt;p&gt;First, the main point of form validation is 1) to helpfully notify the user when they mistype a value, and 2) to prevent backend errors. (e.g. &lt;code&gt;cfmail()&lt;/code&gt; will throw an error for some badly misformed email addresses). Besides that, validation should be used &lt;em&gt;as sparingly as possible&lt;/em&gt;. This is because it's easy to be too strict and unintentionally exclude users with different zip codes, email addresses and phone numbers than we might expect.&lt;/p&gt;

&lt;p&gt;Secondly, you can never force a user to input their personal information if they do not wish to! Requiring an &lt;code&gt;address&lt;/code&gt; field, for example, will generate a significant amount of falsified info, like "1600 Pennsylvania Ave NW".&lt;/p&gt;

&lt;p&gt;With that out of the way, let's take a look at a basic HTML form we're going to validate. Nothing fancy here, just a small contact form. Donation forms are much larger and require much stricter validation (and if you are processing payments through your server, I pray for you!)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"contact.cfm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Your Name&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Your Email&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Message&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button button-primary"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Send"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Later on, we'll tweak this form to support the particular "flow" I prefer for backend validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Form Validation: Backend Vs. Frontend &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Form validation at the frontend level is &lt;strong&gt;far&lt;/strong&gt; superior than equivalent validation at the backend level. Think of the User Experience - with frontend validation, you can get immediate feedback and avoid sending bad data in the first place. Backend validation is only necessary when the frontend is broken, disabled (Noscript mode) or purposely skirted around via some bot or hacker submitting HTTP requests to your backend.&lt;/p&gt;

&lt;p&gt;For this reason, you could probably dispense with the pleasantries and ignore the need for decent UX when validating via the backend. I say "probably" - I still like to provide a nice UX for those legitimate users browsing with javascript disabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validating Field Length (Required Fields) &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Validating a form field is not exactly nuclear science. For many fields(not all, but many), it is enough to ensure that the field value is not empty. When validating required fields, I use a variable to store a simple list of field names deemed "required", and if any of those fields are indeed empty we halt the processing and display an error to the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I use member functions throughout this blog post. Member functions can be great as long as they are relatively short and importantly, &lt;em&gt;achieve only a single purpose&lt;/em&gt;. Larger blocks of code, in my opinion, probably belong in a &lt;code&gt;for&lt;/code&gt; loop - not a member function.&lt;/p&gt;

&lt;p&gt;Here's what I'd use to validate required fields using some clever* member functions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*Cleverness is useful but dangerous; please use carefully. (And see note on member functions above.)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;requiredFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email,phone,message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;invalidFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fieldnames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;fieldname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;requiredFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fieldname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fieldname&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;p class="alert alert-danger"&amp;gt;Please fill out #fieldname#&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;invalidFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listAppend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fieldname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;invalidFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// halt processing and re-render the form.&lt;/span&gt;
    &lt;span class="nx"&gt;cfabort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Fairly straightforward CFML here - iterate through all form fields, see if it is required, and if it is not provided spit out an error and halt processing. This is rather simplistic, but perfectly workable - skip down to "Dealing with Validation Errors" for an improved way to handle error messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validating Field Type &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Validating the &lt;em&gt;type&lt;/em&gt; of data is much more difficult than validating the &lt;em&gt;presence&lt;/em&gt; of data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static Type Checking &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The simple way to do this is to use &lt;code&gt;isValid()&lt;/code&gt; to check email, phone, zip or other standard inputs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;p class="alert alert-danger"&amp;gt;Please enter a valid email&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;telephone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;phone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;p class="alert alert-danger"&amp;gt;Please enter a valid phone number&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I say the &lt;strong&gt;simple way&lt;/strong&gt; for a reason: &lt;em&gt;I personally do not recommend this option&lt;/em&gt;. Why? Because &lt;a href="https://www.raymondcamden.com/2014/07/21/ColdFusion-isValid-Email-and-new-TLDs/"&gt;IsValid is not accurate for email validation&lt;/a&gt;, and the only way to guarantee that an email address is truly valid is to send the user an email. This is common practice in signup forms, for example.&lt;/p&gt;

&lt;p&gt;I would avoid stringent validation for any localization-specific formats such as postal codes or phone numbers - there are simply too many variants. For any validation regex, there will almost certainly be issues with certain "valid" formats. That is my &lt;em&gt;opinion&lt;/em&gt; - you are free to use or reject it!&lt;/p&gt;

&lt;p&gt;For simpler values like numerics, floats or strings, &lt;code&gt;isValid()&lt;/code&gt; is fine. For example, we could validate a donation form's "amount" field to make sure it is a dollar value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;float&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;p class="alert alert-danger"&amp;gt;Please enter a valid donation amount&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Iterative Type Checking &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Now, instead of hard-coded field type checking, we could loop over an array of field names with type info:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;formFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;float&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;},{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}];&lt;/span&gt;
&lt;span class="nx"&gt;formFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;p class="alert alert-error"&amp;gt;#field.name# must be a valid #field.type#&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I prefer this approach &lt;em&gt;if&lt;/em&gt; I'm going to generate the form dynamically via CFML, because I'll probably already have metadata about each field. For most smaller/non-generated HTML forms, who really cares if my code is a little repetitive?&lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with Validation Errors &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Most of the examples shown above display a Bootstrap alert immediately and abort or exit the form processing to show the message to the user. That is more than adequate &lt;em&gt;as long as we trust our frontend validation&lt;/em&gt;. Validating on the frontend will filter out most real users from submitting invalid data in the first place.&lt;/p&gt;

&lt;p&gt;However, we can improve on this model if we have the ability to generate the HTML form. Halting the request, displaying an error, and asking the user to click the back button is inconvenient and may clear the form, causing the user to lose all progress made. For a better flow, I usually stuff an &lt;code&gt;errors&lt;/code&gt; array with error messages, then render the form with errors at the top (if the submission is invalid):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;requiredFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email,phone,message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fieldnames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;fieldname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;requiredFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fieldname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fieldname&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fieldname# is required.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// don't process the form; display it instead.&lt;/span&gt;
    &lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form.cfm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once we have that array of error messages, we can easily display a Bootstrap alert for each error at the top of &lt;code&gt;form.cfm&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;cfif&lt;/span&gt; &lt;span class="na"&gt;errors.len&lt;/span&gt;&lt;span class="err"&gt;()&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;cfloop&lt;/span&gt; &lt;span class="na"&gt;list=&lt;/span&gt;&lt;span class="s"&gt;"#error#"&lt;/span&gt; &lt;span class="na"&gt;index=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alert alert-error"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#error#&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/cfloop&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/cfif&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!--- render form ---&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And finally, make sure to tweak the form by filling each input with the submitted &lt;code&gt;form.field&lt;/code&gt; value. This allows the user to seamlessly  pick up after an invalid submission, letting them easily fill out a required field or correct an email typo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"contact.cfm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Your Name&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"#encodeForHTMLAttribute(form.name)#"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Your Email&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"#encodeForHTMLAttribute(form.email)#"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Message&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#encodeForHTMLAttribute(form.message)#&lt;span class="nt"&gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button button-primary"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Send"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;PS. Make sure to encode all user-submitted data to prevent Cross-Site Scripting (XSS)!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Form validation is not hard, just tedious. Hopefully this helps you understand the basics of validation. When in doubt, be more permissive than you need to be, but &lt;em&gt;never trust user input&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;That wraps up Part One of Form Processing in CFScript. If you liked this or hated this, please comment below. :)&lt;/p&gt;

</description>
      <category>cfml</category>
      <category>coldfusion</category>
      <category>html</category>
      <category>validation</category>
    </item>
  </channel>
</rss>
