From d0720e784ee094d0390ec38799878eaa99f1837b Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Fri, 16 Aug 2013 10:29:32 +0800 Subject: [PATCH 1/2] MDL-40877 core_text: Added UTF-8 safe strrchr method --- lib/tests/textlib_test.php | 12 ++++++++++++ lib/textlib.class.php | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/lib/tests/textlib_test.php b/lib/tests/textlib_test.php index 35f500dcd04..6ffcf06ff9e 100644 --- a/lib/tests/textlib_test.php +++ b/lib/tests/textlib_test.php @@ -366,6 +366,18 @@ class core_textlib_testcase extends advanced_testcase { $this->assertSame($textlib->specialtoascii('ábc'), 'abc'); $this->assertSame($textlib->strtotitle('abc ABC'), 'Abc Abc'); } + + /** + * Test strrchr. + */ + public function test_strrchr() { + $str = "Žluťoučký koníček"; + $this->assertSame('koníček', textlib::strrchr($str, 'koní')); + $this->assertSame('Žluťoučký ', textlib::strrchr($str, 'koní', true)); + $this->assertFalse(textlib::strrchr($str, 'A')); + $this->assertFalse(textlib::strrchr($str, 'ç', true)); + } + } diff --git a/lib/textlib.class.php b/lib/textlib.class.php index bddcaa721d6..37351e0ca0e 100644 --- a/lib/textlib.class.php +++ b/lib/textlib.class.php @@ -238,6 +238,36 @@ class textlib { return $result; } + /** + * Finds the last occurrence of a character in a string within another. + * UTF-8 ONLY safe mb_strrchr(). + * + * @param string $haystack The string from which to get the last occurrence of needle. + * @param string $needle The string to find in haystack. + * @param boolean $part If true, returns the portion before needle, else return the portion after (including needle). + * @return string|false False when not found. + * @since 2.4.6, 2.5.2, 2.6 + */ + public static function strrchr($haystack, $needle, $part = false) { + + if (function_exists('mb_strrchr')) { + return mb_strrchr($haystack, $needle, $part, 'UTF-8'); + } + + $pos = self::strrpos($haystack, $needle); + if ($pos === false) { + return false; + } + + $length = null; + if ($part) { + $length = $pos; + $pos = 0; + } + + return self::substr($haystack, $pos, $length, 'utf-8'); + } + /** * Multibyte safe strlen() function, uses mbstring or iconv for UTF-8, falls back to typo3. * From a8f5f4b6e2f5b47834396c657607174a5ac07bba Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Tue, 13 Aug 2013 09:35:59 +0800 Subject: [PATCH 2/2] MDL-40877 repository_url: Use textlib functions instead of mb_strlen() --- repository/url/locallib.php | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/repository/url/locallib.php b/repository/url/locallib.php index 042350b4951..3a470170274 100644 --- a/repository/url/locallib.php +++ b/repository/url/locallib.php @@ -40,6 +40,8 @@ * See: http://www.opensource.org/licenses/bsd-license.php */ +defined('MOODLE_INTERNAL') || die(); + /** * Combine a base URL and a relative URL to produce a new * absolute URL. The base URL is often the URL of a page, @@ -79,9 +81,9 @@ function url_to_absolute( $baseUrl, $relativeUrl ) if ( $b === FALSE || empty( $b['scheme'] ) || empty( $b['host'] ) ) return FALSE; $r['scheme'] = $b['scheme']; - if (empty($b['path'])) { - $b['path'] = ''; - } + if (empty($b['path'])) { + $b['path'] = ''; + } // If relative URL has an authority, clean path and return. if ( isset( $r['host'] ) ) @@ -110,15 +112,16 @@ function url_to_absolute( $baseUrl, $relativeUrl ) return join_url( $r ); } - // If relative URL path doesn't start with /, merge with base path - if ( $r['path'][0] != '/' ) - { - $base = mb_strrchr( $b['path'], '/', TRUE, 'UTF-8' ); - if ( $base === FALSE ) $base = ''; + // If relative URL path doesn't start with /, merge with base path. + if ($r['path'][0] != '/') { + $base = textlib::strrchr($b['path'], '/', TRUE); + if ($base === FALSE) { + $base = ''; + } $r['path'] = $base . '/' . $r['path']; } - $r['path'] = url_remove_dot_segments( $r['path'] ); - return join_url( $r ); + $r['path'] = url_remove_dot_segments($r['path']); + return join_url($r); } /** @@ -152,12 +155,15 @@ function url_remove_dot_segments( $path ) array_push( $outSegs, $seg ); } $outPath = implode( '/', $outSegs ); - if ( $path[0] == '/' ) + + if ($path[0] == '/') { $outPath = '/' . $outPath; - // compare last multi-byte character against '/' - if ( $outPath != '/' && - (mb_strlen($path)-1) == mb_strrpos( $path, '/', 'UTF-8' ) ) + } + + // Compare last multi-byte character against '/'. + if ($outPath != '/' && (textlib::strlen($path) - 1) == textlib::strrpos($path, '/', 'UTF-8')) { $outPath .= '/'; + } return $outPath; }