HTTP_ConditionalGet

Last-Modified is known : add Content-Length

Here, like the first example, we know the Last-Modified time, but we also want to set the Content-Length to increase cacheability and allow HTTP persistent connections. Instead of sending headers immediately, we first generate our content, then use setContentLength(strlen($content)) to add the header. Then finally call sendHeaders() and send the content.

Note: This is not required if your PHP config buffers all output and your script doesn't do any incremental flushing of the output buffer. PHP will generally set Content-Length for you if it can.

This script emulates a document that changes every 20 seconds.
This is version: Mon, 23 Dec 2024 12:43:40 -0500

Notes

How to distinguish 200 and 304 responses

For these pages all 200 responses are sent in chunks a second apart, so you should notice that 304 responses are quicker. You can also use HTTP sniffers like Fiddler (win) and LiveHTTPHeaders (Firefox add-on) to verify headers and content being sent.

Browser notes

Opera
Opera has a couple behaviors against the HTTP spec: Manual refreshes (F5) prevents the ETag/If-Modified-Since headers from being sent; it only sends them when following a link or bookmark. Also, Opera will not honor the must-revalidate Cache-Control value unless max-age is set. To get Opera to follow the spec, ConditionalGet will send Opera max-age=0 (if one is not already set).
Safari
ETag validation is unsupported, but Safari supports HTTP/1.0 validation via If-Modified-Since headers as long as the cache is explicitly marked "public" or "private" ("private" is default in ConditionalGet).