Use preg_match rather than fnmatch for 'like' operator

fnmatch() will not recognize 'é' as a single character when the LC_CTYPE locale
is set to C / POSIX. So transform the shell-style pattern to PCRE, and use
preg_match() instead.

fnmatch() was not available on Windows prior to PHP 5.3, so code snippets for
preg_match()-powered polyfills abound. I used the pattern translation map from
<http://www.php.net/manual/en/function.fnmatch.php#100207> after testing
different implementations and finding it to be the most complete.

Bug: 66930
Change-Id: Ice12c7b9dbe6472fe4131679a48a0ad54fac6394
This commit is contained in:
Ori Livneh 2014-06-23 11:25:11 -07:00
parent f0325d3a92
commit ea46bfdd16

View file

@ -69,6 +69,18 @@ class AFPData {
const DFloat = 'float';
const DList = 'list';
// Translation table mapping shell-style wildcards to PCRE equivalents.
// Derived from <http://www.php.net/manual/en/function.fnmatch.php#100207>
private static $wildcardMap = array(
'\*' => '.*',
'\.' => '\.',
'\?' => '.',
'\[' => '[',
'\[\!' => '[^',
'\\' => '\\\\',
'\]' => ']',
);
public $type;
public $data;
@ -247,9 +259,9 @@ class AFPData {
*/
public static function keywordLike( $str, $pattern ) {
$str = $str->toString();
$pattern = $pattern->toString();
$pattern = '#^' . strtr( preg_quote( $pattern->toString(), '#' ), self::$wildcardMap ) . '$#u';
wfSuppressWarnings();
$result = fnmatch( $pattern, $str );
$result = preg_match( $pattern, $str );
wfRestoreWarnings();
return new AFPData( self::DBool, (bool)$result );
}