views:

146

answers:

5

I store all of my images behind the webroot (before /var/www/), which means that the web server is unable to send cache headers back for my pictures. What do I need to add to this to make the user's web cache work? Currently, this is getting hit every time by the same browser.

My <img> path on my pages look something like this:

<img src="pic.php?u=1134&i=13513&s=0">

Edit: Could it be that it is because "pic.php?u=1134&i=13513&s=0" is not a valid file name or something?

// pic.php
<?php

    // open the file in a binary mode
    $user = $_GET['u'];
    $id = $_GET['i'];
    $s = $_GET['s'];

    if (!isset($user) && !isset($s) && $isset($id))
    {
     // display a lock!
     exit(0);
    }

    require_once("bootstrap_minimal.php"); //setup db connection, etc

    // does this image_id belong to the user?
    $stmt = $db->query('SELECT image_id, user_id, file_name, private FROM images WHERE image_id = ?', $id);
    $obj = $stmt->fetchObject();

    if (is_object($obj))
    {
     // is the picture is the users?
     if ($obj->user_id != $_SESSION['user_id'])
     {
      // is this a private picture?
      if ($obj->private == 1)
      {
       // check permissions...
       // display a lock in needed!
      }
     }
    }
    else
    {
     // display a error pic?!
     exit(0);
    }

    if ($s == 0)
    {
     $picture = $common->getImagePathThumb($obj->file_name);
    }
    else
    {
     $picture = $common->getImagePath($obj->file_name);
    }

    // send the right headers
    header("Content-Type: image/png");
    header("Content-Length: " . filesize($picture));

    $fp = fopen($picture, 'rb');

    // dump the picture and stop the script
    fpassthru($fp);
    exit;
?>
+2  A: 

Apache only caches static files by default. You need to send a cache control header via the header() function. This article has a lot of information on the topic.

Alternatively, you could use the PHP file to redirect to the actual location of the image. (This is probably the easiest way if you don't know anything about headers.)

musicfreak
Redirecting to the image location is no use if the image isn't under the document root or a suitable alias, which also defeats the purpose of putting it behind an authentication check.
Rob
It was just an alternative that I threw out there. If it doesn't apply to your setup, don't use it. I don't see why I was downvoted for that.
musicfreak
A: 

What I would do in your situation is to stream the bytes of the image using a .php file. Don't link to images directly; instead, link to a php file that: - outputs the cache headers - reads the file off of disk, from behind the webroot - sends the image bits down the wire

Alex
+4  A: 

You need to add something like:

$expiry = 3600*24*7; // A week
header('Expires: ' . gmdate('D, d M Y H:i:s' time() + $expiry) . ' GMT');
header('Cache-control: private, max-age=' . $expiry);
Greg
It looks like the images are being protected behind some authentication, so that Cache-control header needs to specify private caching; no public storage.
Rob
missing a ')' after ' GMT'. Works great, TY!
Mike Curry
Also ty Rob, I changed 'public' to 'private'
Mike Curry
Thanks for the comments - updated the answer
Greg
A: 

Simple answer: you aren't telling your users' browser to cache it

Andrew G. Johnson
+1  A: 

You might try:

header("Cache-Control: max-age=3600");

That should send a cache timeout of one hour on the file.

Kazar