1
0
mirror of https://github.com/mrclay/minify.git synced 2025-01-17 21:28:14 +01:00

More work on HTML helpers

This commit is contained in:
Steve Clay 2010-05-17 02:30:51 +00:00
parent b41a908dbf
commit f2ebbeb526
5 changed files with 202 additions and 180 deletions

View File

@ -13,25 +13,46 @@
class Minify_HTML_Helper {
public $rewriteWorks = true;
public $minAppUri = '/min';
public $groupsConfigFile = '';
public static function groupUri($key, $farExpires = true, $debug = false, $charset = 'UTF-8')
/*
* Get an HTML-escaped Minify URI for a group or set of files
*
* @param mixed $keyOrFiles a group key or array of filepaths/URIs
* @param array $opts options:
* 'farExpires' : (default true) append a modified timestamp for cache revving
* 'debug' : (default false) append debug flag
* 'charset' : (default 'UTF-8') for htmlspecialchars
* 'minAppUri' : (default '/min') URI of min directory
* 'rewriteWorks' : (default true) does mod_rewrite work in min app?
* 'groupsConfigFile' : specify if different
* @return string
*/
public static function getUri($keyOrFiles, $opts = array())
{
$opts = array_merge(array( // default options
'farExpires' => true
,'debug' => false
,'charset' => 'UTF-8'
,'minAppUri' => '/min'
,'rewriteWorks' => true
,'groupsConfigFile' => ''
), $opts);
$h = new self;
$h->setGroup($key, $farExpires);
$uri = $h->getRawUri($farExpires, $debug);
return htmlspecialchars($uri, ENT_QUOTES, $charset);
}
public static function filesUri($files, $farExpires = true, $debug = false, $charset = 'UTF-8')
{
$h = new self;
$h->setFiles($files, $farExpires);
$uri = $h->getRawUri($farExpires, $debug);
return htmlspecialchars($uri, ENT_QUOTES, $charset);
$h->minAppUri = $opts['minAppUri'];
$h->rewriteWorks = $opts['rewriteWorks'];
$h->groupsConfigFile = $opts['groupsConfigFile'];
if (is_array($keyOrFiles)) {
$h->setFiles($keyOrFiles, $opts['farExpires']);
} else {
$h->setGroup($keyOrFiles, $opts['farExpires']);
}
$uri = $h->getRawUri($opts['farExpires'], $opts['debug']);
return htmlspecialchars($uri, ENT_QUOTES, $opts['charset']);
}
/*
* Get URI (not html-escaped) to minify a group/set of files
* Get non-HTML-escaped URI to minify the specified files
*/
public function getRawUri($farExpires = true, $debug = false)
{
@ -41,7 +62,7 @@ class Minify_HTML_Helper {
}
if (null === $this->_groupKey) {
// @todo: implement shortest uri
$path .= "f=" . $this->_fileList;
$path = self::_getShortestUri($this->_filePaths, $path);
} else {
$path .= "g=" . $this->_groupKey;
}
@ -57,7 +78,7 @@ class Minify_HTML_Helper {
{
$this->_groupKey = null;
if ($checkLastModified) {
$this->_sniffLastModified($files);
$this->_lastModified = self::getLastModified($files);
}
// normalize paths like in /min/f=<paths>
foreach ($files as $k => $file) {
@ -70,51 +91,30 @@ class Minify_HTML_Helper {
$file = strtr($file, '\\', '/');
$files[$k] = $file;
}
$this->_fileList = implode(',', $files);
$this->_filePaths = $files;
}
public function setGroup($key, $checkLastModified = true)
{
$this->_groupKey = $key;
if ($checkLastModified) {
$gcFile = (null === $this->_groupsConfigFile)
? dirname(dirname(dirname(dirname(__FILE__)))) . '/groupsConfig.php'
: $this->_groupsConfigFile;
if (is_file($gcFile)) {
$gc = (require $gcFile);
if (! $this->groupsConfigFile) {
$this->groupsConfigFile = dirname(dirname(dirname(dirname(__FILE__)))) . '/groupsConfig.php';
}
if (is_file($this->groupsConfigFile)) {
$gc = (require $this->groupsConfigFile);
if (isset($gc[$key])) {
$this->_sniffLastModified($gc[$key]);
$this->_lastModified = self::getLastModified($gc[$key]);
}
}
}
}
public function setPathToMin($path)
public static function getLastModified($sources, $lastModified = 0)
{
if (0 === strpos($path, '.')) {
// relative path
$path = dirname(__FILE__) . "/" . $path;
}
$file = realpath(rtrim($path, '/\\') . '/groupsConfig.php');
if (! $file) {
return false;
}
$this->_groupsConfigFile = $file;
return true;
}
protected $_groupKey = null; // if present, URI will be like g=...
protected $_fileList = '';
protected $_groupsConfigArray = array();
protected $_groupsConfigFile = null;
protected $_lastModified = null;
protected function _sniffLastModified($sources)
{
$max = 0;
$max = $lastModified;
foreach ((array)$sources as $source) {
if ($source instanceof Minify_Source) {
if (is_object($source) && isset($source->lastModified)) {
$max = max($max, $source->lastModified);
} elseif (is_string($source)) {
if (0 === strpos($source, '//')) {
@ -125,14 +125,20 @@ class Minify_HTML_Helper {
}
}
}
$this->_lastModified = $max;
return $max;
}
protected $_groupKey = null; // if present, URI will be like g=...
protected $_filePaths = array();
protected $_lastModified = null;
/**
* In a given array of strings, find the character they all have at
* a particular index
* @param Array arr array of strings
* @param Number pos index to check
*
* @param array $arr array of strings
* @param int $pos index to check
* @return mixed a common char or '' if any do not match
*/
protected static function _getCommonCharAtPos($arr, $pos) {
@ -140,7 +146,7 @@ class Minify_HTML_Helper {
$c = $arr[0][$pos];
if ($c === '' || $l === 1)
return $c;
for ($i = 1; $i < l; ++$i)
for ($i = 1; $i < $l; ++$i)
if ($arr[$i][$pos] !== $c)
return '';
return $c;
@ -148,37 +154,40 @@ class Minify_HTML_Helper {
/**
* Get the shortest URI to minify the set of source files
* @param Array sources URIs
*//*
,getBestUri : function (sources) {
var pos = 0
,base = ''
,c;
*
* @param array $paths root-relative URIs of files
* @param string $minRoot root-relative URI of the "min" application
*/
protected static function _getShortestUri($paths, $minRoot = '/min/') {
$pos = 0;
$base = '';
$c;
while (true) {
c = MUB.getCommonCharAtPos(sources, pos);
if (c === '')
$c = self::_getCommonCharAtPos($paths, $pos);
if ($c === '') {
break;
else
base += c;
++pos;
}
base = base.replace(/[^\/]+$/, '');
var uri = MUB._minRoot + 'f=' + sources.join(',');
if (base.charAt(base.length - 1) === '/') {
// we have a base dir!
var basedSources = sources
,i
,l = sources.length;
for (i = 0; i < l; ++i) {
basedSources[i] = sources[i].substr(base.length);
} else {
$base .= $c;
}
base = base.substr(0, base.length - 1);
var bUri = MUB._minRoot + 'b=' + base + '&f=' + basedSources.join(',');
//window.console && console.log([uri, bUri]);
uri = uri.length < bUri.length
? uri
: bUri;
++$pos;
}
return uri;
}//*/
$base = preg_replace('@[^/]+$@', '', $base);
$uri = $minRoot . 'f=' . implode(',', $paths);
if (substr($base, -1) === '/') {
// we have a base dir!
$basedPaths = $paths;
$l = count($paths);
for ($i = 0; $i < $l; ++$i) {
$basedPaths[$i] = substr($paths[$i], strlen($base));
}
$base = substr($base, 0, strlen($base) - 1);
$bUri = $minRoot . 'b=' . $base . '&f=' . implode(',', $basedPaths);
$uri = strlen($uri) < strlen($bUri)
? $uri
: $bUri;
}
return $uri;
}
}

View File

@ -2,89 +2,73 @@
/**
* Utility functions for generating URIs in HTML files
*
* Before including this file, /min/lib must be in your include_path.
*
* @package Minify
*/
require_once 'Minify/Build.php';
require_once dirname(__FILE__) . '/lib/Minify/HTML/Helper.php';
/**
* Get a timestamped URI to a minified resource using the default Minify install
/*
* Get an HTML-escaped Minify URI for a group or set of files. By default, URIs
* will contain timestamps to allow far-future Expires headers.
*
* <code>
* <link rel="stylesheet" type="text/css" href="<?php echo Minify_groupUri('css'); ?>" />
* <script type="text/javascript" src="<?php echo Minify_groupUri('js'); ?>"></script>
* <link rel="stylesheet" type="text/css" href="<?= Minify_getUri('css'); ?>" />
* <script src="<?= Minify_getUri('js'); ?>"></script>
* <script src="<?= Minify_getUri(array(
* '//scripts/file1.js'
* ,'//scripts/file2.js'
* )); ?>"></script>
* </code>
*
* If you do not want ampersands as HTML entities, set Minify_Build::$ampersand = "&"
* before using this function.
*
* @param string $group a key from groupsConfig.php
* @param boolean $modRewriteWorking (default false) Set to true if the RewriteRule
* directives in .htaccess are functional. This will remove the "?" from URIs, making them
* more cacheable by proxies.
* @param mixed $keyOrFiles a group key or array of file paths/URIs
* @param array $opts options:
* 'farExpires' : (default true) append a modified timestamp for cache revving
* 'debug' : (default false) append debug flag
* 'charset' : (default 'UTF-8') for htmlspecialchars
* 'minAppUri' : (default '/min') URI of min directory
* 'rewriteWorks' : (default true) does mod_rewrite work in min app?
* 'groupsConfigFile' : specify if different
* @return string
*/
function Minify_groupUri($group, $modRewriteWorking = false)
{
$path = $modRewriteWorking
? "/g={$group}"
: "/?g={$group}";
return _Minify_getBuild($group)->uri(
'/' . basename(dirname(__FILE__)) . $path
,$modRewriteWorking
);
}
/**
* Get the last modification time of the source js/css files used by Minify to
* build the page.
*
* If you're caching the output of Minify_groupUri(), you'll want to rebuild
* the cache if it's older than this timestamp.
*
* <code>
* // simplistic HTML cache system
* $file = '/path/to/cache/file';
* if (! file_exists($file) || filemtime($file) < Minify_groupsMtime(array('js', 'css'))) {
* // (re)build cache
* $page = buildPage(); // this calls Minify_groupUri() for js and css
* file_put_contents($file, $page);
* echo $page;
* exit();
* }
* readfile($file);
* </code>
*
* @param array $groups an array of keys from groupsConfig.php
* @return int Unix timestamp of the latest modification
*/
function Minify_groupsMtime($groups)
{
$max = 0;
foreach ((array)$groups as $group) {
$max = max($max, _Minify_getBuild($group)->lastModified);
}
return $max;
}
/**
* @param string $group a key from groupsConfig.php
* @return Minify_Build
* @private
*/
function _Minify_getBuild($group)
function Minify_getUri($keyOrFiles, $opts = array())
{
static $builds = array();
static $gc = false;
if (false === $gc) {
$gc = (require dirname(__FILE__) . '/groupsConfig.php');
}
if (! isset($builds[$group])) {
$builds[$group] = new Minify_Build($gc[$group]);
}
return $builds[$group];
return Minify_HTML_Helper::getUri($keyOrFiles, $opts);
}
/**
* Get the last modification time of several source js/css files. If you're
* caching the output of Minify_getUri(), you might want to know if one of the
* dependent source files has changed so you can update the HTML.
*
* Since this makes a bunch of stat() calls, you might not want to check this
* on every request.
*
* @param array $keysAndFiles group keys and/or file paths/URIs.
* @return int latest modification time of all given keys/files
*/
function Minify_mtime($keysAndFiles, $groupsConfigFile = null)
{
$gc = null;
if (! $groupsConfigFile) {
$groupsConfigFile = dirname(__FILE__) . '/groupsConfig.php';
}
$sources = array();
foreach ($keysAndFiles as $keyOrFile) {
if (is_object($keyOrFile)
|| 0 === strpos($keyOrFile, '/')
|| 1 === strpos($keyOrFile, ':\\')) {
// a file/source obj
$sources[] = $keyOrFile;
} else {
if (! $gc) {
$gc = (require $groupsConfigFile);
}
foreach ($gc[$keyOrFile] as $source) {
$sources[] = $source;
}
}
}
return Minify_HTML_Helper::getLastModified($sources);
}

View File

@ -0,0 +1,8 @@
<?php
return array(
'css' => array(
'//_test_files/css/paths_prepend.css'
,'//_test_files/css/styles.css'
)
);

View File

@ -7,42 +7,62 @@ function test_Minify_HTML_Helper()
{
global $thisDir;
$realDocRoot = $_SERVER['DOCUMENT_ROOT'];
$_SERVER['DOCUMENT_ROOT'] = $thisDir;
$file1 = $thisDir . '/_test_files/css/paths_prepend.css';
$file2 = $thisDir . '/_test_files/css/styles.css';
$maxTime = max(filemtime($file1), filemtime($file2));
$path1 = '/' . dirname($_SERVER['SCRIPT_NAME']) . '/_test_files/css/paths_prepend.css';
$path2 = '/' . dirname($_SERVER['SCRIPT_NAME']) . '/_test_files/css/styles.css';
$uri1 = '//_test_files/css/paths_prepend.css';
$uri2 = '//_test_files/css/styles.css';
echo Minify_HTML_Helper::filesUri(array($path1, $path2)) . "\n";
echo Minify_HTML_Helper::filesUri(array($file1, $file2)) . "\n";
echo Minify_HTML_Helper::groupUri('notRealGroup') . "\n";
$expected = "/min/b=_test_files/css&amp;f=paths_prepend.css,styles.css&amp;{$maxTime}";
$actual = Minify_HTML_Helper::getUri(array($uri1, $uri2));
$passed = assertTrue($actual === $expected, 'Minify_HTML_Helper : given URIs');
$expected = "/min/b=_test_files/css&amp;f=paths_prepend.css,styles.css&amp;{$maxTime}";
$actual = Minify_HTML_Helper::getUri(array($file1, $file2));
$passed = assertTrue($actual === $expected, 'Minify_HTML_Helper : given filepaths');
//echo Minify_HTML_Helper::filesUri(array($file1, $file2));
$expected = "/min/g=notRealGroup&amp;debug";
$actual = Minify_HTML_Helper::getUri('notRealGroup', array('debug' => true));
$passed = assertTrue($actual === $expected, 'Minify_HTML_Helper : non-existent group & debug');
/*
$b = new Minify_Build($file1);
assertTrue($b->lastModified == filemtime($file1)
,'Minify_Build : single file path');
$b = new Minify_Build(array($file1, $file2));
assertTrue($maxTime == $b->lastModified
,'Minify_Build : multiple file paths');
require_once 'Minify.php';
$b = new Minify_Build(array(
$file1
,new Minify_Source(array('filepath' => $file2))
$expected = "/myApp/min/?g=css&amp;{$maxTime}";
$actual = Minify_HTML_Helper::getUri('css', array(
'rewriteWorks' => false
,'minAppUri' => '/myApp/min/'
,'groupsConfigFile' => $thisDir . '/_test_files/htmlHelper_groupsConfig.php'
));
assertTrue($maxTime == $b->lastModified
,'Minify_Build : file path and a Minify_Source');
assertTrue($b->uri('/path') == "/path?{$maxTime}"
,'Minify_Build : uri() with no querystring');
assertTrue($b->uri('/path?hello') == "/path?hello&amp;{$maxTime}"
,'Minify_Build : uri() with existing querystring');
//*/
$passed = assertTrue($actual === $expected, 'Minify_HTML_Helper : existing group');
$utilsFile = dirname(dirname(__FILE__)) . '/min/utils.php';
if (is_file($utilsFile)) {
require_once $utilsFile;
$fiveSecondsAgo = $_SERVER['REQUEST_TIME'] - 5;
$obj = new stdClass();
$obj->lastModified = $fiveSecondsAgo;
$output = Minify_mtime(array(
$uri1
,$uri2
,$obj
));
$passed = assertTrue($output === $fiveSecondsAgo, 'utils.php : Minify_mtime w/ files & obj');
$obj = new stdClass();
$obj->lastModified = strtotime('2000-01-01');
$output = Minify_mtime(array(
$obj
,'css'
), $thisDir . '/_test_files/htmlHelper_groupsConfig.php');
$passed = assertTrue($output === $maxTime, 'utils.php : Minify_mtime w/ obj & group');
}
$_SERVER['DOCUMENT_ROOT'] = $realDocRoot;
}
test_Minify_HTML_Helper();

View File

@ -2,6 +2,7 @@
require 'test_Minify.php';
require 'test_Minify_Build.php';
require 'test_Minify_HTML_Helper.php';
require 'test_Minify_Cache_APC.php';
require 'test_Minify_Cache_File.php';
require 'test_Minify_Cache_Memcache.php';