From f174914db9f77ae2fb15aa140a22ec2c2a8ebf31 Mon Sep 17 00:00:00 2001 From: gicode Date: Sun, 22 Jan 2012 04:57:37 +0000 Subject: [PATCH] Follow-up 102587 to address performance concerns in wfRemoveDotSegments. --- includes/GlobalFunctions.php | 58 ++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 2aab35a5c7..5a80865ef1 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -577,29 +577,49 @@ function wfAssembleUrl( $urlParts ) { */ function wfRemoveDotSegments( $urlPath ) { $output = ''; - - while ( $urlPath ) { - $matches = null; - if ( preg_match('%^\.\.?/%', $urlPath, $matches) ) { - # Step A, remove leading "../" or "./" - $urlPath = substr( $urlPath, strlen( $matches[0] ) ); - } elseif ( preg_match( '%^/\.(/|$)%', $urlPath, $matches ) ) { - # Step B, replace leading "/.$" or "/./" with "/" - $start = strlen( $matches[0] ); - $urlPath = '/' . substr( $urlPath, $start ); - } elseif ( preg_match( '%^/\.\.(/|$)%', $urlPath, $matches ) ) { - # Step C, replace leading "/..$" or "/../" with "/" and + $inputOffset = 0; + $inputLength = strlen( $urlPath ); + + while ( $inputOffset < $inputLength ) { + $prefixLengthOne = substr( $urlPath, $inputOffset, 1 ); + $prefixLengthTwo = substr( $urlPath, $inputOffset, 2 ); + $prefixLengthThree = substr( $urlPath, $inputOffset, 3 ); + $prefixLengthFour = substr( $urlPath, $inputOffset, 4 ); + + if ( $prefixLengthTwo == './' ) { + # Step A, remove leading "./" + $inputOffset += 2; + } elseif ( $prefixLengthThree == '../' ) { + # Step A, remove leading "../" + $inputOffset += 3; + } elseif ( ( $prefixLengthTwo == '/.' ) && ( $inputOffset + 2 == $inputLength ) ) { + # Step B, replace leading "/.$" with "/" + $inputOffset += 1; + $urlPath[$inputOffset] = '/'; + } elseif ( $prefixLengthThree == '/./' ) { + # Step B, replace leading "/./" with "/" + $inputOffset += 2; + } elseif ( $prefixLengthThree == '/..' && ( $inputOffset + 3 == $inputLength ) ) { + # Step C, replace leading "/..$" with "/" and + # remove last path component in output + $inputOffset += 2; + $urlPath[$inputOffset] = '/'; + $output = preg_replace('%(^|/)[^/]*$%', '', $output); + } elseif ( $prefixLengthFour == '/../' ) { + # Step C, replace leading "/../" with "/" and # remove last path component in output - $start = strlen( $matches[0] ); - $urlPath = '/' . substr( $urlPath, $start ); + $inputOffset += 3; $output = preg_replace('%(^|/)[^/]*$%', '', $output); - } elseif ( preg_match( '%^\.\.?$%', $urlPath, $matches ) ) { - # Step D, remove "^..$" or "^.$" - $urlPath = ''; + } elseif ( ( $prefixLengthOne == '.' ) && ( $inputOffset + 1 == $inputLength ) ) { + # Step D, remove "^.$" + $inputOffset += 1; + } elseif ( ( $prefixLengthTwo == '..' ) && ( $inputOffset + 2 == $inputLength ) ) { + # Step D, remove "^..$" + $inputOffset += 2; } else { # Step E, move leading path segment to output - preg_match( '%^/?[^/]*%', $urlPath, $matches ); - $urlPath = substr( $urlPath, strlen( $matches[0] ) ); + preg_match( '%/?[^/]*%A', $urlPath, $matches, 0, $inputOffset ); + $inputOffset += strlen( $matches[0] ); $output .= $matches[0]; } } -- 2.20.1