1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-09-19 16:38:51 +02:00

Provide some "preg_*" wrappers which raise exceptions on failure

Summary: Ref T13608. Ref T13100. Ref T13586. Properly checking "preg_match()" and similar calls for failure and raising useful exceptions is complicated and error-prone. Provide wrapper functions with an API that's more consistent with the rest of the codebase: matches are returned; and errors raise detailed exceptions.

Test Plan: See next change.

Maniphest Tasks: T13608, T13586, T13100

Differential Revision: https://secure.phabricator.com/D21561
This commit is contained in:
epriestley 2021-02-17 12:42:09 -08:00
parent f501f85eb8
commit 9d5802cb9f
3 changed files with 94 additions and 0 deletions

View file

@ -849,6 +849,7 @@ phutil_register_library_map(array(
'PhutilRawEnglishLocale' => 'internationalization/locales/PhutilRawEnglishLocale.php', 'PhutilRawEnglishLocale' => 'internationalization/locales/PhutilRawEnglishLocale.php',
'PhutilReadableSerializer' => 'readableserializer/PhutilReadableSerializer.php', 'PhutilReadableSerializer' => 'readableserializer/PhutilReadableSerializer.php',
'PhutilReadableSerializerTestCase' => 'readableserializer/__tests__/PhutilReadableSerializerTestCase.php', 'PhutilReadableSerializerTestCase' => 'readableserializer/__tests__/PhutilReadableSerializerTestCase.php',
'PhutilRegexException' => 'exception/PhutilRegexException.php',
'PhutilRope' => 'utils/PhutilRope.php', 'PhutilRope' => 'utils/PhutilRope.php',
'PhutilRopeTestCase' => 'utils/__tests__/PhutilRopeTestCase.php', 'PhutilRopeTestCase' => 'utils/__tests__/PhutilRopeTestCase.php',
'PhutilServiceProfiler' => 'serviceprofiler/PhutilServiceProfiler.php', 'PhutilServiceProfiler' => 'serviceprofiler/PhutilServiceProfiler.php',
@ -1009,6 +1010,9 @@ phutil_register_library_map(array(
'phutil_partition' => 'utils/utils.php', 'phutil_partition' => 'utils/utils.php',
'phutil_passthru' => 'future/exec/execx.php', 'phutil_passthru' => 'future/exec/execx.php',
'phutil_person' => 'internationalization/pht.php', 'phutil_person' => 'internationalization/pht.php',
'phutil_preg_match' => 'utils/utils.php',
'phutil_preg_match_all' => 'utils/utils.php',
'phutil_raise_preg_exception' => 'utils/utils.php',
'phutil_register_library' => 'init/lib/core.php', 'phutil_register_library' => 'init/lib/core.php',
'phutil_register_library_map' => 'init/lib/core.php', 'phutil_register_library_map' => 'init/lib/core.php',
'phutil_set_system_locale' => 'utils/utf8.php', 'phutil_set_system_locale' => 'utils/utf8.php',
@ -1925,6 +1929,7 @@ phutil_register_library_map(array(
'PhutilRawEnglishLocale' => 'PhutilLocale', 'PhutilRawEnglishLocale' => 'PhutilLocale',
'PhutilReadableSerializer' => 'Phobject', 'PhutilReadableSerializer' => 'Phobject',
'PhutilReadableSerializerTestCase' => 'PhutilTestCase', 'PhutilReadableSerializerTestCase' => 'PhutilTestCase',
'PhutilRegexException' => 'Exception',
'PhutilRope' => 'Phobject', 'PhutilRope' => 'Phobject',
'PhutilRopeTestCase' => 'PhutilTestCase', 'PhutilRopeTestCase' => 'PhutilTestCase',
'PhutilServiceProfiler' => 'Phobject', 'PhutilServiceProfiler' => 'Phobject',

View file

@ -0,0 +1,3 @@
<?php
final class PhutilRegexException extends Exception {}

View file

@ -2008,3 +2008,89 @@ function phutil_partition(array $map) {
return $partitions; return $partitions;
} }
function phutil_preg_match(
$pattern,
$subject,
$flags = 0,
$offset = 0) {
$matches = null;
$result = @preg_match($pattern, $subject, $matches, $flags, $offset);
if ($result === false || $result === null) {
phutil_raise_preg_exception(
'preg_match',
array(
$pattern,
$subject,
$matches,
$flags,
$offset,
));
}
return $matches;
}
function phutil_preg_match_all(
$pattern,
$subject,
$flags = 0,
$offset = 0) {
$matches = null;
$result = @preg_match_all($pattern, $subject, $matches, $flags, $offset);
if ($result === false || $result === null) {
phutil_raise_preg_exception(
'preg_match_all',
array(
$pattern,
$subject,
$matches,
$flags,
$offset,
));
}
return $matches;
}
function phutil_raise_preg_exception($function, array $argv) {
$trap = new PhutilErrorTrap();
// NOTE: This ugly construction to avoid issues with reference behavior when
// passing values through "call_user_func_array()".
switch ($function) {
case 'preg_match':
@preg_match($argv[0], $argv[1], $argv[2], $argv[3], $argv[4]);
break;
case 'preg_match_all':
@preg_match_all($argv[0], $argv[1], $argv[2], $argv[3], $argv[4]);
break;
}
$error_message = $trap->getErrorsAsString();
$trap->destroy();
$pattern = $argv[0];
$pattern_display = sprintf(
'"%s"',
addcslashes($pattern, '\\\"'));
$message = array();
$message[] = pht(
'Call to %s(%s, ...) failed.',
$function,
$pattern_display);
if (strlen($error_message)) {
$message[] = pht(
'Regular expression engine emitted message: %s',
$error_message);
}
$message = implode("\n\n", $message);
throw new PhutilRegexException($message);
}