Make WordPress Core

Ticket #36356: 36356-wp_parse_url.patch

File 36356-wp_parse_url.patch, 6.4 KB (added by jrf, 8 years ago)

Add $component parameter - includes unit tests

  • src/wp-includes/http.php

    From 6c3dfe202c34de831c3968e3af428d2160abdb05 Mon Sep 17 00:00:00 2001
    From: jrfnl <github_nospam@adviesenzo.nl>
    Date: Thu, 31 Mar 2016 11:07:17 +0200
    Subject: [PATCH] Add the $component parameter to the wp_parse_url() function.
    
    ---
     src/wp-includes/http.php          | 59 +++++++++++++++++++++++++++++----------
     tests/phpunit/tests/http/http.php | 54 +++++++++++++++++++++++++++++++++++
     2 files changed, 98 insertions(+), 15 deletions(-)
    
    diff --git a/src/wp-includes/http.php b/src/wp-includes/http.php
    index dc75037..dddb463 100644
    a b function ms_allowed_http_request_hosts( $is_external, $host ) { 
    630630 * when URL parsing failed.
    631631 *
    632632 * @since 4.4.0
    633  *
    634  * @param string $url The URL to parse.
    635  * @return bool|array False on failure; Array of URL components on success;
    636  *                    See parse_url()'s return values.
     633 * @since 4.6.0 The $component parameter was added for function completeness.
     634 *
     635 * @param string $url       The URL to parse.
     636 * @param int    $component The specific component to retrieve. Use one of the PHP
     637 *                          predefined constants to specify which one.
     638 *                          Defaults to -1 (= return all parts as an array).
     639 *                          @see http://php.net/manual/en/function.parse-url.php
     640 * @return mixed False on failure; Array of URL components on success;
     641 *               When a specific component has been requested: null if the component doesn't
     642 *               exist in the given URL; a sting or - in the case of PHP_URL_PORT - integer
     643 *               when it does;
     644 *               See parse_url()'s return values.
    637645 */
    638 function wp_parse_url( $url ) {
    639         $parts = @parse_url( $url );
    640         if ( ! $parts ) {
     646function wp_parse_url( $url, $component = -1 ) {
     647        $parts = @parse_url( $url, $component );
     648
     649        if ( version_compare( PHP_VERSION, '5.4.7', '>=' ) ) {
     650                return $parts;
     651        }
     652
     653        if ( false === $parts ) {
    641654                // < PHP 5.4.7 compat, trouble with relative paths including a scheme break in the path
    642655                if ( '/' == $url[0] && false !== strpos( $url, '://' ) ) {
    643656                        // Since we know it's a relative path, prefix with a scheme/host placeholder and try again
    644                         if ( ! $parts = @parse_url( 'placeholder://placeholder' . $url ) ) {
     657                        if ( ! $parts = @parse_url( 'placeholder://placeholder' . $url, $component ) ) {
    645658                                return $parts;
    646659                        }
    647660                        // Remove the placeholder values
    function wp_parse_url( $url ) { 
    652665        }
    653666
    654667        // < PHP 5.4.7 compat, doesn't detect schemeless URL's host field
    655         if ( '//' == substr( $url, 0, 2 ) && ! isset( $parts['host'] ) ) {
    656                 $path_parts = explode( '/', substr( $parts['path'], 2 ), 2 );
    657                 $parts['host'] = $path_parts[0];
    658                 if ( isset( $path_parts[1] ) ) {
    659                         $parts['path'] = '/' . $path_parts[1];
    660                 } else {
    661                         unset( $parts['path'] );
     668        if ( '//' == substr( $url, 0, 2 ) ) {
     669                if ( -1 === $component && ! isset( $parts['host'] ) ) {
     670                        $path_parts = explode( '/', substr( $parts['path'], 2 ), 2 );
     671                        $parts['host'] = $path_parts[0];
     672                        if ( isset( $path_parts[1] ) ) {
     673                                $parts['path'] = '/' . $path_parts[1];
     674                        } else {
     675                                unset( $parts['path'] );
     676                        }
     677                } elseif ( PHP_URL_HOST === $component || PHP_URL_PATH === $component ) {
     678                        $all_parts = @parse_url( $url );
     679                        if ( ! isset( $all_parts['host'] ) ) {
     680                                $path_parts = explode( '/', substr( $all_parts['path'], 2 ), 2 );
     681                                if ( PHP_URL_PATH === $component ) {
     682                                        if ( isset( $path_parts[1] ) ) {
     683                                                $parts = '/' . $path_parts[1];
     684                                        } else {
     685                                                $parts = null;
     686                                        }
     687                                } elseif ( PHP_URL_HOST === $component ) {
     688                                        $parts = $path_parts[0];
     689                                }
     690                        }
    662691                }
    663692        }
    664693
  • tests/phpunit/tests/http/http.php

    diff --git a/tests/phpunit/tests/http/http.php b/tests/phpunit/tests/http/http.php
    index 74eda29..9e81bce 100644
    a b class Tests_HTTP_HTTP extends WP_UnitTestCase { 
    104104        }
    105105
    106106        /**
     107         * @ticket 36356
     108         *
     109         * @dataProvider parse_url_component_testcases
     110         */
     111        function test_wp_parse_url_with_component( $url, $component, $expected ) {
     112                $actual = wp_parse_url( $url, $component );
     113                $this->assertEquals( $expected, $actual );
     114        }
     115
     116        function parse_url_component_testcases() {
     117                $test_url = 'http://username:password@hostname:9090/path?arg=value#anchor';
     118
     119                // 0: The URL, 1: The requested component, 2: The expected resulting structure.
     120                return array(
     121                        array( $test_url, -1, array( 'scheme' => 'http', 'host' => 'hostname', 'port' => 9090, 'user' => 'username', 'pass' => 'password', 'path' => '/path', 'query' => 'arg=value', 'fragment' => 'anchor' ) ),
     122                        array( $test_url, PHP_URL_SCHEME, 'http' ),
     123                        array( $test_url, PHP_URL_USER, 'username' ),
     124                        array( $test_url, PHP_URL_PASS, 'password' ),
     125                        array( $test_url, PHP_URL_HOST, 'hostname' ),
     126                        array( $test_url, PHP_URL_PORT, 9090 ),
     127                        array( $test_url, PHP_URL_PATH, '/path' ),
     128                        array( $test_url, PHP_URL_QUERY, 'arg=value' ),
     129                        array( $test_url, PHP_URL_FRAGMENT, 'anchor' ),
     130
     131                        // < PHP 5.4.7: Schemeless URL
     132                        array( '//example.com/path/', PHP_URL_HOST, 'example.com' ),
     133                        array( '//example.com/path/', PHP_URL_PATH, '/path/' ),
     134                        array( '//example.com/', PHP_URL_HOST, 'example.com' ),
     135                        array( '//example.com/', PHP_URL_PATH, '/' ),
     136                        array( 'http://example.com//path/', PHP_URL_HOST, 'example.com' ),
     137                        array( 'http://example.com//path/', PHP_URL_PATH, '//path/' ),
     138
     139                        // < PHP 5.4.7: Scheme seperator in the URL
     140                        array( 'http://example.com/http://example.net/', PHP_URL_HOST, 'example.com' ),
     141                        array( 'http://example.com/http://example.net/', PHP_URL_PATH, '/http://example.net/' ),
     142                        array( '/path/http://example.net/', PHP_URL_HOST, null ),
     143                        array( '/path/http://example.net/', PHP_URL_PATH, '/path/http://example.net/' ),
     144
     145                        // < PHP 5.4.7: IPv6 literals in schemeless URLs are handled incorrectly.
     146                        array( '//[::FFFF::127.0.0.1]/', PHP_URL_HOST, '[::FFFF::127.0.0.1]' ),
     147                        array( '//[::FFFF::127.0.0.1]/', PHP_URL_PATH, '/' ),
     148
     149                        // PHP's parse_url() calls this an invalid url, we handle it as a path
     150                        array( '/://example.com/', PHP_URL_PATH, '/://example.com/' ),
     151
     152                );
     153                /*
     154                Untestable edge cases in various PHP:
     155                  - ///example.com - Fails in PHP >= 5.4.7, assumed path in <5.4.7
     156                  - ://example.com - assumed path in PHP >= 5.4.7, fails in <5.4.7
     157                */
     158        }
     159
     160        /**
    107161         * @ticket 35426
    108162         */
    109163        public function test_http_response_code_constants() {