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