1
0
mirror of https://github.com/mrclay/minify.git synced 2025-08-04 13:17:32 +02:00

Perf update for JSmin (Minify_Javascript), + phpDocs for public HTTP_* class APIs, minor Minify fix, private members changed to protected to allow easier subclassing.

This commit is contained in:
Steve Clay
2008-03-03 16:23:39 +00:00
parent 7a3d7129b4
commit e8ac1dc8d0
9 changed files with 304 additions and 161 deletions

View File

@@ -32,49 +32,43 @@
*/ */
class HTTP_ConditionalGet { class HTTP_ConditionalGet {
private $headers = array(); /**
private $lmTime = null; * Does the client have a valid copy of the requested resource?
private $etag = null; *
* You'll want to check this after instantiating the object. If true, do
* not send content, just call sendHeaders() if you haven't already.
*
* @var bool
*/
public $cacheIsValid = null; public $cacheIsValid = null;
public function getHeaders() {
return $this->headers;
}
/** /**
* Depending on the PHP config, PHP will buffer all output and set * @param array $spec options
* 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. * '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)
*
* 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers
* will be sent with content. This is recommended.
*
* 'contentHash': (string) if given, only the ETag header can be sent with
* content (only HTTP1.1 clients can conditionally GET). The given string
* should be short with no quote characters and always change when the
* resource changes (recommend md5()). This is not needed/used if
* lastModifiedTime is given.
*
* 'invalidate': (bool) if true, the client cache will be considered invalid
* without testing. Effectively this disables conditional GET.
* (default false)
*
* 'setExpires': (mixed) set this to a timestamp or GMT date to send an
* Expires header with the content instead of ETag/Last-Modified. If given,
* Conditional GETs will not be performed, but the public/private
* Cache-Control header will still be sent. (default null)
*
* @return null
*/ */
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) { public function __construct($spec) {
$scope = (isset($spec['isPublic']) && $spec['isPublic']) $scope = (isset($spec['isPublic']) && $spec['isPublic'])
? 'public' ? 'public'
@@ -84,7 +78,7 @@ class HTTP_ConditionalGet {
if (is_numeric($spec['setExpires'])) { if (is_numeric($spec['setExpires'])) {
$spec['setExpires'] = self::gmtdate($spec['setExpires']); $spec['setExpires'] = self::gmtdate($spec['setExpires']);
} }
$this->headers = array( $this->_headers = array(
'Cache-Control' => $scope 'Cache-Control' => $scope
,'Expires' => $spec['setExpires'] ,'Expires' => $spec['setExpires']
); );
@@ -93,41 +87,114 @@ class HTTP_ConditionalGet {
} }
if (isset($spec['lastModifiedTime'])) { if (isset($spec['lastModifiedTime'])) {
// base both headers on time // base both headers on time
$this->setLastModified($spec['lastModifiedTime']); $this->_setLastModified($spec['lastModifiedTime']);
$this->setEtag($spec['lastModifiedTime'], $scope); $this->_setEtag($spec['lastModifiedTime'], $scope);
} else { } else {
// hope to use ETag // hope to use ETag
if (isset($spec['contentHash'])) { if (isset($spec['contentHash'])) {
$this->setEtag($spec['contentHash'], $scope); $this->_setEtag($spec['contentHash'], $scope);
} }
} }
$this->headers['Cache-Control'] = "max-age=0, {$scope}, must-revalidate"; $this->_headers['Cache-Control'] = "max-age=0, {$scope}, must-revalidate";
// invalidate cache if disabled, otherwise check // invalidate cache if disabled, otherwise check
$this->cacheIsValid = (isset($spec['invalidate']) && $spec['invalidate']) $this->cacheIsValid = (isset($spec['invalidate']) && $spec['invalidate'])
? false ? false
: $this->isCacheValid(); : $this->_isCacheValid();
}
/**
* Get array of output headers to be sent
*
* In the case of 304 responses, this array will only contain the response
* code header: array('_responseCode' => 'HTTP/1.0 304 Not Modified')
*
* Otherwise something like:
* <code>
* array(
* 'Cache-Control' => 'max-age=0, public, must-revalidate'
* ,'ETag' => '"foobar"'
* )
* </code>
*
* @return array
*/
public function getHeaders() {
return $this->_headers;
}
/**
* Set the Content-Length header in bytes
*
* With most PHP configs, as long as you don't flush() output, this method
* is not needed and PHP will buffer all output and set Content-Length for
* you. Otherwise you'll want to call this to let the client know up front.
*
* @param int $bytes
*
* @return int copy of input $bytes
*/
public function setContentLength($bytes) {
return $this->_headers['Content-Length'] = $bytes;
}
/**
* Send headers
*
* @see getHeaders()
*
* Note this doesn't "clear" the headers. Calling sendHeaders() will
* call header() again (but probably have not effect) and getHeaders() will
* still return the headers.
*
* @return null
*/
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);
}
}
protected $_headers = array();
protected $_lmTime = null;
protected $_etag = null;
protected function _setEtag($hash, $scope) {
$this->_etag = '"' . $hash
. substr($scope, 0, 3)
. '"';
$this->_headers['ETag'] = $this->_etag;
}
protected function _setLastModified($time) {
$this->_lmTime = (int)$time;
$this->_headers['Last-Modified'] = self::gmtdate($time);
} }
/** /**
* Determine validity of client cache and queue 304 header if valid * Determine validity of client cache and queue 304 header if valid
*/ */
private function isCacheValid() protected function _isCacheValid()
{ {
if (null === $this->etag) { if (null === $this->_etag) {
// ETag was our backup, so we know we don't have lmTime either // ETag was our backup, so we know we don't have lmTime either
return false; return false;
} }
$isValid = ($this->resourceMatchedEtag() || $this->resourceNotModified()); $isValid = ($this->resourceMatchedEtag() || $this->resourceNotModified());
if ($isValid) { if ($isValid) {
// overwrite headers, only need 304 // overwrite headers, only need 304
$this->headers = array( $this->_headers = array(
'_responseCode' => 'HTTP/1.0 304 Not Modified' '_responseCode' => 'HTTP/1.0 304 Not Modified'
); );
} }
return $isValid; return $isValid;
} }
private function resourceMatchedEtag() { protected function resourceMatchedEtag() {
if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) { if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
return false; return false;
} }
@@ -136,14 +203,14 @@ class HTTP_ConditionalGet {
: $_SERVER['HTTP_IF_NONE_MATCH']; : $_SERVER['HTTP_IF_NONE_MATCH'];
$cachedEtags = split(',', $cachedEtagList); $cachedEtags = split(',', $cachedEtagList);
foreach ($cachedEtags as $cachedEtag) { foreach ($cachedEtags as $cachedEtag) {
if (trim($cachedEtag) == $this->etag) { if (trim($cachedEtag) == $this->_etag) {
return true; return true;
} }
} }
return false; return false;
} }
private function resourceNotModified() { protected function resourceNotModified() {
if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
return false; return false;
} }
@@ -154,11 +221,10 @@ class HTTP_ConditionalGet {
// IE has tacked on extra data to this header, strip it // IE has tacked on extra data to this header, strip it
$ifModifiedSince = substr($ifModifiedSince, 0, $semicolon); $ifModifiedSince = substr($ifModifiedSince, 0, $semicolon);
} }
return ($ifModifiedSince == self::gmtdate($this->lmTime)); return ($ifModifiedSince == self::gmtdate($this->_lmTime));
} }
private static function gmtdate($ts) { protected static function gmtdate($ts) {
return gmdate('D, d M Y H:i:s \G\M\T', $ts); return gmdate('D, d M Y H:i:s \G\M\T', $ts);
} }
} }

View File

@@ -104,7 +104,7 @@ class HTTP_ConditionalGet_Build {
file_put_contents($file, "{$this->lastModified}|{$nextCheck}"); file_put_contents($file, "{$this->lastModified}|{$nextCheck}");
} }
private static function _scan($max, $path, $options) protected static function _scan($max, $path, $options)
{ {
$d = dir($path); $d = dir($path);
while (false !== ($entry = $d->read())) { while (false !== ($entry = $d->read())) {

View File

@@ -23,70 +23,134 @@
*/ */
class HTTP_Encoder { class HTTP_Encoder {
/**
* Default compression level for zlib operations
*
* This level is used if encode() is not given a $compressionLevel
*
* @var int
*/
public static $compressionLevel = 6; public static $compressionLevel = 6;
private static $clientEncodeMethod = null;
private $content = '';
private $headers = array();
private $encodeMethod = array('', '');
/**
* Get an HTTP Encoder object
*
* @param array $spec options
*
* 'content': (string required) content to be encoded
*
* 'type': (string) if set, the Content-Type header will have this value.
*
* 'method: (string) only set this if you are forcing a particular encoding
* method. If not set, the best method will be chosen by getAcceptedEncoding()
* The available methods are 'gzip', 'deflate', 'compress', and '' (no
* encoding)
*
* @return null
*/
public function __construct($spec) { public function __construct($spec) {
if (isset($spec['content'])) { $this->_content = $spec['content'];
$this->content = $spec['content']; $this->_headers['Content-Length'] = (string)strlen($this->_content);
}
$this->headers['Content-Length'] = strlen($this->content);
if (isset($spec['type'])) { if (isset($spec['type'])) {
$this->headers['Content-Type'] = $spec['type']; $this->_headers['Content-Type'] = $spec['type'];
} }
if (self::$clientEncodeMethod === null) { if (self::$_clientEncodeMethod === null) {
self::$clientEncodeMethod = self::getAcceptedEncoding(); self::$_clientEncodeMethod = self::getAcceptedEncoding();
} }
if (isset($spec['method']) if (isset($spec['method'])
&& in_array($spec['method'], array('gzip', 'deflate', 'compress', ''))) && in_array($spec['method'], array('gzip', 'deflate', 'compress', '')))
{ {
$this->encodeMethod = array($spec['method'], $spec['method']); $this->_encodeMethod = array($spec['method'], $spec['method']);
} else { } else {
$this->encodeMethod = self::$clientEncodeMethod; $this->_encodeMethod = self::$_clientEncodeMethod;
} }
} }
public function getContent() {
return $this->content;
}
public function getHeaders() {
return $this->headers;
}
/** /**
* Send the file and headers (encoded or not) * Get content in current form
*
* Call after encode() for encoded content.
*
* return string
*/
public function getContent() {
return $this->_content;
}
/**
* Get array of output headers to be sent
*
* E.g.
* <code>
* array(
* 'Content-Length' => '615'
* ,'Content-Encoding' => 'x-gzip'
* ,'Vary' => 'Accept-Encoding'
* )
* </code>
*
* @return array
*/
public function getHeaders() {
return $this->_headers;
}
/**
* Send output headers
* *
* You must call this before headers are sent and it probably cannot be * You must call this before headers are sent and it probably cannot be
* used in conjunction with zlib output buffering / mod_gzip. Errors are * used in conjunction with zlib output buffering / mod_gzip. Errors are
* not handled purposefully. * not handled purposefully.
*/ *
public function sendAll() { * @see getHeaders()
$this->sendHeaders(); *
echo $this->content; * @return null
}
/**
* Send just the headers
*/ */
public function sendHeaders() { public function sendHeaders() {
foreach ($this->headers as $name => $val) { foreach ($this->_headers as $name => $val) {
header($name . ': ' . $val); header($name . ': ' . $val);
} }
} }
// returns array(encoding, encoding to use in Content-Encoding header) /**
// eg. array('gzip', 'x-gzip') * Send output headers and content
*
* A shortcut for sendHeaders() and echo getContent()
*
* 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.
*
* @return null
*/
public function sendAll() {
$this->sendHeaders();
echo $this->_content;
}
/**
* Determine the client's best encoding method from the HTTP Accept-Encoding
* header.
*
* If no Accept-Encoding header is set, or the browser is IE before v6 SP2,
* 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
*
* @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() { public static function getAcceptedEncoding() {
if (self::$clientEncodeMethod !== null) { if (self::$_clientEncodeMethod !== null) {
return self::$clientEncodeMethod; return self::$_clientEncodeMethod;
} }
if (! isset($_SERVER['HTTP_ACCEPT_ENCODING']) if (! isset($_SERVER['HTTP_ACCEPT_ENCODING'])
|| self::isBuggyIe()) || self::_isBuggyIe())
{ {
return array('', ''); return array('', '');
} }
@@ -104,37 +168,55 @@ class HTTP_Encoder {
} }
/** /**
* If conditionsEncode the content * Encode (compress) the content
* @return bool success *
* If the encode method is '' (none) or compression level is 0, or the 'zlib'
* extension isn't loaded, we return false.
*
* Then the appropriate gz_* function is called to compress the content. If
* this fails, false is returned.
*
* If successful, the Content-Length header is updated, and Content-Encoding
* and Vary headers are added.
*
* @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 function encode($compressionLevel = null) { public function encode($compressionLevel = null) {
if (null === $compressionLevel) { if (null === $compressionLevel) {
$compressionLevel = self::$compressionLevel; $compressionLevel = self::$compressionLevel;
} }
if ('' === $this->encodeMethod[0] if ('' === $this->_encodeMethod[0]
|| ($compressionLevel == 0) || ($compressionLevel == 0)
|| !extension_loaded('zlib')) || !extension_loaded('zlib'))
{ {
return false; return false;
} }
if ($this->encodeMethod[0] === 'gzip') { if ($this->_encodeMethod[0] === 'gzip') {
$encoded = gzencode($this->content, $compressionLevel); $encoded = gzencode($this->_content, $compressionLevel);
} elseif ($this->encodeMethod[0] === 'deflate') { } elseif ($this->_encodeMethod[0] === 'deflate') {
$encoded = gzdeflate($this->content, $compressionLevel); $encoded = gzdeflate($this->_content, $compressionLevel);
} else { } else {
$encoded = gzcompress($this->content, $compressionLevel); $encoded = gzcompress($this->_content, $compressionLevel);
} }
if (false === $encoded) { if (false === $encoded) {
return false; return false;
} }
$this->headers['Content-Length'] = strlen($encoded); $this->_headers['Content-Length'] = strlen($encoded);
$this->headers['Content-Encoding'] = $this->encodeMethod[1]; $this->_headers['Content-Encoding'] = $this->_encodeMethod[1];
$this->headers['Vary'] = 'Accept-Encoding'; $this->_headers['Vary'] = 'Accept-Encoding';
$this->content = $encoded; $this->_content = $encoded;
return true; return true;
} }
private static function isBuggyIe() protected static $_clientEncodeMethod = null;
protected $content = '';
protected $headers = array();
protected $encodeMethod = array('', '');
protected static function _isBuggyIe()
{ {
if (strstr($_SERVER['HTTP_USER_AGENT'], 'Opera') if (strstr($_SERVER['HTTP_USER_AGENT'], 'Opera')
|| !preg_match('/^Mozilla\/4\.0 \(compatible; MSIE ([0-9]\.[0-9])/i', $_SERVER['HTTP_USER_AGENT'], $m)) || !preg_match('/^Mozilla\/4\.0 \(compatible; MSIE ([0-9]\.[0-9])/i', $_SERVER['HTTP_USER_AGENT'], $m))

View File

@@ -146,16 +146,15 @@ class Minify {
$cg = new HTTP_ConditionalGet($cgOptions); $cg = new HTTP_ConditionalGet($cgOptions);
if ($cg->cacheIsValid) { if ($cg->cacheIsValid) {
// client's cache is valid // client's cache is valid
if (self::$_options['quiet']) { if (! self::$_options['quiet']) {
$cg->sendHeaders();
}
return array( return array(
'success' => true 'success' => true
,'statusCode' => 304 ,'statusCode' => 304
,'content' => '' ,'content' => ''
,'headers' => array() ,'headers' => array()
); );
} else {
$cg->sendHeaders();
}
} }
// client will need output // client will need output
$headers = $cg->getHeaders(); $headers = $cg->getHeaders();
@@ -216,22 +215,22 @@ class Minify {
/** /**
* @var mixed null if disk cache is not to be used * @var mixed null if disk cache is not to be used
*/ */
private static $_cachePath = null; protected static $_cachePath = null;
/** /**
* @var Minify_Controller active controller for current request * @var Minify_Controller active controller for current request
*/ */
private static $_controller = null; protected static $_controller = null;
/** /**
* @var array options for current request * @var array options for current request
*/ */
private static $_options = null; protected static $_options = null;
/** /**
* @var Cache_Lite_File cache obj for current request * @var Cache_Lite_File cache obj for current request
*/ */
private static $_cache = null; protected static $_cache = null;
@@ -247,7 +246,7 @@ class Minify {
* *
* @return string minified, encoded content * @return string minified, encoded content
*/ */
private static function _fetchContent($encodeMethod) protected static function _fetchContent($encodeMethod)
{ {
$cacheId = self::_getCacheId(self::$_controller->sources, self::$_options) $cacheId = self::_getCacheId(self::$_controller->sources, self::$_options)
. $encodeMethod; . $encodeMethod;
@@ -278,7 +277,7 @@ class Minify {
* *
* @return null * @return null
*/ */
private static function _setupCache() { protected static function _setupCache() {
// until the patch is rolled into PEAR, we'll provide the // until the patch is rolled into PEAR, we'll provide the
// class in our package // class in our package
require_once dirname(__FILE__) . '/Cache/Lite/File.php'; require_once dirname(__FILE__) . '/Cache/Lite/File.php';
@@ -297,7 +296,7 @@ class Minify {
* *
* @return string * @return string
*/ */
private static function _combineMinify() { protected static function _combineMinify() {
$type = self::$_options['contentType']; // ease readability $type = self::$_options['contentType']; // ease readability
// when combining scripts, make sure all statements separated // when combining scripts, make sure all statements separated
@@ -366,7 +365,7 @@ class Minify {
* *
* @return string * @return string
*/ */
private static function _encode($content) protected static function _encode($content)
{ {
if (self::$_options['encodeMethod'] === '' if (self::$_options['encodeMethod'] === ''
|| ! self::$_options['encodeOutput']) { || ! self::$_options['encodeOutput']) {
@@ -389,7 +388,7 @@ class Minify {
* *
* @return string * @return string
*/ */
private static function _getCacheId() { protected static function _getCacheId() {
return md5(serialize(array( return md5(serialize(array(
Minify_Source::getDigest(self::$_controller->sources) Minify_Source::getDigest(self::$_controller->sources)
,self::$_options['minifiers'] ,self::$_options['minifiers']

View File

@@ -87,17 +87,17 @@ class Minify_CSS {
* *
* I.e. are some browsers targetted until the next comment? * I.e. are some browsers targetted until the next comment?
*/ */
private static $_inHack = false; protected static $_inHack = false;
/** /**
* @var string string to be prepended to relative URIs * @var string string to be prepended to relative URIs
*/ */
private static $_tempPrepend = ''; protected static $_tempPrepend = '';
/** /**
* @var string path of this stylesheet for rewriting purposes * @var string path of this stylesheet for rewriting purposes
*/ */
private static $_tempCurrentPath = ''; protected static $_tempCurrentPath = '';
/** /**
* Process what looks like a comment and return a replacement * Process what looks like a comment and return a replacement
@@ -106,7 +106,7 @@ class Minify_CSS {
* *
* @return string * @return string
*/ */
private static function _commentCB($m) protected static function _commentCB($m)
{ {
$m = $m[1]; $m = $m[1];
// $m is everything after the opening tokens and before the closing tokens // $m is everything after the opening tokens and before the closing tokens
@@ -148,12 +148,12 @@ class Minify_CSS {
* *
* @return string * @return string
*/ */
private static function _selectorsCB($m) protected static function _selectorsCB($m)
{ {
return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]); return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
} }
private static function _urlCB($m) protected static function _urlCB($m)
{ {
$isImport = (0 === strpos($m[0], '@import')); $isImport = (0 === strpos($m[0], '@import'));
if ($isImport) { if ($isImport) {

View File

@@ -54,7 +54,7 @@ class Minify_Controller_Page extends Minify_Controller_Base {
return $options; return $options;
} }
private $_loadCssJsMinifiers = false; protected $_loadCssJsMinifiers = false;
/** /**
* @see Minify_Controller_Base::loadMinifier() * @see Minify_Controller_Base::loadMinifier()

View File

@@ -84,21 +84,21 @@ class Minify_HTML {
return $html; return $html;
} }
private static $_isXhtml = false; protected static $_isXhtml = false;
private static $_replacementHash = null; protected static $_replacementHash = null;
private static $_pres = array(); protected static $_pres = array();
private static $_scripts = array(); protected static $_scripts = array();
private static $_styles = array(); protected static $_styles = array();
private static $_cssMinifier = null; protected static $_cssMinifier = null;
private static $_jsMinifier = null; protected static $_jsMinifier = null;
private static function _removePreCB($m) protected static function _removePreCB($m)
{ {
self::$_pres[] = $m[1]; self::$_pres[] = $m[1];
return self::$_replacementHash . 'PRE' . count(self::$_pres); return self::$_replacementHash . 'PRE' . count(self::$_pres);
} }
private static function _removeStyleCB($m) protected static function _removeStyleCB($m)
{ {
$openStyle = $m[1]; $openStyle = $m[1];
$css = $m[2]; $css = $m[2];
@@ -123,7 +123,7 @@ class Minify_HTML {
return self::$_replacementHash . 'STYLE' . count(self::$_styles); return self::$_replacementHash . 'STYLE' . count(self::$_styles);
} }
private static function _removeScriptCB($m) protected static function _removeScriptCB($m)
{ {
$openScript = $m[1]; $openScript = $m[1];
$js = $m[2]; $js = $m[2];
@@ -147,14 +147,14 @@ class Minify_HTML {
return self::$_replacementHash . 'SCRIPT' . count(self::$_scripts); return self::$_replacementHash . 'SCRIPT' . count(self::$_scripts);
} }
private static function _removeCdata($str) protected static function _removeCdata($str)
{ {
return (false !== strpos($str, '<![CDATA[')) return (false !== strpos($str, '<![CDATA['))
? str_replace(array('<![CDATA[', ']]>'), '', $str) ? str_replace(array('<![CDATA[', ']]>'), '', $str)
: $str; : $str;
} }
private static function _needsCdata($str) protected static function _needsCdata($str)
{ {
return (self::$_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str)); return (self::$_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
} }

View File

@@ -39,9 +39,9 @@
* @package Minify_Javascript * @package Minify_Javascript
* @author Ryan Grove <ryan@wonko.com> * @author Ryan Grove <ryan@wonko.com>
* @copyright 2002 Douglas Crockford <douglas@crockford.com> (JSMin.c) * @copyright 2002 Douglas Crockford <douglas@crockford.com> (JSMin.c)
* @copyright 2007 Ryan Grove <ryan@wonko.com> (PHP port) * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
* @license http://opensource.org/licenses/mit-license.php MIT License * @license http://opensource.org/licenses/mit-license.php MIT License
* @version 1.1.0 (2007-06-01) * @version 1.1.1 (2008-03-03)
* @link http://code.google.com/p/jsmin-php/ * @link http://code.google.com/p/jsmin-php/
*/ */
@@ -55,7 +55,7 @@ class Minify_Javascript {
private $inputIndex = 0; private $inputIndex = 0;
private $inputLength = 0; private $inputLength = 0;
private $lookAhead = null; private $lookAhead = null;
private $output = array(); private $output = '';
// -- Public Static Methods -------------------------------------------------- // -- Public Static Methods --------------------------------------------------
@@ -74,14 +74,14 @@ class Minify_Javascript {
private function action($d) { private function action($d) {
switch($d) { switch($d) {
case 1: case 1:
$this->output[] = $this->a; $this->output .= $this->a;
case 2: case 2:
$this->a = $this->b; $this->a = $this->b;
if ($this->a === "'" || $this->a === '"') { if ($this->a === "'" || $this->a === '"') {
for (;;) { for (;;) {
$this->output[] = $this->a; $this->output .= $this->a;
$this->a = $this->get(); $this->a = $this->get();
if ($this->a === $this->b) { if ($this->a === $this->b) {
@@ -93,7 +93,7 @@ class Minify_Javascript {
} }
if ($this->a === '\\') { if ($this->a === '\\') {
$this->output[] = $this->a; $this->output .= $this->a;
$this->a = $this->get(); $this->a = $this->get();
} }
} }
@@ -107,25 +107,23 @@ class Minify_Javascript {
$this->a === ':' || $this->a === '[' || $this->a === '!' || $this->a === ':' || $this->a === '[' || $this->a === '!' ||
$this->a === '&' || $this->a === '|' || $this->a === '?')) { $this->a === '&' || $this->a === '|' || $this->a === '?')) {
$this->output[] = $this->a; $this->output .= $this->a;
$this->output[] = $this->b; $this->output .= $this->b;
for (;;) { for (;;) {
$this->a = $this->get(); $this->a = $this->get();
if ($this->a === '/') { if ($this->a === '/') {
break; break;
} } elseif ($this->a === '\\') {
elseif ($this->a === '\\') { $this->output .= $this->a;
$this->output[] = $this->a;
$this->a = $this->get(); $this->a = $this->get();
} } elseif (ord($this->a) <= self::ORD_LF) {
elseif (ord($this->a) <= self::ORD_LF) {
throw new Minify_JavascriptException('Unterminated regular expression '. throw new Minify_JavascriptException('Unterminated regular expression '.
'literal.'); 'literal.');
} }
$this->output[] = $this->a; $this->output .= $this->a;
} }
$this->b = $this->next(); $this->b = $this->next();
@@ -141,8 +139,7 @@ class Minify_Javascript {
if ($this->inputIndex < $this->inputLength) { if ($this->inputIndex < $this->inputLength) {
$c = $this->input[$this->inputIndex]; $c = $this->input[$this->inputIndex];
$this->inputIndex += 1; $this->inputIndex += 1;
} } else {
else {
$c = null; $c = null;
} }
} }
@@ -167,8 +164,7 @@ class Minify_Javascript {
case ' ': case ' ':
if (self::isAlphaNum($this->b)) { if (self::isAlphaNum($this->b)) {
$this->action(1); $this->action(1);
} } else {
else {
$this->action(2); $this->action(2);
} }
break; break;
@@ -237,7 +233,7 @@ class Minify_Javascript {
} }
} }
return implode('', $this->output); return $this->output;
} }
private function next() { private function next() {

View File

@@ -129,8 +129,8 @@ class Minify_Source {
return 'text/plain'; return 'text/plain';
} }
private $_content = null; protected $_content = null;
private $_filepath = null; protected $_filepath = null;
private $_id = null; protected $_id = null;
} }