6

im having trouble setting the Etag on a user's browser reliably. When a user clicks on one of my external links, i would like to set the article id into their Etag (i use cookies too, but id like to experiment with Etag specifically to test its reliability).

When the same user returns to my site a few hours/days later, i would like to be able to read the Etag value and use it for stuff.

I can set an Etag on the initial click, but when the user returns the Etag value is gone. I assume its expired or something. Here is the code i have been trying:

<?

$time = 1280951171;
$lastmod = gmdate('D, d M Y H:i:s \G\M\T', $time);
$etag = '123';


$ifmod = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $lastmod : null; 
$iftag = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? $_SERVER['HTTP_IF_NONE_MATCH'] == $etag : null; 

if (($ifmod || $iftag) && ($ifmod !== false && $iftag !== false)) { 
    header('HTTP/1.0 304 Not Modified'); 
} else {
    header("Last-Modified: $lastmod"); 
    header("ETag: $etag");
}

print_r($_SERVER);

?>
Peter John
  • 1,859
  • 4
  • 15
  • 14

2 Answers2

5

You should be wrapping your etag in double quotes (as the link Codler mentioned shows):

'"' . $etag . '"'

I don't think it's likely to solve your problem, but you probably want

header('Not Modified',true,304);

instead of

header('HTTP/1.0 304 Not Modified');

As of PHP 5.4 there's a better way to do this with http_response_code:

http_response_code(304);

Also, have you checked for the usual suspects stopping headers? Unicode Byte-Order Markers are very annoying with this. (Disregard if you can see other headers you're setting yourself)

Alan Pearce
  • 1,320
  • 10
  • 17
  • awesome stuff!! the "" is what i was missing :-) Thanks! – Peter John Aug 12 '10 at 11:40
  • Actually, the `header('Not Modified',true,304);` syntax resulted in a "500 Internal Server Error" on my Wordpress web. The original syntax seems to be safer. – Sphinxxx Dec 10 '14 at 02:18
  • 1
    @Sphinxxx Unfortunately, that will be wrong for most web user agents which use HTTP/1.1 (which it why I recommended against hard-coding it). I've updated the post to include a 'new' function in PHP 5.4 that's preferable to the others. Try that instead. – Alan Pearce Dec 10 '14 at 09:44
  • @AlanPearce - Thanks for the update! I'll have to update to PHP 5.4, but in the meantime I found a different, clean-ish way to do this: Add the status code to a different header you were going to add, e.g. an ETag: `header("Etag: ".$my_etag, true, 304);`. My guess is that your proposed `header('Not Modified',..` solution doesn't work because "Not Modified" isn't a valid "Key: Value" header(?) – Sphinxxx Dec 12 '14 at 00:26
  • @Sphinxxx Yeah, that way works, although it's a bit confusing. Might need a comment! It's weird, I remember testing the previous version several years ago, so I presume it worked at some point. It's not a `Key: value` header because it's the status line – Alan Pearce Dec 12 '14 at 11:12
-3

Etag is not so reliable http://developer.yahoo.com/performance/rules.html#etags

Codler
  • 10,951
  • 6
  • 52
  • 65
  • Interesting link, thanks - although we just use one Web server, so it should hopefully be a decent fallback plan – Peter John Aug 12 '10 at 08:49
  • 3
    That's only true if ETags are generated in certain ways. "The problem with ETags is that they *typically* are constructed using attributes that make them unique to a specific server hosting a site." @PeterSmith is specifying his own ETags and can easily avoid doing this. – Matt Kantor Sep 16 '12 at 20:51
  • 6
    @Codler, etags are reliable when you use them correctly, and unreliable if you used them wrongly. – Pacerier Jul 28 '13 at 15:27