These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * DokuWiki StyleSheet creator |
||
4 | * |
||
5 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) |
||
6 | * @author Andreas Gohr <[email protected]> |
||
7 | */ |
||
8 | |||
9 | use dokuwiki\Cache\Cache; |
||
10 | |||
11 | if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../'); |
||
12 | if(!defined('NOSESSION')) define('NOSESSION',true); // we do not use a session or authentication here (better caching) |
||
13 | if(!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT',1); // we gzip ourself here |
||
14 | if(!defined('NL')) define('NL',"\n"); |
||
15 | require_once(DOKU_INC.'inc/init.php'); |
||
16 | |||
17 | // Main (don't run when UNIT test) |
||
18 | if(!defined('SIMPLE_TEST')){ |
||
19 | header('Content-Type: text/css; charset=utf-8'); |
||
20 | css_out(); |
||
21 | } |
||
22 | |||
23 | |||
24 | // ---------------------- functions ------------------------------ |
||
25 | |||
26 | /** |
||
27 | * Output all needed Styles |
||
28 | * |
||
29 | * @author Andreas Gohr <[email protected]> |
||
30 | */ |
||
31 | function css_out(){ |
||
32 | global $conf; |
||
33 | global $lang; |
||
34 | global $config_cascade; |
||
35 | global $INPUT; |
||
36 | |||
37 | if ($INPUT->str('s') == 'feed') { |
||
38 | $mediatypes = array('feed'); |
||
39 | $type = 'feed'; |
||
40 | } else { |
||
41 | $mediatypes = array('screen', 'all', 'print', 'speech'); |
||
42 | $type = ''; |
||
43 | } |
||
44 | |||
45 | // decide from where to get the template |
||
46 | $tpl = trim(preg_replace('/[^\w-]+/','',$INPUT->str('t'))); |
||
47 | if(!$tpl) $tpl = $conf['template']; |
||
48 | |||
49 | // load style.ini |
||
50 | $styleUtil = new \dokuwiki\StyleUtils(); |
||
51 | $styleini = $styleUtil->cssStyleini($tpl, $INPUT->bool('preview')); |
||
52 | |||
53 | // cache influencers |
||
54 | $tplinc = tpl_incdir($tpl); |
||
55 | $cache_files = getConfigFiles('main'); |
||
56 | $cache_files[] = $tplinc.'style.ini'; |
||
57 | $cache_files[] = DOKU_CONF."tpl/$tpl/style.ini"; |
||
58 | $cache_files[] = __FILE__; |
||
59 | if($INPUT->bool('preview')) $cache_files[] = $conf['cachedir'].'/preview.ini'; |
||
60 | |||
61 | // Array of needed files and their web locations, the latter ones |
||
62 | // are needed to fix relative paths in the stylesheets |
||
63 | $media_files = array(); |
||
64 | foreach($mediatypes as $mediatype) { |
||
65 | $files = array(); |
||
66 | |||
67 | // load core styles |
||
68 | $files[DOKU_INC.'lib/styles/'.$mediatype.'.css'] = DOKU_BASE.'lib/styles/'; |
||
69 | |||
70 | // load jQuery-UI theme |
||
71 | if ($mediatype == 'screen') { |
||
72 | $files[DOKU_INC.'lib/scripts/jquery/jquery-ui-theme/smoothness.css'] = |
||
73 | DOKU_BASE.'lib/scripts/jquery/jquery-ui-theme/'; |
||
74 | } |
||
75 | // load plugin styles |
||
76 | $files = array_merge($files, css_pluginstyles($mediatype)); |
||
77 | // load template styles |
||
78 | if (isset($styleini['stylesheets'][$mediatype])) { |
||
79 | $files = array_merge($files, $styleini['stylesheets'][$mediatype]); |
||
80 | } |
||
81 | // load user styles |
||
82 | if(!empty($config_cascade['userstyle'][$mediatype])) { |
||
83 | foreach($config_cascade['userstyle'][$mediatype] as $userstyle) { |
||
84 | $files[$userstyle] = DOKU_BASE; |
||
85 | } |
||
86 | } |
||
87 | |||
88 | // Let plugins decide to either put more styles here or to remove some |
||
89 | $media_files[$mediatype] = css_filewrapper($mediatype, $files); |
||
90 | $CSSEvt = new Doku_Event('CSS_STYLES_INCLUDED', $media_files[$mediatype]); |
||
91 | |||
92 | // Make it preventable. |
||
93 | if ( $CSSEvt->advise_before() ) { |
||
94 | $cache_files = array_merge($cache_files, array_keys($media_files[$mediatype]['files'])); |
||
95 | } else { |
||
96 | // unset if prevented. Nothing will be printed for this mediatype. |
||
97 | unset($media_files[$mediatype]); |
||
98 | } |
||
99 | |||
100 | // finish event. |
||
101 | $CSSEvt->advise_after(); |
||
102 | } |
||
103 | |||
104 | // The generated script depends on some dynamic options |
||
105 | $cache = new Cache( |
||
106 | 'styles' . |
||
107 | $_SERVER['HTTP_HOST'] . |
||
108 | $_SERVER['SERVER_PORT'] . |
||
109 | $INPUT->bool('preview') . |
||
110 | DOKU_BASE . |
||
111 | $tpl . |
||
112 | $type, |
||
113 | '.css' |
||
114 | ); |
||
115 | $cache->_event = 'CSS_CACHE_USE'; |
||
0 ignored issues
–
show
The property
dokuwiki\Cache\Cache::$_event has been deprecated with message: since 2019-02-02 use the respective getters instead!
This property has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead. ![]() |
|||
116 | |||
117 | // check cache age & handle conditional request |
||
118 | // This may exit if a cache can be used |
||
119 | $cache_ok = $cache->useCache(array('files' => $cache_files)); |
||
120 | http_cached($cache->cache, $cache_ok); |
||
121 | |||
122 | // start output buffering |
||
123 | ob_start(); |
||
124 | |||
125 | // Fire CSS_STYLES_INCLUDED for one last time to let the |
||
126 | // plugins decide whether to include the DW default styles. |
||
127 | // This can be done by preventing the Default. |
||
128 | $media_files['DW_DEFAULT'] = css_filewrapper('DW_DEFAULT'); |
||
129 | trigger_event('CSS_STYLES_INCLUDED', $media_files['DW_DEFAULT'], 'css_defaultstyles'); |
||
130 | |||
131 | // build the stylesheet |
||
132 | foreach ($mediatypes as $mediatype) { |
||
133 | |||
134 | // Check if there is a wrapper set for this type. |
||
135 | if ( !isset($media_files[$mediatype]) ) { |
||
136 | continue; |
||
137 | } |
||
138 | |||
139 | $cssData = $media_files[$mediatype]; |
||
140 | |||
141 | // Print the styles. |
||
142 | print NL; |
||
143 | if ( $cssData['encapsulate'] === true ) print $cssData['encapsulationPrefix'] . ' {'; |
||
144 | print '/* START '.$cssData['mediatype'].' styles */'.NL; |
||
145 | |||
146 | // load files |
||
147 | foreach($cssData['files'] as $file => $location){ |
||
148 | $display = str_replace(fullpath(DOKU_INC), '', fullpath($file)); |
||
149 | print "\n/* XXXXXXXXX $display XXXXXXXXX */\n"; |
||
150 | print css_loadfile($file, $location); |
||
151 | } |
||
152 | |||
153 | print NL; |
||
154 | if ( $cssData['encapsulate'] === true ) print '} /* /@media '; |
||
155 | else print '/*'; |
||
156 | print ' END '.$cssData['mediatype'].' styles */'.NL; |
||
157 | } |
||
158 | |||
159 | // end output buffering and get contents |
||
160 | $css = ob_get_contents(); |
||
161 | ob_end_clean(); |
||
162 | |||
163 | // strip any source maps |
||
164 | stripsourcemaps($css); |
||
165 | |||
166 | // apply style replacements |
||
167 | $css = css_applystyle($css, $styleini['replacements']); |
||
168 | |||
169 | // parse less |
||
170 | $css = css_parseless($css); |
||
171 | |||
172 | // compress whitespace and comments |
||
173 | if($conf['compress']){ |
||
174 | $css = css_compress($css); |
||
175 | } |
||
176 | |||
177 | // embed small images right into the stylesheet |
||
178 | if($conf['cssdatauri']){ |
||
179 | $base = preg_quote(DOKU_BASE,'#'); |
||
180 | $css = preg_replace_callback('#(url\([ \'"]*)('.$base.')(.*?(?:\.(png|gif)))#i','css_datauri',$css); |
||
181 | } |
||
182 | |||
183 | http_cached_finish($cache->cache, $css); |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Uses phpless to parse LESS in our CSS |
||
188 | * |
||
189 | * most of this function is error handling to show a nice useful error when |
||
190 | * LESS compilation fails |
||
191 | * |
||
192 | * @param string $css |
||
193 | * @return string |
||
194 | */ |
||
195 | function css_parseless($css) { |
||
196 | global $conf; |
||
197 | |||
198 | $less = new lessc(); |
||
199 | $less->importDir = array(DOKU_INC); |
||
200 | $less->setPreserveComments(!$conf['compress']); |
||
201 | |||
202 | if (defined('DOKU_UNITTEST')){ |
||
203 | $less->importDir[] = TMP_DIR; |
||
204 | } |
||
205 | |||
206 | try { |
||
207 | return $less->compile($css); |
||
208 | } catch(Exception $e) { |
||
209 | // get exception message |
||
210 | $msg = str_replace(array("\n", "\r", "'"), array(), $e->getMessage()); |
||
211 | |||
212 | // try to use line number to find affected file |
||
213 | if(preg_match('/line: (\d+)$/', $msg, $m)){ |
||
214 | $msg = substr($msg, 0, -1* strlen($m[0])); //remove useless linenumber |
||
215 | $lno = $m[1]; |
||
216 | |||
217 | // walk upwards to last include |
||
218 | $lines = explode("\n", $css); |
||
219 | for($i=$lno-1; $i>=0; $i--){ |
||
220 | if(preg_match('/\/(\* XXXXXXXXX )(.*?)( XXXXXXXXX \*)\//', $lines[$i], $m)){ |
||
221 | // we found it, add info to message |
||
222 | $msg .= ' in '.$m[2].' at line '.($lno-$i); |
||
223 | break; |
||
224 | } |
||
225 | } |
||
226 | } |
||
227 | |||
228 | // something went wrong |
||
229 | $error = 'A fatal error occured during compilation of the CSS files. '. |
||
230 | 'If you recently installed a new plugin or template it '. |
||
231 | 'might be broken and you should try disabling it again. ['.$msg.']'; |
||
232 | |||
233 | echo ".dokuwiki:before { |
||
234 | content: '$error'; |
||
235 | background-color: red; |
||
236 | display: block; |
||
237 | background-color: #fcc; |
||
238 | border-color: #ebb; |
||
239 | color: #000; |
||
240 | padding: 0.5em; |
||
241 | }"; |
||
242 | |||
243 | exit; |
||
244 | } |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * Does placeholder replacements in the style according to |
||
249 | * the ones defined in a templates style.ini file |
||
250 | * |
||
251 | * This also adds the ini defined placeholders as less variables |
||
252 | * (sans the surrounding __ and with a ini_ prefix) |
||
253 | * |
||
254 | * @author Andreas Gohr <[email protected]> |
||
255 | * |
||
256 | * @param string $css |
||
257 | * @param array $replacements array(placeholder => value) |
||
258 | * @return string |
||
259 | */ |
||
260 | function css_applystyle($css, $replacements) { |
||
261 | // we convert ini replacements to LESS variable names |
||
262 | // and build a list of variable: value; pairs |
||
263 | $less = ''; |
||
264 | foreach((array) $replacements as $key => $value) { |
||
265 | $lkey = trim($key, '_'); |
||
266 | $lkey = '@ini_'.$lkey; |
||
267 | $less .= "$lkey: $value;\n"; |
||
268 | |||
269 | $replacements[$key] = $lkey; |
||
270 | } |
||
271 | |||
272 | // we now replace all old ini replacements with LESS variables |
||
273 | $css = strtr($css, $replacements); |
||
274 | |||
275 | // now prepend the list of LESS variables as the very first thing |
||
276 | $css = $less.$css; |
||
277 | return $css; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Wrapper for the files, content and mediatype for the event CSS_STYLES_INCLUDED |
||
282 | * |
||
283 | * @author Gerry Weißbach <[email protected]> |
||
284 | * |
||
285 | * @param string $mediatype type ofthe current media files/content set |
||
286 | * @param array $files set of files that define the current mediatype |
||
287 | * @return array |
||
288 | */ |
||
289 | function css_filewrapper($mediatype, $files=array()){ |
||
290 | return array( |
||
291 | 'files' => $files, |
||
292 | 'mediatype' => $mediatype, |
||
293 | 'encapsulate' => $mediatype != 'all', |
||
294 | 'encapsulationPrefix' => '@media '.$mediatype |
||
295 | ); |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * Prints the @media encapsulated default styles of DokuWiki |
||
300 | * |
||
301 | * @author Gerry Weißbach <[email protected]> |
||
302 | * |
||
303 | * This function is being called by a CSS_STYLES_INCLUDED event |
||
304 | * The event can be distinguished by the mediatype which is: |
||
305 | * DW_DEFAULT |
||
306 | */ |
||
307 | function css_defaultstyles(){ |
||
308 | // print the default classes for interwiki links and file downloads |
||
309 | print '@media screen {'; |
||
310 | css_interwiki(); |
||
311 | css_filetypes(); |
||
312 | print '}'; |
||
313 | } |
||
314 | |||
315 | /** |
||
316 | * Prints classes for interwikilinks |
||
317 | * |
||
318 | * Interwiki links have two classes: 'interwiki' and 'iw_$name>' where |
||
319 | * $name is the identifier given in the config. All Interwiki links get |
||
320 | * an default style with a default icon. If a special icon is available |
||
321 | * for an interwiki URL it is set in it's own class. Both classes can be |
||
322 | * overwritten in the template or userstyles. |
||
323 | * |
||
324 | * @author Andreas Gohr <[email protected]> |
||
325 | */ |
||
326 | function css_interwiki(){ |
||
327 | |||
328 | // default style |
||
329 | echo 'a.interwiki {'; |
||
330 | echo ' background: transparent url('.DOKU_BASE.'lib/images/interwiki.png) 0px 1px no-repeat;'; |
||
331 | echo ' padding: 1px 0px 1px 16px;'; |
||
332 | echo '}'; |
||
333 | |||
334 | // additional styles when icon available |
||
335 | $iwlinks = getInterwiki(); |
||
336 | foreach(array_keys($iwlinks) as $iw){ |
||
337 | $class = preg_replace('/[^_\-a-z0-9]+/i','_',$iw); |
||
338 | if(file_exists(DOKU_INC.'lib/images/interwiki/'.$iw.'.png')){ |
||
339 | echo "a.iw_$class {"; |
||
340 | echo ' background-image: url('.DOKU_BASE.'lib/images/interwiki/'.$iw.'.png)'; |
||
341 | echo '}'; |
||
342 | }elseif(file_exists(DOKU_INC.'lib/images/interwiki/'.$iw.'.gif')){ |
||
343 | echo "a.iw_$class {"; |
||
344 | echo ' background-image: url('.DOKU_BASE.'lib/images/interwiki/'.$iw.'.gif)'; |
||
345 | echo '}'; |
||
346 | } |
||
347 | } |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * Prints classes for file download links |
||
352 | * |
||
353 | * @author Andreas Gohr <[email protected]> |
||
354 | */ |
||
355 | function css_filetypes(){ |
||
356 | |||
357 | // default style |
||
358 | echo '.mediafile {'; |
||
359 | echo ' background: transparent url('.DOKU_BASE.'lib/images/fileicons/file.png) 0px 1px no-repeat;'; |
||
360 | echo ' padding-left: 18px;'; |
||
361 | echo ' padding-bottom: 1px;'; |
||
362 | echo '}'; |
||
363 | |||
364 | // additional styles when icon available |
||
365 | // scan directory for all icons |
||
366 | $exts = array(); |
||
367 | if($dh = opendir(DOKU_INC.'lib/images/fileicons')){ |
||
368 | while(false !== ($file = readdir($dh))){ |
||
369 | if(preg_match('/([_\-a-z0-9]+(?:\.[_\-a-z0-9]+)*?)\.(png|gif)/i',$file,$match)){ |
||
370 | $ext = strtolower($match[1]); |
||
371 | $type = '.'.strtolower($match[2]); |
||
372 | if($ext!='file' && (!isset($exts[$ext]) || $type=='.png')){ |
||
373 | $exts[$ext] = $type; |
||
374 | } |
||
375 | } |
||
376 | } |
||
377 | closedir($dh); |
||
378 | } |
||
379 | foreach($exts as $ext=>$type){ |
||
380 | $class = preg_replace('/[^_\-a-z0-9]+/','_',$ext); |
||
381 | echo ".mf_$class {"; |
||
382 | echo ' background-image: url('.DOKU_BASE.'lib/images/fileicons/'.$ext.$type.')'; |
||
383 | echo '}'; |
||
384 | } |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * Loads a given file and fixes relative URLs with the |
||
389 | * given location prefix |
||
390 | * |
||
391 | * @param string $file file system path |
||
392 | * @param string $location |
||
393 | * @return string |
||
394 | */ |
||
395 | function css_loadfile($file,$location=''){ |
||
396 | $css_file = new DokuCssFile($file); |
||
397 | return $css_file->load($location); |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * Helper class to abstract loading of css/less files |
||
402 | * |
||
403 | * @author Chris Smith <[email protected]> |
||
404 | */ |
||
405 | class DokuCssFile { |
||
406 | |||
407 | protected $filepath; // file system path to the CSS/Less file |
||
408 | protected $location; // base url location of the CSS/Less file |
||
409 | protected $relative_path = null; |
||
410 | |||
411 | public function __construct($file) { |
||
412 | $this->filepath = $file; |
||
413 | } |
||
414 | |||
415 | /** |
||
416 | * Load the contents of the css/less file and adjust any relative paths/urls (relative to this file) to be |
||
417 | * relative to the dokuwiki root: the web root (DOKU_BASE) for most files; the file system root (DOKU_INC) |
||
418 | * for less files. |
||
419 | * |
||
420 | * @param string $location base url for this file |
||
421 | * @return string the CSS/Less contents of the file |
||
422 | */ |
||
423 | public function load($location='') { |
||
424 | if (!file_exists($this->filepath)) return ''; |
||
425 | |||
426 | $css = io_readFile($this->filepath); |
||
427 | if (!$location) return $css; |
||
428 | |||
429 | $this->location = $location; |
||
430 | |||
431 | $css = preg_replace_callback('#(url\( *)([\'"]?)(.*?)(\2)( *\))#',array($this,'replacements'),$css); |
||
432 | $css = preg_replace_callback('#(@import\s+)([\'"])(.*?)(\2)#',array($this,'replacements'),$css); |
||
433 | |||
434 | return $css; |
||
435 | } |
||
436 | |||
437 | /** |
||
438 | * Get the relative file system path of this file, relative to dokuwiki's root folder, DOKU_INC |
||
439 | * |
||
440 | * @return string relative file system path |
||
441 | */ |
||
442 | protected function getRelativePath(){ |
||
443 | |||
444 | if (is_null($this->relative_path)) { |
||
445 | $basedir = array(DOKU_INC); |
||
446 | |||
447 | // during testing, files may be found relative to a second base dir, TMP_DIR |
||
448 | if (defined('DOKU_UNITTEST')) { |
||
449 | $basedir[] = realpath(TMP_DIR); |
||
450 | } |
||
451 | |||
452 | $basedir = array_map('preg_quote_cb', $basedir); |
||
453 | $regex = '/^('.join('|',$basedir).')/'; |
||
454 | $this->relative_path = preg_replace($regex, '', dirname($this->filepath)); |
||
455 | } |
||
456 | |||
457 | return $this->relative_path; |
||
458 | } |
||
459 | |||
460 | /** |
||
461 | * preg_replace callback to adjust relative urls from relative to this file to relative |
||
462 | * to the appropriate dokuwiki root location as described in the code |
||
463 | * |
||
464 | * @param array see http://php.net/preg_replace_callback |
||
465 | * @return string see http://php.net/preg_replace_callback |
||
466 | */ |
||
467 | public function replacements($match) { |
||
468 | |||
469 | // not a relative url? - no adjustment required |
||
470 | if (preg_match('#^(/|data:|https?://)#',$match[3])) { |
||
471 | return $match[0]; |
||
472 | } |
||
473 | // a less file import? - requires a file system location |
||
474 | else if (substr($match[3],-5) == '.less') { |
||
475 | if ($match[3]{0} != '/') { |
||
476 | $match[3] = $this->getRelativePath() . '/' . $match[3]; |
||
477 | } |
||
478 | } |
||
479 | // everything else requires a url adjustment |
||
480 | else { |
||
481 | $match[3] = $this->location . $match[3]; |
||
482 | } |
||
483 | |||
484 | return join('',array_slice($match,1)); |
||
485 | } |
||
486 | } |
||
487 | |||
488 | /** |
||
489 | * Convert local image URLs to data URLs if the filesize is small |
||
490 | * |
||
491 | * Callback for preg_replace_callback |
||
492 | * |
||
493 | * @param array $match |
||
494 | * @return string |
||
495 | */ |
||
496 | function css_datauri($match){ |
||
497 | global $conf; |
||
498 | |||
499 | $pre = unslash($match[1]); |
||
500 | $base = unslash($match[2]); |
||
501 | $url = unslash($match[3]); |
||
502 | $ext = unslash($match[4]); |
||
503 | |||
504 | $local = DOKU_INC.$url; |
||
505 | $size = @filesize($local); |
||
506 | if($size && $size < $conf['cssdatauri']){ |
||
507 | $data = base64_encode(file_get_contents($local)); |
||
508 | } |
||
509 | if (!empty($data)){ |
||
510 | $url = 'data:image/'.$ext.';base64,'.$data; |
||
511 | }else{ |
||
512 | $url = $base.$url; |
||
513 | } |
||
514 | return $pre.$url; |
||
515 | } |
||
516 | |||
517 | |||
518 | /** |
||
519 | * Returns a list of possible Plugin Styles (no existance check here) |
||
520 | * |
||
521 | * @author Andreas Gohr <[email protected]> |
||
522 | * |
||
523 | * @param string $mediatype |
||
524 | * @return array |
||
525 | */ |
||
526 | function css_pluginstyles($mediatype='screen'){ |
||
527 | $list = array(); |
||
528 | $plugins = plugin_list(); |
||
529 | foreach ($plugins as $p){ |
||
530 | $list[DOKU_PLUGIN."$p/$mediatype.css"] = DOKU_BASE."lib/plugins/$p/"; |
||
531 | $list[DOKU_PLUGIN."$p/$mediatype.less"] = DOKU_BASE."lib/plugins/$p/"; |
||
532 | // alternative for screen.css |
||
533 | if ($mediatype=='screen') { |
||
534 | $list[DOKU_PLUGIN."$p/style.css"] = DOKU_BASE."lib/plugins/$p/"; |
||
535 | $list[DOKU_PLUGIN."$p/style.less"] = DOKU_BASE."lib/plugins/$p/"; |
||
536 | } |
||
537 | } |
||
538 | return $list; |
||
539 | } |
||
540 | |||
541 | /** |
||
542 | * Very simple CSS optimizer |
||
543 | * |
||
544 | * @author Andreas Gohr <[email protected]> |
||
545 | * |
||
546 | * @param string $css |
||
547 | * @return string |
||
548 | */ |
||
549 | function css_compress($css){ |
||
550 | //strip comments through a callback |
||
551 | $css = preg_replace_callback('#(/\*)(.*?)(\*/)#s','css_comment_cb',$css); |
||
552 | |||
553 | //strip (incorrect but common) one line comments |
||
554 | $css = preg_replace_callback('/^.*\/\/.*$/m','css_onelinecomment_cb',$css); |
||
555 | |||
556 | // strip whitespaces |
||
557 | $css = preg_replace('![\r\n\t ]+!',' ',$css); |
||
558 | $css = preg_replace('/ ?([;,{}\/]) ?/','\\1',$css); |
||
559 | $css = preg_replace('/ ?: /',':',$css); |
||
560 | |||
561 | // number compression |
||
562 | $css = preg_replace( |
||
563 | '/([: ])0+(\.\d+?)0*((?:pt|pc|in|mm|cm|em|ex|px)\b|%)(?=[^\{]*[;\}])/', |
||
564 | '$1$2$3', |
||
565 | $css |
||
566 | ); // "0.1em" to ".1em", "1.10em" to "1.1em" |
||
567 | $css = preg_replace( |
||
568 | '/([: ])\.(0)+((?:pt|pc|in|mm|cm|em|ex|px)\b|%)(?=[^\{]*[;\}])/', |
||
569 | '$1$2', |
||
570 | $css |
||
571 | ); // ".0em" to "0" |
||
572 | $css = preg_replace( |
||
573 | '/([: ]0)0*(\.0*)?((?:pt|pc|in|mm|cm|em|ex|px)(?=[^\{]*[;\}])\b|%)/', |
||
574 | '$1', |
||
575 | $css |
||
576 | ); // "0.0em" to "0" |
||
577 | $css = preg_replace( |
||
578 | '/([: ]\d+)(\.0*)((?:pt|pc|in|mm|cm|em|ex|px)(?=[^\{]*[;\}])\b|%)/', |
||
579 | '$1$3', |
||
580 | $css |
||
581 | ); // "1.0em" to "1em" |
||
582 | $css = preg_replace( |
||
583 | '/([: ])0+(\d+|\d*\.\d+)((?:pt|pc|in|mm|cm|em|ex|px)(?=[^\{]*[;\}])\b|%)/', |
||
584 | '$1$2$3', |
||
585 | $css |
||
586 | ); // "001em" to "1em" |
||
587 | |||
588 | // shorten attributes (1em 1em 1em 1em -> 1em) |
||
589 | $css = preg_replace( |
||
590 | '/(?<![\w\-])((?:margin|padding|border|border-(?:width|radius)):)([\w\.]+)( \2)+(?=[;\}]| !)/', |
||
591 | '$1$2', |
||
592 | $css |
||
593 | ); // "1em 1em 1em 1em" to "1em" |
||
594 | $css = preg_replace( |
||
595 | '/(?<![\w\-])((?:margin|padding|border|border-(?:width)):)([\w\.]+) ([\w\.]+) \2 \3(?=[;\}]| !)/', |
||
596 | '$1$2 $3', |
||
597 | $css |
||
598 | ); // "1em 2em 1em 2em" to "1em 2em" |
||
599 | |||
600 | // shorten colors |
||
601 | $css = preg_replace( |
||
602 | "/#([0-9a-fA-F]{1})\\1([0-9a-fA-F]{1})\\2([0-9a-fA-F]{1})\\3(?=[^\{]*[;\}])/", |
||
603 | "#\\1\\2\\3", |
||
604 | $css |
||
605 | ); |
||
606 | |||
607 | return $css; |
||
608 | } |
||
609 | |||
610 | /** |
||
611 | * Callback for css_compress() |
||
612 | * |
||
613 | * Keeps short comments (< 5 chars) to maintain typical browser hacks |
||
614 | * |
||
615 | * @author Andreas Gohr <[email protected]> |
||
616 | * |
||
617 | * @param array $matches |
||
618 | * @return string |
||
619 | */ |
||
620 | function css_comment_cb($matches){ |
||
621 | if(strlen($matches[2]) > 4) return ''; |
||
622 | return $matches[0]; |
||
623 | } |
||
624 | |||
625 | /** |
||
626 | * Callback for css_compress() |
||
627 | * |
||
628 | * Strips one line comments but makes sure it will not destroy url() constructs with slashes |
||
629 | * |
||
630 | * @param array $matches |
||
631 | * @return string |
||
632 | */ |
||
633 | function css_onelinecomment_cb($matches) { |
||
634 | $line = $matches[0]; |
||
635 | |||
636 | $i = 0; |
||
637 | $len = strlen($line); |
||
638 | |||
639 | while ($i< $len){ |
||
640 | $nextcom = strpos($line, '//', $i); |
||
641 | $nexturl = stripos($line, 'url(', $i); |
||
642 | |||
643 | if($nextcom === false) { |
||
644 | // no more comments, we're done |
||
645 | $i = $len; |
||
646 | break; |
||
647 | } |
||
648 | |||
649 | // keep any quoted string that starts before a comment |
||
650 | $nextsqt = strpos($line, "'", $i); |
||
651 | $nextdqt = strpos($line, '"', $i); |
||
652 | if(min($nextsqt, $nextdqt) < $nextcom) { |
||
653 | $skipto = false; |
||
654 | if($nextsqt !== false && ($nextdqt === false || $nextsqt < $nextdqt)) { |
||
655 | $skipto = strpos($line, "'", $nextsqt+1) +1; |
||
656 | } else if ($nextdqt !== false) { |
||
657 | $skipto = strpos($line, '"', $nextdqt+1) +1; |
||
658 | } |
||
659 | |||
660 | if($skipto !== false) { |
||
661 | $i = $skipto; |
||
662 | continue; |
||
663 | } |
||
664 | } |
||
665 | |||
666 | if($nexturl === false || $nextcom < $nexturl) { |
||
667 | // no url anymore, strip comment and be done |
||
668 | $i = $nextcom; |
||
669 | break; |
||
670 | } |
||
671 | |||
672 | // we have an upcoming url |
||
673 | $i = strpos($line, ')', $nexturl); |
||
674 | } |
||
675 | |||
676 | return substr($line, 0, $i); |
||
677 | } |
||
678 | |||
679 | //Setup VIM: ex: et ts=4 : |
||
680 |
Since your code implements the magic setter
_set
, this function will be called for any write access on an undefined variable. You can add the@property
annotation to your class or interface to document the existence of this variable.Since the property has write access only, you can use the @property-write annotation instead.
Of course, you may also just have mistyped another name, in which case you should fix the error.
See also the PhpDoc documentation for @property.