ucantblamem

Hi, I’m James Angus. I have a greed for learning, an obsession with all things web; I am in love with standards, accessibility, creating things for use by people and yes, this site was designed on a mac. Read on ยป

Ruby, CGI and the attack of the ignorant

22nd Mar 2008

I have been developing Rails applications for a year or two now and have even deployed a couple on my own Media Temple account (no linkage, sorry), however I’d never attempted to put together a simple ruby script in my cgi-bin.

In the past, I have written python and perl cgi scripts, but never ruby. So, today I started working a little script to help me quickly setup SVN repositories… But, I quickly found that all my knowledge of UNIX, scripting and CGI equated to squat when I was greeted with a starkly contrasted “Internal Application Error” page - otherwise known as an HTTP 500 error.

Debugging the problem, I checked that:

  • My script had 755 permissions
  • The script belonged to the correct group
  • The shebang line was correct: #!/usr/bin/env ruby
  • I ran the script from the command line
  • But, everything seemed fine.

Finally, I turned on error logging from the Media Temple (Plesk) control panel and refreshed the page again. On inspecting the error log, I noticed the line “Premature end of script headers” - What the heck is that???

After quite a bit of Googling to find the actual meaning of this error, it hit home that unlike PHP, general-purpose scripting language - such as ruby - don’t send a default set of HTTP headers to the browser and hence Apache wasn’t sure what to do with the results from the CGI.

Adding the following line fixed my troubles and allowed me to start building out my little utility:

print "Content-type: text/html\\n\\n"

For anyone who wants a very quick “base” script to check your servers’ setup and start building your own ruby-cgi script, try throwing this into a *.cgi file in your cgi-bin:

#!/usr/bin/env ruby
print "Content-type: text/html\\n\\n"
print "Hello world"

PHP: Casting Objects

20th Mar 2008

Working in an MVC environment, one of the things that we do quite often is take a record from a database and send it to the view for display in some form or another. In a strict MVC paradigm the view really shouldn’t know the names of the fields in the database, yet all too often you will find that the code behind most applications is simply loading a row from the database as an object and sending that object - through the controller - to the view and echo-ing out each property of the object as necessary.

One of the major reasons for doing things this way is that too much effort is required to take one object and make it more meaningful to the view. The problem is compounded when you are taking a series of rows - or an array of objects - and sending that to the view.

Now, in practical terms, it really doesn’t matter; the views ultimately get processed by the application language before they get to the client, so you could hardly say that the controller is exposing your data structure (or any other such nonsense). In any case, this relatively small problem has been on my mind for some time and it wasn’t until recently - while working on an unrelated problem - that I found a solution.

The function that I came up with allows you to “cast” an entire object into another object structure using a given format. Take the following object for instance:

$obj = new stdClass;
$obj->name = 'Jeff';
$obj->id = 39;

A very simple object with two properties - name and ID. Now, if we wanted to make this an option in a select-list for example, ideally the view would accept three properties: The value (for the “value” attribute of the tag), the text (which would display in the select-list itself) and the title (attribute, because we like semantics right? :P). What we would really like this object to look like is this:

$obj = new stdClass;
$obj->text = 'Jeff';
$obj->title = 'Jeff';
$obj->value = 39;

In pure PHP, we would normally do this like so:

$obj = new stdClass;
$obj->name = 'Jeff';
$obj->id = 39;

$new_obj = new stdClass;
$new_obj->text = $obj->name;
$new_obj->title = $obj->name;
$new_obj->value = $obj->id;

This is a very raw and relatively unmaintainable solution, especially for objects with plenty of properties - like most database records. What we really need is a function that, give an object and some kind of map, can take the properties from the original object and create another object using the map. Here is just such a function:

/**
 * Take one object and cast it to another object structure using a given format
 * The '&' symbol can be used in the rules to copy a property.
 *
 * @access public
 * @param object $obj The original object that will be cast
 * @param array $rules An associative array of key/value pairs. The key is the name of the current object's property and the value is the new key for the "cast" object.
 * @param mixed $blank_value The value given to a property if there is no existing property available in the original object
 * @return object
 * @author James Angus - ucantblamem.com
 * @copyright (c) James Angus 2007. All rights reserved.
 * @license MIT License - http://www.opensource.org/licenses/mit-license.php
 * @version 1.0
 */
function cast_object($obj, $rules = array(), $blank_value = 0)
{
    $obj = (array) $obj;
    $fin = array();

    foreach($rules as $key => $value) {
        if(isset($obj[$key])) {
            $fin[$value] = $obj[$key];
        } elseif (substr($key, 0, 1) == '&') {
            $key = str_replace('&', ", $key);
            if(isset($obj[$key])) {
                $fin[$value] = $obj[$key];
            }  else {
                $fin[$value] = $blank_value;
            }
        } else {
            $fin[$value] = $blank_value;
        }
    }

    return (object) $fin;
} // cast_object()

With this function we can now rewrite our little example like so:

$obj = new stdClass;
$obj->name = 'Jeff';
$obj->id = 39;

$new_obj = cast_object($obj, array('name' => 'text', '&name' => 'title', 'id' => 'value'));

Note that the second key in our array has an ampersand appended. Because array keys must be unique, I built in a mechanism for copying a property more than once. In the above example, the value of the “name” property will be copied to both the “text” and “title” properties of the new object. Also of note is that you can use multiple ampersands to copy a property as many times as you need.

Lastly, I have allowed you to specify a value for properties that could not be found in the original object. This means, that the object returned contains all the properties specified in the rules.

Ramblings of a restless mind: February 2008

3rd Mar 2008