Beware PHP’s split()

January 29, 2009

Many programming languages have have a join function that takes an array of strings and concatenates them, and a corresponding split function that does the opposite: takes a string and splits it up into an array.

Python has join and split, C# has join and split, Javascript has join and split, and Java has a split (although it’s sadly missing a join). PHP, though, has implode and explode. They do the same thing as join and split in other languages, it’s just that PHP has decided not to to follow the standard naming convention for these functions.

Fortunately for developers like me who are used to the “join” and “split” names PHP has aliases. Therefore you can happily call join and split in PHP and it’ll basically call implode and explode for you… or so I though! Unfortunately this isn’t the case! Join is an alias of implode. From the PHP documentation:

join — Alias of implode()

And here’s the documentation for implode:

implode — Join array elements with a string
string implode ( string $glue , array $pieces )

That’s pretty clear. It’s not quite the case for split though:

split — Split string into array by regular expression
array split ( string $pattern , string $string [, int $limit ] )

Notice how it isn’t defined as an alias of explode! Here’s the documentation for explode:

explode — Split a string by string
array explode ( string $delimiter , string $string [, int $limit=-1 ] )

Notice how it’s ever so slightly different? The explode function takes a string delimiter, but split takes a regular expression string! This means that in the majority of cases you’ll get exactly the same result from both functions, but you’ll suffer a slight performance hit with split. Using my profile class I worked out that explode is just over twice as fast as split.

The real problem arises when your delimiter string contains characters that mean something different when interpreted as a regular expression (such as “.”, “|”, “?”, “+” and “*”). See the following example with a “.”:

<?php
$sentence = "One. Two.";
var_dump(split(".", $sentence));
/* Output:
array(10) {
  [0]=>
  string(0) ""
  [1]=>
  string(0) ""
  [2]=>
  string(0) ""
  [3]=>
  string(0) ""
  [4]=>
  string(0) ""
  [5]=>
  string(0) ""
  [6]=>
  string(0) ""
  [7]=>
  string(0) ""
  [8]=>
  string(0) ""
  [9]=>
  string(0) ""
} */
var_dump(explode(".", $sentence));
/* Output:
array(3) {
  [0]=>
  string(3) "One"
  [1]=>
  string(4) " Two"
  [2]=>
  string(0) ""
} */
?>

So you’ve been warned! Feel free to use join instead of implode, but use split with caution!

Ubiquity CmdUtils.injectHTML workaround

If you haven’t already heard about Mozilla Ubiquity I suggest you watch the introductory video, which will explain it far better than I can.

I’ve been having a bit of a play around with it, and written a few small commands. The API documentation is really good, but this being early alpha software (currently v0.1.5) not everything works as expected.

For one of my commands I wanted to inject some HTML into the current webpage. Looking through the docs CmdUtils.injectHTML seemed to be exactly what I was after. Unfortunately it doesn’t work, but the workaround is simple enough:

var html = 'content to inject';
var doc = CmdUtils.getDocument();
doc.body.innerHTML += html;

Hopefully this will be fixed in the next release.

Using Git and GitHub to Sync Config Files

January 25, 2009

After years of using Linux I’ve built up a collection of customised config scripts for things like bash, vim, and screen. Having everything setup just how I want it is great, until I need to start working on a new computer. A simple solution is to copy all my config files over to the new computer, but it means I need to re-copy all the config files if I make any changes to them. This isn’t too much of a problem if I’m only working on two computers, but it becomes a real pain with more.

The solution I’ve come up with (and I’m sure others have too) is to put all my config files into into a Git repository on GitHub. Any changes to the config files can be committed to the repository, and than a quick update operation other machines keeps all the config files in sync. In this post I’ll describe how to set it all up.

Adding your config files to GitHub

You’ll obviously need to install Git. On any debian based system this is as simple as:

   sudo aptitude install git-core

You’ll also nee to Signup for a free GitHub account, and create a new repository. GitHub uses public-key cryptography and SSH for authentication, so you’ll need to create a SSH public key on each machine you’ll be accessing GitHub from. Details of how to do this are given in their guide. After adding your public key details to your GitHub account page you’re ready to add your config files:

  git init
  git add .bashrc
  git add .vimrc
  git add <any other config files you want to add>
  git commit -m 'Initial commit'
  git remote add origin git@github.com:coderholic/config.git # Your URL will differ
  git push origin master

Now all your config files are on GitHub!

Setting up a new machine

You’ll need to create a SSH public key on the new machine, just as you did on the previous one. Once you’ve done that:

Once you’ve done that:

  git init
  git pull git@github.com:coderholic/config.git
  git remote add origin git@github.com:coderholic/config.git

And your setup will match your other machine!

Making changes

The real benefit of storing your config files on GitHub is that it makes it really easy to synchronise changes between all your computers. After making a change on one computer:

  git commit -a -m "Useful commit message goes here"
  git push origin master

Then all you need to do on your other machines is issue the following command:

  git pull origin master

And you’re synced!

If you’re interested in seeing my config files you can see them on the GitHub page: http://github.com/coderholic/config/tree/master

AVI to DVD Shell Script

January 19, 2009

Inspired by a movable tripe blog post I came up with the following shell script to convert an AVI file to an ISO image that can be burned to disc and played back on a standard DVD player.

The script requires mencoder, ffmpeg, dvdauthor and mkisofs, and will let you know you if any of these are missing. Use it like follows:

./dvd.sh input.avi

Once the script has finished a “dvd.iso” file will be created, which can then be burned to DVD using your favourite disc burning tool.

#!/bin/bash
# AVI to DVD Script
# Ben Dowling - www.coderholic.com

# Change to "ntsc" if you'd like to create NTSC disks
format="pal"

# Check we have enough command line arguments
if [ $# != 1 ]
then
	echo "Usage: $0 <input file>"
	exit
fi

# Check for dependencies
missing=0
dependencies=( "mencoder" "ffmpeg" "dvdauthor" "mkisofs" )
for command in ${dependencies[@]}
do
	if ! command -v $command &>/dev/null
	then
		echo "$command not found"
		missing=1
	fi
done

if [ $missing = 1 ]
then
	echo "Please install the missing applications and try again"
	exit
fi

function emphasise() {
	echo ""
	echo "********** $1 **********"
	echo ""
}

# Check the file exists
input_file=$1
if [ ! -e $input_file ]
then
	echo "Input file not found"
	exit
fi

emphasise "Converting AVI to MPG"

ffmpeg -i finalmovie.avi -y -target ${format}-dvd -sameq -aspect 16:9 finalmovie.mpg

if [ $? != 0 ]
then
	emphasise "Conversion failed"
	exit
fi

emphasise "Creating DVD contents"

dvdauthor --title -o dvd -f finalmovie.mpg
first=$?
dvdauthor -o dvd -T
second=$?

if [ $first != 0 || $second != 0 ]
then
	emphasise "DVD Creation failed"
	exit
fi

emphasise "Creating ISO image"

mkisofs -dvd-video -o dvd.iso dvd/

if [ $? != 0 ]
then
	emphasise "ISO Creation failed"
	exit
fi

# Everything passed. Cleanup
rm -f finalmovie.mpg
rm -rf dvd/

emphasise "Success: dvd.iso image created"