HTTP API: Add a `$component` parameter to `wp_parse_url()` to give it parity with PHP's `parse_url()` function.
Fixes #36356 Props jrf git-svn-id: https://develop.svn.wordpress.org/trunk@38694 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
41fc5ba881
commit
e0f4a218fb
|
@ -633,29 +633,47 @@ function ms_allowed_http_request_hosts( $is_external, $host ) {
|
||||||
* when URL parsing failed.
|
* when URL parsing failed.
|
||||||
*
|
*
|
||||||
* @since 4.4.0
|
* @since 4.4.0
|
||||||
|
* @since 4.7.0 The $component parameter was added for parity with PHP's parse_url().
|
||||||
*
|
*
|
||||||
* @param string $url The URL to parse.
|
* @param string $url The URL to parse.
|
||||||
* @return bool|array False on failure; Array of URL components on success;
|
* @param int $component The specific component to retrieve. Use one of the PHP
|
||||||
* See parse_url()'s return values.
|
* predefined constants to specify which one.
|
||||||
|
* Defaults to -1 (= return all parts as an array).
|
||||||
|
* @see http://php.net/manual/en/function.parse-url.php
|
||||||
|
* @return mixed False on failure; Array of URL components on success;
|
||||||
|
* When a specific component has been requested: null if the component doesn't
|
||||||
|
* exist in the given URL; a sting or - in the case of PHP_URL_PORT - integer
|
||||||
|
* when it does; See parse_url()'s return values.
|
||||||
*/
|
*/
|
||||||
function wp_parse_url( $url ) {
|
function wp_parse_url( $url, $component = -1 ) {
|
||||||
$parts = @parse_url( $url );
|
$parts = @parse_url( $url, $component );
|
||||||
if ( ! $parts ) {
|
|
||||||
// < PHP 5.4.7 compat, trouble with relative paths including a scheme break in the path
|
if ( version_compare( PHP_VERSION, '5.4.7', '>=' ) ) {
|
||||||
if ( '/' == $url[0] && false !== strpos( $url, '://' ) ) {
|
|
||||||
// Since we know it's a relative path, prefix with a scheme/host placeholder and try again
|
|
||||||
if ( ! $parts = @parse_url( 'placeholder://placeholder' . $url ) ) {
|
|
||||||
return $parts;
|
return $parts;
|
||||||
}
|
}
|
||||||
// Remove the placeholder values
|
|
||||||
|
if ( false === $parts ) {
|
||||||
|
// < PHP 5.4.7 compat, trouble with relative paths including a scheme break in the path.
|
||||||
|
if ( '/' == $url[0] && false !== strpos( $url, '://' ) ) {
|
||||||
|
if ( in_array( $component, array( PHP_URL_SCHEME, PHP_URL_HOST ), true ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Since we know it's a relative path, prefix with a scheme/host placeholder and try again.
|
||||||
|
if ( ! $parts = @parse_url( 'placeholder://placeholder' . $url, $component ) ) {
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
// Remove the placeholder values.
|
||||||
|
if ( -1 === $component ) {
|
||||||
unset( $parts['scheme'], $parts['host'] );
|
unset( $parts['scheme'], $parts['host'] );
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return $parts;
|
return $parts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// < PHP 5.4.7 compat, doesn't detect schemeless URL's host field
|
// < PHP 5.4.7 compat, doesn't detect a schemeless URL's host field.
|
||||||
if ( '//' == substr( $url, 0, 2 ) && ! isset( $parts['host'] ) ) {
|
if ( '//' == substr( $url, 0, 2 ) ) {
|
||||||
|
if ( -1 === $component && ! isset( $parts['host'] ) ) {
|
||||||
$path_parts = explode( '/', substr( $parts['path'], 2 ), 2 );
|
$path_parts = explode( '/', substr( $parts['path'], 2 ), 2 );
|
||||||
$parts['host'] = $path_parts[0];
|
$parts['host'] = $path_parts[0];
|
||||||
if ( isset( $path_parts[1] ) ) {
|
if ( isset( $path_parts[1] ) ) {
|
||||||
|
@ -663,6 +681,21 @@ function wp_parse_url( $url ) {
|
||||||
} else {
|
} else {
|
||||||
unset( $parts['path'] );
|
unset( $parts['path'] );
|
||||||
}
|
}
|
||||||
|
} elseif ( PHP_URL_HOST === $component || PHP_URL_PATH === $component ) {
|
||||||
|
$all_parts = @parse_url( $url );
|
||||||
|
if ( ! isset( $all_parts['host'] ) ) {
|
||||||
|
$path_parts = explode( '/', substr( $all_parts['path'], 2 ), 2 );
|
||||||
|
if ( PHP_URL_PATH === $component ) {
|
||||||
|
if ( isset( $path_parts[1] ) ) {
|
||||||
|
$parts = '/' . $path_parts[1];
|
||||||
|
} else {
|
||||||
|
$parts = null;
|
||||||
|
}
|
||||||
|
} elseif ( PHP_URL_HOST === $component ) {
|
||||||
|
$parts = $path_parts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $parts;
|
return $parts;
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
class Tests_HTTP_HTTP extends WP_UnitTestCase {
|
class Tests_HTTP_HTTP extends WP_UnitTestCase {
|
||||||
|
|
||||||
|
const FULL_TEST_URL = 'http://username:password@host.name:9090/path?arg1=value1&arg2=value2#anchor';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider make_absolute_url_testcases
|
* @dataProvider make_absolute_url_testcases
|
||||||
*/
|
*/
|
||||||
|
@ -78,6 +80,16 @@ class Tests_HTTP_HTTP extends WP_UnitTestCase {
|
||||||
function parse_url_testcases() {
|
function parse_url_testcases() {
|
||||||
// 0: The URL, 1: The expected resulting structure
|
// 0: The URL, 1: The expected resulting structure
|
||||||
return array(
|
return array(
|
||||||
|
array( self::FULL_TEST_URL, array(
|
||||||
|
'scheme' => 'http',
|
||||||
|
'host' => 'host.name',
|
||||||
|
'port' => 9090,
|
||||||
|
'user' => 'username',
|
||||||
|
'pass' => 'password',
|
||||||
|
'path' => '/path',
|
||||||
|
'query' => 'arg1=value1&arg2=value2',
|
||||||
|
'fragment' => 'anchor',
|
||||||
|
) ),
|
||||||
array( 'http://example.com/', array( 'scheme' => 'http', 'host' => 'example.com', 'path' => '/' ) ),
|
array( 'http://example.com/', array( 'scheme' => 'http', 'host' => 'example.com', 'path' => '/' ) ),
|
||||||
|
|
||||||
// < PHP 5.4.7: Schemeless URL
|
// < PHP 5.4.7: Schemeless URL
|
||||||
|
@ -85,7 +97,7 @@ class Tests_HTTP_HTTP extends WP_UnitTestCase {
|
||||||
array( '//example.com/', array( 'host' => 'example.com', 'path' => '/' ) ),
|
array( '//example.com/', array( 'host' => 'example.com', 'path' => '/' ) ),
|
||||||
array( 'http://example.com//path/', array( 'scheme' => 'http', 'host' => 'example.com', 'path' => '//path/' ) ),
|
array( 'http://example.com//path/', array( 'scheme' => 'http', 'host' => 'example.com', 'path' => '//path/' ) ),
|
||||||
|
|
||||||
// < PHP 5.4.7: Scheme seperator in the URL
|
// < PHP 5.4.7: Scheme separator in the URL.
|
||||||
array( 'http://example.com/http://example.net/', array( 'scheme' => 'http', 'host' => 'example.com', 'path' => '/http://example.net/' ) ),
|
array( 'http://example.com/http://example.net/', array( 'scheme' => 'http', 'host' => 'example.com', 'path' => '/http://example.net/' ) ),
|
||||||
array( '/path/http://example.net/', array( 'path' => '/path/http://example.net/' ) ),
|
array( '/path/http://example.net/', array( 'path' => '/path/http://example.net/' ) ),
|
||||||
|
|
||||||
|
@ -103,6 +115,69 @@ class Tests_HTTP_HTTP extends WP_UnitTestCase {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ticket 36356
|
||||||
|
*/
|
||||||
|
function test_wp_parse_url_with_default_component() {
|
||||||
|
$actual = wp_parse_url( self::FULL_TEST_URL, -1 );
|
||||||
|
$this->assertEquals( array(
|
||||||
|
'scheme' => 'http',
|
||||||
|
'host' => 'host.name',
|
||||||
|
'port' => 9090,
|
||||||
|
'user' => 'username',
|
||||||
|
'pass' => 'password',
|
||||||
|
'path' => '/path',
|
||||||
|
'query' => 'arg1=value1&arg2=value2',
|
||||||
|
'fragment' => 'anchor',
|
||||||
|
), $actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ticket 36356
|
||||||
|
*
|
||||||
|
* @dataProvider parse_url_component_testcases
|
||||||
|
*/
|
||||||
|
function test_wp_parse_url_with_component( $url, $component, $expected ) {
|
||||||
|
$actual = wp_parse_url( $url, $component );
|
||||||
|
$this->assertSame( $expected, $actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_url_component_testcases() {
|
||||||
|
// 0: The URL, 1: The requested component, 2: The expected resulting structure.
|
||||||
|
return array(
|
||||||
|
array( self::FULL_TEST_URL, PHP_URL_SCHEME, 'http' ),
|
||||||
|
array( self::FULL_TEST_URL, PHP_URL_USER, 'username' ),
|
||||||
|
array( self::FULL_TEST_URL, PHP_URL_PASS, 'password' ),
|
||||||
|
array( self::FULL_TEST_URL, PHP_URL_HOST, 'host.name' ),
|
||||||
|
array( self::FULL_TEST_URL, PHP_URL_PORT, 9090 ),
|
||||||
|
array( self::FULL_TEST_URL, PHP_URL_PATH, '/path' ),
|
||||||
|
array( self::FULL_TEST_URL, PHP_URL_QUERY, 'arg1=value1&arg2=value2' ),
|
||||||
|
array( self::FULL_TEST_URL, PHP_URL_FRAGMENT, 'anchor' ),
|
||||||
|
|
||||||
|
// < PHP 5.4.7: Schemeless URL.
|
||||||
|
array( '//example.com/path/', PHP_URL_HOST, 'example.com' ),
|
||||||
|
array( '//example.com/path/', PHP_URL_PATH, '/path/' ),
|
||||||
|
array( '//example.com/', PHP_URL_HOST, 'example.com' ),
|
||||||
|
array( '//example.com/', PHP_URL_PATH, '/' ),
|
||||||
|
array( 'http://example.com//path/', PHP_URL_HOST, 'example.com' ),
|
||||||
|
array( 'http://example.com//path/', PHP_URL_PATH, '//path/' ),
|
||||||
|
|
||||||
|
// < PHP 5.4.7: Scheme separator in the URL.
|
||||||
|
array( 'http://example.com/http://example.net/', PHP_URL_HOST, 'example.com' ),
|
||||||
|
array( 'http://example.com/http://example.net/', PHP_URL_PATH, '/http://example.net/' ),
|
||||||
|
array( '/path/http://example.net/', PHP_URL_HOST, null ),
|
||||||
|
array( '/path/http://example.net/', PHP_URL_PATH, '/path/http://example.net/' ),
|
||||||
|
|
||||||
|
// < PHP 5.4.7: IPv6 literals in schemeless URLs are handled incorrectly.
|
||||||
|
array( '//[::FFFF::127.0.0.1]/', PHP_URL_HOST, '[::FFFF::127.0.0.1]' ),
|
||||||
|
array( '//[::FFFF::127.0.0.1]/', PHP_URL_PATH, '/' ),
|
||||||
|
|
||||||
|
// PHP's parse_url() calls this an invalid URL, we handle it as a path.
|
||||||
|
array( '/://example.com/', PHP_URL_PATH, '/://example.com/' ),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ticket 35426
|
* @ticket 35426
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue