Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 40 additions & 23 deletions PHP-Minify-Lib/CSSmin.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?php

/*!
* cssmin.php rev ebaf67b 12/06/2013
* cssmin.php 2.4.8-2
* Author: Tubal Martin - http://tubalmartin.me/
* Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
*
* This is a PHP port of the CSS minification tool distributed with YUICompressor,
* This is a PHP port of the CSS minification tool distributed with YUICompressor,
* itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
* Permission is hereby granted to use the PHP version under the same
* conditions as the YUICompressor.
Expand Down Expand Up @@ -92,7 +92,7 @@ public function run($css = '', $linebreak_pos = FALSE)
// preserve strings so their content doesn't get accidentally minified
$css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css);

// Let's divide css code in chunks of 25.000 chars aprox.
// Let's divide css code in chunks of 5.000 chars aprox.
// Reason: PHP's PCRE functions like preg_replace have a "backtrack limit"
// of 100.000 chars by default (php < 5.3.7) so if we're dealing with really
// long strings and a (sub)pattern matches a number of chars greater than
Expand All @@ -101,7 +101,7 @@ public function run($css = '', $linebreak_pos = FALSE)
$charset = '';
$charset_regexp = '/(@charset)( [^;]+;)/i';
$css_chunks = array();
$css_chunk_length = 25000; // aprox size, not exact
$css_chunk_length = 5000; // aprox size, not exact
$start_index = 0;
$i = $css_chunk_length; // save initial iterations
$l = strlen($css);
Expand All @@ -113,7 +113,7 @@ public function run($css = '', $linebreak_pos = FALSE)
} else {
// chunk css code securely
while ($i < $l) {
$i += 50; // save iterations. 500 checks for a closing curly brace }
$i += 50; // save iterations
if ($l - $start_index <= $css_chunk_length || $i >= $l) {
$css_chunks[] = $this->str_slice($css, $start_index);
break;
Expand Down Expand Up @@ -264,6 +264,9 @@ private function minify($css, $linebreak_pos)
// Normalize all whitespace strings to single spaces. Easier to work with that way.
$css = preg_replace('/\s+/', ' ', $css);

// Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters
$css = preg_replace_callback('/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array($this, 'preserve_old_IE_specific_matrix_definition'), $css);

// Shorten & preserve calculations calc(...) since spaces are important
$css = preg_replace_callback('/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array($this, 'replace_calc'), $css);

Expand All @@ -289,7 +292,7 @@ private function minify($css, $linebreak_pos)
// But, be careful not to turn "p :link {...}" into "p:link{...}"
// Swap out any pseudo-class colons with the token, and then swap back.
$css = preg_replace_callback('/(?:^|\})(?:(?:[^\{\:])+\:)+(?:[^\{]*\{)/', array($this, 'replace_colon'), $css);

// Remove spaces before the things that should not have spaces before them.
$css = preg_replace('/\s+([\!\{\}\;\:\>\+\(\)\]\~\=,])/', '$1', $css);

Expand Down Expand Up @@ -317,7 +320,7 @@ private function minify($css, $linebreak_pos)
// lower case some common function that can be values
// NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
$css = preg_replace_callback('/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS', array($this, 'lowercase_common_functions_values'), $css);

// Put the space back in some cases, to support stuff like
// @media screen and (-webkit-min-device-pixel-ratio:0){
$css = preg_replace('/\band\(/i', 'and (', $css);
Expand All @@ -336,6 +339,9 @@ private function minify($css, $linebreak_pos)
// Replace 0 length units 0(px,em,%) with 0.
$css = preg_replace('/(^|[^0-9])(?:0?\.)?0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%|deg|g?rad|m?s|k?hz)/iS', '${1}0', $css);

// 0% step in a keyframe? restore the % unit
$css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]*?\{)(.*?\}\s*\})/iS', array($this, 'replace_keyframe_zero'), $css);

// Replace 0 0; or 0 0 0; or 0 0 0 0; with 0.
$css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css);

Expand Down Expand Up @@ -373,6 +379,16 @@ private function minify($css, $linebreak_pos)
// Add "/" back to fix Opera -o-device-pixel-ratio query
$css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css);

// Replace multiple semi-colons in a row by a single one
// See SF bug #1980989
$css = preg_replace('/;;+/', ';', $css);

// Restore new lines for /*! important comments
$css = preg_replace('/'. self::NL .'/', "\n", $css);

// Lowercase all uppercase properties
$css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css);

// Some source control tools don't like it when files containing lines longer
// than, say 8000 characters, are checked in. The linebreak option is used in
// that case to split long lines after a specific column.
Expand All @@ -388,18 +404,8 @@ private function minify($css, $linebreak_pos)
}
}

// Replace multiple semi-colons in a row by a single one
// See SF bug #1980989
$css = preg_replace('/;;+/', ';', $css);

// Restore new lines for /*! important comments
$css = preg_replace('/'. self::NL .'/', "\n", $css);

// Lowercase all uppercase properties
$css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css);

// restore preserved comments and strings
for ($i = 0, $max = count($this->preserved_tokens); $i < $max; $i++) {
// restore preserved comments and strings in reverse order
for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) {
$css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1);
}

Expand Down Expand Up @@ -582,6 +588,17 @@ private function replace_calc($matches)
return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
}

private function preserve_old_IE_specific_matrix_definition($matches)
{
$this->preserved_tokens[] = $matches[1];
return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
}

private function replace_keyframe_zero($matches)
{
return $matches[1] . preg_replace('/0\s*,/', '0%,', preg_replace('/\s*0\s*\{/', '0%{', $matches[2]));
}

private function rgb_to_hex($matches)
{
// Support for percentage values rgb(100%, 0%, 45%);
Expand Down Expand Up @@ -638,22 +655,22 @@ private function lowercase_pseudo_first($matches)
return ':first-'. strtolower($matches[1]) .' '. $matches[2];
}

private function lowercase_directives($matches)
private function lowercase_directives($matches)
{
return '@'. strtolower($matches[1]);
}

private function lowercase_pseudo_elements($matches)
private function lowercase_pseudo_elements($matches)
{
return ':'. strtolower($matches[1]);
}

private function lowercase_common_functions($matches)
private function lowercase_common_functions($matches)
{
return ':'. strtolower($matches[1]) .'(';
}

private function lowercase_common_functions_values($matches)
private function lowercase_common_functions_values($matches)
{
return $matches[1] . strtolower($matches[2]);
}
Expand Down
40 changes: 26 additions & 14 deletions PHP-Minify-Lib/JSMin.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,9 @@ protected function action($command)
break;
}
if ($this->isEOF($this->a)) {
$byte = $this->inputIndex - 1;
throw new JSMin_UnterminatedStringException(
"JSMin: Unterminated String at byte {$this->inputIndex}: {$str}");
"JSMin: Unterminated String at byte {$byte}: {$str}");
}
$str .= $this->a;
if ($this->a === '\\') {
Expand Down Expand Up @@ -251,8 +252,9 @@ protected function action($command)
$this->a = $this->get();
$pattern .= $this->a;
} elseif ($this->isEOF($this->a)) {
$byte = $this->inputIndex - 1;
throw new JSMin_UnterminatedRegExpException(
"JSMin: Unterminated RegExp at byte {$this->inputIndex}: {$pattern}");
"JSMin: Unterminated RegExp at byte {$byte}: {$pattern}");
}
$this->output .= $this->a;
$this->lastByteOut = $this->a;
Expand All @@ -272,23 +274,33 @@ protected function isRegexpLiteral()
// we obviously aren't dividing
return true;
}
if ($this->a === ' ' || $this->a === "\n") {
$length = strlen($this->output);
if ($length < 2) { // weird edge case
return true;

// we have to check for a preceding keyword, and we don't need to pattern
// match over the whole output.
$recentOutput = substr($this->output, -10);

// check if return/typeof directly precede a pattern without a space
foreach (array('return', 'typeof') as $keyword) {
if ($this->a !== substr($keyword, -1)) {
// certainly wasn't keyword
continue;
}
// you can't divide a keyword
if (preg_match('/(?:case|else|in|return|typeof)$/', $this->output, $m)) {
if ($this->output === $m[0]) { // odd but could happen
return true;
}
// make sure it's a keyword, not end of an identifier
$charBeforeKeyword = substr($this->output, $length - strlen($m[0]) - 1, 1);
if (! $this->isAlphaNum($charBeforeKeyword)) {
if (preg_match("~(^|[\\s\\S])" . substr($keyword, 0, -1) . "$~", $recentOutput, $m)) {
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
return true;
}
}
}

// check all keywords
if ($this->a === ' ' || $this->a === "\n") {
if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) {
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
return true;
}
}
}

return false;
}

Expand Down
8 changes: 5 additions & 3 deletions PHP-Minify-Lib/Minify.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/
class Minify {

const VERSION = '2.1.5';
const VERSION = '2.2.0';
const TYPE_CSS = 'text/css';
const TYPE_HTML = 'text/html';
// there is some debate over the ideal JS Content-Type, but this is the
Expand Down Expand Up @@ -441,7 +441,7 @@ protected static function _errorExit($header, $url)
/**
* Set up sources to use Minify_Lines
*
* @param array $sources Minify_Source instances
* @param Minify_Source[] $sources Minify_Source instances
*/
protected static function _setupDebug($sources)
{
Expand All @@ -458,6 +458,8 @@ protected static function _setupDebug($sources)
* Combines sources and minifies the result.
*
* @return string
*
* @throws Exception
*/
protected static function _combineMinify()
{
Expand Down Expand Up @@ -563,7 +565,7 @@ protected static function _getCacheId($prefix = 'minify')
{
$name = preg_replace('/[^a-zA-Z0-9\\.=_,]/', '', self::$_controller->selectionId);
$name = preg_replace('/\\.+/', '.', $name);
$name = substr($name, 0, 200 - 34 - strlen($prefix));
$name = substr($name, 0, 100 - 34 - strlen($prefix));
$md5 = md5(serialize(array(
Minify_Source::getDigest(self::$_controller->sources)
,self::$_options['minifiers']
Expand Down
7 changes: 2 additions & 5 deletions PHP-Minify-Lib/Minify/CSS/UriRewriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,8 @@ private static function _processUriCB($m)
? $m[1]
: substr($m[1], 1, strlen($m[1]) - 2);
}
// analyze URI
if ('/' !== $uri[0] // root-relative
&& false === strpos($uri, '//') // protocol (non-data)
&& 0 !== strpos($uri, 'data:') // data protocol
) {
// if not root/scheme relative and not starts with scheme
if (!preg_match('~^(/|[a-z]+\:)~', $uri)) {
// URI is file-relative: rewrite depending on options
if (self::$_prependPath === null) {
$uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
Expand Down
85 changes: 85 additions & 0 deletions PHP-Minify-Lib/Minify/CSSmin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php
/**
* Class Minify_CSSmin
* @package Minify
*/

/**
* Wrapper for CSSmin
*
* This class uses CSSmin and Minify_CSS_UriRewriter to minify CSS and rewrite relative URIs.
*
* @package Minify
* @author Stephen Clay <steve@mrclay.org>
*/
class Minify_CSSmin {

/**
* Minify a CSS string
*
* @param string $css
*
* @param array $options available options:
*
* '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,
'currentDir' => null,
'docRoot' => $_SERVER['DOCUMENT_ROOT'],
'prependRelativePath' => null,
'symlinks' => array(),
), $options);

if ($options['removeCharsets']) {
$css = preg_replace('/@charset[^;]+;\\s*/', '', $css);
}
if ($options['compress']) {
$obj = new CSSmin();
$css = $obj->run($css);
}
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']
);
}
}
}
2 changes: 1 addition & 1 deletion PHP-Minify-Lib/Minify/ClosureCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public static function minify($js, $options = array())
{
self::_prepare();
if (! ($tmpFile = tempnam(self::$tempDir, 'cc_'))) {
throw new Exception('Minify_ClosureCompiler : could not create temp file.');
throw new Exception('Minify_ClosureCompiler : could not create temp file in "'.self::$tempDir.'".');
}
file_put_contents($tmpFile, $js);
exec(self::_getCmd($options, $tmpFile), $output, $result_code);
Expand Down
Loading