How to get the browser to cache images, with PHP?

I'm totally new to how to cache images.

I output all images in a gallery with PHP, and want the images already shown, to be cached by the browser, so the PHP script don't have to output the same image again. All I want is the images to show up faster.

When calling an image I do like this:

<img src="showImage.php?id=601">

and the showImage.php-file does:

$id = (int) $_GET['id'];
$resultat = mysql_query("
    SELECT filename, id
    FROM Media 
    WHERE id = $id
");
$data = mysql_fetch_assoc($resultat);

...

//Only if the user are logged in
if(isset($_SESSION['user'])){
    header("Content-Type: image/jpeg");

    //$data['filename'] can be = dsSGKLMsgKkD3325J.jpg
    echo(file_get_contents("images/".$data['filename']."")); 
}

Solution 1:

First of all, if you're using sessions, you must disable session_cache_limiter (by setting it to none or public). Headers it sends are pretty bad for caches.

session_cache_limiter('none');

Then send Cache-Control: max-age=number_of_seconds and optionally an equivalent Expires: header.

header('Cache-control: max-age='.(60*60*24*365));
header('Expires: '.gmdate(DATE_RFC1123,time()+60*60*24*365));

For the best cacheability, send Last-Modified header and reply with status 304 and empty body if the browser sends a matching If-Modified-Since header.

header('Last-Modified: '.gmdate(DATE_RFC1123,filemtime($path_to_image)));

For brevity I'm cheating here a bit (the example doesn't verify the date), but it's valid as long as you don't mind browsers keeping the cached file forever:

if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
   header('HTTP/1.1 304 Not Modified');
   die();
}

Solution 2:

Here's some code I use for 304 header support:

  /**
   * @return false if not cached or modified, true otherwise.
   * @param bool check_request set this to true if you want to check the client's request headers and "return" 304 if it makes sense. will only output the cache response headers otherwise.
   **/     
  protected function sendHTTPCacheHeaders($cache_file_name, $check_request = false)
  {
    $mtime = @filemtime($cache_file_name);

    if($mtime > 0)
    {
      $gmt_mtime = gmdate('D, d M Y H:i:s', $mtime) . ' GMT';
      $etag = sprintf('%08x-%08x', crc32($cache_file_name), $mtime);

      header('ETag: "' . $etag . '"');
      header('Last-Modified: ' . $gmt_mtime);
      header('Cache-Control: private');
      // we don't send an "Expires:" header to make clients/browsers use if-modified-since and/or if-none-match

      if($check_request)
      {
        if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && !empty($_SERVER['HTTP_IF_NONE_MATCH']))
        {
          $tmp = explode(';', $_SERVER['HTTP_IF_NONE_MATCH']); // IE fix!
          if(!empty($tmp[0]) && strtotime($tmp[0]) == strtotime($gmt_mtime))
          {
            header('HTTP/1.1 304 Not Modified');
            return false;
          }
        }

        if(isset($_SERVER['HTTP_IF_NONE_MATCH']))
        {
          if(str_replace(array('\"', '"'), '', $_SERVER['HTTP_IF_NONE_MATCH']) == $etag)
          {
            header('HTTP/1.1 304 Not Modified');
            return false;
          }
        }
      }
    }

    return true;
  }