3 * Class Minify_HTML_Helper
8 * Helpers for writing Minfy URIs into HTML
11 * @author Stephen Clay <steve@mrclay.org>
13 class Minify_HTML_Helper {
14 public $rewriteWorks = true;
15 public $minAppUri = '/min';
16 public $groupsConfigFile = '';
19 * Get an HTML-escaped Minify URI for a group or set of files
21 * @param string|array $keyOrFiles a group key or array of filepaths/URIs
22 * @param array $opts options:
23 * 'farExpires' : (default true) append a modified timestamp for cache revving
24 * 'debug' : (default false) append debug flag
25 * 'charset' : (default 'UTF-8') for htmlspecialchars
26 * 'minAppUri' : (default '/min') URI of min directory
27 * 'rewriteWorks' : (default true) does mod_rewrite work in min app?
28 * 'groupsConfigFile' : specify if different
31 public static function getUri($keyOrFiles, $opts = array())
33 $opts = array_merge(array( // default options
37 ,'minAppUri' => '/min'
38 ,'rewriteWorks' => true
39 ,'groupsConfigFile' => ''
42 $h->minAppUri = $opts['minAppUri'];
43 $h->rewriteWorks = $opts['rewriteWorks'];
44 $h->groupsConfigFile = $opts['groupsConfigFile'];
45 if (is_array($keyOrFiles)) {
46 $h->setFiles($keyOrFiles, $opts['farExpires']);
48 $h->setGroup($keyOrFiles, $opts['farExpires']);
50 $uri = $h->getRawUri($opts['farExpires'], $opts['debug']);
51 return htmlspecialchars($uri, ENT_QUOTES, $opts['charset']);
55 * Get non-HTML-escaped URI to minify the specified files
57 * @param bool $farExpires
61 public function getRawUri($farExpires = true, $debug = false)
63 $path = rtrim($this->minAppUri, '/') . '/';
64 if (! $this->rewriteWorks) {
67 if (null === $this->_groupKey) {
68 // @todo: implement shortest uri
69 $path = self::_getShortestUri($this->_filePaths, $path);
71 $path .= "g=" . $this->_groupKey;
75 } elseif ($farExpires && $this->_lastModified) {
76 $path .= "&" . $this->_lastModified;
82 * Set the files that will comprise the URI we're building
85 * @param bool $checkLastModified
87 public function setFiles($files, $checkLastModified = true)
89 $this->_groupKey = null;
90 if ($checkLastModified) {
91 $this->_lastModified = self::getLastModified($files);
93 // normalize paths like in /min/f=<paths>
94 foreach ($files as $k => $file) {
95 if (0 === strpos($file, '//')) {
96 $file = substr($file, 2);
97 } elseif (0 === strpos($file, '/')
98 || 1 === strpos($file, ':\\')) {
99 $file = substr($file, strlen($_SERVER['DOCUMENT_ROOT']) + 1);
101 $file = strtr($file, '\\', '/');
104 $this->_filePaths = $files;
108 * Set the group of files that will comprise the URI we're building
111 * @param bool $checkLastModified
113 public function setGroup($key, $checkLastModified = true)
115 $this->_groupKey = $key;
116 if ($checkLastModified) {
117 if (! $this->groupsConfigFile) {
118 $this->groupsConfigFile = dirname(dirname(dirname(dirname(__FILE__)))) . '/groupsConfig.php';
120 if (is_file($this->groupsConfigFile)) {
121 $gc = (require $this->groupsConfigFile);
122 $keys = explode(',', $key);
123 foreach ($keys as $key) {
124 if (isset($gc[$key])) {
125 $this->_lastModified = self::getLastModified($gc[$key], $this->_lastModified);
133 * Get the max(lastModified) of all files
135 * @param array|string $sources
136 * @param int $lastModified
139 public static function getLastModified($sources, $lastModified = 0)
141 $max = $lastModified;
142 foreach ((array)$sources as $source) {
143 if (is_object($source) && isset($source->lastModified)) {
144 $max = max($max, $source->lastModified);
145 } elseif (is_string($source)) {
146 if (0 === strpos($source, '//')) {
147 $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1);
149 if (is_file($source)) {
150 $max = max($max, filemtime($source));
157 protected $_groupKey = null; // if present, URI will be like g=...
158 protected $_filePaths = array();
159 protected $_lastModified = null;
163 * In a given array of strings, find the character they all have at
166 * @param array $arr array of strings
167 * @param int $pos index to check
168 * @return mixed a common char or '' if any do not match
170 protected static function _getCommonCharAtPos($arr, $pos) {
171 if (!isset($arr[0][$pos])) {
179 for ($i = 1; $i < $l; ++$i) {
180 if ($arr[$i][$pos] !== $c) {
188 * Get the shortest URI to minify the set of source files
190 * @param array $paths root-relative URIs of files
191 * @param string $minRoot root-relative URI of the "min" application
194 protected static function _getShortestUri($paths, $minRoot = '/min/') {
198 $c = self::_getCommonCharAtPos($paths, $pos);
206 $base = preg_replace('@[^/]+$@', '', $base);
207 $uri = $minRoot . 'f=' . implode(',', $paths);
209 if (substr($base, -1) === '/') {
210 // we have a base dir!
211 $basedPaths = $paths;
213 for ($i = 0; $i < $l; ++$i) {
214 $basedPaths[$i] = substr($paths[$i], strlen($base));
216 $base = substr($base, 0, strlen($base) - 1);
217 $bUri = $minRoot . 'b=' . $base . '&f=' . implode(',', $basedPaths);
219 $uri = strlen($uri) < strlen($bUri)