diff --git a/PHP-Minify-Lib/CSSmin.php b/PHP-Minify-Lib/CSSmin.php index a60b4ac..e85f23e 100644 --- a/PHP-Minify-Lib/CSSmin.php +++ b/PHP-Minify-Lib/CSSmin.php @@ -1,11 +1,11 @@ = $l) { $css_chunks[] = $this->str_slice($css, $start_index); break; @@ -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); @@ -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); @@ -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); @@ -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); @@ -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. @@ -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); } @@ -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%); @@ -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]); } diff --git a/PHP-Minify-Lib/JSMin.php b/PHP-Minify-Lib/JSMin.php index c84dd84..9840d8b 100644 --- a/PHP-Minify-Lib/JSMin.php +++ b/PHP-Minify-Lib/JSMin.php @@ -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 === '\\') { @@ -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; @@ -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; } diff --git a/PHP-Minify-Lib/Minify.php b/PHP-Minify-Lib/Minify.php index c1cf797..2b38f89 100644 --- a/PHP-Minify-Lib/Minify.php +++ b/PHP-Minify-Lib/Minify.php @@ -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 @@ -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) { @@ -458,6 +458,8 @@ protected static function _setupDebug($sources) * Combines sources and minifies the result. * * @return string + * + * @throws Exception */ protected static function _combineMinify() { @@ -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'] diff --git a/PHP-Minify-Lib/Minify/CSS/UriRewriter.php b/PHP-Minify-Lib/Minify/CSS/UriRewriter.php index 8845f15..50360ce 100644 --- a/PHP-Minify-Lib/Minify/CSS/UriRewriter.php +++ b/PHP-Minify-Lib/Minify/CSS/UriRewriter.php @@ -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); diff --git a/PHP-Minify-Lib/Minify/CSSmin.php b/PHP-Minify-Lib/Minify/CSSmin.php new file mode 100644 index 0000000..4403383 --- /dev/null +++ b/PHP-Minify-Lib/Minify/CSSmin.php @@ -0,0 +1,85 @@ + + */ +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.: + * + * array('//symlink' => '/real/target/path') // unix + * array('//static' => 'D:\\staticStorage') // Windows + * + * + * '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'] + ); + } + } +} diff --git a/PHP-Minify-Lib/Minify/ClosureCompiler.php b/PHP-Minify-Lib/Minify/ClosureCompiler.php index 7856097..bdcdc7e 100644 --- a/PHP-Minify-Lib/Minify/ClosureCompiler.php +++ b/PHP-Minify-Lib/Minify/ClosureCompiler.php @@ -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); diff --git a/PHP-Minify-Lib/Minify/Controller/MinApp.php b/PHP-Minify-Lib/Minify/Controller/MinApp.php index 90268df..6943ee6 100644 --- a/PHP-Minify-Lib/Minify/Controller/MinApp.php +++ b/PHP-Minify-Lib/Minify/Controller/MinApp.php @@ -20,6 +20,13 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { * @return array Minify options */ public function setupSources($options) { + // PHP insecure by default: realpath() and other FS functions can't handle null bytes. + foreach (array('g', 'b', 'f') as $key) { + if (isset($_GET[$key])) { + $_GET[$key] = str_replace("\x00", '', (string)$_GET[$key]); + } + } + // filter controller options $cOptions = array_merge( array( @@ -34,12 +41,7 @@ public function setupSources($options) { $sources = array(); $this->selectionId = ''; $firstMissingResource = null; - if (isset($_GET['g'])) { - if (! is_string($_GET['g'])) { - $this->log("GET param 'g' was invalid"); - return $options; - } // add group(s) $this->selectionId .= 'g=' . $_GET['g']; $keys = explode(',', $_GET['g']); @@ -94,10 +96,6 @@ public function setupSources($options) { } } if (! $cOptions['groupsOnly'] && isset($_GET['f'])) { - if (! is_string($_GET['f'])) { - $this->log("GET param 'f' was invalid"); - return $options; - } // try user files // The following restrictions are to limit the URLs that minify will // respond to. @@ -126,8 +124,7 @@ public function setupSources($options) { } if (isset($_GET['b'])) { // check for validity - if (is_string($_GET['b']) - && preg_match('@^[^/]+(?:/[^/]+)*$@', $_GET['b']) + if (preg_match('@^[^/]+(?:/[^/]+)*$@', $_GET['b']) && false === strpos($_GET['b'], '..') && $_GET['b'] !== '.') { // valid base diff --git a/PHP-Minify-Lib/Minify/Controller/Version1.php b/PHP-Minify-Lib/Minify/Controller/Version1.php index 120d28b..91fcf61 100644 --- a/PHP-Minify-Lib/Minify/Controller/Version1.php +++ b/PHP-Minify-Lib/Minify/Controller/Version1.php @@ -24,6 +24,11 @@ class Minify_Controller_Version1 extends Minify_Controller_Base { * */ public function setupSources($options) { + // PHP insecure by default: realpath() and other FS functions can't handle null bytes. + if (isset($_GET['files'])) { + $_GET['files'] = str_replace("\x00", '', (string)$_GET['files']); + } + self::_setupDefines(); if (MINIFY_USE_CACHE) { $cacheDir = defined('MINIFY_CACHE_DIR') @@ -49,8 +54,7 @@ public function setupSources($options) { ) { return $options; } - $extension = $m[1]; - + $files = explode(',', $_GET['files']); if (count($files) > MINIFY_MAX_FILES) { return $options; @@ -61,7 +65,6 @@ public function setupSources($options) { . DIRECTORY_SEPARATOR; $prependAbsPaths = $_SERVER['DOCUMENT_ROOT']; - $sources = array(); $goodFiles = array(); $hasBadSource = false; diff --git a/PHP-Minify-Lib/Minify/HTML.php b/PHP-Minify-Lib/Minify/HTML.php index da356dd..40f7307 100644 --- a/PHP-Minify-Lib/Minify/HTML.php +++ b/PHP-Minify-Lib/Minify/HTML.php @@ -63,8 +63,6 @@ public static function minify($html, $options = array()) { * * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If * unset, minify will sniff for an XHTML doctype. - * - * @return null */ public function __construct($html, $options = array()) { @@ -133,7 +131,7 @@ public function process() // remove ws around block/undisplayed elements $this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body' - .'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form' + .'|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); diff --git a/PHP-Minify-Lib/Minify/JS/ClosureCompiler.php b/PHP-Minify-Lib/Minify/JS/ClosureCompiler.php index 51f7cd1..e067d7c 100644 --- a/PHP-Minify-Lib/Minify/JS/ClosureCompiler.php +++ b/PHP-Minify-Lib/Minify/JS/ClosureCompiler.php @@ -14,13 +14,68 @@ * @todo can use a stream wrapper to unit test this? */ class Minify_JS_ClosureCompiler { - const URL = 'http://closure-compiler.appspot.com/compile'; /** - * Minify Javascript code via HTTP request to the Closure Compiler API + * @var string The option key for the maximum POST byte size + */ + const OPTION_MAX_BYTES = 'maxBytes'; + + /** + * @var string The option key for additional params. @see __construct + */ + const OPTION_ADDITIONAL_OPTIONS = 'additionalParams'; + + /** + * @var string The option key for the fallback Minifier + */ + const OPTION_FALLBACK_FUNCTION = 'fallbackFunc'; + + /** + * @var string The option key for the service URL + */ + const OPTION_COMPILER_URL = 'compilerUrl'; + + /** + * @var int The default maximum POST byte size according to https://developers.google.com/closure/compiler/docs/api-ref + */ + const DEFAULT_MAX_BYTES = 200000; + + /** + * @var string[] $DEFAULT_OPTIONS The default options to pass to the compiler service + * + * @note This would be a constant if PHP allowed it + */ + private static $DEFAULT_OPTIONS = array( + 'output_format' => 'text', + 'compilation_level' => 'SIMPLE_OPTIMIZATIONS' + ); + + /** + * @var string $url URL of compiler server. defaults to Google's + */ + protected $serviceUrl = 'http://closure-compiler.appspot.com/compile'; + + /** + * @var int $maxBytes The maximum JS size that can be sent to the compiler server in bytes + */ + protected $maxBytes = self::DEFAULT_MAX_BYTES; + + /** + * @var string[] $additionalOptions Additional options to pass to the compiler service + */ + protected $additionalOptions = array(); + + /** + * @var callable Function to minify JS if service fails. Default is JSMin + */ + protected $fallbackMinifier = array('JSMin', 'minify'); + + /** + * Minify JavaScript code via HTTP request to a Closure Compiler API * * @param string $js input code - * @param array $options unused at this point + * @param array $options Options passed to __construct(). @see __construct + * * @return string */ public static function minify($js, array $options = array()) @@ -30,53 +85,91 @@ public static function minify($js, array $options = array()) } /** + * @param array $options Options with keys available below: * - * @param array $options + * fallbackFunc : (callable) function to minify if service unavailable. Default is JSMin. * - * fallbackFunc : default array($this, 'fallback'); + * compilerUrl : (string) URL to closure compiler server + * + * maxBytes : (int) The maximum amount of bytes to be sent as js_code in the POST request. + * Defaults to 200000. + * + * additionalParams : (string[]) Additional parameters to pass to the compiler server. Can be anything named + * in https://developers.google.com/closure/compiler/docs/api-ref except for js_code and + * output_info */ public function __construct(array $options = array()) { - $this->_fallbackFunc = isset($options['fallbackMinifier']) - ? $options['fallbackMinifier'] - : array($this, '_fallback'); + if (isset($options[self::OPTION_FALLBACK_FUNCTION])) { + $this->fallbackMinifier = $options[self::OPTION_FALLBACK_FUNCTION]; + } + if (isset($options[self::OPTION_COMPILER_URL])) { + $this->serviceUrl = $options[self::OPTION_COMPILER_URL]; + } + if (isset($options[self::OPTION_ADDITIONAL_OPTIONS]) && is_array($options[self::OPTION_ADDITIONAL_OPTIONS])) { + $this->additionalOptions = $options[self::OPTION_ADDITIONAL_OPTIONS]; + } + if (isset($options[self::OPTION_MAX_BYTES])) { + $this->maxBytes = (int) $options[self::OPTION_MAX_BYTES]; + } } + /** + * Call the service to perform the minification + * + * @param string $js JavaScript code + * @return string + * @throws Minify_JS_ClosureCompiler_Exception + */ public function min($js) { - $postBody = $this->_buildPostBody($js); - $bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) - ? mb_strlen($postBody, '8bit') - : strlen($postBody); - if ($bytes > 200000) { - throw new Minify_JS_ClosureCompiler_Exception( - 'POST content larger than 200000 bytes' - ); + $postBody = $this->buildPostBody($js); + + if ($this->maxBytes > 0) { + $bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) + ? mb_strlen($postBody, '8bit') + : strlen($postBody); + if ($bytes > $this->maxBytes) { + throw new Minify_JS_ClosureCompiler_Exception( + 'POST content larger than ' . $this->maxBytes . ' bytes' + ); + } } - $response = $this->_getResponse($postBody); + + $response = $this->getResponse($postBody); + if (preg_match('/^Error\(\d\d?\):/', $response)) { - if (is_callable($this->_fallbackFunc)) { + if (is_callable($this->fallbackMinifier)) { + // use fallback $response = "/* Received errors from Closure Compiler API:\n$response" . "\n(Using fallback minifier)\n*/\n"; - $response .= call_user_func($this->_fallbackFunc, $js); + $response .= call_user_func($this->fallbackMinifier, $js); } else { throw new Minify_JS_ClosureCompiler_Exception($response); } } + if ($response === '') { - $errors = $this->_getResponse($this->_buildPostBody($js, true)); + $errors = $this->getResponse($this->buildPostBody($js, true)); throw new Minify_JS_ClosureCompiler_Exception($errors); } + return $response; } - protected $_fallbackFunc = null; - - protected function _getResponse($postBody) + /** + * Get the response for a given POST body + * + * @param string $postBody + * @return string + * @throws Minify_JS_ClosureCompiler_Exception + */ + protected function getResponse($postBody) { $allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen')); + if ($allowUrlFopen) { - $contents = file_get_contents(self::URL, false, stream_context_create(array( + $contents = file_get_contents($this->serviceUrl, false, stream_context_create(array( 'http' => array( 'method' => 'POST', 'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close\r\n", @@ -86,7 +179,7 @@ protected function _getResponse($postBody) ) ))); } elseif (defined('CURLOPT_POST')) { - $ch = curl_init(self::URL); + $ch = curl_init($this->serviceUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded')); @@ -100,32 +193,37 @@ protected function _getResponse($postBody) "Could not make HTTP request: allow_url_open is false and cURL not available" ); } + if (false === $contents) { throw new Minify_JS_ClosureCompiler_Exception( "No HTTP response from server" ); } - return trim($contents); - } - protected function _buildPostBody($js, $returnErrors = false) - { - return http_build_query(array( - 'js_code' => $js, - 'output_info' => ($returnErrors ? 'errors' : 'compiled_code'), - 'output_format' => 'text', - 'compilation_level' => 'SIMPLE_OPTIMIZATIONS' - ), null, '&'); + return trim($contents); } /** - * Default fallback function if CC API fails - * @param string $js + * Build a POST request body + * + * @param string $js JavaScript code + * @param bool $returnErrors * @return string */ - protected function _fallback($js) + protected function buildPostBody($js, $returnErrors = false) { - return JSMin::minify($js); + return http_build_query( + array_merge( + self::$DEFAULT_OPTIONS, + $this->additionalOptions, + array( + 'js_code' => $js, + 'output_info' => ($returnErrors ? 'errors' : 'compiled_code') + ) + ), + null, + '&' + ); } } diff --git a/PHP-Minify-Lib/Minify/YUICompressor.php b/PHP-Minify-Lib/Minify/YUICompressor.php index 8e6bfcb..5762e89 100644 --- a/PHP-Minify-Lib/Minify/YUICompressor.php +++ b/PHP-Minify-Lib/Minify/YUICompressor.php @@ -90,7 +90,7 @@ private static function _minify($type, $content, $options) { self::_prepare(); if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) { - throw new Exception('Minify_YUICompressor : could not create temp file.'); + throw new Exception('Minify_YUICompressor : could not create temp file in "'.self::$tempDir.'".'); } file_put_contents($tmpFile, $content); exec(self::_getCmd($options, $type, $tmpFile), $output, $result_code);