mirror of
https://github.com/mrclay/minify.git
synced 2025-08-13 17:44:00 +02:00
V1.9.0 overhaul
This commit is contained in:
164
lib/HTTP/ConditionalGet.php
Normal file
164
lib/HTTP/ConditionalGet.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implement conditional GET via a timestamp or hash of content
|
||||
*
|
||||
* <code>
|
||||
* // easiest usage
|
||||
* $cg = new HTTP_ConditionalGet(array(
|
||||
* 'lastModifiedTime' => filemtime(__FILE__)
|
||||
* ));
|
||||
* $cg->sendHeaders();
|
||||
* if ($cg->cacheIsValid) {
|
||||
* exit(); // done
|
||||
* }
|
||||
* // echo content
|
||||
* </code>
|
||||
*
|
||||
*
|
||||
* <code>
|
||||
* // 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));
|
||||
* $cg->sendHeaders();
|
||||
* </code>
|
||||
*/
|
||||
class HTTP_ConditionalGet {
|
||||
|
||||
private $headers = array();
|
||||
private $lmTime = null;
|
||||
private $etag = null;
|
||||
public $cacheIsValid = null;
|
||||
|
||||
public function getHeaders() {
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on the PHP config, PHP will buffer all output and set
|
||||
* Content-Length for you. If it doesn't, or you flush() while sending data,
|
||||
* you'll want to call this to let the client know up front.
|
||||
*/
|
||||
public function setContentLength($bytes) {
|
||||
return $this->headers['Content-Length'] = $bytes;
|
||||
}
|
||||
|
||||
public function sendHeaders() {
|
||||
$headers = $this->headers;
|
||||
if (array_key_exists('_responseCode', $headers)) {
|
||||
header($headers['_responseCode']);
|
||||
unset($headers['_responseCode']);
|
||||
}
|
||||
foreach ($headers as $name => $val) {
|
||||
header($name . ': ' . $val);
|
||||
}
|
||||
}
|
||||
|
||||
private function setEtag($hash, $scope) {
|
||||
$this->etag = '"' . $hash
|
||||
. substr($scope, 0, 3)
|
||||
. '"';
|
||||
$this->headers['ETag'] = $this->etag;
|
||||
}
|
||||
|
||||
private function setLastModified($time) {
|
||||
$this->lmTime = (int)$time;
|
||||
$this->headers['Last-Modified'] = self::gmtdate($time);
|
||||
}
|
||||
|
||||
// TODO: allow custom Cache-Control directives, but offer pre-configured
|
||||
// "modes" for common cache models
|
||||
public function __construct($spec) {
|
||||
$scope = (isset($spec['isPublic']) && $spec['isPublic'])
|
||||
? 'public'
|
||||
: 'private';
|
||||
// allow far-expires header
|
||||
if (isset($spec['cacheUntil'])) {
|
||||
if (is_numeric($spec['cacheUntil'])) {
|
||||
$spec['cacheUntil'] = self::gmtdate($spec['cacheUntil']);
|
||||
}
|
||||
$this->headers = array(
|
||||
'Cache-Control' => $scope
|
||||
,'Expires' => $spec['cacheUntil']
|
||||
);
|
||||
$this->cacheIsValid = false;
|
||||
return;
|
||||
}
|
||||
if (isset($spec['lastModifiedTime'])) {
|
||||
// base both headers on time
|
||||
$this->setLastModified($spec['lastModifiedTime']);
|
||||
$this->setEtag($spec['lastModifiedTime'], $scope);
|
||||
} else {
|
||||
// hope to use ETag
|
||||
if (isset($spec['contentHash'])) {
|
||||
$this->setEtag($spec['contentHash'], $scope);
|
||||
}
|
||||
}
|
||||
$this->headers['Cache-Control'] = "max-age=0, {$scope}, must-revalidate";
|
||||
// invalidate cache if disabled, otherwise check
|
||||
$this->cacheIsValid = (isset($spec['invalidate']) && $spec['invalidate'])
|
||||
? false
|
||||
: $this->isCacheValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine validity of client cache and queue 304 header if valid
|
||||
*/
|
||||
private function isCacheValid()
|
||||
{
|
||||
if (null === $this->etag) {
|
||||
// ETag was our backup, so we know we don't have lmTime either
|
||||
return false;
|
||||
}
|
||||
$isValid = ($this->resourceMatchedEtag() || $this->resourceNotModified());
|
||||
if ($isValid) {
|
||||
// overwrite headers, only need 304
|
||||
$this->headers = array(
|
||||
'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
||||
);
|
||||
}
|
||||
return $isValid;
|
||||
}
|
||||
|
||||
private function resourceMatchedEtag() {
|
||||
if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
||||
return false;
|
||||
}
|
||||
$cachedEtagList = get_magic_quotes_gpc()
|
||||
? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])
|
||||
: $_SERVER['HTTP_IF_NONE_MATCH'];
|
||||
$cachedEtags = split(',', $cachedEtagList);
|
||||
foreach ($cachedEtags as $cachedEtag) {
|
||||
if (trim($cachedEtag) == $this->etag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function resourceNotModified() {
|
||||
if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
|
||||
return false;
|
||||
}
|
||||
$ifModifiedSince = get_magic_quotes_gpc()
|
||||
? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
||||
: $_SERVER['HTTP_IF_MODIFIED_SINCE'];
|
||||
if (false !== ($semicolon = strrpos($ifModifiedSince, ';'))) {
|
||||
// IE has tacked on extra data to this header, strip it
|
||||
$ifModifiedSince = substr($ifModifiedSince, 0, $semicolon);
|
||||
}
|
||||
return ($ifModifiedSince == self::gmtdate($this->lmTime));
|
||||
}
|
||||
|
||||
private static function gmtdate($ts) {
|
||||
return gmdate('D, d M Y H:i:s \G\M\T', $ts);
|
||||
}
|
||||
}
|
||||
|
44
lib/HTTP/ConditionalGet/test/2.php
Normal file
44
lib/HTTP/ConditionalGet/test/2.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
require '../../ConditionalGet.php';
|
||||
|
||||
// emulate regularly updating document
|
||||
$every = 20;
|
||||
$lastModified = round(time()/$every)*$every - $every;
|
||||
|
||||
$cg = new HTTP_ConditionalGet(array(
|
||||
'lastModifiedTime' => $lastModified
|
||||
));
|
||||
if ($cg->cacheIsValid) {
|
||||
$cg->sendHeaders();
|
||||
// we're done
|
||||
exit();
|
||||
}
|
||||
|
||||
// generate content
|
||||
$title = 'Last-Modified is known : add Content-Length';
|
||||
$explain = '
|
||||
<p>Here, like <a href="./">the first example</a>, we know the Last-Modified time,
|
||||
but we also want to set the Content-Length to increase cacheability and allow
|
||||
HTTP persistent connections. Instead of sending headers immediately, we first
|
||||
generate our content, then use <code>setContentLength(strlen($content))</code>
|
||||
to add the header. Then finally call <code>sendHeaders()</code> and send the
|
||||
content.</p>
|
||||
<p><strong>Note:</strong> This is not required if your PHP config buffers all
|
||||
output and your script doesn\'t do any incremental flushing of the output
|
||||
buffer. PHP will generally set Content-Length for you if it can.</p>
|
||||
<p>This script emulates a document that changes every ' .$every. ' seconds.
|
||||
<br>This is version: ' . date('r', $lastModified) . '</p>
|
||||
';
|
||||
|
||||
require '_include.php';
|
||||
$content = get_content(array(
|
||||
'title' => $title
|
||||
,'explain' => $explain
|
||||
));
|
||||
|
||||
$cg->setContentLength(strlen($content));
|
||||
$cg->sendHeaders();
|
||||
send_slowly($content);
|
||||
|
||||
?>
|
39
lib/HTTP/ConditionalGet/test/3.php
Normal file
39
lib/HTTP/ConditionalGet/test/3.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
require '../../ConditionalGet.php';
|
||||
|
||||
// generate content first (not ideal)
|
||||
// emulate regularly updating document
|
||||
$every = 20;
|
||||
$lastModified = round(time()/$every)*$every - $every;
|
||||
$title = 'Last-Modified is unknown : use hash of content for ETag';
|
||||
$explain = '
|
||||
<p>When Last-Modified is unknown, you can still use ETags, but you need a short
|
||||
string that is unique for that content. In the worst case, you have to generate
|
||||
all the content first, <em>then</em> instantiate HTTP_ConditionalGet, setting
|
||||
the array key <code>contentHash</code> to the output of a hash function of the
|
||||
content. Since we have the full content, we might as well also use
|
||||
<code>setContentLength(strlen($content))</code> in the case where we need to
|
||||
send it.</p>
|
||||
<p>This script emulates a document that changes every ' .$every. ' seconds.
|
||||
<br>This is version: ' . date('r', $lastModified) . '</p>
|
||||
';
|
||||
require '_include.php';
|
||||
$content = get_content(array(
|
||||
'title' => $title
|
||||
,'explain' => $explain
|
||||
));
|
||||
|
||||
$cg = new HTTP_ConditionalGet(array(
|
||||
'contentHash' => substr(md5($content), 7)
|
||||
));
|
||||
if ($cg->cacheIsValid) {
|
||||
$cg->sendHeaders();
|
||||
// we're done
|
||||
exit();
|
||||
}
|
||||
$cg->setContentLength(strlen($content));
|
||||
$cg->sendHeaders();
|
||||
|
||||
send_slowly($content);
|
||||
|
||||
?>
|
46
lib/HTTP/ConditionalGet/test/4.php
Normal file
46
lib/HTTP/ConditionalGet/test/4.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
require '../../ConditionalGet.php';
|
||||
|
||||
// emulate regularly updating document
|
||||
$every = 20;
|
||||
$lastModified = round(time()/$every)*$every - $every;
|
||||
|
||||
$cg = new HTTP_ConditionalGet(array(
|
||||
'lastModifiedTime' => $lastModified
|
||||
));
|
||||
$cg->sendHeaders();
|
||||
if ($cg->cacheIsValid) {
|
||||
// we're done
|
||||
exit();
|
||||
}
|
||||
|
||||
// output encoded content
|
||||
|
||||
$title = 'ConditionalGet + Encoder';
|
||||
$explain = '
|
||||
<p>Using ConditionalGet and Encoder is straightforward. First impliment the
|
||||
ConditionalGet, then if the cache is not valid, encode and send the content</p>
|
||||
<p>This script emulates a document that changes every ' .$every. ' seconds.
|
||||
<br>This is version: ' . date('r', $lastModified) . '</p>
|
||||
';
|
||||
require '_include.php';
|
||||
$content = get_content(array(
|
||||
'title' => $title
|
||||
,'explain' => $explain
|
||||
));
|
||||
|
||||
require '../../Encoder.php';
|
||||
$he = new HTTP_Encoder(array(
|
||||
'content' => get_content(array(
|
||||
'title' => $title
|
||||
,'explain' => $explain
|
||||
))
|
||||
));
|
||||
$he->encode();
|
||||
|
||||
// usually you would just $he->sendAll(), but here we want to emulate slow
|
||||
// connection
|
||||
$he->sendHeaders();
|
||||
send_slowly($he->getContent());
|
||||
|
||||
?>
|
27
lib/HTTP/ConditionalGet/test/5.php
Normal file
27
lib/HTTP/ConditionalGet/test/5.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
require '../../ConditionalGet.php';
|
||||
|
||||
// far expires
|
||||
$cg = new HTTP_ConditionalGet(array(
|
||||
'cacheUntil' => (time() + 86400 * 365) // 1 yr
|
||||
));
|
||||
$cg->sendHeaders();
|
||||
|
||||
// generate, send content
|
||||
$title = 'Expires date is known';
|
||||
$explain = '
|
||||
<p>Here we set "cacheUntil" to a timestamp or GMT date string. This results in
|
||||
<code>$cacheIsValid</code> always being false, so content is always served, but
|
||||
with an Expires header.
|
||||
<p><strong>Note:</strong> This isn\'t a conditional GET, but is useful if you\'re
|
||||
used to the HTTP_ConditionalGet workflow already.</p>
|
||||
';
|
||||
|
||||
require '_include.php';
|
||||
echo get_content(array(
|
||||
'title' => $title
|
||||
,'explain' => $explain
|
||||
));
|
||||
|
||||
?>
|
67
lib/HTTP/ConditionalGet/test/_include.php
Normal file
67
lib/HTTP/ConditionalGet/test/_include.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
function send_slowly($content)
|
||||
{
|
||||
$half = ceil(strlen($content) / 2);
|
||||
$content = str_split($content, $half);
|
||||
while ($chunk = array_shift($content)) {
|
||||
sleep(1);
|
||||
echo $chunk;
|
||||
ob_flush();
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
function get_content($data)
|
||||
{
|
||||
ob_start();
|
||||
?>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>HTTP_ConditionalGet : <?php echo $data['title']; ?></title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>HTTP_ConditionalGet</h1>
|
||||
<h2><?php echo $data['title']; ?></h2>
|
||||
<?php echo $data['explain']; ?>
|
||||
<ul>
|
||||
<li><a href="./">Last-Modified is known : simple usage</a></li>
|
||||
<li><a href="2.php">Last-Modified is known : add Content-Length</a></li>
|
||||
<li><a href="3.php">Last-Modified is unknown : use hash of content for ETag</a></li>
|
||||
<li><a href="4.php">ConditionalGet + Encoder</a></li>
|
||||
<li><a href="5.php">Expires date is known</a></li>
|
||||
</ul>
|
||||
<h2>Notes</h2>
|
||||
<h3>How to distinguish 200 and 304 responses</h3>
|
||||
<p>For these pages all 200 responses are sent in chunks a second apart, so you
|
||||
should notice that 304 responses are quicker. You can also use HTTP sniffers
|
||||
like <a href="http://www.fiddlertool.com/">Fiddler (win)</a> and
|
||||
<a href="http://livehttpheaders.mozdev.org/">LiveHTTPHeaders (Firefox add-on)</a>
|
||||
to verify headers and content being sent.</p>
|
||||
<h3>Browser notes</h3>
|
||||
<dl>
|
||||
<dt>Opera</dt>
|
||||
<dd>Opera has a couple behaviors against the HTTP spec: Manual refreshes (F5)
|
||||
prevents the ETag/If-Modified-Since headers from being sent; it only sends
|
||||
them when following a link or bookmark. Also, Opera will not honor the
|
||||
<code>must-revalidate</code> Cache-Control value unless <code>max-age</code>
|
||||
is set. To get Opera to follow the spec, ConditionalGet will send Opera max-age=0
|
||||
(if one is not already set).</dd>
|
||||
<dt>Safari</dt>
|
||||
<dd>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.</dd>
|
||||
</dl>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $content;
|
||||
}
|
||||
|
||||
?>
|
36
lib/HTTP/ConditionalGet/test/index.php
Normal file
36
lib/HTTP/ConditionalGet/test/index.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
require '../../ConditionalGet.php';
|
||||
|
||||
// emulate regularly updating document
|
||||
$every = 20;
|
||||
$lastModified = round(time()/$every)*$every - $every;
|
||||
|
||||
$cg = new HTTP_ConditionalGet(array(
|
||||
'lastModifiedTime' => $lastModified
|
||||
));
|
||||
$cg->sendHeaders();
|
||||
if ($cg->cacheIsValid) {
|
||||
// we're done
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = 'Last-Modified is known : simple usage';
|
||||
$explain = '
|
||||
<p>If your content has not changed since a certain timestamp, set this via the
|
||||
the <code>lastModifiedTime</code> array key when instantiating HTTP_ConditionalGet.
|
||||
You can immediately call the method <code>sendHeaders()</code> to set the
|
||||
Last-Modified, ETag, and Cache-Control headers. The, if <code>cacheIsValid</code>
|
||||
property is false, you echo the content.</p>
|
||||
<p>This script emulates a document that changes every ' .$every. ' seconds.
|
||||
<br>This is version: ' . date('r', $lastModified) . '</p>
|
||||
';
|
||||
|
||||
require '_include.php';
|
||||
|
||||
echo send_slowly(get_content(array(
|
||||
'title' => $title
|
||||
,'explain' => $explain
|
||||
)));
|
||||
|
||||
?>
|
151
lib/HTTP/Encoder.php
Normal file
151
lib/HTTP/Encoder.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Encode and send gzipped/deflated content
|
||||
*
|
||||
* <code>
|
||||
* // Send a CSS file, compressed if possible
|
||||
* $he = new HTTP_Encoder(array(
|
||||
* 'content' => file_get_contents($cssFile)
|
||||
* ,'type' => 'text/css'
|
||||
* ));
|
||||
* $he->encode();
|
||||
* $he->sendAll();
|
||||
* </code>
|
||||
*
|
||||
* <code>
|
||||
* // Just sniff for the accepted encoding
|
||||
* $encoding = HTTP_Encoder::getAcceptedEncoding();
|
||||
* </code>
|
||||
*
|
||||
* For more control over headers, use getHeaders() and getData() and send your
|
||||
* own output.
|
||||
*/
|
||||
class HTTP_Encoder {
|
||||
|
||||
public static $compressionLevel = 6;
|
||||
private static $clientEncodeMethod = null;
|
||||
|
||||
private $content = '';
|
||||
private $headers = array();
|
||||
|
||||
private $encodeMethod = array('', '');
|
||||
|
||||
public function __construct($spec) {
|
||||
if (isset($spec['content'])) {
|
||||
$this->content = $spec['content'];
|
||||
}
|
||||
$this->headers['Content-Length'] = strlen($this->content);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public function getContent() {
|
||||
return $this->content;
|
||||
}
|
||||
public function getHeaders() {
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the file and headers (encoded or not)
|
||||
*
|
||||
* You must call this before headers are sent and it probably cannot be
|
||||
* used in conjunction with zlib output buffering / mod_gzip. Errors are
|
||||
* not handled purposefully.
|
||||
*/
|
||||
public function sendAll() {
|
||||
$this->sendHeaders();
|
||||
echo $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send just the headers
|
||||
*/
|
||||
public function sendHeaders() {
|
||||
foreach ($this->headers as $name => $val) {
|
||||
header($name . ': ' . $val);
|
||||
}
|
||||
}
|
||||
|
||||
// returns array(encoding, encoding to use in Content-Encoding header)
|
||||
// eg. array('gzip', 'x-gzip')
|
||||
public static function getAcceptedEncoding() {
|
||||
if (self::$clientEncodeMethod !== null) {
|
||||
return self::$clientEncodeMethod;
|
||||
}
|
||||
if (! isset($_SERVER['HTTP_ACCEPT_ENCODING'])
|
||||
|| self::isBuggyIe())
|
||||
{
|
||||
return array('', '');
|
||||
}
|
||||
// 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'])) {
|
||||
return array('deflate', 'deflate');
|
||||
}
|
||||
if (preg_match('@(?:^|,)\s*((?:x-)?compress)\s*(?:$|,|;\s*q=(?:0\.|1))@', $_SERVER['HTTP_ACCEPT_ENCODING'], $m)) {
|
||||
return array('compress', $m[1]);
|
||||
}
|
||||
return array('', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* If conditionsEncode the content
|
||||
* @return bool success
|
||||
*/
|
||||
public function encode($compressionLevel = null) {
|
||||
if (null === $compressionLevel) {
|
||||
$compressionLevel = self::$compressionLevel;
|
||||
}
|
||||
if ('' === $this->encodeMethod[0]
|
||||
|| ($compressionLevel == 0)
|
||||
|| !extension_loaded('zlib'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ($this->encodeMethod[0] === 'gzip') {
|
||||
$encoded = gzencode($this->content, $compressionLevel);
|
||||
} elseif ($this->encodeMethod[0] === 'deflate') {
|
||||
$encoded = gzdeflate($this->content, $compressionLevel);
|
||||
} else {
|
||||
$encoded = gzcompress($this->content, $compressionLevel);
|
||||
}
|
||||
if (false === $encoded) {
|
||||
return false;
|
||||
}
|
||||
$this->headers['Content-Length'] = strlen($encoded);
|
||||
$this->headers['Content-Encoding'] = $this->encodeMethod[1];
|
||||
$this->headers['Vary'] = 'Accept-Encoding';
|
||||
$this->content = $encoded;
|
||||
return true;
|
||||
}
|
||||
|
||||
private 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))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$version = floatval($m[1]);
|
||||
if ($version < 6) return true;
|
||||
if ($version == 6 && !strstr($_SERVER['HTTP_USER_AGENT'], 'SV1')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
BIN
lib/HTTP/Encoder/test/green.png
Normal file
BIN
lib/HTTP/Encoder/test/green.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 202 B |
60
lib/HTTP/Encoder/test/index.php
Normal file
60
lib/HTTP/Encoder/test/index.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
ini_set('display_errors', 'on');
|
||||
|
||||
require '../../Encoder.php';
|
||||
|
||||
if (!isset($_GET['test'])) {
|
||||
$type = 'text/html';
|
||||
ob_start();
|
||||
?>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>HTTP_Encoder Test</title>
|
||||
<style type="text/css">
|
||||
@import "?test=2";
|
||||
#img {background:url("?test=1");}
|
||||
.green {background:#0f0;}
|
||||
p span {padding:0 .5em;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>HTTP_Encoder test</h1>
|
||||
<p><span class="green"> HTML </span></p>
|
||||
<p><span id="css"> CSS </span></p>
|
||||
<p><span id="js"> Javascript </span></p>
|
||||
<p><span id="img"> image </span></p>
|
||||
<script src="?test=3" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
} elseif ($_GET['test'] == '1') {
|
||||
$content = file_get_contents(dirname(__FILE__) . '/green.png');
|
||||
$type = 'image/png';
|
||||
|
||||
} elseif ($_GET['test'] == '2') {
|
||||
$content = '#css {background:#0f0;}';
|
||||
$type = 'text/css';
|
||||
|
||||
} else {
|
||||
$content = '
|
||||
window.onload = function(){
|
||||
document.getElementById("js").className = "green";
|
||||
};
|
||||
';
|
||||
$type = 'text/javascript';
|
||||
|
||||
}
|
||||
|
||||
$he = new HTTP_Encoder(array(
|
||||
'content' => $content
|
||||
,'type' => $type
|
||||
));
|
||||
$he->encode();
|
||||
$he->sendAll();
|
||||
|
||||
?>
|
Reference in New Issue
Block a user