From b5534428163811c58b62eb9e94db206c92fb4cc8 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Wed, 4 Feb 2009 22:03:29 +0000 Subject: [PATCH] HTTP_ConditionalGet::check() HTTP_Encoder::output() --- min/lib/HTTP/ConditionalGet.php | 68 +++++++++++++++++++++++++++------ min/lib/HTTP/Encoder.php | 29 ++++++++++++++ 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/min/lib/HTTP/ConditionalGet.php b/min/lib/HTTP/ConditionalGet.php index 51b9b84..40de43b 100644 --- a/min/lib/HTTP/ConditionalGet.php +++ b/min/lib/HTTP/ConditionalGet.php @@ -13,6 +13,7 @@ * list($updateTime, $content) = getDbUpdateAndContent(); * $cg = new HTTP_ConditionalGet(array( * 'lastModifiedTime' => $updateTime + * ,'isPublic' => true * )); * $cg->sendHeaders(); * if ($cg->cacheIsValid) { @@ -20,6 +21,12 @@ * } * echo $content; * + * + * E.g. Shortcut for the above + * + * HTTP_ConditionalGet::check($updateTime, true); // exits if client has cache + * echo $content; + * * * E.g. Content from DB with no update time: * @@ -69,8 +76,8 @@ class HTTP_ConditionalGet { * @param array $spec options * * 'isPublic': (bool) if true, the Cache-Control header will contain - * "public", allowing proxy caches to cache the content. Otherwise - * "private" will be sent, allowing only browsers to cache. (default false) + * "public", allowing proxies to cache the content. Otherwise "private" will + * be sent, allowing only browser caching. (default false) * * 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers * will be sent with content. This is recommended. @@ -95,7 +102,8 @@ class HTTP_ConditionalGet { * * @return null */ - public function __construct($spec) { + public function __construct($spec) + { $scope = (isset($spec['isPublic']) && $spec['isPublic']) ? 'public' : 'private'; @@ -147,7 +155,8 @@ class HTTP_ConditionalGet { * * @return array */ - public function getHeaders() { + public function getHeaders() + { return $this->_headers; } @@ -162,7 +171,8 @@ class HTTP_ConditionalGet { * * @return int copy of input $bytes */ - public function setContentLength($bytes) { + public function setContentLength($bytes) + { return $this->_headers['Content-Length'] = $bytes; } @@ -177,7 +187,8 @@ class HTTP_ConditionalGet { * * @return null */ - public function sendHeaders() { + public function sendHeaders() + { $headers = $this->_headers; if (array_key_exists('_responseCode', $headers)) { header($headers['_responseCode']); @@ -188,6 +199,36 @@ class HTTP_ConditionalGet { } } + /** + * Exit if the client's cache is valid for this resource + * + * This is a convenience method for common use of the class + * + * @param int $lastModifiedTime if given, both ETag AND Last-Modified headers + * will be sent with content. This is recommended. + * + * @param bool $isPublic (default false) if true, the Cache-Control header + * will contain "public", allowing proxies to cache the content. Otherwise + * "private" will be sent, allowing only browser caching. + * + * @param array $options (default empty) additional options for constructor + * + * @return null + */ + public static function check($lastModifiedTime = null, $isPublic = false, $options = array()) + { + if (null !== $lastModifiedTime) { + $options['lastModifiedTime'] = (int)$lastModifiedTime; + } + $options['isPublic'] = (bool)$isPublic; + $cg = new HTTP_ConditionalGet($options); + $cg->sendHeaders(); + if ($cg->cacheIsValid) { + exit(); + } + } + + /** * Get a GMT formatted date for use in HTTP headers * @@ -199,7 +240,8 @@ class HTTP_ConditionalGet { * * @return string */ - public static function gmtDate($time) { + public static function gmtDate($time) + { return gmdate('D, d M Y H:i:s \G\M\T', $time); } @@ -207,14 +249,16 @@ class HTTP_ConditionalGet { protected $_lmTime = null; protected $_etag = null; - protected function _setEtag($hash, $scope) { + protected function _setEtag($hash, $scope) + { $this->_etag = '"' . $hash . substr($scope, 0, 3) . '"'; $this->_headers['ETag'] = $this->_etag; } - protected function _setLastModified($time) { + protected function _setLastModified($time) + { $this->_lmTime = (int)$time; $this->_headers['Last-Modified'] = self::gmtDate($time); } @@ -237,7 +281,8 @@ class HTTP_ConditionalGet { return $isValid; } - protected function resourceMatchedEtag() { + protected function resourceMatchedEtag() + { if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) { return false; } @@ -253,7 +298,8 @@ class HTTP_ConditionalGet { return false; } - protected function resourceNotModified() { + protected function resourceNotModified() + { if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { return false; } diff --git a/min/lib/HTTP/Encoder.php b/min/lib/HTTP/Encoder.php index f25cd83..176da33 100644 --- a/min/lib/HTTP/Encoder.php +++ b/min/lib/HTTP/Encoder.php @@ -19,6 +19,12 @@ * * * + * // Shortcut to encoding output + * header('Content-Type: text/css'); // needed if not HTML + * HTTP_Encoder::output($css); + * + * + * * // Just sniff for the accepted encoding * $encoding = HTTP_Encoder::getAcceptedEncoding(); * @@ -257,6 +263,29 @@ class HTTP_Encoder { $this->_headers['Vary'] = 'Accept-Encoding'; $this->_content = $encoded; return true; + } + + /** + * Encode and send appropriate headers and content + * + * This is a convenience method for common use of the class + * + * @param string $content + * + * @param int $compressionLevel given to zlib functions. If not given, the + * class default will be used. + * + * @return bool success true if the content was actually compressed + */ + public static function output($content, $compressionLevel = null) + { + if (null === $compressionLevel) { + $compressionLevel = self::$compressionLevel; + } + $he = new HTTP_Encoder(array('content' => $content)); + $ret = $he->encode($compressionLevel); + $he->sendAll(); + return $ret; } protected $_content = '';