From: Kunal Mehta Date: Thu, 29 Jan 2015 18:30:57 +0000 (-0800) Subject: StringUtils: throw InvalidArgumentException and move into libs/ X-Git-Tag: 1.31.0-rc.0~12537^2 X-Git-Url: http://git.cyclocoop.org/%28?a=commitdiff_plain;h=4675950b19e58ac702111f51336f132ce97adef5;p=lhc%2Fweb%2Fwiklou.git StringUtils: throw InvalidArgumentException and move into libs/ Bug: T87863 Change-Id: Iac5bd958c27cad834e35930d0b99adb75c60411b --- diff --git a/autoload.php b/autoload.php index e6f0f89bd7..90cd074d7d 100644 --- a/autoload.php +++ b/autoload.php @@ -1155,7 +1155,7 @@ $wgAutoloadLocalClasses = array( 'StoreFileOp' => __DIR__ . '/includes/filebackend/FileOp.php', 'StreamFile' => __DIR__ . '/includes/StreamFile.php', 'StringPrefixSearch' => __DIR__ . '/includes/PrefixSearch.php', - 'StringUtils' => __DIR__ . '/includes/utils/StringUtils.php', + 'StringUtils' => __DIR__ . '/includes/libs/StringUtils.php', 'StripState' => __DIR__ . '/includes/parser/StripState.php', 'StubObject' => __DIR__ . '/includes/StubObject.php', 'StubUserLang' => __DIR__ . '/includes/StubObject.php', diff --git a/includes/libs/StringUtils.php b/includes/libs/StringUtils.php new file mode 100644 index 0000000000..11ae0b26f2 --- /dev/null +++ b/includes/libs/StringUtils.php @@ -0,0 +1,317 @@ +cb(), $subject, $flags ); + } + + /** + * More or less "markup-safe" explode() + * Ignores any instances of the separator inside <...> + * @param string $separator + * @param string $text + * @return array + */ + static function explodeMarkup( $separator, $text ) { + $placeholder = "\x00"; + + // Remove placeholder instances + $text = str_replace( $placeholder, '', $text ); + + // Replace instances of the separator inside HTML-like tags with the placeholder + $replacer = new DoubleReplacer( $separator, $placeholder ); + $cleaned = StringUtils::delimiterReplaceCallback( '<', '>', $replacer->cb(), $text ); + + // Explode, then put the replaced separators back in + $items = explode( $separator, $cleaned ); + foreach ( $items as $i => $str ) { + $items[$i] = str_replace( $placeholder, $separator, $str ); + } + + return $items; + } + + /** + * Escape a string to make it suitable for inclusion in a preg_replace() + * replacement parameter. + * + * @param string $string + * @return string + */ + static function escapeRegexReplacement( $string ) { + $string = str_replace( '\\', '\\\\', $string ); + $string = str_replace( '$', '\\$', $string ); + + return $string; + } + + /** + * Workalike for explode() with limited memory usage. + * Returns an Iterator + * @param string $separator + * @param string $subject + * @return ArrayIterator|ExplodeIterator + */ + static function explode( $separator, $subject ) { + if ( substr_count( $subject, $separator ) > 1000 ) { + return new ExplodeIterator( $separator, $subject ); + } else { + return new ArrayIterator( explode( $separator, $subject ) ); + } + } +} diff --git a/includes/utils/StringUtils.php b/includes/utils/StringUtils.php deleted file mode 100644 index 77fff595bd..0000000000 --- a/includes/utils/StringUtils.php +++ /dev/null @@ -1,317 +0,0 @@ -cb(), $subject, $flags ); - } - - /** - * More or less "markup-safe" explode() - * Ignores any instances of the separator inside <...> - * @param string $separator - * @param string $text - * @return array - */ - static function explodeMarkup( $separator, $text ) { - $placeholder = "\x00"; - - // Remove placeholder instances - $text = str_replace( $placeholder, '', $text ); - - // Replace instances of the separator inside HTML-like tags with the placeholder - $replacer = new DoubleReplacer( $separator, $placeholder ); - $cleaned = StringUtils::delimiterReplaceCallback( '<', '>', $replacer->cb(), $text ); - - // Explode, then put the replaced separators back in - $items = explode( $separator, $cleaned ); - foreach ( $items as $i => $str ) { - $items[$i] = str_replace( $placeholder, $separator, $str ); - } - - return $items; - } - - /** - * Escape a string to make it suitable for inclusion in a preg_replace() - * replacement parameter. - * - * @param string $string - * @return string - */ - static function escapeRegexReplacement( $string ) { - $string = str_replace( '\\', '\\\\', $string ); - $string = str_replace( '$', '\\$', $string ); - - return $string; - } - - /** - * Workalike for explode() with limited memory usage. - * Returns an Iterator - * @param string $separator - * @param string $subject - * @return ArrayIterator|ExplodeIterator - */ - static function explode( $separator, $subject ) { - if ( substr_count( $subject, $separator ) > 1000 ) { - return new ExplodeIterator( $separator, $subject ); - } else { - return new ArrayIterator( explode( $separator, $subject ) ); - } - } -} diff --git a/tests/phpunit/includes/libs/StringUtilsTest.php b/tests/phpunit/includes/libs/StringUtilsTest.php new file mode 100644 index 0000000000..7c24fae6d5 --- /dev/null +++ b/tests/phpunit/includes/libs/StringUtilsTest.php @@ -0,0 +1,149 @@ +markTestSkipped( 'Test requires the mbstring PHP extension' ); + } + $this->assertEquals( $expected, + StringUtils::isUtf8( $string ), + 'Testing string "' . $this->escaped( $string ) . '" with mb_check_encoding' + ); + } + + /** + * This tests StringUtils::isUtf8 making sure we use the pure PHP + * implementation used as a fallback when mb_check_encoding() is + * not available. + * + * @covers StringUtils::isUtf8 + * @dataProvider provideStringsForIsUtf8Check + */ + public function testIsUtf8WithPhpFallbackImplementation( $expected, $string ) { + $this->assertEquals( $expected, + StringUtils::isUtf8( $string, /** disable mbstring: */true ), + 'Testing string "' . $this->escaped( $string ) . '" with pure PHP implementation' + ); + } + + /** + * Print high range characters as a hexadecimal + * @param string $string + * @return string + */ + function escaped( $string ) { + $escaped = ''; + $length = strlen( $string ); + for ( $i = 0; $i < $length; $i++ ) { + $char = $string[$i]; + $val = ord( $char ); + if ( $val > 127 ) { + $escaped .= '\x' . dechex( $val ); + } else { + $escaped .= $char; + } + } + + return $escaped; + } + + /** + * See also "UTF-8 decoder capability and stress test" by + * Markus Kuhn: + * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt + */ + public static function provideStringsForIsUtf8Check() { + // Expected return values for StringUtils::isUtf8() + $PASS = true; + $FAIL = false; + + return array( + 'some ASCII' => array( $PASS, 'Some ASCII' ), + 'euro sign' => array( $PASS, "Euro sign €" ), + + 'first possible sequence 1 byte' => array( $PASS, "\x00" ), + 'first possible sequence 2 bytes' => array( $PASS, "\xc2\x80" ), + 'first possible sequence 3 bytes' => array( $PASS, "\xe0\xa0\x80" ), + 'first possible sequence 4 bytes' => array( $PASS, "\xf0\x90\x80\x80" ), + 'first possible sequence 5 bytes' => array( $FAIL, "\xf8\x88\x80\x80\x80" ), + 'first possible sequence 6 bytes' => array( $FAIL, "\xfc\x84\x80\x80\x80\x80" ), + + 'last possible sequence 1 byte' => array( $PASS, "\x7f" ), + 'last possible sequence 2 bytes' => array( $PASS, "\xdf\xbf" ), + 'last possible sequence 3 bytes' => array( $PASS, "\xef\xbf\xbf" ), + 'last possible sequence 4 bytes (U+1FFFFF)' => array( $FAIL, "\xf7\xbf\xbf\xbf" ), + 'last possible sequence 5 bytes' => array( $FAIL, "\xfb\xbf\xbf\xbf\xbf" ), + 'last possible sequence 6 bytes' => array( $FAIL, "\xfd\xbf\xbf\xbf\xbf\xbf" ), + + 'boundary 1' => array( $PASS, "\xed\x9f\xbf" ), + 'boundary 2' => array( $PASS, "\xee\x80\x80" ), + 'boundary 3' => array( $PASS, "\xef\xbf\xbd" ), + 'boundary 4' => array( $PASS, "\xf2\x80\x80\x80" ), + 'boundary 5 (U+FFFFF)' => array( $PASS, "\xf3\xbf\xbf\xbf" ), + 'boundary 6 (U+100000)' => array( $PASS, "\xf4\x80\x80\x80" ), + 'boundary 7 (U+10FFFF)' => array( $PASS, "\xf4\x8f\xbf\xbf" ), + 'boundary 8 (U+110000)' => array( $FAIL, "\xf4\x90\x80\x80" ), + + 'malformed 1' => array( $FAIL, "\x80" ), + 'malformed 2' => array( $FAIL, "\xbf" ), + 'malformed 3' => array( $FAIL, "\x80\xbf" ), + 'malformed 4' => array( $FAIL, "\x80\xbf\x80" ), + 'malformed 5' => array( $FAIL, "\x80\xbf\x80\xbf" ), + 'malformed 6' => array( $FAIL, "\x80\xbf\x80\xbf\x80" ), + 'malformed 7' => array( $FAIL, "\x80\xbf\x80\xbf\x80\xbf" ), + 'malformed 8' => array( $FAIL, "\x80\xbf\x80\xbf\x80\xbf\x80" ), + + 'last byte missing 1' => array( $FAIL, "\xc0" ), + 'last byte missing 2' => array( $FAIL, "\xe0\x80" ), + 'last byte missing 3' => array( $FAIL, "\xf0\x80\x80" ), + 'last byte missing 4' => array( $FAIL, "\xf8\x80\x80\x80" ), + 'last byte missing 5' => array( $FAIL, "\xfc\x80\x80\x80\x80" ), + 'last byte missing 6' => array( $FAIL, "\xdf" ), + 'last byte missing 7' => array( $FAIL, "\xef\xbf" ), + 'last byte missing 8' => array( $FAIL, "\xf7\xbf\xbf" ), + 'last byte missing 9' => array( $FAIL, "\xfb\xbf\xbf\xbf" ), + 'last byte missing 10' => array( $FAIL, "\xfd\xbf\xbf\xbf\xbf" ), + + 'extra continuation byte 1' => array( $FAIL, "e\xaf" ), + 'extra continuation byte 2' => array( $FAIL, "\xc3\x89\xaf" ), + 'extra continuation byte 3' => array( $FAIL, "\xef\xbc\xa5\xaf" ), + 'extra continuation byte 4' => array( $FAIL, "\xf0\x9d\x99\xb4\xaf" ), + + 'impossible bytes 1' => array( $FAIL, "\xfe" ), + 'impossible bytes 2' => array( $FAIL, "\xff" ), + 'impossible bytes 3' => array( $FAIL, "\xfe\xfe\xff\xff" ), + + 'overlong sequences 1' => array( $FAIL, "\xc0\xaf" ), + 'overlong sequences 2' => array( $FAIL, "\xc1\xaf" ), + 'overlong sequences 3' => array( $FAIL, "\xe0\x80\xaf" ), + 'overlong sequences 4' => array( $FAIL, "\xf0\x80\x80\xaf" ), + 'overlong sequences 5' => array( $FAIL, "\xf8\x80\x80\x80\xaf" ), + 'overlong sequences 6' => array( $FAIL, "\xfc\x80\x80\x80\x80\xaf" ), + + 'maximum overlong sequences 1' => array( $FAIL, "\xc1\xbf" ), + 'maximum overlong sequences 2' => array( $FAIL, "\xe0\x9f\xbf" ), + 'maximum overlong sequences 3' => array( $FAIL, "\xf0\x8f\xbf\xbf" ), + 'maximum overlong sequences 4' => array( $FAIL, "\xf8\x87\xbf\xbf" ), + 'maximum overlong sequences 5' => array( $FAIL, "\xfc\x83\xbf\xbf\xbf\xbf" ), + + 'surrogates 1 (U+D799)' => array( $PASS, "\xed\x9f\xbf" ), + 'surrogates 2 (U+E000)' => array( $PASS, "\xee\x80\x80" ), + 'surrogates 3 (U+D800)' => array( $FAIL, "\xed\xa0\x80" ), + 'surrogates 4 (U+DBFF)' => array( $FAIL, "\xed\xaf\xbf" ), + 'surrogates 5 (U+DC00)' => array( $FAIL, "\xed\xb0\x80" ), + 'surrogates 6 (U+DFFF)' => array( $FAIL, "\xed\xbf\xbf" ), + 'surrogates 7 (U+D800 U+DC00)' => array( $FAIL, "\xed\xa0\x80\xed\xb0\x80" ), + + 'noncharacters 1' => array( $PASS, "\xef\xbf\xbe" ), + 'noncharacters 2' => array( $PASS, "\xef\xbf\xbf" ), + ); + } +} diff --git a/tests/phpunit/includes/utils/StringUtilsTest.php b/tests/phpunit/includes/utils/StringUtilsTest.php deleted file mode 100644 index 7c24fae6d5..0000000000 --- a/tests/phpunit/includes/utils/StringUtilsTest.php +++ /dev/null @@ -1,149 +0,0 @@ -markTestSkipped( 'Test requires the mbstring PHP extension' ); - } - $this->assertEquals( $expected, - StringUtils::isUtf8( $string ), - 'Testing string "' . $this->escaped( $string ) . '" with mb_check_encoding' - ); - } - - /** - * This tests StringUtils::isUtf8 making sure we use the pure PHP - * implementation used as a fallback when mb_check_encoding() is - * not available. - * - * @covers StringUtils::isUtf8 - * @dataProvider provideStringsForIsUtf8Check - */ - public function testIsUtf8WithPhpFallbackImplementation( $expected, $string ) { - $this->assertEquals( $expected, - StringUtils::isUtf8( $string, /** disable mbstring: */true ), - 'Testing string "' . $this->escaped( $string ) . '" with pure PHP implementation' - ); - } - - /** - * Print high range characters as a hexadecimal - * @param string $string - * @return string - */ - function escaped( $string ) { - $escaped = ''; - $length = strlen( $string ); - for ( $i = 0; $i < $length; $i++ ) { - $char = $string[$i]; - $val = ord( $char ); - if ( $val > 127 ) { - $escaped .= '\x' . dechex( $val ); - } else { - $escaped .= $char; - } - } - - return $escaped; - } - - /** - * See also "UTF-8 decoder capability and stress test" by - * Markus Kuhn: - * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt - */ - public static function provideStringsForIsUtf8Check() { - // Expected return values for StringUtils::isUtf8() - $PASS = true; - $FAIL = false; - - return array( - 'some ASCII' => array( $PASS, 'Some ASCII' ), - 'euro sign' => array( $PASS, "Euro sign €" ), - - 'first possible sequence 1 byte' => array( $PASS, "\x00" ), - 'first possible sequence 2 bytes' => array( $PASS, "\xc2\x80" ), - 'first possible sequence 3 bytes' => array( $PASS, "\xe0\xa0\x80" ), - 'first possible sequence 4 bytes' => array( $PASS, "\xf0\x90\x80\x80" ), - 'first possible sequence 5 bytes' => array( $FAIL, "\xf8\x88\x80\x80\x80" ), - 'first possible sequence 6 bytes' => array( $FAIL, "\xfc\x84\x80\x80\x80\x80" ), - - 'last possible sequence 1 byte' => array( $PASS, "\x7f" ), - 'last possible sequence 2 bytes' => array( $PASS, "\xdf\xbf" ), - 'last possible sequence 3 bytes' => array( $PASS, "\xef\xbf\xbf" ), - 'last possible sequence 4 bytes (U+1FFFFF)' => array( $FAIL, "\xf7\xbf\xbf\xbf" ), - 'last possible sequence 5 bytes' => array( $FAIL, "\xfb\xbf\xbf\xbf\xbf" ), - 'last possible sequence 6 bytes' => array( $FAIL, "\xfd\xbf\xbf\xbf\xbf\xbf" ), - - 'boundary 1' => array( $PASS, "\xed\x9f\xbf" ), - 'boundary 2' => array( $PASS, "\xee\x80\x80" ), - 'boundary 3' => array( $PASS, "\xef\xbf\xbd" ), - 'boundary 4' => array( $PASS, "\xf2\x80\x80\x80" ), - 'boundary 5 (U+FFFFF)' => array( $PASS, "\xf3\xbf\xbf\xbf" ), - 'boundary 6 (U+100000)' => array( $PASS, "\xf4\x80\x80\x80" ), - 'boundary 7 (U+10FFFF)' => array( $PASS, "\xf4\x8f\xbf\xbf" ), - 'boundary 8 (U+110000)' => array( $FAIL, "\xf4\x90\x80\x80" ), - - 'malformed 1' => array( $FAIL, "\x80" ), - 'malformed 2' => array( $FAIL, "\xbf" ), - 'malformed 3' => array( $FAIL, "\x80\xbf" ), - 'malformed 4' => array( $FAIL, "\x80\xbf\x80" ), - 'malformed 5' => array( $FAIL, "\x80\xbf\x80\xbf" ), - 'malformed 6' => array( $FAIL, "\x80\xbf\x80\xbf\x80" ), - 'malformed 7' => array( $FAIL, "\x80\xbf\x80\xbf\x80\xbf" ), - 'malformed 8' => array( $FAIL, "\x80\xbf\x80\xbf\x80\xbf\x80" ), - - 'last byte missing 1' => array( $FAIL, "\xc0" ), - 'last byte missing 2' => array( $FAIL, "\xe0\x80" ), - 'last byte missing 3' => array( $FAIL, "\xf0\x80\x80" ), - 'last byte missing 4' => array( $FAIL, "\xf8\x80\x80\x80" ), - 'last byte missing 5' => array( $FAIL, "\xfc\x80\x80\x80\x80" ), - 'last byte missing 6' => array( $FAIL, "\xdf" ), - 'last byte missing 7' => array( $FAIL, "\xef\xbf" ), - 'last byte missing 8' => array( $FAIL, "\xf7\xbf\xbf" ), - 'last byte missing 9' => array( $FAIL, "\xfb\xbf\xbf\xbf" ), - 'last byte missing 10' => array( $FAIL, "\xfd\xbf\xbf\xbf\xbf" ), - - 'extra continuation byte 1' => array( $FAIL, "e\xaf" ), - 'extra continuation byte 2' => array( $FAIL, "\xc3\x89\xaf" ), - 'extra continuation byte 3' => array( $FAIL, "\xef\xbc\xa5\xaf" ), - 'extra continuation byte 4' => array( $FAIL, "\xf0\x9d\x99\xb4\xaf" ), - - 'impossible bytes 1' => array( $FAIL, "\xfe" ), - 'impossible bytes 2' => array( $FAIL, "\xff" ), - 'impossible bytes 3' => array( $FAIL, "\xfe\xfe\xff\xff" ), - - 'overlong sequences 1' => array( $FAIL, "\xc0\xaf" ), - 'overlong sequences 2' => array( $FAIL, "\xc1\xaf" ), - 'overlong sequences 3' => array( $FAIL, "\xe0\x80\xaf" ), - 'overlong sequences 4' => array( $FAIL, "\xf0\x80\x80\xaf" ), - 'overlong sequences 5' => array( $FAIL, "\xf8\x80\x80\x80\xaf" ), - 'overlong sequences 6' => array( $FAIL, "\xfc\x80\x80\x80\x80\xaf" ), - - 'maximum overlong sequences 1' => array( $FAIL, "\xc1\xbf" ), - 'maximum overlong sequences 2' => array( $FAIL, "\xe0\x9f\xbf" ), - 'maximum overlong sequences 3' => array( $FAIL, "\xf0\x8f\xbf\xbf" ), - 'maximum overlong sequences 4' => array( $FAIL, "\xf8\x87\xbf\xbf" ), - 'maximum overlong sequences 5' => array( $FAIL, "\xfc\x83\xbf\xbf\xbf\xbf" ), - - 'surrogates 1 (U+D799)' => array( $PASS, "\xed\x9f\xbf" ), - 'surrogates 2 (U+E000)' => array( $PASS, "\xee\x80\x80" ), - 'surrogates 3 (U+D800)' => array( $FAIL, "\xed\xa0\x80" ), - 'surrogates 4 (U+DBFF)' => array( $FAIL, "\xed\xaf\xbf" ), - 'surrogates 5 (U+DC00)' => array( $FAIL, "\xed\xb0\x80" ), - 'surrogates 6 (U+DFFF)' => array( $FAIL, "\xed\xbf\xbf" ), - 'surrogates 7 (U+D800 U+DC00)' => array( $FAIL, "\xed\xa0\x80\xed\xb0\x80" ), - - 'noncharacters 1' => array( $PASS, "\xef\xbf\xbe" ), - 'noncharacters 2' => array( $PASS, "\xef\xbf\xbf" ), - ); - } -}