cSprites for PHP 5.3.1/2

Joost posted a great article on reducing http requests on WordPress sites recently and one comment caught my attention. Nabil mentioned cSprites. It’s a WordPress plugin that merges the images in your posts into one file and uses CSS to position the single merged file in place of the original images. Here’s a good post explaining how this technique works.

Unfortunately it hasn’t been updated in over a year, and the current version doesn’t work if you have PHP 5.3.2 (and probably 5.3.1) as it trips over this PHP bug. The fix is simple, get rid of call_user_func_array() and call the functions directly.

I had it installed here and it worked well enough but not perfectly. Here’s the post I made on the plugin’s support forum if anyone’s interested.

I don’t think the author will update the plugin again and in fact he’s looking for someone else to take over. Anyone?

The plugin has been running on my photoblog for the last hour ago and I haven’t noticed any problems yet. As a bonus, it also stops people right clicking and stealing saving my photos for their own use. I’ve since removed it as visitors were only seeing blank images. Oh well.

So, want to give a “fixed version” a go? Grab csprites-for-wordpress.zip and install it in the usual way. Support queries should be directed towards the plugin support forum. ;)

Oh yeah, there’s also the SpriteMe bookmarklet if you don’t want to go fiddling with WordPress plugins!

PHP is_numeric() vs is_int()

Some lessons you don’t forget, but this one I did because it doesn’t come up very often.

Don’t use is_int() because, as Jeremy says, it’ll lie to you. Use is_numeric() instead.

Copy the following chunk of code into a php file and run it. You’ll be surprised at the outcome:

$t = "12345";
if( is_int($t ) ) {
    echo $t . " is an int!";
} else {
    echo $t . " is not an int!";
}

The problem is that is_int() thinks a string of numbers is a string, not an integer. The is_int() man page has an example illustrating that but it’s easy to miss. That function should carry a public health warning!

There’s also the ctype_digit() function too but it has it’s own gotcha:

Note: This function require a string to be useful, so for example passing in an integer will always return FALSE. However, also note that HTML Forms will result in numeric strings and not integers. See also the types section of the manual.

No activity within 1800 seconds; please log in again

1800 seconds is such a long time, right?

  1. It’s 30 minutes.
  2. It’s 0.5 hours.
  3. It’s 0.0208333333 days.
  4. It’s also 5.70397764 × 10-5 years.

And it’s not long enough for me. phpMyAdmin logs you out after 1800 seconds, obviously for security reasons. That’s fine if there are other people about, if I was in an office with people coming and going, but I work from home. All I see for most of the day is my family, the radio, my messy desk, computers, and the view out the window. Time to figure out how to make that 1800 second limit a little longer or remove it altogether.

After a little digging, I discovered that extending the time limit to a day is actually quite easy. Open your phpMyAdmin’s config.inc.php and search for or add the following line:

$cfg['LoginCookieValidity'] = 86400;

Refresh your logged out phpMyAdmin and presuming you haven’t left it idle for 24 hours, you’ll be logged in again!

If the time limit really bugs you, you need http authentication. Look for the “auth_type” line in the config.inc.php and change that to “http”. phpMyAdmin won’t log you out as long as your browser is open. Perfect!

If you’re concerned about sending your MySQL username and password in the clear each time you make a request to phpMyAdmin you can either use SSL or try the “config” auth_type. Make sure you fill in the username and password fields in the config file, and secure the phpMyAdmin directory with a htpasswd file.

Ping. The ping heard across the world

If you’re wondering why trackbacks and pings aren’t working on your blog then you might want to do what I did earlier today: allow your blog to talk to other servers.

WordPress needs either allow_url_fopen to be set On or to have the Curl extension loaded. If you’re having problems receiving pings from other blogs then both of these are probably turned off or missing. Wouldn’t it be nice if Options->Discussion warned that pings wouldn’t work?

Look in your php.ini, or the output of phpinfo() to check for both. If you want to enable fopen, then the entry in php.ini should look like this:

;;;;;;;;;;;;;;;;;;
; Fopen wrappers ;
;;;;;;;;;;;;;;;;;;

; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
allow_url_fopen = On

I switched to Litespeed web server a while back and by default allow_url_fopen is set to Off and the curl library isn’t included. Check /opt/lsws/php/php.ini and make sure remote fopens are allowed!

Thanks Barry for helping me fix that.

PS. if you linked to this blog recently, feel free to save your post again. WordPress will ping my site again and this time the ping will get through.

Donncha's Thursday Links

I have to admit, I preferred how WP 2.2 displayed lots of draft posts on the edit and post pages. Having to go to the Write page and click on the “54 more” link is annoying. For some reason, this post didn’t show up as the newest draft. Now it does, maybe because I deleted another (newer) draft post of the same name. When I created another “Donncha’s Thursday Links” post it didn’t show in the drafts list either. I had to search the drafts posts for “donncha” and it appeared at the bottom of that list. Strange.

I should get used to having my photos ripped off, but I don’t think I ever will. It’s as upsetting now as it ever was.

PS. Ray D’Arcy appears on the Restaurant tonight on RTE 1 at 8.30pm!

Is your eAccelerator cache dir still there?

While looking through this WordPress performance post I realised that eAccelerator might not be running properly on this blog. For some time I’ve noticed this site hasn’t been as quick off the mark as it used to be. Dare I say it, but it was even a little sluggish!

If you’re not familiar with it, eAccelerator is a PHP accelerator. It caches PHP bytecode and performs optimizations to make your PHP site run a lot faster.

I verified that eAccelerator was loaded and then checked my php.ini configuration. Sure enough, the eaccelerator.cache_dir directive was set to “/tmp/eacc/” and that directory was deleted the last time my server rebooted.

A permanent fix is to change the location of the cache dir. Put it anywhere the webserver can read, but don’t put it in /tmp/.

While you’re looking at eAccelerator, upgrade to the latest version, especially if you’re running PHP5.

Notes when upgrading to PHP5

I upgraded one of my servers to PHP5 this morning. Two things to watch out for:

  • The location of your php.ini may have changed. It’s probably now in /etc/php5/apache2/. You need to copy over any changes from your old one.
  • Update your libraries too such as the mysql client and the gd library. Don’t forget you can delete the old ones. apt-get install php5-mysql php5-gd will do the job of installing, the old packages have a php4 prefix.
  • WP-Cache doesn’t like PHP5 much. If you see a blank page after upgrading to PHP5, then hit reload and it loads, then WP-Cache needs to be modified. Leroy has the fix, open wp-cache-phase2.php in your wp-cache folder and change ob_end_clean() to ob_end_flush(). SImple as that!

The reason for the upgrade? I wanted to install the gd extension, but after lots of fun upgrading everything my browser tried to download every page, complaining that it was a phtml file. I chose the upgrade to PHP5 to fix it!

And finally, the reason for gd, was to get the heatmap in this wordpress click tracking plugin working. It’s like Crazy Egg and it works well, but I couldn’t get it to display a heatmap for any page other than the front page. Some of the comments on Daily Blog Tips where I found it are hilarious. They completely miss the point of using a heatmap!

Cannot load mysql extension. Please check your PHP configuration.

A friend recently had a problem configuring a new server. He installed PHP, Apache, MySQL and phpMyAdmin but when he launched it he got the following error:

phpMyAdmin – Error
Cannot load mysql extension. Please check your PHP configuration.

If you’ve installed all of the above more than once you’ll know what is more than likely wrong. The MySQL PHP module isn’t loaded. First of all, you must find your php.ini. It could be anywhere but if you create a small php file with the phpinfo(); command it will tell you where it is. Common places include /etc/apache/, /etc/php4/apache2/php.ini, /etc/php5/apache2/php.ini or even /usr/local/lib/php.ini

Edit your server’s php.ini and look for the following line. Remove the ‘;’ from the start of the line and restart Apache. Things should work fine now!

;extension=mysql.so

should become

extension=mysql.so

Killing off PHP

Do you know why Apache processes get stuck and stop responding when serving pages on a WordPress site?

I’ve seen this happen here and on my previous host on a regular basis. I don’t know what happens. It can’t be a PHP script gone into an infinite loop because the normal Apache timeout should kill it. It’s not MySQL as a quick inspection of the process list usually shows it’s empty.

It could be plugins, some of them haven’t been written to the high standards that is expected in WordPress core. It could be some strange interaction between plugins and core code and memory limits and PHP extensions.

Whatever causes it, this will fix it. It’s brutal, it’s crude, but it’ll stop the load average going up on your box and it will ensure that every Apache child process is listening and responding. Add this to the crontab of your nobody or www-data user. Pick whichever user runs the webserver because you want to limit the damage in case something bad happens and the command malfunctions!
*/10 * * * * ps auxw|grep apache2| awk '$10 !~ /0:00/ {print $2":"$10}'|awk -F ':' '$2 !~ 0 {print $1}'|xargs kill -9 2> /dev/null
What this does is it uses the ps, grep, and awk tools to find processes that are using anything more than the minimum CPU time. It is very crude, but it works.

If you use Litespeed, then replace “apache2″ with “lsphp”. I have found that this is very necessary as those processes get stuck quite often, especially in low memory situations.

Simple UTW Performance Boost

The Ultimate Tag Warrior plugin for WordPress is a great plugin. It does the job of handling tags rather well. I’ve noticed many hits from Google searches that go to a tag page instead of a category page of the same name so there’s something there that Google likes. I love it! Christine Davis did a super job filling a niche with the “ultimate” tool that anyone could want.
Unfortunately what isn’t so good is what goes on behind the scenes:

  1. UTW ignores your default category when saving your posts. Why ignore the default category when that is probably the subject you care most about? On my photoblog, In Photos.org my default category is “photos” and I certainly want people to find my images.
  2. UTW does an expensive SQL JOIN when it can’t find any tags for a post. Remember what I said about the default category? If you primarily post to your default category then every time someone sends you a request your server will get bogged down trying to find a non-existant record. It’s really bad when you have several years of posts and thousands of records in there.
  3. If you’re not going to use the fancy AJAX tag search then don’t load the associated Javascript. It saves an extra request on the first page load, and the browser doesn’t have to process the file.

Here is a patch that addresses those issues. It needs to be edited before you use it because you have to add a default tag. Here’s how to install it:

  1. Decide on a useful default tag. For this blog I use “holy-shmoly”. Open your WordPress database with phpmyadmin and look in wp_post2tag (the name may be different depending on your prefix). If you have already used the tag then find it and note down the tag_id of that tag. Otherwise, add your tag and note the new tag_id.
  2. Edit utw-patch.diff and look for the strings DEFAULT_TAG_NAME and DEFAULT_TAG_ID and replace with the name and id you picked out in the last step.
  3. To apply the patch, copy it into your wp-content/plugins/UltimateTagWarrior/ directory and run the following command.

    patch -p0 < utw-patch.diff

  4. If you don’t have access to patch, then open utw-patch.diff in your favourite editor and make as much sense of it as you can. It’s not hard once you have the source files open as well.

I’ve noticed a significant drop in server spikes since I made those changes. It takes a while for the default tag to be populated as it’s done when posts are visited but once it’s finished you should see a marked improvement. Oh, and install WP-Cache 2.0 as well. That’ll help you ride out the occasional digg!

Download the patch: utw-patch.diff for UTW 3.14159 for WordPress 2.0

By request, here are the modified files. Rename .txt to .php and copy them into your plugins/UltimateTagWarrior/ directory, overwrite the originals:

  1. ultimate-tag-warrior-actions-wordpress2.txt
  2. ultimate-tag-warrior-actions.txt
  3. ultimate-tag-warrior-core.txt