diff options
| author | 2023-04-10 12:42:06 +0200 | |
|---|---|---|
| committer | 2023-04-10 12:42:06 +0200 | |
| commit | 90bf0ecd81bde1c758fd6d6febe7bdc4b82594b0 (patch) | |
| tree | de693997bef9403223cf092307e883144978d4f4 /lib | |
| parent | 74bf894db02c2d50fa414cc652512cfe48db4267 (diff) | |
PHPStan 9 for lib/http-conditional.php (#5277)
Contributes to https://github.com/FreshRSS/FreshRSS/issues/4112
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/http-conditional.php | 274 |
1 files changed, 137 insertions, 137 deletions
diff --git a/lib/http-conditional.php b/lib/http-conditional.php index 6c7c89d32..1a1b6a6dc 100644 --- a/lib/http-conditional.php +++ b/lib/http-conditional.php @@ -6,43 +6,35 @@ - If the client already has the same version in its cache, avoid transferring data again (304 Not Modified). - Possibility to control cache for client and proxies (public or private policy, life time). - When $feedMode is set to true, in the case of a RSS/ATOM feed, - it puts a timestamp in the global variable $clientCacheDate to allow the sending of only the articles newer than the client's cache. + it puts a timestamp in the global variable $clientCacheDate to allow the sending of only the articles newer than the client’s cache. - When $compression is set to true, compress the data before sending it to the client and persistent connections are allowed. - When $session is set to true, automatically checks if $_SESSION has been modified during the last generation the document. - Interface: - - function httpConditional($UnixTimeStamp,$cacheSeconds=0,$cachePrivacy=0,$feedMode=false,$compression=false) - [Required] $UnixTimeStamp: Date of the last modification of the data to send to the client (Unix Timestamp format). - [Implied] $cacheSeconds=0: Lifetime in seconds of the document. If $cacheSeconds<0, cache is disabled. If $cacheSeconds==0, the document will be revalidated each time it is accessed. If $cacheSeconds>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 persistent 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 latest version), false if the new content has to be send to the client. - Typical use: - <?php - require_once('http-conditional.php'); - //Date of the last modification of the content (Unix Timestamp format). - //Examples: query the database, or last modification of a static file. - $dateLastModification=...; - if (httpConditional($dateLastModification)) - { - ... //Close database connections, and other cleaning. - exit(); //No need to send anything - } - //Do not send any text to the client before this line. - ... //Rest of the script, just as you would do normally. - ?> - - Version 1.8 beta, 2016-08-07, http://alexandre.alapetite.fr/doc-alex/php-http-304/ + +```php +<?php + require_once('http-conditional.php'); + //Date of the last modification of the content (Unix Timestamp format). + //Examples: query the database, or last modification of a static file. + $dateLastModification = ...; + if (httpConditional($dateLastModification)) { + ... //Close database connections, and other cleaning. + exit(); //No need to send anything + } + //Do not send any text to the client before this line. + ... //Rest of the script, just as you would do normally. +?> +``` + + Version 1.9, 2023-04-08, https://alexandre.alapetite.fr/doc-alex/php-http-304/ ------------------------------------------------------------------ - Written by Alexandre Alapetite, http://alexandre.alapetite.fr/cv/ + Written by Alexandre Alapetite in 2004, https://alexandre.alapetite.fr/cv/ - Copyright 2004-2016, 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 + Copyright 2004-2023, Licence: Creative Commons "Attribution-ShareAlike 2.0 France" BY-SA (FR), + https://creativecommons.org/licenses/by-sa/2.0/fr/ + https://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 @@ -53,164 +45,172 @@ 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/ + https://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 - +/** + * In RSS/ATOM feedMode, contains the date of the clients last update. + * Global public variable because PHP4 did not allow conditional arguments by reference + * @var int + */ +$clientCacheDate = 0; + +/** + * Global private variable + * @var bool + */ +$_sessionMode = false; + +/** + * RFC2616 HTTP/1.1: https://www.w3.org/Protocols/rfc2616/rfc2616.html + * RFC1945 HTTP/1.0: https://www.w3.org/Protocols/rfc1945/rfc1945.txt + * Credits: https://alexandre.alapetite.fr/doc-alex/php-http-304/ + * + * @param int $UnixTimeStamp: Date of the last modification of the data to send to the client (Unix Timestamp format). + * @param int $cacheSeconds (default 0) Lifetime in seconds of the document. If $cacheSeconds<0, cache is disabled. + * If $cacheSeconds==0, the document will be revalidated each time it is accessed. If $cacheSeconds>0, the document will be cashed and not revalidated against the server for this delay. + * @phpstan-param 0|1|2 $cachePrivacy + * @param int $cachePrivacy (default 0) 0=private, 1=normal (public), 2=forced public. When public, it allows a cashed document ($cacheSeconds>0) to be shared by several users. + * @param bool $feedMode (default 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. + * @param bool $compression (default false) Enable the compression and allows persistent connections (automatic detection of the capacities of the client). + * @param bool $session (default 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. + * @return bool True if the connection can be closed (e.g.: the client has already the latest version), false if the new content has to be send to the client. + */ +function httpConditional(int $UnixTimeStamp, int $cacheSeconds = 0, int $cachePrivacy = 0, bool $feedMode = false, bool $compression = false, bool $session = false): bool { if (headers_sent()) return false; - if (isset($_SERVER['SCRIPT_FILENAME'])) $scriptName=$_SERVER['SCRIPT_FILENAME']; - elseif (isset($_SERVER['PATH_TRANSLATED'])) $scriptName=$_SERVER['PATH_TRANSLATED']; + 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; + if ((!$feedMode) && (($modifScript = (int)filemtime($scriptName)) > $UnixTimeStamp)) + $UnixTimeStamp = $modifScript; + $UnixTimeStamp = (int)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'; + $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)) - { + 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(); + $_sessionMode = $session; + $myQuery .= print_r($_SESSION, true) . session_name() . '=' . session_id(); } - $etagServer='"'.md5($scriptName.$myQuery.'#'.$dateLastModif).'"'; + $etagServer = '"' . md5($scriptName . $myQuery . '#' . $dateLastModif) . '"'; // @phpstan-ignore-next-line - if ((!$is412)&&isset($_SERVER['HTTP_IF_MATCH'])) - {//rfc2616-sec14.html#sec14.24 - $etagsClient=stripslashes($_SERVER['HTTP_IF_MATCH']); - $etagsClient=str_ireplace('-gzip','',$etagsClient); - $is412=(($etagsClient!=='*')&&(strpos($etagsClient,$etagServer)===false)); + if ((!$is412) && isset($_SERVER['HTTP_IF_MATCH'])) { //rfc2616-sec14.html#sec14.24 + $etagsClient = stripslashes($_SERVER['HTTP_IF_MATCH']); + $etagsClient = str_ireplace('-gzip', '', $etagsClient); + $is412 = (($etagsClient !== '*') && (strpos($etagsClient, $etagServer) === false)); } // @phpstan-ignore-next-line - if ($is304&&isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) - {//rfc2616-sec14.html#sec14.25 //rfc1945.txt + 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); + $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 + if ($is304 && isset($_SERVER['HTTP_IF_NONE_MATCH'])) { //rfc2616-sec14.html#sec14.26 $nbCond++; - $etagClient=stripslashes($_SERVER['HTTP_IF_NONE_MATCH']); - $etagClient=str_ireplace('-gzip','',$etagClient); - $is304=(($etagClient===$etagServer)||($etagClient==='*')); + $etagClient = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']); + $etagClient = str_ireplace('-gzip', '', $etagClient); + $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 ((!$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 + if ($feedMode) { //Special RSS/ATOM global $clientCacheDate; - $clientCacheDate=@strtotime($dateCacheClient); - $cachePrivacy=0; + $clientCacheDate = @strtotime($dateCacheClient); + $cachePrivacy = 0; } - if ($is412) - {//rfc2616-sec10.html#sec10.4.13 + 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 + } elseif ($is304 && ($nbCond > 0)) { //rfc2616-sec10.html#sec10.3.5 header('HTTP/1.0 304 Not Modified'); - header('Etag: '.$etagServer); + header('Etag: ' . $etagServer); if ($feedMode) header('Connection: close'); //Comment this line under IIS return true; - } - else - {//rfc2616-sec10.html#sec10.2.1 + } 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'; + if ($cacheSeconds < 0) { + $cache = 'private, no-cache, no-store, must-revalidate'; //header('Expires: 0'); header('Pragma: no-cache'); - } - else - { - if ($cacheSeconds===0) - { - $cache='private, must-revalidate, '; + } else { + if ($cacheSeconds === 0) { + $cache = 'private, must-revalidate, '; //header('Expires: 0'); - } - elseif ($cachePrivacy===0) $cache='private, '; - elseif ($cachePrivacy===2) $cache='public, '; - else $cache=''; - $cache.='max-age='.floor($cacheSeconds); + } 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); + 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 + 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; +/** + * Private function automatically called at the end of the script when compression is enabled. + * One can adjust the level of compression with zlib.output_compression_level in php.ini + * Reference rfc2616-sec14.html#sec14.11 + */ +function _httpConditionalCallBack(string $buffer, int $mode = 5): string { + 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 persistent connections //rfc2616-sec14.html#sec14.13 + header('Content-Length: ' . strlen($buffer)); //Allows persistent 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; +/** + * Update HTTP headers if the content has just been modified by the client’s request. + * See an example on https://alexandre.alapetite.fr/doc-alex/compteur/ + */ +function httpConditionalRefresh(int $UnixTimeStamp): void { + if (headers_sent()) return; - if (isset($_SERVER['SCRIPT_FILENAME'])) $scriptName=$_SERVER['SCRIPT_FILENAME']; - elseif (isset($_SERVER['PATH_TRANSLATED'])) $scriptName=$_SERVER['PATH_TRANSLATED']; - else return false; + if (isset($_SERVER['SCRIPT_FILENAME'])) $scriptName = $_SERVER['SCRIPT_FILENAME']; + elseif (isset($_SERVER['PATH_TRANSLATED'])) $scriptName = $_SERVER['PATH_TRANSLATED']; + else return; - $dateLastModif=gmdate('D, d M Y H:i:s \G\M\T',$UnixTimeStamp); + $dateLastModif = gmdate('D, d M Y H:i:s \G\M\T', $UnixTimeStamp); - if (isset($_SERVER['QUERY_STRING'])) $myQuery='?'.$_SERVER['QUERY_STRING']; - else $myQuery=''; + 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).'"'; + 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); + header('Last-Modified: ' . $dateLastModif); + header('Etag: ' . $etagServer); } |
