views:

747

answers:

5

I am serving images through php and having some problems setting it up to respond with 304 headers to save on load time.

Most of the code below I found on php.net. It works, however ALWAYS responds with 200. For some reason the If-Modified-Since header is not being received on any requests even though I am sending the Last-Modified header initially. This is being done on an apache server. Any idea what might be wrong?

Example: http://tinyurl.com/mcku6c

This page will load the image from disk and display it to browser, along with sending a Last-Modified header. If you refresh the page, the browser doesn't send a If-Modified-Since header like it should.

define('SITEPATH', (dirname($_SERVER['SCRIPT_NAME']) == '/') ? '/' : dirname($_SERVER['SCRIPT_NAME']).'/');

$load_path = $_SERVER['DOCUMENT_ROOT'] . SITEPATH . 'fpo_image.jpg';

// Get headers sent by the client.
$headers  = apache_request_headers(); 
$file_time = filemtime($load_path);

header('Cache-Control: must-revalidate');
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $file_time).' GMT');

if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) == $file_time)) {

 header('HTTP/1.1 304 Not Modified');
 header('Connection: close');

} else {

 header('HTTP/1.1 200 OK');
 header('Content-Length: '. filesize($load_path));
 header('Content-type: image/jpeg');       

 readfile($load_path);

}
+1  A: 

I believe it should be

if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) >= $file_time)) {

Checking if the modified time is greater than or equal rather than just equal. Although I do understand the two values should be the same.

anveo
Any idea why the 'If-Modified-Since' is not being received by php for subsequent requests? I am debugging the $headers value and it never shows up in there. Supposedly all you have to do is set a 'Last-Modified' and it should show up.
Louis W
Are you sure your browser is sending it? Use a plugin like LiveHTTPHeaders to verify that. Also when I do it I use $_SERVER[] rather than apache_request_headers()
anveo
Yea, I checked both _SERVER and apache_request_headers() very strange. Maybe I should put up an example to show.
Louis W
A: 

Demo added... Don't know how to bump this up...

Louis W
Tested your example with FF3.5 and IE8, works as expected (used Fiddler2 to verify).
mark
A: 

mandor at mandor dot net posted a solution at the PHP.net documentation for the header function which worked for me:

<?php

        // Test image.
        $fn = '/test/foo.png';

        // Getting headers sent by the client.
        $headers = apache_request_headers();

        // Checking if the client is validating his cache and if it is current.
        if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) == filemtime($fn))) {
            // Client's cache IS current, so we just respond '304 Not Modified'.
            header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($fn)).' GMT', true, 304);
        } else {
            // Image not cached or cache outdated, we respond '200 OK' and output the image.
            header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($fn)).' GMT', true, 200);
            header('Content-Length: '.filesize($fn));
            header('Content-Type: image/png');
            print file_get_contents($fn);
        }

    ?>
Keith
A: 

After searching for a while, I've found the answer. The browser didn't cached anything (and didn't send the If-Modified-Since) until I sent the following header:

Cache-Control: private;

After doing this all worked fine.

Zsolti
A: 

Check if sessions are being used on that page, If so, try this:

session_cache_limiter(false);

If the above worked, here's the explanation:

Php's session mechanism sends some automatic cache-related headers in order to improve the session cookie privacy, avoiding it to be cached by intermediate proxyes:

http://php.net/manual/en/function.session-cache-limiter.php

These automatic headers cause the browser not to ever send the If-Modified-Since header, as they instruct it to not to perform any caching at all.

azkotoki