Statify dynamic images from timthumb

Just to remind: we are going through WordPress performance optimization stage 2 (after 3x speed from Stage 1) and focusing on decrease of number (or payload) of HTTP requests. Last several posts were devoted to CSS images optimization. We reduced their number and reviewed some well-known techniques to perform this automatically (or semi-automatically).
Before we start with actual HTML images distribution through multiple hosts (yes, it’s the most powerful technique here) we need to prepare our thumbnail library – timthumb – to be more fast and reliable.
Why dynamic images are evil?
Frankly speaking it’s very convenient – to upload only one image to the website and create thumbnails of any size from it. But let’s reveal this anti-pattern of web performance optimization. For this image (from the last post)

We have the following timings (get by webo.name).

Here we have about 12ms – it’s too much (but we remember – we are working on a weak shared hosting, it’s a miracle that website can load so fast here) for server side expenses. And for a dynamic equivalent for this static image we have the following figure.

It’s about 8ms difference. It’s not so much, isn’t it? Really?
For the home page we have 3 large dynamic images (slide show) and 3 smaller (for the slide show too). 16 images x 8ms = 128ms. It’s still not so much but if we compare these expenses with our home page (and every HTML cached page) timings we can see that dynamic image generation ‘eats’ more than 6x from just HTML document response time.
And with every hit to the home page we lose 130ms (and can’t serve 5x more hits with our shared hosting). Please note – this is about home page, pagination and archives pages (with a lot of thumbnails) only. On single post pages there are only 6 such images – mush less but still 2x losses.
How to fix this?
Well the idea is clear enough. We need to create mnemonic file names for each dynamic image (as you remember we actually enabled their caching on Stage 1). And then just add little rewrite magic to .htaccess (sorry if you are not using Apache, maybe you can create the same rules for nginx, lighttpd, or something else) to check cached thumbnail existence and serve it instead of calling dynamic script.
Starting with timthumb.php
We are going to wp-content/themes/bacipress/ (it’s our timthumb.php actual location – it seems to be in the curent theme folder). Cache files are named like md5 hash. So let’s look for a function md5 whch can perform such transformation.
On the line 338 there is
$cache_file = md5( $cachename ) . '.' . $ext;
It seems it’s what we are looking for.
File name is calculated in these 2 lines (this one and the one above).
$cachename = get_request( 'src', 'timthumb' ) ... $cache_file = md5( $cachename ) . '.' . $ext;
So we need to change logic of $cachename creation. And remove md5 (because md5 sum calculation with every Apache redirect will be very heavy). These two lines have been transformed to
$filename = preg_replace("@http://[^/]+/(.*)\.$ext$@", "$1", get_request( 'src', 'timthumb' ));
$cachename = $filename . '-' .
get_request( 'w', 100 ) . '-' .
get_request( 'h', 100 ) . '-' .
get_request( 'zc', 1 ) . '-' .
get_request( '9', 80 );
$cache_file = $cachename . '.' . $ext;There are several changes:
- We have added correct file name calculation (from the website root) – and removed from it actual file extension (because we need to add some parameters, and this extension is added a bit lower).
- We have just added dashes in
$cachenamefor better readability. - And we have removed
md5from$cache_file.
So we have replaced initial 2 lines with these 7 ones.
Also we need to change default cache directory to the website root (so all thumbnails will be placed exactly near source files). It’s line 39 in file timthumb.php:
$cache_dir = './';
Please change it to the following one.
$cache_dir = '../../../';
OK. Now all our images are placed regarding there location in the website structure. It’s a half of our optimization.
Finishing with .htaccess
The last part is to add some RewriteEngine magic to our .htaccess. Let’s find there the following strings (in BEGIN WordPress part).
RewriteEngine On RewriteBase /
The last one can be commented or absent – it isn’t required if we are working with WordPress located in the document root of the website. OK. Please insert here (under these rules) the following lines.
RewriteCond %{SCRIPT_FILENAME} timthumb\.php
RewriteCond %{QUERY_STRING} src=http:\/\/[^\/]+\/(.*)\.(png|jpe?g)&w=([0-9]+)&h=([0-9]+)&zc=([0-9]+)
RewriteCond YOUR_HOME_DIRECTORY/%1-%3-%4-%5-80.%2 -f
RewriteRule .* /%1-%3-%4-%5-80.%2 [L]This can be a bit complicated but let’s review what they perform. The first one
RewriteCond %{SCRIPT_FILENAME} timthumb\.phpchecks if any dynamic image (served via timthumb.php) is requested.
The second one
RewriteCond %{QUERY_STRING} src=http:\/\/[^\/]+\/(.*)\.(png|jpe?g)&w=([0-9]+)&h=([0-9]+)&zc=([0-9]+)computes GET parameters (from query string) to get image file name, its extension, width, and height. Please note there is no quality parameter. If your images URLs look different (with additional GET parameter) please add it to this rule.
The third one
RewriteCond YOUR_HOME_DIRECTORY/%1-%3-%4-%5-80.%2 -f
checks if there is file with requested name (we create such files after the first request with fixes to timthumb.php described above). Variables (%1, %2, %3, %4, %5) are computed from the second rule (expressions in curly brackets).
Small note: how to get your home directory? Some of WordPress plugins can your this information but you can also create in the website root a file rootdir.php with the following content
<?php echo $_SERVER['DOCUMENT_ROOT'] ?>
and copy its output (after you open it in browser). It will be YOUR_HOME_DIRECTORY. Please don’t forget to delete this file after you get this info.
And the last Rewrite rule
RewriteRule .* /%1-%3-%4-%5-80.%2 [L]
just redirects (internally, without no subsequent redirect – flag [L]) to the end file name. Great.
All this has resulted into less response time.

Not 12ms for the really static file but also not 20ms for dynamic (cached) image.
Conclusion
With quite a few changes in timthumb.php and .htaccess we can gain a bit more performance from our website and get it ready for multiple domains usage (which will be discussed in the next blog post). For the home page actual savings are about 15-20ms, or less than 1% (because all images are load in 3-4 chunks of parallel flows). This improvement can save a bit for dedicated server but for a shared hosting it improves the whole website efficiency (because we save server expenses and can show more pages to our visitors without overload).
1 RESPONSES TO Statify dynamic images from timthumb