diff --git a/lib/HTTP/ConditionalGet.php b/lib/HTTP/ConditionalGet.php index ade3245..d080060 100644 --- a/lib/HTTP/ConditionalGet.php +++ b/lib/HTTP/ConditionalGet.php @@ -3,31 +3,46 @@ /** * Implement conditional GET via a timestamp or hash of content * + * E.g. Content from DB with update time: * - * // easiest usage + * list($updateTime, $content) = getDbUpdateAndContent(); * $cg = new HTTP_ConditionalGet(array( - * 'lastModifiedTime' => filemtime(__FILE__) + * 'lastModifiedTime' => $updateTime * )); * $cg->sendHeaders(); * if ($cg->cacheIsValid) { - * exit(); // done - * } - * // echo content - * - * - * - * - * // better to add content length once it's known - * $cg = new HTTP_ConditionalGet(array( - * 'lastModifiedTime' => filemtime(__FILE__) - * )); - * if ($cg->cacheIsValid) { - * $cg->sendHeaders(); * exit(); * } - * $content = get_content(); - * $cg->setContentLength(strlen($content)); + * echo $content; + * + * + * E.g. Content from DB with no update time: + * + * $content = getContentFromDB(); + * $cg = new HTTP_ConditionalGet(array( + * 'contentHash' => md5($content) + * )); * $cg->sendHeaders(); + * if ($cg->cacheIsValid) { + * exit(); + * } + * echo $content; + * + * + * E.g. Static content with some static includes: + * + * // before content + * $cg = new HTTP_ConditionalGet(array( + * 'lastUpdateTime' => max( + * filemtime(__FILE__) + * ,filemtime('/path/to/header.inc') + * ,filemtime('/path/to/footer.inc') + * ) + * )); + * $cg->sendHeaders(); + * if ($cg->cacheIsValid) { + * exit(); + * } * */ class HTTP_ConditionalGet { @@ -76,7 +91,7 @@ class HTTP_ConditionalGet { // allow far-expires header if (isset($spec['setExpires'])) { if (is_numeric($spec['setExpires'])) { - $spec['setExpires'] = self::gmtdate($spec['setExpires']); + $spec['setExpires'] = self::gmtDate($spec['setExpires']); } $this->_headers = array( 'Cache-Control' => $scope @@ -159,6 +174,21 @@ class HTTP_ConditionalGet { } } + /** + * Get a GMT formatted date for use in HTTP headers + * + * + * header('Expires: ' . HTTP_ConditionalGet::gmtdate($time)); + * + * + * @param int $time unix timestamp + * + * @return string + */ + public static function gmtDate($time) { + return gmdate('D, d M Y H:i:s \G\M\T', $time); + } + protected $_headers = array(); protected $_lmTime = null; protected $_etag = null; @@ -172,7 +202,7 @@ class HTTP_ConditionalGet { protected function _setLastModified($time) { $this->_lmTime = (int)$time; - $this->_headers['Last-Modified'] = self::gmtdate($time); + $this->_headers['Last-Modified'] = self::gmtDate($time); } /** @@ -221,10 +251,6 @@ class HTTP_ConditionalGet { // IE has tacked on extra data to this header, strip it $ifModifiedSince = substr($ifModifiedSince, 0, $semicolon); } - return ($ifModifiedSince == self::gmtdate($this->_lmTime)); - } - - protected static function gmtdate($ts) { - return gmdate('D, d M Y H:i:s \G\M\T', $ts); + return ($ifModifiedSince == self::gmtDate($this->_lmTime)); } } diff --git a/lib/HTTP/ConditionalGet/test/_include.php b/lib/HTTP/ConditionalGet/test/_include.php index 8ee2b48..6bc28b9 100644 --- a/lib/HTTP/ConditionalGet/test/_include.php +++ b/lib/HTTP/ConditionalGet/test/_include.php @@ -52,9 +52,7 @@ to verify headers and content being sent.

Safari
ETag validation is unsupported, but Safari supports HTTP/1.0 validation via If-Modified-Since headers as long as the cache is explicitly marked - "public" or "private". ConditionalGet can send one of these - values determined by cookies/session data, but it's best to explicitly - set the option 'isPublic' to true or false.
+ "public" or "private" ("private" is default in ConditionalGet). diff --git a/lib/HTTP/Encoder.php b/lib/HTTP/Encoder.php index 0565b6f..2d4d876 100644 --- a/lib/HTTP/Encoder.php +++ b/lib/HTTP/Encoder.php @@ -54,15 +54,12 @@ class HTTP_Encoder { if (isset($spec['type'])) { $this->_headers['Content-Type'] = $spec['type']; } - if (self::$_clientEncodeMethod === null) { - self::$_clientEncodeMethod = self::getAcceptedEncoding(); - } if (isset($spec['method']) && in_array($spec['method'], array('gzip', 'deflate', 'compress', ''))) { $this->_encodeMethod = array($spec['method'], $spec['method']); } else { - $this->_encodeMethod = self::$_clientEncodeMethod; + $this->_encodeMethod = self::getAcceptedEncoding(); } } @@ -136,32 +133,41 @@ class HTTP_Encoder { * this will return ('', ''), the "identity" encoding. * * A syntax-aware scan is done of the Accept-Encoding, so the method must - * be non 0. The methods are favored in order of gzip, deflate, then - * compress. - * - * Note: this value is cached internally for the entire PHP execution + * be non 0. The methods are favored in order of deflate, gzip, then + * compress. Yes, deflate is always smaller and faster! * * @return array two values, 1st is the actual encoding method, 2nd is the * alias of that method to use in the Content-Encoding header (some browsers * call gzip "x-gzip" etc.) */ public static function getAcceptedEncoding() { - if (self::$_clientEncodeMethod !== null) { - return self::$_clientEncodeMethod; - } if (! isset($_SERVER['HTTP_ACCEPT_ENCODING']) || self::_isBuggyIe()) { return array('', ''); } + // @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html // test for (x-)gzip, if q is specified, can't be "0" - if (preg_match('@(?:^|,)\s*((?:x-)?gzip)\s*(?:$|,|;\s*q=(?:0\.|1))@', $_SERVER['HTTP_ACCEPT_ENCODING'], $m)) { - return array('gzip', $m[1]); - } - if (preg_match('@(?:^|,)\s*deflate\s*(?:$|,|;\s*q=(?:0\.|1))@', $_SERVER['HTTP_ACCEPT_ENCODING'])) { + // faster test for most common "gzip, deflate" + if (preg_match('@(?:,| )deflate$@', $_SERVER['HTTP_ACCEPT_ENCODING']) + || preg_match( + '@(?:^|,)\\s*deflate\\s*(?:$|,|;\\s*q=(?:0\\.|1))@' + ,$_SERVER['HTTP_ACCEPT_ENCODING']) + ) { return array('deflate', 'deflate'); } - if (preg_match('@(?:^|,)\s*((?:x-)?compress)\s*(?:$|,|;\s*q=(?:0\.|1))@', $_SERVER['HTTP_ACCEPT_ENCODING'], $m)) { + if (preg_match( + '@(?:^|,)\\s*((?:x-)?gzip)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@' + ,$_SERVER['HTTP_ACCEPT_ENCODING'] + ,$m) + ) { + return array('gzip', $m[1]); + } + if (preg_match( + '@(?:^|,)\\s*((?:x-)?compress)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@' + ,$_SERVER['HTTP_ACCEPT_ENCODING'] + ,$m) + ) { return array('compress', $m[1]); } return array('', ''); @@ -211,21 +217,27 @@ class HTTP_Encoder { return true; } - protected static $_clientEncodeMethod = null; - protected $content = ''; - protected $headers = array(); - protected $encodeMethod = array('', ''); + protected $_content = ''; + protected $_headers = array(); + protected $_encodeMethod = array('', ''); + /** + * Is the browser an IE version earlier than 6 SP2? + */ protected static function _isBuggyIe() { - if (strstr($_SERVER['HTTP_USER_AGENT'], 'Opera') - || !preg_match('/^Mozilla\/4\.0 \(compatible; MSIE ([0-9]\.[0-9])/i', $_SERVER['HTTP_USER_AGENT'], $m)) - { + if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') + || !preg_match( + '/^Mozilla\/4\.0 \(compatible; MSIE ([0-9]\.[0-9])/i' + ,$_SERVER['HTTP_USER_AGENT'] + ,$m + ) + ) { return false; } $version = floatval($m[1]); if ($version < 6) return true; - if ($version == 6 && !strstr($_SERVER['HTTP_USER_AGENT'], 'SV1')) { + if ($version == 6 && false === strpos($_SERVER['HTTP_USER_AGENT'], 'SV1')) { return true; } return false; diff --git a/lib/HTTP/Encoder/test/index.php b/lib/HTTP/Encoder/test/index.php index 1cc096e..47ed4e5 100644 --- a/lib/HTTP/Encoder/test/index.php +++ b/lib/HTTP/Encoder/test/index.php @@ -46,8 +46,7 @@ window.onload = function(){ document.getElementById("js").className = "green"; }; '; - $type = 'text/javascript'; - + $type = 'application/x-javascript'; } $he = new HTTP_Encoder(array( diff --git a/lib/Minify.php b/lib/Minify.php index c89aefa..46703f4 100644 --- a/lib/Minify.php +++ b/lib/Minify.php @@ -16,7 +16,7 @@ * @package Minify * @author Ryan Grove * @author Stephen Clay - * @copyright 2007 Ryan Grove. All rights reserved. + * @copyright 2008 Ryan Grove, Stephen Clay. All rights reserved. * @license http://opensource.org/licenses/bsd-license.php New BSD License * @version 1.9.0 * @link http://code.google.com/p/minify/ @@ -27,8 +27,10 @@ require_once 'Minify/Source.php'; class Minify { const TYPE_CSS = 'text/css'; - const TYPE_JS = 'application/x-javascript'; const TYPE_HTML = 'text/html'; + // there is some debate over the ideal JS Content-Type, but this is the + // Apache default and what Yahoo! uses.. + const TYPE_JS = 'application/x-javascript'; /** * @var bool Should the un-encoded version be cached? diff --git a/web/test/css/caio.css b/web/test/_test_files/css/caio.css similarity index 100% rename from web/test/css/caio.css rename to web/test/_test_files/css/caio.css diff --git a/web/test/css/caio.min.css b/web/test/_test_files/css/caio.min.css similarity index 100% rename from web/test/css/caio.min.css rename to web/test/_test_files/css/caio.min.css diff --git a/web/test/css/comments.css b/web/test/_test_files/css/comments.css similarity index 100% rename from web/test/css/comments.css rename to web/test/_test_files/css/comments.css diff --git a/web/test/css/comments.min.css b/web/test/_test_files/css/comments.min.css similarity index 100% rename from web/test/css/comments.min.css rename to web/test/_test_files/css/comments.min.css diff --git a/web/test/css/hacks.css b/web/test/_test_files/css/hacks.css similarity index 100% rename from web/test/css/hacks.css rename to web/test/_test_files/css/hacks.css diff --git a/web/test/css/hacks.min.css b/web/test/_test_files/css/hacks.min.css similarity index 100% rename from web/test/css/hacks.min.css rename to web/test/_test_files/css/hacks.min.css diff --git a/web/test/css/paths.css b/web/test/_test_files/css/paths.css similarity index 100% rename from web/test/css/paths.css rename to web/test/_test_files/css/paths.css diff --git a/web/test/css/paths.min.css b/web/test/_test_files/css/paths.min.css similarity index 100% rename from web/test/css/paths.min.css rename to web/test/_test_files/css/paths.min.css diff --git a/web/test/css/readme.txt b/web/test/_test_files/css/readme.txt similarity index 100% rename from web/test/css/readme.txt rename to web/test/_test_files/css/readme.txt diff --git a/web/test/css/styles.css b/web/test/_test_files/css/styles.css similarity index 100% rename from web/test/css/styles.css rename to web/test/_test_files/css/styles.css diff --git a/web/test/css/styles.min.css b/web/test/_test_files/css/styles.min.css similarity index 100% rename from web/test/css/styles.min.css rename to web/test/_test_files/css/styles.min.css diff --git a/web/test/css/subsilver.css b/web/test/_test_files/css/subsilver.css similarity index 100% rename from web/test/css/subsilver.css rename to web/test/_test_files/css/subsilver.css diff --git a/web/test/css/subsilver.min.css b/web/test/_test_files/css/subsilver.min.css similarity index 100% rename from web/test/css/subsilver.min.css rename to web/test/_test_files/css/subsilver.min.css diff --git a/web/test/html/before.html b/web/test/_test_files/html/before.html similarity index 100% rename from web/test/html/before.html rename to web/test/_test_files/html/before.html diff --git a/web/test/html/before.min.html b/web/test/_test_files/html/before.min.html similarity index 100% rename from web/test/html/before.min.html rename to web/test/_test_files/html/before.min.html diff --git a/web/test/js/before.js b/web/test/_test_files/js/before.js similarity index 100% rename from web/test/js/before.js rename to web/test/_test_files/js/before.js diff --git a/web/test/js/before.min.js b/web/test/_test_files/js/before.min.js similarity index 100% rename from web/test/js/before.min.js rename to web/test/_test_files/js/before.min.js diff --git a/web/test/minify/QueryString.js b/web/test/_test_files/minify/QueryString.js similarity index 100% rename from web/test/minify/QueryString.js rename to web/test/_test_files/minify/QueryString.js diff --git a/web/test/minify/email.js b/web/test/_test_files/minify/email.js similarity index 100% rename from web/test/minify/email.js rename to web/test/_test_files/minify/email.js diff --git a/web/test/minify/minified.css b/web/test/_test_files/minify/minified.css similarity index 100% rename from web/test/minify/minified.css rename to web/test/_test_files/minify/minified.css diff --git a/web/test/minify/minified.js b/web/test/_test_files/minify/minified.js similarity index 100% rename from web/test/minify/minified.js rename to web/test/_test_files/minify/minified.js diff --git a/web/test/packer/before.js b/web/test/_test_files/packer/before.js similarity index 100% rename from web/test/packer/before.js rename to web/test/_test_files/packer/before.js diff --git a/web/test/packer/before.min.js b/web/test/_test_files/packer/before.min.js similarity index 100% rename from web/test/packer/before.min.js rename to web/test/_test_files/packer/before.min.js diff --git a/web/test/test_CSS.php b/web/test/test_CSS.php index 969c95e..98eb654 100644 --- a/web/test/test_CSS.php +++ b/web/test/test_CSS.php @@ -1,32 +1,42 @@ read())) { - if (preg_match('/^([\w\\-]+)\.css$/', $entry, $m)) { - $list[] = $m[1]; - } -} -$d->close(); - -foreach ($list as $item) { - - $options = ($item === 'paths') - ? array('prependRelativePath' => '../') - : array(); +function test_CSS() +{ + global $thisDir; - $src = file_get_contents($thisDir . '/css/' . $item . '.css'); - $minExpected = file_get_contents($thisDir . '/css/' . $item . '.min.css'); - $minOutput = Minify_CSS::minify($src, $options); - assertTrue($minExpected === $minOutput, 'Minify_CSS : ' . $item); + $cssPath = dirname(__FILE__) . '/_test_files/css'; - if ($minExpected !== $minOutput) { - echo "\n---Source\n\n{$src}"; - echo "\n\n---Expected\n\n{$minExpected}"; - echo "\n\n---Output\n\n{$minOutput}\n\n\n\n"; + // build test file list + $d = dir($cssPath); + while (false !== ($entry = $d->read())) { + if (preg_match('/^([\w\\-]+)\.css$/', $entry, $m)) { + $list[] = $m[1]; + } } + $d->close(); + + foreach ($list as $item) { + + $options = ($item === 'paths') + ? array('prependRelativePath' => '../') + : array(); + + $src = file_get_contents($cssPath . "/{$item}.css"); + $minExpected = file_get_contents($cssPath . "/{$item}.min.css"); + $minOutput = Minify_CSS::minify($src, $options); + $passed = assertTrue($minExpected === $minOutput, 'Minify_CSS : ' . $item); + + if (__FILE__ === $_SERVER['SCRIPT_FILENAME']) { + echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n"; + if (!$passed) { + echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n"; + echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n"; + } + } + } } +test_CSS(); diff --git a/web/test/test_HTML.php b/web/test/test_HTML.php index 2f714a3..801ad70 100644 --- a/web/test/test_HTML.php +++ b/web/test/test_HTML.php @@ -1,22 +1,29 @@ array('Minify_CSS', 'minify') - ,'jsMinifier' => array('Minify_Javascript', 'minify') -)); - -$passed = assertTrue($minExpected === $minOutput, 'Minify_HTML'); - -echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}"; -if (! $passed) { - echo "\n\n\n\n---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}"; +function test_HTML() +{ + global $thisDir; + + $src = file_get_contents($thisDir . '/_test_files/html/before.html'); + $minExpected = file_get_contents($thisDir . '/_test_files/html/before.min.html'); + + $minOutput = Minify_HTML::minify($src, array( + 'cssMinifier' => array('Minify_CSS', 'minify') + ,'jsMinifier' => array('Minify_Javascript', 'minify') + )); + + $passed = assertTrue($minExpected === $minOutput, 'Minify_HTML'); + + if (__FILE__ === $_SERVER['SCRIPT_FILENAME']) { + echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n"; + echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n"; + echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n"; + } } -echo "\n\n---Source: " .strlen($src). " bytes\n\n{$src}"; + +test_HTML(); diff --git a/web/test/test_HTTP_Encoder.php b/web/test/test_HTTP_Encoder.php new file mode 100644 index 0000000..30e4262 --- /dev/null +++ b/web/test/test_HTTP_Encoder.php @@ -0,0 +1,97 @@ + 'Any browser' + ,'ae' => 'compress, x-gzip' + ,'exp' => array('gzip', 'x-gzip') + ,'desc' => 'recognize "x-gzip" as gzip' + ) + ,array( + 'ua' => 'Any browser' + ,'ae' => 'compress, x-gzip;q=0.5' + ,'exp' => array('gzip', 'x-gzip') + ,'desc' => 'gzip w/ non-zero q' + ) + ,array( + 'ua' => 'Any browser' + ,'ae' => 'compress, x-gzip;q=0' + ,'exp' => array('compress', 'compress') + ,'desc' => 'gzip w/ zero q' + ) + ,array( + 'ua' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)' + ,'ae' => 'gzip, deflate' + ,'exp' => array('', '') + ,'desc' => 'IE6 w/o "enhanced security"' + ) + ,array( + 'ua' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)' + ,'ae' => 'gzip, deflate' + ,'exp' => array('deflate', 'deflate') + ,'desc' => 'IE6 w/ "enhanced security"' + ) + ,array( + 'ua' => 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.01)' + ,'ae' => 'gzip, deflate' + ,'exp' => array('', '') + ,'desc' => 'IE5.5' + ) + ,array( + 'ua' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.25' + ,'ae' => 'gzip,deflate' + ,'exp' => array('deflate', 'deflate') + ,'desc' => 'Opera identifying as IE6' + ) + ); + + foreach ($methodTests as $test) { + $_SERVER['HTTP_USER_AGENT'] = $test['ua']; + $_SERVER['HTTP_ACCEPT_ENCODING'] = $test['ae']; + $exp = $test['exp']; + $ret = HTTP_Encoder::getAcceptedEncoding(); + $passed = assertTrue($exp == $ret, 'HTTP_Encoder : ' . $test['desc']); + + if (__FILE__ === $_SERVER['SCRIPT_FILENAME']) { + echo "\n--- AE | UA = {$test['ae']} | {$test['ua']}\n"; + echo "Expected = " . preg_replace('/\\s+/', ' ', var_export($exp, 1)) . "\n"; + echo "Returned = " . preg_replace('/\\s+/', ' ', var_export($ret, 1)) . "\n\n"; + } + } + + $variedContent = file_get_contents($thisDir . '/_test_files/html/before.html') + . file_get_contents($thisDir . '/_test_files/css/subsilver.css') + . file_get_contents($thisDir . '/../examples/1/jquery-1.2.3.js'); + + $encodingTests = array( + array('method' => 'gzip', 'exp' => 32174) + ,array('method' => 'deflate', 'exp' => 32156) + ,array('method' => 'compress', 'exp' => 32210) + ); + + foreach ($encodingTests as $test) { + $e = new HTTP_Encoder(array( + 'content' => $variedContent + ,'method' => $test['method'] + )); + $e->encode(9); + $ret = strlen($e->getContent()); + + $passed = assertTrue($ret == $test['exp'] + ,"HTTP_Encoder : {$test['method']} compression"); + + if (__FILE__ === $_SERVER['SCRIPT_FILENAME']) { + echo "\n--- {$test['method']}: expected bytes: " + , "{$test['exp']}. Returned: {$ret}\n\n"; + } + } +} + +test_HTTP_Encoder(); \ No newline at end of file diff --git a/web/test/test_Javascript.php b/web/test/test_Javascript.php index bd3e499..d94354a 100644 --- a/web/test/test_Javascript.php +++ b/web/test/test_Javascript.php @@ -1,16 +1,23 @@ true - ,'statusCode' => 200 - // Minify_Javascript always converts to \n line endings - ,'content' => preg_replace('/\\r\\n?/', "\n", file_get_contents($thisDir . '/minify/minified.js')) - ,'headers' => array ( - 'Cache-Control' => 'public', - 'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $tomorrow), - 'Content-Type' => 'application/x-javascript', - ) -); -$output = Minify::serve('Files', array( - 'files' => array( - $thisDir . '/minify/email.js' - ,$thisDir . '/minify/QueryString.js' - ) - ,'quiet' => true - ,'setExpires' => $tomorrow - ,'encodeOutput' => false -)); -$passed = assertTrue($expected === $output, 'Minify - JS and Expires'); -echo "\nOutput: " .var_export($output, 1). "\n\n"; -if (! $passed) { - echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n"; +function test_Minify() +{ + global $thisDir; + + $minifyTestPath = dirname(__FILE__) . '/_test_files/minify'; + $tomorrow = time() + 86400; + $lastModified = time() - 86400; + + // Test minifying JS and serving with Expires header + + $expected = array( + 'success' => true + ,'statusCode' => 200 + // Minify_Javascript always converts to \n line endings + ,'content' => preg_replace('/\\r\\n?/', "\n", file_get_contents($minifyTestPath . '/minified.js')) + ,'headers' => array ( + 'Cache-Control' => 'public', + 'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $tomorrow), + 'Content-Type' => 'application/x-javascript', + ) + ); + $output = Minify::serve('Files', array( + 'files' => array( + $minifyTestPath . '/email.js' + ,$minifyTestPath . '/QueryString.js' + ) + ,'quiet' => true + ,'setExpires' => $tomorrow + ,'encodeOutput' => false + )); + $passed = assertTrue($expected === $output, 'Minify : JS and Expires'); + + if (__FILE__ === $_SERVER['SCRIPT_FILENAME']) { + echo "\nOutput: " .var_export($output, 1). "\n\n"; + if (! $passed) { + echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n"; + } + } + + // Test minifying CSS and responding with Etag/Last-Modified + + // don't allow conditional headers + unset($_SERVER['HTTP_IF_NONE_MATCH'], $_SERVER['HTTP_IF_MODIFIED_SINCE']); + + $expected = array( + 'success' => true + ,'statusCode' => 200 + ,'content' => file_get_contents($minifyTestPath . '/minified.css') + ,'headers' => array ( + 'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified), + 'ETag' => "\"{$lastModified}pub\"", + 'Cache-Control' => 'max-age=0, public, must-revalidate', + 'Content-Type' => 'text/css', + ) + ); + $output = Minify::serve('Files', array( + 'files' => array( + $thisDir . '/_test_files/css/styles.css' + ,$thisDir . '/_test_files/css/subsilver.css' + ) + ,'quiet' => true + ,'lastModifiedTime' => $lastModified + ,'encodeOutput' => false + )); + $passed = assertTrue($expected === $output, 'Minify : CSS and Etag/Last-Modified'); + if (__FILE__ === $_SERVER['SCRIPT_FILENAME']) { + echo "\nOutput: " .var_export($output, 1). "\n\n"; + if (! $passed) { + echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n"; + } + } + + // Test 304 response + + // simulate conditional headers + $_SERVER['HTTP_IF_NONE_MATCH'] = "\"{$lastModified}pub\""; + $_SERVER['HTTP_IF_MODIFIED_SINCE'] = gmdate('D, d M Y H:i:s \G\M\T', $lastModified); + + $expected = array ( + 'success' => true + ,'statusCode' => 304 + ,'content' => '', + 'headers' => array() + ); + $output = Minify::serve('Files', array( + 'files' => array( + $thisDir . '/_test_files/css/styles.css' + ) + ,'quiet' => true + ,'lastModifiedTime' => $lastModified + ,'encodeOutput' => false + )); + $passed = assertTrue($expected === $output, 'Minify : 304 response'); + if (__FILE__ === $_SERVER['SCRIPT_FILENAME']) { + echo "\nOutput: " .var_export($output, 1). "\n\n"; + if (! $passed) { + echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n"; + } + } } - - -// Test minifying CSS and responding with Etag/Last-Modified - -// don't allow conditional headers -unset($_SERVER['HTTP_IF_NONE_MATCH'], $_SERVER['HTTP_IF_MODIFIED_SINCE']); - -$expected = array( - 'success' => true - ,'statusCode' => 200 - ,'content' => file_get_contents($thisDir . '/minify/minified.css') - ,'headers' => array ( - 'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified), - 'ETag' => "\"{$lastModified}pub\"", - 'Cache-Control' => 'max-age=0, public, must-revalidate', - 'Content-Type' => 'text/css', - ) -); -$output = Minify::serve('Files', array( - 'files' => array( - $thisDir . '/css/styles.css' - ,$thisDir . '/css/subsilver.css' - ) - ,'quiet' => true - ,'lastModifiedTime' => $lastModified - ,'encodeOutput' => false -)); -$passed = assertTrue($expected === $output, 'Minify - CSS and Etag/Last-Modified'); -echo "\nOutput: " .var_export($output, 1). "\n\n"; -if (! $passed) { - echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n"; -} - - -// Test 304 response - -// simulate conditional headers -$_SERVER['HTTP_IF_NONE_MATCH'] = "\"{$lastModified}pub\""; -$_SERVER['HTTP_IF_MODIFIED_SINCE'] = gmdate('D, d M Y H:i:s \G\M\T', $lastModified); - -$expected = array ( - 'success' => true - ,'statusCode' => 304 - ,'content' => '', - 'headers' => array() -); -$output = Minify::serve('Files', array( - 'files' => array( - $thisDir . '/css/styles.css' - ) - ,'quiet' => true - ,'lastModifiedTime' => $lastModified - ,'encodeOutput' => false -)); -$passed = assertTrue($expected === $output, 'Minify - 304 response'); -echo "\nOutput: " .var_export($output, 1). "\n\n"; -if (! $passed) { - echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n"; -} +test_Minify(); diff --git a/web/test/test_Packer.php b/web/test/test_Packer.php index c2752e1..f0b6868 100644 --- a/web/test/test_Packer.php +++ b/web/test/test_Packer.php @@ -1,16 +1,23 @@ \ No newline at end of file