/* Protected Static Members */
/** @var array List of common image files extensions and MIME-types */
- protected static $mimeTypes = array(
+ protected static $mimeTypes = [
'gif' => 'image/gif',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'tiff' => 'image/tiff',
'xbm' => 'image/x-xbitmap',
'svg' => 'image/svg+xml',
- );
+ ];
/* Static Methods */
/**
- * Gets a list of local file paths which are referenced in a CSS style sheet.
- *
- * If you wish non-existent files to be listed too, use getAllLocalFileReferences().
- *
- * For backwards-compatibility, if the second parameter is not given or null,
- * this function will return an empty array instead of erroring out.
- *
- * @param string $source CSS stylesheet source to process
- * @param string $path File path where the source was read from
- * @return array List of local file references
- */
- public static function getLocalFileReferences( $source, $path = null ) {
- if ( $path === null ) {
- return array();
- }
-
- $files = self::getAllLocalFileReferences( $source, $path );
-
- // Skip non-existent files
- $files = array_filter( $files, function ( $file ) {
- return file_exists( $file );
- } );
-
- return $files;
- }
-
- /**
- * Gets a list of local file paths which are referenced in a CSS style sheet, including
- * non-existent files.
+ * Get a list of local files referenced in a stylesheet (includes non-existent files).
*
* @param string $source CSS stylesheet source to process
* @param string $path File path where the source was read from
* @return array List of local file references
*/
- public static function getAllLocalFileReferences( $source, $path ) {
+ public static function getLocalFileReferences( $source, $path ) {
$stripped = preg_replace( '/' . self::COMMENT_REGEX . '/s', '', $source );
$path = rtrim( $path, '/' ) . '/';
- $files = array();
+ $files = [];
$rFlags = PREG_OFFSET_CAPTURE | PREG_SET_ORDER;
if ( preg_match_all( '/' . self::URL_REGEX . '/', $stripped, $matches, $rFlags ) ) {
return false;
}
+ /**
+ * Serialize a string (escape and quote) for use as a CSS string value.
+ * http://www.w3.org/TR/2013/WD-cssom-20131205/#serialize-a-string
+ *
+ * @param string $value
+ * @return string
+ * @throws Exception
+ */
+ public static function serializeStringValue( $value ) {
+ if ( strstr( $value, "\0" ) ) {
+ throw new Exception( "Invalid character in CSS string" );
+ }
+ $value = strtr( $value, [ '\\' => '\\\\', '"' => '\\"' ] );
+ $value = preg_replace_callback( '/[\x01-\x1f\x7f-\x9f]/', function ( $match ) {
+ return '\\' . base_convert( ord( $match[0] ), 10, 16 ) . ' ';
+ }, $value );
+ return '"' . $value . '"';
+ }
+
/**
* @param $file string
* @return bool|string
if ( preg_match( '!^[\w\d:@/~.%+;,?&=-]+$!', $url ) ) {
return "url($url)";
} else {
- return 'url("' . strtr( $url, array( '\\' => '\\\\', '"' => '\\"' ) ) . '")';
+ return 'url("' . strtr( $url, [ '\\' => '\\\\', '"' => '\\"' ] ) . '")';
}
}
// Replace all comments by a placeholder so they will not interfere with the remapping.
// Warning: This will also catch on anything looking like the start of a comment between
// quotation marks (e.g. "foo /* bar").
- $comments = array();
+ $comments = [];
$pattern = '/(?!' . CSSMin::EMBED_REGEX . ')(' . CSSMin::COMMENT_REGEX . ')/s';
// Check for global @embed comment and remove it. Allow other comments to be present
// before @embed (they have been replaced with placeholders at this point).
$embedAll = false;
- $rule = preg_replace( '/^((?:\s+|' . CSSMin::PLACEHOLDER . '(\d+)x)*)' . CSSMin::EMBED_REGEX . '\s*/', '$1', $rule, 1, $embedAll );
+ $rule = preg_replace(
+ '/^((?:\s+|' .
+ CSSMin::PLACEHOLDER .
+ '(\d+)x)*)' .
+ CSSMin::EMBED_REGEX .
+ '\s*/',
+ '$1',
+ $rule,
+ 1,
+ $embedAll
+ );
// Build two versions of current rule: with remapped URLs
// and with embedded data: URIs (where possible).
if ( $embedData ) {
// Remember the occurring MIME types to avoid fallbacks when embedding some files.
- $mimeTypes = array();
+ $mimeTypes = [];
$ruleWithEmbedded = preg_replace_callback(
$pattern,
$url = $match['file'] . $match['query'];
$file = $local . $match['file'];
if (
- !CSSMin::isRemoteUrl( $url ) && !CSSMin::isLocalUrl( $url )
+ !self::isRemoteUrl( $url ) && !self::isLocalUrl( $url )
&& file_exists( $file )
) {
$mimeTypes[ CSSMin::getMimeType( $file ) ] = true;
);
// Are all referenced images SVGs?
- $needsEmbedFallback = $mimeTypes !== array( 'image/svg+xml' => true );
+ $needsEmbedFallback = $mimeTypes !== [ 'image/svg+xml' => true ];
}
if ( !$embedData || $ruleWithEmbedded === $ruleWithRemapped ) {
/**
* Is this CSS rule referencing a remote URL?
*
- * @private Until we require PHP 5.5 and we can access self:: from closures.
* @param string $maybeUrl
* @return bool
*/
- public static function isRemoteUrl( $maybeUrl ) {
+ protected static function isRemoteUrl( $maybeUrl ) {
if ( substr( $maybeUrl, 0, 2 ) === '//' || parse_url( $maybeUrl, PHP_URL_SCHEME ) ) {
return true;
}
/**
* Is this CSS rule referencing a local URL?
*
- * @private Until we require PHP 5.5 and we can access self:: from closures.
* @param string $maybeUrl
* @return bool
*/
- public static function isLocalUrl( $maybeUrl ) {
+ protected static function isLocalUrl( $maybeUrl ) {
if ( $maybeUrl !== '' && $maybeUrl[0] === '/' && !self::isRemoteUrl( $maybeUrl ) ) {
return true;
}
// Path to the actual file on the filesystem
$localFile = "{$local}/{$file}";
if ( file_exists( $localFile ) ) {
- // Add version parameter as the first five hex digits
- // of the MD5 hash of the file's contents.
- $url .= '?' . substr( md5_file( $localFile ), 0, 5 );
if ( $embed ) {
$data = self::encodeImageAsDataURI( $localFile );
if ( $data !== false ) {
return $data;
}
}
+ if ( method_exists( 'OutputPage', 'transformFilePath' ) ) {
+ $url = OutputPage::transformFilePath( $remote, $local, $file );
+ } else {
+ // Add version parameter as the first five hex digits
+ // of the MD5 hash of the file's contents.
+ $url .= '?' . substr( md5_file( $localFile ), 0, 5 );
+ }
}
// If any of these conditions failed (file missing, we don't want to embed it
// or it's not embeddable), return the URL (possibly with ?timestamp part)
public static function minify( $css ) {
return trim(
str_replace(
- array( '; ', ': ', ' {', '{ ', ', ', '} ', ';}' ),
- array( ';', ':', '{', '{', ',', '}', '}' ),
- preg_replace( array( '/\s+/', '/\/\*.*?\*\//s' ), array( ' ', '' ), $css )
+ [ '; ', ': ', ' {', '{ ', ', ', '} ', ';}' ],
+ [ ';', ':', '{', '{', ',', '}', '}' ],
+ preg_replace( [ '/\s+/', '/\/\*.*?\*\//s' ], [ ' ', '' ], $css )
)
);
}