Coding with Jesse

buttons need type="submit" to submit in IE

In a typical round of doing Internet Explorer clean up at the end of a project, I had to figure out why my <button>Submit</button> wasn't submitting a form in IE.

I did a search on "html button" and went to the w3c HTML 4.01 specifications:

type = submit|button|reset [CI]

This attribute declares the type of the button. Possible values:

submit: Creates a submit button. This is the default value.
reset: Creates a reset button.
button: Creates a push button.

So the default is submit. But Internet Explorer has obviously forgotten this in IE6 and IE7. I found it worked without type="submit" in Firefox, Safari, Chrome and Opera. I haven't tested in IE8 because I don't have it installed. Maybe someone wants to check it out? Here is a demo page.

So I guess we should get in the habit of using:

<button type="submit">Submit</button>
Published on December 26th, 2008. © Jesse Skinner

Use Arrays in HTML Form Variables

When you're dealing with processing forms, a lot of the time you have a one-to-one mapping of form fields and database columns, with perhaps an extra submit button or some fields that need special processing (eg. passwords).

Although many frameworks like CodeIgniter make this easier, you can still easily come up with code like this:

$this->db->insert('accounts', array(
    'first_name' => $this->input->post('first_name'),
    'last_name' => $this->input->post('last_name'),
    'email' => $this->input->post('email'),
    'address1' => $this->input->post('address1'),
    'address2' => $this->input->post('address2'),
    'city' => $this->input->post('city'),
    'state' => $this->input->post('state'),
    'zip' => $this->input->post('zip'),
    'phone' => $this->input->post('phone'),
    'fax' => $this->input->post('fax')
));

See all that repetition? Whenever you see a group of lines that look almost the same, you know there is probably an opportunity to clean things up. Well luckily, there's a really neat one.

You can create arrays in form fields using square brackets. That means you can name fields like account[first_name] and account[last_name] and in most server-side languages, you will end up with an 'account' array.

In HTML, PHP and CodeIgniter, that might look something like this:

<input type="text" name="account[first_name]"/>
<input type="text" name="account[last_name]"/>
<!-- etc... -->
<input type="text" name="account[fax]"/>
<input type="submit" name="submit"/> <!-- note the lack of 'account' -->

// meanwhile, on the server...
$account = $this->input->post('account');

// VERY IMPORTANT: unset any fields that shouldn't be edited
unset($account['id']);

$this->db->insert('accounts', $account);

See? Much cleaner. Yes, you do open a slight security hole potential, so be very careful when doing this on tables that have security implications, ie. user data. If you have an 'admin' column on your 'users' table, someone could maliciously add <input type="hidden" name="users[admin]" value="1"/> to your form using Firebug and grant themselves administration access. You can solve this by adding something like unset($user['admin']); to the incoming data. If you wanted to be really safe, you could have an array of the keys you want to allow and filter against that using something like PHP's array_intersect_key with array_flip:

$user = $this->input->post('user');

// only allow keys in $user to match the values in $columns
$columns = array('first_name', 'last_name', /* etc.. */ );
$user = array_intersect_key($user, array_flip($columns)));

You can even do this with checkboxes and multiple select boxes, and alternatively leave out the key in the array to create a regular array (ie. not associative) of values:

<label><input type="checkbox" name="choice[]" value="1"/> 1</label>
<label><input type="checkbox" name="choice[]" value="2"/> 2</label>
<!-- etc... -->

// meanwhile, on the server...
$choice = $this->input->post('choice');

print_r($choice); // Array ( [0] => 1 [1] => 2 )

This "trick" can really clean your code up. I used it recently to drastically simplify a form that had a shipping address and billing address. If the user checked a box saying "My shipping and billing are the same", I was able to simply do something like this:

$shipping = $_POST['shipping'];
$shipping_billing_same = $_POST['shipping_billing_same'];

if ($shipping_billing_same) {
    $billing = $shipping;
} else {
    $billing = $_POST['billing'];
}

Much nicer than that 24 form fields that were hard-coded previously.

I've given examples here in PHP and CodeIgniter. Does anyone else want to give examples in other server-side languages and frameworks?

Published on November 3rd, 2008. © Jesse Skinner

5 Reasons Freelancers Can Succeed in a Shrinking Economy

Like many people, I've been a bit obsessed about the economy lately. I'm wasn't sure whether or not to be scared, and to be honest I still don't. But I did think of some reasons freelancing might be a safe place to be.

  1. You have a diversified clientele. Your clients can be anywhere in the world, and you have many of them. And if you're lucky, you have more than enough work to fill your time. No matter how bad the economy gets, there should still be some business available.
  2. You have very little overhead. For most freelancers, all you need to work is a laptop and the Internet, both of which you'd probably have even if you weren't freelancing. You probably pay $10/month for your web site hosting, but otherwise you don't have a reason to borrow money. The gears of the credit crunch don't touch your business.
  3. You can drop your prices whenever you want. If you find less people can afford what you're charging, you'll be able to adjust accordingly. If you have a job and they decide they can't afford you, then you get laid off.
  4. The Internet is the place to be for self-employed professionals. With the considerably low cost of having the Internet, I would assume that a lot more business will happen online as more people become self-employed and work from home. The number of people you can potentially connect with online feels infinite.
  5. Businesses who don't want employees might turn to freelancers. Who knows, maybe in uncertain times, more business will want to hire freelancers on a contract basis rather than dedicate to hiring an employee they don't know if they'll be able to keep.

For those of you who don't freelance, I'm not suggesting you quit your job and start freelancing tomorrow. You'll have to decide that for yourself. If you want to start freelancing, I would suggest is to get the ball rolling on the side while you have a job. Get that website up and get some presence on the Internet. That way you'll have something to fall back on if you lose your job.

So things don't look too bad for us freelancers. How about you? Have you noticed the shrinking economy having a direct effect on your business or job? What do you think we can expect?

Published on October 24th, 2008. © Jesse Skinner

Keeping a Live Eye on Logs

In web development, you can get really used to getting good error messages. If you're coding in PHP, you come to rely on the web server telling you if a variable is undefined or a file is missing.

Likewise, when you're debugging, sometimes the easiest sanity check is to output some text. You'll find me using echo "wtf?"; die; quite often when I'm trying to figure out why a block of code isn't being executed.

But sometimes, even these rudimentary methods of developing aren't available to you. Maybe error messages are turned off on the web server you're stuck debugging. Or maybe you have a lot of Ajax requests flying around and are tired of peeking at the result of each request.

Log files to the rescue. Nearly every framework and server has logging functionality. Apache usually logs every request, so you can see when images, static files, and other requests are made. CodeIgniter has several levels of logging, including DEBUG, ERROR and INFO. Whatever framework you use, or if you're using one you built yourself, you'll probably find some way of writing log messages to a file.

And if you have a log file that's being updated, you have a way of watching things happen in real time. I'm not talking about opening up the log file every now and then and looking back through it, I'm talking about watching it being updated as it happens.

Let's say you have a web server running Linux and are trying to debug something using CodeIgniter. You SSH into the web server, find the log file, and tail -f it. tail is a command which will dump the end of a file out for you. If you add the -f parameter, it will "follow" the file, printing out any new lines as they are added to the log file.

$ cd thefutureoftheweb.com/system/logs
$ tail -f log-2008-10-23.php

If you're working locally on Windows, make sure you have Cygwin installed. (Cygwin gives you a Linux-style console in Windows so you can do awesome stuff like this.) If so, you should have or be able to use tail in the exact same way. Mac and Linux users should have tail installed already.

Back at my old job, we used to keep console windows open using tail to watch the live web servers, especially after an update. This way we could see errors appearing to users live and could investigate and solve problems that would otherwise a) get buried in the logs, or b) go completely unnoticed.

It can really help to get in the groove of having one or two terminal windows open tailing the logs of the servers you're currently working on. And then if you get the urge to write echo "wtf?"; die; you can instead write log_message('info', 'wtf?'); (or equivalent in your framework of choice).

For further information, check out:

Happy tailing!

Published on October 22nd, 2008. © Jesse Skinner

Using PHP's empty() Instead of isset() and count()

I often work with data arrays in PHP as a way to pass information around or store information in sessions. When you work with these, you can't always assume that all properties are defined. I had some conditional logic code in PHP that was only supposed to execute if an array contained any values:

$data = array(
   'text' => array( 'hello', 'world' ),
   'numbers' => array( 43, 2, 55 )
);

if (count($data['text'])) {
   // do something with $data['text']
}

But then I was in a situation where $data['text'] may or may not be defined. So I was going to update my if statement like so:

if (isset($data['text']) && count($data['text'])) {
   // do something
}

But that looks kind of messy. I don't really like isset() but it is a necessary evil to avoid "Undefined" errors. Or is it?

if (!empty($data['text'])) {
   // do something
}

empty() to the rescue - it returns true if $data['text'] is undefined, or if it is an empty array, or if it is false or null or 0. So !empty() is what I'm really trying to determine, and it works great.

For more info, see: empty() at PHP.net.

Published on October 20th, 2008. © Jesse Skinner
<< older posts newer posts >> All posts