MediaWiki  1.23.15
CSSMin.php
Go to the documentation of this file.
1 <?php
30 class CSSMin {
31 
32  /* Constants */
33 
40  const EMBED_SIZE_LIMIT = 24576;
41  const URL_REGEX = 'url\(\s*[\'"]?(?P<file>[^\?\)\'"]*?)(?P<query>\?[^\)\'"]*?|)[\'"]?\s*\)';
42  const EMBED_REGEX = '\/\*\s*\@embed\s*\*\/';
43 
44  /* Protected Static Members */
45 
47  protected static $mimeTypes = array(
48  'gif' => 'image/gif',
49  'jpe' => 'image/jpeg',
50  'jpeg' => 'image/jpeg',
51  'jpg' => 'image/jpeg',
52  'png' => 'image/png',
53  'tif' => 'image/tiff',
54  'tiff' => 'image/tiff',
55  'xbm' => 'image/x-xbitmap',
56  'svg' => 'image/svg+xml',
57  );
58 
59  /* Static Methods */
60 
71  public static function getLocalFileReferences( $source, $path = null ) {
72  if ( $path === null ) {
73  return array();
74  }
75 
76  $path = rtrim( $path, '/' ) . '/';
77  $files = array();
78 
79  $rFlags = PREG_OFFSET_CAPTURE | PREG_SET_ORDER;
80  if ( preg_match_all( '/' . self::URL_REGEX . '/', $source, $matches, $rFlags ) ) {
81  foreach ( $matches as $match ) {
82  $url = $match['file'][0];
83 
84  // Skip fully-qualified and protocol-relative URLs and data URIs
85  if ( substr( $url, 0, 2 ) === '//' || parse_url( $url, PHP_URL_SCHEME ) ) {
86  break;
87  }
88 
89  $file = $path . $url;
90  // Skip non-existent files
91  if ( file_exists( $file ) ) {
92  break;
93  }
94 
95  $files[] = $file;
96  }
97  }
98  return $files;
99  }
100 
115  public static function encodeImageAsDataURI( $file, $type = null, $sizeLimit = self::EMBED_SIZE_LIMIT ) {
116  if ( $sizeLimit !== false && filesize( $file ) >= $sizeLimit ) {
117  return false;
118  }
119  if ( $type === null ) {
121  }
122  if ( !$type ) {
123  return false;
124  }
125  $data = base64_encode( file_get_contents( $file ) );
126  return 'data:' . $type . ';base64,' . $data;
127  }
128 
133  public static function getMimeType( $file ) {
134  $realpath = realpath( $file );
135  // Try a couple of different ways to get the mime-type of a file, in order of
136  // preference
137  if (
138  $realpath
139  && function_exists( 'finfo_file' )
140  && function_exists( 'finfo_open' )
141  && defined( 'FILEINFO_MIME_TYPE' )
142  ) {
143  // As of PHP 5.3, this is how you get the mime-type of a file; it uses the Fileinfo
144  // PECL extension
145  return finfo_file( finfo_open( FILEINFO_MIME_TYPE ), $realpath );
146  } elseif ( function_exists( 'mime_content_type' ) ) {
147  // Before this was deprecated in PHP 5.3, this was how you got the mime-type of a file
148  return mime_content_type( $file );
149  } else {
150  // Worst-case scenario has happened, use the file extension to infer the mime-type
151  $ext = strtolower( pathinfo( $file, PATHINFO_EXTENSION ) );
152  if ( isset( self::$mimeTypes[$ext] ) ) {
153  return self::$mimeTypes[$ext];
154  }
155  }
156  return false;
157  }
158 
166  public static function buildUrlValue( $url ) {
167  // The list below has been crafted to match URLs such as:
168  // scheme://user@domain:port/~user/fi%20le.png?query=yes&really=y+s
169  // data:image/png;base64,R0lGODlh/+==
170  if ( preg_match( '!^[\w\d:@/~.%+;,?&=-]+$!', $url ) ) {
171  return "url($url)";
172  } else {
173  return 'url("' . strtr( $url, array( '\\' => '\\\\', '"' => '\\"' ) ) . '")';
174  }
175  }
176 
187  public static function remap( $source, $local, $remote, $embedData = true ) {
188  // High-level overview:
189  // * For each CSS rule in $source that includes at least one url() value:
190  // * Check for an @embed comment at the start indicating that all URIs should be embedded
191  // * For each url() value:
192  // * Check for an @embed comment directly preceding the value
193  // * If either @embed comment exists:
194  // * Embedding the URL as data: URI, if it's possible / allowed
195  // * Otherwise remap the URL to work in generated stylesheets
196 
197  // Guard against trailing slashes, because "some/remote/../foo.png"
198  // resolves to "some/remote/foo.png" on (some?) clients (bug 27052).
199  if ( substr( $remote, -1 ) == '/' ) {
200  $remote = substr( $remote, 0, -1 );
201  }
202 
203  // Note: This will not correctly handle cases where ';', '{' or '}' appears in the rule itself,
204  // e.g. in a quoted string. You are advised not to use such characters in file names.
205  // We also match start/end of the string to be consistent in edge-cases ('@import url(…)').
206  $pattern = '/(?:^|[;{])\K[^;{}]*' . CSSMin::URL_REGEX . '[^;}]*(?=[;}]|$)/';
207  return preg_replace_callback( $pattern, function ( $matchOuter ) use ( $local, $remote, $embedData ) {
208  $rule = $matchOuter[0];
209 
210  // Check for global @embed comment and remove it
211  $embedAll = false;
212  $rule = preg_replace( '/^(\s*)' . CSSMin::EMBED_REGEX . '\s*/', '$1', $rule, 1, $embedAll );
213 
214  // Build two versions of current rule: with remapped URLs and with embedded data: URIs (where possible)
215  $pattern = '/(?P<embed>' . CSSMin::EMBED_REGEX . '\s*|)' . CSSMin::URL_REGEX . '/';
216 
217  $ruleWithRemapped = preg_replace_callback( $pattern, function ( $match ) use ( $local, $remote ) {
218  $remapped = CSSMin::remapOne( $match['file'], $match['query'], $local, $remote, false );
219  return CSSMin::buildUrlValue( $remapped );
220  }, $rule );
221 
222  if ( $embedData ) {
223  $ruleWithEmbedded = preg_replace_callback( $pattern, function ( $match ) use ( $embedAll, $local, $remote ) {
224  $embed = $embedAll || $match['embed'];
225  $embedded = CSSMin::remapOne( $match['file'], $match['query'], $local, $remote, $embed );
226  return CSSMin::buildUrlValue( $embedded );
227  }, $rule );
228  }
229 
230  if ( $embedData && $ruleWithEmbedded !== $ruleWithRemapped ) {
231  // Build 2 CSS properties; one which uses a base64 encoded data URI in place
232  // of the @embed comment to try and retain line-number integrity, and the
233  // other with a remapped an versioned URL and an Internet Explorer hack
234  // making it ignored in all browsers that support data URIs
235  return "$ruleWithEmbedded;$ruleWithRemapped!ie";
236  } else {
237  // No reason to repeat twice
238  return $ruleWithRemapped;
239  }
240  }, $source );
241  }
242 
253  public static function remapOne( $file, $query, $local, $remote, $embed ) {
254  // The full URL possibly with query, as passed to the 'url()' value in CSS
255  $url = $file . $query;
256 
257  // Skip fully-qualified and protocol-relative URLs and data URIs
258  if ( substr( $url, 0, 2 ) === '//' || parse_url( $url, PHP_URL_SCHEME ) ) {
259  return $url;
260  }
261 
262  // URLs with absolute paths like /w/index.php need to be expanded
263  // to absolute URLs but otherwise left alone
264  if ( $url !== '' && $url[0] === '/' ) {
265  // Replace the file path with an expanded (possibly protocol-relative) URL
266  // ...but only if wfExpandUrl() is even available.
267  // This will not be the case if we're running outside of MW
268  if ( function_exists( 'wfExpandUrl' ) ) {
269  return wfExpandUrl( $url, PROTO_RELATIVE );
270  } else {
271  return $url;
272  }
273  }
274 
275  if ( $local === false ) {
276  // Assume that all paths are relative to $remote, and make them absolute
277  return $remote . '/' . $url;
278  } else {
279  // We drop the query part here and instead make the path relative to $remote
280  $url = "{$remote}/{$file}";
281  // Path to the actual file on the filesystem
282  $localFile = "{$local}/{$file}";
283  if ( file_exists( $localFile ) ) {
284  // Add version parameter as a time-stamp in ISO 8601 format,
285  // using Z for the timezone, meaning GMT
286  $url .= '?' . gmdate( 'Y-m-d\TH:i:s\Z', round( filemtime( $localFile ), -2 ) );
287  if ( $embed ) {
288  $data = self::encodeImageAsDataURI( $localFile );
289  if ( $data !== false ) {
290  return $data;
291  }
292  }
293  }
294  // If any of these conditions failed (file missing, we don't want to embed it
295  // or it's not embeddable), return the URL (possibly with ?timestamp part)
296  return $url;
297  }
298  }
299 
306  public static function minify( $css ) {
307  return trim(
308  str_replace(
309  array( '; ', ': ', ' {', '{ ', ', ', '} ', ';}' ),
310  array( ';', ':', '{', '{', ',', '}', '}' ),
311  preg_replace( array( '/\s+/', '/\/\*.*?\*\//s' ), array( ' ', '' ), $css )
312  )
313  );
314  }
315 }
CSSMin\buildUrlValue
static buildUrlValue( $url)
Build a CSS 'url()' value for the given URL, quoting parentheses (and other funny characters) and esc...
Definition: CSSMin.php:166
CSSMin\minify
static minify( $css)
Removes whitespace from CSS data.
Definition: CSSMin.php:306
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
$files
$files
Definition: importImages.php:67
CSSMin\remap
static remap( $source, $local, $remote, $embedData=true)
Remaps CSS URL paths and automatically embeds data URIs for CSS rules or url() values preceded by an ...
Definition: CSSMin.php:187
CSSMin\encodeImageAsDataURI
static encodeImageAsDataURI( $file, $type=null, $sizeLimit=self::EMBED_SIZE_LIMIT)
Encode an image file as a base64 data URI.
Definition: CSSMin.php:115
CSSMin\EMBED_REGEX
const EMBED_REGEX
Definition: CSSMin.php:42
CSSMin\getLocalFileReferences
static getLocalFileReferences( $source, $path=null)
Gets a list of local file paths which are referenced in a CSS style sheet.
Definition: CSSMin.php:71
$css
$css
Definition: styleTest.css.php:50
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
CSSMin\URL_REGEX
const URL_REGEX
Definition: CSSMin.php:41
$matches
if(!defined( 'MEDIAWIKI')) if(!isset( $wgVersion)) $matches
Definition: NoLocalSettings.php:33
PROTO_RELATIVE
const PROTO_RELATIVE
Definition: Defines.php:269
$file
if(PHP_SAPI !='cli') $file
Definition: UtfNormalTest2.php:30
$ext
$ext
Definition: NoLocalSettings.php:34
CSSMin\getMimeType
static getMimeType( $file)
Definition: CSSMin.php:133
CSSMin
Transforms CSS data.
Definition: CSSMin.php:30
$path
$path
Definition: NoLocalSettings.php:35
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
$source
if(PHP_SAPI !='cli') $source
Definition: mwdoc-filter.php:18
CSSMin\remapOne
static remapOne( $file, $query, $local, $remote, $embed)
Remap or embed a CSS URL path.
Definition: CSSMin.php:253
$query
return true to allow those checks to and false if checking is done use this to change the tables headers temp or archived zone change it to an object instance and return false override the list derivative used the name of the old file when set the default code will be skipped add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1105
CSSMin\$mimeTypes
static $mimeTypes
Definition: CSSMin.php:47
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:544
CSSMin\EMBED_SIZE_LIMIT
const EMBED_SIZE_LIMIT
Maximum file size to still qualify for in-line embedding as a data-URI.
Definition: CSSMin.php:40
$type
$type
Definition: testCompression.php:46