Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00%
0 / 1
0.00%
0 / 12
CRAP
0.00%
0 / 73
Caching
0.00%
0 / 1
0.00%
0 / 12
650
0.00%
0 / 73
 noCachingControl()
0.00%
0 / 1
2
0.00%
0 / 4
 anonymous function ($data)
0.00%
0 / 1
2
0.00%
0 / 1
 dosProtectionCachingControl()
0.00%
0 / 1
2
0.00%
0 / 4
 shortCachingControl()
0.00%
0 / 1
2
0.00%
0 / 4
 conservativeCachingControl()
0.00%
0 / 1
2
0.00%
0 / 4
 aggressiveCachingControl()
0.00%
0 / 1
2
0.00%
0 / 4
 veryAggressiveCachingControl()
0.00%
0 / 1
2
0.00%
0 / 2
 setCacheControl($maxAge=0)
0.00%
0 / 1
12
0.00%
0 / 6
 processor($data, $sec=0)
0.00%
0 / 1
12
0.00%
0 / 12
 anyETagMatched($myTag)
0.00%
0 / 1
42
0.00%
0 / 16
 isExpired($lastModifiedOn)
0.00%
0 / 1
12
0.00%
0 / 10
 isNotModified($ETag=null, \DateTime $lastModifiedOn)
0.00%
0 / 1
12
0.00%
0 / 5
<?php
namespace BOTK\Core;
use BOTK\Models\HttpProblem;
class Caching
{
const
NO = 'noCachingControl',
DOS_PROTECTION = 'dosProtectionCachingControl',
SHORT = 'shortCachingControlControl',
CONSERVATIVE = 'conservativeCachingControl',
AGGRESSIVE = 'aggressiveCachingControl',
VERY_AGGRESSIVE = 'veryAggressiveCachingControl';
public static function noCachingControl() //3 sec
{
return function ($data) { return Caching::processor($data);};
}
public static function dosProtectionCachingControl() //3 sec
{
return function ($data) { return Caching::processor($data, 3);};
}
public static function shortCachingControl() //30 sec
{
return function ($data) { return Caching::processor($data,30);};
}
public static function conservativeCachingControl() //three minute
{
return function ($data) { return Caching::processor($data, 60*3);};
}
public static function aggressiveCachingControl() //one hour
{
return function ($data) { return Caching::processor($data, 60*60);};
}
public static function veryAggressiveCachingControl() //one day
{
return function ($data) { return Caching::processor($data, 60*60*24);};
}
public static function setCacheControl($maxAge=0)
{
$cacheControl= (($sec=intval($maxAge))>0)?"max-age=$sec":'';
if ($cacheControl) header ('Cache-Control: '.$cacheControl);
return $cacheControl;
}
/**
* This routine drive http caching process
* Not sure to have well understand caching :-(
*
* Note that this routine is called by stateTransfer and may be called also from
* End-Point routine after the controller exit.
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
*/
public static function processor($data, $sec=0)
{
// ensure not negative caching age!
if ($sec<0) $sec=0;
$etag = Http::setETagHeader($data);
$lastModifiedOn = Http::setLastModifiedHeader($data, new \DateTime());
// this is the caching algorithm: only return data if necessary..
if( self::isNotModified($etag, $lastModifiedOn) ){
// Return http status 304 Not Modified and stop data flow processing
Http::setHttpResponseCode(304);
return ''; // return empty data
}
// advertise caching policy
self::setCacheControl($sec);
return $data;
}
/**
* Compare Etag against HTTP_IF_NONE_MATCH
*
* @return false in no match found,
*/
private static function anyETagMatched($myTag)
{
if (!$myTag) return false;
$myTag=str_replace('"', '', $myTag); //remove quoting
$if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ?
str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) :
false ;
// warning, this assumes that , is never part of ETag!
if( false !== $if_none_match ) {
$tags = explode( ", ", $if_none_match ) ;
foreach( $tags as $tag ) {
if( strpos($tag,$myTag)===0 ) return true ; // partial tag match
}
return false ;
}
return null ;
}
/**
* Compare HTTP_IF_MODIFIED_SINCE with a date (date tyme format)
*/
private static function isExpired($lastModifiedOn)
{
$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
? new \DateTime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
: false;
if( false !== $if_modified_since ) {
return ( $if_modified_since < $lastModifiedOn ) ;
}
return true ;
}
/**
* Apply cache controls algorithm respect protocol requirement.
*/
private static function isNotModified($ETag=null, \DateTime $lastModifiedOn)
{
$anyTagMatched = self::anyETagMatched($ETag) ;
return ( $anyTagMatched || ( ( is_null($anyTagMatched) && !self::isExpired($lastModifiedOn) ) ));
}
}