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 git-svn-id: https://develop.svn.wordpress.org/trunk@34920 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
f9f92b223d
commit
4046919a11
@ -2137,15 +2137,17 @@ function _make_web_ftp_clickable_cb( $matches ) {
|
||||
$ret = '';
|
||||
$dest = $matches[2];
|
||||
$dest = 'http://' . $dest;
|
||||
$dest = esc_url($dest);
|
||||
if ( empty($dest) )
|
||||
return $matches[0];
|
||||
|
||||
// removed trailing [.,;:)] from URL
|
||||
if ( in_array( substr($dest, -1), array('.', ',', ';', ':', ')') ) === true ) {
|
||||
$ret = substr($dest, -1);
|
||||
$dest = substr($dest, 0, strlen($dest)-1);
|
||||
}
|
||||
|
||||
$dest = esc_url($dest);
|
||||
if ( empty($dest) )
|
||||
return $matches[0];
|
||||
|
||||
return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>$ret";
|
||||
}
|
||||
|
||||
@ -3352,7 +3354,7 @@ function esc_url( $url, $protocols = null, $_context = 'display' ) {
|
||||
return $url;
|
||||
|
||||
$url = str_replace( ' ', '%20', $url );
|
||||
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);
|
||||
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url);
|
||||
|
||||
if ( '' === $url ) {
|
||||
return $url;
|
||||
@ -3365,7 +3367,7 @@ function esc_url( $url, $protocols = null, $_context = 'display' ) {
|
||||
|
||||
$url = str_replace(';//', '://', $url);
|
||||
/* If the URL doesn't appear to contain a scheme, we
|
||||
* presume it needs http:// appended (unless a relative
|
||||
* presume it needs http:// prepended (unless a relative
|
||||
* link starting with /, # or ? or a php file).
|
||||
*/
|
||||
if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) &&
|
||||
@ -3379,6 +3381,43 @@ function esc_url( $url, $protocols = null, $_context = 'display' ) {
|
||||
$url = str_replace( "'", ''', $url );
|
||||
}
|
||||
|
||||
if ( ( false !== strpos( $url, '[' ) ) || ( false !== strpos( $url, ']' ) ) ) {
|
||||
|
||||
$parsed = parse_url( $url );
|
||||
$front = '';
|
||||
|
||||
if ( isset( $parsed['scheme'] ) ) {
|
||||
$front .= $parsed['scheme'] . '://';
|
||||
} elseif ( '/' === $url[0] ) {
|
||||
$front .= '//';
|
||||
}
|
||||
|
||||
if ( isset( $parsed['user'] ) ) {
|
||||
$front .= $parsed['user'];
|
||||
}
|
||||
|
||||
if ( isset( $parsed['pass'] ) ) {
|
||||
$front .= ':' . $parsed['pass'];
|
||||
}
|
||||
|
||||
if ( isset( $parsed['user'] ) || isset( $parsed['pass'] ) ) {
|
||||
$front .= '@';
|
||||
}
|
||||
|
||||
if ( isset( $parsed['host'] ) ) {
|
||||
$front .= $parsed['host'];
|
||||
}
|
||||
|
||||
if ( isset( $parsed['port'] ) ) {
|
||||
$front .= ':' . $parsed['port'];
|
||||
}
|
||||
|
||||
$end_dirty = str_replace( $front, '', $url );
|
||||
$end_clean = str_replace( array( '[', ']' ), array( '%5B', '%5D' ), $end_dirty );
|
||||
$url = str_replace( $end_dirty, $end_clean, $url );
|
||||
|
||||
}
|
||||
|
||||
if ( '/' === $url[0] ) {
|
||||
$good_protocol_url = $url;
|
||||
} else {
|
||||
|
@ -40,15 +40,24 @@ class Tests_Formatting_EscUrl extends WP_UnitTestCase {
|
||||
}
|
||||
|
||||
function test_all_url_parts() {
|
||||
$url = 'https://user:password@host.example.com:1234/path;p=1?q=2&r=3#fragment';
|
||||
$this->assertEquals( $url, esc_url_raw( $url ) );
|
||||
$url = 'https://user:pass@host.example.com:1234/path;p=1?query=2&r[]=3#fragment';
|
||||
|
||||
$this->assertEquals( 'https://user:password@host.example.com:1234/path;p=1?q=2&r=3#fragment', esc_url( $url ) );
|
||||
|
||||
$this->assertEquals( 'http://example.com?foo', esc_url( 'http://example.com?foo' ) );
|
||||
$this->assertEquals( array(
|
||||
'scheme' => 'https',
|
||||
'host' => 'host.example.com',
|
||||
'port' => 1234,
|
||||
'user' => 'user',
|
||||
'pass' => 'pass',
|
||||
'path' => '/path;p=1',
|
||||
'query' => 'query=2&r[]=3',
|
||||
'fragment' => 'fragment',
|
||||
), parse_url( $url ) );
|
||||
$this->assertEquals( 'https://user:pass@host.example.com:1234/path;p=1?query=2&r%5B%5D=3#fragment', esc_url_raw( $url ) );
|
||||
$this->assertEquals( 'https://user:pass@host.example.com:1234/path;p=1?query=2&r%5B%5D=3#fragment', esc_url( $url ) );
|
||||
}
|
||||
|
||||
function test_bare() {
|
||||
$this->assertEquals( 'http://example.com?foo', esc_url( 'example.com?foo' ) );
|
||||
$this->assertEquals( 'http://example.com', esc_url( 'example.com' ) );
|
||||
$this->assertEquals( 'http://localhost', esc_url( 'localhost' ) );
|
||||
$this->assertEquals( 'http://example.com/foo', esc_url( 'example.com/foo' ) );
|
||||
@ -125,6 +134,29 @@ class Tests_Formatting_EscUrl extends WP_UnitTestCase {
|
||||
$this->assertEquals( 'feed:http://wordpress.org/feed/', esc_url( 'feed:http://wordpress.org/feed/' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 16859
|
||||
*/
|
||||
function test_square_brackets() {
|
||||
$this->assertEquals( '/example.php?one%5B%5D=two', esc_url( '/example.php?one[]=two' ) );
|
||||
$this->assertEquals( '?foo%5Bbar%5D=baz', esc_url( '?foo[bar]=baz' ) );
|
||||
$this->assertEquals( '//example.com/?foo%5Bbar%5D=baz', esc_url( '//example.com/?foo[bar]=baz' ) );
|
||||
$this->assertEquals( 'http://example.com/?foo%5Bbar%5D=baz', esc_url( 'example.com/?foo[bar]=baz' ) );
|
||||
$this->assertEquals( 'http://localhost?foo%5Bbar%5D=baz', esc_url( 'localhost?foo[bar]=baz' ) );
|
||||
$this->assertEquals( 'http://example.com/?foo%5Bbar%5D=baz', esc_url( 'http://example.com/?foo[bar]=baz' ) );
|
||||
$this->assertEquals( 'http://example.com/?foo%5Bbar%5D=baz', esc_url( 'http://example.com/?foo%5Bbar%5D=baz' ) );
|
||||
$this->assertEquals( 'http://example.com/?baz=bar&foo%5Bbar%5D=baz', esc_url( 'http://example.com/?baz=bar&foo[bar]=baz' ) );
|
||||
$this->assertEquals( 'http://example.com/?baz=bar&foo%5Bbar%5D=baz', esc_url( 'http://example.com/?baz=bar&foo%5Bbar%5D=baz' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Courtesy of http://blog.lunatech.com/2009/02/03/what-every-web-developer-must-know-about-url-encoding
|
||||
*/
|
||||
function test_reserved_characters() {
|
||||
$url = "http://example.com/:@-._~!$&'()*+,=;:@-._~!$&'()*+,=:@-._~!$&'()*+,==?/?:@-._~!$%27()*+,;=/?:@-._~!$%27()*+,;==#/?:@-._~!$&'()*+,;=";
|
||||
$this->assertEquals( $url, esc_url_raw( $url ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 21974
|
||||
*/
|
||||
@ -175,7 +207,7 @@ EOT;
|
||||
* @ticket 28015
|
||||
*/
|
||||
function test_invalid_charaters() {
|
||||
$this->assertEmpty( esc_url_raw('"^[]<>{}`') );
|
||||
$this->assertEmpty( esc_url_raw('"^<>{}`') );
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user