summaryrefslogtreecommitdiff
path: root/ext/pcre
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-09-15 11:26:59 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-09-15 12:03:18 +0200
commitd81ea5e9285d0eb49c730e1ea7cccf3fefa1fad5 (patch)
treeb73ee4ebf270bea814263996bbd062000c5d0b79 /ext/pcre
parentda0663a337b608a4b0008672b494e3a71e6e4cfc (diff)
downloadphp-git-d81ea5e9285d0eb49c730e1ea7cccf3fefa1fad5.tar.gz
Fix preg_replace_callback_array() with array subject
Apparently this "feature" was completely untested...
Diffstat (limited to 'ext/pcre')
-rw-r--r--ext/pcre/php_pcre.c63
-rw-r--r--ext/pcre/php_pcre.stub.php7
-rw-r--r--ext/pcre/php_pcre_arginfo.h4
-rw-r--r--ext/pcre/tests/bug73392.phpt2
-rw-r--r--ext/pcre/tests/preg_replace_callback_array.phpt12
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"
+}