Follow-up 102587 to address performance concerns in wfRemoveDotSegments.
authorgicode <gicode@localhost>
Sun, 22 Jan 2012 04:57:37 +0000 (04:57 +0000)
committergicode <gicode@localhost>
Sun, 22 Jan 2012 04:57:37 +0000 (04:57 +0000)
includes/GlobalFunctions.php

index 2aab35a..5a80865 100644 (file)
@@ -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];
                }
        }