Back to blog
Jul 2018·2 min readAI-translated

Simple Image Resizing + Caching

#autoresize#cache-image#php#resize-image-php

Every now and then an existing image is needed in a different size. You can either use Photoshop to create an individually cropped version of the image for each case and embed those in the website (for this, Autopush - Simply Upload Changed Files might come in handy), but you can also do it on the fly with a PHP script. And to keep performance from suffering too much, you can cache the result as well, so the original image is only cropped if it hasn't already been cropped to the desired size before. All of this comes at the expense of some storage space, but with the manual version (cropping via Photoshop) it would be no different ;-)

The first thing we need is an .htaccess file that sends our .png, .jpg and .jpeg requests to a PHP script, which then does the rest of the work. Put the following in the .htaccess file so that every image file automatically runs through the PHP script:

RewriteRule ^(.*)\.(jpg|jpeg|png)/?([0-9]*)?/([0-9]*)?/?([0-1]{1})?$ parse_image.php?i=$1&e=$2&w=$3&h=$4&r=$5 [L,QSA]

The path to parse_image.php has to be adjusted, of course ;-) This htaccess rule does nothing other than intercept all files ending in jpg, jpeg or png and forward them to parse_image.php. In addition, 3 parameters can be given in path style, which are then processed by the PHP script (see below). If no parameters are passed, the "main image" is served without further changes. The additional parameters are

  • width of the output image (parameter 1)
  • height (parameter 2)
  • 1 or 0, depending on whether we want to keep the proportions or not (parameter 3)

We can then call it like this:

<img src="images/040.jpg/100/200/1">

images/040.jpg is the path to the image, the first value (100) is the width of the output image, the second (200) the height, and the third value indicates whether the image should be scaled proportionally or whether the desired area is simply "cut out". Here '1' - so the output is scaled proportionally. The script for caching and output looks like this: the constant "CACHEFOLDER" has to be adjusted to a folder PHP has read and write access to (otherwise we couldn't save the new image). As a little extra treat, the constant ALLOWED_TYPES specifies which MIME types are allowed and which are not.

# The folder where we cache the images
define("CACHEFOLDER", "cache/images/");
# Allowed types - here jpeg, jpg and png
define("ALLOWED_TYPES", ['image/jpeg', 'image/jpg', 'image/png']);
# We read the GET variable r (ratio) and store true or false in $keep_ratio accordingly
$keep_ratio = ($_GET['r'] == '1') ? true : false;
# The GET parameters are fetched and written to variables. You don't have to do this, of course, but it makes the whole process clearer
list($file, $ext, $dimensions['w'], $dimensions['h']) = [$_GET['i'], $_GET['e'], isset($_GET['w']) ? $_GET['w'] : 0, isset($_GET['h']) ? $_GET['h'] : 0];
# An MD5 hash is created from the file name, target width and target height and the information on whether the dimensions should be kept or not.
$hash = CACHEFOLDER . md5($file.$ext.$dimensions['w'].$dimensions['h'].(($keep_ratio) ? '1' : '0'));
# $file_src contains the complete path to the original file
$file_src = $file . '.' . $ext;
# If the original file is not one of the ALLOWED_TYPES above, we abort processing (it's not a png, jpg or jpeg image and the script was most likely called directly)
if (!in_array(mime_content_type($file_src), ALLOWED_TYPES)) die();
# If no file matching our hash exists, there is no cached version of our image and we create one.
# To do so, we first create a jpeg image from our original image, get the size of the image and then scale the image depending on the given parameters
if (!file_exists($hash)){
  $res['src'] = imagecreatefromjpeg($file_src);
  $filedata = getimagesize($file_src);
  if ($dimensions['w'] == 0 || $dimensions['h'] == 0) list($dimensions['w'], $dimensions['h']) = [$filedata[0], $filedata[1]];
  $res['dst'] = imagecreatetruecolor($dimensions['w'], $dimensions['h']);
  if ($keep_ratio === false){
    imagecopyresized($res['dst'], $res['src'], 0, 0, 0, 0, $dimensions['w'], $dimensions['h'], $filedata[0], $filedata[1]);
  }else{
    if ($filedata[0] && $filedata[1]) {
      $dst['h'] = $dimensions['h'];
      $dst['w'] = floor($filedata[0] * ($dimensions['h'] / $filedata[1]));
      $crop['x'] = ceil(($filedata[0] - $filedata[1]) / 2);
      $crop['y'] = 0;
    }else{
      $dst['w'] = $dimensions['w'];
      $dst['h'] = floor($filedata[1] * ($dimensions['w'] / $filedata[0]));
      $crop['x'] = 0;
      $crop['y'] = ceil(($filedata[1] - $filedata[0]) / 2);
    }
    imagecopyresampled($res['dst'], $res['src'], 0, 0, $crop['x'], $crop['y'], $dst['w'], $dst['h'], $filedata[0], $filedata[1]);
  }
  # Finally, we output our file.
  imagejpeg($res['dst'], $hash);
}
header('Content-Type: ' . mime_content_type($hash));
header('Content-Length: ' . filesize($hash));
readfile($hash);
Newer\"This copy of the Install OS X Sierra application can't be verified\"OlderSimple Template Engine