const EMBED_REGEX = '\/\*\s*\@embed\s*\*\/';
const COMMENT_REGEX = '\/\*.*?\*\/';
- /** @var array List of common image files extensions and MIME-types */
+ /** @var string[] List of common image files extensions and MIME-types */
protected static $mimeTypes = [
'gif' => 'image/gif',
'jpe' => 'image/jpeg',
*
* @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
+ * @return string[] List of local file references
*/
public static function getLocalFileReferences( $source, $path ) {
$stripped = preg_replace( '/' . self::COMMENT_REGEX . '/s', '', $source );
* @param bool $ie8Compat By default, a data URI will only be produced if it can be made short
* enough to fit in Internet Explorer 8 (and earlier) URI length limit (32,768 bytes). Pass
* `false` to remove this limitation.
- * @return string|bool Image contents encoded as a data URI or false.
+ * @return string|false Image contents encoded as a data URI or false.
*/
public static function encodeImageAsDataURI( $file, $type = null, $ie8Compat = true ) {
// Fast-fail for files that definitely exceed the maximum data URI length
* @param string $contents File contents to encode.
* @param string $type File's MIME type.
* @param bool $ie8Compat See encodeImageAsDataURI().
- * @return string|bool Image contents encoded as a data URI or false.
+ * @return string|false Image contents encoded as a data URI or false.
*/
public static function encodeStringAsDataURI( $contents, $type, $ie8Compat = true ) {
// Try #1: Non-encoded data URI
/**
* Serialize a string (escape and quote) for use as a CSS string value.
- * https://www.w3.org/TR/2016/WD-cssom-1-20160317/#serialize-a-string
+ * https://drafts.csswg.org/cssom/#serialize-a-string
*
* @param string $value
* @return string
*/
public static function serializeStringValue( $value ) {
- $value = strtr( $value, [ "\0" => "\\fffd ", '\\' => '\\\\', '"' => '\\"' ] );
+ $value = strtr( $value, [ "\0" => "\xEF\xBF\xBD", '\\' => '\\\\', '"' => '\\"' ] );
$value = preg_replace_callback( '/[\x01-\x1f\x7f]/', function ( $match ) {
return '\\' . base_convert( ord( $match[0] ), 10, 16 ) . ' ';
}, $value );
* @return bool
*/
protected static function isLocalUrl( $maybeUrl ) {
- if ( $maybeUrl !== '' && $maybeUrl[0] === '/' && !self::isRemoteUrl( $maybeUrl ) ) {
- return true;
- }
- return false;
+ return isset( $maybeUrl[1] ) && $maybeUrl[0] === '/' && $maybeUrl[1] !== '/';
}
/**
// is only supported in PHP 5.6. Use a getter method for now.
$urlRegex = '(' .
// Unquoted url
- 'url\(\s*(?P<file0>[^\'"][^\?\)]+?)(?P<query0>\?[^\)]*?|)\s*\)' .
+ 'url\(\s*(?P<file0>[^\s\'"][^\?\)]+?)(?P<query0>\?[^\)]*?|)\s*\)' .
// Single quoted url
'|url\(\s*\'(?P<file1>[^\?\']+?)(?P<query1>\?[^\']*?|)\'\s*\)' .
// Double quoted url
return $data;
}
}
- if ( method_exists( 'OutputPage', 'transformFilePath' ) ) {
+ if ( class_exists( OutputPage::class ) ) {
$url = OutputPage::transformFilePath( $remote, $local, $file );
} else {
// Add version parameter as the first five hex digits
public static function provideSerializeStringValue() {
return [
[ 'Hello World!', '"Hello World!"' ],
- [ "Null\0Null", "\"Null\\fffd Null\"" ],
+ [ "Null\0Null", "\"Null\xEF\xBF\xBDNull\"" ],
[ '"', '"\\""' ],
[ "'", '"\'"' ],
[ "\\", '"\\\\"' ],
[ true, '//example.org/x.y.z/image.png' ],
[ true, '//localhost/styles.css?query=yes' ],
[ true, 'data:image/gif;base64,R0lGODlhAQABAIAAAP8AADAAACwAAAAAAQABAAACAkQBADs=' ],
+ [ false, '' ],
+ [ false, '/' ],
+ [ true, '//' ],
[ false, 'x.gif' ],
[ false, '/x.gif' ],
[ false, './x.gif' ],
public static function provideIsLocalUrls() {
return [
+ [ false, '' ],
+ [ false, '/' ],
+ [ false, '//' ],
[ false, 'x.gif' ],
[ true, '/x.gif' ],
[ false, './x.gif' ],
[ 'background-image: url("");', false, '/example', false ],
'background-image: url("");',
],
+ 'Single quote with outer spacing' => [
+ [ "background-image: url( '' );", false, '/example', false ],
+ "background-image: url( '' );",
+ ],
];
}
'foo { background: url(/static/foo.png?query=yes); }',
'foo { background: url(https://expand.example/static/foo.png?query=yes); }',
],
+ [
+ 'Path-relative URL with query',
+ "foo { background: url(?query=yes); }",
+ 'foo { background: url(http://localhost/w/?query=yes); }',
+ ],
[
'Remote URL (unnecessary quotes not preserved)',
'foo { background: url("http://example.org/w/unnecessary-quotes.png"); }',
'foo { background: url(//localhost/styles.css?quoted=single) }',
],
[
- 'Background URL (containing parentheses; T60473)',
+ 'Background URL (double quoted, containing parentheses; T60473)',
'foo { background: url("//localhost/styles.css?query=(parens)") }',
'foo { background: url("//localhost/styles.css?query=(parens)") }',
],
'foo { background: url(\'//localhost/styles.css?quote="\') }',
'foo { background: url("//localhost/styles.css?quote=\"") }',
],
+ [
+ 'Background URL (double quoted with outer spacing)',
+ 'foo { background: url( "http://localhost/styles.css?quoted=double" ) }',
+ 'foo { background: url(http://localhost/styles.css?quoted=double) }',
+ ],
+ [
+ 'Background URL (single quoted, containing spaces, with outer spacing)',
+ "foo { background: url( ' red.gif ' ); }",
+ 'foo { background: url("http://localhost/w/ red.gif "); }',
+ ],
[
'Simple case with comments before url',
'foo { prop: /* some {funny;} comment */ url(bar.png); }',