From adc9a958afa5fb9f6f2dab4ae8abac1f932a7db4 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 3 Nov 2013 20:28:52 +0100 Subject: Préchargement et requêtes conditionnelles HTTP/1.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grosse amélioration des performances en utilisant le cache HTTP : - Implémentation de HTTP/1.1, c.a.d. If-Modified-Since, If-None-Match, If-Unmodified-Since, If-Match... avec la librairie http://alexandre.alapetite.fr/doc-alex/php-http-304/ - Support de HEAD (HTTP /1.0). - Préchargement de la page suivante (avec link next prefetch) dans le cas de pagination. - Et nouvelle possibilité de navigation pour les navigateurs qui supportent "next". - La date de dernier changement est pour l'instant primitive et correspond au dernier changement de la session PHP ou Configuration.array.php ou application.log ou touch.txt. - touch.txt est modifié a chaque requête UPDATE ou INSERT ou DELETE. --- lib/http-conditional.php | 207 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 lib/http-conditional.php (limited to 'lib/http-conditional.php') diff --git a/lib/http-conditional.php b/lib/http-conditional.php new file mode 100644 index 000000000..bd038aec3 --- /dev/null +++ b/lib/http-conditional.php @@ -0,0 +1,207 @@ +0, the document will be cashed and not revalidated against the server for this delay. + [Implied] $cachePrivacy=0: 0=private, 1=normal (public), 2=forced public. When public, it allows a cashed document ($cacheSeconds>0) to be shared by several users. + [Implied] $feedMode=false: Special RSS/ATOM feeds. When true, it sets $cachePrivacy to 0 (private), does not use the modification time of the script itself, and puts the date of the client's cache (or a old date from 1980) in the global variable $clientCacheDate. + [implied] $compression=false: Enable the compression and allows persistant connections (automatic detection of the capacities of the client). + [implied] $session=false: To be turned on when sessions are used. Checks if the data contained in $_SESSION has been modified during the last generation the document. + Returns: True if the connection can be closed (e.g.: the client has already the lastest version), false if the new content has to be send to the client. + + Typical use: + + + Version 1.6.2a, 2008-03-06, http://alexandre.alapetite.fr/doc-alex/php-http-304/ + + ------------------------------------------------------------------ + Written by Alexandre Alapetite, http://alexandre.alapetite.fr/cv/ + + Copyright 2004-2008, Licence: Creative Commons "Attribution-ShareAlike 2.0 France" BY-SA (FR), + http://creativecommons.org/licenses/by-sa/2.0/fr/ + http://alexandre.alapetite.fr/divers/apropos/#by-sa + - Attribution. You must give the original author credit + - Share Alike. If you alter, transform, or build upon this work, + you may distribute the resulting work only under a license identical to this one + (Can be included in GPL/LGPL projects) + - The French law is authoritative + - Any of these conditions can be waived if you get permission from Alexandre Alapetite + - Please send to Alexandre Alapetite the modifications you make, + in order to improve this file for the benefit of everybody + + If you want to distribute this code, please do it as a link to: + http://alexandre.alapetite.fr/doc-alex/php-http-304/ +*/ + +//In RSS/ATOM feedMode, contains the date of the clients last update. +$clientCacheDate=0; //Global public variable because PHP4 does not allow conditional arguments by reference +$_sessionMode=false; //Global private variable + +function httpConditional($UnixTimeStamp,$cacheSeconds=0,$cachePrivacy=0,$feedMode=false,$compression=false,$session=false) +{//Credits: http://alexandre.alapetite.fr/doc-alex/php-http-304/ + //RFC2616 HTTP/1.1: http://www.w3.org/Protocols/rfc2616/rfc2616.html + //RFC1945 HTTP/1.0: http://www.w3.org/Protocols/rfc1945/rfc1945.txt + + if (headers_sent()) return false; + + if (isset($_SERVER['SCRIPT_FILENAME'])) $scriptName=$_SERVER['SCRIPT_FILENAME']; + elseif (isset($_SERVER['PATH_TRANSLATED'])) $scriptName=$_SERVER['PATH_TRANSLATED']; + else return false; + + if ((!$feedMode)&&(($modifScript=filemtime($scriptName))>$UnixTimeStamp)) + $UnixTimeStamp=$modifScript; + $UnixTimeStamp=min($UnixTimeStamp,time()); + $is304=true; + $is412=false; + $nbCond=0; + + //rfc2616-sec3.html#sec3.3.1 + $dateLastModif=gmdate('D, d M Y H:i:s \G\M\T',$UnixTimeStamp); + $dateCacheClient='Thu, 10 Jan 1980 20:30:40 GMT'; + + //rfc2616-sec14.html#sec14.19 //='"0123456789abcdef0123456789abcdef"' + if (isset($_SERVER['QUERY_STRING'])) $myQuery='?'.$_SERVER['QUERY_STRING']; + else $myQuery=''; + if ($session&&isset($_SESSION)) + { + global $_sessionMode; + $_sessionMode=$session; + $myQuery.=print_r($_SESSION,true).session_name().'='.session_id(); + } + $etagServer='"'.md5($scriptName.$myQuery.'#'.$dateLastModif).'"'; + + if ((!$is412)&&isset($_SERVER['HTTP_IF_MATCH'])) + {//rfc2616-sec14.html#sec14.24 + $etagsClient=stripslashes($_SERVER['HTTP_IF_MATCH']); + $is412=(($etagClient!='*')&&(strpos($etagsClient,$etagServer)===false)); + } + if ($is304&&isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) + {//rfc2616-sec14.html#sec14.25 //rfc1945.txt + $nbCond++; + $dateCacheClient=$_SERVER['HTTP_IF_MODIFIED_SINCE']; + $p=strpos($dateCacheClient,';'); + if ($p!==false) + $dateCacheClient=substr($dateCacheClient,0,$p); + $is304=($dateCacheClient==$dateLastModif); + } + if ($is304&&isset($_SERVER['HTTP_IF_NONE_MATCH'])) + {//rfc2616-sec14.html#sec14.26 + $nbCond++; + $etagClient=stripslashes($_SERVER['HTTP_IF_NONE_MATCH']); + $is304=(($etagClient==$etagServer)||($etagClient=='*')); + } + if ((!$is412)&&isset($_SERVER['HTTP_IF_UNMODIFIED_SINCE'])) + {//rfc2616-sec14.html#sec14.28 + $dateCacheClient=$_SERVER['HTTP_IF_UNMODIFIED_SINCE']; + $p=strpos($dateCacheClient,';'); + if ($p!==false) + $dateCacheClient=substr($dateCacheClient,0,$p); + $is412=($dateCacheClient!=$dateLastModif); + } + if ($feedMode) + {//Special RSS/ATOM + global $clientCacheDate; + $clientCacheDate=strtotime($dateCacheClient); + $cachePrivacy=0; + } + + if ($is412) + {//rfc2616-sec10.html#sec10.4.13 + header('HTTP/1.1 412 Precondition Failed'); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Content-Type: text/plain'); + echo "HTTP/1.1 Error 412 Precondition Failed: Precondition request failed positive evaluation\n"; + return true; + } + elseif ($is304&&($nbCond>0)) + {//rfc2616-sec10.html#sec10.3.5 + header('HTTP/1.0 304 Not Modified'); + header('Etag: '.$etagServer); + if ($feedMode) header('Connection: close'); //Comment this line under IIS + return true; + } + else + {//rfc2616-sec10.html#sec10.2.1 + //rfc2616-sec14.html#sec14.3 + if ($compression) ob_start('_httpConditionalCallBack'); //Will check HTTP_ACCEPT_ENCODING + //header('HTTP/1.0 200 OK'); + if ($cacheSeconds<0) + { + $cache='private, no-cache, no-store, must-revalidate'; + header('Pragma: no-cache'); + } + else + { + if ($cacheSeconds==0) $cache='private, must-revalidate, '; + elseif ($cachePrivacy==0) $cache='private, '; + elseif ($cachePrivacy==2) $cache='public, '; + else $cache=''; + $cache.='max-age='.floor($cacheSeconds); + } + //header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T',time()+$cacheSeconds)); //HTTP/1.0 //rfc2616-sec14.html#sec14.21 + header('Cache-Control: '.$cache); //rfc2616-sec14.html#sec14.9 + header('Last-Modified: '.$dateLastModif); + header('Etag: '.$etagServer); + if ($feedMode) header('Connection: close'); //rfc2616-sec14.html#sec14.10 //Comment this line under IIS + return $_SERVER['REQUEST_METHOD']=='HEAD'; //rfc2616-sec9.html#sec9.4 + } +} + +function _httpConditionalCallBack($buffer,$mode=5) +{//Private function automatically called at the end of the script when compression is enabled + //rfc2616-sec14.html#sec14.11 + //You can adjust the level of compression with zlib.output_compression_level in php.ini + if (extension_loaded('zlib')&&(!ini_get('zlib.output_compression'))) + { + $buffer2=ob_gzhandler($buffer,$mode); //Will check HTTP_ACCEPT_ENCODING and put correct headers such as Vary //rfc2616-sec14.html#sec14.44 + if (strlen($buffer2)>1) //When ob_gzhandler succeeded + $buffer=$buffer2; + } + header('Content-Length: '.strlen($buffer)); //Allows persistant connections //rfc2616-sec14.html#sec14.13 + return $buffer; +} + +function httpConditionalRefresh($UnixTimeStamp) +{//Update HTTP headers if the content has just been modified by the client's request + //See an example on http://alexandre.alapetite.fr/doc-alex/compteur/ + if (headers_sent()) return false; + + if (isset($_SERVER['SCRIPT_FILENAME'])) $scriptName=$_SERVER['SCRIPT_FILENAME']; + elseif (isset($_SERVER['PATH_TRANSLATED'])) $scriptName=$_SERVER['PATH_TRANSLATED']; + else return false; + + $dateLastModif=gmdate('D, d M Y H:i:s \G\M\T',$UnixTimeStamp); + + if (isset($_SERVER['QUERY_STRING'])) $myQuery='?'.$_SERVER['QUERY_STRING']; + else $myQuery=''; + global $_sessionMode; + if ($_sessionMode&&isset($_SESSION)) + $myQuery.=print_r($_SESSION,true).session_name().'='.session_id(); + $etagServer='"'.md5($scriptName.$myQuery.'#'.$dateLastModif).'"'; + + header('Last-Modified: '.$dateLastModif); + header('Etag: '.$etagServer); +} -- cgit v1.2.3