mirror of
https://github.com/mrclay/minify.git
synced 2025-08-16 19:14:01 +02:00
All PHP/doc files have Unix newlines w/ no BOM
This commit is contained in:
50
HISTORY
50
HISTORY
@@ -1,26 +1,26 @@
|
|||||||
Minify Release History
|
Minify Release History
|
||||||
|
|
||||||
Version 2.0.2 beta (2008-06-24)
|
Version 2.0.2 beta (2008-06-24)
|
||||||
* Fast new cache system. Cached files served almost 3x as fast.
|
* Fast new cache system. Cached files served almost 3x as fast.
|
||||||
* Dropped support of compress encoding (though HTTP_Encoder still supports it)
|
* Dropped support of compress encoding (though HTTP_Encoder still supports it)
|
||||||
|
|
||||||
Version 2.0.1 (2008-05-31)
|
Version 2.0.1 (2008-05-31)
|
||||||
* E_STRICT compliance (Cache_Lite_File).
|
* E_STRICT compliance (Cache_Lite_File).
|
||||||
|
|
||||||
Version 2.0.0 (2008-05-22)
|
Version 2.0.0 (2008-05-22)
|
||||||
* Complete code overhaul. Minify is now a PEAR-style class and toolkit
|
* Complete code overhaul. Minify is now a PEAR-style class and toolkit
|
||||||
for building customized minifying file servers.
|
for building customized minifying file servers.
|
||||||
* Content-Encoding: deflate/gzip/compress, based on request headers
|
* Content-Encoding: deflate/gzip/compress, based on request headers
|
||||||
* Expanded CSS and HTML minifiers with test cases
|
* Expanded CSS and HTML minifiers with test cases
|
||||||
* Easily plug-in 3rd-party minifiers (like Packer)
|
* Easily plug-in 3rd-party minifiers (like Packer)
|
||||||
* Plug-able front end controller allows changing the way files are chosen
|
* Plug-able front end controller allows changing the way files are chosen
|
||||||
* Compression & encoding modules lazy-loaded as needed (304 responses use minimal code)
|
* Compression & encoding modules lazy-loaded as needed (304 responses use minimal code)
|
||||||
* Separate utility classes for HTTP encoding and cache control
|
* Separate utility classes for HTTP encoding and cache control
|
||||||
|
|
||||||
Version 1.0.1 (2007-05-05)
|
Version 1.0.1 (2007-05-05)
|
||||||
* Fixed various problems resolving pathnames when hosted on an NFS mount.
|
* Fixed various problems resolving pathnames when hosted on an NFS mount.
|
||||||
* Fixed 'undefined constant' notice.
|
* Fixed 'undefined constant' notice.
|
||||||
* Replaced old JSMin library with a much faster custom implementation.
|
* Replaced old JSMin library with a much faster custom implementation.
|
||||||
|
|
||||||
Version 1.0.0 (2007-05-02)
|
Version 1.0.0 (2007-05-02)
|
||||||
* First release.
|
* First release.
|
50
LICENSE
50
LICENSE
@@ -1,25 +1,25 @@
|
|||||||
Copyright (c) 2007 Ryan Grove <ryan@wonko.com>
|
Copyright (c) 2007 Ryan Grove <ryan@wonko.com>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice,
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
this list of conditions and the following disclaimer.
|
this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
this list of conditions and the following disclaimer in the documentation
|
this list of conditions and the following disclaimer in the documentation
|
||||||
and/or other materials provided with the distribution.
|
and/or other materials provided with the distribution.
|
||||||
* Neither the name of this project nor the names of its contributors may be
|
* Neither the name of this project nor the names of its contributors may be
|
||||||
used to endorse or promote products derived from this software without
|
used to endorse or promote products derived from this software without
|
||||||
specific prior written permission.
|
specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
92
README
92
README
@@ -1,46 +1,46 @@
|
|||||||
WELCOME TO MINIFY 2.0!
|
WELCOME TO MINIFY 2.0!
|
||||||
|
|
||||||
Minify is an HTTP content server. It compresses sources of content
|
Minify is an HTTP content server. It compresses sources of content
|
||||||
(usually files), combines the result and serves it with appropriate
|
(usually files), combines the result and serves it with appropriate
|
||||||
HTTP headers. These headers can allow clients to perform conditional
|
HTTP headers. These headers can allow clients to perform conditional
|
||||||
GETs (serving content only when clients do not have a valid cache)
|
GETs (serving content only when clients do not have a valid cache)
|
||||||
or tell clients to cache the file until a given date/time.
|
or tell clients to cache the file until a given date/time.
|
||||||
More info: http://code.google.com/p/minify/
|
More info: http://code.google.com/p/minify/
|
||||||
|
|
||||||
INSTALLATION AND USAGE: http://code.google.com/p/minify/wiki/UserGuide
|
INSTALLATION AND USAGE: http://code.google.com/p/minify/wiki/UserGuide
|
||||||
|
|
||||||
UNIT TESTING & EXAMPLES: http://code.google.com/p/minify/wiki/TestingMinify
|
UNIT TESTING & EXAMPLES: http://code.google.com/p/minify/wiki/TestingMinify
|
||||||
|
|
||||||
MINIFY OVERVIEW
|
MINIFY OVERVIEW
|
||||||
|
|
||||||
Minify works with Minify_Source objects. These usually represent a file
|
Minify works with Minify_Source objects. These usually represent a file
|
||||||
on disk, but a source can also be a string in memory or from a database.
|
on disk, but a source can also be a string in memory or from a database.
|
||||||
Sources with known "last modified" timestamps allow Minify to implement
|
Sources with known "last modified" timestamps allow Minify to implement
|
||||||
server-side caching and conditional GETs.
|
server-side caching and conditional GETs.
|
||||||
|
|
||||||
You configure Minify via a Minify_Controller object. The controller
|
You configure Minify via a Minify_Controller object. The controller
|
||||||
supplies the sources and default options to serve a request,
|
supplies the sources and default options to serve a request,
|
||||||
determining how it's to be responded to. Several controllers are
|
determining how it's to be responded to. Several controllers are
|
||||||
supplied with Minify, but it's also fairly easy to write your own. See
|
supplied with Minify, but it's also fairly easy to write your own. See
|
||||||
the files in /lib/Minify/Controller for examples.
|
the files in /lib/Minify/Controller for examples.
|
||||||
|
|
||||||
To use an existing controller, you call Minify::serve(), passing it:
|
To use an existing controller, you call Minify::serve(), passing it:
|
||||||
1. the name of your controller of choice (without the "Minify_Controller"
|
1. the name of your controller of choice (without the "Minify_Controller"
|
||||||
prefix) or a custom controller object subclassed from Minify_Controller_Base.
|
prefix) or a custom controller object subclassed from Minify_Controller_Base.
|
||||||
2. a combined array of controller and Minify options. Eg.:
|
2. a combined array of controller and Minify options. Eg.:
|
||||||
|
|
||||||
// serve a minified javascript file and tell clients to cache it for a
|
// serve a minified javascript file and tell clients to cache it for a
|
||||||
// year
|
// year
|
||||||
Minify::serve('Files', array(
|
Minify::serve('Files', array(
|
||||||
'files' => array('/path/to/file1.js', '/path/to/file2.js')
|
'files' => array('/path/to/file1.js', '/path/to/file2.js')
|
||||||
,'setExpires' => (time() + 86400 * 365)
|
,'setExpires' => (time() + 86400 * 365)
|
||||||
));
|
));
|
||||||
|
|
||||||
The above creates an instance of Minify_Controller_Files, which creates
|
The above creates an instance of Minify_Controller_Files, which creates
|
||||||
source objects from the 'files' option, and supplies other default options.
|
source objects from the 'files' option, and supplies other default options.
|
||||||
|
|
||||||
FILE ENCODINGS
|
FILE ENCODINGS
|
||||||
|
|
||||||
Minify *should* work fine with files encoded in UTF-8 or other 8-bit
|
Minify *should* work fine with files encoded in UTF-8 or other 8-bit
|
||||||
encodings like ISO 8859/Windows-1252. Leading UTF-8 BOMs are stripped from
|
encodings like ISO 8859/Windows-1252. Leading UTF-8 BOMs are stripped from
|
||||||
all sources to prevent duplication in output files.
|
all sources to prevent duplication in output files.
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Configuration for default Minify implementation
|
* Configuration for default Minify implementation
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For best performance, specify your temp directory here.
|
* For best performance, specify your temp directory here.
|
||||||
* Otherwise Minify will have to load extra code to guess.
|
* Otherwise Minify will have to load extra code to guess.
|
||||||
*/
|
*/
|
||||||
//$min_cachePath = 'c:\\WINDOWS\Temp';
|
//$min_cachePath = 'c:\\WINDOWS\Temp';
|
||||||
//$min_cachePath = '/tmp';
|
//$min_cachePath = '/tmp';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,29 +20,29 @@
|
|||||||
* those changes are seen immediately.
|
* those changes are seen immediately.
|
||||||
*/
|
*/
|
||||||
$min_serveOptions['maxAge'] = 1800;
|
$min_serveOptions['maxAge'] = 1800;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If you'd like to restrict the "f" option to files within/below
|
* If you'd like to restrict the "f" option to files within/below
|
||||||
* particular directories below DOCUMENT_ROOT, set this here.
|
* particular directories below DOCUMENT_ROOT, set this here.
|
||||||
* You will still need to include the directory in the
|
* You will still need to include the directory in the
|
||||||
* f or b GET parameters.
|
* f or b GET parameters.
|
||||||
*
|
*
|
||||||
* // = DOCUMENT_ROOT
|
* // = DOCUMENT_ROOT
|
||||||
*/
|
*/
|
||||||
//$min_allowDirs = array('//js', '//css');
|
//$min_allowDirs = array('//js', '//css');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manually set the path to Minify's lib folder
|
* Manually set the path to Minify's lib folder
|
||||||
*/
|
*/
|
||||||
//$min_libPath = 'lib';
|
//$min_libPath = 'lib';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to true to disable the "f" GET parameter for specifying files.
|
* Set to true to disable the "f" GET parameter for specifying files.
|
||||||
* Only the "g" parameter will be considered.
|
* Only the "g" parameter will be considered.
|
||||||
*/
|
*/
|
||||||
$min_groupsOnly = false;
|
$min_groupsOnly = false;
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ $min_groupsOnly = false;
|
|||||||
* Uncomment to enable debug mode. Files will be combined with no
|
* Uncomment to enable debug mode. Files will be combined with no
|
||||||
* minification, and comments will be added to indicate the line #s
|
* minification, and comments will be added to indicate the line #s
|
||||||
* of the original files.
|
* of the original files.
|
||||||
*/
|
*/
|
||||||
//$min_serveOptions['debug'] = true;
|
//$min_serveOptions['debug'] = true;
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Groups configuration for default Minify implementation
|
* Groups configuration for default Minify implementation
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
// 'js' => array('//js/file1.js', '//js/file2.js'),
|
// 'js' => array('//js/file1.js', '//js/file2.js'),
|
||||||
// 'css' => array('//css/file1.css', '//css/file2.css'),
|
// 'css' => array('//css/file1.css', '//css/file2.css'),
|
||||||
'js' => array('//js/Class.js', '//js/email.js')
|
'js' => array('//js/Class.js', '//js/email.js')
|
||||||
);
|
);
|
122
min/index.php
122
min/index.php
@@ -1,55 +1,55 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Front controller for default Minify implementation
|
* Front controller for default Minify implementation
|
||||||
*
|
*
|
||||||
* DO NOT EDIT! Configure this utility via config.php and groupsConfig.php
|
* DO NOT EDIT! Configure this utility via config.php and groupsConfig.php
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
define('MINIFY_MIN_DIR', dirname(__FILE__));
|
define('MINIFY_MIN_DIR', dirname(__FILE__));
|
||||||
|
|
||||||
// load config
|
// load config
|
||||||
require MINIFY_MIN_DIR . '/config.php';
|
require MINIFY_MIN_DIR . '/config.php';
|
||||||
|
|
||||||
// setup include path
|
// setup include path
|
||||||
if (!isset($min_libPath)) {
|
if (!isset($min_libPath)) {
|
||||||
// default lib path is inside this directory
|
// default lib path is inside this directory
|
||||||
$min_libPath = MINIFY_MIN_DIR . '/lib';
|
$min_libPath = MINIFY_MIN_DIR . '/lib';
|
||||||
}
|
}
|
||||||
set_include_path($min_libPath . PATH_SEPARATOR . get_include_path());
|
set_include_path($min_libPath . PATH_SEPARATOR . get_include_path());
|
||||||
|
|
||||||
// friendly error if lib wasn't in the include_path
|
// friendly error if lib wasn't in the include_path
|
||||||
if (! (include 'Minify.php')) {
|
if (! (include 'Minify.php')) {
|
||||||
trigger_error(
|
trigger_error(
|
||||||
'Minify: You must add Minify/lib to the include_path or set $min_libPath in config.php'
|
'Minify: You must add Minify/lib to the include_path or set $min_libPath in config.php'
|
||||||
,E_USER_ERROR
|
,E_USER_ERROR
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Minify::$uploaderHoursBehind = $min_uploaderHoursBehind;
|
Minify::$uploaderHoursBehind = $min_uploaderHoursBehind;
|
||||||
|
|
||||||
if (isset($_GET['g'])) {
|
if (isset($_GET['g'])) {
|
||||||
|
|
||||||
Minify::setCache(isset($min_cachePath) ? $min_cachePath : null);
|
Minify::setCache(isset($min_cachePath) ? $min_cachePath : null);
|
||||||
// Groups expects the group key as PATH_INFO
|
// Groups expects the group key as PATH_INFO
|
||||||
// we want to allow ?g=groupKey
|
// we want to allow ?g=groupKey
|
||||||
$_SERVER['PATH_INFO'] = '/' . $_GET['g'];
|
$_SERVER['PATH_INFO'] = '/' . $_GET['g'];
|
||||||
$min_serveOptions['groups'] = (require MINIFY_MIN_DIR . '/groupsConfig.php');
|
$min_serveOptions['groups'] = (require MINIFY_MIN_DIR . '/groupsConfig.php');
|
||||||
if (preg_match('/&\\d/', $_SERVER['QUERY_STRING'])) {
|
if (preg_match('/&\\d/', $_SERVER['QUERY_STRING'])) {
|
||||||
$min_serveOptions['maxAge'] = 31536000;
|
$min_serveOptions['maxAge'] = 31536000;
|
||||||
}
|
}
|
||||||
Minify::serve('Groups', $min_serveOptions);
|
Minify::serve('Groups', $min_serveOptions);
|
||||||
|
|
||||||
} elseif (!$min_groupsOnly && isset($_GET['f'])) {
|
} elseif (!$min_groupsOnly && isset($_GET['f'])) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* crude initial implementation hacked onto on Version1 controller
|
* crude initial implementation hacked onto on Version1 controller
|
||||||
* @todo encapsulate this in a new controller
|
* @todo encapsulate this in a new controller
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (isset($min_cachePath)) {
|
if (isset($min_cachePath)) {
|
||||||
define('MINIFY_CACHE_DIR', $min_cachePath);
|
define('MINIFY_CACHE_DIR', $min_cachePath);
|
||||||
}
|
}
|
||||||
if (isset($min_allowDirs)) {
|
if (isset($min_allowDirs)) {
|
||||||
foreach ((array)$min_allowDirs as $_allowDir) {
|
foreach ((array)$min_allowDirs as $_allowDir) {
|
||||||
@@ -57,16 +57,16 @@ if (isset($_GET['g'])) {
|
|||||||
$_SERVER['DOCUMENT_ROOT'] . substr($_allowDir, 1)
|
$_SERVER['DOCUMENT_ROOT'] . substr($_allowDir, 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Version1 already does validation. All we want is to prepend "b"
|
// Version1 already does validation. All we want is to prepend "b"
|
||||||
// to each file if it looks right.
|
// to each file if it looks right.
|
||||||
$min_base = (isset($_GET['b']) && preg_match('@^[^/.]+(?:/[^/.]+)*$@', $_GET['b']))
|
$min_base = (isset($_GET['b']) && preg_match('@^[^/.]+(?:/[^/.]+)*$@', $_GET['b']))
|
||||||
? '/' . $_GET['b'] . '/'
|
? '/' . $_GET['b'] . '/'
|
||||||
: '/';
|
: '/';
|
||||||
// Version1 expects ?files=/js/file1.js,/js/file2.js,/js/file3.js
|
// Version1 expects ?files=/js/file1.js,/js/file2.js,/js/file3.js
|
||||||
// we want to allow ?f=js/file1.js,js/file2.js,js/file3.js
|
// we want to allow ?f=js/file1.js,js/file2.js,js/file3.js
|
||||||
// or ?b=js&f=file1.js,file2.js,file3.js
|
// or ?b=js&f=file1.js,file2.js,file3.js
|
||||||
$_GET['files'] = $min_base . str_replace(',', ',' . $min_base, $_GET['f']);
|
$_GET['files'] = $min_base . str_replace(',', ',' . $min_base, $_GET['f']);
|
||||||
|
|
||||||
Minify::serve('Version1', $min_serveOptions);
|
Minify::serve('Version1', $min_serveOptions);
|
||||||
}
|
}
|
||||||
|
@@ -1,262 +1,262 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class HTTP_ConditionalGet
|
* Class HTTP_ConditionalGet
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @subpackage HTTP
|
* @subpackage HTTP
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement conditional GET via a timestamp or hash of content
|
* Implement conditional GET via a timestamp or hash of content
|
||||||
*
|
*
|
||||||
* E.g. Content from DB with update time:
|
* E.g. Content from DB with update time:
|
||||||
* <code>
|
* <code>
|
||||||
* list($updateTime, $content) = getDbUpdateAndContent();
|
* list($updateTime, $content) = getDbUpdateAndContent();
|
||||||
* $cg = new HTTP_ConditionalGet(array(
|
* $cg = new HTTP_ConditionalGet(array(
|
||||||
* 'lastModifiedTime' => $updateTime
|
* 'lastModifiedTime' => $updateTime
|
||||||
* ));
|
* ));
|
||||||
* $cg->sendHeaders();
|
* $cg->sendHeaders();
|
||||||
* if ($cg->cacheIsValid) {
|
* if ($cg->cacheIsValid) {
|
||||||
* exit();
|
* exit();
|
||||||
* }
|
* }
|
||||||
* echo $content;
|
* echo $content;
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* E.g. Content from DB with no update time:
|
* E.g. Content from DB with no update time:
|
||||||
* <code>
|
* <code>
|
||||||
* $content = getContentFromDB();
|
* $content = getContentFromDB();
|
||||||
* $cg = new HTTP_ConditionalGet(array(
|
* $cg = new HTTP_ConditionalGet(array(
|
||||||
* 'contentHash' => md5($content)
|
* 'contentHash' => md5($content)
|
||||||
* ));
|
* ));
|
||||||
* $cg->sendHeaders();
|
* $cg->sendHeaders();
|
||||||
* if ($cg->cacheIsValid) {
|
* if ($cg->cacheIsValid) {
|
||||||
* exit();
|
* exit();
|
||||||
* }
|
* }
|
||||||
* echo $content;
|
* echo $content;
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* E.g. Static content with some static includes:
|
* E.g. Static content with some static includes:
|
||||||
* <code>
|
* <code>
|
||||||
* // before content
|
* // before content
|
||||||
* $cg = new HTTP_ConditionalGet(array(
|
* $cg = new HTTP_ConditionalGet(array(
|
||||||
* 'lastUpdateTime' => max(
|
* 'lastUpdateTime' => max(
|
||||||
* filemtime(__FILE__)
|
* filemtime(__FILE__)
|
||||||
* ,filemtime('/path/to/header.inc')
|
* ,filemtime('/path/to/header.inc')
|
||||||
* ,filemtime('/path/to/footer.inc')
|
* ,filemtime('/path/to/footer.inc')
|
||||||
* )
|
* )
|
||||||
* ));
|
* ));
|
||||||
* $cg->sendHeaders();
|
* $cg->sendHeaders();
|
||||||
* if ($cg->cacheIsValid) {
|
* if ($cg->cacheIsValid) {
|
||||||
* exit();
|
* exit();
|
||||||
* }
|
* }
|
||||||
* </code>
|
* </code>
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @subpackage HTTP
|
* @subpackage HTTP
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class HTTP_ConditionalGet {
|
class HTTP_ConditionalGet {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the client have a valid copy of the requested resource?
|
* Does the client have a valid copy of the requested resource?
|
||||||
*
|
*
|
||||||
* You'll want to check this after instantiating the object. If true, do
|
* You'll want to check this after instantiating the object. If true, do
|
||||||
* not send content, just call sendHeaders() if you haven't already.
|
* not send content, just call sendHeaders() if you haven't already.
|
||||||
*
|
*
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
public $cacheIsValid = null;
|
public $cacheIsValid = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $spec options
|
* @param array $spec options
|
||||||
*
|
*
|
||||||
* 'isPublic': (bool) if true, the Cache-Control header will contain
|
* 'isPublic': (bool) if true, the Cache-Control header will contain
|
||||||
* "public", allowing proxy caches to cache the content. Otherwise
|
* "public", allowing proxy caches to cache the content. Otherwise
|
||||||
* "private" will be sent, allowing only browsers to cache. (default false)
|
* "private" will be sent, allowing only browsers to cache. (default false)
|
||||||
*
|
*
|
||||||
* 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers
|
* 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers
|
||||||
* will be sent with content. This is recommended.
|
* will be sent with content. This is recommended.
|
||||||
*
|
*
|
||||||
* 'contentHash': (string) if given, only the ETag header can be sent with
|
* 'contentHash': (string) if given, only the ETag header can be sent with
|
||||||
* content (only HTTP1.1 clients can conditionally GET). The given string
|
* content (only HTTP1.1 clients can conditionally GET). The given string
|
||||||
* should be short with no quote characters and always change when the
|
* should be short with no quote characters and always change when the
|
||||||
* resource changes (recommend md5()). This is not needed/used if
|
* resource changes (recommend md5()). This is not needed/used if
|
||||||
* lastModifiedTime is given.
|
* lastModifiedTime is given.
|
||||||
*
|
*
|
||||||
* 'invalidate': (bool) if true, the client cache will be considered invalid
|
* 'invalidate': (bool) if true, the client cache will be considered invalid
|
||||||
* without testing. Effectively this disables conditional GET.
|
* without testing. Effectively this disables conditional GET.
|
||||||
* (default false)
|
* (default false)
|
||||||
*
|
*
|
||||||
* 'maxAge': (int) if given, this will set the Cache-Control max-age in
|
* 'maxAge': (int) if given, this will set the Cache-Control max-age in
|
||||||
* seconds, and also set the Expires header to the equivalent GMT date.
|
* seconds, and also set the Expires header to the equivalent GMT date.
|
||||||
* After the max-age period has passed, the browser will again send a
|
* After the max-age period has passed, the browser will again send a
|
||||||
* conditional GET to revalidate its cache.
|
* conditional GET to revalidate its cache.
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public function __construct($spec) {
|
public function __construct($spec) {
|
||||||
$scope = (isset($spec['isPublic']) && $spec['isPublic'])
|
$scope = (isset($spec['isPublic']) && $spec['isPublic'])
|
||||||
? 'public'
|
? 'public'
|
||||||
: 'private';
|
: 'private';
|
||||||
$maxAge = 0;
|
$maxAge = 0;
|
||||||
// backwards compatibility (can be removed later)
|
// backwards compatibility (can be removed later)
|
||||||
if (isset($spec['setExpires'])
|
if (isset($spec['setExpires'])
|
||||||
&& is_numeric($spec['setExpires'])
|
&& is_numeric($spec['setExpires'])
|
||||||
&& ! isset($spec['maxAge'])) {
|
&& ! isset($spec['maxAge'])) {
|
||||||
$spec['maxAge'] = $spec['setExpires'] - $_SERVER['REQUEST_TIME'];
|
$spec['maxAge'] = $spec['setExpires'] - $_SERVER['REQUEST_TIME'];
|
||||||
}
|
}
|
||||||
if (isset($spec['maxAge'])) {
|
if (isset($spec['maxAge'])) {
|
||||||
$maxAge = $spec['maxAge'];
|
$maxAge = $spec['maxAge'];
|
||||||
$this->_headers['Expires'] = self::gmtDate(
|
$this->_headers['Expires'] = self::gmtDate(
|
||||||
$_SERVER['REQUEST_TIME'] + $spec['maxAge']
|
$_SERVER['REQUEST_TIME'] + $spec['maxAge']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
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={$maxAge}, {$scope}, must-revalidate";
|
$this->_headers['Cache-Control'] = "max-age={$maxAge}, {$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
|
* Get array of output headers to be sent
|
||||||
*
|
*
|
||||||
* In the case of 304 responses, this array will only contain the response
|
* In the case of 304 responses, this array will only contain the response
|
||||||
* code header: array('_responseCode' => 'HTTP/1.0 304 Not Modified')
|
* code header: array('_responseCode' => 'HTTP/1.0 304 Not Modified')
|
||||||
*
|
*
|
||||||
* Otherwise something like:
|
* Otherwise something like:
|
||||||
* <code>
|
* <code>
|
||||||
* array(
|
* array(
|
||||||
* 'Cache-Control' => 'max-age=0, public, must-revalidate'
|
* 'Cache-Control' => 'max-age=0, public, must-revalidate'
|
||||||
* ,'ETag' => '"foobar"'
|
* ,'ETag' => '"foobar"'
|
||||||
* )
|
* )
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getHeaders() {
|
public function getHeaders() {
|
||||||
return $this->_headers;
|
return $this->_headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the Content-Length header in bytes
|
* Set the Content-Length header in bytes
|
||||||
*
|
*
|
||||||
* With most PHP configs, as long as you don't flush() output, this method
|
* 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
|
* 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.
|
* you. Otherwise you'll want to call this to let the client know up front.
|
||||||
*
|
*
|
||||||
* @param int $bytes
|
* @param int $bytes
|
||||||
*
|
*
|
||||||
* @return int copy of input $bytes
|
* @return int copy of input $bytes
|
||||||
*/
|
*/
|
||||||
public function setContentLength($bytes) {
|
public function setContentLength($bytes) {
|
||||||
return $this->_headers['Content-Length'] = $bytes;
|
return $this->_headers['Content-Length'] = $bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send headers
|
* Send headers
|
||||||
*
|
*
|
||||||
* @see getHeaders()
|
* @see getHeaders()
|
||||||
*
|
*
|
||||||
* Note this doesn't "clear" the headers. Calling sendHeaders() will
|
* Note this doesn't "clear" the headers. Calling sendHeaders() will
|
||||||
* call header() again (but probably have not effect) and getHeaders() will
|
* call header() again (but probably have not effect) and getHeaders() will
|
||||||
* still return the headers.
|
* still return the headers.
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public function sendHeaders() {
|
public function sendHeaders() {
|
||||||
$headers = $this->_headers;
|
$headers = $this->_headers;
|
||||||
if (array_key_exists('_responseCode', $headers)) {
|
if (array_key_exists('_responseCode', $headers)) {
|
||||||
header($headers['_responseCode']);
|
header($headers['_responseCode']);
|
||||||
unset($headers['_responseCode']);
|
unset($headers['_responseCode']);
|
||||||
}
|
}
|
||||||
foreach ($headers as $name => $val) {
|
foreach ($headers as $name => $val) {
|
||||||
header($name . ': ' . $val);
|
header($name . ': ' . $val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a GMT formatted date for use in HTTP headers
|
* Get a GMT formatted date for use in HTTP headers
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* header('Expires: ' . HTTP_ConditionalGet::gmtdate($time));
|
* header('Expires: ' . HTTP_ConditionalGet::gmtdate($time));
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* @param int $time unix timestamp
|
* @param int $time unix timestamp
|
||||||
*
|
*
|
||||||
* @return string
|
* @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);
|
return gmdate('D, d M Y H:i:s \G\M\T', $time);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $_headers = array();
|
protected $_headers = array();
|
||||||
protected $_lmTime = null;
|
protected $_lmTime = null;
|
||||||
protected $_etag = null;
|
protected $_etag = null;
|
||||||
|
|
||||||
protected function _setEtag($hash, $scope) {
|
protected function _setEtag($hash, $scope) {
|
||||||
$this->_etag = '"' . $hash
|
$this->_etag = '"' . $hash
|
||||||
. substr($scope, 0, 3)
|
. substr($scope, 0, 3)
|
||||||
. '"';
|
. '"';
|
||||||
$this->_headers['ETag'] = $this->_etag;
|
$this->_headers['ETag'] = $this->_etag;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _setLastModified($time) {
|
protected function _setLastModified($time) {
|
||||||
$this->_lmTime = (int)$time;
|
$this->_lmTime = (int)$time;
|
||||||
$this->_headers['Last-Modified'] = self::gmtDate($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
|
||||||
*/
|
*/
|
||||||
protected function _isCacheValid()
|
protected function _isCacheValid()
|
||||||
{
|
{
|
||||||
if (null === $this->_etag) {
|
if (null === $this->_etag) {
|
||||||
// lmTime is copied to ETag, so this condition implies that the
|
// lmTime is copied to ETag, so this condition implies that the
|
||||||
// client received neither ETag nor Last-Modified, so can't
|
// client received neither ETag nor Last-Modified, so can't
|
||||||
// possibly has a valid cache.
|
// possibly has a valid cache.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$isValid = ($this->resourceMatchedEtag() || $this->resourceNotModified());
|
$isValid = ($this->resourceMatchedEtag() || $this->resourceNotModified());
|
||||||
if ($isValid) {
|
if ($isValid) {
|
||||||
$this->_headers['_responseCode'] = 'HTTP/1.0 304 Not Modified';
|
$this->_headers['_responseCode'] = 'HTTP/1.0 304 Not Modified';
|
||||||
}
|
}
|
||||||
return $isValid;
|
return $isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function resourceMatchedEtag() {
|
protected function resourceMatchedEtag() {
|
||||||
if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$cachedEtagList = get_magic_quotes_gpc()
|
$cachedEtagList = get_magic_quotes_gpc()
|
||||||
? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])
|
? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])
|
||||||
: $_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function resourceNotModified() {
|
protected function resourceNotModified() {
|
||||||
if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
|
if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$ifModifiedSince = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
|
$ifModifiedSince = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
|
||||||
if (false !== ($semicolon = strrpos($ifModifiedSince, ';'))) {
|
if (false !== ($semicolon = strrpos($ifModifiedSince, ';'))) {
|
||||||
// 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,291 +1,291 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* jsmin.php - PHP implementation of Douglas Crockford's JSMin.
|
* jsmin.php - PHP implementation of Douglas Crockford's JSMin.
|
||||||
*
|
*
|
||||||
* This is pretty much a direct port of jsmin.c to PHP with just a few
|
* This is pretty much a direct port of jsmin.c to PHP with just a few
|
||||||
* PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
|
* PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
|
||||||
* outputs to stdout, this library accepts a string as input and returns another
|
* outputs to stdout, this library accepts a string as input and returns another
|
||||||
* string as output.
|
* string as output.
|
||||||
*
|
*
|
||||||
* PHP 5 or higher is required.
|
* PHP 5 or higher is required.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted to use this version of the library under the
|
* Permission is hereby granted to use this version of the library under the
|
||||||
* same terms as jsmin.c, which has the following license:
|
* same terms as jsmin.c, which has the following license:
|
||||||
*
|
*
|
||||||
* --
|
* --
|
||||||
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
* this software and associated documentation files (the "Software"), to deal in
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
* the Software without restriction, including without limitation the rights to
|
* the Software without restriction, including without limitation the rights to
|
||||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
* so, subject to the following conditions:
|
* so, subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
* copies or substantial portions of the Software.
|
* copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* The Software shall be used for Good, not Evil.
|
* The Software shall be used for Good, not Evil.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
* --
|
* --
|
||||||
*
|
*
|
||||||
* @package JSMin
|
* @package JSMin
|
||||||
* @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 2008 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.1 (2008-03-02)
|
* @version 1.1.1 (2008-03-02)
|
||||||
* @link http://code.google.com/p/jsmin-php/
|
* @link http://code.google.com/p/jsmin-php/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class JSMin {
|
class JSMin {
|
||||||
const ORD_LF = 10;
|
const ORD_LF = 10;
|
||||||
const ORD_SPACE = 32;
|
const ORD_SPACE = 32;
|
||||||
|
|
||||||
protected $a = '';
|
protected $a = '';
|
||||||
protected $b = '';
|
protected $b = '';
|
||||||
protected $input = '';
|
protected $input = '';
|
||||||
protected $inputIndex = 0;
|
protected $inputIndex = 0;
|
||||||
protected $inputLength = 0;
|
protected $inputLength = 0;
|
||||||
protected $lookAhead = null;
|
protected $lookAhead = null;
|
||||||
protected $output = '';
|
protected $output = '';
|
||||||
|
|
||||||
// -- Public Static Methods --------------------------------------------------
|
// -- Public Static Methods --------------------------------------------------
|
||||||
|
|
||||||
public static function minify($js) {
|
public static function minify($js) {
|
||||||
$jsmin = new JSMin($js);
|
$jsmin = new JSMin($js);
|
||||||
return $jsmin->min();
|
return $jsmin->min();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Public Instance Methods ------------------------------------------------
|
// -- Public Instance Methods ------------------------------------------------
|
||||||
|
|
||||||
public function __construct($input) {
|
public function __construct($input) {
|
||||||
$this->input = str_replace("\r\n", "\n", $input);
|
$this->input = str_replace("\r\n", "\n", $input);
|
||||||
$this->inputLength = strlen($this->input);
|
$this->inputLength = strlen($this->input);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Protected Instance Methods ---------------------------------------------
|
// -- Protected Instance Methods ---------------------------------------------
|
||||||
|
|
||||||
protected function action($d) {
|
protected 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) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ord($this->a) <= self::ORD_LF) {
|
if (ord($this->a) <= self::ORD_LF) {
|
||||||
throw new JSMinException('Unterminated string literal.');
|
throw new JSMinException('Unterminated string literal.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->a === '\\') {
|
if ($this->a === '\\') {
|
||||||
$this->output .= $this->a;
|
$this->output .= $this->a;
|
||||||
$this->a = $this->get();
|
$this->a = $this->get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
$this->b = $this->next();
|
$this->b = $this->next();
|
||||||
|
|
||||||
if ($this->b === '/' && (
|
if ($this->b === '/' && (
|
||||||
$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->a === '&' || $this->a === '|' || $this->a === '?')) {
|
$this->a === '&' || $this->a === '|' || $this->a === '?')) {
|
||||||
|
|
||||||
$this->output .= $this->a . $this->b;
|
$this->output .= $this->a . $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 JSMinException('Unterminated regular expression '.
|
throw new JSMinException('Unterminated regular expression '.
|
||||||
'literal.');
|
'literal.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->output .= $this->a;
|
$this->output .= $this->a;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->b = $this->next();
|
$this->b = $this->next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function get() {
|
protected function get() {
|
||||||
$c = $this->lookAhead;
|
$c = $this->lookAhead;
|
||||||
$this->lookAhead = null;
|
$this->lookAhead = null;
|
||||||
|
|
||||||
if ($c === null) {
|
if ($c === null) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($c === "\r") {
|
if ($c === "\r") {
|
||||||
return "\n";
|
return "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
|
if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
|
||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ' ';
|
return ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isAlphaNum($c) {
|
protected function isAlphaNum($c) {
|
||||||
return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
|
return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function min() {
|
protected function min() {
|
||||||
$this->a = "\n";
|
$this->a = "\n";
|
||||||
$this->action(3);
|
$this->action(3);
|
||||||
|
|
||||||
while ($this->a !== null) {
|
while ($this->a !== null) {
|
||||||
switch ($this->a) {
|
switch ($this->a) {
|
||||||
case ' ':
|
case ' ':
|
||||||
if ($this->isAlphaNum($this->b)) {
|
if ($this->isAlphaNum($this->b)) {
|
||||||
$this->action(1);
|
$this->action(1);
|
||||||
} else {
|
} else {
|
||||||
$this->action(2);
|
$this->action(2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "\n":
|
case "\n":
|
||||||
switch ($this->b) {
|
switch ($this->b) {
|
||||||
case '{':
|
case '{':
|
||||||
case '[':
|
case '[':
|
||||||
case '(':
|
case '(':
|
||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
$this->action(1);
|
$this->action(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ' ':
|
case ' ':
|
||||||
$this->action(3);
|
$this->action(3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ($this->isAlphaNum($this->b)) {
|
if ($this->isAlphaNum($this->b)) {
|
||||||
$this->action(1);
|
$this->action(1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->action(2);
|
$this->action(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
switch ($this->b) {
|
switch ($this->b) {
|
||||||
case ' ':
|
case ' ':
|
||||||
if ($this->isAlphaNum($this->a)) {
|
if ($this->isAlphaNum($this->a)) {
|
||||||
$this->action(1);
|
$this->action(1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->action(3);
|
$this->action(3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "\n":
|
case "\n":
|
||||||
switch ($this->a) {
|
switch ($this->a) {
|
||||||
case '}':
|
case '}':
|
||||||
case ']':
|
case ']':
|
||||||
case ')':
|
case ')':
|
||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
case '"':
|
case '"':
|
||||||
case "'":
|
case "'":
|
||||||
$this->action(1);
|
$this->action(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ($this->isAlphaNum($this->a)) {
|
if ($this->isAlphaNum($this->a)) {
|
||||||
$this->action(1);
|
$this->action(1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->action(3);
|
$this->action(3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$this->action(1);
|
$this->action(1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->output;
|
return $this->output;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function next() {
|
protected function next() {
|
||||||
$c = $this->get();
|
$c = $this->get();
|
||||||
|
|
||||||
if ($c === '/') {
|
if ($c === '/') {
|
||||||
switch($this->peek()) {
|
switch($this->peek()) {
|
||||||
case '/':
|
case '/':
|
||||||
for (;;) {
|
for (;;) {
|
||||||
$c = $this->get();
|
$c = $this->get();
|
||||||
|
|
||||||
if (ord($c) <= self::ORD_LF) {
|
if (ord($c) <= self::ORD_LF) {
|
||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
$this->get();
|
$this->get();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch($this->get()) {
|
switch($this->get()) {
|
||||||
case '*':
|
case '*':
|
||||||
if ($this->peek() === '/') {
|
if ($this->peek() === '/') {
|
||||||
$this->get();
|
$this->get();
|
||||||
return ' ';
|
return ' ';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case null:
|
case null:
|
||||||
throw new JSMinException('Unterminated comment.');
|
throw new JSMinException('Unterminated comment.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function peek() {
|
protected function peek() {
|
||||||
$this->lookAhead = $this->get();
|
$this->lookAhead = $this->get();
|
||||||
return $this->lookAhead;
|
return $this->lookAhead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Exceptions ---------------------------------------------------------------
|
// -- Exceptions ---------------------------------------------------------------
|
||||||
class JSMinException extends Exception {}
|
class JSMinException extends Exception {}
|
||||||
?>
|
?>
|
@@ -1,243 +1,243 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify
|
* Class Minify
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minify_Source
|
* Minify_Source
|
||||||
*/
|
*/
|
||||||
require_once 'Minify/Source.php';
|
require_once 'Minify/Source.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minify - Combines, minifies, and caches JavaScript and CSS files on demand.
|
* Minify - Combines, minifies, and caches JavaScript and CSS files on demand.
|
||||||
*
|
*
|
||||||
* See README for usage instructions (for now).
|
* See README for usage instructions (for now).
|
||||||
*
|
*
|
||||||
* This library was inspired by {@link mailto:flashkot@mail.ru jscsscomp by Maxim Martynyuk}
|
* This library was inspired by {@link mailto:flashkot@mail.ru jscsscomp by Maxim Martynyuk}
|
||||||
* and by the article {@link http://www.hunlock.com/blogs/Supercharged_Javascript "Supercharged JavaScript" by Patrick Hunlock}.
|
* and by the article {@link http://www.hunlock.com/blogs/Supercharged_Javascript "Supercharged JavaScript" by Patrick Hunlock}.
|
||||||
*
|
*
|
||||||
* Requires PHP 5.1.0.
|
* Requires PHP 5.1.0.
|
||||||
* Tested on PHP 5.1.6.
|
* Tested on PHP 5.1.6.
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Ryan Grove <ryan@wonko.com>
|
* @author Ryan Grove <ryan@wonko.com>
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
* @copyright 2008 Ryan Grove, Stephen Clay. All rights reserved.
|
* @copyright 2008 Ryan Grove, Stephen Clay. All rights reserved.
|
||||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||||
* @link http://code.google.com/p/minify/
|
* @link http://code.google.com/p/minify/
|
||||||
*/
|
*/
|
||||||
class Minify {
|
class Minify {
|
||||||
|
|
||||||
const TYPE_CSS = 'text/css';
|
const TYPE_CSS = 'text/css';
|
||||||
const TYPE_HTML = 'text/html';
|
const TYPE_HTML = 'text/html';
|
||||||
// there is some debate over the ideal JS Content-Type, but this is the
|
// there is some debate over the ideal JS Content-Type, but this is the
|
||||||
// Apache default and what Yahoo! uses..
|
// Apache default and what Yahoo! uses..
|
||||||
const TYPE_JS = 'application/x-javascript';
|
const TYPE_JS = 'application/x-javascript';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many hours behind are the file modification times of uploaded files?
|
* How many hours behind are the file modification times of uploaded files?
|
||||||
*
|
*
|
||||||
* If you upload files from Windows to a non-Windows server, Windows may report
|
* If you upload files from Windows to a non-Windows server, Windows may report
|
||||||
* incorrect mtimes for the files. Immediately after modifying and uploading a
|
* incorrect mtimes for the files. Immediately after modifying and uploading a
|
||||||
* file, use the touch command to update the mtime on the server. If the mtime
|
* file, use the touch command to update the mtime on the server. If the mtime
|
||||||
* jumps ahead by a number of hours, set this variable to that number. If the mtime
|
* jumps ahead by a number of hours, set this variable to that number. If the mtime
|
||||||
* moves back, this should not be needed.
|
* moves back, this should not be needed.
|
||||||
*
|
*
|
||||||
* @var int $uploaderHoursBehind
|
* @var int $uploaderHoursBehind
|
||||||
*/
|
*/
|
||||||
public static $uploaderHoursBehind = 0;
|
public static $uploaderHoursBehind = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see setCache()
|
* @see setCache()
|
||||||
* @param mixed $cache object with identical interface as Minify_Cache_File or
|
* @param mixed $cache object with identical interface as Minify_Cache_File or
|
||||||
* a directory path. (default = '')
|
* a directory path. (default = '')
|
||||||
* @return null
|
* @return null
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
public static function useServerCache($path = '')
|
public static function useServerCache($path = '')
|
||||||
{
|
{
|
||||||
self::setCache($path);
|
self::setCache($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify a cache object (with identical interface as Minify_Cache_File) or
|
* Specify a cache object (with identical interface as Minify_Cache_File) or
|
||||||
* a path to use with Minify_Cache_File.
|
* a path to use with Minify_Cache_File.
|
||||||
*
|
*
|
||||||
* If not called, Minify will not use a cache and, for each 200 response, will
|
* If not called, Minify will not use a cache and, for each 200 response, will
|
||||||
* need to recombine files, minify and encode the output.
|
* need to recombine files, minify and encode the output.
|
||||||
*
|
*
|
||||||
* @param mixed $cache object with identical interface as Minify_Cache_File or
|
* @param mixed $cache object with identical interface as Minify_Cache_File or
|
||||||
* a directory path. (default = '')
|
* a directory path. (default = '')
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public static function setCache($cache = '')
|
public static function setCache($cache = '')
|
||||||
{
|
{
|
||||||
if (is_string($cache)) {
|
if (is_string($cache)) {
|
||||||
require_once 'Minify/Cache/File.php';
|
require_once 'Minify/Cache/File.php';
|
||||||
self::$_cache = new Minify_Cache_File($cache);
|
self::$_cache = new Minify_Cache_File($cache);
|
||||||
} else {
|
} else {
|
||||||
self::$_cache = $cache;
|
self::$_cache = $cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static $_cache = null;
|
private static $_cache = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serve a request for a minified file.
|
* Serve a request for a minified file.
|
||||||
*
|
*
|
||||||
* Here are the available options and defaults in the base controller:
|
* Here are the available options and defaults in the base controller:
|
||||||
*
|
*
|
||||||
* 'isPublic' : send "public" instead of "private" in Cache-Control
|
* 'isPublic' : send "public" instead of "private" in Cache-Control
|
||||||
* headers, allowing shared caches to cache the output. (default true)
|
* headers, allowing shared caches to cache the output. (default true)
|
||||||
*
|
*
|
||||||
* 'quiet' : set to true to have serve() return an array rather than sending
|
* 'quiet' : set to true to have serve() return an array rather than sending
|
||||||
* any headers/output (default false)
|
* any headers/output (default false)
|
||||||
*
|
*
|
||||||
* 'encodeOutput' : to disable content encoding, set this to false (default true)
|
* 'encodeOutput' : to disable content encoding, set this to false (default true)
|
||||||
*
|
*
|
||||||
* 'encodeMethod' : generally you should let this be determined by
|
* 'encodeMethod' : generally you should let this be determined by
|
||||||
* HTTP_Encoder (leave null), but you can force a particular encoding
|
* HTTP_Encoder (leave null), but you can force a particular encoding
|
||||||
* to be returned, by setting this to 'gzip', 'deflate', or '' (no encoding)
|
* to be returned, by setting this to 'gzip', 'deflate', or '' (no encoding)
|
||||||
*
|
*
|
||||||
* 'encodeLevel' : level of encoding compression (0 to 9, default 9)
|
* 'encodeLevel' : level of encoding compression (0 to 9, default 9)
|
||||||
*
|
*
|
||||||
* 'contentTypeCharset' : appended to the Content-Type header sent. Set to a falsey
|
* 'contentTypeCharset' : appended to the Content-Type header sent. Set to a falsey
|
||||||
* value to remove. (default 'UTF-8')
|
* value to remove. (default 'UTF-8')
|
||||||
*
|
*
|
||||||
* 'maxAge' : set this to the number of seconds the client should use its cache
|
* 'maxAge' : set this to the number of seconds the client should use its cache
|
||||||
* before revalidating with the server. This sets Cache-Control: max-age and the
|
* before revalidating with the server. This sets Cache-Control: max-age and the
|
||||||
* Expires header. Unlike the old 'setExpires' setting, this setting will NOT
|
* Expires header. Unlike the old 'setExpires' setting, this setting will NOT
|
||||||
* prevent conditional GETs. Note this has nothing to do with server-side caching.
|
* prevent conditional GETs. Note this has nothing to do with server-side caching.
|
||||||
*
|
*
|
||||||
* 'rewriteCssUris' : If true, serve() will automatically set the 'currentDir'
|
* 'rewriteCssUris' : If true, serve() will automatically set the 'currentDir'
|
||||||
* minifier option to enable URI rewriting in CSS files (default true)
|
* minifier option to enable URI rewriting in CSS files (default true)
|
||||||
*
|
*
|
||||||
* 'debug' : set to true to minify all sources with the 'Lines' controller, which
|
* 'debug' : set to true to minify all sources with the 'Lines' controller, which
|
||||||
* eases the debugging of combined files. This also prevents 304 responses.
|
* eases the debugging of combined files. This also prevents 304 responses.
|
||||||
* @see Minify_Lines::minify()
|
* @see Minify_Lines::minify()
|
||||||
*
|
*
|
||||||
* 'minifiers' : to override Minify's default choice of minifier function for
|
* 'minifiers' : to override Minify's default choice of minifier function for
|
||||||
* a particular content-type, specify your callback under the key of the
|
* a particular content-type, specify your callback under the key of the
|
||||||
* content-type:
|
* content-type:
|
||||||
* <code>
|
* <code>
|
||||||
* // call customCssMinifier($css) for all CSS minification
|
* // call customCssMinifier($css) for all CSS minification
|
||||||
* $options['minifiers'][Minify::TYPE_CSS] = 'customCssMinifier';
|
* $options['minifiers'][Minify::TYPE_CSS] = 'customCssMinifier';
|
||||||
*
|
*
|
||||||
* // don't minify Javascript at all
|
* // don't minify Javascript at all
|
||||||
* $options['minifiers'][Minify::TYPE_JS] = '';
|
* $options['minifiers'][Minify::TYPE_JS] = '';
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* 'minifierOptions' : to send options to the minifier function, specify your options
|
* 'minifierOptions' : to send options to the minifier function, specify your options
|
||||||
* under the key of the content-type. E.g. To send the CSS minifier an option:
|
* under the key of the content-type. E.g. To send the CSS minifier an option:
|
||||||
* <code>
|
* <code>
|
||||||
* // give CSS minifier array('optionName' => 'optionValue') as 2nd argument
|
* // give CSS minifier array('optionName' => 'optionValue') as 2nd argument
|
||||||
* $options['minifierOptions'][Minify::TYPE_CSS]['optionName'] = 'optionValue';
|
* $options['minifierOptions'][Minify::TYPE_CSS]['optionName'] = 'optionValue';
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* 'contentType' : (optional) this is only needed if your file extension is not
|
* 'contentType' : (optional) this is only needed if your file extension is not
|
||||||
* js/css/html. The given content-type will be sent regardless of source file
|
* js/css/html. The given content-type will be sent regardless of source file
|
||||||
* extension, so this should not be used in a Groups config with other
|
* extension, so this should not be used in a Groups config with other
|
||||||
* Javascript/CSS files.
|
* Javascript/CSS files.
|
||||||
*
|
*
|
||||||
* Any controller options are documented in that controller's setupSources() method.
|
* Any controller options are documented in that controller's setupSources() method.
|
||||||
*
|
*
|
||||||
* @param mixed instance of subclass of Minify_Controller_Base or string name of
|
* @param mixed instance of subclass of Minify_Controller_Base or string name of
|
||||||
* controller. E.g. 'Files'
|
* controller. E.g. 'Files'
|
||||||
*
|
*
|
||||||
* @param array $options controller/serve options
|
* @param array $options controller/serve options
|
||||||
*
|
*
|
||||||
* @return mixed null, or, if the 'quiet' option is set to true, an array
|
* @return mixed null, or, if the 'quiet' option is set to true, an array
|
||||||
* with keys "success" (bool), "statusCode" (int), "content" (string), and
|
* with keys "success" (bool), "statusCode" (int), "content" (string), and
|
||||||
* "headers" (array).
|
* "headers" (array).
|
||||||
*/
|
*/
|
||||||
public static function serve($controller, $options = array()) {
|
public static function serve($controller, $options = array()) {
|
||||||
if (is_string($controller)) {
|
if (is_string($controller)) {
|
||||||
// make $controller into object
|
// make $controller into object
|
||||||
$class = 'Minify_Controller_' . $controller;
|
$class = 'Minify_Controller_' . $controller;
|
||||||
if (! class_exists($class, false)) {
|
if (! class_exists($class, false)) {
|
||||||
require_once "Minify/Controller/"
|
require_once "Minify/Controller/"
|
||||||
. str_replace('_', '/', $controller) . ".php";
|
. str_replace('_', '/', $controller) . ".php";
|
||||||
}
|
}
|
||||||
$controller = new $class();
|
$controller = new $class();
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up controller sources and mix remaining options with
|
// set up controller sources and mix remaining options with
|
||||||
// controller defaults
|
// controller defaults
|
||||||
$options = $controller->setupSources($options);
|
$options = $controller->setupSources($options);
|
||||||
$options = $controller->analyzeSources($options);
|
$options = $controller->analyzeSources($options);
|
||||||
self::$_options = $controller->mixInDefaultOptions($options);
|
self::$_options = $controller->mixInDefaultOptions($options);
|
||||||
|
|
||||||
// check request validity
|
// check request validity
|
||||||
if (! $controller->sources) {
|
if (! $controller->sources) {
|
||||||
// invalid request!
|
// invalid request!
|
||||||
if (! self::$_options['quiet']) {
|
if (! self::$_options['quiet']) {
|
||||||
header(self::$_options['badRequestHeader']);
|
header(self::$_options['badRequestHeader']);
|
||||||
echo self::$_options['badRequestHeader'];
|
echo self::$_options['badRequestHeader'];
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
list(,$statusCode) = explode(' ', self::$_options['badRequestHeader']);
|
list(,$statusCode) = explode(' ', self::$_options['badRequestHeader']);
|
||||||
return array(
|
return array(
|
||||||
'success' => false
|
'success' => false
|
||||||
,'statusCode' => (int)$statusCode
|
,'statusCode' => (int)$statusCode
|
||||||
,'content' => ''
|
,'content' => ''
|
||||||
,'headers' => array()
|
,'headers' => array()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self::$_controller = $controller;
|
self::$_controller = $controller;
|
||||||
|
|
||||||
if (self::$_options['debug']) {
|
if (self::$_options['debug']) {
|
||||||
self::_setupDebug($controller->sources);
|
self::_setupDebug($controller->sources);
|
||||||
self::$_options['maxAge'] = 0;
|
self::$_options['maxAge'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check client cache
|
// check client cache
|
||||||
require_once 'HTTP/ConditionalGet.php';
|
require_once 'HTTP/ConditionalGet.php';
|
||||||
$cgOptions = array(
|
$cgOptions = array(
|
||||||
'lastModifiedTime' => self::$_options['lastModifiedTime']
|
'lastModifiedTime' => self::$_options['lastModifiedTime']
|
||||||
,'isPublic' => self::$_options['isPublic']
|
,'isPublic' => self::$_options['isPublic']
|
||||||
);
|
);
|
||||||
if (self::$_options['maxAge'] > 0) {
|
if (self::$_options['maxAge'] > 0) {
|
||||||
$cgOptions['maxAge'] = self::$_options['maxAge'];
|
$cgOptions['maxAge'] = self::$_options['maxAge'];
|
||||||
}
|
}
|
||||||
$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();
|
$cg->sendHeaders();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
return array(
|
return array(
|
||||||
'success' => true
|
'success' => true
|
||||||
,'statusCode' => 304
|
,'statusCode' => 304
|
||||||
,'content' => ''
|
,'content' => ''
|
||||||
,'headers' => $cg->getHeaders()
|
,'headers' => $cg->getHeaders()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// client will need output
|
// client will need output
|
||||||
$headers = $cg->getHeaders();
|
$headers = $cg->getHeaders();
|
||||||
unset($cg);
|
unset($cg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine encoding
|
// determine encoding
|
||||||
if (self::$_options['encodeOutput']) {
|
if (self::$_options['encodeOutput']) {
|
||||||
if (self::$_options['encodeMethod'] !== null) {
|
if (self::$_options['encodeMethod'] !== null) {
|
||||||
// controller specifically requested this
|
// controller specifically requested this
|
||||||
$contentEncoding = self::$_options['encodeMethod'];
|
$contentEncoding = self::$_options['encodeMethod'];
|
||||||
} else {
|
} else {
|
||||||
// sniff request header
|
// sniff request header
|
||||||
require_once 'HTTP/Encoder.php';
|
require_once 'HTTP/Encoder.php';
|
||||||
// depending on what the client accepts, $contentEncoding may be
|
// depending on what the client accepts, $contentEncoding may be
|
||||||
// 'x-gzip' while our internal encodeMethod is 'gzip'. Calling
|
// 'x-gzip' while our internal encodeMethod is 'gzip'. Calling
|
||||||
// getAcceptedEncoding() with false leaves out compress as an option.
|
// getAcceptedEncoding() with false leaves out compress as an option.
|
||||||
list(self::$_options['encodeMethod'], $contentEncoding) = HTTP_Encoder::getAcceptedEncoding(false);
|
list(self::$_options['encodeMethod'], $contentEncoding) = HTTP_Encoder::getAcceptedEncoding(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self::$_options['encodeMethod'] = ''; // identity (no encoding)
|
self::$_options['encodeMethod'] = ''; // identity (no encoding)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self::$_options['contentType'] === self::TYPE_CSS
|
if (self::$_options['contentType'] === self::TYPE_CSS
|
||||||
@@ -252,184 +252,184 @@ class Minify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check server cache
|
// check server cache
|
||||||
if (null !== self::$_cache) {
|
if (null !== self::$_cache) {
|
||||||
// using cache
|
// using cache
|
||||||
// the goal is to use only the cache methods to sniff the length and
|
// the goal is to use only the cache methods to sniff the length and
|
||||||
// output the content, as they do not require ever loading the file into
|
// output the content, as they do not require ever loading the file into
|
||||||
// memory.
|
// memory.
|
||||||
$cacheId = 'minify_' . self::_getCacheId();
|
$cacheId = 'minify_' . self::_getCacheId();
|
||||||
$encodingExtension = self::$_options['encodeMethod']
|
$encodingExtension = self::$_options['encodeMethod']
|
||||||
? ('deflate' === self::$_options['encodeMethod']
|
? ('deflate' === self::$_options['encodeMethod']
|
||||||
? '.zd'
|
? '.zd'
|
||||||
: '.zg')
|
: '.zg')
|
||||||
: '';
|
: '';
|
||||||
$fullCacheId = $cacheId . $encodingExtension;
|
$fullCacheId = $cacheId . $encodingExtension;
|
||||||
// check cache for valid entry
|
// check cache for valid entry
|
||||||
$cacheIsReady = self::$_cache->isValid($fullCacheId, self::$_options['lastModifiedTime']);
|
$cacheIsReady = self::$_cache->isValid($fullCacheId, self::$_options['lastModifiedTime']);
|
||||||
if ($cacheIsReady) {
|
if ($cacheIsReady) {
|
||||||
$cacheContentLength = self::$_cache->getSize($fullCacheId);
|
$cacheContentLength = self::$_cache->getSize($fullCacheId);
|
||||||
} else {
|
} else {
|
||||||
// generate & cache content
|
// generate & cache content
|
||||||
$content = self::_combineMinify();
|
$content = self::_combineMinify();
|
||||||
self::$_cache->store($cacheId, $content);
|
self::$_cache->store($cacheId, $content);
|
||||||
self::$_cache->store($cacheId . '.zd', gzdeflate($content, self::$_options['encodeLevel']));
|
self::$_cache->store($cacheId . '.zd', gzdeflate($content, self::$_options['encodeLevel']));
|
||||||
self::$_cache->store($cacheId . '.zg', gzencode($content, self::$_options['encodeLevel']));
|
self::$_cache->store($cacheId . '.zg', gzencode($content, self::$_options['encodeLevel']));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no cache
|
// no cache
|
||||||
$cacheIsReady = false;
|
$cacheIsReady = false;
|
||||||
$content = self::_combineMinify();
|
$content = self::_combineMinify();
|
||||||
}
|
}
|
||||||
if (! $cacheIsReady && self::$_options['encodeMethod']) {
|
if (! $cacheIsReady && self::$_options['encodeMethod']) {
|
||||||
// still need to encode
|
// still need to encode
|
||||||
$content = ('deflate' === self::$_options['encodeMethod'])
|
$content = ('deflate' === self::$_options['encodeMethod'])
|
||||||
? gzdeflate($content, self::$_options['encodeLevel'])
|
? gzdeflate($content, self::$_options['encodeLevel'])
|
||||||
: gzencode($content, self::$_options['encodeLevel']);
|
: gzencode($content, self::$_options['encodeLevel']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add headers
|
// add headers
|
||||||
$headers['Content-Length'] = $cacheIsReady
|
$headers['Content-Length'] = $cacheIsReady
|
||||||
? $cacheContentLength
|
? $cacheContentLength
|
||||||
: strlen($content);
|
: strlen($content);
|
||||||
$headers['Content-Type'] = self::$_options['contentTypeCharset']
|
$headers['Content-Type'] = self::$_options['contentTypeCharset']
|
||||||
? self::$_options['contentType'] . '; charset=' . self::$_options['contentTypeCharset']
|
? self::$_options['contentType'] . '; charset=' . self::$_options['contentTypeCharset']
|
||||||
: self::$_options['contentType'];
|
: self::$_options['contentType'];
|
||||||
if (self::$_options['encodeMethod'] !== '') {
|
if (self::$_options['encodeMethod'] !== '') {
|
||||||
$headers['Content-Encoding'] = $contentEncoding;
|
$headers['Content-Encoding'] = $contentEncoding;
|
||||||
$headers['Vary'] = 'Accept-Encoding';
|
$headers['Vary'] = 'Accept-Encoding';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! self::$_options['quiet']) {
|
if (! self::$_options['quiet']) {
|
||||||
// output headers & content
|
// output headers & content
|
||||||
foreach ($headers as $name => $val) {
|
foreach ($headers as $name => $val) {
|
||||||
header($name . ': ' . $val);
|
header($name . ': ' . $val);
|
||||||
}
|
}
|
||||||
if ($cacheIsReady) {
|
if ($cacheIsReady) {
|
||||||
self::$_cache->display($fullCacheId);
|
self::$_cache->display($fullCacheId);
|
||||||
} else {
|
} else {
|
||||||
echo $content;
|
echo $content;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return array(
|
return array(
|
||||||
'success' => true
|
'success' => true
|
||||||
,'statusCode' => 200
|
,'statusCode' => 200
|
||||||
,'content' => $cacheIsReady
|
,'content' => $cacheIsReady
|
||||||
? self::$_cache->fetch($fullCacheId)
|
? self::$_cache->fetch($fullCacheId)
|
||||||
: $content
|
: $content
|
||||||
,'headers' => $headers
|
,'headers' => $headers
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Minify_Controller active controller for current request
|
* @var Minify_Controller active controller for current request
|
||||||
*/
|
*/
|
||||||
protected static $_controller = null;
|
protected static $_controller = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array options for current request
|
* @var array options for current request
|
||||||
*/
|
*/
|
||||||
protected static $_options = null;
|
protected static $_options = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up sources to use Minify_Lines
|
* Set up sources to use Minify_Lines
|
||||||
*
|
*
|
||||||
* @param array $sources Minify_Source instances
|
* @param array $sources Minify_Source instances
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
protected static function _setupDebug($sources)
|
protected static function _setupDebug($sources)
|
||||||
{
|
{
|
||||||
foreach ($sources as $source) {
|
foreach ($sources as $source) {
|
||||||
$source->minifier = array('Minify_Lines', 'minify');
|
$source->minifier = array('Minify_Lines', 'minify');
|
||||||
$id = $source->getId();
|
$id = $source->getId();
|
||||||
$source->minifyOptions = array(
|
$source->minifyOptions = array(
|
||||||
'id' => (is_file($id) ? basename($id) : $id)
|
'id' => (is_file($id) ? basename($id) : $id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combines sources and minifies the result.
|
* Combines sources and minifies the result.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected 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
|
||||||
$implodeSeparator = ($type === self::TYPE_JS)
|
$implodeSeparator = ($type === self::TYPE_JS)
|
||||||
? ';'
|
? ';'
|
||||||
: '';
|
: '';
|
||||||
// allow the user to pass a particular array of options to each
|
// allow the user to pass a particular array of options to each
|
||||||
// minifier (designated by type). source objects may still override
|
// minifier (designated by type). source objects may still override
|
||||||
// these
|
// these
|
||||||
$defaultOptions = isset(self::$_options['minifierOptions'][$type])
|
$defaultOptions = isset(self::$_options['minifierOptions'][$type])
|
||||||
? self::$_options['minifierOptions'][$type]
|
? self::$_options['minifierOptions'][$type]
|
||||||
: array();
|
: array();
|
||||||
// if minifier not set, default is no minification. source objects
|
// if minifier not set, default is no minification. source objects
|
||||||
// may still override this
|
// may still override this
|
||||||
$defaultMinifier = isset(self::$_options['minifiers'][$type])
|
$defaultMinifier = isset(self::$_options['minifiers'][$type])
|
||||||
? self::$_options['minifiers'][$type]
|
? self::$_options['minifiers'][$type]
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
if (Minify_Source::haveNoMinifyPrefs(self::$_controller->sources)) {
|
if (Minify_Source::haveNoMinifyPrefs(self::$_controller->sources)) {
|
||||||
// all source have same options/minifier, better performance
|
// all source have same options/minifier, better performance
|
||||||
// to combine, then minify once
|
// to combine, then minify once
|
||||||
foreach (self::$_controller->sources as $source) {
|
foreach (self::$_controller->sources as $source) {
|
||||||
$pieces[] = $source->getContent();
|
$pieces[] = $source->getContent();
|
||||||
}
|
}
|
||||||
$content = implode($implodeSeparator, $pieces);
|
$content = implode($implodeSeparator, $pieces);
|
||||||
if ($defaultMinifier) {
|
if ($defaultMinifier) {
|
||||||
self::$_controller->loadMinifier($defaultMinifier);
|
self::$_controller->loadMinifier($defaultMinifier);
|
||||||
$content = call_user_func($defaultMinifier, $content, $defaultOptions);
|
$content = call_user_func($defaultMinifier, $content, $defaultOptions);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// minify each source with its own options and minifier, then combine
|
// minify each source with its own options and minifier, then combine
|
||||||
foreach (self::$_controller->sources as $source) {
|
foreach (self::$_controller->sources as $source) {
|
||||||
// allow the source to override our minifier and options
|
// allow the source to override our minifier and options
|
||||||
$minifier = (null !== $source->minifier)
|
$minifier = (null !== $source->minifier)
|
||||||
? $source->minifier
|
? $source->minifier
|
||||||
: $defaultMinifier;
|
: $defaultMinifier;
|
||||||
$options = (null !== $source->minifyOptions)
|
$options = (null !== $source->minifyOptions)
|
||||||
? array_merge($defaultOptions, $source->minifyOptions)
|
? array_merge($defaultOptions, $source->minifyOptions)
|
||||||
: $defaultOptions;
|
: $defaultOptions;
|
||||||
if ($defaultMinifier) {
|
if ($defaultMinifier) {
|
||||||
self::$_controller->loadMinifier($minifier);
|
self::$_controller->loadMinifier($minifier);
|
||||||
// get source content and minify it
|
// get source content and minify it
|
||||||
$pieces[] = call_user_func($minifier, $source->getContent(), $options);
|
$pieces[] = call_user_func($minifier, $source->getContent(), $options);
|
||||||
} else {
|
} else {
|
||||||
$pieces[] = $source->getContent();
|
$pieces[] = $source->getContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$content = implode($implodeSeparator, $pieces);
|
$content = implode($implodeSeparator, $pieces);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do any post-processing (esp. for editing build URIs)
|
// do any post-processing (esp. for editing build URIs)
|
||||||
if (self::$_options['postprocessorRequire']) {
|
if (self::$_options['postprocessorRequire']) {
|
||||||
require_once self::$_options['postprocessorRequire'];
|
require_once self::$_options['postprocessorRequire'];
|
||||||
}
|
}
|
||||||
if (self::$_options['postprocessor']) {
|
if (self::$_options['postprocessor']) {
|
||||||
$content = call_user_func(self::$_options['postprocessor'], $content, $type);
|
$content = call_user_func(self::$_options['postprocessor'], $content, $type);
|
||||||
}
|
}
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a unique cache id for for this request.
|
* Make a unique cache id for for this request.
|
||||||
*
|
*
|
||||||
* Any settings that could affect output are taken into consideration
|
* Any settings that could affect output are taken into consideration
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected 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']
|
||||||
,self::$_options['minifierOptions']
|
,self::$_options['minifierOptions']
|
||||||
,self::$_options['postprocessor']
|
,self::$_options['postprocessor']
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,101 +1,101 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Build
|
* Class Minify_Build
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Source.php';
|
require_once 'Minify/Source.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintain a single last modification time for a group of Minify sources to
|
* Maintain a single last modification time for a group of Minify sources to
|
||||||
* allow use of far off Expires headers in Minify.
|
* allow use of far off Expires headers in Minify.
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* // in config file
|
* // in config file
|
||||||
* $groupSources = array(
|
* $groupSources = array(
|
||||||
* 'js' => array('file1.js', 'file2.js')
|
* 'js' => array('file1.js', 'file2.js')
|
||||||
* ,'css' => array('file1.css', 'file2.css', 'file3.css')
|
* ,'css' => array('file1.css', 'file2.css', 'file3.css')
|
||||||
* )
|
* )
|
||||||
*
|
*
|
||||||
* // during HTML generation
|
* // during HTML generation
|
||||||
* $jsBuild = new Minify_Build($groupSources['js']);
|
* $jsBuild = new Minify_Build($groupSources['js']);
|
||||||
* $cssBuild = new Minify_Build($groupSources['css']);
|
* $cssBuild = new Minify_Build($groupSources['css']);
|
||||||
*
|
*
|
||||||
* $script = "<script type='text/javascript' src='"
|
* $script = "<script type='text/javascript' src='"
|
||||||
* . $jsBuild->uri('/min.php/js') . "'></script>";
|
* . $jsBuild->uri('/min.php/js') . "'></script>";
|
||||||
* $link = "<link rel='stylesheet' type='text/css' href='"
|
* $link = "<link rel='stylesheet' type='text/css' href='"
|
||||||
* . $cssBuild->uri('/min.php/css') . "'>";
|
* . $cssBuild->uri('/min.php/css') . "'>";
|
||||||
*
|
*
|
||||||
* // in min.php
|
* // in min.php
|
||||||
* Minify::serve('Groups', array(
|
* Minify::serve('Groups', array(
|
||||||
* 'groups' => $groupSources
|
* 'groups' => $groupSources
|
||||||
* ,'setExpires' => (time() + 86400 * 365)
|
* ,'setExpires' => (time() + 86400 * 365)
|
||||||
* ));
|
* ));
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_Build {
|
class Minify_Build {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last modification time of all files in the build
|
* Last modification time of all files in the build
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
public $lastModified = 0;
|
public $lastModified = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String to use as ampersand in uri(). Set this to '&' if
|
* String to use as ampersand in uri(). Set this to '&' if
|
||||||
* you are not HTML-escaping URIs.
|
* you are not HTML-escaping URIs.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public static $ampersand = '&';
|
public static $ampersand = '&';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a time-stamped URI
|
* Get a time-stamped URI
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* echo $b->uri('/site.js');
|
* echo $b->uri('/site.js');
|
||||||
* // outputs "/site.js?1678242"
|
* // outputs "/site.js?1678242"
|
||||||
*
|
*
|
||||||
* echo $b->uri('/scriptaculous.js?load=effects');
|
* echo $b->uri('/scriptaculous.js?load=effects');
|
||||||
* // outputs "/scriptaculous.js?load=effects&1678242"
|
* // outputs "/scriptaculous.js?load=effects&1678242"
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* @param string $uri
|
* @param string $uri
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function uri($uri) {
|
public function uri($uri) {
|
||||||
$sep = strpos($uri, '?') === false
|
$sep = strpos($uri, '?') === false
|
||||||
? '?'
|
? '?'
|
||||||
: self::$ampersand;
|
: self::$ampersand;
|
||||||
return "{$uri}{$sep}{$this->lastModified}";
|
return "{$uri}{$sep}{$this->lastModified}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a build object
|
* Create a build object
|
||||||
*
|
*
|
||||||
* @param array $sources array of Minify_Source objects and/or file paths
|
* @param array $sources array of Minify_Source objects and/or file paths
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public function __construct($sources)
|
public function __construct($sources)
|
||||||
{
|
{
|
||||||
$max = 0;
|
$max = 0;
|
||||||
foreach ((array)$sources as $source) {
|
foreach ((array)$sources as $source) {
|
||||||
if ($source instanceof Minify_Source) {
|
if ($source instanceof Minify_Source) {
|
||||||
$max = max($max, $source->lastModified);
|
$max = max($max, $source->lastModified);
|
||||||
} elseif (is_string($source)) {
|
} elseif (is_string($source)) {
|
||||||
if (0 === strpos($source, '//')) {
|
if (0 === strpos($source, '//')) {
|
||||||
$source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1);
|
$source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1);
|
||||||
}
|
}
|
||||||
if (is_file($source)) {
|
if (is_file($source)) {
|
||||||
$max = max($max, filemtime($source));
|
$max = max($max, filemtime($source));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->lastModified = $max;
|
$this->lastModified = $max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_CSS
|
* Class Minify_CSS
|
||||||
* @package Minify
|
* @package Minify
|
||||||
|
@@ -1,103 +1,103 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Cache_File
|
* Class Minify_Cache_File
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Minify_Cache_File {
|
class Minify_Cache_File {
|
||||||
|
|
||||||
public function __construct($path = '')
|
public function __construct($path = '')
|
||||||
{
|
{
|
||||||
if (! $path) {
|
if (! $path) {
|
||||||
require_once 'Solar/Dir.php';
|
require_once 'Solar/Dir.php';
|
||||||
$path = rtrim(Solar_Dir::tmp(), DIRECTORY_SEPARATOR);
|
$path = rtrim(Solar_Dir::tmp(), DIRECTORY_SEPARATOR);
|
||||||
}
|
}
|
||||||
$this->_path = $path;
|
$this->_path = $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write data to cache.
|
* Write data to cache.
|
||||||
*
|
*
|
||||||
* @param string $id cache id (e.g. a filename)
|
* @param string $id cache id (e.g. a filename)
|
||||||
*
|
*
|
||||||
* @param string $data
|
* @param string $data
|
||||||
*
|
*
|
||||||
* @return bool success
|
* @return bool success
|
||||||
*/
|
*/
|
||||||
public function store($id, $data)
|
public function store($id, $data)
|
||||||
{
|
{
|
||||||
return self::_verifiedWrite($this->_path . '/' . $id, $data);
|
return self::_verifiedWrite($this->_path . '/' . $id, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size of a cache entry
|
* Get the size of a cache entry
|
||||||
*
|
*
|
||||||
* @param string $id cache id (e.g. a filename)
|
* @param string $id cache id (e.g. a filename)
|
||||||
*
|
*
|
||||||
* @return int size in bytes
|
* @return int size in bytes
|
||||||
*/
|
*/
|
||||||
public function getSize($id)
|
public function getSize($id)
|
||||||
{
|
{
|
||||||
return filesize($this->_path . '/' . $id);
|
return filesize($this->_path . '/' . $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does a valid cache entry exist?
|
* Does a valid cache entry exist?
|
||||||
*
|
*
|
||||||
* @param string $id cache id (e.g. a filename)
|
* @param string $id cache id (e.g. a filename)
|
||||||
*
|
*
|
||||||
* @param int $srcMtime mtime of the original source file(s)
|
* @param int $srcMtime mtime of the original source file(s)
|
||||||
*
|
*
|
||||||
* @return bool exists
|
* @return bool exists
|
||||||
*/
|
*/
|
||||||
public function isValid($id, $srcMtime)
|
public function isValid($id, $srcMtime)
|
||||||
{
|
{
|
||||||
$file = $this->_path . '/' . $id;
|
$file = $this->_path . '/' . $id;
|
||||||
return (file_exists($file) && (filemtime($file) >= $srcMtime));
|
return (file_exists($file) && (filemtime($file) >= $srcMtime));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the cached content to output
|
* Send the cached content to output
|
||||||
*
|
*
|
||||||
* @param string $id cache id (e.g. a filename)
|
* @param string $id cache id (e.g. a filename)
|
||||||
*/
|
*/
|
||||||
public function display($id)
|
public function display($id)
|
||||||
{
|
{
|
||||||
readfile($this->_path . '/' . $id);
|
readfile($this->_path . '/' . $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the cached content
|
* Fetch the cached content
|
||||||
*
|
*
|
||||||
* @param string $id cache id (e.g. a filename)
|
* @param string $id cache id (e.g. a filename)
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function fetch($id)
|
public function fetch($id)
|
||||||
{
|
{
|
||||||
return file_get_contents($this->_path . '/' . $id);
|
return file_get_contents($this->_path . '/' . $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private $_path = null;
|
private $_path = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write data to file and verify its contents
|
* Write data to file and verify its contents
|
||||||
*
|
*
|
||||||
* @param string $file path
|
* @param string $file path
|
||||||
*
|
*
|
||||||
* @param string $data
|
* @param string $data
|
||||||
*
|
*
|
||||||
* @return bool success
|
* @return bool success
|
||||||
*/
|
*/
|
||||||
private static function _verifiedWrite($file, $data)
|
private static function _verifiedWrite($file, $data)
|
||||||
{
|
{
|
||||||
if (! @file_put_contents($file, $data)) {
|
if (! @file_put_contents($file, $data)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (md5($data) !== md5_file($file)) {
|
if (md5($data) !== md5_file($file)) {
|
||||||
@unlink($file);
|
@unlink($file);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,123 +1,123 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Controller_Base
|
* Class Minify_Controller_Base
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for Minify controller
|
* Base class for Minify controller
|
||||||
*
|
*
|
||||||
* The controller class validates a request and uses it to create sources
|
* The controller class validates a request and uses it to create sources
|
||||||
* for minification and set options like contentType. It's also responsible
|
* for minification and set options like contentType. It's also responsible
|
||||||
* for loading minifier code upon request.
|
* for loading minifier code upon request.
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*
|
*
|
||||||
* @todo add static function to ease setting currentPath for CSS files
|
* @todo add static function to ease setting currentPath for CSS files
|
||||||
* (see line 83 of Version1.php)
|
* (see line 83 of Version1.php)
|
||||||
*/
|
*/
|
||||||
abstract class Minify_Controller_Base {
|
abstract class Minify_Controller_Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup controller sources
|
* Setup controller sources
|
||||||
*
|
*
|
||||||
* You must override this method in your subclass controller to set
|
* You must override this method in your subclass controller to set
|
||||||
* $this->sources. If the request is NOT valid, make sure $this->sources
|
* $this->sources. If the request is NOT valid, make sure $this->sources
|
||||||
* is left an empty array. Then strip any controller-specific options from
|
* is left an empty array. Then strip any controller-specific options from
|
||||||
* $options and return it.
|
* $options and return it.
|
||||||
*
|
*
|
||||||
* @param array $options controller and Minify options
|
* @param array $options controller and Minify options
|
||||||
*
|
*
|
||||||
* @param array $options Minify options
|
* @param array $options Minify options
|
||||||
*/
|
*/
|
||||||
abstract public function setupSources($options);
|
abstract public function setupSources($options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get default Minify options for this controller.
|
* Get default Minify options for this controller.
|
||||||
*
|
*
|
||||||
* Override in subclass to change defaults
|
* Override in subclass to change defaults
|
||||||
*
|
*
|
||||||
* @return array options for Minify
|
* @return array options for Minify
|
||||||
*/
|
*/
|
||||||
public function getDefaultMinifyOptions() {
|
public function getDefaultMinifyOptions() {
|
||||||
return array(
|
return array(
|
||||||
'isPublic' => true
|
'isPublic' => true
|
||||||
,'encodeOutput' => true
|
,'encodeOutput' => true
|
||||||
,'encodeMethod' => null // determine later
|
,'encodeMethod' => null // determine later
|
||||||
,'encodeLevel' => 9
|
,'encodeLevel' => 9
|
||||||
,'minifierOptions' => array() // no minifier options
|
,'minifierOptions' => array() // no minifier options
|
||||||
,'contentTypeCharset' => 'UTF-8'
|
,'contentTypeCharset' => 'UTF-8'
|
||||||
,'maxAge' => 1800 // 30 minutes
|
,'maxAge' => 1800 // 30 minutes
|
||||||
,'rewriteCssUris' => true
|
,'rewriteCssUris' => true
|
||||||
,'quiet' => false // serve() will send headers and output
|
,'quiet' => false // serve() will send headers and output
|
||||||
,'debug' => false
|
,'debug' => false
|
||||||
|
|
||||||
// if you override this, the response code MUST be directly after
|
// if you override this, the response code MUST be directly after
|
||||||
// the first space.
|
// the first space.
|
||||||
,'badRequestHeader' => 'HTTP/1.0 400 Bad Request'
|
,'badRequestHeader' => 'HTTP/1.0 400 Bad Request'
|
||||||
|
|
||||||
// callback function to see/modify content of all sources
|
// callback function to see/modify content of all sources
|
||||||
,'postprocessor' => null
|
,'postprocessor' => null
|
||||||
// file to require to load preprocessor
|
// file to require to load preprocessor
|
||||||
,'postprocessorRequire' => null
|
,'postprocessorRequire' => null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get default minifiers for this controller.
|
* Get default minifiers for this controller.
|
||||||
*
|
*
|
||||||
* Override in subclass to change defaults
|
* Override in subclass to change defaults
|
||||||
*
|
*
|
||||||
* @return array minifier callbacks for common types
|
* @return array minifier callbacks for common types
|
||||||
*/
|
*/
|
||||||
public function getDefaultMinifers() {
|
public function getDefaultMinifers() {
|
||||||
$ret[Minify::TYPE_JS] = array('Minify_Javascript', 'minify');
|
$ret[Minify::TYPE_JS] = array('Minify_Javascript', 'minify');
|
||||||
$ret[Minify::TYPE_CSS] = array('Minify_CSS', 'minify');
|
$ret[Minify::TYPE_CSS] = array('Minify_CSS', 'minify');
|
||||||
$ret[Minify::TYPE_HTML] = array('Minify_HTML', 'minify');
|
$ret[Minify::TYPE_HTML] = array('Minify_HTML', 'minify');
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load any code necessary to execute the given minifier callback.
|
* Load any code necessary to execute the given minifier callback.
|
||||||
*
|
*
|
||||||
* The controller is responsible for loading minification code on demand
|
* The controller is responsible for loading minification code on demand
|
||||||
* via this method. This built-in function will only load classes for
|
* via this method. This built-in function will only load classes for
|
||||||
* static method callbacks where the class isn't already defined. It uses
|
* static method callbacks where the class isn't already defined. It uses
|
||||||
* the PEAR convention, so, given array('Jimmy_Minifier', 'minCss'), this
|
* the PEAR convention, so, given array('Jimmy_Minifier', 'minCss'), this
|
||||||
* function will include 'Jimmy/Minifier.php'
|
* function will include 'Jimmy/Minifier.php'
|
||||||
*
|
*
|
||||||
* If you need code loaded on demand and this doesn't suit you, you'll need
|
* If you need code loaded on demand and this doesn't suit you, you'll need
|
||||||
* to override this function in your subclass.
|
* to override this function in your subclass.
|
||||||
* @see Minify_Controller_Page::loadMinifier()
|
* @see Minify_Controller_Page::loadMinifier()
|
||||||
*
|
*
|
||||||
* @param callback $minifierCallback callback of minifier function
|
* @param callback $minifierCallback callback of minifier function
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public function loadMinifier($minifierCallback)
|
public function loadMinifier($minifierCallback)
|
||||||
{
|
{
|
||||||
if (is_array($minifierCallback)
|
if (is_array($minifierCallback)
|
||||||
&& is_string($minifierCallback[0])
|
&& is_string($minifierCallback[0])
|
||||||
&& !class_exists($minifierCallback[0], false)) {
|
&& !class_exists($minifierCallback[0], false)) {
|
||||||
|
|
||||||
require str_replace('_', '/', $minifierCallback[0]) . '.php';
|
require str_replace('_', '/', $minifierCallback[0]) . '.php';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is a user-given file within an allowable directory, existing,
|
* Is a user-given file within an allowable directory, existing,
|
||||||
* and having an extension js/css/html/txt
|
* and having an extension js/css/html/txt
|
||||||
*
|
*
|
||||||
* This is a convenience function for controllers that have to accept
|
* This is a convenience function for controllers that have to accept
|
||||||
* user-given paths
|
* user-given paths
|
||||||
*
|
*
|
||||||
* @param string $file full file path (already processed by realpath())
|
* @param string $file full file path (already processed by realpath())
|
||||||
* @param array $safeDirs directories where files are safe to serve
|
* @param array $safeDirs directories where files are safe to serve
|
||||||
* @return bool file is safe
|
* @return bool file is safe
|
||||||
*/
|
*/
|
||||||
public static function _fileIsSafe($file, $safeDirs)
|
public static function _fileIsSafe($file, $safeDirs)
|
||||||
{
|
{
|
||||||
$pathOk = false;
|
$pathOk = false;
|
||||||
foreach ((array)$safeDirs as $safeDir) {
|
foreach ((array)$safeDirs as $safeDir) {
|
||||||
if (strpos($file, $safeDir) === 0 && file_exists($file)) {
|
if (strpos($file, $safeDir) === 0 && file_exists($file)) {
|
||||||
@@ -128,68 +128,68 @@ abstract class Minify_Controller_Base {
|
|||||||
if (! $pathOk) {
|
if (! $pathOk) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$base = basename($file);
|
$base = basename($file);
|
||||||
if ($base[0] === '.') {
|
if ($base[0] === '.') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
list($revExt) = explode('.', strrev($base));
|
list($revExt) = explode('.', strrev($base));
|
||||||
return in_array(strrev($revExt), array('js', 'css', 'html', 'txt'));
|
return in_array(strrev($revExt), array('js', 'css', 'html', 'txt'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public static function _haveSameExt
|
/*public static function _haveSameExt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array instances of Minify_Source, which provide content and
|
* @var array instances of Minify_Source, which provide content and
|
||||||
* any individual minification needs.
|
* any individual minification needs.
|
||||||
*
|
*
|
||||||
* @see Minify_Source
|
* @see Minify_Source
|
||||||
*/
|
*/
|
||||||
public $sources = array();
|
public $sources = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mix in default controller options with user-given options
|
* Mix in default controller options with user-given options
|
||||||
*
|
*
|
||||||
* @param array $options user options
|
* @param array $options user options
|
||||||
*
|
*
|
||||||
* @return array mixed options
|
* @return array mixed options
|
||||||
*/
|
*/
|
||||||
public final function mixInDefaultOptions($options)
|
public final function mixInDefaultOptions($options)
|
||||||
{
|
{
|
||||||
$ret = array_merge(
|
$ret = array_merge(
|
||||||
$this->getDefaultMinifyOptions(), $options
|
$this->getDefaultMinifyOptions(), $options
|
||||||
);
|
);
|
||||||
if (! isset($options['minifiers'])) {
|
if (! isset($options['minifiers'])) {
|
||||||
$options['minifiers'] = array();
|
$options['minifiers'] = array();
|
||||||
}
|
}
|
||||||
$ret['minifiers'] = array_merge(
|
$ret['minifiers'] = array_merge(
|
||||||
$this->getDefaultMinifers(), $options['minifiers']
|
$this->getDefaultMinifers(), $options['minifiers']
|
||||||
);
|
);
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyze sources (if there are any) and set $options 'contentType'
|
* Analyze sources (if there are any) and set $options 'contentType'
|
||||||
* and 'lastModifiedTime' if they already aren't.
|
* and 'lastModifiedTime' if they already aren't.
|
||||||
*
|
*
|
||||||
* @param array $options options for Minify
|
* @param array $options options for Minify
|
||||||
*
|
*
|
||||||
* @return array options for Minify
|
* @return array options for Minify
|
||||||
*/
|
*/
|
||||||
public final function analyzeSources($options = array())
|
public final function analyzeSources($options = array())
|
||||||
{
|
{
|
||||||
if ($this->sources) {
|
if ($this->sources) {
|
||||||
if (! isset($options['contentType'])) {
|
if (! isset($options['contentType'])) {
|
||||||
$options['contentType'] = Minify_Source::getContentType($this->sources);
|
$options['contentType'] = Minify_Source::getContentType($this->sources);
|
||||||
}
|
}
|
||||||
// last modified is needed for caching, even if setExpires is set
|
// last modified is needed for caching, even if setExpires is set
|
||||||
if (! isset($options['lastModifiedTime'])) {
|
if (! isset($options['lastModifiedTime'])) {
|
||||||
$max = 0;
|
$max = 0;
|
||||||
foreach ($this->sources as $source) {
|
foreach ($this->sources as $source) {
|
||||||
$max = max($source->lastModified, $max);
|
$max = max($source->lastModified, $max);
|
||||||
}
|
}
|
||||||
$options['lastModifiedTime'] = $max;
|
$options['lastModifiedTime'] = $max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,71 +1,71 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Controller_Files
|
* Class Minify_Controller_Files
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Controller/Base.php';
|
require_once 'Minify/Controller/Base.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for minifying a set of files
|
* Controller class for minifying a set of files
|
||||||
*
|
*
|
||||||
* E.g. the following would serve the minified Javascript for a site
|
* E.g. the following would serve the minified Javascript for a site
|
||||||
* <code>
|
* <code>
|
||||||
* Minify::serve('Files', array(
|
* Minify::serve('Files', array(
|
||||||
* 'files' => array(
|
* 'files' => array(
|
||||||
* '//js/jquery.js'
|
* '//js/jquery.js'
|
||||||
* ,'//js/plugins.js'
|
* ,'//js/plugins.js'
|
||||||
* ,'/home/username/file.js'
|
* ,'/home/username/file.js'
|
||||||
* )
|
* )
|
||||||
* ));
|
* ));
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* As a shortcut, the controller will replace "//" at the beginning
|
* As a shortcut, the controller will replace "//" at the beginning
|
||||||
* of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'.
|
* of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'.
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_Controller_Files extends Minify_Controller_Base {
|
class Minify_Controller_Files extends Minify_Controller_Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up file sources
|
* Set up file sources
|
||||||
*
|
*
|
||||||
* @param array $options controller and Minify options
|
* @param array $options controller and Minify options
|
||||||
* @return array Minify options
|
* @return array Minify options
|
||||||
*
|
*
|
||||||
* Controller options:
|
* Controller options:
|
||||||
*
|
*
|
||||||
* 'files': (required) array of complete file paths, or a single path
|
* 'files': (required) array of complete file paths, or a single path
|
||||||
*/
|
*/
|
||||||
public function setupSources($options) {
|
public function setupSources($options) {
|
||||||
// strip controller options
|
// strip controller options
|
||||||
$files = (array)$options['files'];
|
$files = (array)$options['files'];
|
||||||
unset($options['files']);
|
unset($options['files']);
|
||||||
|
|
||||||
$sources = array();
|
$sources = array();
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
if ($file instanceof Minify_Source) {
|
if ($file instanceof Minify_Source) {
|
||||||
$sources[] = $file;
|
$sources[] = $file;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (0 === strpos($file, '//')) {
|
if (0 === strpos($file, '//')) {
|
||||||
$file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1);
|
$file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1);
|
||||||
}
|
}
|
||||||
$file = realpath($file);
|
$file = realpath($file);
|
||||||
if (file_exists($file)) {
|
if (file_exists($file)) {
|
||||||
$sources[] = new Minify_Source(array(
|
$sources[] = new Minify_Source(array(
|
||||||
'filepath' => $file
|
'filepath' => $file
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
// file not found
|
// file not found
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($sources) {
|
if ($sources) {
|
||||||
$this->sources = $sources;
|
$this->sources = $sources;
|
||||||
}
|
}
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,50 +1,50 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Controller_Groups
|
* Class Minify_Controller_Groups
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Controller/Base.php';
|
require_once 'Minify/Controller/Base.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for serving predetermined groups of minimized sets, selected
|
* Controller class for serving predetermined groups of minimized sets, selected
|
||||||
* by PATH_INFO
|
* by PATH_INFO
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* Minify::serve('Groups', array(
|
* Minify::serve('Groups', array(
|
||||||
* 'groups' => array(
|
* 'groups' => array(
|
||||||
* 'css' => array('//css/type.css', '//css/layout.css')
|
* 'css' => array('//css/type.css', '//css/layout.css')
|
||||||
* ,'js' => array('//js/jquery.js', '//js/site.js')
|
* ,'js' => array('//js/jquery.js', '//js/site.js')
|
||||||
* )
|
* )
|
||||||
* ));
|
* ));
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* If the above code were placed in /serve.php, it would enable the URLs
|
* If the above code were placed in /serve.php, it would enable the URLs
|
||||||
* /serve.php/js and /serve.php/css
|
* /serve.php/js and /serve.php/css
|
||||||
*
|
*
|
||||||
* As a shortcut, the controller will replace "//" at the beginning
|
* As a shortcut, the controller will replace "//" at the beginning
|
||||||
* of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'.
|
* of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'.
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_Controller_Groups extends Minify_Controller_Base {
|
class Minify_Controller_Groups extends Minify_Controller_Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up groups of files as sources
|
* Set up groups of files as sources
|
||||||
*
|
*
|
||||||
* @param array $options controller and Minify options
|
* @param array $options controller and Minify options
|
||||||
* @return array Minify options
|
* @return array Minify options
|
||||||
*
|
*
|
||||||
* Controller options:
|
* Controller options:
|
||||||
*
|
*
|
||||||
* 'groups': (required) array mapping PATH_INFO strings to arrays
|
* 'groups': (required) array mapping PATH_INFO strings to arrays
|
||||||
* of complete file paths. @see Minify_Controller_Groups
|
* of complete file paths. @see Minify_Controller_Groups
|
||||||
*/
|
*/
|
||||||
public function setupSources($options) {
|
public function setupSources($options) {
|
||||||
// strip controller options
|
// strip controller options
|
||||||
$groups = $options['groups'];
|
$groups = $options['groups'];
|
||||||
unset($options['groups']);
|
unset($options['groups']);
|
||||||
|
|
||||||
// mod_fcgid places PATH_INFO in ORIG_PATH_INFO
|
// mod_fcgid places PATH_INFO in ORIG_PATH_INFO
|
||||||
$pi = isset($_SERVER['ORIG_PATH_INFO'])
|
$pi = isset($_SERVER['ORIG_PATH_INFO'])
|
||||||
@@ -57,29 +57,29 @@ class Minify_Controller_Groups extends Minify_Controller_Base {
|
|||||||
// no PATH_INFO or not a valid group
|
// no PATH_INFO or not a valid group
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
$sources = array();
|
$sources = array();
|
||||||
foreach ((array)$groups[$pi] as $file) {
|
foreach ((array)$groups[$pi] as $file) {
|
||||||
if ($file instanceof Minify_Source) {
|
if ($file instanceof Minify_Source) {
|
||||||
$sources[] = $file;
|
$sources[] = $file;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (0 === strpos($file, '//')) {
|
if (0 === strpos($file, '//')) {
|
||||||
$file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1);
|
$file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1);
|
||||||
}
|
}
|
||||||
$file = realpath($file);
|
$file = realpath($file);
|
||||||
if (file_exists($file)) {
|
if (file_exists($file)) {
|
||||||
$sources[] = new Minify_Source(array(
|
$sources[] = new Minify_Source(array(
|
||||||
'filepath' => $file
|
'filepath' => $file
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
// file doesn't exist
|
// file doesn't exist
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($sources) {
|
if ($sources) {
|
||||||
$this->sources = $sources;
|
$this->sources = $sources;
|
||||||
}
|
}
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,80 +1,80 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Controller_Page
|
* Class Minify_Controller_Page
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Controller/Base.php';
|
require_once 'Minify/Controller/Base.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for serving a single HTML page
|
* Controller class for serving a single HTML page
|
||||||
*
|
*
|
||||||
* @link http://code.google.com/p/minify/source/browse/trunk/web/examples/1/index.php#59
|
* @link http://code.google.com/p/minify/source/browse/trunk/web/examples/1/index.php#59
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_Controller_Page extends Minify_Controller_Base {
|
class Minify_Controller_Page extends Minify_Controller_Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up source of HTML content
|
* Set up source of HTML content
|
||||||
*
|
*
|
||||||
* @param array $options controller and Minify options
|
* @param array $options controller and Minify options
|
||||||
* @return array Minify options
|
* @return array Minify options
|
||||||
*
|
*
|
||||||
* Controller options:
|
* Controller options:
|
||||||
*
|
*
|
||||||
* 'content': (required) HTML markup
|
* 'content': (required) HTML markup
|
||||||
*
|
*
|
||||||
* 'id': (required) id of page (string for use in server-side caching)
|
* 'id': (required) id of page (string for use in server-side caching)
|
||||||
*
|
*
|
||||||
* 'lastModifiedTime': timestamp of when this content changed. This
|
* 'lastModifiedTime': timestamp of when this content changed. This
|
||||||
* is recommended to allow both server and client-side caching.
|
* is recommended to allow both server and client-side caching.
|
||||||
*
|
*
|
||||||
* 'minifyAll': should all CSS and Javascript blocks be individually
|
* 'minifyAll': should all CSS and Javascript blocks be individually
|
||||||
* minified? (default false)
|
* minified? (default false)
|
||||||
*
|
*
|
||||||
* @todo Add 'file' option to read HTML file.
|
* @todo Add 'file' option to read HTML file.
|
||||||
*/
|
*/
|
||||||
public function setupSources($options) {
|
public function setupSources($options) {
|
||||||
// strip controller options
|
// strip controller options
|
||||||
$sourceSpec = array(
|
$sourceSpec = array(
|
||||||
'content' => $options['content']
|
'content' => $options['content']
|
||||||
,'id' => $options['id']
|
,'id' => $options['id']
|
||||||
);
|
);
|
||||||
unset($options['content'], $options['id']);
|
unset($options['content'], $options['id']);
|
||||||
|
|
||||||
if (isset($options['minifyAll'])) {
|
if (isset($options['minifyAll'])) {
|
||||||
// this will be the 2nd argument passed to Minify_HTML::minify()
|
// this will be the 2nd argument passed to Minify_HTML::minify()
|
||||||
$sourceSpec['minifyOptions'] = array(
|
$sourceSpec['minifyOptions'] = array(
|
||||||
'cssMinifier' => array('Minify_CSS', 'minify')
|
'cssMinifier' => array('Minify_CSS', 'minify')
|
||||||
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
||||||
);
|
);
|
||||||
$this->_loadCssJsMinifiers = true;
|
$this->_loadCssJsMinifiers = true;
|
||||||
unset($options['minifyAll']);
|
unset($options['minifyAll']);
|
||||||
}
|
}
|
||||||
$this->sources[] = new Minify_Source($sourceSpec);
|
$this->sources[] = new Minify_Source($sourceSpec);
|
||||||
|
|
||||||
// may not be needed
|
// may not be needed
|
||||||
//$options['minifier'] = array('Minify_HTML', 'minify');
|
//$options['minifier'] = array('Minify_HTML', 'minify');
|
||||||
|
|
||||||
$options['contentType'] = Minify::TYPE_HTML;
|
$options['contentType'] = Minify::TYPE_HTML;
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $_loadCssJsMinifiers = false;
|
protected $_loadCssJsMinifiers = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Minify_Controller_Base::loadMinifier()
|
* @see Minify_Controller_Base::loadMinifier()
|
||||||
*/
|
*/
|
||||||
public function loadMinifier($minifierCallback)
|
public function loadMinifier($minifierCallback)
|
||||||
{
|
{
|
||||||
if ($this->_loadCssJsMinifiers) {
|
if ($this->_loadCssJsMinifiers) {
|
||||||
// Minify will not call for these so we must manually load
|
// Minify will not call for these so we must manually load
|
||||||
// them when Minify/HTML.php is called for.
|
// them when Minify/HTML.php is called for.
|
||||||
require 'Minify/CSS.php';
|
require 'Minify/CSS.php';
|
||||||
require 'Minify/Javascript.php';
|
require 'Minify/Javascript.php';
|
||||||
}
|
}
|
||||||
parent::loadMinifier($minifierCallback); // load Minify/HTML.php
|
parent::loadMinifier($minifierCallback); // load Minify/HTML.php
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,118 +1,118 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Controller_Version1
|
* Class Minify_Controller_Version1
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Controller/Base.php';
|
require_once 'Minify/Controller/Base.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for emulating version 1 of minify.php
|
* Controller class for emulating version 1 of minify.php
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* Minify::serve('Version1');
|
* Minify::serve('Version1');
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_Controller_Version1 extends Minify_Controller_Base {
|
class Minify_Controller_Version1 extends Minify_Controller_Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up groups of files as sources
|
* Set up groups of files as sources
|
||||||
*
|
*
|
||||||
* @param array $options controller and Minify options
|
* @param array $options controller and Minify options
|
||||||
* @return array Minify options
|
* @return array Minify options
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setupSources($options) {
|
public function setupSources($options) {
|
||||||
self::_setupDefines();
|
self::_setupDefines();
|
||||||
if (MINIFY_USE_CACHE) {
|
if (MINIFY_USE_CACHE) {
|
||||||
$cacheDir = defined('MINIFY_CACHE_DIR')
|
$cacheDir = defined('MINIFY_CACHE_DIR')
|
||||||
? MINIFY_CACHE_DIR
|
? MINIFY_CACHE_DIR
|
||||||
: '';
|
: '';
|
||||||
Minify::setCache($cacheDir);
|
Minify::setCache($cacheDir);
|
||||||
}
|
}
|
||||||
$options['badRequestHeader'] = 'HTTP/1.0 404 Not Found';
|
$options['badRequestHeader'] = 'HTTP/1.0 404 Not Found';
|
||||||
$options['contentTypeCharset'] = MINIFY_ENCODING;
|
$options['contentTypeCharset'] = MINIFY_ENCODING;
|
||||||
|
|
||||||
// The following restrictions are to limit the URLs that minify will
|
// The following restrictions are to limit the URLs that minify will
|
||||||
// respond to. Ideally there should be only one way to reference a file.
|
// respond to. Ideally there should be only one way to reference a file.
|
||||||
if (! isset($_GET['files'])
|
if (! isset($_GET['files'])
|
||||||
// verify at least one file, files are single comma separated,
|
// verify at least one file, files are single comma separated,
|
||||||
// and are all same extension
|
// and are all same extension
|
||||||
|| ! preg_match('/^[^,]+\\.(css|js)(,[^,]+\\.\\1)*$/', $_GET['files'], $m)
|
|| ! preg_match('/^[^,]+\\.(css|js)(,[^,]+\\.\\1)*$/', $_GET['files'], $m)
|
||||||
// no "//" (makes URL rewriting easier)
|
// no "//" (makes URL rewriting easier)
|
||||||
|| strpos($_GET['files'], '//') !== false
|
|| strpos($_GET['files'], '//') !== false
|
||||||
// no "\"
|
// no "\"
|
||||||
|| strpos($_GET['files'], '\\') !== false
|
|| strpos($_GET['files'], '\\') !== false
|
||||||
// no "./"
|
// no "./"
|
||||||
|| preg_match('/(?:^|[^\\.])\\.\\//', $_GET['files'])
|
|| preg_match('/(?:^|[^\\.])\\.\\//', $_GET['files'])
|
||||||
) {
|
) {
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
$extension = $m[1];
|
$extension = $m[1];
|
||||||
|
|
||||||
$files = explode(',', $_GET['files']);
|
$files = explode(',', $_GET['files']);
|
||||||
if (count($files) > MINIFY_MAX_FILES) {
|
if (count($files) > MINIFY_MAX_FILES) {
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
// strings for prepending to relative/absolute paths
|
// strings for prepending to relative/absolute paths
|
||||||
$prependRelPaths = dirname($_SERVER['SCRIPT_FILENAME'])
|
$prependRelPaths = dirname($_SERVER['SCRIPT_FILENAME'])
|
||||||
. DIRECTORY_SEPARATOR;
|
. DIRECTORY_SEPARATOR;
|
||||||
$prependAbsPaths = $_SERVER['DOCUMENT_ROOT'];
|
$prependAbsPaths = $_SERVER['DOCUMENT_ROOT'];
|
||||||
|
|
||||||
$sources = array();
|
$sources = array();
|
||||||
$goodFiles = array();
|
$goodFiles = array();
|
||||||
$hasBadSource = false;
|
$hasBadSource = false;
|
||||||
|
|
||||||
$allowDirs = isset($options['allowDirs'])
|
$allowDirs = isset($options['allowDirs'])
|
||||||
? $options['allowDirs']
|
? $options['allowDirs']
|
||||||
: MINIFY_BASE_DIR;
|
: MINIFY_BASE_DIR;
|
||||||
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
// prepend appropriate string for abs/rel paths
|
// prepend appropriate string for abs/rel paths
|
||||||
$file = ($file[0] === '/' ? $prependAbsPaths : $prependRelPaths) . $file;
|
$file = ($file[0] === '/' ? $prependAbsPaths : $prependRelPaths) . $file;
|
||||||
// make sure a real file!
|
// make sure a real file!
|
||||||
$file = realpath($file);
|
$file = realpath($file);
|
||||||
// don't allow unsafe or duplicate files
|
// don't allow unsafe or duplicate files
|
||||||
if (parent::_fileIsSafe($file, $allowDirs)
|
if (parent::_fileIsSafe($file, $allowDirs)
|
||||||
&& !in_array($file, $goodFiles))
|
&& !in_array($file, $goodFiles))
|
||||||
{
|
{
|
||||||
$goodFiles[] = $file;
|
$goodFiles[] = $file;
|
||||||
$srcOptions = array(
|
$srcOptions = array(
|
||||||
'filepath' => $file
|
'filepath' => $file
|
||||||
);
|
);
|
||||||
$this->sources[] = new Minify_Source($srcOptions);
|
$this->sources[] = new Minify_Source($srcOptions);
|
||||||
} else {
|
} else {
|
||||||
$hasBadSource = true;
|
$hasBadSource = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($hasBadSource) {
|
if ($hasBadSource) {
|
||||||
$this->sources = array();
|
$this->sources = array();
|
||||||
}
|
}
|
||||||
if (! MINIFY_REWRITE_CSS_URLS) {
|
if (! MINIFY_REWRITE_CSS_URLS) {
|
||||||
$options['rewriteCssUris'] = false;
|
$options['rewriteCssUris'] = false;
|
||||||
}
|
}
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function _setupDefines()
|
private static function _setupDefines()
|
||||||
{
|
{
|
||||||
$defaults = array(
|
$defaults = array(
|
||||||
'MINIFY_BASE_DIR' => realpath($_SERVER['DOCUMENT_ROOT'])
|
'MINIFY_BASE_DIR' => realpath($_SERVER['DOCUMENT_ROOT'])
|
||||||
,'MINIFY_ENCODING' => 'utf-8'
|
,'MINIFY_ENCODING' => 'utf-8'
|
||||||
,'MINIFY_MAX_FILES' => 16
|
,'MINIFY_MAX_FILES' => 16
|
||||||
,'MINIFY_REWRITE_CSS_URLS' => true
|
,'MINIFY_REWRITE_CSS_URLS' => true
|
||||||
,'MINIFY_USE_CACHE' => true
|
,'MINIFY_USE_CACHE' => true
|
||||||
);
|
);
|
||||||
foreach ($defaults as $const => $val) {
|
foreach ($defaults as $const => $val) {
|
||||||
if (! defined($const)) {
|
if (! defined($const)) {
|
||||||
define($const, $val);
|
define($const, $val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,88 +1,88 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_HTML
|
* Class Minify_HTML
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compress HTML
|
* Compress HTML
|
||||||
*
|
*
|
||||||
* This is a heavy regex-based removal of whitespace, unnecessary comments and
|
* This is a heavy regex-based removal of whitespace, unnecessary comments and
|
||||||
* tokens. IE conditional comments are preserved. There are also options to have
|
* tokens. IE conditional comments are preserved. There are also options to have
|
||||||
* STYLE and SCRIPT blocks compressed by callback functions.
|
* STYLE and SCRIPT blocks compressed by callback functions.
|
||||||
*
|
*
|
||||||
* A test suite is available.
|
* A test suite is available.
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_HTML {
|
class Minify_HTML {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Minify" an HTML page
|
* "Minify" an HTML page
|
||||||
*
|
*
|
||||||
* @param string $html
|
* @param string $html
|
||||||
* @param array $options
|
* @param array $options
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function minify($html, $options = array()) {
|
public static function minify($html, $options = array()) {
|
||||||
|
|
||||||
if (isset($options['cssMinifier'])) {
|
if (isset($options['cssMinifier'])) {
|
||||||
self::$_cssMinifier = $options['cssMinifier'];
|
self::$_cssMinifier = $options['cssMinifier'];
|
||||||
}
|
}
|
||||||
if (isset($options['jsMinifier'])) {
|
if (isset($options['jsMinifier'])) {
|
||||||
self::$_jsMinifier = $options['jsMinifier'];
|
self::$_jsMinifier = $options['jsMinifier'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$html = str_replace("\r\n", "\n", trim($html));
|
$html = str_replace("\r\n", "\n", trim($html));
|
||||||
|
|
||||||
self::$_isXhtml = (false !== strpos($html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
|
self::$_isXhtml = (false !== strpos($html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
|
||||||
|
|
||||||
self::$_replacementHash = 'MINIFYHTML' . md5(time());
|
self::$_replacementHash = 'MINIFYHTML' . md5(time());
|
||||||
self::$_placeholders = array();
|
self::$_placeholders = array();
|
||||||
|
|
||||||
// replace SCRIPTs (and minify) with placeholders
|
// replace SCRIPTs (and minify) with placeholders
|
||||||
$html = preg_replace_callback(
|
$html = preg_replace_callback(
|
||||||
'/\\s*(<script\\b[^>]*?>)([\\s\\S]*?)<\\/script>\\s*/i'
|
'/\\s*(<script\\b[^>]*?>)([\\s\\S]*?)<\\/script>\\s*/i'
|
||||||
,array('Minify_HTML', '_removeScriptCB')
|
,array('Minify_HTML', '_removeScriptCB')
|
||||||
,$html);
|
,$html);
|
||||||
|
|
||||||
// replace STYLEs (and minify) with placeholders
|
// replace STYLEs (and minify) with placeholders
|
||||||
$html = preg_replace_callback(
|
$html = preg_replace_callback(
|
||||||
'/\\s*(<style\\b[^>]*?>)([\\s\\S]*?)<\\/style>\\s*/i'
|
'/\\s*(<style\\b[^>]*?>)([\\s\\S]*?)<\\/style>\\s*/i'
|
||||||
,array('Minify_HTML', '_removeStyleCB')
|
,array('Minify_HTML', '_removeStyleCB')
|
||||||
,$html);
|
,$html);
|
||||||
|
|
||||||
// remove HTML comments (but not IE conditional comments).
|
// remove HTML comments (but not IE conditional comments).
|
||||||
$html = preg_replace('/<!--[^\\[][\\s\\S]*?-->/', '', $html);
|
$html = preg_replace('/<!--[^\\[][\\s\\S]*?-->/', '', $html);
|
||||||
|
|
||||||
// replace PREs with placeholders
|
// replace PREs with placeholders
|
||||||
$html = preg_replace_callback('/\\s*(<pre\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
|
$html = preg_replace_callback('/\\s*(<pre\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
|
||||||
,array('Minify_HTML', '_removePreCB')
|
,array('Minify_HTML', '_removePreCB')
|
||||||
, $html);
|
, $html);
|
||||||
|
|
||||||
// replace TEXTAREAs with placeholders
|
// replace TEXTAREAs with placeholders
|
||||||
$html = preg_replace_callback(
|
$html = preg_replace_callback(
|
||||||
'/\\s*(<textarea\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
|
'/\\s*(<textarea\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
|
||||||
,array('Minify_HTML', '_removeTaCB')
|
,array('Minify_HTML', '_removeTaCB')
|
||||||
, $html);
|
, $html);
|
||||||
|
|
||||||
// trim each line.
|
// trim each line.
|
||||||
// @todo take into account attribute values that span multiple lines.
|
// @todo take into account attribute values that span multiple lines.
|
||||||
$html = preg_replace('/^\\s+|\\s+$/m', '', $html);
|
$html = preg_replace('/^\\s+|\\s+$/m', '', $html);
|
||||||
|
|
||||||
// remove ws around block/undisplayed elements
|
// remove ws around block/undisplayed elements
|
||||||
$html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
|
$html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
|
||||||
.'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
|
.'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
|
||||||
.'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta'
|
.'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta'
|
||||||
.'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)'
|
.'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)'
|
||||||
.'|ul)\\b[^>]*>)/i', '$1', $html);
|
.'|ul)\\b[^>]*>)/i', '$1', $html);
|
||||||
|
|
||||||
// remove ws outside of all elements
|
// remove ws outside of all elements
|
||||||
$html = preg_replace_callback(
|
$html = preg_replace_callback(
|
||||||
'/>([^<]+)</'
|
'/>([^<]+)</'
|
||||||
,array('Minify_HTML', '_outsideTagCB')
|
,array('Minify_HTML', '_outsideTagCB')
|
||||||
,$html);
|
,$html);
|
||||||
|
|
||||||
// fill placeholders
|
// fill placeholders
|
||||||
$html = str_replace(
|
$html = str_replace(
|
||||||
@@ -90,13 +90,13 @@ class Minify_HTML {
|
|||||||
,array_values(self::$_placeholders)
|
,array_values(self::$_placeholders)
|
||||||
,$html
|
,$html
|
||||||
);
|
);
|
||||||
self::$_placeholders = array();
|
self::$_placeholders = array();
|
||||||
|
|
||||||
// use newlines before 1st attribute in open tags (to limit line lengths)
|
// use newlines before 1st attribute in open tags (to limit line lengths)
|
||||||
$html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $html);
|
$html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $html);
|
||||||
|
|
||||||
self::$_cssMinifier = self::$_jsMinifier = null;
|
self::$_cssMinifier = self::$_jsMinifier = null;
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function _reservePlace($content)
|
protected static function _reservePlace($content)
|
||||||
@@ -104,83 +104,83 @@ class Minify_HTML {
|
|||||||
$placeholder = '%' . self::$_replacementHash . count(self::$_placeholders) . '%';
|
$placeholder = '%' . self::$_replacementHash . count(self::$_placeholders) . '%';
|
||||||
self::$_placeholders[$placeholder] = $content;
|
self::$_placeholders[$placeholder] = $content;
|
||||||
return $placeholder;
|
return $placeholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static $_isXhtml = false;
|
protected static $_isXhtml = false;
|
||||||
protected static $_replacementHash = null;
|
protected static $_replacementHash = null;
|
||||||
protected static $_placeholders = array();
|
protected static $_placeholders = array();
|
||||||
protected static $_cssMinifier = null;
|
protected static $_cssMinifier = null;
|
||||||
protected static $_jsMinifier = null;
|
protected static $_jsMinifier = null;
|
||||||
|
|
||||||
protected static function _outsideTagCB($m)
|
protected static function _outsideTagCB($m)
|
||||||
{
|
{
|
||||||
return '>' . preg_replace('/^\\s+|\\s+$/', ' ', $m[1]) . '<';
|
return '>' . preg_replace('/^\\s+|\\s+$/', ' ', $m[1]) . '<';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function _removePreCB($m)
|
protected static function _removePreCB($m)
|
||||||
{
|
{
|
||||||
return self::_reservePlace($m[1]);
|
return self::_reservePlace($m[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function _removeTaCB($m)
|
protected static function _removeTaCB($m)
|
||||||
{
|
{
|
||||||
return self::_reservePlace($m[1]);
|
return self::_reservePlace($m[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function _removeStyleCB($m)
|
protected static function _removeStyleCB($m)
|
||||||
{
|
{
|
||||||
$openStyle = $m[1];
|
$openStyle = $m[1];
|
||||||
$css = $m[2];
|
$css = $m[2];
|
||||||
// remove HTML comments
|
// remove HTML comments
|
||||||
$css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
|
$css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
|
||||||
|
|
||||||
// remove CDATA section markers
|
// remove CDATA section markers
|
||||||
$css = self::_removeCdata($css);
|
$css = self::_removeCdata($css);
|
||||||
|
|
||||||
// minify
|
// minify
|
||||||
$minifier = self::$_cssMinifier
|
$minifier = self::$_cssMinifier
|
||||||
? self::$_cssMinifier
|
? self::$_cssMinifier
|
||||||
: 'trim';
|
: 'trim';
|
||||||
$css = call_user_func($minifier, $css);
|
$css = call_user_func($minifier, $css);
|
||||||
|
|
||||||
return self::_reservePlace(self::_needsCdata($css)
|
return self::_reservePlace(self::_needsCdata($css)
|
||||||
? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
|
? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
|
||||||
: "{$openStyle}{$css}</style>"
|
: "{$openStyle}{$css}</style>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function _removeScriptCB($m)
|
protected static function _removeScriptCB($m)
|
||||||
{
|
{
|
||||||
$openScript = $m[1];
|
$openScript = $m[1];
|
||||||
$js = $m[2];
|
$js = $m[2];
|
||||||
|
|
||||||
// remove HTML comments (and ending "//" if present)
|
// remove HTML comments (and ending "//" if present)
|
||||||
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
||||||
|
|
||||||
// remove CDATA section markers
|
// remove CDATA section markers
|
||||||
$js = self::_removeCdata($js);
|
$js = self::_removeCdata($js);
|
||||||
|
|
||||||
// minify
|
// minify
|
||||||
$minifier = self::$_jsMinifier
|
$minifier = self::$_jsMinifier
|
||||||
? self::$_jsMinifier
|
? self::$_jsMinifier
|
||||||
: 'trim';
|
: 'trim';
|
||||||
$js = call_user_func($minifier, $js);
|
$js = call_user_func($minifier, $js);
|
||||||
|
|
||||||
return self::_reservePlace(self::_needsCdata($js)
|
return self::_reservePlace(self::_needsCdata($js)
|
||||||
? "{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>"
|
? "{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>"
|
||||||
: "{$openScript}{$js}</script>"
|
: "{$openScript}{$js}</script>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function _needsCdata($str)
|
protected static function _needsCdata($str)
|
||||||
{
|
{
|
||||||
return (self::$_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
|
return (self::$_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,74 +1,74 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Javascript
|
* Class Minify_Javascript
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require 'JSMin.php';
|
require 'JSMin.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compress Javascript using Ryan Grove's JSMin class
|
* Compress Javascript using Ryan Grove's JSMin class
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_Javascript {
|
class Minify_Javascript {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minify a Javascript string
|
* Minify a Javascript string
|
||||||
*
|
*
|
||||||
* @param string $js
|
* @param string $js
|
||||||
*
|
*
|
||||||
* @param array $options available options:
|
* @param array $options available options:
|
||||||
*
|
*
|
||||||
* 'preserveComments': (default true) multi-line comments that begin
|
* 'preserveComments': (default true) multi-line comments that begin
|
||||||
* with "/*!" will be preserved with newlines before and after to
|
* with "/*!" will be preserved with newlines before and after to
|
||||||
* enhance readability.
|
* enhance readability.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function minify($js, $options = array())
|
public static function minify($js, $options = array())
|
||||||
{
|
{
|
||||||
if (isset($options['preserveComments'])
|
if (isset($options['preserveComments'])
|
||||||
&& !$options['preserveComments']) {
|
&& !$options['preserveComments']) {
|
||||||
return trim(JSMin::minify($js));
|
return trim(JSMin::minify($js));
|
||||||
}
|
}
|
||||||
$ret = '';
|
$ret = '';
|
||||||
while (1) {
|
while (1) {
|
||||||
list($beforeComment, $comment, $afterComment)
|
list($beforeComment, $comment, $afterComment)
|
||||||
= self::_nextYuiComment($js);
|
= self::_nextYuiComment($js);
|
||||||
$ret .= trim(JSMin::minify($beforeComment));
|
$ret .= trim(JSMin::minify($beforeComment));
|
||||||
if (false === $comment) {
|
if (false === $comment) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$ret .= $comment;
|
$ret .= $comment;
|
||||||
$js = $afterComment;
|
$js = $afterComment;
|
||||||
}
|
}
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract comments that YUI Compressor preserves.
|
* Extract comments that YUI Compressor preserves.
|
||||||
*
|
*
|
||||||
* @param string $in input
|
* @param string $in input
|
||||||
*
|
*
|
||||||
* @return array 3 elements are returned. If a YUI comment is found, the
|
* @return array 3 elements are returned. If a YUI comment is found, the
|
||||||
* 2nd element is the comment and the 1st and 2nd are the surrounding
|
* 2nd element is the comment and the 1st and 2nd are the surrounding
|
||||||
* strings. If no comment is found, the entire string is returned as the
|
* strings. If no comment is found, the entire string is returned as the
|
||||||
* 1st element and the other two are false.
|
* 1st element and the other two are false.
|
||||||
*/
|
*/
|
||||||
private static function _nextYuiComment($in)
|
private static function _nextYuiComment($in)
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
(false !== ($start = strpos($in, '/*!')))
|
(false !== ($start = strpos($in, '/*!')))
|
||||||
&& (false !== ($end = strpos($in, '*/', $start + 3)))
|
&& (false !== ($end = strpos($in, '*/', $start + 3)))
|
||||||
)
|
)
|
||||||
? array(
|
? array(
|
||||||
substr($in, 0, $start)
|
substr($in, 0, $start)
|
||||||
,"\n/*" . substr($in, $start + 3, $end - $start - 1) . "\n"
|
,"\n/*" . substr($in, $start + 3, $end - $start - 1) . "\n"
|
||||||
,substr($in, -(strlen($in) - $end - 2))
|
,substr($in, -(strlen($in) - $end - 2))
|
||||||
)
|
)
|
||||||
: array($in, false, false);
|
: array($in, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,124 +1,124 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Lines
|
* Class Minify_Lines
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add line numbers in C-style comments for easier debugging of combined content
|
* Add line numbers in C-style comments for easier debugging of combined content
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_Lines {
|
class Minify_Lines {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add line numbers in C-style comments
|
* Add line numbers in C-style comments
|
||||||
*
|
*
|
||||||
* This uses a very basic parser easily fooled by comment tokens inside
|
* This uses a very basic parser easily fooled by comment tokens inside
|
||||||
* strings or regexes, but, otherwise, generally clean code will not be
|
* strings or regexes, but, otherwise, generally clean code will not be
|
||||||
* mangled.
|
* mangled.
|
||||||
*
|
*
|
||||||
* @param string $content
|
* @param string $content
|
||||||
*
|
*
|
||||||
* @param array $options available options:
|
* @param array $options available options:
|
||||||
*
|
*
|
||||||
* 'id': (optional) string to identify file. E.g. file name/path
|
* 'id': (optional) string to identify file. E.g. file name/path
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function minify($content, $options = array())
|
public static function minify($content, $options = array())
|
||||||
{
|
{
|
||||||
$id = (isset($options['id']) && $options['id'])
|
$id = (isset($options['id']) && $options['id'])
|
||||||
? $options['id']
|
? $options['id']
|
||||||
: '';
|
: '';
|
||||||
if (! $eol = self::_getEol($content)) {
|
if (! $eol = self::_getEol($content)) {
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
$lines = explode($eol, $content);
|
$lines = explode($eol, $content);
|
||||||
$numLines = count($lines);
|
$numLines = count($lines);
|
||||||
// determine left padding
|
// determine left padding
|
||||||
$padTo = strlen($numLines);
|
$padTo = strlen($numLines);
|
||||||
$inComment = false;
|
$inComment = false;
|
||||||
$i = 0;
|
$i = 0;
|
||||||
$newLines = array();
|
$newLines = array();
|
||||||
while (null !== ($line = array_shift($lines))) {
|
while (null !== ($line = array_shift($lines))) {
|
||||||
if (('' !== $id) && (0 == $i % 50)) {
|
if (('' !== $id) && (0 == $i % 50)) {
|
||||||
array_push($newLines, '', "/* {$id} */", '');
|
array_push($newLines, '', "/* {$id} */", '');
|
||||||
}
|
}
|
||||||
++$i;
|
++$i;
|
||||||
$newLines[] = self::_addNote($line, $i, $inComment, $padTo);
|
$newLines[] = self::_addNote($line, $i, $inComment, $padTo);
|
||||||
$inComment = self::_eolInComment($line, $inComment);
|
$inComment = self::_eolInComment($line, $inComment);
|
||||||
}
|
}
|
||||||
return implode($eol, $newLines) . $eol;
|
return implode($eol, $newLines) . $eol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine EOL character sequence
|
* Determine EOL character sequence
|
||||||
*
|
*
|
||||||
* @param string $str file content
|
* @param string $str file content
|
||||||
*
|
*
|
||||||
* @return string EOL char(s) or '' if no EOL could be found
|
* @return string EOL char(s) or '' if no EOL could be found
|
||||||
*/
|
*/
|
||||||
private static function _getEol($str)
|
private static function _getEol($str)
|
||||||
{
|
{
|
||||||
$r = strpos($str, "\r");
|
$r = strpos($str, "\r");
|
||||||
$n = strpos($str, "\n");
|
$n = strpos($str, "\n");
|
||||||
if (false === $r && false === $n) {
|
if (false === $r && false === $n) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return ($r !== false)
|
return ($r !== false)
|
||||||
? ($n == ($r + 1)
|
? ($n == ($r + 1)
|
||||||
? "\r\n"
|
? "\r\n"
|
||||||
: "\r")
|
: "\r")
|
||||||
: "\n";
|
: "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the parser within a C-style comment at the end of this line?
|
* Is the parser within a C-style comment at the end of this line?
|
||||||
*
|
*
|
||||||
* @param string $line current line of code
|
* @param string $line current line of code
|
||||||
*
|
*
|
||||||
* @param bool $inComment was the parser in a comment at the
|
* @param bool $inComment was the parser in a comment at the
|
||||||
* beginning of the line?
|
* beginning of the line?
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private static function _eolInComment($line, $inComment)
|
private static function _eolInComment($line, $inComment)
|
||||||
{
|
{
|
||||||
while (strlen($line)) {
|
while (strlen($line)) {
|
||||||
$search = $inComment
|
$search = $inComment
|
||||||
? '*/'
|
? '*/'
|
||||||
: '/*';
|
: '/*';
|
||||||
$pos = strpos($line, $search);
|
$pos = strpos($line, $search);
|
||||||
if (false === $pos) {
|
if (false === $pos) {
|
||||||
return $inComment;
|
return $inComment;
|
||||||
} else {
|
} else {
|
||||||
$inComment = ! $inComment;
|
$inComment = ! $inComment;
|
||||||
$line = substr($line, $pos + 2);
|
$line = substr($line, $pos + 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $inComment;
|
return $inComment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepend a comment (or note) to the given line
|
* Prepend a comment (or note) to the given line
|
||||||
*
|
*
|
||||||
* @param string $line current line of code
|
* @param string $line current line of code
|
||||||
*
|
*
|
||||||
* @param string $note content of note/comment
|
* @param string $note content of note/comment
|
||||||
*
|
*
|
||||||
* @param bool $inComment was the parser in a comment at the
|
* @param bool $inComment was the parser in a comment at the
|
||||||
* beginning of the line?
|
* beginning of the line?
|
||||||
*
|
*
|
||||||
* @param int $padTo minimum width of comment
|
* @param int $padTo minimum width of comment
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private static function _addNote($line, $note, $inComment, $padTo)
|
private static function _addNote($line, $note, $inComment, $padTo)
|
||||||
{
|
{
|
||||||
return $inComment
|
return $inComment
|
||||||
? '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' *| ' . $line
|
? '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' *| ' . $line
|
||||||
: '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' */ ' . $line;
|
: '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' */ ' . $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,177 +1,177 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_Source
|
* Class Minify_Source
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A content source to be minified by Minify.
|
* A content source to be minified by Minify.
|
||||||
*
|
*
|
||||||
* This allows per-source minification options and the mixing of files with
|
* This allows per-source minification options and the mixing of files with
|
||||||
* content from other sources.
|
* content from other sources.
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_Source {
|
class Minify_Source {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int time of last modification
|
* @var int time of last modification
|
||||||
*/
|
*/
|
||||||
public $lastModified = null;
|
public $lastModified = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var callback minifier function specifically for this source.
|
* @var callback minifier function specifically for this source.
|
||||||
*/
|
*/
|
||||||
public $minifier = null;
|
public $minifier = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array minification options specific to this source.
|
* @var array minification options specific to this source.
|
||||||
*/
|
*/
|
||||||
public $minifyOptions = null;
|
public $minifyOptions = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string full path of file
|
* @var string full path of file
|
||||||
*/
|
*/
|
||||||
public $filepath = null;
|
public $filepath = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Minify_Source
|
* Create a Minify_Source
|
||||||
*
|
*
|
||||||
* In the $spec array(), you can either provide a 'filepath' to an existing
|
* In the $spec array(), you can either provide a 'filepath' to an existing
|
||||||
* file (existence will not be checked!) or give 'id' (unique string for
|
* file (existence will not be checked!) or give 'id' (unique string for
|
||||||
* the content), 'content' (the string content) and 'lastModified'
|
* the content), 'content' (the string content) and 'lastModified'
|
||||||
* (unixtime of last update).
|
* (unixtime of last update).
|
||||||
*
|
*
|
||||||
* As a shortcut, the controller will replace "//" at the beginning
|
* As a shortcut, the controller will replace "//" at the beginning
|
||||||
* of a filepath with $_SERVER['DOCUMENT_ROOT'] . '/'.
|
* of a filepath with $_SERVER['DOCUMENT_ROOT'] . '/'.
|
||||||
*
|
*
|
||||||
* @param array $spec options
|
* @param array $spec options
|
||||||
*/
|
*/
|
||||||
public function __construct($spec)
|
public function __construct($spec)
|
||||||
{
|
{
|
||||||
if (isset($spec['filepath'])) {
|
if (isset($spec['filepath'])) {
|
||||||
if (0 === strpos($spec['filepath'], '//')) {
|
if (0 === strpos($spec['filepath'], '//')) {
|
||||||
$spec['filepath'] = $_SERVER['DOCUMENT_ROOT'] . substr($spec['filepath'], 1);
|
$spec['filepath'] = $_SERVER['DOCUMENT_ROOT'] . substr($spec['filepath'], 1);
|
||||||
}
|
}
|
||||||
$this->filepath = $spec['filepath'];
|
$this->filepath = $spec['filepath'];
|
||||||
$this->_id = $spec['filepath'];
|
$this->_id = $spec['filepath'];
|
||||||
$this->lastModified = filemtime($spec['filepath'])
|
$this->lastModified = filemtime($spec['filepath'])
|
||||||
// offset for Windows uploaders with out of sync clocks
|
// offset for Windows uploaders with out of sync clocks
|
||||||
+ round(Minify::$uploaderHoursBehind * 3600);
|
+ round(Minify::$uploaderHoursBehind * 3600);
|
||||||
} elseif (isset($spec['id'])) {
|
} elseif (isset($spec['id'])) {
|
||||||
$this->_id = 'id::' . $spec['id'];
|
$this->_id = 'id::' . $spec['id'];
|
||||||
if (isset($spec['content'])) {
|
if (isset($spec['content'])) {
|
||||||
$this->_content = $spec['content'];
|
$this->_content = $spec['content'];
|
||||||
} else {
|
} else {
|
||||||
$this->_getContentFunc = $spec['getContentFunc'];
|
$this->_getContentFunc = $spec['getContentFunc'];
|
||||||
}
|
}
|
||||||
$this->lastModified = isset($spec['lastModified'])
|
$this->lastModified = isset($spec['lastModified'])
|
||||||
? $spec['lastModified']
|
? $spec['lastModified']
|
||||||
: time();
|
: time();
|
||||||
}
|
}
|
||||||
if (isset($spec['minifier'])) {
|
if (isset($spec['minifier'])) {
|
||||||
$this->minifier = $spec['minifier'];
|
$this->minifier = $spec['minifier'];
|
||||||
}
|
}
|
||||||
if (isset($spec['minifyOptions'])) {
|
if (isset($spec['minifyOptions'])) {
|
||||||
$this->minifyOptions = $spec['minifyOptions'];
|
$this->minifyOptions = $spec['minifyOptions'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get content
|
* Get content
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getContent()
|
public function getContent()
|
||||||
{
|
{
|
||||||
$content = (null !== $this->filepath)
|
$content = (null !== $this->filepath)
|
||||||
? file_get_contents($this->filepath)
|
? file_get_contents($this->filepath)
|
||||||
: ((null !== $this->_content)
|
: ((null !== $this->_content)
|
||||||
? $this->_content
|
? $this->_content
|
||||||
: call_user_func($this->_getContentFunc, $this->_id)
|
: call_user_func($this->_getContentFunc, $this->_id)
|
||||||
);
|
);
|
||||||
// remove UTF-8 BOM if present
|
// remove UTF-8 BOM if present
|
||||||
return (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3))
|
return (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3))
|
||||||
? substr($content, 3)
|
? substr($content, 3)
|
||||||
: $content;
|
: $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get id
|
* Get id
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getId()
|
public function getId()
|
||||||
{
|
{
|
||||||
return $this->_id;
|
return $this->_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies a single minification call can handle all sources
|
* Verifies a single minification call can handle all sources
|
||||||
*
|
*
|
||||||
* @param array $sources Minify_Source instances
|
* @param array $sources Minify_Source instances
|
||||||
*
|
*
|
||||||
* @return bool true iff there no sources with specific minifier preferences.
|
* @return bool true iff there no sources with specific minifier preferences.
|
||||||
*/
|
*/
|
||||||
public static function haveNoMinifyPrefs($sources)
|
public static function haveNoMinifyPrefs($sources)
|
||||||
{
|
{
|
||||||
foreach ($sources as $source) {
|
foreach ($sources as $source) {
|
||||||
if (null !== $source->minifier
|
if (null !== $source->minifier
|
||||||
|| null !== $source->minifyOptions) {
|
|| null !== $source->minifyOptions) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get unique string for a set of sources
|
* Get unique string for a set of sources
|
||||||
*
|
*
|
||||||
* @param array $sources Minify_Source instances
|
* @param array $sources Minify_Source instances
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function getDigest($sources)
|
public static function getDigest($sources)
|
||||||
{
|
{
|
||||||
foreach ($sources as $source) {
|
foreach ($sources as $source) {
|
||||||
$info[] = array(
|
$info[] = array(
|
||||||
$source->_id, $source->minifier, $source->minifyOptions
|
$source->_id, $source->minifier, $source->minifyOptions
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return md5(serialize($info));
|
return md5(serialize($info));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Guess content type from the first filename extension available
|
* Guess content type from the first filename extension available
|
||||||
*
|
*
|
||||||
* This is called if the user doesn't pass in a 'contentType' options
|
* This is called if the user doesn't pass in a 'contentType' options
|
||||||
*
|
*
|
||||||
* @param array $sources Minify_Source instances
|
* @param array $sources Minify_Source instances
|
||||||
*
|
*
|
||||||
* @return string content type. e.g. 'text/css'
|
* @return string content type. e.g. 'text/css'
|
||||||
*/
|
*/
|
||||||
public static function getContentType($sources)
|
public static function getContentType($sources)
|
||||||
{
|
{
|
||||||
$exts = array(
|
$exts = array(
|
||||||
'css' => Minify::TYPE_CSS
|
'css' => Minify::TYPE_CSS
|
||||||
,'js' => Minify::TYPE_JS
|
,'js' => Minify::TYPE_JS
|
||||||
,'html' => Minify::TYPE_HTML
|
,'html' => Minify::TYPE_HTML
|
||||||
);
|
);
|
||||||
foreach ($sources as $source) {
|
foreach ($sources as $source) {
|
||||||
if (null !== $source->filepath) {
|
if (null !== $source->filepath) {
|
||||||
$segments = explode('.', $source->filepath);
|
$segments = explode('.', $source->filepath);
|
||||||
$ext = array_pop($segments);
|
$ext = array_pop($segments);
|
||||||
if (isset($exts[$ext])) {
|
if (isset($exts[$ext])) {
|
||||||
return $exts[$ext];
|
return $exts[$ext];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'text/plain';
|
return 'text/plain';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $_content = null;
|
protected $_content = null;
|
||||||
protected $_getContentFunc = null;
|
protected $_getContentFunc = null;
|
||||||
protected $_id = null;
|
protected $_id = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,31 +1,31 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Function min_group_uri()
|
* Function min_group_uri()
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once dirname(__FILE__) . '/lib/Minify/Build.php';
|
require_once dirname(__FILE__) . '/lib/Minify/Build.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a timestamped URI to a minified resource using the default Minify install
|
* Get a timestamped URI to a minified resource using the default Minify install
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* <link rel="stylesheet" type="text/css" href="<?php min_group_uri('css'); ?>" />
|
* <link rel="stylesheet" type="text/css" href="<?php min_group_uri('css'); ?>" />
|
||||||
* <script type="text/javascript" src="<?php min_group_uri('js'); ?>"></script>
|
* <script type="text/javascript" src="<?php min_group_uri('js'); ?>"></script>
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* @param string $group a key of the array in groupsConfig.php
|
* @param string $group a key of the array in groupsConfig.php
|
||||||
* @param string $ampersand '&' or '&' (default '&')
|
* @param string $ampersand '&' or '&' (default '&')
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function min_group_uri($group, $ampersand = '&')
|
function min_group_uri($group, $ampersand = '&')
|
||||||
{
|
{
|
||||||
static $gc = false;
|
static $gc = false;
|
||||||
if (false === $gc) {
|
if (false === $gc) {
|
||||||
$gc = (require dirname(__FILE__) . '/groupsConfig.php');
|
$gc = (require dirname(__FILE__) . '/groupsConfig.php');
|
||||||
}
|
}
|
||||||
$b = new Minify_Build($gc[$group]);
|
$b = new Minify_Build($gc[$group]);
|
||||||
Minify_Build::$ampersand = $ampersand;
|
Minify_Build::$ampersand = $ampersand;
|
||||||
return $b->uri('/' . basename(dirname(__FILE__)) . '/?g=' . $group);
|
return $b->uri('/' . basename(dirname(__FILE__)) . '/?g=' . $group);
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,25 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* The goal with this file is to benchmark serving the file doing the absolute
|
* The goal with this file is to benchmark serving the file doing the absolute
|
||||||
* least operations possible. E.g. we know we'll have to check for the file,
|
* least operations possible. E.g. we know we'll have to check for the file,
|
||||||
* check its size and the mtimes of it and the src file.
|
* check its size and the mtimes of it and the src file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$src = realpath(dirname(__FILE__) . '/../minify/before.js');
|
$src = realpath(dirname(__FILE__) . '/../minify/before.js');
|
||||||
$cached = realpath(dirname(__FILE__) . '/../type-map') . '/before.js.zd';
|
$cached = realpath(dirname(__FILE__) . '/../type-map') . '/before.js.zd';
|
||||||
|
|
||||||
// clearstatcache() takes over 2ms on Athlon 64 X2 5600+! Avoid at all costs!
|
// clearstatcache() takes over 2ms on Athlon 64 X2 5600+! Avoid at all costs!
|
||||||
//clearstatcache();
|
//clearstatcache();
|
||||||
|
|
||||||
filemtime($src);
|
filemtime($src);
|
||||||
file_exists($cached);
|
file_exists($cached);
|
||||||
filemtime($cached);
|
filemtime($cached);
|
||||||
|
|
||||||
header('Cache-Control: public, max-age=31536000');
|
header('Cache-Control: public, max-age=31536000');
|
||||||
header('Expires: '. gmdate('D, d M Y H:i:s \G\M\T', $_SERVER['REQUEST_TIME'] + (86400 * 365)));
|
header('Expires: '. gmdate('D, d M Y H:i:s \G\M\T', $_SERVER['REQUEST_TIME'] + (86400 * 365)));
|
||||||
header('Content-Type: application/x-javascript; charset=utf-8');
|
header('Content-Type: application/x-javascript; charset=utf-8');
|
||||||
header('Content-Encoding: deflate');
|
header('Content-Encoding: deflate');
|
||||||
header('Content-Length: ' . filesize($cached));
|
header('Content-Length: ' . filesize($cached));
|
||||||
header('Vary: Accept-Encoding');
|
header('Vary: Accept-Encoding');
|
||||||
|
|
||||||
readfile($cached);
|
readfile($cached);
|
@@ -1,15 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
require '../../config.php';
|
||||||
|
|
||||||
require 'Minify.php';
|
require 'Minify.php';
|
||||||
|
|
||||||
// give an explicit path to avoid having to load Solar/Dir.php
|
// give an explicit path to avoid having to load Solar/Dir.php
|
||||||
Minify::setCache($minifyCachePath);
|
Minify::setCache($minifyCachePath);
|
||||||
|
|
||||||
Minify::serve('Files', array(
|
Minify::serve('Files', array(
|
||||||
'files' => array(
|
'files' => array(
|
||||||
dirname(__FILE__) . '/before.js'
|
dirname(__FILE__) . '/before.js'
|
||||||
)
|
)
|
||||||
,'setExpires' => $_SERVER['REQUEST_TIME'] + 31536000 // 1 yr
|
,'setExpires' => $_SERVER['REQUEST_TIME'] + 31536000 // 1 yr
|
||||||
));
|
));
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
require '../../config.php';
|
||||||
|
|
||||||
require 'Minify.php';
|
require 'Minify.php';
|
||||||
|
|
||||||
// give an explicit path to avoid having to load Solar/Dir.php
|
// give an explicit path to avoid having to load Solar/Dir.php
|
||||||
Minify::setCache($minifyCachePath);
|
Minify::setCache($minifyCachePath);
|
||||||
|
|
||||||
Minify::serve('Groups', array(
|
Minify::serve('Groups', array(
|
||||||
'groups' => array(
|
'groups' => array(
|
||||||
'test' => array(dirname(__FILE__) . '/before.js')
|
'test' => array(dirname(__FILE__) . '/before.js')
|
||||||
)
|
)
|
||||||
,'setExpires' => $_SERVER['REQUEST_TIME'] + 31536000 // 1 yr
|
,'setExpires' => $_SERVER['REQUEST_TIME'] + 31536000 // 1 yr
|
||||||
));
|
));
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
require '../../config.php';
|
||||||
|
|
||||||
define('MINIFY_BASE_DIR', realpath(
|
define('MINIFY_BASE_DIR', realpath(
|
||||||
dirname(__FILE__) . '/../minify'
|
dirname(__FILE__) . '/../minify'
|
||||||
));
|
));
|
||||||
define('MINIFY_CACHE_DIR', $minifyCachePath);
|
define('MINIFY_CACHE_DIR', $minifyCachePath);
|
||||||
|
|
||||||
require 'Minify.php';
|
require 'Minify.php';
|
||||||
|
|
||||||
Minify::serve('Version1');
|
Minify::serve('Version1');
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the location of Minify's "lib" directory to the include_path. In
|
* Add the location of Minify's "lib" directory to the include_path. In
|
||||||
* production this could be done via .htaccess or some other method.
|
* production this could be done via .htaccess or some other method.
|
||||||
*/
|
*/
|
||||||
ini_set('include_path',
|
ini_set('include_path',
|
||||||
dirname(__FILE__) . '/../min/lib'
|
dirname(__FILE__) . '/../min/lib'
|
||||||
. PATH_SEPARATOR . ini_get('include_path')
|
. PATH_SEPARATOR . ini_get('include_path')
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set $minifyCachePath to a PHP-writeable path to enable server-side caching
|
* Set $minifyCachePath to a PHP-writeable path to enable server-side caching
|
||||||
* in all examples and tests.
|
* in all examples and tests.
|
||||||
*/
|
*/
|
||||||
$minifyCachePath = 'C:/xampp/tmp'; // '';
|
$minifyCachePath = 'C:/xampp/tmp'; // '';
|
||||||
|
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$base = realpath(dirname(__FILE__) . '/..');
|
$base = realpath(dirname(__FILE__) . '/..');
|
||||||
$groupsSources = array(
|
$groupsSources = array(
|
||||||
'js' => array(
|
'js' => array(
|
||||||
"{$base}/jquery-1.2.3.js"
|
"{$base}/jquery-1.2.3.js"
|
||||||
,"{$base}/test space.js"
|
,"{$base}/test space.js"
|
||||||
)
|
)
|
||||||
,'css' => array("{$base}/test.css")
|
,'css' => array("{$base}/test.css")
|
||||||
);
|
);
|
||||||
unset($base);
|
unset($base);
|
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
require '../../config.php';
|
||||||
require '_groupsSources.php';
|
require '_groupsSources.php';
|
||||||
require 'Minify.php';
|
require 'Minify.php';
|
||||||
|
|
||||||
if ($minifyCachePath) {
|
if ($minifyCachePath) {
|
||||||
Minify::setCache($minifyCachePath);
|
Minify::setCache($minifyCachePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Minify::serve('Groups', array(
|
Minify::serve('Groups', array(
|
||||||
'groups' => $groupsSources
|
'groups' => $groupsSources
|
||||||
,'setExpires' => time() + 86400 * 365
|
,'setExpires' => time() + 86400 * 365
|
||||||
));
|
));
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$base = realpath(dirname(__FILE__) . '/..');
|
$base = realpath(dirname(__FILE__) . '/..');
|
||||||
$groupsSources = array(
|
$groupsSources = array(
|
||||||
'js' => array(
|
'js' => array(
|
||||||
"{$base}/jquery-1.2.3.js"
|
"{$base}/jquery-1.2.3.js"
|
||||||
,"{$base}/test space.js"
|
,"{$base}/test space.js"
|
||||||
)
|
)
|
||||||
,'css' => array("{$base}/test.css")
|
,'css' => array("{$base}/test.css")
|
||||||
);
|
);
|
||||||
unset($base);
|
unset($base);
|
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
require '../../config.php';
|
||||||
require '_groupsSources.php';
|
require '_groupsSources.php';
|
||||||
require 'Minify.php';
|
require 'Minify.php';
|
||||||
|
|
||||||
if ($minifyCachePath) {
|
if ($minifyCachePath) {
|
||||||
Minify::setCache($minifyCachePath);
|
Minify::setCache($minifyCachePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Minify::serve('Groups', array(
|
Minify::serve('Groups', array(
|
||||||
'groups' => $groupsSources
|
'groups' => $groupsSources
|
||||||
,'setExpires' => time() + 86400 * 365
|
,'setExpires' => time() + 86400 * 365
|
||||||
));
|
));
|
||||||
|
@@ -1,44 +1,44 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This script will serve a single js/css file in this directory. Here we place
|
* This script will serve a single js/css file in this directory. Here we place
|
||||||
* the front-end-controller logic in user code, then use the "Files" controller
|
* the front-end-controller logic in user code, then use the "Files" controller
|
||||||
* to minify the file. Alternately, we could have created a custom controller
|
* to minify the file. Alternately, we could have created a custom controller
|
||||||
* with the same logic and passed it to Minify::handleRequest().
|
* with the same logic and passed it to Minify::handleRequest().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require '../../config.php';
|
require '../../config.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Files controller only "knows" HTML, CSS, and JS files. Other files
|
* The Files controller only "knows" HTML, CSS, and JS files. Other files
|
||||||
* would only be trim()ed and sent as plain/text.
|
* would only be trim()ed and sent as plain/text.
|
||||||
*/
|
*/
|
||||||
$serveExtensions = array('css', 'js');
|
$serveExtensions = array('css', 'js');
|
||||||
|
|
||||||
// serve
|
// serve
|
||||||
if (isset($_GET['f'])) {
|
if (isset($_GET['f'])) {
|
||||||
$filename = basename($_GET['f']); // remove any naughty bits
|
$filename = basename($_GET['f']); // remove any naughty bits
|
||||||
$filenamePattern = '/[^\'"\\/\\\\]+\\.(?:'
|
$filenamePattern = '/[^\'"\\/\\\\]+\\.(?:'
|
||||||
.implode('|', $serveExtensions). ')$/';
|
.implode('|', $serveExtensions). ')$/';
|
||||||
|
|
||||||
if (preg_match($filenamePattern, $filename)
|
if (preg_match($filenamePattern, $filename)
|
||||||
&& file_exists(dirname(__FILE__) . '/../' . $filename)) {
|
&& file_exists(dirname(__FILE__) . '/../' . $filename)) {
|
||||||
|
|
||||||
require 'Minify.php';
|
require 'Minify.php';
|
||||||
|
|
||||||
if ($minifyCachePath) {
|
if ($minifyCachePath) {
|
||||||
Minify::setCache($minifyCachePath);
|
Minify::setCache($minifyCachePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Files controller can serve an array of files, but here we just
|
// The Files controller can serve an array of files, but here we just
|
||||||
// need one.
|
// need one.
|
||||||
Minify::serve('Files', array(
|
Minify::serve('Files', array(
|
||||||
// controller will cast a string to an array for you
|
// controller will cast a string to an array for you
|
||||||
'files' => dirname(__FILE__) . '/../' . $filename
|
'files' => dirname(__FILE__) . '/../' . $filename
|
||||||
));
|
));
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header("HTTP/1.0 404 Not Found");
|
header("HTTP/1.0 404 Not Found");
|
||||||
echo "HTTP/1.0 404 Not Found";
|
echo "HTTP/1.0 404 Not Found";
|
@@ -1,44 +1,44 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
require '../../config.php';
|
||||||
require 'HTTP/ConditionalGet.php';
|
require 'HTTP/ConditionalGet.php';
|
||||||
|
|
||||||
// emulate regularly updating document
|
// emulate regularly updating document
|
||||||
$every = 20;
|
$every = 20;
|
||||||
$lastModified = round(time()/$every)*$every - $every;
|
$lastModified = round(time()/$every)*$every - $every;
|
||||||
|
|
||||||
$cg = new HTTP_ConditionalGet(array(
|
$cg = new HTTP_ConditionalGet(array(
|
||||||
'lastModifiedTime' => $lastModified
|
'lastModifiedTime' => $lastModified
|
||||||
));
|
));
|
||||||
if ($cg->cacheIsValid) {
|
if ($cg->cacheIsValid) {
|
||||||
$cg->sendHeaders();
|
$cg->sendHeaders();
|
||||||
// we're done
|
// we're done
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate content
|
// generate content
|
||||||
$title = 'Last-Modified is known : add Content-Length';
|
$title = 'Last-Modified is known : add Content-Length';
|
||||||
$explain = '
|
$explain = '
|
||||||
<p>Here, like <a href="./">the first example</a>, we know the Last-Modified time,
|
<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
|
but we also want to set the Content-Length to increase cacheability and allow
|
||||||
HTTP persistent connections. Instead of sending headers immediately, we first
|
HTTP persistent connections. Instead of sending headers immediately, we first
|
||||||
generate our content, then use <code>setContentLength(strlen($content))</code>
|
generate our content, then use <code>setContentLength(strlen($content))</code>
|
||||||
to add the header. Then finally call <code>sendHeaders()</code> and send the
|
to add the header. Then finally call <code>sendHeaders()</code> and send the
|
||||||
content.</p>
|
content.</p>
|
||||||
<p><strong>Note:</strong> This is not required if your PHP config buffers all
|
<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
|
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>
|
buffer. PHP will generally set Content-Length for you if it can.</p>
|
||||||
<p>This script emulates a document that changes every ' .$every. ' seconds.
|
<p>This script emulates a document that changes every ' .$every. ' seconds.
|
||||||
<br>This is version: ' . date('r', $lastModified) . '</p>
|
<br>This is version: ' . date('r', $lastModified) . '</p>
|
||||||
';
|
';
|
||||||
|
|
||||||
require '_include.php';
|
require '_include.php';
|
||||||
$content = get_content(array(
|
$content = get_content(array(
|
||||||
'title' => $title
|
'title' => $title
|
||||||
,'explain' => $explain
|
,'explain' => $explain
|
||||||
));
|
));
|
||||||
|
|
||||||
$cg->setContentLength(strlen($content));
|
$cg->setContentLength(strlen($content));
|
||||||
$cg->sendHeaders();
|
$cg->sendHeaders();
|
||||||
send_slowly($content);
|
send_slowly($content);
|
||||||
|
|
||||||
|
@@ -1,27 +1,27 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../../config.php';
|
require '../../config.php';
|
||||||
require 'HTTP/ConditionalGet.php';
|
require 'HTTP/ConditionalGet.php';
|
||||||
|
|
||||||
// far expires
|
// far expires
|
||||||
$cg = new HTTP_ConditionalGet(array(
|
$cg = new HTTP_ConditionalGet(array(
|
||||||
'maxAge' => 20
|
'maxAge' => 20
|
||||||
,'lastModifiedTime' => filemtime(__FILE__)
|
,'lastModifiedTime' => filemtime(__FILE__)
|
||||||
));
|
));
|
||||||
$cg->sendHeaders();
|
$cg->sendHeaders();
|
||||||
|
|
||||||
// generate, send content
|
// generate, send content
|
||||||
$title = 'Last-Modified + Expires';
|
$title = 'Last-Modified + Expires';
|
||||||
$explain = '
|
$explain = '
|
||||||
<p>Here we set a static "lastModifiedTime" and "maxAge" to 20. The browser
|
<p>Here we set a static "lastModifiedTime" and "maxAge" to 20. The browser
|
||||||
will consider this document fresh for 20 seconds, then revalidate its cache. After
|
will consider this document fresh for 20 seconds, then revalidate its cache. After
|
||||||
the 304 response, the cache will be good for another 20 seconds. Unless you force
|
the 304 response, the cache will be good for another 20 seconds. Unless you force
|
||||||
a reload, there will only be 304 responses for this page after the initial download.
|
a reload, there will only be 304 responses for this page after the initial download.
|
||||||
';
|
';
|
||||||
|
|
||||||
require '_include.php';
|
require '_include.php';
|
||||||
echo get_content(array(
|
echo get_content(array(
|
||||||
'title' => $title
|
'title' => $title
|
||||||
,'explain' => $explain
|
,'explain' => $explain
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@@ -1,30 +1,28 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../config.php';
|
require '../config.php';
|
||||||
|
|
||||||
error_reporting(E_ALL | E_STRICT);
|
error_reporting(E_ALL | E_STRICT);
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
header('Content-Type: text/plain');
|
header('Content-Type: text/plain');
|
||||||
|
|
||||||
$thisDir = dirname(__FILE__);
|
$thisDir = dirname(__FILE__);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pTest - PHP Unit Tester
|
* pTest - PHP Unit Tester
|
||||||
* @param mixed $test Condition to test, evaluated as boolean
|
* @param mixed $test Condition to test, evaluated as boolean
|
||||||
* @param string $message Descriptive message to output upon test
|
* @param string $message Descriptive message to output upon test
|
||||||
* @url http://www.sitepoint.com/blogs/2007/08/13/ptest-php-unit-tester-in-9-lines-of-code/
|
* @url http://www.sitepoint.com/blogs/2007/08/13/ptest-php-unit-tester-in-9-lines-of-code/
|
||||||
*/
|
*/
|
||||||
function assertTrue($test, $message)
|
function assertTrue($test, $message)
|
||||||
{
|
{
|
||||||
static $count;
|
static $count;
|
||||||
if (!isset($count)) $count = array('pass'=>0, 'fail'=>0, 'total'=>0);
|
if (!isset($count)) $count = array('pass'=>0, 'fail'=>0, 'total'=>0);
|
||||||
|
|
||||||
$mode = $test ? 'pass' : 'fail';
|
$mode = $test ? 'pass' : 'fail';
|
||||||
$outMode = $test ? 'PASS' : '!FAIL';
|
$outMode = $test ? 'PASS' : '!FAIL';
|
||||||
printf("%s: %s (%d of %d tests run so far have %sed)\n",
|
printf("%s: %s (%d of %d tests run so far have %sed)\n",
|
||||||
$outMode, $message, ++$count[$mode], ++$count['total'], $mode);
|
$outMode, $message, ++$count[$mode], ++$count['total'], $mode);
|
||||||
|
|
||||||
return (bool)$test;
|
return (bool)$test;
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
|
||||||
|
@@ -1,42 +1,42 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once '_inc.php';
|
require_once '_inc.php';
|
||||||
|
|
||||||
require_once 'Minify/CSS.php';
|
require_once 'Minify/CSS.php';
|
||||||
|
|
||||||
function test_CSS()
|
function test_CSS()
|
||||||
{
|
{
|
||||||
global $thisDir;
|
global $thisDir;
|
||||||
|
|
||||||
$cssPath = dirname(__FILE__) . '/_test_files/css';
|
$cssPath = dirname(__FILE__) . '/_test_files/css';
|
||||||
|
|
||||||
// build test file list
|
// build test file list
|
||||||
$d = dir($cssPath);
|
$d = dir($cssPath);
|
||||||
while (false !== ($entry = $d->read())) {
|
while (false !== ($entry = $d->read())) {
|
||||||
if (preg_match('/^([\w\\-]+)\.css$/', $entry, $m)) {
|
if (preg_match('/^([\w\\-]+)\.css$/', $entry, $m)) {
|
||||||
$list[] = $m[1];
|
$list[] = $m[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$d->close();
|
$d->close();
|
||||||
|
|
||||||
foreach ($list as $item) {
|
foreach ($list as $item) {
|
||||||
|
|
||||||
$options = ($item === 'paths')
|
$options = ($item === 'paths')
|
||||||
? array('prependRelativePath' => '../')
|
? array('prependRelativePath' => '../')
|
||||||
: array();
|
: array();
|
||||||
|
|
||||||
$src = file_get_contents($cssPath . "/{$item}.css");
|
$src = file_get_contents($cssPath . "/{$item}.css");
|
||||||
$minExpected = file_get_contents($cssPath . "/{$item}.min.css");
|
$minExpected = file_get_contents($cssPath . "/{$item}.min.css");
|
||||||
$minOutput = Minify_CSS::minify($src, $options);
|
$minOutput = Minify_CSS::minify($src, $options);
|
||||||
$passed = assertTrue($minExpected === $minOutput, 'Minify_CSS : ' . $item);
|
$passed = assertTrue($minExpected === $minOutput, 'Minify_CSS : ' . $item);
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n";
|
echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n";
|
||||||
if (!$passed) {
|
if (!$passed) {
|
||||||
echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n";
|
echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n";
|
||||||
echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n";
|
echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test_CSS();
|
test_CSS();
|
||||||
|
@@ -1,59 +1,59 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once '_inc.php';
|
require_once '_inc.php';
|
||||||
|
|
||||||
require_once 'Minify/HTML.php';
|
require_once 'Minify/HTML.php';
|
||||||
require_once 'Minify/CSS.php';
|
require_once 'Minify/CSS.php';
|
||||||
require_once 'Minify/Javascript.php';
|
require_once 'Minify/Javascript.php';
|
||||||
|
|
||||||
function test_HTML()
|
function test_HTML()
|
||||||
{
|
{
|
||||||
global $thisDir;
|
global $thisDir;
|
||||||
|
|
||||||
$src = file_get_contents($thisDir . '/_test_files/html/before.html');
|
$src = file_get_contents($thisDir . '/_test_files/html/before.html');
|
||||||
$minExpected = file_get_contents($thisDir . '/_test_files/html/before.min.html');
|
$minExpected = file_get_contents($thisDir . '/_test_files/html/before.min.html');
|
||||||
|
|
||||||
$time = microtime(true);
|
$time = microtime(true);
|
||||||
$minOutput = Minify_HTML::minify($src, array(
|
$minOutput = Minify_HTML::minify($src, array(
|
||||||
'cssMinifier' => array('Minify_CSS', 'minify')
|
'cssMinifier' => array('Minify_CSS', 'minify')
|
||||||
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
||||||
));
|
));
|
||||||
$time = microtime(true) - $time;
|
$time = microtime(true) - $time;
|
||||||
|
|
||||||
$passed = assertTrue($minExpected === $minOutput, 'Minify_HTML');
|
$passed = assertTrue($minExpected === $minOutput, 'Minify_HTML');
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
if ($passed) {
|
if ($passed) {
|
||||||
echo "\n---Source: ", strlen($src), " bytes\n"
|
echo "\n---Source: ", strlen($src), " bytes\n"
|
||||||
, "---Output: ", strlen($minOutput), " bytes (", round($time * 1000), " ms)\n\n{$minOutput}\n\n\n";
|
, "---Output: ", strlen($minOutput), " bytes (", round($time * 1000), " ms)\n\n{$minOutput}\n\n\n";
|
||||||
} else {
|
} else {
|
||||||
echo "\n---Output: ", strlen($minOutput), " bytes (", round($time * 1000), " ms)\n\n{$minOutput}\n\n"
|
echo "\n---Output: ", strlen($minOutput), " bytes (", round($time * 1000), " ms)\n\n{$minOutput}\n\n"
|
||||||
, "---Expected: ", strlen($minExpected), " bytes\n\n{$minExpected}\n\n"
|
, "---Expected: ", strlen($minExpected), " bytes\n\n{$minExpected}\n\n"
|
||||||
, "---Source: ", strlen($src), " bytes\n\n{$src}\n\n\n";
|
, "---Source: ", strlen($src), " bytes\n\n{$src}\n\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$src = file_get_contents($thisDir . '/_test_files/html/before2.html');
|
$src = file_get_contents($thisDir . '/_test_files/html/before2.html');
|
||||||
$minExpected = file_get_contents($thisDir . '/_test_files/html/before2.min.html');
|
$minExpected = file_get_contents($thisDir . '/_test_files/html/before2.min.html');
|
||||||
|
|
||||||
$time = microtime(true);
|
$time = microtime(true);
|
||||||
$minOutput = Minify_HTML::minify($src, array(
|
$minOutput = Minify_HTML::minify($src, array(
|
||||||
'cssMinifier' => array('Minify_CSS', 'minify')
|
'cssMinifier' => array('Minify_CSS', 'minify')
|
||||||
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
||||||
));
|
));
|
||||||
$time = microtime(true) - $time;
|
$time = microtime(true) - $time;
|
||||||
|
|
||||||
$passed = assertTrue($minExpected === $minOutput, 'Minify_HTML');
|
$passed = assertTrue($minExpected === $minOutput, 'Minify_HTML');
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
if ($passed) {
|
if ($passed) {
|
||||||
echo "\n---Source: ", strlen($src), " bytes\n"
|
echo "\n---Source: ", strlen($src), " bytes\n"
|
||||||
, "---Output: ", strlen($minOutput), " bytes (", round($time * 1000), " ms)\n\n{$minOutput}\n\n\n";
|
, "---Output: ", strlen($minOutput), " bytes (", round($time * 1000), " ms)\n\n{$minOutput}\n\n\n";
|
||||||
} else {
|
} else {
|
||||||
echo "\n---Output: ", strlen($minOutput), " bytes (", round($time * 1000), " ms)\n\n{$minOutput}\n\n"
|
echo "\n---Output: ", strlen($minOutput), " bytes (", round($time * 1000), " ms)\n\n{$minOutput}\n\n"
|
||||||
, "---Expected: ", strlen($minExpected), " bytes\n\n{$minExpected}\n\n"
|
, "---Expected: ", strlen($minExpected), " bytes\n\n{$minExpected}\n\n"
|
||||||
, "---Source: ", strlen($src), " bytes\n\n{$src}\n\n\n";
|
, "---Source: ", strlen($src), " bytes\n\n{$src}\n\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test_HTML();
|
test_HTML();
|
||||||
|
@@ -1,117 +1,117 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once '_inc.php';
|
require_once '_inc.php';
|
||||||
|
|
||||||
require_once 'HTTP/ConditionalGet.php';
|
require_once 'HTTP/ConditionalGet.php';
|
||||||
|
|
||||||
function test_HTTP_ConditionalGet()
|
function test_HTTP_ConditionalGet()
|
||||||
{
|
{
|
||||||
global $thisDir;
|
global $thisDir;
|
||||||
|
|
||||||
$lmTime = time() - 900;
|
$lmTime = time() - 900;
|
||||||
$gmtTime = gmdate('D, d M Y H:i:s \G\M\T', $lmTime);
|
$gmtTime = gmdate('D, d M Y H:i:s \G\M\T', $lmTime);
|
||||||
|
|
||||||
$tests = array(
|
$tests = array(
|
||||||
array(
|
array(
|
||||||
'desc' => 'client has valid If-Modified-Since'
|
'desc' => 'client has valid If-Modified-Since'
|
||||||
,'inm' => null
|
,'inm' => null
|
||||||
,'ims' => $gmtTime
|
,'ims' => $gmtTime
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Last-Modified' => $gmtTime
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'ETag' => "\"{$lmTime}pri\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
||||||
,'isValid' => true
|
,'isValid' => true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'desc' => 'client has valid If-Modified-Since with trailing semicolon'
|
'desc' => 'client has valid If-Modified-Since with trailing semicolon'
|
||||||
,'inm' => null
|
,'inm' => null
|
||||||
,'ims' => $gmtTime . ';'
|
,'ims' => $gmtTime . ';'
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Last-Modified' => $gmtTime
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'ETag' => "\"{$lmTime}pri\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
||||||
,'isValid' => true
|
,'isValid' => true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'desc' => 'client has valid ETag'
|
'desc' => 'client has valid ETag'
|
||||||
,'inm' => "\"badEtagFoo\", \"{$lmTime}pri\""
|
,'inm' => "\"badEtagFoo\", \"{$lmTime}pri\""
|
||||||
,'ims' => null
|
,'ims' => null
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Last-Modified' => $gmtTime
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'ETag' => "\"{$lmTime}pri\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
,'_responseCode' => 'HTTP/1.0 304 Not Modified'
|
||||||
,'isValid' => true
|
,'isValid' => true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'desc' => 'no conditional get'
|
'desc' => 'no conditional get'
|
||||||
,'inm' => null
|
,'inm' => null
|
||||||
,'ims' => null
|
,'ims' => null
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Last-Modified' => $gmtTime
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'ETag' => "\"{$lmTime}pri\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'isValid' => false
|
,'isValid' => false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'desc' => 'client has invalid ETag'
|
'desc' => 'client has invalid ETag'
|
||||||
,'inm' => '"' . ($lmTime - 300) . 'pri"'
|
,'inm' => '"' . ($lmTime - 300) . 'pri"'
|
||||||
,'ims' => null
|
,'ims' => null
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Last-Modified' => $gmtTime
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'ETag' => "\"{$lmTime}pri\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'isValid' => false
|
,'isValid' => false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'desc' => 'client has invalid If-Modified-Since'
|
'desc' => 'client has invalid If-Modified-Since'
|
||||||
,'inm' => null
|
,'inm' => null
|
||||||
,'ims' => gmdate('D, d M Y H:i:s \G\M\T', $lmTime - 300)
|
,'ims' => gmdate('D, d M Y H:i:s \G\M\T', $lmTime - 300)
|
||||||
,'exp' => array(
|
,'exp' => array(
|
||||||
'Last-Modified' => $gmtTime
|
'Last-Modified' => $gmtTime
|
||||||
,'ETag' => "\"{$lmTime}pri\""
|
,'ETag' => "\"{$lmTime}pri\""
|
||||||
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
,'Cache-Control' => 'max-age=0, private, must-revalidate'
|
||||||
,'isValid' => false
|
,'isValid' => false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($tests as $test) {
|
foreach ($tests as $test) {
|
||||||
// setup env
|
// setup env
|
||||||
if (null === $test['inm']) {
|
if (null === $test['inm']) {
|
||||||
unset($_SERVER['HTTP_IF_NONE_MATCH']);
|
unset($_SERVER['HTTP_IF_NONE_MATCH']);
|
||||||
} else {
|
} else {
|
||||||
$_SERVER['HTTP_IF_NONE_MATCH'] = get_magic_quotes_gpc()
|
$_SERVER['HTTP_IF_NONE_MATCH'] = get_magic_quotes_gpc()
|
||||||
? addslashes($test['inm'])
|
? addslashes($test['inm'])
|
||||||
: $test['inm'];;
|
: $test['inm'];;
|
||||||
}
|
}
|
||||||
if (null === $test['ims']) {
|
if (null === $test['ims']) {
|
||||||
unset($_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
unset($_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
||||||
} else {
|
} else {
|
||||||
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = $test['ims'];
|
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = $test['ims'];
|
||||||
}
|
}
|
||||||
$exp = $test['exp'];
|
$exp = $test['exp'];
|
||||||
|
|
||||||
$cg = new HTTP_ConditionalGet(array(
|
$cg = new HTTP_ConditionalGet(array(
|
||||||
'lastModifiedTime' => $lmTime
|
'lastModifiedTime' => $lmTime
|
||||||
));
|
));
|
||||||
$ret = $cg->getHeaders();
|
$ret = $cg->getHeaders();
|
||||||
$ret['isValid'] = $cg->cacheIsValid;
|
$ret['isValid'] = $cg->cacheIsValid;
|
||||||
|
|
||||||
$passed = assertTrue($exp == $ret, 'HTTP_ConditionalGet : ' . $test['desc']);
|
$passed = assertTrue($exp == $ret, 'HTTP_ConditionalGet : ' . $test['desc']);
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\n--- INM = {$test['inm']} / IMS = {$test['ims']}\n";
|
echo "\n--- INM = {$test['inm']} / IMS = {$test['ims']}\n";
|
||||||
echo "Expected = " . preg_replace('/\\s+/', ' ', var_export($exp, 1)) . "\n";
|
echo "Expected = " . preg_replace('/\\s+/', ' ', var_export($exp, 1)) . "\n";
|
||||||
echo "Returned = " . preg_replace('/\\s+/', ' ', var_export($ret, 1)) . "\n\n";
|
echo "Returned = " . preg_replace('/\\s+/', ' ', var_export($ret, 1)) . "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test_HTTP_ConditionalGet();
|
test_HTTP_ConditionalGet();
|
@@ -1,224 +1,224 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once '_inc.php';
|
require_once '_inc.php';
|
||||||
|
|
||||||
require_once 'HTTP/Encoder.php';
|
require_once 'HTTP/Encoder.php';
|
||||||
|
|
||||||
function test_HTTP_Encoder()
|
function test_HTTP_Encoder()
|
||||||
{
|
{
|
||||||
global $thisDir;
|
global $thisDir;
|
||||||
|
|
||||||
$methodTests = array(
|
$methodTests = array(
|
||||||
array(
|
array(
|
||||||
'ua' => 'Any browser'
|
'ua' => 'Any browser'
|
||||||
,'ae' => 'compress, x-gzip'
|
,'ae' => 'compress, x-gzip'
|
||||||
,'exp' => array('gzip', 'x-gzip')
|
,'exp' => array('gzip', 'x-gzip')
|
||||||
,'desc' => 'recognize "x-gzip" as gzip'
|
,'desc' => 'recognize "x-gzip" as gzip'
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'ua' => 'Any browser'
|
'ua' => 'Any browser'
|
||||||
,'ae' => 'compress, x-gzip;q=0.5'
|
,'ae' => 'compress, x-gzip;q=0.5'
|
||||||
,'exp' => array('gzip', 'x-gzip')
|
,'exp' => array('gzip', 'x-gzip')
|
||||||
,'desc' => 'gzip w/ non-zero q'
|
,'desc' => 'gzip w/ non-zero q'
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'ua' => 'Any browser'
|
'ua' => 'Any browser'
|
||||||
,'ae' => 'compress, x-gzip;q=0'
|
,'ae' => 'compress, x-gzip;q=0'
|
||||||
,'exp' => array('compress', 'compress')
|
,'exp' => array('compress', 'compress')
|
||||||
,'desc' => 'gzip w/ zero q'
|
,'desc' => 'gzip w/ zero q'
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'ua' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'
|
'ua' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'
|
||||||
,'ae' => 'gzip, deflate'
|
,'ae' => 'gzip, deflate'
|
||||||
,'exp' => array('', '')
|
,'exp' => array('', '')
|
||||||
,'desc' => 'IE6 w/o "enhanced security"'
|
,'desc' => 'IE6 w/o "enhanced security"'
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'ua' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)'
|
'ua' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)'
|
||||||
,'ae' => 'gzip, deflate'
|
,'ae' => 'gzip, deflate'
|
||||||
,'exp' => array('deflate', 'deflate')
|
,'exp' => array('deflate', 'deflate')
|
||||||
,'desc' => 'IE6 w/ "enhanced security"'
|
,'desc' => 'IE6 w/ "enhanced security"'
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'ua' => 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.01)'
|
'ua' => 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.01)'
|
||||||
,'ae' => 'gzip, deflate'
|
,'ae' => 'gzip, deflate'
|
||||||
,'exp' => array('', '')
|
,'exp' => array('', '')
|
||||||
,'desc' => 'IE5.5'
|
,'desc' => 'IE5.5'
|
||||||
)
|
)
|
||||||
,array(
|
,array(
|
||||||
'ua' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.25'
|
'ua' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.25'
|
||||||
,'ae' => 'gzip,deflate'
|
,'ae' => 'gzip,deflate'
|
||||||
,'exp' => array('deflate', 'deflate')
|
,'exp' => array('deflate', 'deflate')
|
||||||
,'desc' => 'Opera identifying as IE6'
|
,'desc' => 'Opera identifying as IE6'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($methodTests as $test) {
|
foreach ($methodTests as $test) {
|
||||||
$_SERVER['HTTP_USER_AGENT'] = $test['ua'];
|
$_SERVER['HTTP_USER_AGENT'] = $test['ua'];
|
||||||
$_SERVER['HTTP_ACCEPT_ENCODING'] = $test['ae'];
|
$_SERVER['HTTP_ACCEPT_ENCODING'] = $test['ae'];
|
||||||
$exp = $test['exp'];
|
$exp = $test['exp'];
|
||||||
$ret = HTTP_Encoder::getAcceptedEncoding();
|
$ret = HTTP_Encoder::getAcceptedEncoding();
|
||||||
$passed = assertTrue($exp == $ret, 'HTTP_Encoder : ' . $test['desc']);
|
$passed = assertTrue($exp == $ret, 'HTTP_Encoder : ' . $test['desc']);
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\n--- AE | UA = {$test['ae']} | {$test['ua']}\n";
|
echo "\n--- AE | UA = {$test['ae']} | {$test['ua']}\n";
|
||||||
echo "Expected = " . preg_replace('/\\s+/', ' ', var_export($exp, 1)) . "\n";
|
echo "Expected = " . preg_replace('/\\s+/', ' ', var_export($exp, 1)) . "\n";
|
||||||
echo "Returned = " . preg_replace('/\\s+/', ' ', var_export($ret, 1)) . "\n\n";
|
echo "Returned = " . preg_replace('/\\s+/', ' ', var_export($ret, 1)) . "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$variedContent = file_get_contents($thisDir . '/_test_files/html/before.html')
|
$variedContent = file_get_contents($thisDir . '/_test_files/html/before.html')
|
||||||
. file_get_contents($thisDir . '/_test_files/css/subsilver.css')
|
. file_get_contents($thisDir . '/_test_files/css/subsilver.css')
|
||||||
. file_get_contents($thisDir . '/../examples/jquery-1.2.3.js');
|
. file_get_contents($thisDir . '/../examples/jquery-1.2.3.js');
|
||||||
$variedLength = strlen($variedContent);
|
$variedLength = strlen($variedContent);
|
||||||
|
|
||||||
$encodingTests = array(
|
$encodingTests = array(
|
||||||
array('method' => 'deflate', 'inv' => 'gzinflate', 'exp' => 32157)
|
array('method' => 'deflate', 'inv' => 'gzinflate', 'exp' => 32157)
|
||||||
,array('method' => 'gzip', 'inv' => '_gzdecode', 'exp' => 32175)
|
,array('method' => 'gzip', 'inv' => '_gzdecode', 'exp' => 32175)
|
||||||
,array('method' => 'compress', 'inv' => 'gzuncompress', 'exp' => 32211)
|
,array('method' => 'compress', 'inv' => 'gzuncompress', 'exp' => 32211)
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($encodingTests as $test) {
|
foreach ($encodingTests as $test) {
|
||||||
$e = new HTTP_Encoder(array(
|
$e = new HTTP_Encoder(array(
|
||||||
'content' => $variedContent
|
'content' => $variedContent
|
||||||
,'method' => $test['method']
|
,'method' => $test['method']
|
||||||
));
|
));
|
||||||
$e->encode(9);
|
$e->encode(9);
|
||||||
$ret = strlen($e->getContent());
|
$ret = strlen($e->getContent());
|
||||||
|
|
||||||
// test uncompression
|
// test uncompression
|
||||||
$roundTrip = @call_user_func($test['inv'], $e->getContent());
|
$roundTrip = @call_user_func($test['inv'], $e->getContent());
|
||||||
$desc = "HTTP_Encoder : {$test['method']} : uncompress possible";
|
$desc = "HTTP_Encoder : {$test['method']} : uncompress possible";
|
||||||
$passed = assertTrue($variedContent == $roundTrip, $desc);
|
$passed = assertTrue($variedContent == $roundTrip, $desc);
|
||||||
|
|
||||||
// test expected compressed size
|
// test expected compressed size
|
||||||
$desc = "HTTP_Encoder : {$test['method']} : compressed to "
|
$desc = "HTTP_Encoder : {$test['method']} : compressed to "
|
||||||
. sprintf('%4.2f%% of original', $ret/$variedLength*100);
|
. sprintf('%4.2f%% of original', $ret/$variedLength*100);
|
||||||
$passed = assertTrue(abs($ret - $test['exp']) < 100, $desc);
|
$passed = assertTrue(abs($ret - $test['exp']) < 100, $desc);
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\n--- {$test['method']}: expected bytes: "
|
echo "\n--- {$test['method']}: expected bytes: "
|
||||||
, "{$test['exp']}. Returned: {$ret} "
|
, "{$test['exp']}. Returned: {$ret} "
|
||||||
, "(off by ". abs($ret - $test['exp']) . " bytes)\n\n";
|
, "(off by ". abs($ret - $test['exp']) . " bytes)\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test_HTTP_Encoder();
|
test_HTTP_Encoder();
|
||||||
|
|
||||||
function _gzdecode($data)
|
function _gzdecode($data)
|
||||||
{
|
{
|
||||||
$filename = $error = '';
|
$filename = $error = '';
|
||||||
return _phpman_gzdecode($data, $filename, $error);
|
return _phpman_gzdecode($data, $filename, $error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://www.php.net/manual/en/function.gzdecode.php#82930
|
// http://www.php.net/manual/en/function.gzdecode.php#82930
|
||||||
function _phpman_gzdecode($data, &$filename='', &$error='', $maxlength=null)
|
function _phpman_gzdecode($data, &$filename='', &$error='', $maxlength=null)
|
||||||
{
|
{
|
||||||
$len = strlen($data);
|
$len = strlen($data);
|
||||||
if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) {
|
if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) {
|
||||||
$error = "Not in GZIP format.";
|
$error = "Not in GZIP format.";
|
||||||
return null; // Not GZIP format (See RFC 1952)
|
return null; // Not GZIP format (See RFC 1952)
|
||||||
}
|
}
|
||||||
$method = ord(substr($data,2,1)); // Compression method
|
$method = ord(substr($data,2,1)); // Compression method
|
||||||
$flags = ord(substr($data,3,1)); // Flags
|
$flags = ord(substr($data,3,1)); // Flags
|
||||||
if ($flags & 31 != $flags) {
|
if ($flags & 31 != $flags) {
|
||||||
$error = "Reserved bits not allowed.";
|
$error = "Reserved bits not allowed.";
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// NOTE: $mtime may be negative (PHP integer limitations)
|
// NOTE: $mtime may be negative (PHP integer limitations)
|
||||||
$mtime = unpack("V", substr($data,4,4));
|
$mtime = unpack("V", substr($data,4,4));
|
||||||
$mtime = $mtime[1];
|
$mtime = $mtime[1];
|
||||||
$xfl = substr($data,8,1);
|
$xfl = substr($data,8,1);
|
||||||
$os = substr($data,8,1);
|
$os = substr($data,8,1);
|
||||||
$headerlen = 10;
|
$headerlen = 10;
|
||||||
$extralen = 0;
|
$extralen = 0;
|
||||||
$extra = "";
|
$extra = "";
|
||||||
if ($flags & 4) {
|
if ($flags & 4) {
|
||||||
// 2-byte length prefixed EXTRA data in header
|
// 2-byte length prefixed EXTRA data in header
|
||||||
if ($len - $headerlen - 2 < 8) {
|
if ($len - $headerlen - 2 < 8) {
|
||||||
return false; // invalid
|
return false; // invalid
|
||||||
}
|
}
|
||||||
$extralen = unpack("v",substr($data,8,2));
|
$extralen = unpack("v",substr($data,8,2));
|
||||||
$extralen = $extralen[1];
|
$extralen = $extralen[1];
|
||||||
if ($len - $headerlen - 2 - $extralen < 8) {
|
if ($len - $headerlen - 2 - $extralen < 8) {
|
||||||
return false; // invalid
|
return false; // invalid
|
||||||
}
|
}
|
||||||
$extra = substr($data,10,$extralen);
|
$extra = substr($data,10,$extralen);
|
||||||
$headerlen += 2 + $extralen;
|
$headerlen += 2 + $extralen;
|
||||||
}
|
}
|
||||||
$filenamelen = 0;
|
$filenamelen = 0;
|
||||||
$filename = "";
|
$filename = "";
|
||||||
if ($flags & 8) {
|
if ($flags & 8) {
|
||||||
// C-style string
|
// C-style string
|
||||||
if ($len - $headerlen - 1 < 8) {
|
if ($len - $headerlen - 1 < 8) {
|
||||||
return false; // invalid
|
return false; // invalid
|
||||||
}
|
}
|
||||||
$filenamelen = strpos(substr($data,$headerlen),chr(0));
|
$filenamelen = strpos(substr($data,$headerlen),chr(0));
|
||||||
if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
|
if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
|
||||||
return false; // invalid
|
return false; // invalid
|
||||||
}
|
}
|
||||||
$filename = substr($data,$headerlen,$filenamelen);
|
$filename = substr($data,$headerlen,$filenamelen);
|
||||||
$headerlen += $filenamelen + 1;
|
$headerlen += $filenamelen + 1;
|
||||||
}
|
}
|
||||||
$commentlen = 0;
|
$commentlen = 0;
|
||||||
$comment = "";
|
$comment = "";
|
||||||
if ($flags & 16) {
|
if ($flags & 16) {
|
||||||
// C-style string COMMENT data in header
|
// C-style string COMMENT data in header
|
||||||
if ($len - $headerlen - 1 < 8) {
|
if ($len - $headerlen - 1 < 8) {
|
||||||
return false; // invalid
|
return false; // invalid
|
||||||
}
|
}
|
||||||
$commentlen = strpos(substr($data,$headerlen),chr(0));
|
$commentlen = strpos(substr($data,$headerlen),chr(0));
|
||||||
if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
|
if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
|
||||||
return false; // Invalid header format
|
return false; // Invalid header format
|
||||||
}
|
}
|
||||||
$comment = substr($data,$headerlen,$commentlen);
|
$comment = substr($data,$headerlen,$commentlen);
|
||||||
$headerlen += $commentlen + 1;
|
$headerlen += $commentlen + 1;
|
||||||
}
|
}
|
||||||
$headercrc = "";
|
$headercrc = "";
|
||||||
if ($flags & 2) {
|
if ($flags & 2) {
|
||||||
// 2-bytes (lowest order) of CRC32 on header present
|
// 2-bytes (lowest order) of CRC32 on header present
|
||||||
if ($len - $headerlen - 2 < 8) {
|
if ($len - $headerlen - 2 < 8) {
|
||||||
return false; // invalid
|
return false; // invalid
|
||||||
}
|
}
|
||||||
$calccrc = crc32(substr($data,0,$headerlen)) & 0xffff;
|
$calccrc = crc32(substr($data,0,$headerlen)) & 0xffff;
|
||||||
$headercrc = unpack("v", substr($data,$headerlen,2));
|
$headercrc = unpack("v", substr($data,$headerlen,2));
|
||||||
$headercrc = $headercrc[1];
|
$headercrc = $headercrc[1];
|
||||||
if ($headercrc != $calccrc) {
|
if ($headercrc != $calccrc) {
|
||||||
$error = "Header checksum failed.";
|
$error = "Header checksum failed.";
|
||||||
return false; // Bad header CRC
|
return false; // Bad header CRC
|
||||||
}
|
}
|
||||||
$headerlen += 2;
|
$headerlen += 2;
|
||||||
}
|
}
|
||||||
// GZIP FOOTER
|
// GZIP FOOTER
|
||||||
$datacrc = unpack("V",substr($data,-8,4));
|
$datacrc = unpack("V",substr($data,-8,4));
|
||||||
$datacrc = sprintf('%u',$datacrc[1] & 0xFFFFFFFF);
|
$datacrc = sprintf('%u',$datacrc[1] & 0xFFFFFFFF);
|
||||||
$isize = unpack("V",substr($data,-4));
|
$isize = unpack("V",substr($data,-4));
|
||||||
$isize = $isize[1];
|
$isize = $isize[1];
|
||||||
// decompression:
|
// decompression:
|
||||||
$bodylen = $len-$headerlen-8;
|
$bodylen = $len-$headerlen-8;
|
||||||
if ($bodylen < 1) {
|
if ($bodylen < 1) {
|
||||||
// IMPLEMENTATION BUG!
|
// IMPLEMENTATION BUG!
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$body = substr($data,$headerlen,$bodylen);
|
$body = substr($data,$headerlen,$bodylen);
|
||||||
$data = "";
|
$data = "";
|
||||||
if ($bodylen > 0) {
|
if ($bodylen > 0) {
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
case 8:
|
case 8:
|
||||||
// Currently the only supported compression method:
|
// Currently the only supported compression method:
|
||||||
$data = gzinflate($body,$maxlength);
|
$data = gzinflate($body,$maxlength);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$error = "Unknown compression method.";
|
$error = "Unknown compression method.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} // zero-byte body content is allowed
|
} // zero-byte body content is allowed
|
||||||
// Verifiy CRC32
|
// Verifiy CRC32
|
||||||
$crc = sprintf("%u",crc32($data));
|
$crc = sprintf("%u",crc32($data));
|
||||||
$crcOK = $crc == $datacrc;
|
$crcOK = $crc == $datacrc;
|
||||||
$lenOK = $isize == strlen($data);
|
$lenOK = $isize == strlen($data);
|
||||||
if (!$lenOK || !$crcOK) {
|
if (!$lenOK || !$crcOK) {
|
||||||
$error = ( $lenOK ? '' : 'Length check FAILED. ') . ( $crcOK ? '' : 'Checksum FAILED.');
|
$error = ( $lenOK ? '' : 'Length check FAILED. ') . ( $crcOK ? '' : 'Checksum FAILED.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
@@ -1,37 +1,37 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once '_inc.php';
|
require_once '_inc.php';
|
||||||
|
|
||||||
require_once 'Minify/Javascript.php';
|
require_once 'Minify/Javascript.php';
|
||||||
|
|
||||||
function test_Javascript()
|
function test_Javascript()
|
||||||
{
|
{
|
||||||
global $thisDir;
|
global $thisDir;
|
||||||
|
|
||||||
$src = file_get_contents($thisDir . '/_test_files/js/before.js');
|
$src = file_get_contents($thisDir . '/_test_files/js/before.js');
|
||||||
$minExpected = file_get_contents($thisDir . '/_test_files/js/before.min.js');
|
$minExpected = file_get_contents($thisDir . '/_test_files/js/before.min.js');
|
||||||
$minOutput = Minify_Javascript::minify($src);
|
$minOutput = Minify_Javascript::minify($src);
|
||||||
|
|
||||||
$passed = assertTrue($minExpected == $minOutput, 'Minify_Javascript');
|
$passed = assertTrue($minExpected == $minOutput, 'Minify_Javascript');
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n";
|
echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n";
|
||||||
echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n";
|
echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n";
|
||||||
echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n";
|
echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//$src = file_get_contents($thisDir . '/_test_files/js/before.js');
|
//$src = file_get_contents($thisDir . '/_test_files/js/before.js');
|
||||||
$minExpected = file_get_contents($thisDir . '/_test_files/js/before_noComments.min.js');
|
$minExpected = file_get_contents($thisDir . '/_test_files/js/before_noComments.min.js');
|
||||||
$minOutput = Minify_Javascript::minify($src, array(
|
$minOutput = Minify_Javascript::minify($src, array(
|
||||||
'preserveComments' => false
|
'preserveComments' => false
|
||||||
));
|
));
|
||||||
|
|
||||||
$passed = assertTrue($minExpected == $minOutput, 'Minify_Javascript');
|
$passed = assertTrue($minExpected == $minOutput, 'Minify_Javascript');
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n";
|
echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n";
|
||||||
echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n";
|
echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n";
|
||||||
echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n";
|
echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test_Javascript();
|
test_Javascript();
|
||||||
|
@@ -1,33 +1,33 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once '_inc.php';
|
require_once '_inc.php';
|
||||||
require_once 'Minify.php';
|
require_once 'Minify.php';
|
||||||
|
|
||||||
function test_Lines()
|
function test_Lines()
|
||||||
{
|
{
|
||||||
global $thisDir;
|
global $thisDir;
|
||||||
|
|
||||||
$exp = file_get_contents("{$thisDir}/_test_files/minify/lines_output.js");
|
$exp = file_get_contents("{$thisDir}/_test_files/minify/lines_output.js");
|
||||||
|
|
||||||
$ret = Minify::serve('Files', array(
|
$ret = Minify::serve('Files', array(
|
||||||
'debug' => true
|
'debug' => true
|
||||||
,'quiet' => true
|
,'quiet' => true
|
||||||
,'encodeOutput' => false
|
,'encodeOutput' => false
|
||||||
,'files' => array(
|
,'files' => array(
|
||||||
"{$thisDir}/_test_files/minify/email.js"
|
"{$thisDir}/_test_files/minify/email.js"
|
||||||
,"{$thisDir}/_test_files/minify/QueryString.js"
|
,"{$thisDir}/_test_files/minify/QueryString.js"
|
||||||
,"{$thisDir}/_test_files/js/before.js"
|
,"{$thisDir}/_test_files/js/before.js"
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
$passed = assertTrue($exp === $ret['content'], 'Minify_Lines');
|
$passed = assertTrue($exp === $ret['content'], 'Minify_Lines');
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\n---Output: " .strlen($ret['content']). " bytes\n\n{$ret['content']}\n\n";
|
echo "\n---Output: " .strlen($ret['content']). " bytes\n\n{$ret['content']}\n\n";
|
||||||
if (!$passed) {
|
if (!$passed) {
|
||||||
echo "---Expected: " .strlen($exp). " bytes\n\n{$exp}\n\n\n";
|
echo "---Expected: " .strlen($exp). " bytes\n\n{$exp}\n\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test_Lines();
|
test_Lines();
|
@@ -1,101 +1,101 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// currently these only test serve() when passed the 'quiet' options
|
// currently these only test serve() when passed the 'quiet' options
|
||||||
|
|
||||||
require_once '_inc.php';
|
require_once '_inc.php';
|
||||||
require_once 'Minify.php';
|
require_once 'Minify.php';
|
||||||
|
|
||||||
function test_Minify()
|
function test_Minify()
|
||||||
{
|
{
|
||||||
global $thisDir;
|
global $thisDir;
|
||||||
|
|
||||||
$minifyTestPath = dirname(__FILE__) . '/_test_files/minify';
|
$minifyTestPath = dirname(__FILE__) . '/_test_files/minify';
|
||||||
$tomorrow = $_SERVER['REQUEST_TIME'] + 86400;
|
$tomorrow = $_SERVER['REQUEST_TIME'] + 86400;
|
||||||
$lastModified = $_SERVER['REQUEST_TIME'] - 86400;
|
$lastModified = $_SERVER['REQUEST_TIME'] - 86400;
|
||||||
|
|
||||||
// Test 304 response
|
// Test 304 response
|
||||||
|
|
||||||
// simulate conditional headers
|
// simulate conditional headers
|
||||||
$_SERVER['HTTP_IF_NONE_MATCH'] = "\"{$lastModified}pub\"";
|
$_SERVER['HTTP_IF_NONE_MATCH'] = "\"{$lastModified}pub\"";
|
||||||
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = gmdate('D, d M Y H:i:s \G\M\T', $lastModified);
|
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = gmdate('D, d M Y H:i:s \G\M\T', $lastModified);
|
||||||
|
|
||||||
$expected = array (
|
$expected = array (
|
||||||
'success' => true
|
'success' => true
|
||||||
,'statusCode' => 304
|
,'statusCode' => 304
|
||||||
,'content' => '',
|
,'content' => '',
|
||||||
'headers' => array(
|
'headers' => array(
|
||||||
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $_SERVER['REQUEST_TIME'] + 1800),
|
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $_SERVER['REQUEST_TIME'] + 1800),
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"{$lastModified}pub\"",
|
'ETag' => "\"{$lastModified}pub\"",
|
||||||
'Cache-Control' => 'max-age=1800, public, must-revalidate',
|
'Cache-Control' => 'max-age=1800, public, must-revalidate',
|
||||||
'_responseCode' => 'HTTP/1.0 304 Not Modified',
|
'_responseCode' => 'HTTP/1.0 304 Not Modified',
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$output = Minify::serve('Files', array(
|
$output = Minify::serve('Files', array(
|
||||||
'files' => $thisDir . '/_test_files/css/styles.css' // controller casts to array
|
'files' => $thisDir . '/_test_files/css/styles.css' // controller casts to array
|
||||||
,'quiet' => true
|
,'quiet' => true
|
||||||
,'lastModifiedTime' => $lastModified
|
,'lastModifiedTime' => $lastModified
|
||||||
,'encodeOutput' => false
|
,'encodeOutput' => false
|
||||||
));
|
));
|
||||||
$passed = assertTrue($expected === $output, 'Minify : 304 response');
|
$passed = assertTrue($expected === $output, 'Minify : 304 response');
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\nOutput: " .var_export($output, 1). "\n\n";
|
echo "\nOutput: " .var_export($output, 1). "\n\n";
|
||||||
if (! $passed) {
|
if (! $passed) {
|
||||||
echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n";
|
echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
//! class_exists('Cache_Lite_File', false)
|
//! class_exists('Cache_Lite_File', false)
|
||||||
! class_exists('HTTP_Encoder', false)
|
! class_exists('HTTP_Encoder', false)
|
||||||
&& ! class_exists('Minify_CSS', false)
|
&& ! class_exists('Minify_CSS', false)
|
||||||
&& ! class_exists('Minify_Cache', false)
|
&& ! class_exists('Minify_Cache', false)
|
||||||
,'Encoder.php, CSS.php, Cache.php not loaded'
|
,'Encoder.php, CSS.php, Cache.php not loaded'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test minifying JS and serving with Expires header
|
// Test minifying JS and serving with Expires header
|
||||||
|
|
||||||
$content = preg_replace('/\\r\\n?/', "\n", file_get_contents($minifyTestPath . '/minified.js'));
|
$content = preg_replace('/\\r\\n?/', "\n", file_get_contents($minifyTestPath . '/minified.js'));
|
||||||
$lastModified = filemtime($minifyTestPath . '/minified.js');
|
$lastModified = filemtime($minifyTestPath . '/minified.js');
|
||||||
$expected = array(
|
$expected = array(
|
||||||
'success' => true
|
'success' => true
|
||||||
,'statusCode' => 200
|
,'statusCode' => 200
|
||||||
// Minify_Javascript always converts to \n line endings
|
// Minify_Javascript always converts to \n line endings
|
||||||
,'content' => $content
|
,'content' => $content
|
||||||
,'headers' => array (
|
,'headers' => array (
|
||||||
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $tomorrow),
|
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $tomorrow),
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"{$lastModified}pub\"",
|
'ETag' => "\"{$lastModified}pub\"",
|
||||||
'Cache-Control' => 'max-age=86400, public, must-revalidate',
|
'Cache-Control' => 'max-age=86400, public, must-revalidate',
|
||||||
'Content-Length' => strlen($content),
|
'Content-Length' => strlen($content),
|
||||||
'Content-Type' => 'application/x-javascript; charset=UTF-8',
|
'Content-Type' => 'application/x-javascript; charset=UTF-8',
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$output = Minify::serve('Files', array(
|
$output = Minify::serve('Files', array(
|
||||||
'files' => array(
|
'files' => array(
|
||||||
$minifyTestPath . '/email.js'
|
$minifyTestPath . '/email.js'
|
||||||
,$minifyTestPath . '/QueryString.js'
|
,$minifyTestPath . '/QueryString.js'
|
||||||
)
|
)
|
||||||
,'quiet' => true
|
,'quiet' => true
|
||||||
,'maxAge' => 86400
|
,'maxAge' => 86400
|
||||||
,'encodeOutput' => false
|
,'encodeOutput' => false
|
||||||
));
|
));
|
||||||
$passed = assertTrue($expected === $output, 'Minify : JS and Expires');
|
$passed = assertTrue($expected === $output, 'Minify : JS and Expires');
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\nOutput: " .var_export($output, 1). "\n\n";
|
echo "\nOutput: " .var_export($output, 1). "\n\n";
|
||||||
if (! $passed) {
|
if (! $passed) {
|
||||||
echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n";
|
echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test minifying CSS and responding with Etag/Last-Modified
|
// Test minifying CSS and responding with Etag/Last-Modified
|
||||||
|
|
||||||
// needed to expose E_STRICT warning in Cache_Lite_File
|
// needed to expose E_STRICT warning in Cache_Lite_File
|
||||||
Minify::setCache();
|
Minify::setCache();
|
||||||
|
|
||||||
// don't allow conditional headers
|
// don't allow conditional headers
|
||||||
unset($_SERVER['HTTP_IF_NONE_MATCH'], $_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
unset($_SERVER['HTTP_IF_NONE_MATCH'], $_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
||||||
|
|
||||||
$pathToWebTest = str_replace(
|
$pathToWebTest = str_replace(
|
||||||
DIRECTORY_SEPARATOR
|
DIRECTORY_SEPARATOR
|
||||||
@@ -107,37 +107,37 @@ function test_Minify()
|
|||||||
,$pathToWebTest
|
,$pathToWebTest
|
||||||
,file_get_contents($minifyTestPath . '/minified.css')
|
,file_get_contents($minifyTestPath . '/minified.css')
|
||||||
);
|
);
|
||||||
|
|
||||||
$expected = array(
|
$expected = array(
|
||||||
'success' => true
|
'success' => true
|
||||||
,'statusCode' => 200
|
,'statusCode' => 200
|
||||||
,'content' => $expectedContent
|
,'content' => $expectedContent
|
||||||
,'headers' => array (
|
,'headers' => array (
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"{$lastModified}pub\"",
|
'ETag' => "\"{$lastModified}pub\"",
|
||||||
'Cache-Control' => 'max-age=0, public, must-revalidate',
|
'Cache-Control' => 'max-age=0, public, must-revalidate',
|
||||||
'Content-Length' => strlen($expectedContent),
|
'Content-Length' => strlen($expectedContent),
|
||||||
'Content-Type' => 'text/css; charset=UTF-8',
|
'Content-Type' => 'text/css; charset=UTF-8',
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$output = Minify::serve('Files', array(
|
$output = Minify::serve('Files', array(
|
||||||
'files' => array(
|
'files' => array(
|
||||||
$thisDir . '/_test_files/css/styles.css'
|
$thisDir . '/_test_files/css/styles.css'
|
||||||
,$thisDir . '/_test_files/css/subsilver.css'
|
,$thisDir . '/_test_files/css/subsilver.css'
|
||||||
)
|
)
|
||||||
,'quiet' => true
|
,'quiet' => true
|
||||||
,'lastModifiedTime' => $lastModified
|
,'lastModifiedTime' => $lastModified
|
||||||
,'encodeOutput' => false
|
,'encodeOutput' => false
|
||||||
,'maxAge' => false
|
,'maxAge' => false
|
||||||
));
|
));
|
||||||
|
|
||||||
$passed = assertTrue($expected === $output, 'Minify : CSS and Etag/Last-Modified');
|
$passed = assertTrue($expected === $output, 'Minify : CSS and Etag/Last-Modified');
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
echo "\nOutput: " .var_export($output, 1). "\n\n";
|
echo "\nOutput: " .var_export($output, 1). "\n\n";
|
||||||
if (! $passed) {
|
if (! $passed) {
|
||||||
echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n";
|
echo "\n\n\n\n---Expected: " .var_export($expected, 1). "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test_Minify();
|
test_Minify();
|
||||||
|
@@ -1,35 +1,35 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once '_inc.php';
|
require_once '_inc.php';
|
||||||
|
|
||||||
require_once 'Minify/Build.php';
|
require_once 'Minify/Build.php';
|
||||||
|
|
||||||
function test_Minify_Build()
|
function test_Minify_Build()
|
||||||
{
|
{
|
||||||
global $thisDir;
|
global $thisDir;
|
||||||
|
|
||||||
$file1 = $thisDir . '/_test_files/css/paths.css';
|
$file1 = $thisDir . '/_test_files/css/paths.css';
|
||||||
$file2 = $thisDir . '/_test_files/css/styles.css';
|
$file2 = $thisDir . '/_test_files/css/styles.css';
|
||||||
$maxTime = max(filemtime($file1), filemtime($file2));
|
$maxTime = max(filemtime($file1), filemtime($file2));
|
||||||
|
|
||||||
$b = new Minify_Build($file1);
|
$b = new Minify_Build($file1);
|
||||||
assertTrue($b->lastModified == filemtime($file1)
|
assertTrue($b->lastModified == filemtime($file1)
|
||||||
,'Minify_Build : single file path');
|
,'Minify_Build : single file path');
|
||||||
|
|
||||||
$b = new Minify_Build(array($file1, $file2));
|
$b = new Minify_Build(array($file1, $file2));
|
||||||
assertTrue($maxTime == $b->lastModified
|
assertTrue($maxTime == $b->lastModified
|
||||||
,'Minify_Build : multiple file paths');
|
,'Minify_Build : multiple file paths');
|
||||||
|
|
||||||
$b = new Minify_Build(array(
|
$b = new Minify_Build(array(
|
||||||
$file1
|
$file1
|
||||||
,new Minify_Source(array('filepath' => $file2))
|
,new Minify_Source(array('filepath' => $file2))
|
||||||
));
|
));
|
||||||
|
|
||||||
assertTrue($maxTime == $b->lastModified
|
assertTrue($maxTime == $b->lastModified
|
||||||
,'Minify_Build : file path and a Minify_Source');
|
,'Minify_Build : file path and a Minify_Source');
|
||||||
assertTrue($b->uri('/path') == "/path?{$maxTime}"
|
assertTrue($b->uri('/path') == "/path?{$maxTime}"
|
||||||
,'Minify_Build : uri() with no querystring');
|
,'Minify_Build : uri() with no querystring');
|
||||||
assertTrue($b->uri('/path?hello') == "/path?hello&{$maxTime}"
|
assertTrue($b->uri('/path?hello') == "/path?hello&{$maxTime}"
|
||||||
,'Minify_Build : uri() with existing querystring');
|
,'Minify_Build : uri() with existing querystring');
|
||||||
}
|
}
|
||||||
|
|
||||||
test_Minify_Build();
|
test_Minify_Build();
|
@@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require 'test_Minify.php';
|
require 'test_Minify.php';
|
||||||
require 'test_Javascript.php';
|
require 'test_Javascript.php';
|
||||||
require 'test_CSS.php';
|
require 'test_CSS.php';
|
||||||
require 'test_Lines.php';
|
require 'test_Lines.php';
|
||||||
require 'test_HTML.php';
|
require 'test_HTML.php';
|
||||||
require 'test_Minify_Build.php';
|
require 'test_Minify_Build.php';
|
||||||
require 'test_HTTP_Encoder.php';
|
require 'test_HTTP_Encoder.php';
|
||||||
require 'test_HTTP_ConditionalGet.php';
|
require 'test_HTTP_ConditionalGet.php';
|
||||||
|
@@ -1,32 +1,32 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
if (isset($_FILES['subject']['name'])) {
|
if (isset($_FILES['subject']['name'])) {
|
||||||
|
|
||||||
require '../../min/lib/HTTP/Encoder.php';
|
require '../../min/lib/HTTP/Encoder.php';
|
||||||
$he = new HTTP_Encoder(array(
|
$he = new HTTP_Encoder(array(
|
||||||
'content' => file_get_contents($_FILES['subject']['tmp_name'])
|
'content' => file_get_contents($_FILES['subject']['tmp_name'])
|
||||||
,'method' => $_POST['method']
|
,'method' => $_POST['method']
|
||||||
));
|
));
|
||||||
header('Content-Type: application/octet-stream');
|
header('Content-Type: application/octet-stream');
|
||||||
header('Content-Transfer-Encoding: binary');
|
header('Content-Transfer-Encoding: binary');
|
||||||
header("Content-Disposition: attachment; filename=\"{$_FILES['subject']['name']}."
|
header("Content-Disposition: attachment; filename=\"{$_FILES['subject']['name']}."
|
||||||
. ($_POST['method'] == 'deflate'
|
. ($_POST['method'] == 'deflate'
|
||||||
? 'zd'
|
? 'zd'
|
||||||
: ($_POST['method'] == 'gzip'
|
: ($_POST['method'] == 'gzip'
|
||||||
? 'zg'
|
? 'zg'
|
||||||
: 'zc'
|
: 'zc'
|
||||||
)
|
)
|
||||||
) . '"');
|
) . '"');
|
||||||
$he->encode(9);
|
$he->encode(9);
|
||||||
echo $he->getContent();
|
echo $he->getContent();
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
<p>Encode <input type="file" name="subject" /><br />
|
<p>Encode <input type="file" name="subject" /><br />
|
||||||
as <input type="submit" name="method" value="deflate" />
|
as <input type="submit" name="method" value="deflate" />
|
||||||
<input type="submit" name="method" value="gzip" />
|
<input type="submit" name="method" value="gzip" />
|
||||||
<input type="submit" name="method" value="compress" />
|
<input type="submit" name="method" value="compress" />
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
@@ -1,50 +1,53 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
if (isset($_FILES['subject']['name'])
|
if (isset($_FILES['subject']['name'])
|
||||||
&& preg_match('/\\.(js|css|html)$/', $_FILES['subject']['name'], $m)
|
&& preg_match('/\\.(js|css|x?html?)$/', $_FILES['subject']['name'], $m)
|
||||||
) {
|
) {
|
||||||
ini_set('include_path',
|
ini_set('include_path',
|
||||||
dirname(__FILE__) . '/../../min/lib'
|
dirname(__FILE__) . '/../../min/lib'
|
||||||
. PATH_SEPARATOR . ini_get('include_path')
|
. PATH_SEPARATOR . ini_get('include_path')
|
||||||
);
|
);
|
||||||
|
|
||||||
// eh why not
|
// eh why not
|
||||||
require 'Minify/HTML.php';
|
require 'Minify/HTML.php';
|
||||||
require 'Minify/CSS.php';
|
require 'Minify/CSS.php';
|
||||||
require 'Minify/Javascript.php';
|
require 'Minify/Javascript.php';
|
||||||
|
|
||||||
$arg2 = null;
|
$arg2 = null;
|
||||||
switch ($m[1]) {
|
switch ($m[1]) {
|
||||||
case 'js':
|
case 'js':
|
||||||
$type = 'Javascript';
|
$type = 'Javascript';
|
||||||
break;
|
break;
|
||||||
case 'css':
|
case 'css':
|
||||||
$type = 'CSS';
|
$type = 'CSS';
|
||||||
break;
|
break;
|
||||||
case 'html':
|
case 'html': // fallthrough
|
||||||
$type = 'HTML';
|
case 'htm': // fallthrough
|
||||||
$arg2 = array(
|
case 'xhtml':
|
||||||
'cssMinifier' => array('Minify_CSS', 'minify')
|
$type = 'HTML';
|
||||||
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
$arg2 = array(
|
||||||
);
|
'cssMinifier' => array('Minify_CSS', 'minify')
|
||||||
}
|
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
||||||
$func = array('Minify_' . $type, 'minify');
|
);
|
||||||
|
}
|
||||||
$out = call_user_func($func, file_get_contents($_FILES['subject']['tmp_name']), $arg2);
|
$func = array('Minify_' . $type, 'minify');
|
||||||
|
|
||||||
header('Content-Type: application/octet-stream');
|
$out = call_user_func($func, file_get_contents($_FILES['subject']['tmp_name']), $arg2);
|
||||||
header('Content-Transfer-Encoding: binary');
|
|
||||||
header('Content-Disposition: attachment; filename="'
|
header('Content-Type: application/octet-stream');
|
||||||
. preg_replace('/\\.(\w+)$/', '.min.$1', $_FILES['subject']['name'])
|
header('Content-Transfer-Encoding: binary');
|
||||||
. '"');
|
header('Content-Disposition: attachment; filename="'
|
||||||
|
. preg_replace('/\\.(\w+)$/', '.min.$1', $_FILES['subject']['name'])
|
||||||
echo $out;
|
. '"');
|
||||||
exit();
|
|
||||||
}
|
//@unlink($_FILES['subject']['tmp_name']);
|
||||||
|
echo $out;
|
||||||
?>
|
exit();
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
}
|
||||||
<p>Minify <input type="file" name="subject" /><br />
|
|
||||||
<input type="submit" name="method" value="Go!" />
|
?>
|
||||||
</p>
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
|
<p>Minify <input type="file" name="subject" /><br />
|
||||||
|
<input type="submit" name="method" value="Go!" />
|
||||||
|
</p>
|
||||||
</form>
|
</form>
|
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require '../config.php'; // just to set include_path
|
require '../config.php'; // just to set include_path
|
||||||
require 'Minify.php';
|
require 'Minify.php';
|
||||||
|
|
||||||
Minify::serve('Version1');
|
Minify::serve('Version1');
|
||||||
|
Reference in New Issue
Block a user