Make WordPress Core

Changeset 34920


Ignore:
Timestamp:
10/07/2015 11:38:22 PM (9 years ago)
Author:
johnbillion
Message:

Avoid stripping square brackets from URLs, and instead correctly encode them. Square brackets must be encoded in the path, path parameters, query parameters, and fragment, but must not be encoded in anything up to the domain and port.

Adds tests.

Fixes #16859

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/formatting.php

    r34770 r34920  
    21382138    $dest = $matches[2];
    21392139    $dest = 'http://' . $dest;
    2140     $dest = esc_url($dest);
    2141     if ( empty($dest) )
    2142         return $matches[0];
    21432140
    21442141    // removed trailing [.,;:)] from URL
     
    21472144        $dest = substr($dest, 0, strlen($dest)-1);
    21482145    }
     2146
     2147    $dest = esc_url($dest);
     2148    if ( empty($dest) )
     2149        return $matches[0];
     2150
    21492151    return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>$ret";
    21502152}
     
    33533355
    33543356    $url = str_replace( ' ', '%20', $url );
    3355     $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);
     3357    $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url);
    33563358
    33573359    if ( '' === $url ) {
     
    33663368    $url = str_replace(';//', '://', $url);
    33673369    /* If the URL doesn't appear to contain a scheme, we
    3368      * presume it needs http:// appended (unless a relative
     3370     * presume it needs http:// prepended (unless a relative
    33693371     * link starting with /, # or ? or a php file).
    33703372     */
     
    33783380        $url = str_replace( '&amp;', '&#038;', $url );
    33793381        $url = str_replace( "'", '&#039;', $url );
     3382    }
     3383
     3384    if ( ( false !== strpos( $url, '[' ) ) || ( false !== strpos( $url, ']' ) ) ) {
     3385
     3386        $parsed = parse_url( $url );
     3387        $front  = '';
     3388
     3389        if ( isset( $parsed['scheme'] ) ) {
     3390            $front .= $parsed['scheme'] . '://';
     3391        } elseif ( '/' === $url[0] ) {
     3392            $front .= '//';
     3393        }
     3394
     3395        if ( isset( $parsed['user'] ) ) {
     3396            $front .= $parsed['user'];
     3397        }
     3398
     3399        if ( isset( $parsed['pass'] ) ) {
     3400            $front .= ':' . $parsed['pass'];
     3401        }
     3402
     3403        if ( isset( $parsed['user'] ) || isset( $parsed['pass'] ) ) {
     3404            $front .= '@';
     3405        }
     3406
     3407        if ( isset( $parsed['host'] ) ) {
     3408            $front .= $parsed['host'];
     3409        }
     3410
     3411        if ( isset( $parsed['port'] ) ) {
     3412            $front .= ':' . $parsed['port'];
     3413        }
     3414
     3415        $end_dirty = str_replace( $front, '', $url );
     3416        $end_clean = str_replace( array( '[', ']' ), array( '%5B', '%5D' ), $end_dirty );
     3417        $url       = str_replace( $end_dirty, $end_clean, $url );
     3418
    33803419    }
    33813420
  • trunk/tests/phpunit/tests/formatting/EscUrl.php

    r34675 r34920  
    4141
    4242    function test_all_url_parts() {
    43         $url = 'https://user:password@host.example.com:1234/path;p=1?q=2&r=3#fragment';
    44         $this->assertEquals( $url, esc_url_raw( $url ) );
    45 
    46         $this->assertEquals( 'https://user:password@host.example.com:1234/path;p=1?q=2&#038;r=3#fragment', esc_url( $url ) );
    47 
    48         $this->assertEquals( 'http://example.com?foo', esc_url( 'http://example.com?foo' ) );
     43        $url = 'https://user:pass@host.example.com:1234/path;p=1?query=2&r[]=3#fragment';
     44
     45        $this->assertEquals( array(
     46            'scheme'   => 'https',
     47            'host'     => 'host.example.com',
     48            'port'     => 1234,
     49            'user'     => 'user',
     50            'pass'     => 'pass',
     51            'path'     => '/path;p=1',
     52            'query'    => 'query=2&r[]=3',
     53            'fragment' => 'fragment',
     54        ), parse_url( $url ) );
     55        $this->assertEquals( 'https://user:pass@host.example.com:1234/path;p=1?query=2&r%5B%5D=3#fragment', esc_url_raw( $url ) );
     56        $this->assertEquals( 'https://user:pass@host.example.com:1234/path;p=1?query=2&#038;r%5B%5D=3#fragment', esc_url( $url ) );
    4957    }
    5058
    5159    function test_bare() {
     60        $this->assertEquals( 'http://example.com?foo', esc_url( 'example.com?foo' ) );
    5261        $this->assertEquals( 'http://example.com', esc_url( 'example.com' ) );
    5362        $this->assertEquals( 'http://localhost', esc_url( 'localhost' ) );
     
    127136
    128137    /**
     138     * @ticket 16859
     139     */
     140    function test_square_brackets() {
     141        $this->assertEquals( '/example.php?one%5B%5D=two', esc_url( '/example.php?one[]=two' ) );
     142        $this->assertEquals( '?foo%5Bbar%5D=baz', esc_url( '?foo[bar]=baz' ) );
     143        $this->assertEquals( '//example.com/?foo%5Bbar%5D=baz', esc_url( '//example.com/?foo[bar]=baz' ) );
     144        $this->assertEquals( 'http://example.com/?foo%5Bbar%5D=baz', esc_url( 'example.com/?foo[bar]=baz' ) );
     145        $this->assertEquals( 'http://localhost?foo%5Bbar%5D=baz', esc_url( 'localhost?foo[bar]=baz' ) );
     146        $this->assertEquals( 'http://example.com/?foo%5Bbar%5D=baz', esc_url( 'http://example.com/?foo[bar]=baz' ) );
     147        $this->assertEquals( 'http://example.com/?foo%5Bbar%5D=baz', esc_url( 'http://example.com/?foo%5Bbar%5D=baz' ) );
     148        $this->assertEquals( 'http://example.com/?baz=bar&#038;foo%5Bbar%5D=baz', esc_url( 'http://example.com/?baz=bar&foo[bar]=baz' ) );
     149        $this->assertEquals( 'http://example.com/?baz=bar&#038;foo%5Bbar%5D=baz', esc_url( 'http://example.com/?baz=bar&#038;foo%5Bbar%5D=baz' ) );
     150    }
     151
     152    /**
     153     * Courtesy of http://blog.lunatech.com/2009/02/03/what-every-web-developer-must-know-about-url-encoding
     154     */
     155    function test_reserved_characters() {
     156        $url = "http://example.com/:@-._~!$&'()*+,=;:@-._~!$&'()*+,=:@-._~!$&'()*+,==?/?:@-._~!$%27()*+,;=/?:@-._~!$%27()*+,;==#/?:@-._~!$&'()*+,;=";
     157        $this->assertEquals( $url, esc_url_raw( $url ) );
     158    }
     159
     160    /**
    129161     * @ticket 21974
    130162     */
     
    176208     */
    177209    function test_invalid_charaters() {
    178         $this->assertEmpty( esc_url_raw('"^[]<>{}`') );
     210        $this->assertEmpty( esc_url_raw('"^<>{}`') );
    179211    }
    180212
Note: See TracChangeset for help on using the changeset viewer.