PluginProbe
ezCache / 1.3.11
ezCache v1.3.11
2.6.5 2.6.4 2.6.2 2.6.3 2.6.1 2.6.0 2.5.6 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5 2.2.1 2.2.2 trunk 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.3 1.3.1 1.3.10 1.3.11 All 49 releases
ezcache / includes / ThirdParty / Minify_CSS_UriRewriter.php

Minify_CSS_UriRewriter.php in ezCache 1.3.11, at includes/ThirdParty/Minify_CSS_UriRewriter.php

361 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Upress\EzCache\ThirdParty;
3
4 /**
5 * Class Minify_CSS_UriRewriter
6 *
7 * @package Minify
8 */
9
10 /**
11 * Rewrite file-relative URIs as root-relative in CSS files
12 *
13 * @package Minify
14 * @author Stephen Clay <steve@mrclay.org>
15 */
16 class Minify_CSS_UriRewriter {
17
18 /**
19 * rewrite() and rewriteRelative() append debugging information here
20 *
21 * @var string
22 */
23 public static $debugText = '';
24
25 /**
26 * In CSS content, rewrite file relative URIs as root relative
27 *
28 * @param string $css
29 *
30 * @param string $currentDir The directory of the current CSS file.
31 *
32 * @param string $docRoot The document root of the web site in which
33 * the CSS file resides (default = $_SERVER['DOCUMENT_ROOT']).
34 *
35 * @param array $symlinks (default = array()) If the CSS file is stored in
36 * a symlink-ed directory, provide an array of link paths to
37 * target paths, where the link paths are within the document root. Because
38 * paths need to be normalized for this to work, use "//" to substitute
39 * the doc root in the link paths (the array keys). E.g.:
40 * <code>
41 * array('//symlink' => '/real/target/path') // unix
42 * array('//static' => 'D:\\staticStorage') // Windows
43 * </code>
44 *
45 * @return string
46 */
47 public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array())
48 {
49 self::$_docRoot = self::_realpath(
50 $docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT']
51 );
52 self::$_currentDir = self::_realpath($currentDir);
53 self::$_symlinks = array();
54
55 // normalize symlinks in order to map to link
56 foreach ($symlinks as $link => $target) {
57 $link = ($link === '//') ? self::$_docRoot : str_replace('//', self::$_docRoot . '/', $link);
58 $link = strtr($link, '/', DIRECTORY_SEPARATOR);
59
60 self::$_symlinks[$link] = self::_realpath($target);
61 }
62
63 self::$debugText .= "docRoot : " . self::$_docRoot . "\n"
64 . "currentDir : " . self::$_currentDir . "\n";
65 if (self::$_symlinks) {
66 self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n";
67 }
68 self::$debugText .= "\n";
69
70 $css = self::_trimUrls($css);
71
72 $css = self::_owlifySvgPaths($css);
73
74 // rewrite
75 $pattern = '/@import\\s+([\'"])(.*?)[\'"]/';
76 $css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
77
78 $pattern = '/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/';
79 $css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
80
81 $css = self::_unOwlify($css);
82
83 return $css;
84 }
85
86 /**
87 * In CSS content, prepend a path to relative URIs
88 *
89 * @param string $css
90 *
91 * @param string $path The path to prepend.
92 *
93 * @return string
94 */
95 public static function prepend($css, $path)
96 {
97 self::$_prependPath = $path;
98
99 $css = self::_trimUrls($css);
100
101 $css = self::_owlifySvgPaths($css);
102
103 // append
104 $pattern = '/@import\\s+([\'"])(.*?)[\'"]/';
105 $css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
106
107 $pattern = '/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/';
108 $css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
109
110 $css = self::_unOwlify($css);
111
112 self::$_prependPath = null;
113
114 return $css;
115 }
116
117 /**
118 * Get a root relative URI from a file relative URI
119 *
120 * <code>
121 * Minify_CSS_UriRewriter::rewriteRelative(
122 * '../img/hello.gif'
123 * , '/home/user/www/css' // path of CSS file
124 * , '/home/user/www' // doc root
125 * );
126 * // returns '/img/hello.gif'
127 *
128 * // example where static files are stored in a symlinked directory
129 * Minify_CSS_UriRewriter::rewriteRelative(
130 * 'hello.gif'
131 * , '/var/staticFiles/theme'
132 * , '/home/user/www'
133 * , array('/home/user/www/static' => '/var/staticFiles')
134 * );
135 * // returns '/static/theme/hello.gif'
136 * </code>
137 *
138 * @param string $uri file relative URI
139 *
140 * @param string $realCurrentDir realpath of the current file's directory.
141 *
142 * @param string $realDocRoot realpath of the site document root.
143 *
144 * @param array $symlinks (default = array()) If the file is stored in
145 * a symlink-ed directory, provide an array of link paths to
146 * real target paths, where the link paths "appear" to be within the document
147 * root. E.g.:
148 * <code>
149 * array('/home/foo/www/not/real/path' => '/real/target/path') // unix
150 * array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path') // Windows
151 * </code>
152 *
153 * @return string
154 */
155 public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array())
156 {
157 // prepend path with current dir separator (OS-independent)
158 $path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR);
159 $path .= DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR);
160
161 self::$debugText .= "file-relative URI : {$uri}\n"
162 . "path prepended : {$path}\n";
163
164 // "unresolve" a symlink back to doc root
165 foreach ($symlinks as $link => $target) {
166 if (0 === strpos($path, $target)) {
167 // replace $target with $link
168 $path = $link . substr($path, strlen($target));
169
170 self::$debugText .= "symlink unresolved : {$path}\n";
171
172 break;
173 }
174 }
175 // strip doc root
176 $path = substr($path, strlen($realDocRoot));
177
178 self::$debugText .= "docroot stripped : {$path}\n";
179
180 // fix to root-relative URI
181 $uri = strtr($path, '/\\', '//');
182 $uri = self::removeDots($uri);
183
184 self::$debugText .= "traversals removed : {$uri}\n\n";
185
186 return $uri;
187 }
188
189 /**
190 * Remove instances of "./" and "../" where possible from a root-relative URI
191 *
192 * @param string $uri
193 *
194 * @return string
195 */
196 public static function removeDots($uri)
197 {
198 $uri = str_replace('/./', '/', $uri);
199 // inspired by patch from Oleg Cherniy
200 do {
201 $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
202 } while ($changed);
203
204 return $uri;
205 }
206
207 /**
208 * Defines which class to call as part of callbacks, change this
209 * if you extend Minify_CSS_UriRewriter
210 *
211 * @var string
212 */
213 protected static $className = '\Upress\EzCache\ThirdParty\Minify_CSS_UriRewriter';
214
215 /**
216 * Get realpath with any trailing slash removed. If realpath() fails,
217 * just remove the trailing slash.
218 *
219 * @param string $path
220 *
221 * @return mixed path with no trailing slash
222 */
223 protected static function _realpath($path)
224 {
225 $realPath = realpath($path);
226 if ($realPath !== false) {
227 $path = $realPath;
228 }
229
230 return rtrim($path, '/\\');
231 }
232
233 /**
234 * Directory of this stylesheet
235 *
236 * @var string
237 */
238 private static $_currentDir = '';
239
240 /**
241 * DOC_ROOT
242 *
243 * @var string
244 */
245 private static $_docRoot = '';
246
247 /**
248 * directory replacements to map symlink targets back to their
249 * source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'
250 *
251 * @var array
252 */
253 private static $_symlinks = array();
254
255 /**
256 * Path to prepend
257 *
258 * @var string
259 */
260 private static $_prependPath = null;
261
262 /**
263 * @param string $css
264 *
265 * @return string
266 */
267 private static function _trimUrls($css)
268 {
269 $pattern = '/
270 url\\( # url(
271 \\s*
272 ([^\\)]+?) # 1 = URI (assuming does not contain ")")
273 \\s*
274 \\) # )
275 /x';
276
277 return preg_replace($pattern, 'url($1)', $css);
278 }
279
280 /**
281 * @param array $m
282 *
283 * @return string
284 */
285 private static function _processUriCB($m)
286 {
287 // $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
288 $isImport = ($m[0][0] === '@');
289 // determine URI and the quote character (if any)
290 if ($isImport) {
291 $quoteChar = $m[1];
292 $uri = $m[2];
293 } else {
294 // $m[1] is either quoted or not
295 $quoteChar = ($m[1][0] === "'" || $m[1][0] === '"') ? $m[1][0] : '';
296
297 $uri = ($quoteChar === '') ? $m[1] : substr($m[1], 1, strlen($m[1]) - 2);
298 }
299
300 if ($uri === '') {
301 return $m[0];
302 }
303
304 // if not root/scheme relative and not starts with scheme
305 if (!preg_match('~^(/|[a-z]+\:)~', $uri)) {
306 // URI is file-relative: rewrite depending on options
307 if (self::$_prependPath === null) {
308 $uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
309 } else {
310 $uri = self::$_prependPath . $uri;
311 if ($uri[0] === '/') {
312 $root = '';
313 $rootRelative = $uri;
314 $uri = $root . self::removeDots($rootRelative);
315 } elseif (preg_match('@^((https?\:)?//([^/]+))/@', $uri, $m) && (false !== strpos($m[3], '.'))) {
316 $root = $m[1];
317 $rootRelative = substr($uri, strlen($root));
318 $uri = $root . self::removeDots($rootRelative);
319 }
320 }
321 }
322
323 if ($isImport) {
324 return "@import {$quoteChar}{$uri}{$quoteChar}";
325 } else {
326 return "url({$quoteChar}{$uri}{$quoteChar})";
327 }
328 }
329
330 /**
331 * Mungs some inline SVG URL declarations so they won't be touched
332 *
333 * @link https://github.com/mrclay/minify/issues/517
334 * @see _unOwlify
335 *
336 * @param string $css
337 * @return string
338 */
339 private static function _owlifySvgPaths($css)
340 {
341 $pattern = '~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)url(\(\s*#\w+\s*\))~';
342
343 return preg_replace($pattern, '$1owl$2', $css);
344 }
345
346 /**
347 * Undo work of _owlify
348 *
349 * @see _owlifySvgPaths
350 *
351 * @param string $css
352 * @return string
353 */
354 private static function _unOwlify($css)
355 {
356 $pattern = '~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)owl~';
357
358 return preg_replace($pattern, '$1url', $css);
359 }
360 }
361