Saving SVG to PNG on your cold fusion server

I built a client side javascript SVG to PNG converter that works on *modern* browsers, however, depending on your target audience the browsers that frequent your site may be less than modern – i.e. IE. In this situation you only have one option, convert the image on the server side and then render it using the good old image tag.

First, cold fusion ships with some outdated batik files (which handle the cfimage tag) , so you will need to update those first, and add the missing files that will add your svg to -> image processing ability. I used the steps found in this post to accomplish the task; I’ll list them here in short format so you can get into the ext chart part of this project.

  1. Stop your cold fusion service
  2. Download the files from the batik website http://xmlgraphics.apache.org/batik/download.cgi
  3. Rename the jar files in /wwwroot/WEB-INF/cfform/jars/  that start with batik by adding the extension .old
  4. Copy the batik jar files into /wwwroot/WEB-INF/lib
  5. Restart Cold Fusion

Next, let’s assume that we have two files, one called convertImage.cfm and one called convertImage.cfc, of course, we want to pass the svg markup to the cfm which will pass the data to the cfc for processing.

<cfcase value="saveChart">
        <cfset saveChart = data.saveChart( svg=form.svg) />
        <cfset json = "{'success':'#saveChart#'}" />
</cfcase>

The code below goes in the cfc file.

<cffunction name="saveChart" >
        <cfargument name="svg" />
            <cftry>
            <cfset svgFile = "c:\websites\temp.svg" />
            <cfset jpgFile = replace("c:\websites\temp.svg", ".svg", ".jpg") />
            <cfset pngFile = (pngPath) />--->
            <cffile action="delete" file="c:\websites\temp.jpg" >

	<cfif FileExists(svgFile)>
            	<cffile action="delete" file="c:\websites\temp.svg" >
            	<cffile action="write" file="c:\websites\temp.svg" output="#svg#" >
           <cfelse>
           	<cffile action="write" file="c:\websites\temp.svg" output="#svg#"  >
           </cfif>

            <cfset t = createObject("java", "org.apache.batik.transcoder.image.JPEGTranscoder").init() />
            <cfset svgURI = createObject("java", "java.io.File").init(svgFile).toURL().toString() />
            <cfset input 	= createObject("java", "org.apache.batik.transcoder.TranscoderInput").init(svgURI) />
            <cfset ostream 	= createObject("java", "java.io.FileOutputStream").init(jpgFile) />
            <cfset output 	= createObject("java", "org.apache.batik.transcoder.TranscoderOutput").init(ostream) />
            <cfset t.transcode(input, output) />
            <cfset ostream.flush() />
            <cfset ostream.close() />

            <cfcatch type="any">
          		 <cfreturn "false" />
            </cfcatch>
            </cftry>
        <cfreturn "true" />
    </cffunction>

The function below would go in your javascript controller.

   saveChart: function(me){
        this.dTask.delay(500, function(){
                var svg = me.up('panel').down('chart').save(
                    {
                        type    :'image/svg+xml'
                    }
                );

                Ext.Ajax.request({
                    url: 'convertImage.cfm?remoteEvent=saveChart',
                    params: {
                        svg: svg
                    },
                    success: function(){
                        // process server response here
                        window.open('temp.jpg');
                    }
                });
        });
    },

A look at cold fusion, ext and cfqueryparam strategies

In a perfect world all user input data would conform to the max length of the database fields that you want to put them in right? As we all know, we don’t live in a perfect world, so you as a developer are forced (hopefully) to build in several layers of redundancy in your data validation methods. The steps below outline some pretty basic concepts when it comes to handling string input from an ext app using cold fusion as the back end language.
You should be using cfqueryparam for all of your input by now, but just in case you are not consider the following example from Adobe itself.

You have a table called sometable and you are updating somelement based on passing someprimamrykey to the server. On the other side you have written the following and are patiently waiting for the data to come via the url and populate the following values:

<cfparam name=" somelement " default="" >
<cfparam name=" someprimamrykey " default="">
<cfquery name="my_cool_query" datasource="big_db" >

UPDATE  my_table
SET
some_column = '#somelement #'
WHERE
my_primar_key = # someprimamrykey #

</cfquery>

Now let’s plug in some values we’ll replace somelement with ‘Acme Incorporated’ and replace someprimarykey with an integer like say 7. So far so good, right? Of course, this is all taken from the query string below that is visible for all to see.

https://my_site.org? somelement= Acme%20Incorporated& someprimamrykey=7

Now since we have a keen eye for detail we immediately notice that the primary key looks like an integer and could be used in the WHERE statement of the query which is – where else but at the end. Knowing this we enter the following value in the textbox on our site that corresponds with someprimarykey, ’7 DELETE from user_table’.

We’ll type in the following url to do the trick:

https://my_site.org? somelement= Acme%20Incorporated& 7%20DELETE%20from%20user_table

Now the query that will get run is below:

UPDATE  my_table
SET
some_column = 'Acme Incorporated' 
WHERE
my_primar_key = 7 DELETE from user_table
</cfquery>

Uh-oh we just deleted all the users, of course this assumes that we know the name of the user table but say you are running some open source content management system, then all of the names are known variables, right?

How can we stop this from happening?

Let’s take the following steps on the client side in our Ext code:

Make sure you set the maxLength AND the enforceMaxlength config options in your extjs code to stop the user from having the ability to enter strings of any length.
If you want to restrict the input to alpha numeric only use the built in Ext.Vtype in the text fields vtype config option. If you need to get fancy, or want to make sure that other characters get let in like those in foreign languages that are not a-z you could look into writing your own vtype and adding it to this config option.

Great, now that you have all of your client side validation in place lets work on making the server side is just as secure.

Always use cfqueryparam with the maxlength attribute set to the same maxlength as the database element and the ext maxlength above, this will make sure that cold fusion throws an error when someone tries to pass in a string that is longer than the specified maxlength. Why, you might ask, we already took care of that on the client side, didn’t we? Well, chances are you are still passing the variable and someone could inject their own value and pass it directly to the server, for instance, by modifying the URL above like we just did in the example.

Let’s see what happens to the input in the example above if we were to use cfqueryparam instead of just outputting the vale in the query directly, as in the code below the whole query would have failed due to the fact that the Delete statement was tacked onto the end of the primary key which is an integer.

UPDATE  my_table
SET
some_column = <cfqueryparam cfsqltype="cf_sql_varchar"  value="Acme Incorporated"
			maxlength="20"	 /> 
WHERE
my_primar_key =  <cfqueryparam cfsqltype="cf_sql_integer" 	value="7 DELETE from user_table " />
</cfquery>

If this had been a where clause looking at a string value instead of an integer, no damage would have been done as the cfqueryparam tag would have escaped the output with single quotes which would have meant that the SQL would have evaluated the whole string.

Some cold fusion cfqueryparam / extjs form field tips for xtype numberfield

If you code in cold fusion you should be using cfqueryparam when you are inputting data into your back end database, that’s a given as it is pretty effective against sql injection hacks, but when you do this you run the risk of throwing errors that you never worried about previously. The two most common problems are maxlength violations, and null value errors in numeric fields, to handle these two issues in your Extjs project I suggest the following approach:

Client Side Considerations:

Always use the xtype:numberfield, or the Ext.form.field.Number input control.

Make sure that you set a valid minValue, or it will default to negative infinity, and you may also need to set a maxValue if you do not want the user to enter a number greater than the ceiling on the data type.

Remember that decimals are allowed by default, so if you want to store the input in an integer field make sure you set allowDecimals to false.
Decide if this is a required field, if so set allowBlank to false to make sure that the user enters a number before submitting the field.

Server Side Considerations:

When you always want a value in the database field (for example a price or quantity field) — Always use cold fusion’s val() function around your input variables as it will convert the numeric characters at the beginning of a string to a number, but, will replace the value with a zero if there are leading characters, meaning the end result is you will always get a valid number in your number field. See the code below.

UPDATE  some_table
SET 
some_currency_value  = <cfqueryparam cfsqltype="cf_sql_float"		value="#val(some_user_input_data)#"	/>

In the example above if some_user_input_data was set to XYZ6563 then the code above would set the value zero. If the numbers were in front of the letters then the letters would be removed and the value entered into database would be 6563 and XYZ would be left off.

When you may actually want a null in the database field – If you do not want to use the val() function but still want to prevent invalid data input from causing cold fusion errors on the back end of your application you can use the IsValid() function coupled with the null attribute in cfqueryparam and ensure that your invalid values insert a null into the field.

Here’s how and why.

UPDATE  some_table
SET 
some_int_value  = <cfqueryparam cfsqltype="cf_sql_integer" 	
value="# some_user_input_data #"
 null="#not IsValid('integer', some_user_input_data)#"  />

The null attribute is looking for a yes or a no, a 1 or a 0 to tell it to ignore the value in the value field and just put the NULL into the database using not in front will reverse the 1 or zero that the Isvalid function returns thus telling cold fusion to place a NULL in the database when the value passed was not a valid integer. You can take a look at more features of the IsValid function here.

There you have it, some tips on keeping your number field values in place and ensuring that the integrity of your back end data stays sound.

Really, really hard to find coldfusion error : Form entries are incomplete or invalid, it all comes down to your field names

If you are using ext as a front end and sending form data asynchronously to the back end in hopes of getting a response back in the form of success:true and you get back a failed response with the title above in the cold fusion produced HTML code you might scratch your head, and certainly waste a few hours digging for the answer. It seems that cold fusion looks at the names of the fields that contain underscores as two separate parts, first, the variable name and second, the validation type. Any of the suffixes in the list below will cause coldfusion to throw the invalid field error.

Field name suffix Verifies
_integer, _cfforminteger An integer of the range -2,147,483,648 — 2,147,483,647. Treats the initial characters “$ ¤ ¥ £ +” as valid input, but removes them from the number.
_cfformnumeric Any numeric value. Treats the initial characters “$ ¤ ¥ £ +”as valid input, but does NOT remove them from the number.
_float, _cfformfloat Any value (including an integer) that can be represented as a floating point number with up to 12 signif- icant digits. Treats the initial characters “$ ¤ ¥ £ +” as valid input, but removes them from the number.

Converts input data to a real number; for example a dump of an integer value on the action page includes a decimal point followed by a 0.

_range, _cfformrange A numeric value within boundaries specified by the value attribute. Specify the range in the value attribute using the format “min=minvalue max=maxvalue.” You cannot specify a custom error message for this validation.
_date, _cfformdate A date in any format that ColdFusion can understand; converts the input to ODBC date format. Allows entry of a time part, but removes it from the ODBC value.
_cfformusdate A date in the form m/d/y, m-d-y , or m.d.y, The m and d format can be 1 or 2 digits; y can be 2 or 4 digits.
Does not convert the string to an ODBC value and does not allow a time part.
_eurodate, _cfformeurodate A date in the form d/m/y, d-m-y, or d.m.y. The m and d format can be 1 or 2 digits; y can be 2 or 4 digits.
Converts the input to ODBC date format. Allows entry of a time part, but removes it from the ODBC value.
_time, _cfformtime A time. Can be in 12-hour or 24-hour clock format, and can include seconds in the form hh:mm:ss or a case-independent am or pm indicator.

Converts the input to ODBC time format. Allows entry of a date part, but removes it from the ODBC value.

_cfformcreditcard After stripping blanks and dashes, a number that conforms to the mod10 algorithm. Number must have
13-16 digits.
_cfformSSN,_cfformsocial_security_number A nine-digit Social Security number. Can be of the form xxx-xx-xxxx or xxx xx xxxx.