forked from leftypol/leftypol
Remove bundled minify dependency
This commit is contained in:
parent
b5834cafaf
commit
8c97b3a3fb
5 changed files with 0 additions and 845 deletions
|
@ -1,99 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Class Minify_CSS
|
|
||||||
* @package Minify
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify CSS
|
|
||||||
*
|
|
||||||
* This class uses Minify_CSS_Compressor and Minify_CSS_UriRewriter to
|
|
||||||
* minify CSS and rewrite relative URIs.
|
|
||||||
*
|
|
||||||
* @package Minify
|
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
|
||||||
* @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
|
|
||||||
*/
|
|
||||||
class Minify_CSS {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify a CSS string
|
|
||||||
*
|
|
||||||
* @param string $css
|
|
||||||
*
|
|
||||||
* @param array $options available options:
|
|
||||||
*
|
|
||||||
* 'preserveComments': (default true) multi-line comments that begin
|
|
||||||
* with "/*!" will be preserved with newlines before and after to
|
|
||||||
* enhance readability.
|
|
||||||
*
|
|
||||||
* 'removeCharsets': (default true) remove all @charset at-rules
|
|
||||||
*
|
|
||||||
* 'prependRelativePath': (default null) if given, this string will be
|
|
||||||
* prepended to all relative URIs in import/url declarations
|
|
||||||
*
|
|
||||||
* 'currentDir': (default null) if given, this is assumed to be the
|
|
||||||
* directory of the current CSS file. Using this, minify will rewrite
|
|
||||||
* all relative URIs in import/url declarations to correctly point to
|
|
||||||
* the desired files. For this to work, the files *must* exist and be
|
|
||||||
* visible by the PHP process.
|
|
||||||
*
|
|
||||||
* 'symlinks': (default = array()) If the CSS file is stored in
|
|
||||||
* a symlink-ed directory, provide an array of link paths to
|
|
||||||
* target paths, where the link paths are within the document root. Because
|
|
||||||
* paths need to be normalized for this to work, use "//" to substitute
|
|
||||||
* the doc root in the link paths (the array keys). E.g.:
|
|
||||||
* <code>
|
|
||||||
* array('//symlink' => '/real/target/path') // unix
|
|
||||||
* array('//static' => 'D:\\staticStorage') // Windows
|
|
||||||
* </code>
|
|
||||||
*
|
|
||||||
* 'docRoot': (default = $_SERVER['DOCUMENT_ROOT'])
|
|
||||||
* see Minify_CSS_UriRewriter::rewrite
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function minify($css, $options = array())
|
|
||||||
{
|
|
||||||
$options = array_merge(array(
|
|
||||||
'compress' => true,
|
|
||||||
'removeCharsets' => true,
|
|
||||||
'preserveComments' => true,
|
|
||||||
'currentDir' => null,
|
|
||||||
'docRoot' => $_SERVER['DOCUMENT_ROOT'],
|
|
||||||
'prependRelativePath' => null,
|
|
||||||
'symlinks' => array(),
|
|
||||||
), $options);
|
|
||||||
|
|
||||||
if ($options['removeCharsets']) {
|
|
||||||
$css = preg_replace('/@charset[^;]+;\\s*/', '', $css);
|
|
||||||
}
|
|
||||||
if ($options['compress']) {
|
|
||||||
if (! $options['preserveComments']) {
|
|
||||||
$css = Minify_CSS_Compressor::process($css, $options);
|
|
||||||
} else {
|
|
||||||
$css = Minify_CommentPreserver::process(
|
|
||||||
$css
|
|
||||||
,array('Minify_CSS_Compressor', 'process')
|
|
||||||
,array($options)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (! $options['currentDir'] && ! $options['prependRelativePath']) {
|
|
||||||
return $css;
|
|
||||||
}
|
|
||||||
if ($options['currentDir']) {
|
|
||||||
return Minify_CSS_UriRewriter::rewrite(
|
|
||||||
$css
|
|
||||||
,$options['currentDir']
|
|
||||||
,$options['docRoot']
|
|
||||||
,$options['symlinks']
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Minify_CSS_UriRewriter::prepend(
|
|
||||||
$css
|
|
||||||
,$options['prependRelativePath']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,249 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Class Minify_CSS_Compressor
|
|
||||||
* @package Minify
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compress CSS
|
|
||||||
*
|
|
||||||
* This is a heavy regex-based removal of whitespace, unnecessary
|
|
||||||
* comments and tokens, and some CSS value minimization, where practical.
|
|
||||||
* Many steps have been taken to avoid breaking comment-based hacks,
|
|
||||||
* including the ie5/mac filter (and its inversion), but expect tricky
|
|
||||||
* hacks involving comment tokens in 'content' value strings to break
|
|
||||||
* minimization badly. A test suite is available.
|
|
||||||
*
|
|
||||||
* @package Minify
|
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
|
||||||
* @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
|
|
||||||
*/
|
|
||||||
class Minify_CSS_Compressor {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify a CSS string
|
|
||||||
*
|
|
||||||
* @param string $css
|
|
||||||
*
|
|
||||||
* @param array $options (currently ignored)
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function process($css, $options = array())
|
|
||||||
{
|
|
||||||
$obj = new Minify_CSS_Compressor($options);
|
|
||||||
return $obj->_process($css);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $_options = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Are we "in" a hack? I.e. are some browsers targetted until the next comment?
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
protected $_inHack = false;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param array $options (currently ignored)
|
|
||||||
*/
|
|
||||||
private function __construct($options) {
|
|
||||||
$this->_options = $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify a CSS string
|
|
||||||
*
|
|
||||||
* @param string $css
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function _process($css)
|
|
||||||
{
|
|
||||||
$css = str_replace("\r\n", "\n", $css);
|
|
||||||
|
|
||||||
// preserve empty comment after '>'
|
|
||||||
// http://www.webdevout.net/css-hacks#in_css-selectors
|
|
||||||
$css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
|
|
||||||
|
|
||||||
// preserve empty comment between property and value
|
|
||||||
// http://css-discuss.incutio.com/?page=BoxModelHack
|
|
||||||
$css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
|
|
||||||
$css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
|
|
||||||
|
|
||||||
// apply callback to all valid comments (and strip out surrounding ws
|
|
||||||
$css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
|
|
||||||
,array($this, '_commentCB'), $css);
|
|
||||||
|
|
||||||
// remove ws around { } and last semicolon in declaration block
|
|
||||||
$css = preg_replace('/\\s*{\\s*/', '{', $css);
|
|
||||||
$css = preg_replace('/;?\\s*}\\s*/', '}', $css);
|
|
||||||
|
|
||||||
// remove ws surrounding semicolons
|
|
||||||
$css = preg_replace('/\\s*;\\s*/', ';', $css);
|
|
||||||
|
|
||||||
// remove ws around urls
|
|
||||||
$css = preg_replace('/
|
|
||||||
url\\( # url(
|
|
||||||
\\s*
|
|
||||||
([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
|
|
||||||
\\s*
|
|
||||||
\\) # )
|
|
||||||
/x', 'url($1)', $css);
|
|
||||||
|
|
||||||
// remove ws between rules and colons
|
|
||||||
$css = preg_replace('/
|
|
||||||
\\s*
|
|
||||||
([{;]) # 1 = beginning of block or rule separator
|
|
||||||
\\s*
|
|
||||||
([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
|
|
||||||
\\s*
|
|
||||||
:
|
|
||||||
\\s*
|
|
||||||
(\\b|[#\'"-]) # 3 = first character of a value
|
|
||||||
/x', '$1$2:$3', $css);
|
|
||||||
|
|
||||||
// remove ws in selectors
|
|
||||||
$css = preg_replace_callback('/
|
|
||||||
(?: # non-capture
|
|
||||||
\\s*
|
|
||||||
[^~>+,\\s]+ # selector part
|
|
||||||
\\s*
|
|
||||||
[,>+~] # combinators
|
|
||||||
)+
|
|
||||||
\\s*
|
|
||||||
[^~>+,\\s]+ # selector part
|
|
||||||
{ # open declaration block
|
|
||||||
/x'
|
|
||||||
,array($this, '_selectorsCB'), $css);
|
|
||||||
|
|
||||||
// minimize hex colors
|
|
||||||
$css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
|
|
||||||
, '$1#$2$3$4$5', $css);
|
|
||||||
|
|
||||||
// remove spaces between font families
|
|
||||||
$css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
|
|
||||||
,array($this, '_fontFamilyCB'), $css);
|
|
||||||
|
|
||||||
$css = preg_replace('/@import\\s+url/', '@import url', $css);
|
|
||||||
|
|
||||||
// replace any ws involving newlines with a single newline
|
|
||||||
$css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
|
|
||||||
|
|
||||||
// separate common descendent selectors w/ newlines (to limit line lengths)
|
|
||||||
$css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
|
|
||||||
|
|
||||||
// Use newline after 1st numeric value (to limit line lengths).
|
|
||||||
$css = preg_replace('/
|
|
||||||
((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
|
|
||||||
\\s+
|
|
||||||
/x'
|
|
||||||
,"$1\n", $css);
|
|
||||||
|
|
||||||
// prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
|
|
||||||
$css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
|
|
||||||
|
|
||||||
return trim($css);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace what looks like a set of selectors
|
|
||||||
*
|
|
||||||
* @param array $m regex matches
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function _selectorsCB($m)
|
|
||||||
{
|
|
||||||
// remove ws around the combinators
|
|
||||||
return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a comment and return a replacement
|
|
||||||
*
|
|
||||||
* @param array $m regex matches
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function _commentCB($m)
|
|
||||||
{
|
|
||||||
$hasSurroundingWs = (trim($m[0]) !== $m[1]);
|
|
||||||
$m = $m[1];
|
|
||||||
// $m is the comment content w/o the surrounding tokens,
|
|
||||||
// but the return value will replace the entire comment.
|
|
||||||
if ($m === 'keep') {
|
|
||||||
return '/**/';
|
|
||||||
}
|
|
||||||
if ($m === '" "') {
|
|
||||||
// component of http://tantek.com/CSS/Examples/midpass.html
|
|
||||||
return '/*" "*/';
|
|
||||||
}
|
|
||||||
if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
|
|
||||||
// component of http://tantek.com/CSS/Examples/midpass.html
|
|
||||||
return '/*";}}/* */';
|
|
||||||
}
|
|
||||||
if ($this->_inHack) {
|
|
||||||
// inversion: feeding only to one browser
|
|
||||||
if (preg_match('@
|
|
||||||
^/ # comment started like /*/
|
|
||||||
\\s*
|
|
||||||
(\\S[\\s\\S]+?) # has at least some non-ws content
|
|
||||||
\\s*
|
|
||||||
/\\* # ends like /*/ or /**/
|
|
||||||
@x', $m, $n)) {
|
|
||||||
// end hack mode after this comment, but preserve the hack and comment content
|
|
||||||
$this->_inHack = false;
|
|
||||||
return "/*/{$n[1]}/**/";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (substr($m, -1) === '\\') { // comment ends like \*/
|
|
||||||
// begin hack mode and preserve hack
|
|
||||||
$this->_inHack = true;
|
|
||||||
return '/*\\*/';
|
|
||||||
}
|
|
||||||
if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
|
|
||||||
// begin hack mode and preserve hack
|
|
||||||
$this->_inHack = true;
|
|
||||||
return '/*/*/';
|
|
||||||
}
|
|
||||||
if ($this->_inHack) {
|
|
||||||
// a regular comment ends hack mode but should be preserved
|
|
||||||
$this->_inHack = false;
|
|
||||||
return '/**/';
|
|
||||||
}
|
|
||||||
// Issue 107: if there's any surrounding whitespace, it may be important, so
|
|
||||||
// replace the comment with a single space
|
|
||||||
return $hasSurroundingWs // remove all other comments
|
|
||||||
? ' '
|
|
||||||
: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a font-family listing and return a replacement
|
|
||||||
*
|
|
||||||
* @param array $m regex matches
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function _fontFamilyCB($m)
|
|
||||||
{
|
|
||||||
// Issue 210: must not eliminate WS between words in unquoted families
|
|
||||||
$pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
|
||||||
$out = 'font-family:';
|
|
||||||
while (null !== ($piece = array_shift($pieces))) {
|
|
||||||
if ($piece[0] !== '"' && $piece[0] !== "'") {
|
|
||||||
$piece = preg_replace('/\\s+/', ' ', $piece);
|
|
||||||
$piece = preg_replace('/\\s?,\\s?/', ',', $piece);
|
|
||||||
}
|
|
||||||
$out .= $piece;
|
|
||||||
}
|
|
||||||
return $out . $m[2];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detect whether request should be debugged
|
|
||||||
*
|
|
||||||
* @package Minify
|
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
|
||||||
*/
|
|
||||||
class Minify_DebugDetector {
|
|
||||||
public static function shouldDebugRequest($cookie, $get, $requestUri)
|
|
||||||
{
|
|
||||||
if (isset($get['debug'])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (! empty($cookie['minifyDebug'])) {
|
|
||||||
foreach (preg_split('/\\s+/', $cookie['minifyDebug']) as $debugUri) {
|
|
||||||
$pattern = '@' . preg_quote($debugUri, '@') . '@i';
|
|
||||||
$pattern = str_replace(array('\\*', '\\?'), array('.*', '.'), $pattern);
|
|
||||||
if (preg_match($pattern, $requestUri)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,255 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Class Minify_HTML
|
|
||||||
* @package Minify
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compress HTML
|
|
||||||
*
|
|
||||||
* This is a heavy regex-based removal of whitespace, unnecessary comments and
|
|
||||||
* tokens. IE conditional comments are preserved. There are also options to have
|
|
||||||
* STYLE and SCRIPT blocks compressed by callback functions.
|
|
||||||
*
|
|
||||||
* A test suite is available.
|
|
||||||
*
|
|
||||||
* @package Minify
|
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
|
||||||
*/
|
|
||||||
class Minify_HTML {
|
|
||||||
/**
|
|
||||||
* @var boolean
|
|
||||||
*/
|
|
||||||
protected $_jsCleanComments = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* "Minify" an HTML page
|
|
||||||
*
|
|
||||||
* @param string $html
|
|
||||||
*
|
|
||||||
* @param array $options
|
|
||||||
*
|
|
||||||
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
|
||||||
* elements.
|
|
||||||
*
|
|
||||||
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
|
||||||
* elements. Note: the type attribute is ignored.
|
|
||||||
*
|
|
||||||
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
|
||||||
* unset, minify will sniff for an XHTML doctype.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function minify($html, $options = array()) {
|
|
||||||
$min = new self($html, $options);
|
|
||||||
return $min->process();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a minifier object
|
|
||||||
*
|
|
||||||
* @param string $html
|
|
||||||
*
|
|
||||||
* @param array $options
|
|
||||||
*
|
|
||||||
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
|
||||||
* elements.
|
|
||||||
*
|
|
||||||
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
|
||||||
* elements. Note: the type attribute is ignored.
|
|
||||||
*
|
|
||||||
* 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block
|
|
||||||
*
|
|
||||||
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
|
||||||
* unset, minify will sniff for an XHTML doctype.
|
|
||||||
*/
|
|
||||||
public function __construct($html, $options = array())
|
|
||||||
{
|
|
||||||
$this->_html = str_replace("\r\n", "\n", trim($html));
|
|
||||||
if (isset($options['xhtml'])) {
|
|
||||||
$this->_isXhtml = (bool)$options['xhtml'];
|
|
||||||
}
|
|
||||||
if (isset($options['cssMinifier'])) {
|
|
||||||
$this->_cssMinifier = $options['cssMinifier'];
|
|
||||||
}
|
|
||||||
if (isset($options['jsMinifier'])) {
|
|
||||||
$this->_jsMinifier = $options['jsMinifier'];
|
|
||||||
}
|
|
||||||
if (isset($options['jsCleanComments'])) {
|
|
||||||
$this->_jsCleanComments = (bool)$options['jsCleanComments'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify the markeup given in the constructor
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function process()
|
|
||||||
{
|
|
||||||
if ($this->_isXhtml === null) {
|
|
||||||
$this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']);
|
|
||||||
$this->_placeholders = array();
|
|
||||||
|
|
||||||
// replace SCRIPTs (and minify) with placeholders
|
|
||||||
$this->_html = preg_replace_callback(
|
|
||||||
'/(\\s*)<script(\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
|
|
||||||
,array($this, '_removeScriptCB')
|
|
||||||
,$this->_html);
|
|
||||||
|
|
||||||
// replace STYLEs (and minify) with placeholders
|
|
||||||
$this->_html = preg_replace_callback(
|
|
||||||
'/\\s*<style(\\b[^>]*>)([\\s\\S]*?)<\\/style>\\s*/i'
|
|
||||||
,array($this, '_removeStyleCB')
|
|
||||||
,$this->_html);
|
|
||||||
|
|
||||||
// remove HTML comments (not containing IE conditional comments).
|
|
||||||
$this->_html = preg_replace_callback(
|
|
||||||
'/<!--([\\s\\S]*?)-->/'
|
|
||||||
,array($this, '_commentCB')
|
|
||||||
,$this->_html);
|
|
||||||
|
|
||||||
// replace PREs with placeholders
|
|
||||||
$this->_html = preg_replace_callback('/\\s*<pre(\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
|
|
||||||
,array($this, '_removePreCB')
|
|
||||||
,$this->_html);
|
|
||||||
|
|
||||||
// replace TEXTAREAs with placeholders
|
|
||||||
$this->_html = preg_replace_callback(
|
|
||||||
'/\\s*<textarea(\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
|
|
||||||
,array($this, '_removeTextareaCB')
|
|
||||||
,$this->_html);
|
|
||||||
|
|
||||||
// trim each line.
|
|
||||||
// @todo take into account attribute values that span multiple lines.
|
|
||||||
$this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html);
|
|
||||||
|
|
||||||
// remove ws around block/undisplayed elements
|
|
||||||
$this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
|
|
||||||
.'|caption|center|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
|
|
||||||
.'|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)'
|
|
||||||
.'|ul)\\b[^>]*>)/i', '$1', $this->_html);
|
|
||||||
|
|
||||||
// remove ws outside of all elements
|
|
||||||
$this->_html = preg_replace(
|
|
||||||
'/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?</'
|
|
||||||
,'>$1$2$3<'
|
|
||||||
,$this->_html);
|
|
||||||
|
|
||||||
// use newlines before 1st attribute in open tags (to limit line lengths)
|
|
||||||
$this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
|
|
||||||
|
|
||||||
// fill placeholders
|
|
||||||
$this->_html = str_replace(
|
|
||||||
array_keys($this->_placeholders)
|
|
||||||
,array_values($this->_placeholders)
|
|
||||||
,$this->_html
|
|
||||||
);
|
|
||||||
// issue 229: multi-pass to catch scripts that didn't get replaced in textareas
|
|
||||||
$this->_html = str_replace(
|
|
||||||
array_keys($this->_placeholders)
|
|
||||||
,array_values($this->_placeholders)
|
|
||||||
,$this->_html
|
|
||||||
);
|
|
||||||
return $this->_html;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function _commentCB($m)
|
|
||||||
{
|
|
||||||
return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<!['))
|
|
||||||
? $m[0]
|
|
||||||
: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function _reservePlace($content)
|
|
||||||
{
|
|
||||||
$placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
|
|
||||||
$this->_placeholders[$placeholder] = $content;
|
|
||||||
return $placeholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected $_isXhtml = null;
|
|
||||||
protected $_replacementHash = null;
|
|
||||||
protected $_placeholders = array();
|
|
||||||
protected $_cssMinifier = null;
|
|
||||||
protected $_jsMinifier = null;
|
|
||||||
|
|
||||||
protected function _removePreCB($m)
|
|
||||||
{
|
|
||||||
return $this->_reservePlace("<pre{$m[1]}");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function _removeTextareaCB($m)
|
|
||||||
{
|
|
||||||
return $this->_reservePlace("<textarea{$m[1]}");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function _removeStyleCB($m)
|
|
||||||
{
|
|
||||||
$openStyle = "<style{$m[1]}";
|
|
||||||
$css = $m[2];
|
|
||||||
// remove HTML comments
|
|
||||||
$css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
|
|
||||||
|
|
||||||
// remove CDATA section markers
|
|
||||||
$css = $this->_removeCdata($css);
|
|
||||||
|
|
||||||
// minify
|
|
||||||
$minifier = $this->_cssMinifier
|
|
||||||
? $this->_cssMinifier
|
|
||||||
: 'trim';
|
|
||||||
$css = call_user_func($minifier, $css);
|
|
||||||
|
|
||||||
return $this->_reservePlace($this->_needsCdata($css)
|
|
||||||
? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
|
|
||||||
: "{$openStyle}{$css}</style>"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function _removeScriptCB($m)
|
|
||||||
{
|
|
||||||
$openScript = "<script{$m[2]}";
|
|
||||||
$js = $m[3];
|
|
||||||
|
|
||||||
// whitespace surrounding? preserve at least one space
|
|
||||||
$ws1 = ($m[1] === '') ? '' : ' ';
|
|
||||||
$ws2 = ($m[4] === '') ? '' : ' ';
|
|
||||||
|
|
||||||
// remove HTML comments (and ending "//" if present)
|
|
||||||
if ($this->_jsCleanComments) {
|
|
||||||
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove CDATA section markers
|
|
||||||
$js = $this->_removeCdata($js);
|
|
||||||
|
|
||||||
// minify
|
|
||||||
$minifier = $this->_jsMinifier
|
|
||||||
? $this->_jsMinifier
|
|
||||||
: 'trim';
|
|
||||||
$js = call_user_func($minifier, $js);
|
|
||||||
|
|
||||||
return $this->_reservePlace($this->_needsCdata($js)
|
|
||||||
? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
|
|
||||||
: "{$ws1}{$openScript}{$js}</script>{$ws2}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function _removeCdata($str)
|
|
||||||
{
|
|
||||||
return (false !== strpos($str, '<![CDATA['))
|
|
||||||
? str_replace(array('<![CDATA[', ']]>'), '', $str)
|
|
||||||
: $str;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function _needsCdata($str)
|
|
||||||
{
|
|
||||||
return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,216 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Class Minify_ImportProcessor
|
|
||||||
* @package Minify
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Linearize a CSS/JS file by including content specified by CSS import
|
|
||||||
* declarations. In CSS files, relative URIs are fixed.
|
|
||||||
*
|
|
||||||
* @imports will be processed regardless of where they appear in the source
|
|
||||||
* files; i.e. @imports commented out or in string content will still be
|
|
||||||
* processed!
|
|
||||||
*
|
|
||||||
* This has a unit test but should be considered "experimental".
|
|
||||||
*
|
|
||||||
* @package Minify
|
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
|
||||||
* @author Simon Schick <simonsimcity@gmail.com>
|
|
||||||
*/
|
|
||||||
class Minify_ImportProcessor {
|
|
||||||
|
|
||||||
public static $filesIncluded = array();
|
|
||||||
|
|
||||||
public static function process($file)
|
|
||||||
{
|
|
||||||
self::$filesIncluded = array();
|
|
||||||
self::$_isCss = (strtolower(substr($file, -4)) === '.css');
|
|
||||||
$obj = new Minify_ImportProcessor(dirname($file));
|
|
||||||
return $obj->_getContent($file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// allows callback funcs to know the current directory
|
|
||||||
private $_currentDir = null;
|
|
||||||
|
|
||||||
// allows callback funcs to know the directory of the file that inherits this one
|
|
||||||
private $_previewsDir = null;
|
|
||||||
|
|
||||||
// allows _importCB to write the fetched content back to the obj
|
|
||||||
private $_importedContent = '';
|
|
||||||
|
|
||||||
private static $_isCss = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param String $currentDir
|
|
||||||
* @param String $previewsDir Is only used internally
|
|
||||||
*/
|
|
||||||
private function __construct($currentDir, $previewsDir = "")
|
|
||||||
{
|
|
||||||
$this->_currentDir = $currentDir;
|
|
||||||
$this->_previewsDir = $previewsDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function _getContent($file, $is_imported = false)
|
|
||||||
{
|
|
||||||
$file = realpath($file);
|
|
||||||
if (! $file
|
|
||||||
|| in_array($file, self::$filesIncluded)
|
|
||||||
|| false === ($content = @file_get_contents($file))
|
|
||||||
) {
|
|
||||||
// file missing, already included, or failed read
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
self::$filesIncluded[] = realpath($file);
|
|
||||||
$this->_currentDir = dirname($file);
|
|
||||||
|
|
||||||
// remove UTF-8 BOM if present
|
|
||||||
if (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) {
|
|
||||||
$content = substr($content, 3);
|
|
||||||
}
|
|
||||||
// ensure uniform EOLs
|
|
||||||
$content = str_replace("\r\n", "\n", $content);
|
|
||||||
|
|
||||||
// process @imports
|
|
||||||
$content = preg_replace_callback(
|
|
||||||
'/
|
|
||||||
@import\\s+
|
|
||||||
(?:url\\(\\s*)? # maybe url(
|
|
||||||
[\'"]? # maybe quote
|
|
||||||
(.*?) # 1 = URI
|
|
||||||
[\'"]? # maybe end quote
|
|
||||||
(?:\\s*\\))? # maybe )
|
|
||||||
([a-zA-Z,\\s]*)? # 2 = media list
|
|
||||||
; # end token
|
|
||||||
/x'
|
|
||||||
,array($this, '_importCB')
|
|
||||||
,$content
|
|
||||||
);
|
|
||||||
|
|
||||||
// You only need to rework the import-path if the script is imported
|
|
||||||
if (self::$_isCss && $is_imported) {
|
|
||||||
// rewrite remaining relative URIs
|
|
||||||
$content = preg_replace_callback(
|
|
||||||
'/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
|
|
||||||
,array($this, '_urlCB')
|
|
||||||
,$content
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->_importedContent . $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function _importCB($m)
|
|
||||||
{
|
|
||||||
$url = $m[1];
|
|
||||||
$mediaList = preg_replace('/\\s+/', '', $m[2]);
|
|
||||||
|
|
||||||
if (strpos($url, '://') > 0) {
|
|
||||||
// protocol, leave in place for CSS, comment for JS
|
|
||||||
return self::$_isCss
|
|
||||||
? $m[0]
|
|
||||||
: "/* Minify_ImportProcessor will not include remote content */";
|
|
||||||
}
|
|
||||||
if ('/' === $url[0]) {
|
|
||||||
// protocol-relative or root path
|
|
||||||
$url = ltrim($url, '/');
|
|
||||||
$file = realpath($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR
|
|
||||||
. strtr($url, '/', DIRECTORY_SEPARATOR);
|
|
||||||
} else {
|
|
||||||
// relative to current path
|
|
||||||
$file = $this->_currentDir . DIRECTORY_SEPARATOR
|
|
||||||
. strtr($url, '/', DIRECTORY_SEPARATOR);
|
|
||||||
}
|
|
||||||
$obj = new Minify_ImportProcessor(dirname($file), $this->_currentDir);
|
|
||||||
$content = $obj->_getContent($file, true);
|
|
||||||
if ('' === $content) {
|
|
||||||
// failed. leave in place for CSS, comment for JS
|
|
||||||
return self::$_isCss
|
|
||||||
? $m[0]
|
|
||||||
: "/* Minify_ImportProcessor could not fetch '{$file}' */";
|
|
||||||
}
|
|
||||||
return (!self::$_isCss || preg_match('@(?:^$|\\ball\\b)@', $mediaList))
|
|
||||||
? $content
|
|
||||||
: "@media {$mediaList} {\n{$content}\n}\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
private function _urlCB($m)
|
|
||||||
{
|
|
||||||
// $m[1] is either quoted or not
|
|
||||||
$quote = ($m[1][0] === "'" || $m[1][0] === '"')
|
|
||||||
? $m[1][0]
|
|
||||||
: '';
|
|
||||||
$url = ($quote === '')
|
|
||||||
? $m[1]
|
|
||||||
: substr($m[1], 1, strlen($m[1]) - 2);
|
|
||||||
if ('/' !== $url[0]) {
|
|
||||||
if (strpos($url, '//') > 0) {
|
|
||||||
// probably starts with protocol, do not alter
|
|
||||||
} else {
|
|
||||||
// prepend path with current dir separator (OS-independent)
|
|
||||||
$path = $this->_currentDir
|
|
||||||
. DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR);
|
|
||||||
// update the relative path by the directory of the file that imported this one
|
|
||||||
$url = self::getPathDiff(realpath($this->_previewsDir), $path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "url({$quote}{$url}{$quote})";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $from
|
|
||||||
* @param string $to
|
|
||||||
* @param string $ps
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function getPathDiff($from, $to, $ps = DIRECTORY_SEPARATOR)
|
|
||||||
{
|
|
||||||
$realFrom = $this->truepath($from);
|
|
||||||
$realTo = $this->truepath($to);
|
|
||||||
|
|
||||||
$arFrom = explode($ps, rtrim($realFrom, $ps));
|
|
||||||
$arTo = explode($ps, rtrim($realTo, $ps));
|
|
||||||
while (count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0]))
|
|
||||||
{
|
|
||||||
array_shift($arFrom);
|
|
||||||
array_shift($arTo);
|
|
||||||
}
|
|
||||||
return str_pad("", count($arFrom) * 3, '..' . $ps) . implode($ps, $arTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is to replace PHP's extremely buggy realpath().
|
|
||||||
* @param string $path The original path, can be relative etc.
|
|
||||||
* @return string The resolved path, it might not exist.
|
|
||||||
* @see http://stackoverflow.com/questions/4049856/replace-phps-realpath
|
|
||||||
*/
|
|
||||||
function truepath($path)
|
|
||||||
{
|
|
||||||
// whether $path is unix or not
|
|
||||||
$unipath = strlen($path) == 0 || $path{0} != '/';
|
|
||||||
// attempts to detect if path is relative in which case, add cwd
|
|
||||||
if (strpos($path, ':') === false && $unipath)
|
|
||||||
$path = $this->_currentDir . DIRECTORY_SEPARATOR . $path;
|
|
||||||
|
|
||||||
// resolve path parts (single dot, double dot and double delimiters)
|
|
||||||
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
|
|
||||||
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
|
|
||||||
$absolutes = array();
|
|
||||||
foreach ($parts as $part) {
|
|
||||||
if ('.' == $part)
|
|
||||||
continue;
|
|
||||||
if ('..' == $part) {
|
|
||||||
array_pop($absolutes);
|
|
||||||
} else {
|
|
||||||
$absolutes[] = $part;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$path = implode(DIRECTORY_SEPARATOR, $absolutes);
|
|
||||||
// resolve any symlinks
|
|
||||||
if (file_exists($path) && linkinfo($path) > 0)
|
|
||||||
$path = readlink($path);
|
|
||||||
// put initial separator that could have been lost
|
|
||||||
$path = !$unipath ? '/' . $path : $path;
|
|
||||||
return $path;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue