Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

php eTag generation using php

This PHP code generates an eTag for an xml file. The problem is eTag updates only when the file it self is updated/modified. I need the etag to update when the dynamic results are updated as well. any idea how this can be done?

//get the last-modified-date of this very file
$lastModified=filemtime(__FILE__);

//get a unique hash of this file (etag)
$etagFile = md5_file(__FILE__);

//get the HTTP_IF_MODIFIED_SINCE header if set
$ifModifiedSince=(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false);

//get the HTTP_IF_NONE_MATCH header if set (etag: unique file hash)
$etagHeader=(isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : false);

//set last-modified header
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $lastModified)." GMT");

//set etag-header
header("Etag: $etagFile");

//make sure caching is turned on    
//check if page has changed. If not, send 304 and exit
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])==$lastModified || $etagHeader == $etagFile)
{
       header("HTTP/1.1 304 Not Modified");
       exit;
}
like image 247
apak Avatar asked Mar 14 '26 15:03

apak


2 Answers

You can do something like this.
Get a unique hash of dynamic content instead of file and set it as eTag.

<?php
  $last_modified  = filemtime( __FILE__ );

  $modified_since = ( isset( $_SERVER["HTTP_IF_MODIFIED_SINCE"] ) ? strtotime( $_SERVER["HTTP_IF_MODIFIED_SINCE"] ) : false );
  $etagHeader     = ( isset( $_SERVER["HTTP_IF_NONE_MATCH"] ) ? trim( $_SERVER["HTTP_IF_NONE_MATCH"] ) : false );

  // This is the actual output from this file (in your case the xml data)
  $content  = 'your xml data from db or file';
  // generate the etag from your output
  $etag     = sprintf( '"%s-%s"', $last_modified, md5( $content ) );

  //set last-modified header
  header( "Last-Modified: ".gmdate( "D, d M Y H:i:s", $last_modified )." GMT" );
  //set etag-header
  header( "Etag: ".$etag );

  // if last modified date is same as "HTTP_IF_MODIFIED_SINCE", send 304 then exit
  if ( (int)$modified_since === (int)$last_modified && $etag === $etagHeader ) {
    header( "HTTP/1.1 304 Not Modified" );
    exit;
  }

  // new content or file modified, so output ypur content
  echo $content;
  exit;
?>
like image 56
bystwn22 Avatar answered Mar 16 '26 06:03

bystwn22


You can use get_included_files() to get all PHP files that have been used to generate the file.

Once you generate the file for a first time, store that list in some sort of storage (associated with the URL, of course), and give to the client the largest filemtime() from that list. Next time, retrieve the file list, and check if any of the files' filemtime() is larger than the one given in the HTTP request. Regenerate as soon you find one, or deliver the cached response if you don't find one.

Obviously, this approach assumes that generating the response and/or sending it is very performance costly. Otherwise, doing all those filemtime() checks can end up being more taxing than simply regenerating the file each time.

like image 39
boen_robot Avatar answered Mar 16 '26 04:03

boen_robot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!