mirror of
https://github.com/mrclay/minify.git
synced 2025-08-09 15:46:34 +02:00
+ URI rewriter in CSS min, fix for protocol-relative URIs, + partial minify.php compatibility
This commit is contained in:
@@ -55,34 +55,6 @@ class Minify {
|
||||
: $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a controller instance and handle the request
|
||||
*
|
||||
* @param string type This should be the filename of the controller without
|
||||
* extension. e.g. 'Group'
|
||||
*
|
||||
* @param array $ctrlOptions options for the controller's constructor
|
||||
*
|
||||
* @param array $minOptions options passed on to Minify
|
||||
*
|
||||
* @return mixed false on failure or array of content and headers sent
|
||||
*/
|
||||
public static function serveold($type, $ctrlOptions = array(), $minOptions = array()) {
|
||||
$class = 'Minify_Controller_' . $type;
|
||||
if (! class_exists($class, false)) {
|
||||
require_once "Minify/Controller/{$type}.php";
|
||||
}
|
||||
$ctrl = new $class($ctrlOptions, $minOptions);
|
||||
$ret = self::handleRequest($ctrl);
|
||||
if (false === $ret) {
|
||||
if (! isset($ctrl->minOptions['quiet']) || ! $ctrl->minOptions['quiet']) {
|
||||
header("HTTP/1.0 400 Bad Request");
|
||||
exit('400 Bad Request');
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve a request for a minified file.
|
||||
*
|
||||
@@ -219,7 +191,7 @@ class Minify {
|
||||
// add headers to those from ConditionalGet
|
||||
//$headers['Content-Length'] = strlen($content);
|
||||
$headers['Content-Type'] = (null !== self::$_options['contentTypeCharset'])
|
||||
? self::$_options['contentType'] . ';charset=' . self::$_options['contentTypeCharset']
|
||||
? self::$_options['contentType'] . '; charset=' . self::$_options['contentTypeCharset']
|
||||
: self::$_options['contentType'];
|
||||
if (self::$_options['encodeMethod'] !== '') {
|
||||
$headers['Content-Encoding'] = $contentEncoding;
|
||||
|
@@ -64,15 +64,21 @@ class Minify_CSS {
|
||||
$css = preg_replace('/#([a-f\\d])\\1([a-f\\d])\\2([a-f\\d])\\3([\\s;\\}])/i'
|
||||
, '#$1$2$3$4', $css);
|
||||
|
||||
$rewrite = false;
|
||||
if (isset($options['prependRelativePath'])) {
|
||||
self::$_tempPrepend = $options['prependRelativePath'];
|
||||
$rewrite = true;
|
||||
} elseif (isset($options['currentPath'])) {
|
||||
self::$_tempCurrentPath = $options['currentPath'];
|
||||
$rewrite = true;
|
||||
}
|
||||
if ($rewrite) {
|
||||
$css = preg_replace_callback('/@import ([\'"])(.*?)[\'"]\\s*;/'
|
||||
,array('Minify_CSS', '_urlCB'), $css);
|
||||
|
||||
$css = preg_replace_callback('/url\\(([^\\)]+)\\)/'
|
||||
,array('Minify_CSS', '_urlCB'), $css);
|
||||
}
|
||||
|
||||
self::$_tempPrepend = self::$_tempCurrentPath = '';
|
||||
return trim($css);
|
||||
}
|
||||
|
||||
@@ -88,6 +94,11 @@ class Minify_CSS {
|
||||
*/
|
||||
private static $_tempPrepend = '';
|
||||
|
||||
/**
|
||||
* @var string path of this stylesheet for rewriting purposes
|
||||
*/
|
||||
private static $_tempCurrentPath = '';
|
||||
|
||||
/**
|
||||
* Process what looks like a comment and return a replacement
|
||||
*
|
||||
@@ -157,17 +168,24 @@ class Minify_CSS {
|
||||
? $m[1]
|
||||
: substr($m[1], 1, strlen($m[1]) - 2);
|
||||
}
|
||||
if ('/' === $url[0]) {
|
||||
if ('/' === $url[1]) {
|
||||
// protocol relative URI!
|
||||
$url = '//' . self::$_tempPrepend . substr($url, 2);
|
||||
}
|
||||
} else {
|
||||
if ('/' !== $url[0]) {
|
||||
if (strpos($url, '//') > 0) {
|
||||
// probably starts with protocol, do not alter
|
||||
} else {
|
||||
// relative URI
|
||||
$url = self::$_tempPrepend . $url;
|
||||
// relative URI, rewrite!
|
||||
if (self::$_tempPrepend) {
|
||||
$url = self::$_tempPrepend . $url;
|
||||
} else {
|
||||
// rewrite absolute url from scratch!
|
||||
// prepend path with current dir separator (OS-independent)
|
||||
$path = self::$_tempCurrentPath
|
||||
. DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR);
|
||||
// strip doc root
|
||||
$path = substr($path, strlen($_SERVER['DOCUMENT_ROOT']));
|
||||
// fix to absolute URL
|
||||
$url = strtr($path, DIRECTORY_SEPARATOR, '/');
|
||||
$url = str_replace('/./', '/', $url);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($isImport) {
|
||||
|
@@ -88,6 +88,32 @@ abstract class Minify_Controller_Base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a user-given file within document root, existing,
|
||||
* and having an extension js/css/html/txt
|
||||
*
|
||||
* This is a convenience function for controllers that have to accept
|
||||
* user-given paths
|
||||
*
|
||||
* @param string $file full file path (already processed by realpath())
|
||||
* @param string $docRoot root where files are safe to serve
|
||||
* @return bool file is safe
|
||||
*/
|
||||
public static function _fileIsSafe($file, $docRoot)
|
||||
{
|
||||
if (strpos($file, $docRoot) !== 0 || ! file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
$base = basename($file);
|
||||
if ($base[0] === '.') {
|
||||
return false;
|
||||
}
|
||||
list($revExt) = explode('.', strrev($base));
|
||||
return in_array(strrev($revExt), array('js', 'css', 'html', 'txt'));
|
||||
}
|
||||
|
||||
/*public static function _haveSameExt
|
||||
|
||||
/**
|
||||
* @var array instances of Minify_Source, which provide content and
|
||||
* any individual minification needs.
|
||||
@@ -125,7 +151,8 @@ abstract class Minify_Controller_Base {
|
||||
*
|
||||
* @return array options for Minify
|
||||
*/
|
||||
public final function analyzeSources($options = array()) {
|
||||
public final function analyzeSources($options = array())
|
||||
{
|
||||
if ($this->sources) {
|
||||
if (! isset($options['contentType'])) {
|
||||
$options['contentType'] = Minify_Source::getContentType($this->sources);
|
||||
|
@@ -113,9 +113,9 @@ class Minify_Source {
|
||||
public static function getContentType($sources)
|
||||
{
|
||||
$exts = array(
|
||||
'css' => 'text/css'
|
||||
,'js' => 'application/x-javascript'
|
||||
,'html' => 'text/html'
|
||||
'css' => Minify::TYPE_CSS
|
||||
,'js' => Minify::TYPE_JS
|
||||
,'html' => Minify::TYPE_HTML
|
||||
);
|
||||
foreach ($sources as $source) {
|
||||
if (null !== $source->_filepath) {
|
||||
|
@@ -1,9 +1,10 @@
|
||||
@import "foo.css";
|
||||
@import 'bar/foo.css';
|
||||
@import '/css/foo.css';
|
||||
@import 'http://foo.com/css/foo.css';
|
||||
@import url(./foo.css);
|
||||
@import url("/css/foo.css");
|
||||
@import url(/css2/foo.css);
|
||||
@import '/css/foo.css'; /* abs, should not alter */
|
||||
@import 'http://foo.com/css/foo.css'; /* abs, should not alter */
|
||||
@import url(../foo.css);
|
||||
@import url("/css/foo.css"); /* abs, should not alter */
|
||||
@import url(/css2/foo.css); /* abs, should not alter */
|
||||
foo {background:url('bar/foo.png')}
|
||||
foo {background:url('http://foo.com/css/foo.css');}
|
||||
foo {background:url('http://foo.com/css/foo.css');} /* abs, should not alter */
|
||||
foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */
|
2
web/test/css/paths.min.css
vendored
2
web/test/css/paths.min.css
vendored
@@ -1 +1 @@
|
||||
@import "../foo.css";@import '../bar/foo.css';@import '/css/foo.css';@import 'http://foo.com/css/foo.css';@import url(.././foo.css);@import url("/css/foo.css");@import url(/css2/foo.css);foo{background:url('../bar/foo.png')}foo{background:url('http://foo.com/css/foo.css')}
|
||||
@import "../foo.css";@import '../bar/foo.css';@import '/css/foo.css';@import 'http://foo.com/css/foo.css';@import url(../../foo.css);@import url("/css/foo.css");@import url(/css2/foo.css);foo{background:url('../bar/foo.png')}foo{background:url('http://foo.com/css/foo.css')}foo{background:url("//foo.com/css/foo.css")}
|
@@ -25,8 +25,8 @@ foreach ($list as $item) {
|
||||
|
||||
if ($minExpected !== $minOutput) {
|
||||
echo "\n---Source\n\n{$src}";
|
||||
echo "\n---Expected\n\n{$minExpected}";
|
||||
echo "\n---Output\n\n{$minOutput}\n\n\n\n";
|
||||
echo "\n\n---Expected\n\n{$minExpected}";
|
||||
echo "\n\n---Output\n\n{$minOutput}\n\n\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
99
web/version1/minify.php
Normal file
99
web/version1/minify.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
//define('MINIFY_BASE_DIR', realpath($_SERVER['DOCUMENT_ROOT'] . '/_3rd_party'));
|
||||
|
||||
require '../config.php'; // just to set include_path
|
||||
require 'Minify.php';
|
||||
require 'Minify/Controller/Base.php';
|
||||
|
||||
if (!defined('MINIFY_BASE_DIR')) {
|
||||
// files cannot be served above this
|
||||
define('MINIFY_BASE_DIR', realpath($_SERVER['DOCUMENT_ROOT']));
|
||||
}
|
||||
if (!defined('MINIFY_CACHE_DIR')) {
|
||||
define('MINIFY_CACHE_DIR', sys_get_temp_dir());
|
||||
}
|
||||
if (!defined('MINIFY_ENCODING')) {
|
||||
define('MINIFY_ENCODING', 'utf-8');
|
||||
}
|
||||
if (!defined('MINIFY_MAX_FILES')) {
|
||||
define('MINIFY_MAX_FILES', 16);
|
||||
}
|
||||
if (!defined('MINIFY_REWRITE_CSS_URLS')) {
|
||||
define('MINIFY_REWRITE_CSS_URLS', true);
|
||||
}
|
||||
if (!defined('MINIFY_USE_CACHE')) {
|
||||
define('MINIFY_USE_CACHE', true);
|
||||
}
|
||||
|
||||
class V1Controller extends Minify_Controller_Base {
|
||||
|
||||
// setup $this->sources and return $options
|
||||
public function setupSources($options) {
|
||||
$options['badRequestHeader'] = 'HTTP/1.0 404 Not Found';
|
||||
$options['contentTypeCharset'] = MINIFY_ENCODING;
|
||||
|
||||
// The following restrictions are to limit the URLs that minify will
|
||||
// respond to. Ideally there should be only one way to reference a file.
|
||||
if (! isset($_GET['files'])
|
||||
// verify at least one file, files are single comma separated,
|
||||
// and are all same extension
|
||||
|| ! preg_match('/^[^,]+\\.(css|js)(,[^,]+\\.\\1)*$/', $_GET['files'], $m)
|
||||
// no "//" (makes URL rewriting easier)
|
||||
|| strpos($_GET['files'], '//') !== false
|
||||
// no "\"
|
||||
|| strpos($_GET['files'], '\\') !== false
|
||||
// no "./"
|
||||
|| preg_match('/(?:^|[^\\.])\\.\\//', $_GET['files'])
|
||||
) {
|
||||
return $options;
|
||||
}
|
||||
$extension = $m[1];
|
||||
|
||||
$files = explode(',', $_GET['files']);
|
||||
if (count($files) > MINIFY_MAX_FILES) {
|
||||
return $options;
|
||||
}
|
||||
|
||||
// strings for prepending to relative/absolute paths
|
||||
$prependRelPaths = dirname($_SERVER['SCRIPT_FILENAME'])
|
||||
. DIRECTORY_SEPARATOR;
|
||||
$prependAbsPaths = $_SERVER['DOCUMENT_ROOT'];
|
||||
|
||||
$sources = array();
|
||||
$goodFiles = array();
|
||||
$hasBadSource = false;
|
||||
foreach ($files as $file) {
|
||||
// prepend appropriate string for abs/rel paths
|
||||
$file = ($file[0] === '/' ? $prependAbsPaths : $prependRelPaths) . $file;
|
||||
// make sure a real file!
|
||||
$file = realpath($file);
|
||||
// don't allow unsafe or duplicate files
|
||||
if (parent::_fileIsSafe($file, MINIFY_BASE_DIR)
|
||||
&& !in_array($file, $goodFiles))
|
||||
{
|
||||
$goodFiles[] = $file;
|
||||
$srcOptions = array(
|
||||
'filepath' => $file
|
||||
);
|
||||
if ('css' === $extension && MINIFY_REWRITE_CSS_URLS) {
|
||||
$srcOptions['minifyOptions']['currentPath'] = dirname($file);
|
||||
}
|
||||
$this->sources[] = new Minify_Source($srcOptions);
|
||||
} else {
|
||||
$hasBadSource = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($hasBadSource) {
|
||||
$this->sources = array();
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
||||
$v1 = new V1Controller();
|
||||
if (MINIFY_USE_CACHE) {
|
||||
Minify::useServerCache(MINIFY_CACHE_DIR);
|
||||
}
|
||||
Minify::serve($v1);
|
Reference in New Issue
Block a user