Google Ads

If you’ve visited my site more than once, you might start to notice that the silly little tagline next to the logo in my header changes, in both content and appearance.

This is accomplished by way of a fancy little bit of PHP. The image generation uses the GD library (with FreeType support), and the fonts are all TrueType.

Again, since my Linode didn’t come with anything preinstalled, I needed to install GD first. It seemed like it might be a bit of a pain - the PHP manual page indicates I was going to have to recompile PHP. Fortunately, this was not the case.

I just had to download it from Ubuntu’s package manager…

apt-get install php5-gd

…and add it to the “extensions” section of php.ini…

nano /etc/php5/apache2/php.ini
 
extension=gd.so

…and restart Apache.

apache2ctl -k graceful

Once that’s out of the way, creating the image was remarkably simple - especially since I found a ready-made script that did exactly what I wanted.

The code is pretty long, so hit the jump to see the rest.

Read the rest of this entry »

There’s a handy little query you can run in SQL to retrieve the identity (primary key) value of a record you just created. So, you can do something like this:

INSERT INTO
  People (
    Name
  ) VALUES (
    'Joe'
  );
  SELECT @@IDENTITY AS NewName;

This query will create a new person and also return the identity value of the newly created record. It can be useful for all kinds of things - I use it frequently.

We recently upgraded to ColdFusion 8 here at Purdue, and my code started breaking.

It turns out that CF8 attempts to “help” you by automatically running SELECT @@IDENTITY after any INSERT query. This is problematic in two ways - it cancels out your own @@IDENTITY query, and it arbitrarily names the result Generated_Keys.

So instead of being able to do something like this:

<cfset TheNewName = People.NewName>

You must use this:

<cfset TheNewName = People.Generated_Keys>

It’s really more annoying than anything else. It seems like a good idea to include the code automatically, but I think it would probably be a little better if there were a conditional in there that prevents CF8 from inserting its automatic query if a SELECT @@IDENTITY query is already present.

2008.09.07 [Sun] | 12:17 AM

Purdue, like a lot of enterprise-level organizations, uses LDAP to manage certain things. One of the advantages to LDAP is that it can provide information about users on a domain. Our organization uses some globally-accessible ColdFusion functions to quickly get user information based on user ID data.

With AJAX libraries and frameworks (we use Scriptaculous and Prototype), we’ve also created a bit of JavaScript that allows retrieving the first nad last name of a user from an entered ID without having to submit the form and post back to the page. It’s a useful tool, but it was originally written to only work with one text field on a page.

In one of the applications I’m currently working on, I have several different fields that require this behavior. I decided to modify the script we have so that I could pass a value to the function as a sort of prefix. That way, I could have a text box with an ID of OwnerID, and another with an ID of UserID. Instead of the normal script, which is called just by lookupID(), I’d be able to refer to a specific input, using something like lookupID(’Owner’).

Everything was coming along the way I needed it to, until I got to the section of code that dealt with changing the values of input boxes on the form. When a user enters a person’s ID, the JavaScript code looks up the person’s first and last name and displays that name in a read-only input box on the page. Since each ID input box had a corresponding read-only input box, I needed to be able to dynamically refer to that box using the prefix passed to the function.

It’s very easy to accomplish, but it took a bit of Googling to figure it out. It turns out that square brackets give us the ability to manage the task. For instance, for a form named “edit”, the standard code might look something like this:

form.edit.OwnerName.value = '(' + FirstName + ' ' + LastName + ')';

However, the OwnerName input box ID needs to be different for each read-only box, so we use square brackets to create a dynamic form element reference, where foo is the prefix passed to the function:

form.edit.elements[foo + 'Name'].value  = '(' + FirstName + ' ' + LastName + ')';

It’s a bit more complicated than dynamic variable names in ColdFusion, but it’s fairly easy to implement, and it gets the job done.

Dynamic variable names can be extremely useful when dealing with similar pieces of code, loops and other such concepts. Each language deals with it differently, but I’ve found it an important element to learn about in most of the applications I create.

2008.08.22 [Fri] | 12:18 PM

Not too long ago, I wrote a short tutorial on using ColdFusion to identify the user’s browser and add extra browser-specific CSS files. Today, I found myself in need of similar functionality for PHP. The code isn’t quite the same - PHP doesn’t have a direct clone of CF’s contains decision operator; you have to use the strstr string function instead. The general idea, however, is the same.

The following script will identify between Firefox, IE6, and IE7. Like my last post, I’ve added an extra piece that will include an ie.css file before including an IE version-specific stylesheet.

<?php
  $thePath = "/css";
  $absPath = $_SERVER['ABSOLUTE_PATH'] . "css";
  $theBrowser = $_SERVER['HTTP_USER_AGENT'];
 
  if(strstr($theBrowser, "Firefox")) {
    $browser = "firefox";
  }
  elseif(strstr($theBrowser, "MSIE 7.0")) {
    $browser = "ie7";
  }
  elseif(strstr($theBrowser, "MSIE 6.0")) {
    $browser = "ie6";
  }
 
  if(file_exists($absPath . '/' . $browser . '.css')) {
    $css = '&lt;link rel="stylesheet" href="' . $thePath . '/' . $browser . '.css" /&gt;';
  }
 
  if(strstr($browser, "ie")) {
    if(file_exists($absPath . '/ie.css')) {
      $css = '&lt;link rel="stylesheet" href="' . $thePath . '/ie.css" /&gt;' . $css;
    }
  }
?>

The ABSOLUTE_PATH server variable tells us where our site is actually stored on the server; I added the name of the directory where my stylesheets are stored to the end of the variable and stuck it in a string called $absPath. You’ll need this absolute path to determine if a CSS file exists in the given directory. The relative link to my CSS directory is stored in $thePath and is used to link to the CSS file in my HTML.

When the code is done, I’m left with two variables I can use anywhere in my application: $browser is the short identifier for the user’s browser; $css contains the HTML to link to the additional stylesheet(s).

It’s the same concept with a slightly different implementation. Happy coding!

One of my current projects at work has an RSS requirement. I’m redesigning the university’s policies website. My customers are concerned that other departments at Purdue have previously copied the content of a policy and placed it on a different site, which is problematic when policies are revised, superseded, or retired.

Implementing an RSS XML file for each policy will allow anyone else to embed a policy in their own site using any web technology while keeping the policies site owners in complete control of the content, no matter where it’s used.

Unfortunately, I had a pretty hard time finding a clear-cut solution for creating XML files dynamically with ColdFusion and SQL. It turns out that it’s not that difficult; it just took a little time to figure it out. One solution involved creating an actual XML file and writing it to the server. This would work for content that never gets updated, but this is a situation where the user needs to be able to implement the RSS in their site and not worry about it again.

The problem is, the XML specification is quite strict. You must be able to pass the file as XML in the header information, which will allow RSS readers (and embedding codes or scripts) to see it and parse it. This is accomplished quite easily through the cfcontent tag. Once you’ve identified the content as XML, you generate the file just like you would a regular HTML-formatted page.

Some quick Googling got me the information I needed on how to create an RSS feed to current specifications - you can check it out on Pete Freitag’s site here.

This is pretty code-heavy, so hit the jump to read the rest.

Read the rest of this entry »

I like to provide clear visual or textual cues for an application. In the admin interface for one of my apps, I provide a pretty easy way of rejecting or accepting form submissions for a class - a red “X” to reject, and a green checkmark to accept. In order to pass these actions to the ColdFusion page on the server side and rely on POST rather than GET, I used the image form control.

You can use images as command buttons in a form pretty easily - <input type=”image”> is a pretty good place to start.

There’s one problem with this - Internet Explorer (including version 7!) doesn’t pass the value attribute of an image control to the server. In ColdFusion, the value is critical, as it’s what’s used to identify controls on the server side (e.g. #arguments.FirstName# would pull the value of whatever control is named FirstName). It does, however, pass the X and Y coordinates of where the user clicked on the image, by adding .X or .Y to the end of whatever is set as the value attribute (e.g. FirstName.X).

The remedy is to use a different value for each image. I was previously treating them all like Submit buttons. In the case of my app, I have one image with a value of “accept” and one with a value of “reject”. My code on the backend looks like this:

<cfif isDefined('arguments.accept.x')>
  <!--- process the application as accepted --->
<cfelseif isDefined('arguments.reject.x')>
  <!--- process the application as rejected --->
</cfif>

It’s an easy solution to an annoying problem. The one caveat about this is that IE will also show the user where the form is going to post, by displaying it in the status bar at the bottom of the browser window. While the user can obviously view the source code if they desire, it’s just something to keep in mind.

On one of my current projects, I’ve found myself in need of passing sensitive data through a URL string. I could use an individual form for each link and pass it via POST, but I wanted to see what I might be able to do by way of encrypting the data. Turns out it’s quite easy.

We’re still running ColdFusion MX 6 here, so some of the newer functions are either crippled or nonexistent. Starting with MX 7, the Encrypt function can handle several different encryption algorithms. I’m stuck with ColdFusion’s own algorithm, which isn’t nearly as secure as AES. However, after a little bit of research, I discovered that it’s actually quite easy to encrypt a variable in your querystring data.

This is a four-step process:

  1. Create a 32-bit string which will be used as the encryption logarithm. I used a phrase, although I would imagine it would be more secure to include some special characters in there.
  2. Encrypt your data using the Encrypt function. This takes two parameters - the string you’re encrypting, and the string you’re using as your logarithm.
  3. Convert the encrypted string to Base64 so it can be used in your URL string, using the Base64 function. The Encrypt function converts your string into a mess of special characters, many of which are invalid in a URL.
  4. On the page that is processing the URL string, convert the encrypted value back to a string and decrypt it by nesting the ToBinary, ToString, and Decrypt functions.

Your final code will look something like this:

<!--- Encrypt String --->
<cfset Secret = 'Don''t tell anyone what this value is!'>
<cfset TheKey = 'This is my secret key phrase! 5-6-7-8, who do we appreciate?'>
<cfset Encrypted = Encrypt(Secret, TheKey)>
<cfset Secret64 = ToBase64(Encrypted)>
 
<!--- Decrypt String --->
<cfset UnlockedSecret = Decrypt(ToString(ToBinary(Secret64)), TheKey)>

Simple, huh? My encrypted values look something like JSQuTyoqWkwgCg==. However, depending on what you’re encrypting (numbers, a phrase, an alphanumeric code, etc.), your obfuscated value might look quite a bit different.

While you certainly should use extreme caution with highly sensitive data like bank account or social security numbers, this is a pretty quick and dirty method of obfuscating data that can’t be passed via POST in your application.

I’m really, annoyingly, obsessively anal about browser compatibility in web design. Even if you’re convinced that none of your users will ever touch Opera, there’s no reason to not make sure your site is usable in Opera…or Lynx, or IE 5.5, or anything else.

There are known ways to hack your CSS so that different browsers (most specifically, IE, but also others like Opera and Safari that have little quirks about how they render certain elements) will still display your content exactly as you like. However, such hacks can be unreliable and make for messy code.

A much, much better and more streamlined way to deal with CSS incompatibility across browsers is to use server-side code to identify the browser agent and add the appropriate stylesheet.

For the projects I do for Purdue, I’ve created a reusable file that I include in all the sites I develop. It checks the browser’s user agent (in ColdFusion, this is the CGI.HTTP_USER_AGENT variable; in PHP it’s $_SERVER['HTTP_USER_AGENT']), looks for a specific word in the agent string, and will include an extra stylesheet if that CSS file exists.

To make my life easier, I use a standard naming convention. For instance, a stylesheet to add Opera-specific CSS is called opera.css. I also add an extra option at the end of my IF statement to handle any browser not listed, by way of other.css. This could be a way to handle versions of IE previous to 5, or other old browsers (Netscape Navigator, anyone?).

I use an additional bit of code so that if the browser is any version of IE, a second stylesheet called ie.css can be used, along with ie5.css, ie6.css, and ie7.css. There are certain CSS bugs that IE 6 and/or 7 have fixed, while other bugs are present in all versions of IE. Using an extra CSS file for all versions of IE makes it easier to handle those browser-specific styles.

To keep my code clean, I also used the ExpandPath function of ColdFusion to make sure an extra browser-specific stylesheet exists for the given user agent. If the file doesn’t exist, the code outputs nothing but an empty variable.

Make sense? Writing the code is extremely easy. This example uses ColdFusion, but you could easily adapt this concept to work with ASP, PHP, Java, or ASP.NET.

<cfset #ThePath# = "/yoursitepath/css">
 
<!--- retrieve browser engine information --->
<cfif CGI.HTTP_USER_AGENT contains "Firefox">
  <cfset browser = "firefox">
<cfelseif CGI.HTTP_USER_AGENT contains "MSIE 7">
  <cfset browser = "ie7">
<cfelseif CGI.HTTP_USER_AGENT contains "MSIE 6">
  <cfset browser = "ie6">
<cfelseif CGI.HTTP_USER_AGENT contains "MSIE 5">
  <cfset browser = "ie5">
<cfelseif CGI.HTTP_USER_AGENT contains "Safari">
  <cfset browser = "safari">
<cfelseif CGI.HTTP_USER_AGENT contains "Opera">
  <cfset browser = "opera">
<cfelse>
  <cfset browser = "other">
</cfif>
 
<cfif FileExists(ExpandPath("#ThePath#/#browser#.css"))>
  <cfset browserCSS = '<link rel="stylesheet" href="#ThePath#/#browser#.css" />'>
<cfelse>
  <cfset browserCSS = "">
</cfif>
 
<!---
  this section adds an additional stylesheet to cover all
  versions of Internet Explorer. ie.css is placed ABOVE browser.css,
  so version-specific styles will take priority.
--->
<cfif browser contains "ie">
  <cfif FileExists(ExpandPath("#ThePath#/ie.css"))>
    <cfset browserCSS = '<link rel="stylesheet" href="#ThePath#/ie.css" />' &amp;
      '#chr(10)##chr(9)##chr(9)#' &amp;
      browserCSS
    >
  </cfif>
</cfif>

Implementation couldn’t be easier. Just add the variable containing the path to the browser-specific CSS file directly after your HTML for importing your main stylesheet:

<link rel="stylesheet" href="/yoursitepath/css/mainstyle.css" />
#browserCSS#

Being the OCD person I am, the #chr(10)##chr(9)##chr(9)# adds tab and linefeed characters to the output, so your source will still look generally clean.

The other benefit to this code snippet is that it creates an additional variable called #browser#. You could use this anywhere in your code to do something browser specific - e.g. if the user is in Safari, put a big “Steve Jobs is lame” banner at the top of the site…the options for sarcasm here are limitless!

Overall, this is a much better solution than using hacks. By relying on the server to make your CSS work the way you want, you have more control over your code. You could even go so far as to put your main style in that variable, so that users who don’t have a supported browser only get the other.css, which could allow you to provide a text-only or unformatted version of your site.

Google Ads