]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Minify/extlib/minify/min/lib/Minify/CSS/UriRewriter.php
Issue #166 - we test exif data below, no need for error output
[quix0rs-gnu-social.git] / plugins / Minify / extlib / minify / min / lib / Minify / CSS / UriRewriter.php
1 <?php
2 /**
3  * Class Minify_CSS_UriRewriter  
4  * @package Minify
5  */
6
7 /**
8  * Rewrite file-relative URIs as root-relative in CSS files
9  *
10  * @package Minify
11  * @author Stephen Clay <steve@mrclay.org>
12  */
13 class Minify_CSS_UriRewriter {
14     
15     /**
16      * Defines which class to call as part of callbacks, change this
17      * if you extend Minify_CSS_UriRewriter
18      * @var string
19      */
20     protected static $className = 'Minify_CSS_UriRewriter';
21     
22     /**
23      * rewrite() and rewriteRelative() append debugging information here
24      * @var string
25      */
26     public static $debugText = '';
27     
28     /**
29      * Rewrite file relative URIs as root relative in CSS files
30      * 
31      * @param string $css
32      * 
33      * @param string $currentDir The directory of the current CSS file.
34      * 
35      * @param string $docRoot The document root of the web site in which 
36      * the CSS file resides (default = $_SERVER['DOCUMENT_ROOT']).
37      * 
38      * @param array $symlinks (default = array()) If the CSS file is stored in 
39      * a symlink-ed directory, provide an array of link paths to
40      * target paths, where the link paths are within the document root. Because 
41      * paths need to be normalized for this to work, use "//" to substitute 
42      * the doc root in the link paths (the array keys). E.g.:
43      * <code>
44      * array('//symlink' => '/real/target/path') // unix
45      * array('//static' => 'D:\\staticStorage')  // Windows
46      * </code>
47      * 
48      * @return string
49      */
50     public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array()) 
51     {
52         self::$_docRoot = self::_realpath(
53             $docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT']
54         );
55         self::$_currentDir = self::_realpath($currentDir);
56         self::$_symlinks = array();
57         
58         // normalize symlinks
59         foreach ($symlinks as $link => $target) {
60             $link = ($link === '//')
61                 ? self::$_docRoot
62                 : str_replace('//', self::$_docRoot . '/', $link);
63             $link = strtr($link, '/', DIRECTORY_SEPARATOR);
64             self::$_symlinks[$link] = self::_realpath($target);
65         }
66         
67         self::$debugText .= "docRoot    : " . self::$_docRoot . "\n"
68                           . "currentDir : " . self::$_currentDir . "\n";
69         if (self::$_symlinks) {
70             self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n";
71         }
72         self::$debugText .= "\n";
73         
74         $css = self::_trimUrls($css);
75         
76         // rewrite
77         $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
78             ,array(self::$className, '_processUriCB'), $css);
79         $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
80             ,array(self::$className, '_processUriCB'), $css);
81
82         return $css;
83     }
84     
85     /**
86      * Prepend a path to relative URIs in CSS files
87      * 
88      * @param string $css
89      * 
90      * @param string $path The path to prepend.
91      * 
92      * @return string
93      */
94     public static function prepend($css, $path)
95     {
96         self::$_prependPath = $path;
97         
98         $css = self::_trimUrls($css);
99         
100         // append
101         $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
102             ,array(self::$className, '_processUriCB'), $css);
103         $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
104             ,array(self::$className, '_processUriCB'), $css);
105
106         self::$_prependPath = null;
107         return $css;
108     }
109     
110     
111     /**
112      * @var string directory of this stylesheet
113      */
114     private static $_currentDir = '';
115     
116     /**
117      * @var string DOC_ROOT
118      */
119     private static $_docRoot = '';
120     
121     /**\r
122      * @var array directory replacements to map symlink targets back to their\r
123      * source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'\r
124      */
125     private static $_symlinks = array();
126     
127     /**
128      * @var string path to prepend
129      */
130     private static $_prependPath = null;
131     
132     private static function _trimUrls($css)
133     {
134         return preg_replace('/
135             url\\(      # url(
136             \\s*
137             ([^\\)]+?)  # 1 = URI (assuming does not contain ")")
138             \\s*
139             \\)         # )
140         /x', 'url($1)', $css);
141     }
142     
143     private static function _processUriCB($m)
144     {
145         // $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
146         $isImport = ($m[0][0] === '@');
147         // determine URI and the quote character (if any)
148         if ($isImport) {
149             $quoteChar = $m[1];
150             $uri = $m[2];
151         } else {
152             // $m[1] is either quoted or not
153             $quoteChar = ($m[1][0] === "'" || $m[1][0] === '"')
154                 ? $m[1][0]
155                 : '';
156             $uri = ($quoteChar === '')
157                 ? $m[1]
158                 : substr($m[1], 1, strlen($m[1]) - 2);
159         }
160         // analyze URI
161         if ('/' !== $uri[0]                  // root-relative
162             && false === strpos($uri, '//')  // protocol (non-data)
163             && 0 !== strpos($uri, 'data:')   // data protocol
164         ) {
165             // URI is file-relative: rewrite depending on options
166             $uri = (self::$_prependPath !== null)
167                 ? (self::$_prependPath . $uri)
168                 : self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
169         }
170         return $isImport
171             ? "@import {$quoteChar}{$uri}{$quoteChar}"
172             : "url({$quoteChar}{$uri}{$quoteChar})";
173     }
174     
175     /**
176      * Rewrite a file relative URI as root relative
177      *
178      * <code>
179      * Minify_CSS_UriRewriter::rewriteRelative(
180      *       '../img/hello.gif'
181      *     , '/home/user/www/css'  // path of CSS file
182      *     , '/home/user/www'      // doc root
183      * );
184      * // returns '/img/hello.gif'
185      * 
186      * // example where static files are stored in a symlinked directory
187      * Minify_CSS_UriRewriter::rewriteRelative(
188      *       'hello.gif'
189      *     , '/var/staticFiles/theme'
190      *     , '/home/user/www'
191      *     , array('/home/user/www/static' => '/var/staticFiles')
192      * );
193      * // returns '/static/theme/hello.gif'
194      * </code>
195      * 
196      * @param string $uri file relative URI
197      * 
198      * @param string $realCurrentDir realpath of the current file's directory.
199      * 
200      * @param string $realDocRoot realpath of the site document root.
201      * 
202      * @param array $symlinks (default = array()) If the file is stored in 
203      * a symlink-ed directory, provide an array of link paths to
204      * real target paths, where the link paths "appear" to be within the document 
205      * root. E.g.:
206      * <code>
207      * array('/home/foo/www/not/real/path' => '/real/target/path') // unix
208      * array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path')  // Windows
209      * </code>
210      * 
211      * @return string
212      */
213     public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array())
214     {
215         // prepend path with current dir separator (OS-independent)
216         $path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR)  
217             . DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR);
218         
219         self::$debugText .= "file-relative URI  : {$uri}\n"
220                           . "path prepended     : {$path}\n";
221         
222         // "unresolve" a symlink back to doc root\r
223         foreach ($symlinks as $link => $target) {\r
224             if (0 === strpos($path, $target)) {\r
225                 // replace $target with $link\r
226                 $path = $link . substr($path, strlen($target));
227                 
228                 self::$debugText .= "symlink unresolved : {$path}\n";\r
229                 
230                 break;\r
231             }\r
232         }
233         // strip doc root
234         $path = substr($path, strlen($realDocRoot));
235         
236         self::$debugText .= "docroot stripped   : {$path}\n";
237         
238         // fix to root-relative URI
239
240         $uri = strtr($path, '/\\', '//');
241
242         // remove /./ and /../ where possible
243         $uri = str_replace('/./', '/', $uri);
244         // inspired by patch from Oleg Cherniy
245         do {
246             $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
247         } while ($changed);
248       
249         self::$debugText .= "traversals removed : {$uri}\n\n";
250         
251         return $uri;
252     }
253     
254     /**
255      * Get realpath with any trailing slash removed. If realpath() fails,
256      * just remove the trailing slash.
257      * 
258      * @param string $path
259      * 
260      * @return mixed path with no trailing slash
261      */
262     protected static function _realpath($path)
263     {
264         $realPath = realpath($path);
265         if ($realPath !== false) {
266             $path = $realPath;
267         }
268         return rtrim($path, '/\\');
269     }
270 }