diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-09-15 11:26:59 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-09-15 12:03:18 +0200 |
commit | d81ea5e9285d0eb49c730e1ea7cccf3fefa1fad5 (patch) | |
tree | b73ee4ebf270bea814263996bbd062000c5d0b79 | |
parent | da0663a337b608a4b0008672b494e3a71e6e4cfc (diff) | |
download | php-git-d81ea5e9285d0eb49c730e1ea7cccf3fefa1fad5.tar.gz |
Fix preg_replace_callback_array() with array subject
Apparently this "feature" was completely untested...
-rw-r--r-- | ext/pcre/php_pcre.c | 63 | ||||
-rw-r--r-- | ext/pcre/php_pcre.stub.php | 7 | ||||
-rw-r--r-- | ext/pcre/php_pcre_arginfo.h | 4 | ||||
-rw-r--r-- | ext/pcre/tests/bug73392.phpt | 2 | ||||
-rw-r--r-- | ext/pcre/tests/preg_replace_callback_array.phpt | 12 |
5 files changed, 59 insertions, 29 deletions
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 35285a42dd..42c423e6bd 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -2398,9 +2398,9 @@ PHP_FUNCTION(preg_replace_callback) /* {{{ Perform Perl-style regular expression replacement using replacement callback. */ PHP_FUNCTION(preg_replace_callback_array) { - zval zv, *replace, *subject, *zcount = NULL; - HashTable *pattern; - zend_string *str_idx_regex; + zval zv, *replace, *zcount = NULL; + HashTable *pattern, *subject_ht; + zend_string *subject_str, *str_idx_regex; zend_long limit = -1, flags = 0; size_t replace_count = 0; zend_fcall_info fci; @@ -2409,7 +2409,7 @@ PHP_FUNCTION(preg_replace_callback_array) /* Get function parameters and do error-checking. */ ZEND_PARSE_PARAMETERS_START(2, 5) Z_PARAM_ARRAY_HT(pattern) - Z_PARAM_ZVAL(subject) + Z_PARAM_ARRAY_HT_OR_STR(subject_ht, subject_str) Z_PARAM_OPTIONAL Z_PARAM_LONG(limit) Z_PARAM_ZVAL(zcount) @@ -2420,41 +2420,66 @@ PHP_FUNCTION(preg_replace_callback_array) fci.object = NULL; fci.named_params = NULL; + if (subject_ht) { + GC_TRY_ADDREF(subject_ht); + } else { + GC_TRY_ADDREF(subject_str); + } + ZEND_HASH_FOREACH_STR_KEY_VAL(pattern, str_idx_regex, replace) { if (!str_idx_regex) { php_error_docref(NULL, E_WARNING, "Delimiter must not be alphanumeric or backslash"); - zval_ptr_dtor(return_value); - RETURN_NULL(); + RETVAL_NULL(); + goto error; } if (!zend_is_callable_ex(replace, NULL, 0, NULL, &fcc, NULL)) { zend_argument_type_error(1, "must contain only valid callbacks"); - RETURN_THROWS(); + goto error; } ZVAL_COPY_VALUE(&fci.function_name, replace); replace_count += preg_replace_func_impl(&zv, str_idx_regex, /* regex_ht */ NULL, &fci, &fcc, - Z_STR_P(subject), Z_ARRVAL_P(subject), - limit, flags); - - if (subject != return_value) { - subject = return_value; - } else { - zval_ptr_dtor(return_value); + subject_str, subject_ht, limit, flags); + switch (Z_TYPE(zv)) { + case IS_ARRAY: + ZEND_ASSERT(subject_ht); + zend_array_release(subject_ht); + subject_ht = Z_ARR(zv); + break; + case IS_STRING: + ZEND_ASSERT(subject_str); + zend_string_release(subject_str); + subject_str = Z_STR(zv); + break; + case IS_NULL: + RETVAL_NULL(); + goto error; + EMPTY_SWITCH_DEFAULT_CASE() } - ZVAL_COPY_VALUE(return_value, &zv); - - if (UNEXPECTED(EG(exception))) { - zval_ptr_dtor(return_value); - RETURN_NULL(); + if (EG(exception)) { + goto error; } } ZEND_HASH_FOREACH_END(); if (zcount) { ZEND_TRY_ASSIGN_REF_LONG(zcount, replace_count); } + + if (subject_ht) { + RETURN_ARR(subject_ht); + } else { + RETURN_STR(subject_str); + } + +error: + if (subject_ht) { + zend_array_release(subject_ht); + } else { + zend_string_release(subject_str); + } } /* }}} */ diff --git a/ext/pcre/php_pcre.stub.php b/ext/pcre/php_pcre.stub.php index eb8b4f3b17..f620d119fd 100644 --- a/ext/pcre/php_pcre.stub.php +++ b/ext/pcre/php_pcre.stub.php @@ -17,11 +17,8 @@ function preg_filter(string|array $regex, string|array $replace, string|array $s /** @param int $count */ function preg_replace_callback(string|array $regex, callable $callback, string|array $subject, int $limit = -1, &$count = null, int $flags = 0): string|array|null {} -/** - * @param array|string $subject - * @param int $count - */ -function preg_replace_callback_array(array $pattern, $subject, int $limit = -1, &$count = null, int $flags = 0): string|array|null {} +/** @param int $count */ +function preg_replace_callback_array(array $pattern, string|array $subject, int $limit = -1, &$count = null, int $flags = 0): string|array|null {} function preg_split(string $pattern, string $subject, int $limit = -1, int $flags = 0): array|false {} diff --git a/ext/pcre/php_pcre_arginfo.h b/ext/pcre/php_pcre_arginfo.h index 4201916910..d1d816cfa0 100644 --- a/ext/pcre/php_pcre_arginfo.h +++ b/ext/pcre/php_pcre_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 8e8fea5b33408e8a1a39c1b1ae71f16fe1bdd391 */ + * Stub hash: 8270971708afa7fa9d82bec0f84c66cc8283f17d */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_preg_match, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) @@ -38,7 +38,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_preg_replace_callback_array, 0, 2, MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_NULL) ZEND_ARG_TYPE_INFO(0, pattern, IS_ARRAY, 0) - ZEND_ARG_INFO(0, subject) + ZEND_ARG_TYPE_MASK(0, subject, MAY_BE_STRING|MAY_BE_ARRAY, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "-1") ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, count, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") diff --git a/ext/pcre/tests/bug73392.phpt b/ext/pcre/tests/bug73392.phpt index 704cc3d351..7546f5d99f 100644 --- a/ext/pcre/tests/bug73392.phpt +++ b/ext/pcre/tests/bug73392.phpt @@ -22,6 +22,4 @@ var_dump(preg_replace_callback_array( ?> --EXPECTF-- Warning: preg_replace_callback_array(): Delimiter must not be alphanumeric or backslash in %sbug73392.php on line %d - -Warning: preg_replace_callback_array(): Delimiter must not be alphanumeric or backslash in %sbug73392.php on line %d NULL diff --git a/ext/pcre/tests/preg_replace_callback_array.phpt b/ext/pcre/tests/preg_replace_callback_array.phpt index ffefa2cc26..cf872547f3 100644 --- a/ext/pcre/tests/preg_replace_callback_array.phpt +++ b/ext/pcre/tests/preg_replace_callback_array.phpt @@ -39,11 +39,21 @@ var_dump(preg_replace_callback_array( "/c/" => new Rep, "/a/" => 'b', "/b/" => function($a) { return "ok"; }), 'a', -1, $count)); - var_dump($count); + +var_dump(preg_replace_callback_array( + array('/a/' => 'b', "/c/" => new Rep), + array('a', 'c'))); + ?> --EXPECT-- string(2) "ok" string(2) "ok" string(2) "ok" int(2) +array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "d" +} |