PluginProbe
WP Super Minify • Minify, Compress and Cache HTML, CSS & JavaScript / trunk
WP Super Minify • Minify, Compress and Cache HTML, CSS & JavaScript vtrunk
trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.4 1.5 1.5.1 1.6 2.0 2.0.1
wp-super-minify / includes / min / lib / Minify / HTML / Helper.php

Helper.php in WP Super Minify • Minify, Compress and Cache HTML, CSS & JavaScript trunk, at includes/min/lib/Minify/HTML/Helper.php

251 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Minify_HTML_Helper
4 * @package Minify
5 */
6
7 /**
8 * Helpers for writing Minify URIs into HTML
9 *
10 * @package Minify
11 * @author Stephen Clay <steve@mrclay.org>
12 */
13 class Minify_HTML_Helper
14 {
15 public $rewriteWorks = true;
16 public $minAppUri = '/min';
17 public $groupsConfigFile = '';
18
19 /**
20 * Get an HTML-escaped Minify URI for a group or set of files
21 *
22 * @param string|array $keyOrFiles a group key or array of filepaths/URIs
23 * @param array $opts options:
24 * 'farExpires' : (default true) append a modified timestamp for cache revving
25 * 'debug' : (default false) append debug flag
26 * 'charset' : (default 'UTF-8') for htmlspecialchars
27 * 'minAppUri' : (default '/min') URI of min directory
28 * 'rewriteWorks' : (default true) does mod_rewrite work in min app?
29 * 'groupsConfigFile' : specify if different
30 * @return string
31 */
32 public static function getUri($keyOrFiles, $opts = array())
33 {
34 $opts = array_merge(array( // default options
35 'farExpires' => true,
36 'debug' => false,
37 'charset' => 'UTF-8',
38 'minAppUri' => '/min',
39 'rewriteWorks' => true,
40 'groupsConfigFile' => self::app()->groupsConfigPath,
41 ), $opts);
42
43 $h = new self;
44 $h->minAppUri = $opts['minAppUri'];
45 $h->rewriteWorks = $opts['rewriteWorks'];
46 $h->groupsConfigFile = $opts['groupsConfigFile'];
47
48 if (is_array($keyOrFiles)) {
49 $h->setFiles($keyOrFiles, $opts['farExpires']);
50 } else {
51 $h->setGroup($keyOrFiles, $opts['farExpires']);
52 }
53 $uri = $h->getRawUri($opts['farExpires'], $opts['debug']);
54
55 return htmlspecialchars($uri, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, $opts['charset']);
56 }
57
58 /**
59 * Get non-HTML-escaped URI to minify the specified files
60 *
61 * @param bool $farExpires
62 * @param bool $debug
63 * @return string
64 */
65 public function getRawUri($farExpires = true, $debug = false)
66 {
67 $path = rtrim($this->minAppUri, '/') . '/';
68 if (! $this->rewriteWorks) {
69 $path .= '?';
70 }
71 if (null === $this->_groupKey) {
72 // @todo: implement shortest uri
73 $path = self::_getShortestUri($this->_filePaths, $path);
74 } else {
75 $path .= "g=" . $this->_groupKey;
76 }
77 if ($debug) {
78 $path .= "&debug";
79 } elseif ($farExpires && $this->_lastModified) {
80 $path .= "&" . $this->_lastModified;
81 }
82
83 return $path;
84 }
85
86 /**
87 * Set the files that will comprise the URI we're building
88 *
89 * @param array $files
90 * @param bool $checkLastModified
91 */
92 public function setFiles($files, $checkLastModified = true)
93 {
94 $this->_groupKey = null;
95 if ($checkLastModified) {
96 $this->_lastModified = self::getLastModified($files);
97 }
98 // normalize paths like in /min/f=<paths>
99 foreach ($files as $k => $file) {
100 if (0 === strpos($file, '//')) {
101 $file = substr($file, 2);
102 } elseif (0 === strpos($file, '/') || 1 === strpos($file, ':\\')) {
103 $file = substr($file, strlen(self::app()->env->getDocRoot()) + 1);
104 }
105 $file = strtr($file, '\\', '/');
106 $files[$k] = $file;
107 }
108 $this->_filePaths = $files;
109 }
110
111 /**
112 * Set the group of files that will comprise the URI we're building
113 *
114 * @param string $key
115 * @param bool $checkLastModified
116 */
117 public function setGroup($key, $checkLastModified = true)
118 {
119 $this->_groupKey = $key;
120 if ($checkLastModified) {
121 if (! $this->groupsConfigFile) {
122 $this->groupsConfigFile = self::app()->groupsConfigPath;
123 }
124 if (is_file($this->groupsConfigFile)) {
125 $gc = (require $this->groupsConfigFile);
126 $keys = explode(',', $key);
127 foreach ($keys as $key) {
128 if (!isset($gc[$key])) {
129 // this can happen if value is null
130 // which could be solved with array_filter
131 continue;
132 }
133
134 $this->_lastModified = self::getLastModified($gc[$key], $this->_lastModified);
135 }
136 }
137 }
138 }
139
140 /**
141 * Get the max(lastModified) of all files
142 *
143 * @param array|string $sources
144 * @param int $lastModified
145 * @return int
146 */
147 public static function getLastModified($sources, $lastModified = 0)
148 {
149 $max = $lastModified;
150 $factory = self::app()->sourceFactory;
151
152 /** @var Minify_Source $source */
153 foreach ((array)$sources as $source) {
154 $source = $factory->makeSource($source);
155 $max = max($max, $source->getLastModified());
156 }
157
158 return $max;
159 }
160
161 /**
162 * @param \Minify\App $app
163 * @return \Minify\App
164 * @internal
165 */
166 public static function app(?\Minify\App $app = null)
167 {
168 static $cached;
169 if ($app) {
170 $cached = $app;
171
172 return $app;
173 }
174 if ($cached === null) {
175 $cached = (require __DIR__ . '/../../../bootstrap.php');
176 }
177
178 return $cached;
179 }
180
181 protected $_groupKey = null; // if present, URI will be like g=...
182 protected $_filePaths = array();
183 protected $_lastModified = null;
184
185 /**
186 * In a given array of strings, find the character they all have at
187 * a particular index
188 *
189 * @param array $arr array of strings
190 * @param int $pos index to check
191 * @return mixed a common char or '' if any do not match
192 */
193 protected static function _getCommonCharAtPos($arr, $pos)
194 {
195 if (!isset($arr[0][$pos])) {
196 return '';
197 }
198 $c = $arr[0][$pos];
199 $l = count($arr);
200 if ($l === 1) {
201 return $c;
202 }
203 for ($i = 1; $i < $l; ++$i) {
204 if ($arr[$i][$pos] !== $c) {
205 return '';
206 }
207 }
208
209 return $c;
210 }
211
212 /**
213 * Get the shortest URI to minify the set of source files
214 *
215 * @param array $paths root-relative URIs of files
216 * @param string $minRoot root-relative URI of the "min" application
217 * @return string
218 */
219 protected static function _getShortestUri($paths, $minRoot = '/min/')
220 {
221 $pos = 0;
222 $base = '';
223 while (true) {
224 $c = self::_getCommonCharAtPos($paths, $pos);
225 if ($c === '') {
226 break;
227 } else {
228 $base .= $c;
229 }
230 ++$pos;
231 }
232 $base = preg_replace('@[^/]+$@', '', $base);
233 $uri = $minRoot . 'f=' . implode(',', $paths);
234
235 if (substr($base, -1) === '/') {
236 // we have a base dir!
237 $basedPaths = $paths;
238 $l = count($paths);
239 for ($i = 0; $i < $l; ++$i) {
240 $basedPaths[$i] = substr($paths[$i], strlen($base));
241 }
242 $base = substr($base, 0, strlen($base) - 1);
243 $bUri = $minRoot . 'b=' . $base . '&f=' . implode(',', $basedPaths);
244
245 $uri = strlen($uri) < strlen($bUri) ? $uri : $bUri;
246 }
247
248 return $uri;
249 }
250 }
251