/ext/standard/array.c
C | 6360 lines | 5077 code | 710 blank | 573 comment | 1527 complexity | 1050632557f69c6cefadd35cb7616cef MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /*
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Andi Gutmans <andi@php.net> |
- | Zeev Suraski <zeev@php.net> |
- | Rasmus Lerdorf <rasmus@php.net> |
- | Andrei Zmievski <andrei@php.net> |
- | Stig Venaas <venaas@php.net> |
- | Jason Greene <jason@php.net> |
- +----------------------------------------------------------------------+
- */
- #include "php.h"
- #include "php_ini.h"
- #include <stdarg.h>
- #include <stdlib.h>
- #include <math.h>
- #include <time.h>
- #include <stdio.h>
- #include <string.h>
- #ifdef PHP_WIN32
- #include "win32/unistd.h"
- #endif
- #include "zend_globals.h"
- #include "zend_interfaces.h"
- #include "php_globals.h"
- #include "php_array.h"
- #include "basic_functions.h"
- #include "php_string.h"
- #include "php_rand.h"
- #include "php_math.h"
- #include "zend_smart_str.h"
- #include "zend_bitset.h"
- #include "zend_exceptions.h"
- #include "ext/spl/spl_array.h"
- /* {{{ defines */
- #define EXTR_OVERWRITE 0
- #define EXTR_SKIP 1
- #define EXTR_PREFIX_SAME 2
- #define EXTR_PREFIX_ALL 3
- #define EXTR_PREFIX_INVALID 4
- #define EXTR_PREFIX_IF_EXISTS 5
- #define EXTR_IF_EXISTS 6
- #define EXTR_REFS 0x100
- #define CASE_LOWER 0
- #define CASE_UPPER 1
- #define DIFF_NORMAL 1
- #define DIFF_KEY 2
- #define DIFF_ASSOC 6
- #define DIFF_COMP_DATA_NONE -1
- #define DIFF_COMP_DATA_INTERNAL 0
- #define DIFF_COMP_DATA_USER 1
- #define DIFF_COMP_KEY_INTERNAL 0
- #define DIFF_COMP_KEY_USER 1
- #define INTERSECT_NORMAL 1
- #define INTERSECT_KEY 2
- #define INTERSECT_ASSOC 6
- #define INTERSECT_COMP_DATA_NONE -1
- #define INTERSECT_COMP_DATA_INTERNAL 0
- #define INTERSECT_COMP_DATA_USER 1
- #define INTERSECT_COMP_KEY_INTERNAL 0
- #define INTERSECT_COMP_KEY_USER 1
- /* }}} */
- ZEND_DECLARE_MODULE_GLOBALS(array)
- /* {{{ php_array_init_globals
- */
- static void php_array_init_globals(zend_array_globals *array_globals)
- {
- memset(array_globals, 0, sizeof(zend_array_globals));
- }
- /* }}} */
- PHP_MINIT_FUNCTION(array) /* {{{ */
- {
- ZEND_INIT_MODULE_GLOBALS(array, php_array_init_globals, NULL);
- REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", EXTR_OVERWRITE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("EXTR_SKIP", EXTR_SKIP, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("EXTR_PREFIX_INVALID", EXTR_PREFIX_INVALID, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("EXTR_PREFIX_IF_EXISTS", EXTR_PREFIX_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("EXTR_IF_EXISTS", EXTR_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("EXTR_REFS", EXTR_REFS, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SORT_ASC", PHP_SORT_ASC, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SORT_DESC", PHP_SORT_DESC, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SORT_REGULAR", PHP_SORT_REGULAR, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SORT_NUMERIC", PHP_SORT_NUMERIC, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SORT_STRING", PHP_SORT_STRING, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SORT_LOCALE_STRING", PHP_SORT_LOCALE_STRING, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SORT_NATURAL", PHP_SORT_NATURAL, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("SORT_FLAG_CASE", PHP_SORT_FLAG_CASE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("CASE_LOWER", CASE_LOWER, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("CASE_UPPER", CASE_UPPER, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT);
- return SUCCESS;
- }
- /* }}} */
- PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
- {
- #ifdef ZTS
- ts_free_id(array_globals_id);
- #endif
- return SUCCESS;
- }
- /* }}} */
- static int php_array_key_compare(Bucket *f, Bucket *s) /* {{{ */
- {
- zend_uchar t;
- zend_long l1, l2;
- double d;
- if (f->key == NULL) {
- if (s->key == NULL) {
- return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
- } else {
- l1 = (zend_long)f->h;
- t = is_numeric_string(s->key->val, s->key->len, &l2, &d, 1);
- if (t == IS_LONG) {
- /* pass */
- } else if (t == IS_DOUBLE) {
- return ZEND_NORMALIZE_BOOL((double)l1 - d);
- } else {
- l2 = 0;
- }
- }
- } else {
- if (s->key) {
- return zendi_smart_strcmp(f->key, s->key);
- } else {
- l2 = (zend_long)s->h;
- t = is_numeric_string(f->key->val, f->key->len, &l1, &d, 1);
- if (t == IS_LONG) {
- /* pass */
- } else if (t == IS_DOUBLE) {
- return ZEND_NORMALIZE_BOOL(d - (double)l2);
- } else {
- l1 = 0;
- }
- }
- }
- return ZEND_NORMALIZE_BOOL(l1 - l2);
- }
- /* }}} */
- static int php_array_reverse_key_compare(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_key_compare(b, a);
- }
- /* }}} */
- static int php_array_key_compare_numeric(Bucket *f, Bucket *s) /* {{{ */
- {
- if (f->key == NULL && s->key == NULL) {
- return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
- } else {
- double d1, d2;
- if (f->key) {
- d1 = zend_strtod(f->key->val, NULL);
- } else {
- d1 = (double)(zend_long)f->h;
- }
- if (s->key) {
- d2 = zend_strtod(s->key->val, NULL);
- } else {
- d2 = (double)(zend_long)s->h;
- }
- return ZEND_NORMALIZE_BOOL(d1 - d2);
- }
- }
- /* }}} */
- static int php_array_reverse_key_compare_numeric(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_key_compare_numeric(b, a);
- }
- /* }}} */
- static int php_array_key_compare_string_case(Bucket *f, Bucket *s) /* {{{ */
- {
- const char *s1, *s2;
- size_t l1, l2;
- char buf1[MAX_LENGTH_OF_LONG + 1];
- char buf2[MAX_LENGTH_OF_LONG + 1];
- if (f->key) {
- s1 = f->key->val;
- l1 = f->key->len;
- } else {
- s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
- l1 = buf1 + sizeof(buf1) - 1 - s1;
- }
- if (s->key) {
- s2 = s->key->val;
- l2 = s->key->len;
- } else {
- s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
- l2 = buf2 + sizeof(buf2) - 1 - s1;
- }
- return zend_binary_strcasecmp_l(s1, l1, s2, l2);
- }
- /* }}} */
- static int php_array_reverse_key_compare_string_case(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_key_compare_string_case(b, a);
- }
- /* }}} */
- static int php_array_key_compare_string(Bucket *f, Bucket *s) /* {{{ */
- {
- const char *s1, *s2;
- size_t l1, l2;
- char buf1[MAX_LENGTH_OF_LONG + 1];
- char buf2[MAX_LENGTH_OF_LONG + 1];
- if (f->key) {
- s1 = f->key->val;
- l1 = f->key->len;
- } else {
- s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
- l1 = buf1 + sizeof(buf1) - 1 - s1;
- }
- if (s->key) {
- s2 = s->key->val;
- l2 = s->key->len;
- } else {
- s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
- l2 = buf2 + sizeof(buf2) - 1 - s2;
- }
- return zend_binary_strcmp(s1, l1, s2, l2);
- }
- /* }}} */
- static int php_array_reverse_key_compare_string(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_key_compare_string(b, a);
- }
- /* }}} */
- static int php_array_key_compare_string_natural_general(Bucket *f, Bucket *s, int fold_case) /* {{{ */
- {
- const char *s1, *s2;
- size_t l1, l2;
- char buf1[MAX_LENGTH_OF_LONG + 1];
- char buf2[MAX_LENGTH_OF_LONG + 1];
- if (f->key) {
- s1 = f->key->val;
- l1 = f->key->len;
- } else {
- s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
- l1 = buf1 + sizeof(buf1) - 1 - s1;
- }
- if (s->key) {
- s2 = s->key->val;
- l2 = s->key->len;
- } else {
- s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
- l2 = buf2 + sizeof(buf2) - 1 - s1;
- }
- return strnatcmp_ex(s1, l1, s2, l2, fold_case);
- }
- /* }}} */
- static int php_array_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_key_compare_string_natural_general(a, b, 1);
- }
- /* }}} */
- static int php_array_reverse_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_key_compare_string_natural_general(b, a, 1);
- }
- /* }}} */
- static int php_array_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_key_compare_string_natural_general(a, b, 0);
- }
- /* }}} */
- static int php_array_reverse_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_key_compare_string_natural_general(b, a, 0);
- }
- /* }}} */
- static int php_array_key_compare_string_locale(Bucket *f, Bucket *s) /* {{{ */
- {
- const char *s1, *s2;
- char buf1[MAX_LENGTH_OF_LONG + 1];
- char buf2[MAX_LENGTH_OF_LONG + 1];
- if (f->key) {
- s1 = f->key->val;
- } else {
- s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
- }
- if (s->key) {
- s2 = s->key->val;
- } else {
- s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
- }
- return strcoll(s1, s2);
- }
- /* }}} */
- static int php_array_reverse_key_compare_string_locale(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_key_compare_string_locale(b, a);
- }
- /* }}} */
- static int php_array_data_compare(Bucket *f, Bucket *s) /* {{{ */
- {
- zval *first = &f->val;
- zval *second = &s->val;
- if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
- first = Z_INDIRECT_P(first);
- }
- if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
- second = Z_INDIRECT_P(second);
- }
- return zend_compare(first, second);
- }
- /* }}} */
- static int php_array_reverse_data_compare(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_data_compare(a, b) * -1;
- }
- /* }}} */
- static int php_array_data_compare_numeric(Bucket *f, Bucket *s) /* {{{ */
- {
- zval *first = &f->val;
- zval *second = &s->val;
- if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
- first = Z_INDIRECT_P(first);
- }
- if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
- second = Z_INDIRECT_P(second);
- }
- return numeric_compare_function(first, second);
- }
- /* }}} */
- static int php_array_reverse_data_compare_numeric(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_data_compare_numeric(b, a);
- }
- /* }}} */
- static int php_array_data_compare_string_case(Bucket *f, Bucket *s) /* {{{ */
- {
- zval *first = &f->val;
- zval *second = &s->val;
- if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
- first = Z_INDIRECT_P(first);
- }
- if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
- second = Z_INDIRECT_P(second);
- }
- return string_case_compare_function(first, second);
- }
- /* }}} */
- static int php_array_reverse_data_compare_string_case(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_data_compare_string_case(b, a);
- }
- /* }}} */
- static int php_array_data_compare_string(Bucket *f, Bucket *s) /* {{{ */
- {
- zval *first = &f->val;
- zval *second = &s->val;
- if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
- first = Z_INDIRECT_P(first);
- }
- if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
- second = Z_INDIRECT_P(second);
- }
- return string_compare_function(first, second);
- }
- /* }}} */
- static int php_array_reverse_data_compare_string(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_data_compare_string(b, a);
- }
- /* }}} */
- static int php_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case) /* {{{ */
- {
- zend_string *tmp_str1, *tmp_str2;
- zend_string *str1 = zval_get_tmp_string(&f->val, &tmp_str1);
- zend_string *str2 = zval_get_tmp_string(&s->val, &tmp_str2);
- int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
- zend_tmp_string_release(tmp_str1);
- zend_tmp_string_release(tmp_str2);
- return result;
- }
- /* }}} */
- static int php_array_natural_compare(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_natural_general_compare(a, b, 0);
- }
- /* }}} */
- static int php_array_reverse_natural_compare(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_natural_general_compare(b, a, 0);
- }
- /* }}} */
- static int php_array_natural_case_compare(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_natural_general_compare(a, b, 1);
- }
- /* }}} */
- static int php_array_reverse_natural_case_compare(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_natural_general_compare(b, a, 1);
- }
- /* }}} */
- static int php_array_data_compare_string_locale(Bucket *f, Bucket *s) /* {{{ */
- {
- zval *first = &f->val;
- zval *second = &s->val;
- if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
- first = Z_INDIRECT_P(first);
- }
- if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
- second = Z_INDIRECT_P(second);
- }
- return string_locale_compare_function(first, second);
- }
- /* }}} */
- static int php_array_reverse_data_compare_string_locale(Bucket *a, Bucket *b) /* {{{ */
- {
- return php_array_data_compare_string_locale(b, a);
- }
- /* }}} */
- static bucket_compare_func_t php_get_key_compare_func(zend_long sort_type, int reverse) /* {{{ */
- {
- switch (sort_type & ~PHP_SORT_FLAG_CASE) {
- case PHP_SORT_NUMERIC:
- if (reverse) {
- return php_array_reverse_key_compare_numeric;
- } else {
- return php_array_key_compare_numeric;
- }
- break;
- case PHP_SORT_STRING:
- if (sort_type & PHP_SORT_FLAG_CASE) {
- if (reverse) {
- return php_array_reverse_key_compare_string_case;
- } else {
- return php_array_key_compare_string_case;
- }
- } else {
- if (reverse) {
- return php_array_reverse_key_compare_string;
- } else {
- return php_array_key_compare_string;
- }
- }
- break;
- case PHP_SORT_NATURAL:
- if (sort_type & PHP_SORT_FLAG_CASE) {
- if (reverse) {
- return php_array_reverse_key_compare_string_natural_case;
- } else {
- return php_array_key_compare_string_natural_case;
- }
- } else {
- if (reverse) {
- return php_array_reverse_key_compare_string_natural;
- } else {
- return php_array_key_compare_string_natural;
- }
- }
- break;
- case PHP_SORT_LOCALE_STRING:
- if (reverse) {
- return php_array_reverse_key_compare_string_locale;
- } else {
- return php_array_key_compare_string_locale;
- }
- break;
- case PHP_SORT_REGULAR:
- default:
- if (reverse) {
- return php_array_reverse_key_compare;
- } else {
- return php_array_key_compare;
- }
- break;
- }
- return NULL;
- }
- /* }}} */
- static bucket_compare_func_t php_get_data_compare_func(zend_long sort_type, int reverse) /* {{{ */
- {
- switch (sort_type & ~PHP_SORT_FLAG_CASE) {
- case PHP_SORT_NUMERIC:
- if (reverse) {
- return php_array_reverse_data_compare_numeric;
- } else {
- return php_array_data_compare_numeric;
- }
- break;
- case PHP_SORT_STRING:
- if (sort_type & PHP_SORT_FLAG_CASE) {
- if (reverse) {
- return php_array_reverse_data_compare_string_case;
- } else {
- return php_array_data_compare_string_case;
- }
- } else {
- if (reverse) {
- return php_array_reverse_data_compare_string;
- } else {
- return php_array_data_compare_string;
- }
- }
- break;
- case PHP_SORT_NATURAL:
- if (sort_type & PHP_SORT_FLAG_CASE) {
- if (reverse) {
- return php_array_reverse_natural_case_compare;
- } else {
- return php_array_natural_case_compare;
- }
- } else {
- if (reverse) {
- return php_array_reverse_natural_compare;
- } else {
- return php_array_natural_compare;
- }
- }
- break;
- case PHP_SORT_LOCALE_STRING:
- if (reverse) {
- return php_array_reverse_data_compare_string_locale;
- } else {
- return php_array_data_compare_string_locale;
- }
- break;
- case PHP_SORT_REGULAR:
- default:
- if (reverse) {
- return php_array_reverse_data_compare;
- } else {
- return php_array_data_compare;
- }
- break;
- }
- return NULL;
- }
- /* }}} */
- /* {{{ proto bool krsort(array &array_arg [, int sort_flags])
- Sort an array by key value in reverse order */
- PHP_FUNCTION(krsort)
- {
- zval *array;
- zend_long sort_type = PHP_SORT_REGULAR;
- bucket_compare_func_t cmp;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_ARRAY_EX(array, 0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(sort_type)
- ZEND_PARSE_PARAMETERS_END();
- cmp = php_get_key_compare_func(sort_type, 1);
- zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto bool ksort(array &array_arg [, int sort_flags])
- Sort an array by key */
- PHP_FUNCTION(ksort)
- {
- zval *array;
- zend_long sort_type = PHP_SORT_REGULAR;
- bucket_compare_func_t cmp;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_ARRAY_EX(array, 0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(sort_type)
- ZEND_PARSE_PARAMETERS_END();
- cmp = php_get_key_compare_func(sort_type, 0);
- zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
- RETURN_TRUE;
- }
- /* }}} */
- PHPAPI zend_long php_count_recursive(HashTable *ht) /* {{{ */
- {
- zend_long cnt = 0;
- zval *element;
- if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
- if (GC_IS_RECURSIVE(ht)) {
- php_error_docref(NULL, E_WARNING, "Recursion detected");
- return 0;
- }
- GC_PROTECT_RECURSION(ht);
- }
- cnt = zend_array_count(ht);
- ZEND_HASH_FOREACH_VAL(ht, element) {
- ZVAL_DEREF(element);
- if (Z_TYPE_P(element) == IS_ARRAY) {
- cnt += php_count_recursive(Z_ARRVAL_P(element));
- }
- } ZEND_HASH_FOREACH_END();
- if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
- GC_UNPROTECT_RECURSION(ht);
- }
- return cnt;
- }
- /* }}} */
- /* {{{ proto int count(mixed var [, int mode])
- Count the number of elements in a variable (usually an array) */
- PHP_FUNCTION(count)
- {
- zval *array;
- zend_long mode = COUNT_NORMAL;
- zend_long cnt;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_ZVAL(array)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(mode)
- ZEND_PARSE_PARAMETERS_END();
- if (mode != COUNT_NORMAL && mode != COUNT_RECURSIVE) {
- zend_argument_value_error(2, "must be either COUNT_NORMAL or COUNT_RECURSIVE");
- RETURN_THROWS();
- }
- switch (Z_TYPE_P(array)) {
- case IS_NULL:
- /* Intentionally not converted to an exception */
- php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");
- RETURN_LONG(0);
- break;
- case IS_ARRAY:
- if (mode != COUNT_RECURSIVE) {
- cnt = zend_array_count(Z_ARRVAL_P(array));
- } else {
- cnt = php_count_recursive(Z_ARRVAL_P(array));
- }
- RETURN_LONG(cnt);
- break;
- case IS_OBJECT: {
- zval retval;
- /* first, we check if the handler is defined */
- if (Z_OBJ_HT_P(array)->count_elements) {
- RETVAL_LONG(1);
- if (SUCCESS == Z_OBJ_HT(*array)->count_elements(Z_OBJ_P(array), &Z_LVAL_P(return_value))) {
- return;
- }
- if (EG(exception)) {
- RETURN_THROWS();
- }
- }
- /* if not and the object implements Countable we call its count() method */
- if (instanceof_function(Z_OBJCE_P(array), zend_ce_countable)) {
- zend_call_method_with_0_params(Z_OBJ_P(array), NULL, NULL, "count", &retval);
- if (Z_TYPE(retval) != IS_UNDEF) {
- RETVAL_LONG(zval_get_long(&retval));
- zval_ptr_dtor(&retval);
- }
- return;
- }
- /* If There's no handler and it doesn't implement Countable then add a warning */
- /* Intentionally not converted to an exception */
- php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");
- RETURN_LONG(1);
- break;
- }
- default:
- /* Intentionally not converted to an exception */
- php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");
- RETURN_LONG(1);
- break;
- }
- }
- /* }}} */
- static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
- {
- zval *array;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ARRAY_EX(array, 0, 1)
- ZEND_PARSE_PARAMETERS_END();
- if (fold_case) {
- zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0);
- } else {
- zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0);
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto void natsort(array &array_arg)
- Sort an array using natural sort */
- PHP_FUNCTION(natsort)
- {
- php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
- }
- /* }}} */
- /* {{{ proto void natcasesort(array &array_arg)
- Sort an array using case-insensitive natural sort */
- PHP_FUNCTION(natcasesort)
- {
- php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
- }
- /* }}} */
- /* {{{ proto bool asort(array &array_arg [, int sort_flags])
- Sort an array and maintain index association */
- PHP_FUNCTION(asort)
- {
- zval *array;
- zend_long sort_type = PHP_SORT_REGULAR;
- bucket_compare_func_t cmp;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_ARRAY_EX(array, 0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(sort_type)
- ZEND_PARSE_PARAMETERS_END();
- cmp = php_get_data_compare_func(sort_type, 0);
- zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto bool arsort(array &array_arg [, int sort_flags])
- Sort an array in reverse order and maintain index association */
- PHP_FUNCTION(arsort)
- {
- zval *array;
- zend_long sort_type = PHP_SORT_REGULAR;
- bucket_compare_func_t cmp;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_ARRAY_EX(array, 0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(sort_type)
- ZEND_PARSE_PARAMETERS_END();
- cmp = php_get_data_compare_func(sort_type, 1);
- zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto bool sort(array &array_arg [, int sort_flags])
- Sort an array */
- PHP_FUNCTION(sort)
- {
- zval *array;
- zend_long sort_type = PHP_SORT_REGULAR;
- bucket_compare_func_t cmp;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_ARRAY_EX(array, 0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(sort_type)
- ZEND_PARSE_PARAMETERS_END();
- cmp = php_get_data_compare_func(sort_type, 0);
- zend_hash_sort(Z_ARRVAL_P(array), cmp, 1);
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto bool rsort(array &array_arg [, int sort_flags])
- Sort an array in reverse order */
- PHP_FUNCTION(rsort)
- {
- zval *array;
- zend_long sort_type = PHP_SORT_REGULAR;
- bucket_compare_func_t cmp;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_ARRAY_EX(array, 0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(sort_type)
- ZEND_PARSE_PARAMETERS_END();
- cmp = php_get_data_compare_func(sort_type, 1);
- zend_hash_sort(Z_ARRVAL_P(array), cmp, 1);
- RETURN_TRUE;
- }
- /* }}} */
- static int php_array_user_compare(Bucket *f, Bucket *s) /* {{{ */
- {
- zval args[2];
- zval retval;
- ZVAL_COPY(&args[0], &f->val);
- ZVAL_COPY(&args[1], &s->val);
- BG(user_compare_fci).param_count = 2;
- BG(user_compare_fci).params = args;
- BG(user_compare_fci).retval = &retval;
- BG(user_compare_fci).no_separation = 0;
- if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
- zend_long ret = zval_get_long(&retval);
- zval_ptr_dtor(&retval);
- zval_ptr_dtor(&args[1]);
- zval_ptr_dtor(&args[0]);
- return ZEND_NORMALIZE_BOOL(ret);
- } else {
- zval_ptr_dtor(&args[1]);
- zval_ptr_dtor(&args[0]);
- return 0;
- }
- }
- /* }}} */
- /* check if comparison function is valid */
- #define PHP_ARRAY_CMP_FUNC_CHECK(func_name) \
- if (!zend_is_callable(*func_name, 0, NULL)) { \
- php_error_docref(NULL, E_WARNING, "Invalid comparison function"); \
- BG(user_compare_fci) = old_user_compare_fci; \
- BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
- RETURN_FALSE; \
- } \
- /* Clear FCI cache otherwise : for example the same or other array with
- * (partly) the same key values has been sorted with uasort() or
- * other sorting function the comparison is cached, however the name
- * of the function for comparison is not respected. see bug #28739 AND #33295
- *
- * Following defines will assist in backup / restore values. */
- #define PHP_ARRAY_CMP_FUNC_VARS \
- zend_fcall_info old_user_compare_fci; \
- zend_fcall_info_cache old_user_compare_fci_cache \
- #define PHP_ARRAY_CMP_FUNC_BACKUP() \
- old_user_compare_fci = BG(user_compare_fci); \
- old_user_compare_fci_cache = BG(user_compare_fci_cache); \
- BG(user_compare_fci_cache) = empty_fcall_info_cache; \
- #define PHP_ARRAY_CMP_FUNC_RESTORE() \
- zend_release_fcall_info_cache(&BG(user_compare_fci_cache)); \
- BG(user_compare_fci) = old_user_compare_fci; \
- BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
- static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compare_func, zend_bool renumber) /* {{{ */
- {
- zval *array;
- zend_array *arr;
- PHP_ARRAY_CMP_FUNC_VARS;
- PHP_ARRAY_CMP_FUNC_BACKUP();
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_ARRAY_EX2(array, 0, 1, 0)
- Z_PARAM_FUNC(BG(user_compare_fci), BG(user_compare_fci_cache))
- ZEND_PARSE_PARAMETERS_END_EX( PHP_ARRAY_CMP_FUNC_RESTORE(); return );
- arr = Z_ARR_P(array);
- if (zend_hash_num_elements(arr) == 0) {
- PHP_ARRAY_CMP_FUNC_RESTORE();
- RETURN_TRUE;
- }
- /* Copy array, so the in-place modifications will not be visible to the callback function */
- arr = zend_array_dup(arr);
- zend_hash_sort(arr, compare_func, renumber);
- zval_ptr_dtor(array);
- ZVAL_ARR(array, arr);
- PHP_ARRAY_CMP_FUNC_RESTORE();
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto bool usort(array array_arg, string cmp_function)
- Sort an array by values using a user-defined comparison function */
- PHP_FUNCTION(usort)
- {
- php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 1);
- }
- /* }}} */
- /* {{{ proto bool uasort(array array_arg, string cmp_function)
- Sort an array with a user-defined comparison function and maintain index association */
- PHP_FUNCTION(uasort)
- {
- php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 0);
- }
- /* }}} */
- static int php_array_user_key_compare(Bucket *f, Bucket *s) /* {{{ */
- {
- zval args[2];
- zval retval;
- zend_long result;
- if (f->key == NULL) {
- ZVAL_LONG(&args[0], f->h);
- } else {
- ZVAL_STR_COPY(&args[0], f->key);
- }
- if (s->key == NULL) {
- ZVAL_LONG(&args[1], s->h);
- } else {
- ZVAL_STR_COPY(&args[1], s->key);
- }
- BG(user_compare_fci).param_count = 2;
- BG(user_compare_fci).params = args;
- BG(user_compare_fci).retval = &retval;
- BG(user_compare_fci).no_separation = 0;
- if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
- result = zval_get_long(&retval);
- zval_ptr_dtor(&retval);
- } else {
- result = 0;
- }
- zval_ptr_dtor(&args[0]);
- zval_ptr_dtor(&args[1]);
- return ZEND_NORMALIZE_BOOL(result);
- }
- /* }}} */
- /* {{{ proto bool uksort(array array_arg, string cmp_function)
- Sort an array by keys using a user-defined comparison function */
- PHP_FUNCTION(uksort)
- {
- php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, 0);
- }
- /* }}} */
- /* {{{ proto mixed end(array array_arg)
- Advances array argument's internal pointer to the last element and return it */
- PHP_FUNCTION(end)
- {
- HashTable *array;
- zval *entry;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
- ZEND_PARSE_PARAMETERS_END();
- zend_hash_internal_pointer_end(array);
- if (USED_RET()) {
- if ((entry = zend_hash_get_current_data(array)) == NULL) {
- RETURN_FALSE;
- }
- if (Z_TYPE_P(entry) == IS_INDIRECT) {
- entry = Z_INDIRECT_P(entry);
- }
- ZVAL_COPY_DEREF(return_value, entry);
- }
- }
- /* }}} */
- /* {{{ proto mixed prev(array array_arg)
- Move array argument's internal pointer to the previous element and return it */
- PHP_FUNCTION(prev)
- {
- HashTable *array;
- zval *entry;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
- ZEND_PARSE_PARAMETERS_END();
- zend_hash_move_backwards(array);
- if (USED_RET()) {
- if ((entry = zend_hash_get_current_data(array)) == NULL) {
- RETURN_FALSE;
- }
- if (Z_TYPE_P(entry) == IS_INDIRECT) {
- entry = Z_INDIRECT_P(entry);
- }
- ZVAL_COPY_DEREF(return_value, entry);
- }
- }
- /* }}} */
- /* {{{ proto mixed next(array array_arg)
- Move array argument's internal pointer to the next element and return it */
- PHP_FUNCTION(next)
- {
- HashTable *array;
- zval *entry;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
- ZEND_PARSE_PARAMETERS_END();
- zend_hash_move_forward(array);
- if (USED_RET()) {
- if ((entry = zend_hash_get_current_data(array)) == NULL) {
- RETURN_FALSE;
- }
- if (Z_TYPE_P(entry) == IS_INDIRECT) {
- entry = Z_INDIRECT_P(entry);
- }
- ZVAL_COPY_DEREF(return_value, entry);
- }
- }
- /* }}} */
- /* {{{ proto mixed reset(array array_arg)
- Set array argument's internal pointer to the first element and return it */
- PHP_FUNCTION(reset)
- {
- HashTable *array;
- zval *entry;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
- ZEND_PARSE_PARAMETERS_END();
- zend_hash_internal_pointer_reset(array);
- if (USED_RET()) {
- if ((entry = zend_hash_get_current_data(array)) == NULL) {
- RETURN_FALSE;
- }
- if (Z_TYPE_P(entry) == IS_INDIRECT) {
- entry = Z_INDIRECT_P(entry);
- }
- ZVAL_COPY_DEREF(return_value, entry);
- }
- }
- /* }}} */
- /* {{{ proto mixed current(array array_arg)
- Return the element currently pointed to by the internal array pointer */
- PHP_FUNCTION(current)
- {
- HashTable *array;
- zval *entry;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ARRAY_OR_OBJECT_HT(array)
- ZEND_PARSE_PARAMETERS_END();
- if ((entry = zend_hash_get_current_data(array)) == NULL) {
- RETURN_FALSE;
- }
- if (Z_TYPE_P(entry) == IS_INDIRECT) {
- entry = Z_INDIRECT_P(entry);
- }
- ZVAL_COPY_DEREF(return_value, entry);
- }
- /* }}} */
- /* {{{ proto mixed key(array array_arg)
- Return the key of the element currently pointed to by the internal array pointer */
- PHP_FUNCTION(key)
- {
- HashTable *array;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ARRAY_OR_OBJECT_HT(array)
- ZEND_PARSE_PARAMETERS_END();
- zend_hash_get_current_key_zval(array, return_value);
- }
- /* }}} */
- /* {{{
- * proto mixed min(array values)
- * proto mixed min(mixed arg1 [, mixed arg2 [, mixed ...]])
- Return the lowest value in an array or a series of arguments */
- PHP_FUNCTION(min)
- {
- int argc;
- zval *args = NULL;
- ZEND_PARSE_PARAMETERS_START(1, -1)
- Z_PARAM_VARIADIC('+', args, argc)
- ZEND_PARSE_PARAMETERS_END();
- /* mixed min ( array $values ) */
- if (argc == 1) {
- zval *result;
- if (Z_TYPE(args[0]) != IS_ARRAY) {
- zend_argument_type_error(1, "must be of type array, %s given", zend_zval_type_name(&args[0]));
- RETURN_THROWS();
- } else {
- if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 0)) != NULL) {
- ZVAL_COPY_DEREF(return_value, result);
- } else {
- zend_argument_value_error(1, "must contain at least one element");
- RETURN_THROWS();
- }
- }
- } else {
- /* mixed min ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
- zval *min, result;
- int i;
- min = &args[0];
- for (i = 1; i < argc; i++) {
- is_smaller_function(&result, &args[i], min);
- if (Z_TYPE(result) == IS_TRUE) {
- min = &args[i];
- }
- }
- ZVAL_COPY(return_value, min);
- }
- }
- /* }}} */
- /* {{{
- * proto mixed max(array values)
- * proto mixed max(mixed arg1 [, mixed arg2 [, mixed ...]])
- Return the highest value in an array or a series of arguments */
- PHP_FUNCTION(max)
- {
- zval *args = NULL;
- int argc;
- ZEND_PARSE_PARAMETERS_START(1, -1)
- Z_PARAM_VARIADIC('+', args, argc)
- ZEND_PARSE_PARAMETERS_END();
- /* mixed max ( array $values ) */
- if (argc == 1) {
- zval *result;
- if (Z_TYPE(args[0]) != IS_ARRAY) {
- zend_argument_type_error(1, "must be of type array, %s given", zend_zval_type_name(&args[0]));
- RETURN_THROWS();
- } else {
- if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 1)) != NULL) {
- ZVAL_COPY_DEREF(return_value, result);
- } else {
- zend_argument_value_error(1, "must contain at least one element");
- RETURN_THROWS();
- }
- }
- } else {
- /* mixed max ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
- zval *max, result;
- int i;
- max = &args[0];
- for (i = 1; i < argc; i++) {
- is_smaller_or_equal_function(&result, &args[i], max);
- if (Z_TYPE(result) == IS_FALSE) {
- max = &args[i];
- }
- }
- ZVAL_COPY(return_value, max);
- }
- }
- /* }}} */
- static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
- {
- zval args[3], /* Arguments to userland function */
- retval, /* Return value - unused */
- *zv;
- HashTable *target_hash = HASH_OF(array);
- HashPosition pos;
- uint32_t ht_iter;
- int result = SUCCESS;
- /* Set up known arguments */
- ZVAL_UNDEF(&args[1]);
- if (userdata) {
- ZVAL_COPY(&args[2], userdata);
- }
- BG(array_walk_fci).retval = &retval;
- BG(array_walk_fci).param_count = userdata ? 3 : 2;
- BG(array_walk_fci).params = args;
- BG(array_walk_fci).no_separation = 0;
- zend_hash_internal_pointer_reset_ex(target_hash, &pos);
- ht_iter = zend_hash_iterator_add(target_hash, pos);
- /* Iterate through hash */
- do {
- /* Retrieve value */
- zv = zend_hash_get_current_data_ex(target_hash, &pos);
- if (zv == NULL) {
- break;
- }
- /* Skip undefined indirect elements */
- if (Z_TYPE_P(zv) == IS_INDIRECT) {
- zv = Z_INDIRECT_P(zv);
- if (Z_TYPE_P(zv) == IS_UNDEF) {
- zend_hash_move_forward_ex(target_hash, &pos);
- continue;
- }
- }
- /* Ensure the value is a reference. Otherwise the location of the value may be freed. */
- ZVAL_MAKE_REF(zv);
- /* Retrieve key */
- zend_hash_get_current_key_zval_ex(target_hash, &args[1], &pos);
- /* Move to next element already now -- this mirrors the approach used by foreach
- * and ensures proper behavior with regard to modifications. */
- zend_hash_move_forward_ex(target_hash, &pos);
- /* Back up hash position, as it may change */
- EG(ht_iterators)[ht_iter].pos = pos;
- if (recursive && Z_TYPE_P(Z_REFVAL_P(zv)) == IS_ARRAY) {
- HashTable *thash;
- zend_fcall_info orig_array_walk_fci;
- zend_fcall_info_cache orig_array_walk_fci_cache;
- zval ref;
- ZVAL_COPY_VALUE(&ref, zv);
- ZVAL_DEREF(zv);
- SEPARATE_ARRAY(zv);
- thash = Z_ARRVAL_P(zv);
- if (GC_IS_RECURSIVE(thash)) {
- zend_throw_error(NULL, "Recursion detected");
- result = FAILURE;
- break;
- }
- /* backup the fcall info and cache */
- orig_array_walk_fci = BG(array_walk_fci);
- orig_array_walk_fci_cache = BG(array_walk_fci_cache);
- Z_ADDREF(ref);
- GC_PROTECT_RECURSION(thash);
- result = php_array_walk(zv, userdata, recursive);
- if (Z_TYPE_P(Z_REFVAL(ref)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL(ref))) {
- /* If the hashtable changed in the meantime, we'll "leak" this apply count
- * increment -- our reference to thash is no longer valid. */
- GC_UNPROTECT_RECURSION(thash);
- }
- zval_ptr_dtor(&ref);
- /* restore the fcall info and cache */
- BG(array_walk_fci) = orig_array_walk_fci;
- BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
- } else {
- ZVAL_COPY(&args[0], zv);
- /* Call the userland function */
- result = zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache));
- if (result == SUCCESS) {
- zval_ptr_dtor(&retval);
- }
- zval_ptr_dtor(&args[0]);
- }
- if (Z_TYPE(args[1]) != IS_UNDEF) {
- zval_ptr_dtor(&args[1]);
- ZVAL_UNDEF(&args[1]);
- }
- if (result == FAILURE) {
- break;
- }
- /* Reload array and position -- both may have changed */
- if (Z_TYPE_P(array) == IS_ARRAY) {
- pos = zend_hash_iterator_pos_ex(ht_iter, array);
- target_hash = Z_ARRVAL_P(array);
- } else if (Z_TYPE_P(array) == IS_OBJECT) {
- target_hash = Z_OBJPROP_P(array);
- pos = zend_hash_iterator_pos(ht_iter, target_hash);
- } else {
- zend_type_error("Iterated value is no longer an array or object");
- result = FAILURE;
- break;
- }
- } while (!EG(exception));
- if (userdata) {
- zval_ptr_dtor(&args[2]);
- }
- zend_hash_iterator_del(ht_iter);
- return result;
- }
- /* }}} */
- /* {{{ proto bool array_walk(array input, string funcname [, mixed userdata])
- Apply a user function to every member of an array */
- PHP_FUNCTION(array_walk)
- {
- zval *array;
- zval *userdata = NULL;
- zend_fcall_info orig_array_walk_fci;
- zend_fcall_info_cache orig_array_walk_fci_cache;
- orig_array_walk_fci = BG(array_walk_fci);
- orig_array_walk_fci_cache = BG(array_walk_fci_cache);
- ZEND_PARSE_PARAMETERS_START(2, 3)
- Z_PARAM_ARRAY_OR_OBJECT_EX(array, 0, 1)
- Z_PARAM_FUNC(BG(array_walk_fci), BG(array_walk_fci_cache))
- Z_PARAM_OPTIONAL
- Z_PARAM_ZVAL(userdata)
- ZEND_PARSE_PARAMETERS_END_EX(
- BG(array_walk_fci) = orig_array_walk_fci;
- BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
- return
- );
- php_array_walk(array, userdata, 0);
- zend_release_fcall_info_cache(&BG(array_walk_fci_cache));
- BG(array_walk_fci) = orig_array_walk_fci;
- BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto bool array_walk_recursive(array input, string funcname [, mixed userdata])
- Apply a user function recursively to every member of an array */
- PHP_FUNCTION(array_walk_recursive)
- {
- zval *array;
- zval *userdata = NULL;
- zend_fcall_info orig_array_walk_fci;
- zend_fcall_info_cache orig_array_walk_fci_cache;
- orig_array_walk_fci = BG(array_walk_fci);
- orig_array_walk_fci_cache = BG(array_walk_fci_cache);
- ZEND_PARSE_PARAMETERS_START(2, 3)
- Z_PARAM_ARRAY_OR_OBJECT_EX(array, 0, 1)
- Z_PARAM_FUNC(BG(array_walk_fci), BG(array_walk_fci_cache))
- Z_PARAM_OPTIONAL
- Z_PARAM_ZVAL(userdata)
- ZEND_PARSE_PARAMETERS_END_EX(
- BG(array_walk_fci) = orig_array_walk_fci;
- BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
- return
- );
- php_array_walk(array, userdata, 1);
- zend_release_fcall_info_cache(&BG(array_walk_fci_cache));
- BG(array_walk_fci) = orig_array_walk_fci;
- BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
- RETURN_TRUE;
- }
- /* }}} */
- /* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
- * 0 = return boolean
- * 1 = return key
- */
- static inline void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
- {
- zval *value, /* value to check for */
- *array, /* array to check in */
- *entry; /* pointer to array entry */
- zend_ulong num_idx;
- zend_string *str_idx;
- zend_bool strict = 0; /* strict comparison or not */
- ZEND_PARSE_PARAMETERS_START(2, 3)
- Z_PARAM_ZVAL(value)
- Z_PARAM_ARRAY(array)
- Z_PARAM_OPTIONAL
- Z_PARAM_BOOL(strict)
- ZEND_PARSE_PARAMETERS_END();
- if (strict) {
- if (Z_TYPE_P(value) == IS_LONG) {
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
- ZVAL_DEREF(entry);
- if (Z_TYPE_P(entry) == IS_LONG && Z_LVAL_P(entry) == Z_LVAL_P(value)) {
- if (behavior == 0) {
- RETURN_TRUE;
- } else {
- if (str_idx) {
- RETVAL_STR_COPY(str_idx);
- } else {
- RETVAL_LONG(num_idx);
- }
- return;
- }
- }
- } ZEND_HASH_FOREACH_END();
- } else {
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
- ZVAL_DEREF(entry);
- if (fast_is_identical_function(value, entry)) {
- if (behavior == 0) {
- RETURN_TRUE;
- } else {
- if (str_idx) {
- RETVAL_STR_COPY(str_idx);
- } else {
- RETVAL_LONG(num_idx);
- }
- return;
- }
- }
- } ZEND_HASH_FOREACH_END();
- }
- } else {
- if (Z_TYPE_P(value) == IS_LONG) {
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
- if (fast_equal_check_long(value, entry)) {
- if (behavior == 0) {
- RETURN_TRUE;
- } else {
- if (str_idx) {
- RETVAL_STR_COPY(str_idx);
- } else {
- RETVAL_LONG(num_idx);
- }
- return;
- }
- }
- } ZEND_HASH_FOREACH_END();
- } else if (Z_TYPE_P(value) == IS_STRING) {
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
- if (fast_equal_check_string(value, entry)) {
- if (behavior == 0) {
- RETURN_TRUE;
- } else {
- if (str_idx) {
- RETVAL_STR_COPY(str_idx);
- } else {
- RETVAL_LONG(num_idx);
- }
- return;
- }
- }
- } ZEND_HASH_FOREACH_END();
- } else {
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
- if (fast_equal_check_function(value, entry)) {
- if (behavior == 0) {
- RETURN_TRUE;
- } else {
- if (str_idx) {
- RETVAL_STR_COPY(str_idx);
- } else {
- RETVAL_LONG(num_idx);
- }
- return;
- }
- }
- } ZEND_HASH_FOREACH_END();
- }
- }
- RETURN_FALSE;
- }
- /* }}} */
- /* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
- Checks if the given value exists in the array */
- PHP_FUNCTION(in_array)
- {
- php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
- }
- /* }}} */
- /* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict])
- Searches the array for a given value and returns the corresponding key if successful */
- PHP_FUNCTION(array_search)
- {
- php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
- }
- /* }}} */
- static zend_always_inline int php_valid_var_name(const char *var_name, size_t var_name_len) /* {{{ */
- {
- #if 1
- /* first 256 bits for first character, and second 256 bits for the next */
- static const uint32_t charset[8] = {
- /* 31 0 63 32 95 64 127 96 */
- 0x00000000, 0x00000000, 0x87fffffe, 0x07fffffe,
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
- static const uint32_t charset2[8] = {
- /* 31 0 63 32 95 64 127 96 */
- 0x00000000, 0x03ff0000, 0x87fffffe, 0x07fffffe,
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
- #endif
- size_t i;
- uint32_t ch;
- if (UNEXPECTED(!var_name_len)) {
- return 0;
- }
- /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
- ch = (uint32_t)((unsigned char *)var_name)[0];
- #if 1
- if (UNEXPECTED(!ZEND_BIT_TEST(charset, ch))) {
- #else
- if (var_name[0] != '_' &&
- (ch < 65 /* A */ || /* Z */ ch > 90) &&
- (ch < 97 /* a */ || /* z */ ch > 122) &&
- (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
- ) {
- #endif
- return 0;
- }
- /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
- if (var_name_len > 1) {
- i = 1;
- do {
- ch = (uint32_t)((unsigned char *)var_name)[i];
- #if 1
- if (UNEXPECTED(!ZEND_BIT_TEST(charset2, ch))) {
- #else
- if (var_name[i] != '_' &&
- (ch < 48 /* 0 */ || /* 9 */ ch > 57) &&
- (ch < 65 /* A */ || /* Z */ ch > 90) &&
- (ch < 97 /* a */ || /* z */ ch > 122) &&
- (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
- ) {
- #endif
- return 0;
- }
- } while (++i < var_name_len);
- }
- return 1;
- }
- /* }}} */
- PHPAPI int php_prefix_varname(zval *result, zend_string *prefix, const char *var_name, size_t var_name_len, zend_bool add_underscore) /* {{{ */
- {
- ZVAL_NEW_STR(result, zend_string_alloc(ZSTR_LEN(prefix) + (add_underscore ? 1 : 0) + var_name_len, 0));
- memcpy(Z_STRVAL_P(result), ZSTR_VAL(prefix), ZSTR_LEN(prefix));
- if (add_underscore) {
- Z_STRVAL_P(result)[ZSTR_LEN(prefix)] = '_';
- }
- memcpy(Z_STRVAL_P(result) + ZSTR_LEN(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1);
- return SUCCESS;
- }
- /* }}} */
- static zend_long php_extract_ref_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */
- {
- zend_long count = 0;
- zend_string *var_name;
- zval *entry, *orig_var;
- ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
- if (!var_name) {
- continue;
- }
- orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
- if (orig_var) {
- if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
- orig_var = Z_INDIRECT_P(orig_var);
- if (Z_TYPE_P(orig_var) == IS_UNDEF) {
- continue;
- }
- }
- if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
- continue;
- }
- if (zend_string_equals_literal(var_name, "GLOBALS")) {
- continue;
- }
- if (zend_string_equals_literal(var_name, "this")) {
- zend_throw_error(NULL, "Cannot re-assign $this");
- return -1;
- }
- if (Z_ISREF_P(entry)) {
- Z_ADDREF_P(entry);
- } else {
- ZVAL_MAKE_REF_EX(entry, 2);
- }
- zval_ptr_dtor(orig_var);
- ZVAL_REF(orig_var, Z_REF_P(entry));
- count++;
- }
- } ZEND_HASH_FOREACH_END();
- return count;
- }
- /* }}} */
- static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */
- {
- zend_long count = 0;
- zend_string *var_name;
- zval *entry, *orig_var;
- ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
- if (!var_name) {
- continue;
- }
- orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
- if (orig_var) {
- if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
- orig_var = Z_INDIRECT_P(orig_var);
- if (Z_TYPE_P(orig_var) == IS_UNDEF) {
- continue;
- }
- }
- if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
- continue;
- }
- if (zend_string_equals_literal(var_name, "GLOBALS")) {
- continue;
- }
- if (zend_string_equals_literal(var_name, "this")) {
- zend_throw_error(NULL, "Cannot re-assign $this");
- return -1;
- }
- ZVAL_DEREF(entry);
- ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
- if (UNEXPECTED(EG(exception))) {
- return -1;
- }
- count++;
- }
- } ZEND_HASH_FOREACH_END();
- return count;
- }
- /* }}} */
- static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */
- {
- zend_long count = 0;
- zend_string *var_name;
- zval *entry, *orig_var;
- ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
- if (!var_name) {
- continue;
- }
- if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
- continue;
- }
- if (zend_string_equals_literal(var_name, "this")) {
- zend_throw_error(NULL, "Cannot re-assign $this");
- return -1;
- }
- orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
- if (orig_var) {
- if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
- orig_var = Z_INDIRECT_P(orig_var);
- }
- if (zend_string_equals_literal(var_name, "GLOBALS")) {
- continue;
- }
- if (Z_ISREF_P(entry)) {
- Z_ADDREF_P(entry);
- } else {
- ZVAL_MAKE_REF_EX(entry, 2);
- }
- zval_ptr_dtor(orig_var);
- ZVAL_REF(orig_var, Z_REF_P(entry));
- } else {
- if (Z_ISREF_P(entry)) {
- Z_ADDREF_P(entry);
- } else {
- ZVAL_MAKE_REF_EX(entry, 2);
- }
- zend_hash_add_new(symbol_table, var_name, entry);
- }
- count++;
- } ZEND_HASH_FOREACH_END();
- return count;
- }
- /* }}} */
- static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */
- {
- zend_long count = 0;
- zend_string *var_name;
- zval *entry, *orig_var;
- ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
- if (!var_name) {
- continue;
- }
- if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
- continue;
- }
- if (zend_string_equals_literal(var_name, "this")) {
- zend_throw_error(NULL, "Cannot re-assign $this");
- return -1;
- }
- orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
- if (orig_var) {
- if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
- orig_var = Z_INDIRECT_P(orig_var);
- }
- if (zend_string_equals_literal(var_name, "GLOBALS")) {
- continue;
- }
- ZVAL_DEREF(entry);
- ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
- if (UNEXPECTED(EG(exception))) {
- return -1;
- }
- } else {
- ZVAL_DEREF(entry);
- Z_TRY_ADDREF_P(entry);
- zend_hash_add_new(symbol_table, var_name, entry);
- }
- count++;
- } ZEND_HASH_FOREACH_END();
- return count;
- }
- /* }}} */
- static zend_long php_extract_ref_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
- {
- zend_long count = 0;
- zend_string *var_name;
- zval *entry, *orig_var, final_name;
- ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
- if (!var_name) {
- continue;
- }
- orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
- if (orig_var) {
- if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
- orig_var = Z_INDIRECT_P(orig_var);
- if (Z_TYPE_P(orig_var) == IS_UNDEF) {
- if (Z_ISREF_P(entry)) {
- Z_ADDREF_P(entry);
- } else {
- ZVAL_MAKE_REF_EX(entry, 2);
- }
- ZVAL_REF(orig_var, Z_REF_P(entry));
- count++;
- continue;
- }
- }
- php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
- if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
- if (zend_string_equals_literal(Z_STR(final_name), "this")) {
- zend_throw_error(NULL, "Cannot re-assign $this");
- return -1;
- } else {
- if (Z_ISREF_P(entry)) {
- Z_ADDREF_P(entry);
- } else {
- ZVAL_MAKE_REF_EX(entry, 2);
- }
- if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
- if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
- orig_var = Z_INDIRECT_P(orig_var);
- }
- zval_ptr_dtor(orig_var);
- ZVAL_REF(orig_var, Z_REF_P(entry));
- } else {
- zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
- }
- count++;
- }
- }
- zval_ptr_dtor_str(&final_name);
- }
- } ZEND_HASH_FOREACH_END();
- return count;
- }
- /* }}} */
- static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
- {
- zend_long count = 0;
- zend_string *var_name;
- zval *entry, *orig_var, final_name;
- ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
- if (!var_name) {
- continue;
- }
- orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
- if (orig_var) {
- if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
- orig_var = Z_INDIRECT_P(orig_var);
- if (Z_TYPE_P(orig_var) == IS_UNDEF) {
- ZVAL_COPY_DEREF(orig_var, entry);
- count++;
- continue;
- }
- }
- php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
- if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
- if (zend_string_equals_literal(Z_STR(final_name), "this")) {
- zend_throw_error(NULL, "Cannot re-assign $this");
- return -1;
- } else {
- ZVAL_DEREF(entry);
- if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
- if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
- orig_var = Z_INDIRECT_P(orig_var);
- }
- ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
- if (UNEXPECTED(EG(exception))) {
- zend_string_release_ex(Z_STR(final_name), 0);
- return -1;
- }
- } else {
- Z_TRY_ADDREF…
Large files files are truncated, but you can click here to view the full file