1

I am using this great randomizer code found here: http://alistapart.com/article/randomizer , but the images are not saved on the browser's cache which means they refresh whenever the site reloads.

Is it possible to keep the images cached on the following code? The reason I am using this script is that php parse on css doesn't work on my server for some reason.

<?php

$folder = '.';
$extList = array();
    $extList['gif'] = 'image/gif';
    $extList['jpg'] = 'image/jpeg';
    $extList['jpeg'] = 'image/jpeg';
    $extList['png'] = 'image/png';

$img = null;

if (substr($folder,-1) != '/') {
    $folder = $folder.'/';
}

if (isset($_GET['img'])) {
    $imageInfo = pathinfo($_GET['img']);
    if (
        isset( $extList[ strtolower( $imageInfo['extension'] ) ] ) &&
        file_exists( $folder.$imageInfo['basename'] )
    ) {
        $img = $folder.$imageInfo['basename'];
    }
} else {
    $fileList = array();
    $handle = opendir($folder);
    while ( false !== ( $file = readdir($handle) ) ) {
        $file_info = pathinfo($file);
        if (
            isset( $extList[ strtolower( $file_info['extension'] ) ] )
        ) {
            $fileList[] = $file;
        }
    }
    closedir($handle);

    if (count($fileList) > 0) {
        $imageNumber = time() % count($fileList);
        $img = $folder.$fileList[$imageNumber];
    }
}

if ($img!=null) {
    $imageInfo = pathinfo($img);
    $contentType = 'Content-type: '.$extList[ $imageInfo['extension'] ];
    header ($contentType);
    readfile($img);
} else {
    if ( function_exists('imagecreate') ) {
        header ("Content-type: image/png");
        $im = @imagecreate (100, 100)
            or die ("Cannot initialize new GD image stream");
        $background_color = imagecolorallocate ($im, 255, 255, 255);
        $text_color = imagecolorallocate ($im, 0,0,0);
        imagestring ($im, 2, 5, 5,  "IMAGE ERROR", $text_color);
        imagepng ($im);
        imagedestroy($im);
    }
}

?>
Tasos
  • 1,622
  • 4
  • 28
  • 47

3 Answers3

3

You can instruct a user's browser to cache your page for a really long time (up to a year, shown below), by specifying the cache duration in the header:

header('Cache-Control: max-age=31556926');

There are two caveats to this, however. First, browsers won't necessarily follow the caching instruction, and may choose to download a new copy of the image anyway. Second, this line must be placed somewhere on your page before any content.

IanPudney
  • 5,941
  • 1
  • 24
  • 39
3

Generating an E-tag and Cache-Control header will help you like this

<?php
  $folder   = '.';
  $extList  = array( "gif", "jpg", "jpeg", "png" );
  $image    = false;

  if ( substr( $folder, -1 ) != '/' ) {
    $folder = $folder.'/';
  }

  if ( isset( $_GET["img"] ) ) {
    $imageExtn  = strtolower( pathinfo( $_GET["img"], PATHINFO_EXTENSION ) );
    $imageName  = basename( $_GET["img"] );
    if ( in_array( $imageExtn, $extList ) && file_exists( $folder.$imageName ) ) {
      $image  = $folder.$imageName;
    }
  }
  else {
    $fileList = array();
    $handle   = opendir( $folder );
    while( false !== ( $file = readdir( $handle ) ) ) {
      $fileExtn = strtolower( pathinfo( $file, PATHINFO_EXTENSION ) );
      if ( in_array( $fileExtn, $extList ) ) {
        $fileList[] = $file;
      }
    }
    closedir( $handle );

    if ( !empty( $fileList ) ) {
      $imageNumber  = time() % count( $fileList );
      $image  = $folder.$fileList[$imageNumber];
    }
  }

  if ( $image !== false ) {
    $contents = implode( "", file( $image ) );
    $md5  = md5( $contents );
    $mtime  = filemtime( $image );
    $etag = etag( $md5, $mtime );

    $r_mtime  = 0;
    $r_etag   = null;

    if ( isset( $_SERVER["HTTP_IF_MODIFIED_SINCE"] ) ) {
      $r_mtime  = strtotime( $_SERVER["HTTP_IF_MODIFIED_SINCE"] );
    }
    if ( isset( $_SERVER["HTTP_IF_NONE_MATCH"] ) ) {
      $r_etag   = trim( $_SERVER["HTTP_IF_NONE_MATCH"] );
    }

    if ( $mtime == $r_mtime && $r_etag == $etag ) {
      header( "HTTP/1.0 304 Not Modified", true, 304 );
      header( "HTTP/1.1 304 Not Modified", true, 304 );
      header( "Content-length: 0" );
      exit;
    }

    header( "Content-type: image/".strtolower( pathinfo( $image, PATHINFO_EXTENSION ) ) );
    header( "Last-Modified: ".gmdate( "D, d M Y H:i:s", $mtime )." GMT" );
    header( "ETag: ".$etag );
    header( "Expires: ".gmdate( "D, d M Y H:i:s", time()+3600 )." GMT" );
    header( "Cache-Control: max-age=3600" );
    header( "Cache-Control: public" );

    echo $contents;
    exit();
  }
  else {
    if ( function_exists( "imagecreate" ) ) {
      header( "Content-type: image/png" );
      $im = @imagecreate( 100, 100 ) or die( "Cannot initialize new GD image stream" );
      $background_color = imagecolorallocate( $im, 255, 255, 255 );
      $text_color = imagecolorallocate( $im, 0, 0, 0 );
      imagestring( $im, 2, 5, 5,  "IMAGE ERROR", $text_color );
      imagepng( $im );
      imagedestroy( $im );
    }
  }

  function etag( $string_1 = null, $string_2 = null, $quote = true ) {
    $quote  = ( $quote ) ? '"' : '';
    $etag   = sprintf( $quote."%s-%s".$quote, $string_1, $string_2 );
    return $etag;
  }
?>
bystwn22
  • 1,776
  • 1
  • 10
  • 9
1

One solution is to use a cookie to store the image you've sent to the user, and always send that image:

if(!isset($_COOKIE['imgCookie']))
{
    //runs if the user doesn't have the cookie
    //run randomizer code
    //setcookie('imgCookie',$imageNumber);
} else {
    //runs if the user already has the cookie
    $imagenumber=$_COOKIE['imgCookie'];
}
//run code for sending image to user
IanPudney
  • 5,941
  • 1
  • 24
  • 39
  • Is there any way of doing this without using cookies? Also, although this code is from 2003, it works fine but I was wondering if there is an easier way of achieving the same thing? – Tasos Jun 25 '13 at 13:05
  • 1
    I've added another answer. – IanPudney Jun 25 '13 at 13:17