/ext/standard/array.c
C | 4526 lines | 3401 code | 614 blank | 511 comment | 1101 complexity | b5b12aed4606a7491dead72c4b471851 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- /*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2011 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@zend.com> |
- | Zeev Suraski <zeev@zend.com> |
- | Rasmus Lerdorf <rasmus@php.net> |
- | Andrei Zmievski <andrei@php.net> |
- | Stig Venaas <venaas@php.net> |
- | Jason Greene <jason@php.net> |
- +----------------------------------------------------------------------+
- */
- /* $Id: array.c 306939 2011-01-01 02:19:59Z felipe $ */
- #include "php.h"
- #include "php_ini.h"
- #include <stdarg.h>
- #include <stdlib.h>
- #include <math.h>
- #include <time.h>
- #include <stdio.h>
- #if HAVE_STRING_H
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #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_smart_str.h"
- #ifdef HAVE_SPL
- #include "ext/spl/spl_array.h"
- #endif
- /* {{{ 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 COUNT_NORMAL 0
- #define COUNT_RECURSIVE 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
- #define DOUBLE_DRIFT_FIX 0.000000000000001
- /* }}} */
- 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("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);
- return SUCCESS;
- }
- /* }}} */
- PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
- {
- #ifdef ZTS
- ts_free_id(array_globals_id);
- #endif
- return SUCCESS;
- }
- /* }}} */
- static void php_set_compare_func(int sort_type TSRMLS_DC) /* {{{ */
- {
- switch (sort_type) {
- case PHP_SORT_NUMERIC:
- ARRAYG(compare_func) = numeric_compare_function;
- break;
- case PHP_SORT_STRING:
- ARRAYG(compare_func) = string_compare_function;
- break;
- #if HAVE_STRCOLL
- case PHP_SORT_LOCALE_STRING:
- ARRAYG(compare_func) = string_locale_compare_function;
- break;
- #endif
- case PHP_SORT_REGULAR:
- default:
- ARRAYG(compare_func) = compare_function;
- break;
- }
- }
- /* }}} */
- static int php_array_key_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
- {
- Bucket *f;
- Bucket *s;
- zval result;
- zval first;
- zval second;
- f = *((Bucket **) a);
- s = *((Bucket **) b);
- if (f->nKeyLength == 0) {
- Z_TYPE(first) = IS_LONG;
- Z_LVAL(first) = f->h;
- } else {
- Z_TYPE(first) = IS_STRING;
- Z_STRVAL(first) = f->arKey;
- Z_STRLEN(first) = f->nKeyLength - 1;
- }
- if (s->nKeyLength == 0) {
- Z_TYPE(second) = IS_LONG;
- Z_LVAL(second) = s->h;
- } else {
- Z_TYPE(second) = IS_STRING;
- Z_STRVAL(second) = s->arKey;
- Z_STRLEN(second) = s->nKeyLength - 1;
- }
- if (ARRAYG(compare_func)(&result, &first, &second TSRMLS_CC) == FAILURE) {
- return 0;
- }
- if (Z_TYPE(result) == IS_DOUBLE) {
- if (Z_DVAL(result) < 0) {
- return -1;
- } else if (Z_DVAL(result) > 0) {
- return 1;
- } else {
- return 0;
- }
- }
- convert_to_long(&result);
- if (Z_LVAL(result) < 0) {
- return -1;
- } else if (Z_LVAL(result) > 0) {
- return 1;
- }
- return 0;
- }
- /* }}} */
- static int php_array_reverse_key_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
- {
- return php_array_key_compare(a, b TSRMLS_CC) * -1;
- }
- /* }}} */
- /* {{{ proto bool krsort(array &array_arg [, int sort_flags])
- Sort an array by key value in reverse order */
- PHP_FUNCTION(krsort)
- {
- zval *array;
- long sort_type = PHP_SORT_REGULAR;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
- RETURN_FALSE;
- }
- php_set_compare_func(sort_type TSRMLS_CC);
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_key_compare, 0 TSRMLS_CC) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto bool ksort(array &array_arg [, int sort_flags])
- Sort an array by key */
- PHP_FUNCTION(ksort)
- {
- zval *array;
- long sort_type = PHP_SORT_REGULAR;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
- RETURN_FALSE;
- }
- php_set_compare_func(sort_type TSRMLS_CC);
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_key_compare, 0 TSRMLS_CC) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- static int php_count_recursive(zval *array, long mode TSRMLS_DC) /* {{{ */
- {
- long cnt = 0;
- zval **element;
- if (Z_TYPE_P(array) == IS_ARRAY) {
- if (Z_ARRVAL_P(array)->nApplyCount > 1) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
- return 0;
- }
- cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
- if (mode == COUNT_RECURSIVE) {
- HashPosition pos;
- for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
- zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **) &element, &pos) == SUCCESS;
- zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)
- ) {
- Z_ARRVAL_P(array)->nApplyCount++;
- cnt += php_count_recursive(*element, COUNT_RECURSIVE TSRMLS_CC);
- Z_ARRVAL_P(array)->nApplyCount--;
- }
- }
- }
- return cnt;
- }
- /* }}} */
- /* {{{ proto int sizeof(mixed var [, int mode])
- Count the number of elements in a variable (usually an array) */
- PHP_FUNCTION(sizeof)
- {
- zval *array;
- long mode = COUNT_NORMAL;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) {
- return;
- }
- switch (Z_TYPE_P(array)) {
- case IS_NULL:
- RETURN_LONG(0);
- break;
- case IS_ARRAY:
- RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));
- break;
- case IS_OBJECT: {
- #ifdef HAVE_SPL
- zval *retval;
- #endif
- /* 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(array, &Z_LVAL_P(return_value) TSRMLS_CC)) {
- return;
- }
- }
- #ifdef HAVE_SPL
- /* if not and the object implements Countable we call its count() method */
- if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Countable TSRMLS_CC)) {
- zend_call_method_with_0_params(&array, NULL, NULL, "count", &retval);
- if (retval) {
- convert_to_long_ex(&retval);
- RETVAL_LONG(Z_LVAL_P(retval));
- zval_ptr_dtor(&retval);
- }
- return;
- }
- #endif
- }
- default:
- RETURN_LONG(1);
- break;
- }
- }
- /* }}} */
- /* Numbers are always smaller than strings int this function as it
- * anyway doesn't make much sense to compare two different data types.
- * This keeps it consistant and simple.
- *
- * This is not correct any more, depends on what compare_func is set to.
- */
- static int php_array_data_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
- {
- Bucket *f;
- Bucket *s;
- zval result;
- zval *first;
- zval *second;
- f = *((Bucket **) a);
- s = *((Bucket **) b);
- first = *((zval **) f->pData);
- second = *((zval **) s->pData);
- if (ARRAYG(compare_func)(&result, first, second TSRMLS_CC) == FAILURE) {
- return 0;
- }
- if (Z_TYPE(result) == IS_DOUBLE) {
- if (Z_DVAL(result) < 0) {
- return -1;
- } else if (Z_DVAL(result) > 0) {
- return 1;
- } else {
- return 0;
- }
- }
- convert_to_long(&result);
- if (Z_LVAL(result) < 0) {
- return -1;
- } else if (Z_LVAL(result) > 0) {
- return 1;
- }
- return 0;
- }
- /* }}} */
- static int php_array_reverse_data_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
- {
- return php_array_data_compare(a, b TSRMLS_CC) * -1;
- }
- /* }}} */
- static int php_array_natural_general_compare(const void *a, const void *b, int fold_case) /* {{{ */
- {
- Bucket *f, *s;
- zval *fval, *sval;
- zval first, second;
- int result;
- f = *((Bucket **) a);
- s = *((Bucket **) b);
- fval = *((zval **) f->pData);
- sval = *((zval **) s->pData);
- first = *fval;
- second = *sval;
- if (Z_TYPE_P(fval) != IS_STRING) {
- zval_copy_ctor(&first);
- convert_to_string(&first);
- }
- if (Z_TYPE_P(sval) != IS_STRING) {
- zval_copy_ctor(&second);
- convert_to_string(&second);
- }
- result = strnatcmp_ex(Z_STRVAL(first), Z_STRLEN(first), Z_STRVAL(second), Z_STRLEN(second), fold_case);
- if (Z_TYPE_P(fval) != IS_STRING) {
- zval_dtor(&first);
- }
- if (Z_TYPE_P(sval) != IS_STRING) {
- zval_dtor(&second);
- }
- return result;
- }
- /* }}} */
- static int php_array_natural_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
- {
- return php_array_natural_general_compare(a, b, 0);
- }
- /* }}} */
- static int php_array_natural_case_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
- {
- return php_array_natural_general_compare(a, b, 1);
- }
- /* }}} */
- static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
- {
- zval *array;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
- return;
- }
- if (fold_case) {
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_case_compare, 0 TSRMLS_CC) == FAILURE) {
- return;
- }
- } else {
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_compare, 0 TSRMLS_CC) == FAILURE) {
- return;
- }
- }
- 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;
- long sort_type = PHP_SORT_REGULAR;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
- RETURN_FALSE;
- }
- php_set_compare_func(sort_type TSRMLS_CC);
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 0 TSRMLS_CC) == FAILURE) {
- RETURN_FALSE;
- }
- 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;
- long sort_type = PHP_SORT_REGULAR;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
- RETURN_FALSE;
- }
- php_set_compare_func(sort_type TSRMLS_CC);
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 0 TSRMLS_CC) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto bool sort(array &array_arg [, int sort_flags])
- Sort an array */
- PHP_FUNCTION(sort)
- {
- zval *array;
- long sort_type = PHP_SORT_REGULAR;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
- RETURN_FALSE;
- }
- php_set_compare_func(sort_type TSRMLS_CC);
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 1 TSRMLS_CC) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- /* {{{ proto bool rsort(array &array_arg [, int sort_flags])
- Sort an array in reverse order */
- PHP_FUNCTION(rsort)
- {
- zval *array;
- long sort_type = PHP_SORT_REGULAR;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
- RETURN_FALSE;
- }
- php_set_compare_func(sort_type TSRMLS_CC);
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 1 TSRMLS_CC) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- static int php_array_user_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
- {
- Bucket *f;
- Bucket *s;
- zval **args[2];
- zval *retval_ptr = NULL;
- f = *((Bucket **) a);
- s = *((Bucket **) b);
- args[0] = (zval **) f->pData;
- args[1] = (zval **) s->pData;
- BG(user_compare_fci).param_count = 2;
- BG(user_compare_fci).params = args;
- BG(user_compare_fci).retval_ptr_ptr = &retval_ptr;
- BG(user_compare_fci).no_separation = 0;
- if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache) TSRMLS_CC) == SUCCESS && retval_ptr) {
- long retval;
- convert_to_long_ex(&retval_ptr);
- retval = Z_LVAL_P(retval_ptr);
- zval_ptr_dtor(&retval_ptr);
- return retval < 0 ? -1 : retval > 0 ? 1 : 0;
- } else {
- return 0;
- }
- }
- /* }}} */
- /* check if comparison function is valid */
- #define PHP_ARRAY_CMP_FUNC_CHECK(func_name) \
- if (!zend_is_callable(*func_name, 0, NULL TSRMLS_CC)) { \
- php_error_docref(NULL TSRMLS_CC, 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 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() \
- BG(user_compare_fci) = old_user_compare_fci; \
- BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
- /* {{{ proto bool usort(array array_arg, string cmp_function)
- Sort an array by values using a user-defined comparison function */
- PHP_FUNCTION(usort)
- {
- zval *array;
- int refcount;
- PHP_ARRAY_CMP_FUNC_VARS;
- PHP_ARRAY_CMP_FUNC_BACKUP();
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
- PHP_ARRAY_CMP_FUNC_RESTORE();
- return;
- }
- /* Clear the is_ref flag, so the attemts to modify the array in user
- * comparison function will create a copy of array and won't affect the
- * original array. The fact of modification is detected using refcount
- * comparison. The result of sorting in such case is undefined and the
- * function returns FALSE.
- */
- Z_UNSET_ISREF_P(array);
- refcount = Z_REFCOUNT_P(array);
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 1 TSRMLS_CC) == FAILURE) {
- RETVAL_FALSE;
- } else {
- if (refcount > Z_REFCOUNT_P(array)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
- RETVAL_FALSE;
- } else {
- RETVAL_TRUE;
- }
- }
-
- if (Z_REFCOUNT_P(array) > 1) {
- Z_SET_ISREF_P(array);
- }
- PHP_ARRAY_CMP_FUNC_RESTORE();
- }
- /* }}} */
- /* {{{ 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)
- {
- zval *array;
- int refcount;
- PHP_ARRAY_CMP_FUNC_VARS;
- PHP_ARRAY_CMP_FUNC_BACKUP();
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
- PHP_ARRAY_CMP_FUNC_RESTORE();
- return;
- }
- /* Clear the is_ref flag, so the attemts to modify the array in user
- * comaprison function will create a copy of array and won't affect the
- * original array. The fact of modification is detected using refcount
- * comparison. The result of sorting in such case is undefined and the
- * function returns FALSE.
- */
- Z_UNSET_ISREF_P(array);
- refcount = Z_REFCOUNT_P(array);
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 0 TSRMLS_CC) == FAILURE) {
- RETVAL_FALSE;
- } else {
- if (refcount > Z_REFCOUNT_P(array)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
- RETVAL_FALSE;
- } else {
- RETVAL_TRUE;
- }
- }
- if (Z_REFCOUNT_P(array) > 1) {
- Z_SET_ISREF_P(array);
- }
- PHP_ARRAY_CMP_FUNC_RESTORE();
- }
- /* }}} */
- static int php_array_user_key_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
- {
- Bucket *f;
- Bucket *s;
- zval *key1, *key2;
- zval **args[2];
- zval *retval_ptr = NULL;
- long result;
- ALLOC_INIT_ZVAL(key1);
- ALLOC_INIT_ZVAL(key2);
- args[0] = &key1;
- args[1] = &key2;
- f = *((Bucket **) a);
- s = *((Bucket **) b);
- if (f->nKeyLength == 0) {
- Z_LVAL_P(key1) = f->h;
- Z_TYPE_P(key1) = IS_LONG;
- } else {
- Z_STRVAL_P(key1) = estrndup(f->arKey, f->nKeyLength - 1);
- Z_STRLEN_P(key1) = f->nKeyLength - 1;
- Z_TYPE_P(key1) = IS_STRING;
- }
- if (s->nKeyLength == 0) {
- Z_LVAL_P(key2) = s->h;
- Z_TYPE_P(key2) = IS_LONG;
- } else {
- Z_STRVAL_P(key2) = estrndup(s->arKey, s->nKeyLength - 1);
- Z_STRLEN_P(key2) = s->nKeyLength - 1;
- Z_TYPE_P(key2) = IS_STRING;
- }
- BG(user_compare_fci).param_count = 2;
- BG(user_compare_fci).params = args;
- BG(user_compare_fci).retval_ptr_ptr = &retval_ptr;
- BG(user_compare_fci).no_separation = 0;
- if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache) TSRMLS_CC) == SUCCESS && retval_ptr) {
- convert_to_long_ex(&retval_ptr);
- result = Z_LVAL_P(retval_ptr);
- zval_ptr_dtor(&retval_ptr);
- } else {
- result = 0;
- }
- zval_ptr_dtor(&key1);
- zval_ptr_dtor(&key2);
- return result;
- }
- /* }}} */
- /* {{{ proto bool uksort(array array_arg, string cmp_function)
- Sort an array by keys using a user-defined comparison function */
- PHP_FUNCTION(uksort)
- {
- zval *array;
- int refcount;
- PHP_ARRAY_CMP_FUNC_VARS;
- PHP_ARRAY_CMP_FUNC_BACKUP();
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
- PHP_ARRAY_CMP_FUNC_RESTORE();
- return;
- }
- /* Clear the is_ref flag, so the attemts to modify the array in user
- * comaprison function will create a copy of array and won't affect the
- * original array. The fact of modification is detected using refcount
- * comparison. The result of sorting in such case is undefined and the
- * function returns FALSE.
- */
- Z_UNSET_ISREF_P(array);
- refcount = Z_REFCOUNT_P(array);
- if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_key_compare, 0 TSRMLS_CC) == FAILURE) {
- RETVAL_FALSE;
- } else {
- if (refcount > Z_REFCOUNT_P(array)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
- RETVAL_FALSE;
- } else {
- RETVAL_TRUE;
- }
- }
- if (Z_REFCOUNT_P(array) > 1) {
- Z_SET_ISREF_P(array);
- }
- PHP_ARRAY_CMP_FUNC_RESTORE();
- }
- /* }}} */
- /* {{{ 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;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
- return;
- }
- zend_hash_internal_pointer_end(array);
- if (return_value_used) {
- if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_ZVAL(*entry, 1, 0);
- }
- }
- /* }}} */
- /* {{{ 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;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
- return;
- }
- zend_hash_move_backwards(array);
- if (return_value_used) {
- if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_ZVAL(*entry, 1, 0);
- }
- }
- /* }}} */
- /* {{{ 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;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
- return;
- }
- zend_hash_move_forward(array);
- if (return_value_used) {
- if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_ZVAL(*entry, 1, 0);
- }
- }
- /* }}} */
- /* {{{ 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;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
- return;
- }
- zend_hash_internal_pointer_reset(array);
- if (return_value_used) {
- if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_ZVAL(*entry, 1, 0);
- }
- }
- /* }}} */
- /* {{{ proto mixed current(array array_arg)
- Return the element currently pointed to by the internal array pointer */
- PHP_FUNCTION(current)
- {
- HashTable *array;
- zval **entry;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
- return;
- }
- if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
- RETURN_FALSE;
- }
- RETURN_ZVAL(*entry, 1, 0);
- }
- /* }}} */
- /* {{{ 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;
- char *string_key;
- uint string_length;
- ulong num_key;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
- return;
- }
- switch (zend_hash_get_current_key_ex(array, &string_key, &string_length, &num_key, 0, NULL)) {
- case HASH_KEY_IS_STRING:
- RETVAL_STRINGL(string_key, string_length - 1, 1);
- break;
- case HASH_KEY_IS_LONG:
- RETVAL_LONG(num_key);
- break;
- case HASH_KEY_NON_EXISTANT:
- return;
- }
- }
- /* }}} */
- /* {{{ 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;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
- return;
- }
-
- php_set_compare_func(PHP_SORT_REGULAR TSRMLS_CC);
-
- /* mixed min ( array $values ) */
- if (argc == 1) {
- zval **result;
-
- if (Z_TYPE_PP(args[0]) != IS_ARRAY) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "When only one parameter is given, it must be an array");
- RETVAL_NULL();
- } else {
- if (zend_hash_minmax(Z_ARRVAL_PP(args[0]), php_array_data_compare, 0, (void **) &result TSRMLS_CC) == SUCCESS) {
- RETVAL_ZVAL(*result, 1, 0);
- } else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array must contain at least one element");
- RETVAL_FALSE;
- }
- }
- } 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 TSRMLS_CC);
- if (Z_LVAL(result) == 1) {
- min = args[i];
- }
- }
- RETVAL_ZVAL(*min, 1, 0);
- }
- if (args) {
- efree(args);
- }
- }
- /* }}} */
- /* {{{ 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;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
- return;
- }
- php_set_compare_func(PHP_SORT_REGULAR TSRMLS_CC);
-
- /* mixed max ( array $values ) */
- if (argc == 1) {
- zval **result;
- if (Z_TYPE_PP(args[0]) != IS_ARRAY) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "When only one parameter is given, it must be an array");
- RETVAL_NULL();
- } else {
- if (zend_hash_minmax(Z_ARRVAL_PP(args[0]), php_array_data_compare, 1, (void **) &result TSRMLS_CC) == SUCCESS) {
- RETVAL_ZVAL(*result, 1, 0);
- } else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array must contain at least one element");
- RETVAL_FALSE;
- }
- }
- } 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 TSRMLS_CC);
- if (Z_LVAL(result) == 0) {
- max = args[i];
- }
- }
- RETVAL_ZVAL(*max, 1, 0);
- }
-
- if (args) {
- efree(args);
- }
- }
- /* }}} */
- static int php_array_walk(HashTable *target_hash, zval **userdata, int recursive TSRMLS_DC) /* {{{ */
- {
- zval **args[3], /* Arguments to userland function */
- *retval_ptr, /* Return value - unused */
- *key=NULL; /* Entry key */
- char *string_key;
- uint string_key_len;
- ulong num_key;
- HashPosition pos;
- /* Set up known arguments */
- args[1] = &key;
- args[2] = userdata;
- if (userdata) {
- Z_ADDREF_PP(userdata);
- }
- zend_hash_internal_pointer_reset_ex(target_hash, &pos);
- BG(array_walk_fci).retval_ptr_ptr = &retval_ptr;
- BG(array_walk_fci).param_count = userdata ? 3 : 2;
- BG(array_walk_fci).params = args;
- BG(array_walk_fci).no_separation = 0;
- /* Iterate through hash */
- while (!EG(exception) && zend_hash_get_current_data_ex(target_hash, (void **)&args[0], &pos) == SUCCESS) {
- if (recursive && Z_TYPE_PP(args[0]) == IS_ARRAY) {
- HashTable *thash;
- zend_fcall_info orig_array_walk_fci;
- zend_fcall_info_cache orig_array_walk_fci_cache;
- SEPARATE_ZVAL_IF_NOT_REF(args[0]);
- thash = Z_ARRVAL_PP(args[0]);
- if (thash->nApplyCount > 1) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
- if (userdata) {
- zval_ptr_dtor(userdata);
- }
- return 0;
- }
- /* backup the fcall info and cache */
- orig_array_walk_fci = BG(array_walk_fci);
- orig_array_walk_fci_cache = BG(array_walk_fci_cache);
- thash->nApplyCount++;
- php_array_walk(thash, userdata, recursive TSRMLS_CC);
- thash->nApplyCount--;
- /* 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 {
- /* Allocate space for key */
- MAKE_STD_ZVAL(key);
- /* Set up the key */
- switch (zend_hash_get_current_key_ex(target_hash, &string_key, &string_key_len, &num_key, 0, &pos)) {
- case HASH_KEY_IS_LONG:
- Z_TYPE_P(key) = IS_LONG;
- Z_LVAL_P(key) = num_key;
- break;
- case HASH_KEY_IS_STRING:
- ZVAL_STRINGL(key, string_key, string_key_len - 1, 1);
- break;
- }
- /* Call the userland function */
- if (zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache) TSRMLS_CC) == SUCCESS) {
- if (retval_ptr) {
- zval_ptr_dtor(&retval_ptr);
- }
- } else {
- if (key) {
- zval_ptr_dtor(&key);
- key = NULL;
- }
- break;
- }
- }
- if (key) {
- zval_ptr_dtor(&key);
- key = NULL;
- }
- zend_hash_move_forward_ex(target_hash, &pos);
- }
- if (userdata) {
- zval_ptr_dtor(userdata);
- }
- return 0;
- }
- /* }}} */
- /* {{{ proto bool array_walk(array input, string funcname [, mixed userdata])
- Apply a user function to every member of an array */
- PHP_FUNCTION(array_walk)
- {
- HashTable *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);
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Hf|z/", &array, &BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
- BG(array_walk_fci) = orig_array_walk_fci;
- BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
- return;
- }
- php_array_walk(array, userdata ? &userdata : NULL, 0 TSRMLS_CC);
- 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)
- {
- HashTable *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);
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Hf|z/", &array, &BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
- BG(array_walk_fci) = orig_array_walk_fci;
- BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
- return;
- }
- php_array_walk(array, userdata ? &userdata : NULL, 1 TSRMLS_CC);
- 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 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 */
- res; /* comparison result */
- HashPosition pos; /* hash iterator */
- zend_bool strict = 0; /* strict comparison or not */
- ulong num_key;
- uint str_key_len;
- char *string_key;
- int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za|b", &value, &array, &strict) == FAILURE) {
- return;
- }
- if (strict) {
- is_equal_func = is_identical_function;
- }
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
- while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {
- is_equal_func(&res, value, *entry TSRMLS_CC);
- if (Z_LVAL(res)) {
- if (behavior == 0) {
- RETURN_TRUE;
- } else {
- /* Return current key */
- switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &str_key_len, &num_key, 0, &pos)) {
- case HASH_KEY_IS_STRING:
- RETURN_STRINGL(string_key, str_key_len - 1, 1);
- break;
- case HASH_KEY_IS_LONG:
- RETURN_LONG(num_key);
- break;
- }
- }
- }
- zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos);
- }
- 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 int php_valid_var_name(char *var_name, int var_name_len) /* {{{ */
- {
- int i, ch;
- if (!var_name || !var_name_len) {
- return 0;
- }
-
- /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
- ch = (int)((unsigned char *)var_name)[0];
- if (var_name[0] != '_' &&
- (ch < 65 /* A */ || /* Z */ ch > 90) &&
- (ch < 97 /* a */ || /* z */ ch > 122) &&
- (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
- ) {
- return 0;
- }
- /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
- if (var_name_len > 1) {
- for (i = 1; i < var_name_len; i++) {
- ch = (int)((unsigned char *)var_name)[i];
- 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)
- ) {
- return 0;
- }
- }
- }
- return 1;
- }
- /* }}} */
- PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, int var_name_len, zend_bool add_underscore TSRMLS_DC) /* {{{ */
- {
- Z_STRLEN_P(result) = Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0) + var_name_len;
- Z_TYPE_P(result) = IS_STRING;
- Z_STRVAL_P(result) = emalloc(Z_STRLEN_P(result) + 1);
- memcpy(Z_STRVAL_P(result), Z_STRVAL_P(prefix), Z_STRLEN_P(prefix));
- if (add_underscore) {
- Z_STRVAL_P(result)[Z_STRLEN_P(prefix)] = '_';
- }
- memcpy(Z_STRVAL_P(result) + Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1);
- return SUCCESS;
- }
- /* }}} */
- /* {{{ proto int extract(array var_array [, int extract_type [, string prefix]])
- Imports variables into symbol table from an array */
- PHP_FUNCTION(extract)
- {
- zval *var_array, *prefix = NULL;
- long extract_type = EXTR_OVERWRITE;
- zval **entry, *data;
- char *var_name;
- ulong num_key;
- uint var_name_len;
- int var_exists, key_type, count = 0;
- int extract_refs = 0;
- HashPosition pos;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|lz/", &var_array, &extract_type, &prefix) == FAILURE) {
- return;
- }
- extract_refs = (extract_type & EXTR_REFS);
- extract_type &= 0xff;
- if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid extract type");
- return;
- }
- if (extract_type > EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS && ZEND_NUM_ARGS() < 3) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "specified extract type requires the prefix parameter");
- return;
- }
- if (prefix) {
- convert_to_string(prefix);
- if (Z_STRLEN_P(prefix) && !php_valid_var_name(Z_STRVAL_P(prefix), Z_STRLEN_P(prefix))) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "prefix is not a valid identifier");
- return;
- }
- }
- if (!EG(active_symbol_table)) {
- zend_rebuild_symbol_table(TSRMLS_C);
- }
- /* var_array is passed by ref for the needs of EXTR_REFS (needs to
- * work on the original array to create refs to its members)
- * simulate pass_by_value if EXTR_REFS is not used */
- if (!extract_refs) {
- SEPARATE_ARG_IF_REF(var_array);
- }
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
- while (zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&entry, &pos) == SUCCESS) {
- zval final_name;
- ZVAL_NULL(&final_name);
- key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &var_name, &var_name_len, &num_key, 0, &pos);
- var_exists = 0;
- if (key_type == HASH_KEY_IS_STRING) {
- var_name_len--;
- var_exists = zend_hash_exists(EG(active_symbol_table), var_name, var_name_len + 1);
- } else if (key_type == HASH_KEY_IS_LONG && (extract_type == EXTR_PREFIX_ALL || extract_type == EXTR_PREFIX_INVALID)) {
- zval num;
- ZVAL_LONG(&num, num_key);
- convert_to_string(&num);
- php_prefix_varname(&final_name, prefix, Z_STRVAL(num), Z_STRLEN(num), 1 TSRMLS_CC);
- zval_dtor(&num);
- } else {
- zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
- continue;
- }
- switch (extract_type) {
- case EXTR_IF_EXISTS:
- if (!var_exists) break;
- /* break omitted intentionally */
- case EXTR_OVERWRITE:
- /* GLOBALS protection */
- if (var_exists && var_name_len == sizeof("GLOBALS")-1 && !strcmp(var_name, "GLOBALS")) {
- break;
- }
- if (var_exists && var_name_len == sizeof("this")-1 && !strcmp(var_name, "this") && EG(scope) && EG(scope)->name_length != 0) {
- break;
- }
- ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
- break;
- case EXTR_PREFIX_IF_EXISTS:
- if (var_exists) {
- php_prefix_varname(&final_name, prefix, var_name, var_name_len, 1 TSRMLS_CC);
- }
- break;
- case EXTR_PREFIX_SAME:
- if (!var_exists && var_name_len != 0) {
- ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
- }
- /* break omitted intentionally */
- case EXTR_PREFIX_ALL:
- if (Z_TYPE(final_name) == IS_NULL && var_name_len != 0) {
- php_prefix_varname(&final_name, prefix, var_name, var_name_len, 1 TSRMLS_CC);
- }
- break;
- case EXTR_PREFIX_INVALID:
- if (Z_TYPE(final_name) == IS_NULL) {
- if (!php_valid_var_name(var_name, var_name_len)) {
- php_prefix_varname(&final_name, prefix, var_name, var_name_len, 1 TSRMLS_CC);
- } else {
- ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
- }
- }
- break;
- default:
- if (!var_exists) {
- ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
- }
- break;
- }
- if (Z_TYPE(final_name) != IS_NULL && php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
- if (extract_refs) {
- zval **orig_var;
- SEPARATE_ZVAL_TO_MAKE_IS_REF(entry);
- zval_add_ref(entry);
- if (zend_hash_find(EG(active_symbol_table), Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, (void **) &orig_var) == SUCCESS) {
- zval_ptr_dtor(orig_var);
- *orig_var = *entry;
- } else {
- zend_hash_update(EG(active_symbol_table), Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, (void **) entry, sizeof(zval *), NULL);
- }
- } else {
- MAKE_STD_ZVAL(data);
- *data = **entry;
- zval_copy_ctor(data);
- ZEND_SET_SYMBOL_WITH_LENGTH(EG(active_symbol_table), Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, data, 1, 0);
- }
- count++;
- }
- zval_dtor(&final_name);
- zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
- }
- if (!extract_refs) {
- zval_ptr_dtor(&var_array);
- }
- RETURN_LONG(count);
- }
- /* }}} */
- static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_value, zval *entry TSRMLS_DC) /* {{{ */
- {
- zval **value_ptr, *value, *data;
- if (Z_TYPE_P(entry) == IS_STRING) {
- if (zend_hash_find(eg_active_symbol_table, Z_STRVAL_P(entry), Z_STRLEN_P(entry) + 1, (void **)&value_ptr) != FAILURE) {
- value = *value_ptr;
- ALLOC_ZVAL(data);
- MAKE_COPY_ZVAL(&value, data);
- zend_hash_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(entry), Z_STRLEN_P(entry) + 1, &data, sizeof(zval *), NULL);
- }
- }
- else if (Z_TYPE_P(entry) == IS_ARRAY) {
- HashPosition pos;
- if ((Z_ARRVAL_P(entry)->nApplyCount > 1)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
- return;
- }
- Z_ARRVAL_P(entry)->nApplyCount++;
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos);
- while (zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), (void**)&value_ptr, &pos) == SUCCESS) {
- value = *value_ptr;
- php_compact_var(eg_active_symbol_table, return_value, value TSRMLS_CC);
- zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos);
- }
- Z_ARRVAL_P(entry)->nApplyCount--;
- }
- }
- /* }}} */
- /* {{{ proto array compact(mixed var_names [, mixed ...])
- Creates a hash containing variables and their values */
- PHP_FUNCTION(compact)
- {
- zval ***args = NULL; /* function arguments array */
- int num_args, i;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
- return;
- }
- if (!EG(active_symbol_table)) {
- zend_rebuild_symbol_table(TSRMLS_C);
- }
- /* compact() is probably most used with a single array of var_names
- or multiple string names, rather than a combination of both.
- So quickly guess a minimum result size based on that */
- if (ZEND_NUM_ARGS() == 1 && Z_TYPE_PP(args[0]) == IS_ARRAY) {
- array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_PP(args[0])));
- } else {
- array_init_size(return_value, ZEND_NUM_ARGS());
- }
- for (i=0; i<ZEND_NUM_ARGS(); i++) {
- php_compact_var(EG(active_symbol_table), return_value, *args[i] TSRMLS_CC);
- }
- if (args) {
- efree(args);
- }
- }
- /* }}} */
- /* {{{ proto array array_fill(int start_key, int num, mixed val)
- Create an array containing num elements starting with index start_key each initialized to val */
- PHP_FUNCTION(array_fill)
- {
- zval *val;
- long start_key, num;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "llz", &start_key, &num, &val) == FAILURE) {
- return;
- }
- if (num < 1) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements must be positive");
- RETURN_FALSE;
- }
- /* allocate an array for return */
- array_init_size(return_value, num);
- num--;
- zval_add_ref(&val);
- zend_hash_index_update(Z_ARRVAL_P(return_value), start_key, &val, sizeof(zval *), NULL);
- while (num--) {
- zval_add_ref(&val);
- zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &val, sizeof(zval *), NULL);
- }
- }
- /* }}} */
- /* {{{ proto array array_fill_keys(array keys, mixed val)
- Create an array using the elements of the first parameter as keys each initialized to val */
- PHP_FUNCTION(array_fill_keys)
- {
- zval *keys, *val, **entry;
- HashPosition pos;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az", &keys, &val) == FAILURE) {
- return;
- }
- /* Initialize return array */
- array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
- while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&entry, &pos) == SUCCESS) {
- if (Z_TYPE_PP(entry) == IS_LONG) {
- zval_add_ref(&val);
- zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &val, sizeof(zval *), NULL);
- } else {
- zval key, *key_ptr = *entry;
- if (Z_TYPE_PP(entry) != IS_STRING) {
- key = **entry;
- zval_copy_ctor(&key);
- convert_to_string(&key);
- key_ptr = &key;
- }
- zval_add_ref(&val);
- zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(key_ptr), Z_STRLEN_P(key_ptr) + 1, &val, sizeof(zval *), NULL);
- if (key_ptr != *entry) {
- zval_dtor(&key);
- }
- }
- zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
- }
- }
- /* }}} */
- /* {{{ proto array range(mixed low, mixed high[, int step])
- Create an array containing the range of integers or characters from low to high (inclusive) */
- PHP_FUNCTION(range)
- {
- zval *zlow, *zhigh, *zstep = NULL;
- int err = 0, is_step_double = 0;
- double step = 1.0;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z/|z/", &zlow, &zhigh, &zstep) == FAILURE) {
- RETURN_FALSE;
- }
- if (zstep) {
- if (Z_TYPE_P(zstep) == IS_DOUBLE ||
- (Z_TYPE_P(zstep) == IS_STRING && is_numeric_string(Z_STRVAL_P(zstep), Z_STRLEN_P(zstep), NULL, NULL, 0) == IS_DOUBLE)
- ) {
- is_step_double = 1;
- }
- convert_to_double_ex(&zstep);
- step = Z_DVAL_P(zstep);
- /* We only want positive step values. */
- if (step < 0.0) {
- step *= -1;
- }
- }
- /* Initialize the return_value as an array. */
- array_init(return_value);
- /* If the range is given as strings, generate an array of characters. */
- if (Z_TYPE_P(zlow) == IS_STRING && Z_TYPE_P(zhigh) == IS_STRING && Z_STRLEN_P(zlow) >= 1 && Z_STRLEN_P(zhigh) >= 1) {
- int type1, type2;
- unsigned char *low, *high;
- long lstep = (long) step;
- type1 = is_numeric_string(Z_STRVAL_P(zlow), Z_STRLEN_P(zlow), NULL, NULL, 0);
- type2 = is_numeric_string(Z_STRVAL_P(zhigh), Z_STRLEN_P(zhigh), NULL, NULL, 0);
- if (type1 == IS_DOUBLE || type2 == IS_DOUBLE || is_step_double) {
- goto double_str;
- } else if (type1 == IS_LONG || type2 == IS_LONG) {
- goto long_str;
- }
- convert_to_string(zlow);
- convert_to_string(zhigh);
- low = (unsigned char *)Z_STRVAL_P(zlow);
- high = (unsigned char *)Z_STRVAL_P(zhigh);
- if (*low > *high) { /* Negative Steps */
- if (lstep <= 0) {
- err = 1;
- goto err;
- }
- for (; *low >= *high; (*low) -= (unsigned int)lstep) {
- add_next_index_stringl(return_value, (const char *)low, 1, 1);
- if (((signed int)*low - lstep) < 0) {
- break;
- }
- }
- } else if (*high > *low) { /* Positive Steps */
- if (lstep <= 0) {
- err = 1;
- goto err;
- }
- for (; *low <= *high; (*low) += (unsigned int)lstep) {
- add_next_index_stringl(return_value, (const char *)low, 1, 1);
- if (((signed int)*low + lstep) > 255) {
- break;
- }
- }
- } else {
- add_next_index_stringl(return_value, (const char *)low, 1, 1);
- }
- } else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) {
- double low, high;
- double_str:
- convert_to_double(zlow);
- convert_to_double(zhigh);
- low = Z_DVAL_P(zlow);
- high = Z_DVAL_P(zhigh);
- if (low > high) { /* Negative steps */
- if (low - high < step || step <= 0) {
- err = 1;
- goto err;
- }
- for (; low >= (high - DOUBLE_DRIFT_FIX); low -= step) {
- add_next_index_double(return_value, low);
- }
- } else if (high > low) { /* Positive steps */
- if (high - low < step || step <= 0) {
- err = 1;
- goto err;
- }
- for (; low <= (high + DOUBLE_DRIFT_FIX); low += step) {
- add_next_index_double(return_value, low);
- }
- } else {
- add_next_index_double(return_value, low);
- }
- } else {
- double low, high;
- long lstep;
- long_str:
- convert_to_double(zlow);
- convert_to_double(zhigh);
- low = Z_DVAL_P(zlow);
- high = Z_DVAL_P(zhigh);
- lstep = (long) step;
- if (low > high) { /* Negative steps */
- if (low - high < lstep || lstep <= 0) {
- err = 1;
- goto err;
- }
- for (; low >= high; low -= lstep) {
- add_next_index_long(return_value, (long)low);
- }
- } else if (high > low) { /* Positive steps */
- if (high - low < lstep || lstep <= 0) {
- err = 1;
- goto err;
- }
- for (; low <= high; low += lstep) {
- add_next_index_long(return_value, (long)low);
- }
- } else {
- add_next_index_long(return_value, (long)low);
- }
- }
- err:
- if (err) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "step exceeds the specified range");
- zval_dtor(return_value);
- RETURN_FALSE;
- }
- }
- /* }}} */
- static void php_array_data_shuffle(zval *array TSRMLS_DC) /* {{{ */
- {
- Bucket **elems, *temp;
- HashTable *hash;
- int j, n_elems, rnd_idx, n_left;
- n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
- if (n_elems < 1) {
- return;
- }
- elems = (Bucket **)safe_emalloc(n_elems, sizeof(Bucket *), 0);
- hash = Z_ARRVAL_P(array);
- n_left = n_elems;
- for (j = 0, temp = hash->pListHead; temp; temp = temp->pListNext)
- elems[j++] = temp;
- while (--n_left) {
- rnd_idx = php_rand(TSRMLS_C);
- RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
- if (rnd_idx != n_left) {
- temp = elems[n_left];
- elems[n_left] = elems[rnd_idx];
- elems[rnd_idx] = temp;
- }
- }
- HANDLE_BLOCK_INTERRUPTIONS();
- hash->pListHead = elems[0];
- hash->pListTail = NULL;
- hash->pInternalPointer = hash->pListHead;
- for (j = 0; j < n_elems; j++) {
- if (hash->pListTail) {
- hash->pListTail->pListNext = elems[j];
- }
- elems[j]->pListLast = hash->pListTail;
- elems[j]->pListNext = NULL;
- hash->pListTail = elems[j];
- }
- temp = hash->pListHead;
- j = 0;
- while (temp != NULL) {
- temp->nKeyLength = 0;
- temp->h = j++;
- temp = temp->pListNext;
- }
- hash->nNextFreeElement = n_elems;
- zend_hash_rehash(hash);
- HANDLE_UNBLOCK_INTERRUPTIONS();
- efree(elems);
- }
- /* }}} */
- /* {{{ proto bool shuffle(array array_arg)
- Randomly shuffle the contents of an array */
- PHP_FUNCTION(shuffle)
- {
- zval *array;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
- RETURN_FALSE;
- }
- php_array_data_shuffle(array TSRMLS_CC);
- RETURN_TRUE;
- }
- /* }}} */
- PHPAPI HashTable* php_splice(HashTable *in_hash, int offset, int length, zval ***list, int list_count, HashTable **removed) /* {{{ */
- {
- HashTable *out_hash = NULL; /* Output hashtable */
- int num_in, /* Number of entries in the input hashtable */
- pos, /* Current position in the hashtable */
- i; /* Loop counter */
- Bucket *p; /* Pointer to hash bucket */
- zval *entry; /* Hash entry */
- /* If input hash doesn't exist, we have nothing to do */
- if (!in_hash) {
- return NULL;
- }
- /* Get number of entries in the input hash */
- num_in = zend_hash_num_elements(in_hash);
- /* Clamp the offset.. */
- if (offset > num_in) {
- offset = num_in;
- } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
- offset = 0;
- }
- /* ..and the length */
- if (length < 0) {
- length = num_in - offset + length;
- } else if (((unsigned)offset + (unsigned)length) > (unsigned)num_in) {
- length = num_in - offset;
- }
- /* Create and initialize output hash */
- ALLOC_HASHTABLE(out_hash);
- zend_hash_init(out_hash, (length > 0 ? num_in - length : 0) + list_count, NULL, ZVAL_PTR_DTOR, 0);
- /* Start at the beginning of the input hash and copy entries to output hash untiā¦
Large files files are truncated, but you can click here to view the full file