Mandatory reading for PHP devs

I just wanted to give this site I stumbled upon some credit: http://www.hackingwithphp.com/. I’ve been developing with PHP for about 15 years, but still the part about performance taught me quite a lot. isset() is apparently faster than array_key_exists() and $i++is slow compared to ++$i. These are micro-optimizations, sure, but there’s no reason to rub PHP the wrong way…

/Peder

Working around the IE9/IE8 XDR Post bug

When creating a REST-API for a client we ran across this really weird problem.

IE8/IE9 can’t make XMLHttpRequest to other domains via CORS. Microsoft invented their own solution for this problem, called XDR. The problem with XDR is that it doesn’t send a Content-type when doing POST requests, defaulting this value to “text/plain” instead.

PHP populates the $_POST array with data, only when the Content-type is set to “application/x-www-form-urlencoded” or “multipart/form-data”. So $_POST is just an empty array, unless you make some kind of workaround.

Here’s a stripped down version on how we solved it.

<?php
if(stristr($_SERVER['HTTP_USER_AGENT'], ' MSIE 9')){
	$msie_post = file_get_contents("php://input");
	parse_str($msie_post, $_POST);
}

Preventing overlapping cron jobs

From time to time, we’re asked to fix broken sites built by other agencies. This can be extremely tricky, but if it’s technologies we know and love (PHP, MySQL, Apache, Memcached, WordPress, CodeIgniter, Laravel, Slim, etc) we usually say yes.

If a site keeps falling every n hours/days, I start by checking if there are any cronjobs around. In this example we’ll pretend that we have a cronjob running a PHP-script every minute, creating an index of all articles in the database. The first few months, this wasn’t a problem as there weren’t that much content to index. Running the cronjob took 10-15 seconds.

6 months later, there are many more articles in the database, and the index takes longer to build. All of a sudden it takes more than 1 minute to complete, and now things get hairy. After 1 minute we have 2 jobs running, and after a few hours we have hundred of cronjobs running. Eventually the server won’t have any more memory to go around, and it’ll crash.

The solution is simple, and has been around in the UNIX world since forever: implement a lock file.

I’ve left out one little bit in the gist above: If the server goes down for reboot while the script is running, there will be a lock-file preventing new crons to run. How you handle this is up to you, for me this differs from time to time. Instead of just creating an empty lock file, you could write the process id (PID) to the lock file instead and use this to check if the script really is running.

Line-out scrobbler

for years i’ve been trying to hijack music recognition services like shahzam to be able to recognize music. i’ve finally got this working thanks to the fine guys at echonest, who kindly provide a proper api for this. my proof of concept is running on a spare macbook.

here’s how it works on the mac atm:
1. the os x automator runs in a 90 second loop, recording audio with quicktime and then running a cli php script.
2. the php script first converts the recorded .mov file to .mp3 with ffmpeg/lame
3. the php script then runs the echonest binary for music fingerprinting, which generates a json string
4. part of the json string is sent via curl to the echonest service and (hopefully) resolved
5. echonest returns artist, title and a unique id. this id is saved i a recent-log so that the php script can skip a run if it runs 2 times during the same song
6. artist and title are curled back to our lamp-server, where we save all plays in a database (mongodb atm)
7. artist and title can then be sent to any service you wish to interact with

making this projekt was pretty straight forward, except for a minor obstacle which took me a few hours to figure out. it turns out that the echonest binary calls ffmpeg internally, and for some reason automator couldn’t find ffmpeg in it’s $PATH. when i realized this the fix was done in a second, i just needed to make a symlink from the $PATH automator used to where i had ffmpeg locally.

next step: will try this a few days and see how well it performs. if it’s good enough i’ll buy a tiny linux box and give it a pair of rca jacks.

links:
the earth people account on last.fm which we scrobble vinyl to atm
the awesome echonest service

NOW On Roskilde

Now On Roskilde is a mobile application which users easily can add to their homescreen.
It shows what’s on right now, together with related artists playing in the near future.

Since nothing is playing right now (+ the correct feed hasn’t been published yet), the app is pretty worthless at the moment. There is a way to get a preview though, by adding a querystring to the url. These urls below will fetch the Roskilde data feed from 2010.

# thu, july 1st 2010, 19:43
http://nowonroskilde.com/?timestamp=1278013434

# fri, july 2st 2010, 19:43
http://nowonroskilde.com/?timestamp=1278017704

nowonroskilde.com by Earth People is a quick hack put together for the Roskilde Labs competition. Also, feel free to use the php class we put together for this.

CodeIgniter development site – on live environment

We recently had to set up a development site for an existing CodeIgniter site, and we wanted to do this effortless. Ideal would obviously be to have a separate virtual domain or a separate box but hey, “ideal” isn’t always ideal, heh.

By applying the same principle as in our previous WordPress article on the same topic, this is done in well under 5 minutes. Upload the same /dev folder as in the WordPress case, and make the following modification in the main CodeIgniter index.php file.

Change this:

$system_folder = "system";

to:

if(isset($_COOKIE["dev"])){
	$system_folder = "sysdev";
}else{
	$system_folder = "system";
}

Then copy the /system directory to /sysdev – and that will be your new development docroot. Once you’re ready to release your next version, either copy each file from /sysdev to /system – or simply change the name of /system to /system-OLD and /sysdev to /system.

html5 validation with(!) facebook opengraph

html5 is that new, cool(?) technology which you should(?) be using when making new sites. but, being the thorough developer you are – it just eats you up from the inside when your brand new html5 website won’t validate because your client decided to add a facebook like button.

the facebook open graph protocol/namespace/api/whatever which was released in spring 2010 will only validate with an xhtml doctype. if you want to work in a html5 doctype and use opengraph, you need to apply a little bit of server logic. have a look at this, i won’t bother explaining the source code, i think you’ll get it.

<?php
function is_facebook(){
if(!(stristr($_SERVER[“HTTP_USER_AGENT”],’facebook’) === FALSE))
return true;
}
}
?><!DOCTYPE html>
<html dir=”ltr” lang=”en-US”<?php if(is_facebook()){echo ‘ xmlns:fb=”http://www.facebook.com/2008/fbml” xmlns:og=”http://opengraphprotocol.org/schema/”‘;}?>>
<head>
<title><?php bloginfo(‘name’); ?></title>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″ />

<?php if(is_facebook()){?>
<meta property=”og:title” content=”<?php echo $title;?>”/>
<meta property=”og:description” content=”<?php echo $description;?>”/>
<meta property=”og:type” content=”article”/>
<meta property=”og:image” content=”<?=$path_to_page_thumbnail?>”/>
<meta property=”og:url” content=”http://<?php echo $_SERVER[“HTTP_HOST”].$_SERVER[“REQUEST_URI”];?>”/>
<meta property=”og:site_name” content=”<?=$the_name_of_the_site?>”/>
<meta property=”fb:appid” content=”<?=$your_fb_app_id?>”/>
<?php }?>

one thing to have in mind is that page level caching is a no go if you apply this tactic. if your cache is clever, you could possibly make an exception for the facebook user agent, delivering fresh content to facebook on all requests.

oh well, it’s just a thought. let me know if i missed something.

php class for ffmpeg

i’ve had a few projects over the last years where i’ve needed to convert some video file to flv, generate a thumbnail and get the video’s duration. i’ve never really got around to wrapping this into something reusable. but here it is, get it if you need it.

you’ll also need a non-windows server with ffmpeg installed, and if you need compability with any non-standard formats (3gp/mp3/etc) you need to install these as well. i won”t go into detail about how this is done, just google it.

when ffmpeg is correctly installed on your box, use this class like this:

$encoder = new videoencoder();
$thumbnail = $encoder->export_thumb("yourfile.mp4");
$duration = $encoder->get_duration("yourfile.mp4");
$videofile = $encoder->export_video("yourfile.mp4");

ok i know it’s better to use a service for this, like the excellent encoding.com – but hey, this is more fun – and really fast! also, worth noting is that while ffmpeg happily converts your files to flv, it will use the old “spark” codec for flash videos, instead of the newer and slightly better codec “on2” due to licensing issues. you can however use mp4 files with recent versions of flash player, which ffmpeg can convert to. use mp4 instead if you worry about video quality (which i guess you should…).

download my php class here.