1
0
mirror of https://github.com/mrclay/minify.git synced 2025-08-13 17:44:00 +02:00

Merge pull request #11 from SimonSimCity/master

Updated ImportProcessor to write relative for imported stuff like images
This commit is contained in:
Steve Clay
2011-11-23 07:26:28 -08:00
8 changed files with 319 additions and 265 deletions

View File

@@ -16,6 +16,7 @@
* *
* @package Minify * @package Minify
* @author Stephen Clay <steve@mrclay.org> * @author Stephen Clay <steve@mrclay.org>
* @author Simon Schick <simonsimcity@gmail.com>
*/ */
class Minify_ImportProcessor { class Minify_ImportProcessor {
@@ -32,17 +33,25 @@ class Minify_ImportProcessor {
// allows callback funcs to know the current directory // allows callback funcs to know the current directory
private $_currentDir = null; 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 // allows _importCB to write the fetched content back to the obj
private $_importedContent = ''; private $_importedContent = '';
private static $_isCss = null; private static $_isCss = null;
private function __construct($currentDir) /**
* @param String $currentDir
* @param String $previewsDir Is only used internally
*/
private function __construct($currentDir, $previewsDir = "")
{ {
$this->_currentDir = $currentDir; $this->_currentDir = $currentDir;
$this->_previewsDir = $previewsDir;
} }
private function _getContent($file) private function _getContent($file, $is_imported = false)
{ {
$file = realpath($file); $file = realpath($file);
if (! $file if (! $file
@@ -78,7 +87,8 @@ class Minify_ImportProcessor {
,$content ,$content
); );
if (self::$_isCss) { // You only need to rework the import-path if the script is imported
if (self::$_isCss && $is_imported) {
// rewrite remaining relative URIs // rewrite remaining relative URIs
$content = preg_replace_callback( $content = preg_replace_callback(
'/url\\(\\s*([^\\)\\s]+)\\s*\\)/' '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
@@ -111,13 +121,13 @@ class Minify_ImportProcessor {
$file = $this->_currentDir . DIRECTORY_SEPARATOR $file = $this->_currentDir . DIRECTORY_SEPARATOR
. strtr($url, '/', DIRECTORY_SEPARATOR); . strtr($url, '/', DIRECTORY_SEPARATOR);
} }
$obj = new Minify_ImportProcessor(dirname($file)); $obj = new Minify_ImportProcessor(dirname($file), $this->_currentDir);
$content = $obj->_getContent($file); $content = $obj->_getContent($file, true);
if ('' === $content) { if ('' === $content) {
// failed. leave in place for CSS, comment for JS // failed. leave in place for CSS, comment for JS
return self::$_isCss return self::$_isCss
? $m[0] ? $m[0]
: "/* Minify_ImportProcessor could not fetch '{$file}' */";; : "/* Minify_ImportProcessor could not fetch '{$file}' */";
} }
return (!self::$_isCss || preg_match('@(?:^$|\\ball\\b)@', $mediaList)) return (!self::$_isCss || preg_match('@(?:^$|\\ball\\b)@', $mediaList))
? $content ? $content
@@ -140,18 +150,67 @@ class Minify_ImportProcessor {
// prepend path with current dir separator (OS-independent) // prepend path with current dir separator (OS-independent)
$path = $this->_currentDir $path = $this->_currentDir
. DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR); . DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR);
// strip doc root // update the relative path by the directory of the file that imported this one
$path = substr($path, strlen(realpath($_SERVER['DOCUMENT_ROOT']))); $url = self::getPathDiff(realpath($this->_previewsDir), $path);
// fix to absolute URL
$url = strtr($path, '/\\', '//');
// remove /./ and /../ where possible
$url = str_replace('/./', '/', $url);
// inspired by patch from Oleg Cherniy
do {
$url = preg_replace('@/(?!\\.\\.?)[^/]+/\\.\\.@', '/', $url, 1, $changed);
} while ($changed);
} }
} }
return "url({$quote}{$url}{$quote})"; 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;
}
} }

View File

@@ -1,4 +1,4 @@
@import url(../css/styles.css); @import url(../../css/styles.css);
@import url(http://example.com/hello.css); @import url(http://example.com/hello.css);
adjacent foo { background: red url(/red.gif); } adjacent foo { background: red url(/red.gif); }
adjacent bar { background: url('../green.gif') } adjacent bar { background: url('../green.gif') }

View File

@@ -1,4 +1,5 @@
@import url(adjacent.css) screen; @import url(adjacent.css) screen;
@import "1/tv.css" tv, projection; @import "1/tv.css" tv, projection;
@import "../lib/css/example.css";
input foo { background: red url(/red.gif); } input foo { background: red url(/red.gif); }
input bar { background: url('../green.gif') } input bar { background: url('../green.gif') }

View File

@@ -34,17 +34,19 @@ h1 + p {
} }
@import url(http://example.com/hello.css); @import url(http://example.com/hello.css);
adjacent foo { background: red url(/red.gif); } adjacent foo { background: red url(/red.gif); }
adjacent bar { background: url('%TEST_FILES_URI%/green.gif') } adjacent bar { background: url('../green.gif') }
} }
@media tv,projection { @media tv,projection {
/* @import url('%TEST_FILES_URI%/importProcessor/1/bad.css') bad; */ /* @import url('1/bad.css') bad; */
adjacent2 foo { background: red url(/red.gif); } adjacent2 foo { background: red url(/red.gif); }
adjacent2 bar { background: url('%TEST_FILES_URI%/importProcessor/green.gif') } adjacent2 bar { background: url('green.gif') }
@import '../input.css'; @import '../input.css';
tv foo { background: red url(/red.gif); } tv foo { background: red url(/red.gif); }
tv bar { background: url('%TEST_FILES_URI%/importProcessor/green.gif') } tv bar { background: url('green.gif') }
} }
input.test bar { background: url('../lib/img/green.gif') }
input foo { background: red url(/red.gif); } input foo { background: red url(/red.gif); }
input bar { background: url('%TEST_FILES_URI%/green.gif') } input bar { background: url('../green.gif') }

View File

@@ -0,0 +1 @@
input.test bar { background: url('../img/green.gif') }

View File

@@ -10,19 +10,9 @@ function test_Minify_ImportProcessor()
$linDir = $thisDir . '/_test_files/importProcessor'; $linDir = $thisDir . '/_test_files/importProcessor';
$testFilesUri = substr( $expected = file_get_contents($linDir . '/css/output.css');
realpath($thisDir . '/_test_files')
,strlen(realpath($_SERVER['DOCUMENT_ROOT']))
);
$testFilesUri = str_replace('\\', '/', $testFilesUri);
$expected = str_replace( $actual = Minify_ImportProcessor::process($linDir . '/css/input.css');
'%TEST_FILES_URI%'
,$testFilesUri
,file_get_contents($linDir . '/output.css')
);
$actual = Minify_ImportProcessor::process($linDir . '/input.css');
$passed = assertTrue($expected === $actual, 'ImportProcessor'); $passed = assertTrue($expected === $actual, 'ImportProcessor');
@@ -34,11 +24,12 @@ function test_Minify_ImportProcessor()
} }
$expectedIncludes = array ( $expectedIncludes = array (
realpath($linDir . '/input.css') realpath($linDir . '/css/input.css')
,realpath($linDir . '/adjacent.css') ,realpath($linDir . '/css/adjacent.css')
,realpath($linDir . '/../css/styles.css') ,realpath($linDir . '/../css/styles.css')
,realpath($linDir . '/1/tv.css') ,realpath($linDir . '/css/1/tv.css')
,realpath($linDir . '/1/adjacent.css') ,realpath($linDir . '/css/1/adjacent.css')
,realpath($linDir . '/lib/css/example.css')
); );
$passed = assertTrue($expectedIncludes === Minify_ImportProcessor::$filesIncluded $passed = assertTrue($expectedIncludes === Minify_ImportProcessor::$filesIncluded