From 6d21ed0d9952b31dfa8bf08924566a296a81dc2c Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Wed, 7 Oct 2015 23:39:23 +0000 Subject: [PATCH] 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 Built from https://develop.svn.wordpress.org/trunk@34920 git-svn-id: http://core.svn.wordpress.org/trunk@34885 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/formatting.php | 49 ++++++++++++++++++++++++++++++++++---- wp-includes/version.php | 2 +- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/wp-includes/formatting.php b/wp-includes/formatting.php index 3dad658e52..2efef24c1e 100644 --- a/wp-includes/formatting.php +++ b/wp-includes/formatting.php @@ -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] . "$dest$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 { diff --git a/wp-includes/version.php b/wp-includes/version.php index bebc61f0b0..f3e42b7be3 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.4-alpha-34919'; +$wp_version = '4.4-alpha-34920'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.