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 /ext/pcre/php_pcre.c | |
parent | da0663a337b608a4b0008672b494e3a71e6e4cfc (diff) | |
download | php-git-d81ea5e9285d0eb49c730e1ea7cccf3fefa1fad5.tar.gz |
Fix preg_replace_callback_array() with array subject
Apparently this "feature" was completely untested...
Diffstat (limited to 'ext/pcre/php_pcre.c')
-rw-r--r-- | ext/pcre/php_pcre.c | 63 |
1 files changed, 44 insertions, 19 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); + } } /* }}} */ |