Creating and Caching Image Thumbnails in PHP using GD and Supporting IF_MODIFIED_SINCE HTTP Header

This is not a tutorial, just some source code that might help you out if you’re looking for hints.

The code below won’t run for you out of the box because you don’t have my framework, but here is a brief explanation of what it does:

If a browser requests a URI like /image/some-image-slug.jpg then “some-image-slug” is looked up and the product ID associated with it is used to reference the image files.

The URI path can include “full” or “thumb” before the slug, like /image/thumb/some-image-slug.jpg.

If the cached image doesn’t exist or is older than the original, then the full or thumb image is remade.

The file modification time of the cached image is used to manage the IF_MODIFIED_SINCE stuff…

My original lesson on IF_MODIFIED_SINCE was found here:
Caching Behavior of Web Browser (pdf)

This post was quite helpful:
If-Modified-Since HTTP Header – How to Use with PHP

This was also helpful:
Creating Thumbnails with PHP using the GD Library

<?php
  define
(“_SC_FRAME”true);
 
  
$maxWidths = array(“full” => 300“thumb” => 100);
 
  require_once(
“fw/fw.php”);
 
  
CONFIG::$debugEcho false;
 
  
$parts preg_split(‘///’preg_replace(‘/.[a-z]+$/’$_SERVER[‘REQUEST_URI’]), 4PREG_SPLIT_NO_EMPTY);
 
  if (
count($parts) >= 3) {
      
$size $parts[count($parts) – 2];
      if (
$size == “image”)
          
$size “full”;
      elseif (
$size != “full” && $size != “thumb”)
          
$size null;
  }
  
$slug $parts[count($parts) – 1];
 
 
  if (
count($parts) < || !$size) {
      
header(“Status: 400 Bad Request”);
      echo 
“400 Bad Request”;
      exit();
  }
 
  
$prodId DB::querySingleValue(“SELECT id FROM ” DB::table(“prods”) . ” WHERE slug = ” DB::esc($slug));
 
  if (!
$prodId) {
      
header(“Status: 404 Not Found”);
      echo 
“404 Not Found: $slug”;
      exit();
  }
 
 
  
$filename mapPath(“/sc/product-images/$size/$prodId.jpg”);
  
$original mapPath(“/sc/product-images/original/$prodId.jpg”);
 
  
$originalExists file_exists($original);
  
$filenameExists file_exists($filename);
 
  if (
$originalExists && $filenameExists && filemtime($original) > filemtime($filename)) {
      
// To avoid a delay in the system read of the modification time…
      // If you save over the same inode, the modification time seems to stick for a bit
      // on the system I’m using.  There’s probably a better way to do this.
      
unlink($filename);
      
$filenameExists false;
  }
 
  if (!
$filenameExists) {
      if (!
$originalExists) {
          
header(“Status: 404 Not Found”);
          echo 
“404 Not Found: $slug (no original)”;
          exit();
      }
     
     
      list(
$width$height) = getimagesize($original);
     
      if (
$width <= $maxWidths[$size]) {
          
copy($original$filename);
          
//debug_str(“copied”);
      
} else {
          
$modWidth $maxWidths[$size];
          
$modHeight $height $modWidth $width;
         
          
$tn imagecreatetruecolor($modWidth$modHeight);
         
          
$ext pathinfo($originalPATHINFO_EXTENSION);
         
          switch (
$ext) {
              case 
“jpg”:
                  
$image imagecreatefromjpeg($original);
                  break;
                 
              case 
“gif”:
                  
$image imagecreatefromgif($original);
                  break;
                 
              case 
“bmp”:
                  
$image imagecreatefromwbmp($original);
                  break;
                 
              case 
“png”:
                  
$image imagecreatefrompng($original);
                  break;
                 
              default:
                  
header(“Status: 500 Error”);
                  echo 
“500 Unknown original file extension [$ext]”;
                  exit();
          }
         
         
          
imagecopyresampled($tn$image0000$modWidth$modHeight$width$height);
          
imagejpeg($tn$filename);
          
//debug_str(“sampled”);   
      
}
  }
 
  
$lastModified filemtime($filename);
 
  if (
array_key_exists(“HTTP_IF_MODIFIED_SINCE”$_SERVER)) {
      
$if_modified_since strtotime(preg_replace(‘/;.*$/’$_SERVER[“HTTP_IF_MODIFIED_SINCE”]));
     
      
//debug_str( date(“r”,$if_modified_since) . ” ” . date(“r”,$lastModified));
     
      
if ($lastModified <= $if_modified_since) {
          
header(“Status: 304 Not Modified”);
          
//debug_str(“not modified”);
          
exit();
      }
  }
 
  
header(‘Content-type: image/jpeg’);
  
header(‘Last-Modified: ‘ gmdate(DATE_RFC1123$lastModified));
 
  
readfile($filename);
 
  
//debug_str(“sent”);?>

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.