Fork me on GitHub

Image Cache using phpThumb and Mod_Rewrite

Posted by Mr PHP on

Generate thumbs by visiting a URL such as your.com/thumbs/50x50/images/image.jpg. This will create a 50x50px thumbnail of your.com/images/image.jpg.

The thumb will be stored on your server at your.com/thumbs/50x50/images/image.jpg so the next request for the same image will be loaded without loading php for ultra fast image cache.

Introduction

About a year ago I came across a fantastic script called phpThumb. It is an open source project used to resize images. Sure you can do the same thing with tools such as GD2 or imagemagick (or magickwand), however its much nicer to not have to worry about those things and just focus on getting the right image with ease.

It was as easy as

<img src="/phpthumb/phpThumb.php?src=myimage.jpg&w=100&h=100">

The problems started to arise on high-volume servers when apache had to get PHP to parse the phpThumb code for every image requested. Sure it has caching but it still has to load PHP to decide if it should use the cache or not.

In the past I have seen this issue solved using mod_rewrite to redirect non-existent images to a script where they can be generated. As a proof-of-concept I will provide the basic information required to get this running.

What you need

  • Apache
  • mod_rewrite
  • PHP

These things usually come with dedicated and shared hosting servers by default, however installation is beyond the scope of this article.

Ok, just tell me how to do it!

Upload phpThumb

Download phpThumb from here: http://phpthumb.sourceforge.net/

Upload phpThumb to yoursite.com/phpthumb

Setup Rewrite

Apache mod_rewrite

Create yoursite.com/thumbs/.htaccess

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^(.*)$ index.php?thumb=$1 [L,QSA]
</IfModule>

Nginx Rewrite

http {
	server {
        listen 80;
        root /app/pictures;
        index index.php;
        # thumbs
        location ^~ /thumbs/ {
            try_files $uri $uri/ /thumbs/index.php?$args;
            # send php files to phpfpm
            location ~ \.php$ {
                include /etc/nginx/fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
                fastcgi_pass php:9000;
                try_files $uri =404;
            }
        }
        # send php files to phpfpm
        location ~ \.php$ {
            include /etc/nginx/fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
            fastcgi_pass php:9000;
            try_files $uri =404;
        }
    }
}

Create the Thumbnail Generator

Create yoursite.com/thumbs/index.php

<?php
/**
 * Create a thumbnail
 *
 * @author Brett @ Mr PHP
 */
 
// define allowed image sizes
$sizes = array(
	'157x153',
	'600x600',
);

// ensure there was a thumb in the URL
if (!$_GET['thumb']) {
	error('no thumb');
}

// get the thumbnail from the URL
$thumb = strip_tags(htmlspecialchars($_GET['thumb']));

// get the image and size
$thumb_array = explode('/',$thumb);
$size = array_shift($thumb_array);
$image = '../'.implode('/',$thumb_array);
list($width,$height) = explode('x',$size);

// ensure the size is valid
if (!in_array($size,$sizes)) {
	error('invalid size');
}

// ensure the image file exists
if (!file_exists($image)) {
	error('no source image');
}

// generate the thumbnail
require('../phpthumb/phpthumb.class.php');
$phpThumb = new phpThumb();
$phpThumb->setSourceFilename($image);
$phpThumb->setParameter('w',$width);
$phpThumb->setParameter('h',$height);
$phpThumb->setParameter('f',substr($thumb,-3,3)); // set the output format
//$phpThumb->setParameter('far','C'); // scale outside
//$phpThumb->setParameter('bg','FFFFFF'); // scale outside
if (!$phpThumb->GenerateThumbnail()) {
	error('cannot generate thumbnail');
}

// make the directory to put the image
if (!mkpath(dirname($thumb),true)) {
        error('cannot create directory');
}

// write the file
if (!$phpThumb->RenderToFile($thumb)) {
	error('cannot save thumbnail');
}

// redirect to the thumb
// note: you need the '?new' or IE wont do a redirect
header('Location: '.dirname($_SERVER['SCRIPT_NAME']).'/'.$thumb.'?new');

// basic error handling
function error($error) {
	header("HTTP/1.0 404 Not Found");
	echo '<h1>Not Found</h1>';
	echo '<p>The image you requested could not be found.</p>';
	echo "<p>An error was triggered: <b>$error</b></p>";
	exit();
}
//recursive dir function
function mkpath($path, $mode){
    is_dir(dirname($path)) || mkpath(dirname($path), $mode);
    return is_dir($path) || @mkdir($path,0777,$mode);
}

Test it out!

Upload an image to yoursite.com/images/myimage.jpg.

Open your web browser to yoursite.com/thumbs/100x100/images/myimage.jpg

Check in your thumbs folder, the file should actually be there now. Next time it is requested PHP will not be loaded.

Link to your thumbs like this:

<img src="/thumbs/100x100/images/myimage.jpg">

Clearing Cache

This is a small script I use to delete all the cached thumbs.

Upload an image to yoursite.com/thumbs/flush.php.

<?php

delete_dir('./images');
echo 'done';

function delete_dir($path) {
	$files = glob($path.'/*');
	foreach($files as $file) {
		if(is_dir($file) && !is_link($file)) {
			delete_dir($file);
		}
		else {
			unlink($file);
		}
	}
	if ($path!='./images') rmdir($path);
}

Tagged with : PHP, Performance


Comments