2010-09-04 04:00:09 +00:00
|
|
|
<?php
|
2011-10-14 21:18:38 +00:00
|
|
|
/**
|
2012-05-04 06:29:11 +00:00
|
|
|
* Minification of CSS stylesheets.
|
|
|
|
|
*
|
2010-09-09 22:12:54 +00:00
|
|
|
* Copyright 2010 Wikimedia Foundation
|
2011-06-17 16:03:52 +00:00
|
|
|
*
|
2010-12-02 19:49:54 +00:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
|
|
|
* not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
2011-06-17 16:03:52 +00:00
|
|
|
*
|
2017-02-25 21:53:36 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2011-06-17 16:03:52 +00:00
|
|
|
*
|
2010-12-02 19:49:54 +00:00
|
|
|
* Unless required by applicable law or agreed to in writing, software distributed
|
|
|
|
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
|
|
|
|
* OF ANY KIND, either express or implied. See the License for the
|
2011-06-17 16:03:52 +00:00
|
|
|
* specific language governing permissions and limitations under the License.
|
|
|
|
|
*
|
2010-09-09 22:12:54 +00:00
|
|
|
* @file
|
2010-09-11 10:20:26 +00:00
|
|
|
* @version 0.1.1 -- 2010-09-11
|
2010-09-09 22:12:54 +00:00
|
|
|
* @author Trevor Parscal <tparscal@wikimedia.org>
|
|
|
|
|
* @copyright Copyright 2010 Wikimedia Foundation
|
2018-05-23 23:23:42 +00:00
|
|
|
* @license Apache-2.0
|
2010-09-08 17:38:26 +00:00
|
|
|
*/
|
2012-05-04 06:29:11 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Transforms CSS data
|
|
|
|
|
*
|
|
|
|
|
* This class provides minification, URL remapping, URL extracting, and data-URL embedding.
|
|
|
|
|
*/
|
2010-09-04 04:00:09 +00:00
|
|
|
class CSSMin {
|
2011-06-17 16:03:52 +00:00
|
|
|
|
2019-08-05 17:00:00 +00:00
|
|
|
/** @var string Strip marker for comments. */
|
2020-05-16 15:06:29 +00:00
|
|
|
private const PLACEHOLDER = "\x7fPLACEHOLDER\x7f";
|
2015-06-02 03:49:16 +00:00
|
|
|
|
2010-09-04 04:00:09 +00:00
|
|
|
/**
|
2014-11-07 19:21:58 +00:00
|
|
|
* Internet Explorer data URI length limit. See encodeImageAsDataURI().
|
2010-09-04 04:00:09 +00:00
|
|
|
*/
|
2020-05-16 15:06:29 +00:00
|
|
|
private const DATA_URI_SIZE_LIMIT = 32768;
|
2017-05-04 02:54:52 +00:00
|
|
|
|
2020-05-16 15:06:29 +00:00
|
|
|
private const EMBED_REGEX = '\/\*\s*\@embed\s*\*\/';
|
|
|
|
|
private const COMMENT_REGEX = '\/\*.*?\*\/';
|
2011-06-17 16:03:52 +00:00
|
|
|
|
2018-04-19 13:45:44 +00:00
|
|
|
/** @var string[] List of common image files extensions and MIME-types */
|
2016-02-17 09:09:32 +00:00
|
|
|
protected static $mimeTypes = [
|
2010-09-09 21:34:44 +00:00
|
|
|
'gif' => 'image/gif',
|
|
|
|
|
'jpe' => 'image/jpeg',
|
|
|
|
|
'jpeg' => 'image/jpeg',
|
|
|
|
|
'jpg' => 'image/jpeg',
|
|
|
|
|
'png' => 'image/png',
|
|
|
|
|
'tif' => 'image/tiff',
|
|
|
|
|
'tiff' => 'image/tiff',
|
|
|
|
|
'xbm' => 'image/x-xbitmap',
|
2013-12-27 11:43:17 +00:00
|
|
|
'svg' => 'image/svg+xml',
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2011-06-17 16:03:52 +00:00
|
|
|
|
2010-09-04 04:00:09 +00:00
|
|
|
/**
|
2016-03-03 00:16:13 +00:00
|
|
|
* Get a list of local files referenced in a stylesheet (includes non-existent files).
|
2015-09-03 21:30:36 +00:00
|
|
|
*
|
|
|
|
|
* @param string $source CSS stylesheet source to process
|
2015-09-19 19:32:09 +00:00
|
|
|
* @param string $path File path where the source was read from
|
2018-04-19 13:45:44 +00:00
|
|
|
* @return string[] List of local file references
|
2015-09-03 21:30:36 +00:00
|
|
|
*/
|
2016-03-03 00:16:13 +00:00
|
|
|
public static function getLocalFileReferences( $source, $path ) {
|
2015-09-19 19:32:09 +00:00
|
|
|
$stripped = preg_replace( '/' . self::COMMENT_REGEX . '/s', '', $source );
|
2014-02-27 13:08:48 +00:00
|
|
|
$path = rtrim( $path, '/' ) . '/';
|
2016-02-17 09:09:32 +00:00
|
|
|
$files = [];
|
2014-02-27 13:08:48 +00:00
|
|
|
|
2010-12-02 19:49:54 +00:00
|
|
|
$rFlags = PREG_OFFSET_CAPTURE | PREG_SET_ORDER;
|
2018-05-31 06:50:19 +00:00
|
|
|
if ( preg_match_all( '/' . self::getUrlRegex() . '/J', $stripped, $matches, $rFlags ) ) {
|
2010-09-04 04:00:09 +00:00
|
|
|
foreach ( $matches as $match ) {
|
2014-02-27 13:16:39 +00:00
|
|
|
$url = $match['file'][0];
|
|
|
|
|
|
|
|
|
|
// Skip fully-qualified and protocol-relative URLs and data URIs
|
2017-04-27 21:33:35 +00:00
|
|
|
if (
|
|
|
|
|
substr( $url, 0, 2 ) === '//' ||
|
2018-07-17 15:59:17 +00:00
|
|
|
parse_url( $url, PHP_URL_SCHEME )
|
2017-04-27 21:33:35 +00:00
|
|
|
) {
|
2014-02-27 13:16:39 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-17 15:59:17 +00:00
|
|
|
// Strip trailing anchors - T115436
|
|
|
|
|
$anchor = strpos( $url, '#' );
|
|
|
|
|
if ( $anchor !== false ) {
|
|
|
|
|
$url = substr( $url, 0, $anchor );
|
|
|
|
|
|
|
|
|
|
// '#some-anchors' is not a file
|
|
|
|
|
if ( $url === '' ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-03 21:30:36 +00:00
|
|
|
$files[] = $path . $url;
|
2010-09-04 04:00:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $files;
|
|
|
|
|
}
|
2011-06-17 16:03:52 +00:00
|
|
|
|
2013-09-18 09:09:11 +00:00
|
|
|
/**
|
2014-09-17 21:14:46 +00:00
|
|
|
* Encode an image file as a data URI.
|
|
|
|
|
*
|
|
|
|
|
* If the image file has a suitable MIME type and size, encode it as a data URI, base64-encoded
|
|
|
|
|
* for binary files or just percent-encoded otherwise. Return false if the image type is
|
|
|
|
|
* unfamiliar or file exceeds the size limit.
|
2013-09-18 09:09:11 +00:00
|
|
|
*
|
|
|
|
|
* @param string $file Image file to encode.
|
|
|
|
|
* @param string|null $type File's MIME type or null. If null, CSSMin will
|
|
|
|
|
* try to autodetect the type.
|
2014-11-07 19:21:58 +00:00
|
|
|
* @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.
|
2018-04-19 13:45:44 +00:00
|
|
|
* @return string|false Image contents encoded as a data URI or false.
|
2013-09-18 09:09:11 +00:00
|
|
|
*/
|
2014-11-07 19:21:58 +00:00
|
|
|
public static function encodeImageAsDataURI( $file, $type = null, $ie8Compat = true ) {
|
|
|
|
|
// Fast-fail for files that definitely exceed the maximum data URI length
|
|
|
|
|
if ( $ie8Compat && filesize( $file ) >= self::DATA_URI_SIZE_LIMIT ) {
|
2013-09-18 09:09:11 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2014-11-07 19:21:58 +00:00
|
|
|
|
2013-09-18 09:09:11 +00:00
|
|
|
if ( $type === null ) {
|
|
|
|
|
$type = self::getMimeType( $file );
|
|
|
|
|
}
|
|
|
|
|
if ( !$type ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-09-17 21:14:46 +00:00
|
|
|
|
2014-11-07 19:21:58 +00:00
|
|
|
return self::encodeStringAsDataURI( file_get_contents( $file ), $type, $ie8Compat );
|
|
|
|
|
}
|
2014-09-17 21:14:46 +00:00
|
|
|
|
2014-11-07 19:21:58 +00:00
|
|
|
/**
|
|
|
|
|
* Encode file contents as a data URI with chosen MIME type.
|
|
|
|
|
*
|
|
|
|
|
* The URI will be base64-encoded for binary files or just percent-encoded otherwise.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.25
|
|
|
|
|
*
|
|
|
|
|
* @param string $contents File contents to encode.
|
|
|
|
|
* @param string $type File's MIME type.
|
|
|
|
|
* @param bool $ie8Compat See encodeImageAsDataURI().
|
2018-04-19 13:45:44 +00:00
|
|
|
* @return string|false Image contents encoded as a data URI or false.
|
2014-11-07 19:21:58 +00:00
|
|
|
*/
|
|
|
|
|
public static function encodeStringAsDataURI( $contents, $type, $ie8Compat = true ) {
|
|
|
|
|
// Try #1: Non-encoded data URI
|
2018-01-09 03:05:40 +00:00
|
|
|
|
|
|
|
|
// Remove XML declaration, it's not needed with data URI usage
|
|
|
|
|
$contents = preg_replace( "/<\\?xml.*?\\?>/", '', $contents );
|
2014-11-07 19:21:58 +00:00
|
|
|
// The regular expression matches ASCII whitespace and printable characters.
|
|
|
|
|
if ( preg_match( '/^[\r\n\t\x20-\x7e]+$/', $contents ) ) {
|
|
|
|
|
// Do not base64-encode non-binary files (sane SVGs).
|
2014-09-17 21:14:46 +00:00
|
|
|
// (This often produces longer URLs, but they compress better, yielding a net smaller size.)
|
2017-09-13 18:56:46 +00:00
|
|
|
$encoded = rawurlencode( $contents );
|
|
|
|
|
// Unencode some things that don't need to be encoded, to make the encoding smaller
|
|
|
|
|
$encoded = strtr( $encoded, [
|
|
|
|
|
'%20' => ' ', // Unencode spaces
|
|
|
|
|
'%2F' => '/', // Unencode slashes
|
|
|
|
|
'%3A' => ':', // Unencode colons
|
|
|
|
|
'%3D' => '=', // Unencode equals signs
|
2018-01-09 02:34:22 +00:00
|
|
|
'%0A' => ' ', // Change newlines to spaces
|
|
|
|
|
'%0D' => ' ', // Change carriage returns to spaces
|
|
|
|
|
'%09' => ' ', // Change tabs to spaces
|
2017-09-13 18:56:46 +00:00
|
|
|
] );
|
2018-01-09 02:34:22 +00:00
|
|
|
// Consolidate runs of multiple spaces in a row
|
|
|
|
|
$encoded = preg_replace( '/ {2,}/', ' ', $encoded );
|
|
|
|
|
// Remove leading and trailing spaces
|
|
|
|
|
$encoded = preg_replace( '/^ | $/', '', $encoded );
|
2018-01-09 03:05:40 +00:00
|
|
|
|
2017-09-13 18:56:46 +00:00
|
|
|
$uri = 'data:' . $type . ',' . $encoded;
|
2014-11-07 19:21:58 +00:00
|
|
|
if ( !$ie8Compat || strlen( $uri ) < self::DATA_URI_SIZE_LIMIT ) {
|
|
|
|
|
return $uri;
|
2014-09-17 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-07 19:21:58 +00:00
|
|
|
// Try #2: Encoded data URI
|
|
|
|
|
$uri = 'data:' . $type . ';base64,' . base64_encode( $contents );
|
|
|
|
|
if ( !$ie8Compat || strlen( $uri ) < self::DATA_URI_SIZE_LIMIT ) {
|
|
|
|
|
return $uri;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A data URI couldn't be produced
|
|
|
|
|
return false;
|
2013-09-18 09:09:11 +00:00
|
|
|
}
|
|
|
|
|
|
2015-09-25 16:43:35 +00:00
|
|
|
/**
|
|
|
|
|
* Serialize a string (escape and quote) for use as a CSS string value.
|
2018-05-17 10:18:27 +00:00
|
|
|
* https://drafts.csswg.org/cssom/#serialize-a-string
|
2015-09-25 16:43:35 +00:00
|
|
|
*
|
|
|
|
|
* @param string $value
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public static function serializeStringValue( $value ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
$value = strtr( $value, [ "\0" => "\u{FFFD}", '\\' => '\\\\', '"' => '\\"' ] );
|
2021-02-10 22:31:02 +00:00
|
|
|
$value = preg_replace_callback( '/[\x01-\x1f\x7f]/', static function ( $match ) {
|
2015-09-25 16:43:35 +00:00
|
|
|
return '\\' . base_convert( ord( $match[0] ), 10, 16 ) . ' ';
|
|
|
|
|
}, $value );
|
|
|
|
|
return '"' . $value . '"';
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-26 04:15:09 +00:00
|
|
|
/**
|
2016-04-30 10:10:17 +00:00
|
|
|
* @param string $file
|
2011-10-26 04:15:09 +00:00
|
|
|
* @return bool|string
|
|
|
|
|
*/
|
2013-09-18 03:58:39 +00:00
|
|
|
public static function getMimeType( $file ) {
|
2017-03-25 03:20:44 +00:00
|
|
|
// Infer the MIME-type from the file extension
|
|
|
|
|
$ext = strtolower( pathinfo( $file, PATHINFO_EXTENSION ) );
|
2018-10-20 21:55:44 +00:00
|
|
|
return self::$mimeTypes[$ext] ?? mime_content_type( realpath( $file ) );
|
2011-02-11 22:57:32 +00:00
|
|
|
}
|
2011-06-17 16:03:52 +00:00
|
|
|
|
2013-12-11 21:00:29 +00:00
|
|
|
/**
|
|
|
|
|
* Build a CSS 'url()' value for the given URL, quoting parentheses (and other funny characters)
|
|
|
|
|
* and escaping quotes as necessary.
|
|
|
|
|
*
|
2014-07-12 00:00:55 +00:00
|
|
|
* See http://www.w3.org/TR/css-syntax-3/#consume-a-url-token
|
|
|
|
|
*
|
2013-12-11 21:00:29 +00:00
|
|
|
* @param string $url URL to process
|
|
|
|
|
* @return string 'url()' value, usually just `"url($url)"`, quoted/escaped if necessary
|
|
|
|
|
*/
|
|
|
|
|
public static function buildUrlValue( $url ) {
|
|
|
|
|
// The list below has been crafted to match URLs such as:
|
|
|
|
|
// scheme://user@domain:port/~user/fi%20le.png?query=yes&really=y+s
|
|
|
|
|
// data:image/png;base64,R0lGODlh/+==
|
2020-05-16 15:06:29 +00:00
|
|
|
if ( preg_match( '!^[\w:@/~.%+;,?&=-]+$!', $url ) ) {
|
2013-12-11 21:00:29 +00:00
|
|
|
return "url($url)";
|
|
|
|
|
} else {
|
2017-09-29 11:53:02 +00:00
|
|
|
return 'url("' . strtr( $url, [ '\\' => '\\\\', '"' => '\\"' ] ) . '")';
|
2013-12-11 21:00:29 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-04 04:00:09 +00:00
|
|
|
/**
|
2014-04-24 19:48:10 +00:00
|
|
|
* Remaps CSS URL paths and automatically embeds data URIs for CSS rules
|
|
|
|
|
* or url() values preceded by an / * @embed * / comment.
|
2010-09-04 12:53:01 +00:00
|
|
|
*
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $source CSS data to remap
|
|
|
|
|
* @param string $local File path where the source was read from
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
* @param string $remote Full URL to the file's directory (may be protocol-relative, trailing slash is optional)
|
2014-04-24 19:48:10 +00:00
|
|
|
* @param bool $embedData If false, never do any data URI embedding,
|
|
|
|
|
* even if / * @embed * / is found.
|
2010-09-04 04:00:09 +00:00
|
|
|
* @return string Remapped CSS data
|
|
|
|
|
*/
|
2012-02-02 10:30:57 +00:00
|
|
|
public static function remap( $source, $local, $remote, $embedData = true ) {
|
2013-11-09 17:59:45 +00:00
|
|
|
// High-level overview:
|
|
|
|
|
// * For each CSS rule in $source that includes at least one url() value:
|
|
|
|
|
// * Check for an @embed comment at the start indicating that all URIs should be embedded
|
|
|
|
|
// * For each url() value:
|
|
|
|
|
// * Check for an @embed comment directly preceding the value
|
|
|
|
|
// * If either @embed comment exists:
|
|
|
|
|
// * Embedding the URL as data: URI, if it's possible / allowed
|
|
|
|
|
// * Otherwise remap the URL to work in generated stylesheets
|
|
|
|
|
|
|
|
|
|
// Guard against trailing slashes, because "some/remote/../foo.png"
|
2017-02-20 22:32:12 +00:00
|
|
|
// resolves to "some/remote/foo.png" on (some?) clients (T29052).
|
2013-11-09 17:59:45 +00:00
|
|
|
if ( substr( $remote, -1 ) == '/' ) {
|
|
|
|
|
$remote = substr( $remote, 0, -1 );
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-02 03:49:16 +00:00
|
|
|
// Disallow U+007F DELETE, which is illegal anyway, and which
|
|
|
|
|
// we use for comment placeholders.
|
|
|
|
|
$source = str_replace( "\x7f", "?", $source );
|
|
|
|
|
|
2014-09-20 21:26:13 +00:00
|
|
|
// 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").
|
2016-02-17 09:09:32 +00:00
|
|
|
$comments = [];
|
2014-06-12 21:55:33 +00:00
|
|
|
|
2017-07-23 01:24:09 +00:00
|
|
|
$pattern = '/(?!' . self::EMBED_REGEX . ')(' . self::COMMENT_REGEX . ')/s';
|
2014-06-12 21:55:33 +00:00
|
|
|
|
|
|
|
|
$source = preg_replace_callback(
|
|
|
|
|
$pattern,
|
2021-02-10 22:31:02 +00:00
|
|
|
static function ( $match ) use ( &$comments ) {
|
2014-06-12 21:55:33 +00:00
|
|
|
$comments[] = $match[ 0 ];
|
2020-05-16 15:06:29 +00:00
|
|
|
return self::PLACEHOLDER . ( count( $comments ) - 1 ) . 'x';
|
2014-06-12 21:55:33 +00:00
|
|
|
},
|
|
|
|
|
$source
|
|
|
|
|
);
|
|
|
|
|
|
2014-06-10 22:04:40 +00:00
|
|
|
// Note: This will not correctly handle cases where ';', '{' or '}'
|
|
|
|
|
// appears in the rule itself, e.g. in a quoted string. You are advised
|
2014-04-24 19:48:10 +00:00
|
|
|
// not to use such characters in file names. We also match start/end of
|
|
|
|
|
// the string to be consistent in edge-cases ('@import url(…)').
|
2018-05-31 06:50:19 +00:00
|
|
|
$pattern = '/(?:^|[;{])\K[^;{}]*' . self::getUrlRegex() . '[^;}]*(?=[;}]|$)/J';
|
2013-11-09 17:59:45 +00:00
|
|
|
|
2014-06-12 21:55:33 +00:00
|
|
|
$source = preg_replace_callback(
|
2014-04-24 19:48:10 +00:00
|
|
|
$pattern,
|
2015-06-02 03:49:16 +00:00
|
|
|
function ( $matchOuter ) use ( $local, $remote, $embedData ) {
|
2014-04-24 19:48:10 +00:00
|
|
|
$rule = $matchOuter[0];
|
|
|
|
|
|
2014-09-20 21:26:13 +00:00
|
|
|
// 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).
|
2014-04-24 19:48:10 +00:00
|
|
|
$embedAll = false;
|
2015-09-26 18:06:36 +00:00
|
|
|
$rule = preg_replace(
|
|
|
|
|
'/^((?:\s+|' .
|
2020-05-16 15:06:29 +00:00
|
|
|
self::PLACEHOLDER .
|
2015-09-26 18:06:36 +00:00
|
|
|
'(\d+)x)*)' .
|
2020-05-16 15:06:29 +00:00
|
|
|
self::EMBED_REGEX .
|
2015-09-26 18:06:36 +00:00
|
|
|
'\s*/',
|
|
|
|
|
'$1',
|
|
|
|
|
$rule,
|
|
|
|
|
1,
|
|
|
|
|
$embedAll
|
|
|
|
|
);
|
2014-04-24 19:48:10 +00:00
|
|
|
|
|
|
|
|
// Build two versions of current rule: with remapped URLs
|
|
|
|
|
// and with embedded data: URIs (where possible).
|
2020-05-16 15:06:29 +00:00
|
|
|
$pattern = '/(?P<embed>' . self::EMBED_REGEX . '\s*|)' . self::getUrlRegex() . '/J';
|
2014-04-24 19:48:10 +00:00
|
|
|
|
|
|
|
|
$ruleWithRemapped = preg_replace_callback(
|
|
|
|
|
$pattern,
|
|
|
|
|
function ( $match ) use ( $local, $remote ) {
|
2020-05-16 15:06:29 +00:00
|
|
|
$remapped = self::remapOne( $match['file'], $match['query'], $local, $remote, false );
|
|
|
|
|
return self::buildUrlValue( $remapped );
|
2014-04-24 19:48:10 +00:00
|
|
|
},
|
|
|
|
|
$rule
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if ( $embedData ) {
|
|
|
|
|
$ruleWithEmbedded = preg_replace_callback(
|
|
|
|
|
$pattern,
|
2021-01-30 01:49:30 +00:00
|
|
|
function ( $match ) use ( $embedAll, $local, $remote ) {
|
2014-04-24 19:48:10 +00:00
|
|
|
$embed = $embedAll || $match['embed'];
|
2020-05-16 15:06:29 +00:00
|
|
|
$embedded = self::remapOne(
|
2014-04-24 19:48:10 +00:00
|
|
|
$match['file'],
|
|
|
|
|
$match['query'],
|
|
|
|
|
$local,
|
|
|
|
|
$remote,
|
|
|
|
|
$embed
|
|
|
|
|
);
|
2020-05-16 15:06:29 +00:00
|
|
|
return self::buildUrlValue( $embedded );
|
2014-04-24 19:48:10 +00:00
|
|
|
},
|
|
|
|
|
$rule
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-22 12:21:47 +00:00
|
|
|
if ( !$embedData || $ruleWithEmbedded === $ruleWithRemapped ) {
|
|
|
|
|
// We're not embedding anything, or we tried to but the file is not embeddable
|
|
|
|
|
return $ruleWithRemapped;
|
2014-04-24 19:48:10 +00:00
|
|
|
} else {
|
2019-10-04 02:15:37 +00:00
|
|
|
// Use a data URI in place of the @embed comment.
|
2014-09-22 12:21:47 +00:00
|
|
|
return $ruleWithEmbedded;
|
2014-04-24 19:48:10 +00:00
|
|
|
}
|
|
|
|
|
}, $source );
|
2014-06-12 21:55:33 +00:00
|
|
|
|
|
|
|
|
// Re-insert comments
|
2017-07-23 01:24:09 +00:00
|
|
|
$pattern = '/' . self::PLACEHOLDER . '(\d+)x/';
|
2021-02-10 22:31:02 +00:00
|
|
|
$source = preg_replace_callback( $pattern, static function ( $match ) use ( &$comments ) {
|
2014-06-12 21:55:33 +00:00
|
|
|
return $comments[ $match[1] ];
|
|
|
|
|
}, $source );
|
|
|
|
|
|
|
|
|
|
return $source;
|
2013-11-09 17:59:45 +00:00
|
|
|
}
|
|
|
|
|
|
2014-09-22 12:21:47 +00:00
|
|
|
/**
|
|
|
|
|
* Is this CSS rule referencing a remote URL?
|
|
|
|
|
*
|
|
|
|
|
* @param string $maybeUrl
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2016-02-10 18:37:07 +00:00
|
|
|
protected static function isRemoteUrl( $maybeUrl ) {
|
2014-09-22 12:21:47 +00:00
|
|
|
if ( substr( $maybeUrl, 0, 2 ) === '//' || parse_url( $maybeUrl, PHP_URL_SCHEME ) ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Is this CSS rule referencing a local URL?
|
|
|
|
|
*
|
|
|
|
|
* @param string $maybeUrl
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2016-02-10 18:37:07 +00:00
|
|
|
protected static function isLocalUrl( $maybeUrl ) {
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
// Accept "/" (known local)
|
|
|
|
|
// Accept "/anything" (known local)
|
|
|
|
|
// Reject "//anything" (known remote)
|
|
|
|
|
// Reject "" (invalid/uncertain)
|
|
|
|
|
return $maybeUrl === '/' || ( isset( $maybeUrl[1] ) && $maybeUrl[0] === '/' && $maybeUrl[1] !== '/' );
|
2014-09-22 12:21:47 +00:00
|
|
|
}
|
|
|
|
|
|
2017-07-28 04:40:21 +00:00
|
|
|
/**
|
|
|
|
|
* @codeCoverageIgnore
|
2019-11-23 22:28:57 +00:00
|
|
|
* @return string
|
2017-07-28 04:40:21 +00:00
|
|
|
*/
|
2017-05-04 02:54:52 +00:00
|
|
|
private static function getUrlRegex() {
|
|
|
|
|
static $urlRegex;
|
|
|
|
|
if ( $urlRegex === null ) {
|
|
|
|
|
$urlRegex = '(' .
|
|
|
|
|
// Unquoted url
|
2018-05-31 06:50:19 +00:00
|
|
|
'url\(\s*(?P<file>[^\s\'"][^\?\)]+?)(?P<query>\?[^\)]*?|)\s*\)' .
|
2017-05-04 02:54:52 +00:00
|
|
|
// Single quoted url
|
2018-05-31 06:50:19 +00:00
|
|
|
'|url\(\s*\'(?P<file>[^\?\']+?)(?P<query>\?[^\']*?|)\'\s*\)' .
|
2017-05-04 02:54:52 +00:00
|
|
|
// Double quoted url
|
2018-05-31 06:50:19 +00:00
|
|
|
'|url\(\s*"(?P<file>[^\?"]+?)(?P<query>\?[^"]*?|)"\s*\)' .
|
2017-05-04 02:54:52 +00:00
|
|
|
')';
|
|
|
|
|
}
|
|
|
|
|
return $urlRegex;
|
|
|
|
|
}
|
|
|
|
|
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
/**
|
|
|
|
|
* Resolve a possibly-relative URL against a base URL.
|
|
|
|
|
*
|
|
|
|
|
* @param string $base
|
|
|
|
|
* @param string $url
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
private static function resolveUrl( string $base, string $url ) : string {
|
|
|
|
|
// Net_URL2::resolve() doesn't allow for resolving against server-less URLs.
|
|
|
|
|
// We need this as for MediaWiki/ResourceLoader, the remote base path may either
|
|
|
|
|
// be separate (e.g. a separate domain), or simply local (like "/w"). In the
|
|
|
|
|
// local case, we don't want to needlessly include the server in the output.
|
|
|
|
|
$isServerless = self::isLocalUrl( $base );
|
|
|
|
|
if ( $isServerless ) {
|
|
|
|
|
$base = "https://placeholder.invalid$base";
|
|
|
|
|
}
|
|
|
|
|
// Net_URL2::resolve() doesn't allow for protocol-relative URLs, but we want to.
|
|
|
|
|
$isProtoRelative = substr( $base, 0, 2 ) === '//';
|
|
|
|
|
if ( $isProtoRelative ) {
|
|
|
|
|
$base = "https:$base";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$baseUrl = new Net_URL2( $base );
|
|
|
|
|
$ret = $baseUrl->resolve( $url );
|
|
|
|
|
if ( $isProtoRelative ) {
|
|
|
|
|
$ret->setScheme( false );
|
|
|
|
|
}
|
|
|
|
|
if ( $isServerless ) {
|
2020-11-25 00:38:53 +00:00
|
|
|
$ret->setScheme( false );
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
$ret->setHost( false );
|
|
|
|
|
}
|
|
|
|
|
return $ret->getURL();
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-09 17:59:45 +00:00
|
|
|
/**
|
|
|
|
|
* Remap or embed a CSS URL path.
|
|
|
|
|
*
|
|
|
|
|
* @param string $file URL to remap/embed
|
|
|
|
|
* @param string $query
|
|
|
|
|
* @param string $local File path where the source was read from
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
* @param string $remote Full URL to the file's directory (may be protocol-relative, trailing slash is optional)
|
2013-11-09 17:59:45 +00:00
|
|
|
* @param bool $embed Whether to do any data URI embedding
|
|
|
|
|
* @return string Remapped/embedded URL data
|
|
|
|
|
*/
|
|
|
|
|
public static function remapOne( $file, $query, $local, $remote, $embed ) {
|
2013-12-11 19:11:44 +00:00
|
|
|
// The full URL possibly with query, as passed to the 'url()' value in CSS
|
|
|
|
|
$url = $file . $query;
|
|
|
|
|
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
// Expand local URLs with absolute paths to a full URL (possibly protocol-relative).
|
|
|
|
|
if ( self::isLocalUrl( $url ) ) {
|
|
|
|
|
return self::resolveUrl( $remote, $url );
|
2013-11-09 17:59:45 +00:00
|
|
|
}
|
2012-06-20 11:05:03 +00:00
|
|
|
|
2014-09-22 12:21:47 +00:00
|
|
|
// Pass thru fully-qualified and protocol-relative URLs and data URIs, as well as local URLs if
|
|
|
|
|
// we can't expand them.
|
2018-07-17 15:59:17 +00:00
|
|
|
// Also skips anchors or the rare `behavior` property specifying application's default behavior
|
2017-04-27 21:33:35 +00:00
|
|
|
if (
|
|
|
|
|
self::isRemoteUrl( $url ) ||
|
2018-07-17 15:59:17 +00:00
|
|
|
substr( $url, 0, 1 ) === '#'
|
2017-04-27 21:33:35 +00:00
|
|
|
) {
|
2014-09-22 12:21:47 +00:00
|
|
|
return $url;
|
2013-11-09 17:59:45 +00:00
|
|
|
}
|
2012-06-20 11:05:03 +00:00
|
|
|
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
// The $remote must have a trailing slash beyond this point for correct path resolution.
|
|
|
|
|
if ( substr( $remote, -1 ) !== '/' ) {
|
|
|
|
|
$remote .= '/';
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-11 20:21:36 +00:00
|
|
|
if ( $local === false ) {
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
// CSS specifies a path that is neither a local file path, nor a local URL.
|
|
|
|
|
// It is probably already a fully-qualitied URL or data URI, but try to expand
|
|
|
|
|
// it just in case.
|
|
|
|
|
$url = self::resolveUrl( $remote, $url );
|
2013-11-09 17:59:45 +00:00
|
|
|
} else {
|
2013-12-11 20:21:36 +00:00
|
|
|
// We drop the query part here and instead make the path relative to $remote
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
$url = self::resolveUrl( $remote, $file );
|
2013-12-11 20:21:36 +00:00
|
|
|
// Path to the actual file on the filesystem
|
|
|
|
|
$localFile = "{$local}/{$file}";
|
|
|
|
|
if ( file_exists( $localFile ) ) {
|
|
|
|
|
if ( $embed ) {
|
|
|
|
|
$data = self::encodeImageAsDataURI( $localFile );
|
|
|
|
|
if ( $data !== false ) {
|
|
|
|
|
return $data;
|
|
|
|
|
}
|
|
|
|
|
}
|
resourceloader: Remove wfExpandUrl() coupling from CSSMin
There are three cases in CSSMin::remap where performs path
resolution.
1. Absolute local path URLs to full URL.
Example: url(/static/foo.png), url(/w/index.php?…), etc.
These previously used wfExpandUrl(), which got the server
name and protocol directly from $wgServer.
We will now use the $remote parameter to get this information
instead, which is generally set to something like
https://wiki/w/resources/foo, and thus naturally contains
the server name and protocol.
The resolution is powered by the Net_URL2 library, allowing
this to work outside Mediawiki as well.
Some tests needed to change because they were calling CSSMin::remap
with an incomplete $remote dummy values like "/" or "/w, because
the test author (past me) was trying to be clever by not supplying
it, knowing MW would ignore it. Now that it is consistently used,
like normal calls from ResourceLoader would, the expected values
will always be based on http://localhost/w, instead of sometimes
the competing $wgServer value of `https://expand.example`.
2. Relative local path to full URL
Example: url(foo.png), url(../foo.png), url(bar/foo.png)
These were already using $remote. The only change is that
they now use Net_URL2 library instead of blind string
concatenation. One of the benefits of this is that we will
no longer need to call wfRemoveDotSegments() to get rid
of things like double slashes or redundant "../" sequences.
Previously, thing like "foo//bar" or "foo/../bar" were cleaned
up only due to wfRemoveDotSegments(). This is now naturally
handled by Net_URL2.
3. Remote URLs
Example: url(http://example.org/bar.png), url(//example.org/bar.png)
This is generally not used in source code, but gadgets may use this,
e.g. for upload.wikimedia.org or cross-wiki imports.
Other changes:
* One test case used spaces within the URL string in CSS, which the
net_url2 library represents with percent-encoding instead.
Same thing either way.
Bug: T88914
Change-Id: Ibef70cc934c0ee8260a244c51bca9fb88c1c0d88
2020-09-11 21:35:37 +00:00
|
|
|
// 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 );
|
2013-12-11 20:21:36 +00:00
|
|
|
}
|
|
|
|
|
// 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)
|
2010-09-04 04:00:09 +00:00
|
|
|
}
|
2015-08-16 17:32:13 +00:00
|
|
|
return $url;
|
2010-09-04 04:00:09 +00:00
|
|
|
}
|
2011-02-11 22:57:32 +00:00
|
|
|
|
2010-09-04 04:00:09 +00:00
|
|
|
/**
|
|
|
|
|
* Removes whitespace from CSS data
|
2010-09-04 12:53:01 +00:00
|
|
|
*
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $css CSS data to minify
|
2010-09-04 12:53:01 +00:00
|
|
|
* @return string Minified CSS data
|
2010-09-04 04:00:09 +00:00
|
|
|
*/
|
|
|
|
|
public static function minify( $css ) {
|
|
|
|
|
return trim(
|
|
|
|
|
str_replace(
|
2017-12-06 16:16:41 +00:00
|
|
|
[ '; ', ': ', ' {', '{ ', ', ', '} ', ';}', '( ', ' )', '[ ', ' ]' ],
|
|
|
|
|
[ ';', ':', '{', '{', ',', '}', '}', '(', ')', '[', ']' ],
|
2016-02-17 09:09:32 +00:00
|
|
|
preg_replace( [ '/\s+/', '/\/\*.*?\*\//s' ], [ ' ', '' ], $css )
|
2010-09-04 04:00:09 +00:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
2010-09-04 12:53:01 +00:00
|
|
|
}
|