PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/standard - array.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 2253 2417 93.2 %
Date: 2015-05-21 Functions: 111 111 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2015 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    |          Rasmus Lerdorf <rasmus@php.net>                             |
      18             :    |          Andrei Zmievski <andrei@php.net>                            |
      19             :    |          Stig Venaas <venaas@php.net>                                |
      20             :    |          Jason Greene <jason@php.net>                                |
      21             :    +----------------------------------------------------------------------+
      22             : */
      23             : 
      24             : /* $Id$ */
      25             : 
      26             : #include "php.h"
      27             : #include "php_ini.h"
      28             : #include <stdarg.h>
      29             : #include <stdlib.h>
      30             : #include <math.h>
      31             : #include <time.h>
      32             : #include <stdio.h>
      33             : #if HAVE_STRING_H
      34             : #include <string.h>
      35             : #else
      36             : #include <strings.h>
      37             : #endif
      38             : #ifdef PHP_WIN32
      39             : #include "win32/unistd.h"
      40             : #endif
      41             : #include "zend_globals.h"
      42             : #include "zend_interfaces.h"
      43             : #include "php_globals.h"
      44             : #include "php_array.h"
      45             : #include "basic_functions.h"
      46             : #include "php_string.h"
      47             : #include "php_rand.h"
      48             : #include "zend_smart_str.h"
      49             : #ifdef HAVE_SPL
      50             : #include "ext/spl/spl_array.h"
      51             : #endif
      52             : 
      53             : /* {{{ defines */
      54             : #define EXTR_OVERWRITE                  0
      55             : #define EXTR_SKIP                               1
      56             : #define EXTR_PREFIX_SAME                2
      57             : #define EXTR_PREFIX_ALL                 3
      58             : #define EXTR_PREFIX_INVALID             4
      59             : #define EXTR_PREFIX_IF_EXISTS   5
      60             : #define EXTR_IF_EXISTS                  6
      61             : 
      62             : #define EXTR_REFS                               0x100
      63             : 
      64             : #define CASE_LOWER                              0
      65             : #define CASE_UPPER                              1
      66             : 
      67             : #define DIFF_NORMAL                     1
      68             : #define DIFF_KEY                        2
      69             : #define DIFF_ASSOC                      6
      70             : #define DIFF_COMP_DATA_NONE    -1
      71             : #define DIFF_COMP_DATA_INTERNAL 0
      72             : #define DIFF_COMP_DATA_USER     1
      73             : #define DIFF_COMP_KEY_INTERNAL  0
      74             : #define DIFF_COMP_KEY_USER      1
      75             : 
      76             : #define INTERSECT_NORMAL                1
      77             : #define INTERSECT_KEY                   2
      78             : #define INTERSECT_ASSOC                 6
      79             : #define INTERSECT_COMP_DATA_NONE    -1
      80             : #define INTERSECT_COMP_DATA_INTERNAL 0
      81             : #define INTERSECT_COMP_DATA_USER     1
      82             : #define INTERSECT_COMP_KEY_INTERNAL  0
      83             : #define INTERSECT_COMP_KEY_USER      1
      84             : 
      85             : #define DOUBLE_DRIFT_FIX        0.000000000000001
      86             : /* }}} */
      87             : 
      88             : ZEND_DECLARE_MODULE_GLOBALS(array)
      89             : 
      90             : /* {{{ php_array_init_globals
      91             : */
      92       20916 : static void php_array_init_globals(zend_array_globals *array_globals)
      93             : {
      94       20916 :         memset(array_globals, 0, sizeof(zend_array_globals));
      95       20916 : }
      96             : /* }}} */
      97             : 
      98       20916 : PHP_MINIT_FUNCTION(array) /* {{{ */
      99             : {
     100       20916 :         ZEND_INIT_MODULE_GLOBALS(array, php_array_init_globals, NULL);
     101             : 
     102       20916 :         REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", EXTR_OVERWRITE, CONST_CS | CONST_PERSISTENT);
     103       20916 :         REGISTER_LONG_CONSTANT("EXTR_SKIP", EXTR_SKIP, CONST_CS | CONST_PERSISTENT);
     104       20916 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT);
     105       20916 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT);
     106       20916 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_INVALID", EXTR_PREFIX_INVALID, CONST_CS | CONST_PERSISTENT);
     107       20916 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_IF_EXISTS", EXTR_PREFIX_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
     108       20916 :         REGISTER_LONG_CONSTANT("EXTR_IF_EXISTS", EXTR_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
     109       20916 :         REGISTER_LONG_CONSTANT("EXTR_REFS", EXTR_REFS, CONST_CS | CONST_PERSISTENT);
     110             : 
     111       20916 :         REGISTER_LONG_CONSTANT("SORT_ASC", PHP_SORT_ASC, CONST_CS | CONST_PERSISTENT);
     112       20916 :         REGISTER_LONG_CONSTANT("SORT_DESC", PHP_SORT_DESC, CONST_CS | CONST_PERSISTENT);
     113             : 
     114       20916 :         REGISTER_LONG_CONSTANT("SORT_REGULAR", PHP_SORT_REGULAR, CONST_CS | CONST_PERSISTENT);
     115       20916 :         REGISTER_LONG_CONSTANT("SORT_NUMERIC", PHP_SORT_NUMERIC, CONST_CS | CONST_PERSISTENT);
     116       20916 :         REGISTER_LONG_CONSTANT("SORT_STRING", PHP_SORT_STRING, CONST_CS | CONST_PERSISTENT);
     117       20916 :         REGISTER_LONG_CONSTANT("SORT_LOCALE_STRING", PHP_SORT_LOCALE_STRING, CONST_CS | CONST_PERSISTENT);
     118       20916 :         REGISTER_LONG_CONSTANT("SORT_NATURAL", PHP_SORT_NATURAL, CONST_CS | CONST_PERSISTENT);
     119       20916 :         REGISTER_LONG_CONSTANT("SORT_FLAG_CASE", PHP_SORT_FLAG_CASE, CONST_CS | CONST_PERSISTENT);
     120             : 
     121       20916 :         REGISTER_LONG_CONSTANT("CASE_LOWER", CASE_LOWER, CONST_CS | CONST_PERSISTENT);
     122       20916 :         REGISTER_LONG_CONSTANT("CASE_UPPER", CASE_UPPER, CONST_CS | CONST_PERSISTENT);
     123             : 
     124       20916 :         REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
     125       20916 :         REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
     126             : 
     127       20916 :         REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT);
     128       20916 :         REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT);
     129             : 
     130       20916 :         return SUCCESS;
     131             : }
     132             : /* }}} */
     133             : 
     134       20952 : PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
     135             : {
     136             : #ifdef ZTS
     137             :         ts_free_id(array_globals_id);
     138             : #endif
     139             : 
     140       20952 :         return SUCCESS;
     141             : }
     142             : /* }}} */
     143             : 
     144        3110 : static void php_set_compare_func(zend_long sort_type) /* {{{ */
     145             : {
     146        3110 :         switch (sort_type & ~PHP_SORT_FLAG_CASE) {
     147             :                 case PHP_SORT_NUMERIC:
     148         107 :                         ARRAYG(compare_func) = numeric_compare_function;
     149         107 :                         break;
     150             : 
     151             :                 case PHP_SORT_STRING:
     152        1360 :                         ARRAYG(compare_func) = sort_type & PHP_SORT_FLAG_CASE ? string_case_compare_function : string_compare_function;
     153        1360 :                         break;
     154             : 
     155             :                 case PHP_SORT_NATURAL:
     156          55 :                         ARRAYG(compare_func) = sort_type & PHP_SORT_FLAG_CASE ? string_natural_case_compare_function : string_natural_compare_function;
     157          55 :                         break;
     158             : 
     159             : #if HAVE_STRCOLL
     160             :                 case PHP_SORT_LOCALE_STRING:
     161           1 :                         ARRAYG(compare_func) = string_locale_compare_function;
     162           1 :                         break;
     163             : #endif
     164             : 
     165             :                 case PHP_SORT_REGULAR:
     166             :                 default:
     167        1587 :                         ARRAYG(compare_func) = compare_function;
     168             :                         break;
     169             :         }
     170        3110 : }
     171             : /* }}} */
     172             : 
     173        2812 : static int php_array_key_compare(const void *a, const void *b) /* {{{ */
     174             : {
     175             :         Bucket *f;
     176             :         Bucket *s;
     177             :         zval result;
     178             :         zval first;
     179             :         zval second;
     180             : 
     181        2812 :         f = (Bucket *) a;
     182        2812 :         s = (Bucket *) b;
     183             : 
     184        2812 :         if (f->key == NULL) {
     185        1629 :                 ZVAL_LONG(&first, f->h);
     186             :         } else {
     187        1183 :                 ZVAL_STR(&first, f->key);
     188             :         }
     189             : 
     190        2812 :         if (s->key == NULL) {
     191        1631 :                 ZVAL_LONG(&second, s->h);
     192             :         } else {
     193        1181 :                 ZVAL_STR(&second, s->key);
     194             :         }
     195             : 
     196        2812 :         if (ARRAYG(compare_func)(&result, &first, &second) == FAILURE) {
     197           0 :                 return 0;
     198             :         }
     199             : 
     200        2812 :         if (EXPECTED(Z_TYPE(result) == IS_LONG)) {
     201        2812 :                 return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
     202           0 :         } else if (Z_TYPE(result) == IS_DOUBLE) {
     203           0 :                 return ZEND_NORMALIZE_BOOL(Z_DVAL(result));
     204             :         }
     205             : 
     206           0 :         return ZEND_NORMALIZE_BOOL(zval_get_long(&result));
     207             : }
     208             : /* }}} */
     209             : 
     210        1268 : static int php_array_reverse_key_compare(const void *a, const void *b) /* {{{ */
     211             : {
     212        1268 :         return php_array_key_compare(a, b) * -1;
     213             : }
     214             : /* }}} */
     215             : 
     216             : /* {{{ proto bool krsort(array &array_arg [, int sort_flags])
     217             :    Sort an array by key value in reverse order */
     218         199 : PHP_FUNCTION(krsort)
     219             : {
     220             :         zval *array;
     221         199 :         zend_long sort_type = PHP_SORT_REGULAR;
     222             : 
     223             : #ifndef FAST_ZPP
     224             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     225             :                 RETURN_FALSE;
     226             :         }
     227             : #else
     228         199 :         ZEND_PARSE_PARAMETERS_START(1, 2)
     229         774 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
     230         103 :                 Z_PARAM_OPTIONAL
     231         229 :                 Z_PARAM_LONG(sort_type)
     232         199 :         ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
     233             : #endif
     234             : 
     235          95 :         php_set_compare_func(sort_type);
     236             : 
     237          95 :         if (zend_hash_sort(Z_ARRVAL_P(array), php_array_reverse_key_compare, 0) == FAILURE) {
     238           0 :                 RETURN_FALSE;
     239             :         }
     240          95 :         RETURN_TRUE;
     241             : }
     242             : /* }}} */
     243             : 
     244             : /* {{{ proto bool ksort(array &array_arg [, int sort_flags])
     245             :    Sort an array by key */
     246         483 : PHP_FUNCTION(ksort)
     247             : {
     248             :         zval *array;
     249         483 :         zend_long sort_type = PHP_SORT_REGULAR;
     250             : 
     251             : #ifndef FAST_ZPP
     252             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     253             :                 RETURN_FALSE;
     254             :         }
     255             : #else
     256         483 :         ZEND_PARSE_PARAMETERS_START(1, 2)
     257        1909 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
     258         387 :                 Z_PARAM_OPTIONAL
     259         533 :                 Z_PARAM_LONG(sort_type)
     260         483 :         ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
     261             : #endif
     262             : 
     263         378 :         php_set_compare_func(sort_type);
     264             : 
     265         378 :         if (zend_hash_sort(Z_ARRVAL_P(array), php_array_key_compare, 0) == FAILURE) {
     266           0 :                 RETURN_FALSE;
     267             :         }
     268         378 :         RETURN_TRUE;
     269             : }
     270             : /* }}} */
     271             : 
     272         248 : PHPAPI zend_long php_count_recursive(zval *array, zend_long mode) /* {{{ */
     273             : {
     274         248 :         zend_long cnt = 0;
     275             :         zval *element;
     276             : 
     277         248 :         if (Z_TYPE_P(array) == IS_ARRAY) {
     278          59 :                 if (Z_ARRVAL_P(array)->u.v.nApplyCount > 1) {
     279           1 :                         php_error_docref(NULL, E_WARNING, "recursion detected");
     280           1 :                         return 0;
     281             :                 }
     282             : 
     283          58 :                 cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
     284          58 :                 if (mode == COUNT_RECURSIVE) {
     285          58 :                     if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) {
     286          58 :                                 Z_ARRVAL_P(array)->u.v.nApplyCount++;
     287             :                         }
     288         270 :                         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), element) {
     289         106 :                                 ZVAL_DEREF(element);
     290         106 :                                 cnt += php_count_recursive(element, COUNT_RECURSIVE);
     291             :                         } ZEND_HASH_FOREACH_END();
     292          58 :                     if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) {
     293          58 :                                 Z_ARRVAL_P(array)->u.v.nApplyCount--;
     294             :                         }
     295             :                 }
     296             :         }
     297             : 
     298         247 :         return cnt;
     299             : }
     300             : /* }}} */
     301             : 
     302             : /* {{{ proto int count(mixed var [, int mode])
     303             :    Count the number of elements in a variable (usually an array) */
     304      208180 : PHP_FUNCTION(count)
     305             : {
     306             :         zval *array;
     307      208180 :         zend_long mode = COUNT_NORMAL;
     308             :         zend_long cnt;
     309             :         zval *element;
     310             : 
     311             : #ifndef FAST_ZPP
     312             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &array, &mode) == FAILURE) {
     313             :                 return;
     314             :         }
     315             : #else
     316      208180 :         ZEND_PARSE_PARAMETERS_START(1, 2)
     317      208173 :                 Z_PARAM_ZVAL(array)
     318      208173 :                 Z_PARAM_OPTIONAL
     319      208621 :                 Z_PARAM_LONG(mode)
     320      208180 :         ZEND_PARSE_PARAMETERS_END();
     321             : #endif
     322             : 
     323      416314 :         switch (Z_TYPE_P(array)) {
     324             :                 case IS_NULL:
     325      160779 :                         RETURN_LONG(0);
     326             :                         break;
     327             :                 case IS_ARRAY:
     328       19896 :                         cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
     329       19896 :                         if (mode == COUNT_RECURSIVE) {
     330         333 :                                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), element) {
     331         142 :                                         ZVAL_DEREF(element);
     332         142 :                                         cnt += php_count_recursive(element, COUNT_RECURSIVE);
     333             :                                 } ZEND_HASH_FOREACH_END();
     334             :                         }
     335       19896 :                         RETURN_LONG(cnt);
     336             :                         break;
     337             :                 case IS_OBJECT: {
     338             : #ifdef HAVE_SPL
     339             :                         zval retval;
     340             : #endif
     341             :                         /* first, we check if the handler is defined */
     342         107 :                         if (Z_OBJ_HT_P(array)->count_elements) {
     343          66 :                                 RETVAL_LONG(1);
     344          66 :                                 if (SUCCESS == Z_OBJ_HT(*array)->count_elements(array, &Z_LVAL_P(return_value))) {
     345          65 :                                         return;
     346             :                                 }
     347             :                         }
     348             : #ifdef HAVE_SPL
     349             :                         /* if not and the object implements Countable we call its count() method */
     350          42 :                         if (instanceof_function(Z_OBJCE_P(array), spl_ce_Countable)) {
     351          26 :                                 zend_call_method_with_0_params(array, NULL, NULL, "count", &retval);
     352          26 :                                 if (Z_TYPE(retval) != IS_UNDEF) {
     353          48 :                                         RETVAL_LONG(zval_get_long(&retval));
     354          24 :                                         zval_ptr_dtor(&retval);
     355             :                                 }
     356          26 :                                 return;
     357             :                         }
     358             : #endif
     359             :                 }
     360             :                 default:
     361       27391 :                         RETURN_LONG(1);
     362             :                         break;
     363             :         }
     364             : }
     365             : /* }}} */
     366             : 
     367             : /* Numbers are always smaller than strings int this function as it
     368             :  * anyway doesn't make much sense to compare two different data types.
     369             :  * This keeps it consistent and simple.
     370             :  *
     371             :  * This is not correct any more, depends on what compare_func is set to.
     372             :  */
     373      241070 : static int php_array_data_compare(const void *a, const void *b) /* {{{ */
     374             : {
     375             :         Bucket *f;
     376             :         Bucket *s;
     377             :         zval result;
     378             :         zval *first;
     379             :         zval *second;
     380             : 
     381      241070 :         f = (Bucket *) a;
     382      241070 :         s = (Bucket *) b;
     383             : 
     384      241070 :         first = &f->val;
     385      241070 :         second = &s->val;
     386             : 
     387      241070 :         if (Z_TYPE_P(first) == IS_INDIRECT) {
     388           7 :                 first = Z_INDIRECT_P(first);
     389             :         }
     390      241070 :         if (Z_TYPE_P(second) == IS_INDIRECT) {
     391           9 :                 second = Z_INDIRECT_P(second);
     392             :         }
     393      241070 :         if (ARRAYG(compare_func)(&result, first, second) == FAILURE) {
     394           0 :                 return 0;
     395             :         }
     396             : 
     397      241070 :         if (EXPECTED(Z_TYPE(result) == IS_LONG)) {
     398      241070 :                 return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
     399           0 :         } else if (Z_TYPE(result) == IS_DOUBLE) {
     400           0 :                 return ZEND_NORMALIZE_BOOL(Z_DVAL(result));
     401             :         }
     402             : 
     403           0 :         return ZEND_NORMALIZE_BOOL(zval_get_long(&result));
     404             : }
     405             : /* }}} */
     406             : 
     407        1803 : static int php_array_reverse_data_compare(const void *a, const void *b) /* {{{ */
     408             : {
     409        1803 :         return php_array_data_compare(a, b) * -1;
     410             : }
     411             : /* }}} */
     412             : 
     413         396 : static int php_array_natural_general_compare(const void *a, const void *b, int fold_case) /* {{{ */
     414             : {
     415         396 :         Bucket *f = (Bucket *) a;
     416         396 :         Bucket *s = (Bucket *) b;
     417         792 :         zend_string *str1 = zval_get_string(&f->val);
     418         792 :         zend_string *str2 = zval_get_string(&s->val);
     419             : 
     420         396 :         int result = strnatcmp_ex(str1->val, str1->len, str2->val, str2->len, fold_case);
     421             : 
     422             :         zend_string_release(str1);
     423             :         zend_string_release(str2);
     424         396 :         return result;
     425             : }
     426             : /* }}} */
     427             : 
     428          66 : static int php_array_natural_compare(const void *a, const void *b) /* {{{ */
     429             : {
     430          66 :         return php_array_natural_general_compare(a, b, 0);
     431             : }
     432             : /* }}} */
     433             : 
     434         330 : static int php_array_natural_case_compare(const void *a, const void *b) /* {{{ */
     435             : {
     436         330 :         return php_array_natural_general_compare(a, b, 1);
     437             : }
     438             : /* }}} */
     439             : 
     440          73 : static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
     441             : {
     442             :         zval *array;
     443             : 
     444          73 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &array) == FAILURE) {
     445          26 :                 return;
     446             :         }
     447             : 
     448          47 :         if (fold_case) {
     449          42 :                 if (zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0) == FAILURE) {
     450           0 :                         return;
     451             :                 }
     452             :         } else {
     453           5 :                 if (zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0) == FAILURE) {
     454           0 :                         return;
     455             :                 }
     456             :         }
     457             : 
     458          47 :         RETURN_TRUE;
     459             : }
     460             : /* }}} */
     461             : 
     462             : /* {{{ proto void natsort(array &array_arg)
     463             :    Sort an array using natural sort */
     464           5 : PHP_FUNCTION(natsort)
     465             : {
     466           5 :         php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
     467           5 : }
     468             : /* }}} */
     469             : 
     470             : /* {{{ proto void natcasesort(array &array_arg)
     471             :    Sort an array using case-insensitive natural sort */
     472          68 : PHP_FUNCTION(natcasesort)
     473             : {
     474          68 :         php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     475          68 : }
     476             : /* }}} */
     477             : 
     478             : /* {{{ proto bool asort(array &array_arg [, int sort_flags])
     479             :    Sort an array and maintain index association */
     480         245 : PHP_FUNCTION(asort)
     481             : {
     482             :         zval *array;
     483         245 :         zend_long sort_type = PHP_SORT_REGULAR;
     484             : 
     485         245 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     486         105 :                 RETURN_FALSE;
     487             :         }
     488             : 
     489         140 :         php_set_compare_func(sort_type);
     490             : 
     491         140 :         if (zend_hash_sort(Z_ARRVAL_P(array), php_array_data_compare, 0) == FAILURE) {
     492           0 :                 RETURN_FALSE;
     493             :         }
     494         140 :         RETURN_TRUE;
     495             : }
     496             : /* }}} */
     497             : 
     498             : /* {{{ proto bool arsort(array &array_arg [, int sort_flags])
     499             :    Sort an array in reverse order and maintain index association */
     500         184 : PHP_FUNCTION(arsort)
     501             : {
     502             :         zval *array;
     503         184 :         zend_long sort_type = PHP_SORT_REGULAR;
     504             : 
     505         184 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     506         104 :                 RETURN_FALSE;
     507             :         }
     508             : 
     509          80 :         php_set_compare_func(sort_type);
     510             : 
     511          80 :         if (zend_hash_sort(Z_ARRVAL_P(array), php_array_reverse_data_compare, 0) == FAILURE) {
     512           0 :                 RETURN_FALSE;
     513             :         }
     514          80 :         RETURN_TRUE;
     515             : }
     516             : /* }}} */
     517             : 
     518             : /* {{{ proto bool sort(array &array_arg [, int sort_flags])
     519             :    Sort an array */
     520         236 : PHP_FUNCTION(sort)
     521             : {
     522             :         zval *array;
     523         236 :         zend_long sort_type = PHP_SORT_REGULAR;
     524             : 
     525         236 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     526         104 :                 RETURN_FALSE;
     527             :         }
     528             : 
     529         132 :         php_set_compare_func(sort_type);
     530             : 
     531         132 :         if (zend_hash_sort(Z_ARRVAL_P(array), php_array_data_compare, 1) == FAILURE) {
     532           0 :                 RETURN_FALSE;
     533             :         }
     534         132 :         RETURN_TRUE;
     535             : }
     536             : /* }}} */
     537             : 
     538             : /* {{{ proto bool rsort(array &array_arg [, int sort_flags])
     539             :    Sort an array in reverse order */
     540         182 : PHP_FUNCTION(rsort)
     541             : {
     542             :         zval *array;
     543         182 :         zend_long sort_type = PHP_SORT_REGULAR;
     544             : 
     545         182 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     546         105 :                 RETURN_FALSE;
     547             :         }
     548             : 
     549          77 :         php_set_compare_func(sort_type);
     550             : 
     551          77 :         if (zend_hash_sort(Z_ARRVAL_P(array), php_array_reverse_data_compare, 1) == FAILURE) {
     552           0 :                 RETURN_FALSE;
     553             :         }
     554          77 :         RETURN_TRUE;
     555             : }
     556             : /* }}} */
     557             : 
     558      188468 : static int php_array_user_compare(const void *a, const void *b) /* {{{ */
     559             : {
     560             :         Bucket *f;
     561             :         Bucket *s;
     562             :         zval args[2];
     563             :         zval retval;
     564             : 
     565      188468 :         f = (Bucket *) a;
     566      188468 :         s = (Bucket *) b;
     567             : 
     568      188468 :         ZVAL_COPY(&args[0], &f->val);
     569      188468 :         ZVAL_COPY(&args[1], &s->val);
     570             : 
     571      188468 :         BG(user_compare_fci).param_count = 2;
     572      188468 :         BG(user_compare_fci).params = args;
     573      188468 :         BG(user_compare_fci).retval = &retval;
     574      188468 :         BG(user_compare_fci).no_separation = 0;
     575      376936 :         if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
     576      188468 :                 zend_long ret = zval_get_long(&retval);
     577      188468 :                 zval_ptr_dtor(&retval);
     578      188468 :                 zval_ptr_dtor(&args[1]);
     579      188468 :                 zval_ptr_dtor(&args[0]);
     580      188468 :                 return ret < 0 ? -1 : ret > 0 ? 1 : 0;
     581             :         } else {
     582           0 :                 zval_ptr_dtor(&args[1]);
     583           0 :                 zval_ptr_dtor(&args[0]);
     584           0 :                 return 0;
     585             :         }
     586             : }
     587             : /* }}} */
     588             : 
     589             : /* check if comparison function is valid */
     590             : #define PHP_ARRAY_CMP_FUNC_CHECK(func_name)     \
     591             :         if (!zend_is_callable(*func_name, 0, NULL)) {   \
     592             :                 php_error_docref(NULL, E_WARNING, "Invalid comparison function");     \
     593             :                 BG(user_compare_fci) = old_user_compare_fci; \
     594             :                 BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
     595             :                 RETURN_FALSE;   \
     596             :         }       \
     597             : 
     598             :         /* Clear FCI cache otherwise : for example the same or other array with
     599             :          * (partly) the same key values has been sorted with uasort() or
     600             :          * other sorting function the comparison is cached, however the name
     601             :          * of the function for comparison is not respected. see bug #28739 AND #33295
     602             :          *
     603             :          * Following defines will assist in backup / restore values. */
     604             : 
     605             : #define PHP_ARRAY_CMP_FUNC_VARS \
     606             :         zend_fcall_info old_user_compare_fci; \
     607             :         zend_fcall_info_cache old_user_compare_fci_cache \
     608             : 
     609             : #define PHP_ARRAY_CMP_FUNC_BACKUP() \
     610             :         old_user_compare_fci = BG(user_compare_fci); \
     611             :         old_user_compare_fci_cache = BG(user_compare_fci_cache); \
     612             :         BG(user_compare_fci_cache) = empty_fcall_info_cache; \
     613             : 
     614             : #define PHP_ARRAY_CMP_FUNC_RESTORE() \
     615             :         BG(user_compare_fci) = old_user_compare_fci; \
     616             :         BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
     617             : 
     618             : /* {{{ proto bool usort(array array_arg, string cmp_function)
     619             :    Sort an array by values using a user-defined comparison function */
     620         104 : PHP_FUNCTION(usort)
     621             : {
     622             :         zval *array;
     623             :         zend_refcounted *arr;
     624             :         unsigned int refcount;
     625             :         PHP_ARRAY_CMP_FUNC_VARS;
     626             : 
     627         104 :         PHP_ARRAY_CMP_FUNC_BACKUP();
     628             : 
     629         104 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/f", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
     630          58 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     631          58 :                 return;
     632             :         }
     633             : 
     634             :         /* Increase reference counter, so the attempts to modify the array in user
     635             :          * comparison function will create a copy of array and won't affect the
     636             :          * original array. The fact of modification is detected using refcount
     637             :          * comparison. The result of sorting in such case is undefined and the
     638             :          * function returns FALSE.
     639             :          */
     640          46 :         Z_ADDREF_P(array);
     641          92 :         refcount = Z_REFCOUNT_P(array);
     642          46 :         arr = Z_COUNTED_P(array);
     643             : 
     644          46 :         if (zend_hash_sort(Z_ARRVAL_P(array), php_array_user_compare, 1) == FAILURE) {
     645           0 :                 RETVAL_FALSE;
     646             :         } else {
     647          92 :                 if (refcount > Z_REFCOUNT_P(array)) {
     648           1 :                         php_error_docref(NULL, E_WARNING, "Array was modified by the user comparison function");
     649           1 :                         if (--GC_REFCOUNT(arr) <= 0) {
     650           1 :                                 _zval_dtor_func(arr ZEND_FILE_LINE_CC);
     651             :                         }
     652           1 :                         RETVAL_FALSE;
     653             :                 } else {
     654          45 :                         Z_DELREF_P(array);
     655          45 :                         RETVAL_TRUE;
     656             :                 }
     657             :         }
     658             : 
     659          46 :         PHP_ARRAY_CMP_FUNC_RESTORE();
     660             : }
     661             : /* }}} */
     662             : 
     663             : /* {{{ proto bool uasort(array array_arg, string cmp_function)
     664             :    Sort an array with a user-defined comparison function and maintain index association */
     665          94 : PHP_FUNCTION(uasort)
     666             : {
     667             :         zval *array;
     668             :         zend_refcounted *arr;
     669             :         unsigned int refcount;
     670             :         PHP_ARRAY_CMP_FUNC_VARS;
     671             : 
     672          94 :         PHP_ARRAY_CMP_FUNC_BACKUP();
     673             : 
     674          94 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/f", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
     675          57 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     676          57 :                 return;
     677             :         }
     678             : 
     679             :         /* Increase reference counter, so the attempts to modify the array in user
     680             :          * comparison function will create a copy of array and won't affect the
     681             :          * original array. The fact of modification is detected using refcount
     682             :          * comparison. The result of sorting in such case is undefined and the
     683             :          * function returns FALSE.
     684             :          */
     685          37 :         Z_ADDREF_P(array);
     686          74 :         refcount = Z_REFCOUNT_P(array);
     687          37 :         arr = Z_COUNTED_P(array);
     688             : 
     689          37 :         if (zend_hash_sort(Z_ARRVAL_P(array), php_array_user_compare, 0) == FAILURE) {
     690           0 :                 RETVAL_FALSE;
     691             :         } else {
     692          74 :                 if (refcount > Z_REFCOUNT_P(array)) {
     693           0 :                         php_error_docref(NULL, E_WARNING, "Array was modified by the user comparison function");
     694           0 :                         if (--GC_REFCOUNT(arr) <= 0) {
     695           0 :                                 _zval_dtor_func(arr ZEND_FILE_LINE_CC);
     696             :                         }
     697           0 :                         RETVAL_FALSE;
     698             :                 } else {
     699          37 :                         Z_DELREF_P(array);
     700          37 :                         RETVAL_TRUE;
     701             :                 }
     702             :         }
     703             : 
     704          37 :         PHP_ARRAY_CMP_FUNC_RESTORE();
     705             : }
     706             : /* }}} */
     707             : 
     708        5090 : static int php_array_user_key_compare(const void *a, const void *b) /* {{{ */
     709             : {
     710             :         Bucket *f;
     711             :         Bucket *s;
     712             :         zval args[2];
     713             :         zval retval;
     714             :         zend_long result;
     715             : 
     716        5090 :         ZVAL_NULL(&args[0]);
     717        5090 :         ZVAL_NULL(&args[1]);
     718             : 
     719        5090 :         f = (Bucket *) a;
     720        5090 :         s = (Bucket *) b;
     721             : 
     722        5090 :         if (f->key == NULL) {
     723        1804 :                 ZVAL_LONG(&args[0], f->h);
     724             :         } else {
     725        3286 :                 ZVAL_STR_COPY(&args[0], f->key);
     726             :         }
     727        5090 :         if (s->key == NULL) {
     728        2031 :                 ZVAL_LONG(&args[1], s->h);
     729             :         } else {
     730        3059 :                 ZVAL_STR_COPY(&args[1], s->key);
     731             :         }
     732             : 
     733        5090 :         BG(user_compare_fci).param_count = 2;
     734        5090 :         BG(user_compare_fci).params = args;
     735        5090 :         BG(user_compare_fci).retval = &retval;
     736        5090 :         BG(user_compare_fci).no_separation = 0;
     737       15270 :         if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
     738        5090 :                 result = zval_get_long(&retval);
     739        5090 :                 zval_ptr_dtor(&retval);
     740             :         } else {
     741           0 :                 result = 0;
     742             :         }
     743             : 
     744        5090 :         zval_ptr_dtor(&args[0]);
     745        5090 :         zval_ptr_dtor(&args[1]);
     746             : 
     747        5090 :         return result < 0 ? -1 : result > 0 ? 1 : 0;
     748             : }
     749             : /* }}} */
     750             : 
     751             : /* {{{ proto bool uksort(array array_arg, string cmp_function)
     752             :    Sort an array by keys using a user-defined comparison function */
     753          62 : PHP_FUNCTION(uksort)
     754             : {
     755             :         zval *array;
     756             :         zend_refcounted *arr;
     757             :         unsigned int refcount;
     758             :         PHP_ARRAY_CMP_FUNC_VARS;
     759             : 
     760          62 :         PHP_ARRAY_CMP_FUNC_BACKUP();
     761             : 
     762          62 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/f", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
     763          53 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     764          53 :                 return;
     765             :         }
     766             : 
     767             :         /* Increase reference counter, so the attempts to modify the array in user
     768             :          * comparison function will create a copy of array and won't affect the
     769             :          * original array. The fact of modification is detected using refcount
     770             :          * comparison. The result of sorting in such case is undefined and the
     771             :          * function returns FALSE.
     772             :          */
     773           9 :         Z_ADDREF_P(array);
     774          18 :         refcount = Z_REFCOUNT_P(array);
     775           9 :         arr = Z_COUNTED_P(array);
     776             : 
     777           9 :         if (zend_hash_sort(Z_ARRVAL_P(array), php_array_user_key_compare, 0) == FAILURE) {
     778           0 :                 RETVAL_FALSE;
     779             :         } else {
     780          18 :                 if (refcount > Z_REFCOUNT_P(array)) {
     781           0 :                         php_error_docref(NULL, E_WARNING, "Array was modified by the user comparison function");
     782           0 :                         if (--GC_REFCOUNT(arr) <= 0) {
     783           0 :                                 _zval_dtor_func(arr ZEND_FILE_LINE_CC);
     784             :                         }
     785           0 :                         RETVAL_FALSE;
     786             :                 } else {
     787           9 :                         Z_DELREF_P(array);
     788           9 :                         RETVAL_TRUE;
     789             :                 }
     790             :         }
     791             : 
     792           9 :         PHP_ARRAY_CMP_FUNC_RESTORE();
     793             : }
     794             : /* }}} */
     795             : 
     796             : /* {{{ proto mixed end(array array_arg)
     797             :    Advances array argument's internal pointer to the last element and return it */
     798          76 : PHP_FUNCTION(end)
     799             : {
     800             :         HashTable *array;
     801             :         zval *entry;
     802             : 
     803             : #ifndef FAST_ZPP
     804             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "H/", &array) == FAILURE) {
     805             :                 return;
     806             :         }
     807             : #else
     808          76 :         ZEND_PARSE_PARAMETERS_START(1, 1)
     809         281 :                 Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
     810          76 :         ZEND_PARSE_PARAMETERS_END();
     811             : #endif
     812             : 
     813          47 :         zend_hash_internal_pointer_end(array);
     814             : 
     815          47 :         if (USED_RET()) {
     816          34 :                 if ((entry = zend_hash_get_current_data(array)) == NULL) {
     817           2 :                         RETURN_FALSE;
     818             :                 }
     819             : 
     820          32 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
     821           1 :                         entry = Z_INDIRECT_P(entry);
     822             :                 }
     823             : 
     824          96 :                 RETURN_ZVAL_FAST(entry);
     825             :         }
     826             : }
     827             : /* }}} */
     828             : 
     829             : /* {{{ proto mixed prev(array array_arg)
     830             :    Move array argument's internal pointer to the previous element and return it */
     831          46 : PHP_FUNCTION(prev)
     832             : {
     833             :         HashTable *array;
     834             :         zval *entry;
     835             : 
     836             : #ifndef FAST_ZPP
     837             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "H/", &array) == FAILURE) {
     838             :                 return;
     839             :         }
     840             : #else
     841          46 :         ZEND_PARSE_PARAMETERS_START(1, 1)
     842         154 :                 Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
     843          46 :         ZEND_PARSE_PARAMETERS_END();
     844             : #endif
     845             : 
     846          21 :         zend_hash_move_backwards(array);
     847             : 
     848          21 :         if (USED_RET()) {
     849          19 :                 if ((entry = zend_hash_get_current_data(array)) == NULL) {
     850           6 :                         RETURN_FALSE;
     851             :                 }
     852             : 
     853          13 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
     854           0 :                         entry = Z_INDIRECT_P(entry);
     855             :                 }
     856             : 
     857          39 :                 RETURN_ZVAL_FAST(entry);
     858             :         }
     859             : }
     860             : /* }}} */
     861             : 
     862             : /* {{{ proto mixed next(array array_arg)
     863             :    Move array argument's internal pointer to the next element and return it */
     864        1225 : PHP_FUNCTION(next)
     865             : {
     866             :         HashTable *array;
     867             :         zval *entry;
     868             : 
     869             : #ifndef FAST_ZPP
     870             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "H/", &array) == FAILURE) {
     871             :                 return;
     872             :         }
     873             : #else
     874        1225 :         ZEND_PARSE_PARAMETERS_START(1, 1)
     875        4889 :                 Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
     876        1225 :         ZEND_PARSE_PARAMETERS_END();
     877             : #endif
     878             : 
     879        1194 :         zend_hash_move_forward(array);
     880             : 
     881        1194 :         if (USED_RET()) {
     882        1147 :                 if ((entry = zend_hash_get_current_data(array)) == NULL) {
     883         291 :                         RETURN_FALSE;
     884             :                 }
     885             : 
     886         856 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
     887           0 :                         entry = Z_INDIRECT_P(entry);
     888             :                 }
     889             : 
     890        2568 :                 RETURN_ZVAL_FAST(entry);
     891             :         }
     892             : }
     893             : /* }}} */
     894             : 
     895             : /* {{{ proto mixed reset(array array_arg)
     896             :    Set array argument's internal pointer to the first element and return it */
     897         412 : PHP_FUNCTION(reset)
     898             : {
     899             :         HashTable *array;
     900             :         zval *entry;
     901             : 
     902             : #ifndef FAST_ZPP
     903             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "H/", &array) == FAILURE) {
     904             :                 return;
     905             :         }
     906             : #else
     907         412 :         ZEND_PARSE_PARAMETERS_START(1, 1)
     908        1627 :                 Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
     909         412 :         ZEND_PARSE_PARAMETERS_END();
     910             : #endif
     911             : 
     912         381 :         zend_hash_internal_pointer_reset(array);
     913             : 
     914         381 :         if (USED_RET()) {
     915          69 :                 if ((entry = zend_hash_get_current_data(array)) == NULL) {
     916           3 :                         RETURN_FALSE;
     917             :                 }
     918             : 
     919          66 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
     920           0 :                         entry = Z_INDIRECT_P(entry);
     921             :                 }
     922             : 
     923         198 :                 RETURN_ZVAL_FAST(entry);
     924             :         }
     925             : }
     926             : /* }}} */
     927             : 
     928             : /* {{{ proto mixed current(array array_arg)
     929             :    Return the element currently pointed to by the internal array pointer */
     930        1366 : PHP_FUNCTION(current)
     931             : {
     932             :         HashTable *array;
     933             :         zval *entry;
     934             : 
     935             : #ifndef FAST_ZPP
     936             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "H", &array) == FAILURE) {
     937             :                 return;
     938             :         }
     939             : #else
     940        1366 :         ZEND_PARSE_PARAMETERS_START(1, 1)
     941        4086 :                 Z_PARAM_ARRAY_OR_OBJECT_HT(array)
     942        1366 :         ZEND_PARSE_PARAMETERS_END();
     943             : #endif
     944             : 
     945        1335 :         if ((entry = zend_hash_get_current_data(array)) == NULL) {
     946          23 :                 RETURN_FALSE;
     947             :         }
     948             : 
     949        1312 :         if (Z_TYPE_P(entry) == IS_INDIRECT) {
     950           1 :                 entry = Z_INDIRECT_P(entry);
     951             :         }
     952             : 
     953        3936 :         RETURN_ZVAL_FAST(entry);
     954             : }
     955             : /* }}} */
     956             : 
     957             : /* {{{ proto mixed key(array array_arg)
     958             :    Return the key of the element currently pointed to by the internal array pointer */
     959        1324 : PHP_FUNCTION(key)
     960             : {
     961             :         HashTable *array;
     962             : 
     963             : #ifndef FAST_ZPP
     964             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "H", &array) == FAILURE) {
     965             :                 return;
     966             :         }
     967             : #else
     968        1324 :         ZEND_PARSE_PARAMETERS_START(1, 1)
     969        3960 :                 Z_PARAM_ARRAY_OR_OBJECT_HT(array)
     970        1324 :         ZEND_PARSE_PARAMETERS_END();
     971             : #endif
     972             : 
     973        1293 :         zend_hash_get_current_key_zval(array, return_value);
     974             : }
     975             : /* }}} */
     976             : 
     977             : /* {{{ proto mixed min(mixed arg1 [, mixed arg2 [, mixed ...]])
     978             :    Return the lowest value in an array or a series of arguments */
     979         667 : PHP_FUNCTION(min)
     980             : {
     981             :         int argc;
     982         667 :         zval *args = NULL;
     983             : 
     984         667 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
     985           2 :                 return;
     986             :         }
     987             : 
     988         665 :         php_set_compare_func(PHP_SORT_REGULAR);
     989             : 
     990             :         /* mixed min ( array $values ) */
     991         665 :         if (argc == 1) {
     992             :                 zval *result;
     993             : 
     994          46 :                 if (Z_TYPE(args[0]) != IS_ARRAY) {
     995           4 :                         php_error_docref(NULL, E_WARNING, "When only one parameter is given, it must be an array");
     996           4 :                         RETVAL_NULL();
     997             :                 } else {
     998          19 :                         if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 0)) != NULL) {
     999          51 :                                 RETVAL_ZVAL_FAST(result);
    1000             :                         } else {
    1001           2 :                                 php_error_docref(NULL, E_WARNING, "Array must contain at least one element");
    1002           2 :                                 RETVAL_FALSE;
    1003             :                         }
    1004             :                 }
    1005             :         } else {
    1006             :                 /* mixed min ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
    1007             :                 zval *min, result;
    1008             :                 int i;
    1009             : 
    1010         642 :                 min = &args[0];
    1011             : 
    1012        2535 :                 for (i = 1; i < argc; i++) {
    1013        1893 :                         is_smaller_function(&result, &args[i], min);
    1014        1893 :                         if (Z_TYPE(result) == IS_TRUE) {
    1015         583 :                                 min = &args[i];
    1016             :                         }
    1017             :                 }
    1018             : 
    1019        1926 :                 RETVAL_ZVAL_FAST(min);
    1020             :         }
    1021             : }
    1022             : /* }}} */
    1023             : 
    1024             : /* {{{ proto mixed max(mixed arg1 [, mixed arg2 [, mixed ...]])
    1025             :    Return the highest value in an array or a series of arguments */
    1026          96 : PHP_FUNCTION(max)
    1027             : {
    1028          96 :         zval *args = NULL;
    1029             :         int argc;
    1030             : 
    1031          96 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    1032           2 :                 return;
    1033             :         }
    1034             : 
    1035          94 :         php_set_compare_func(PHP_SORT_REGULAR);
    1036             : 
    1037             :         /* mixed max ( array $values ) */
    1038          94 :         if (argc == 1) {
    1039             :                 zval *result;
    1040             : 
    1041         134 :                 if (Z_TYPE(args[0]) != IS_ARRAY) {
    1042           4 :                         php_error_docref(NULL, E_WARNING, "When only one parameter is given, it must be an array");
    1043           4 :                         RETVAL_NULL();
    1044             :                 } else {
    1045          63 :                         if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 1)) != NULL) {
    1046         183 :                                 RETVAL_ZVAL_FAST(result);
    1047             :                         } else {
    1048           2 :                                 php_error_docref(NULL, E_WARNING, "Array must contain at least one element");
    1049           2 :                                 RETVAL_FALSE;
    1050             :                         }
    1051             :                 }
    1052             :         } else {
    1053             :                 /* mixed max ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
    1054             :                 zval *max, result;
    1055             :                 int i;
    1056             : 
    1057          27 :                 max = &args[0];
    1058             : 
    1059        1305 :                 for (i = 1; i < argc; i++) {
    1060        1278 :                         is_smaller_or_equal_function(&result, &args[i], max);
    1061        1278 :                         if (Z_TYPE(result) == IS_FALSE) {
    1062          43 :                                 max = &args[i];
    1063             :                         }
    1064             :                 }
    1065             : 
    1066          81 :                 RETVAL_ZVAL_FAST(max);
    1067             :         }
    1068             : }
    1069             : /* }}} */
    1070             : 
    1071         258 : static int php_array_walk(HashTable *target_hash, zval *userdata, int recursive) /* {{{ */
    1072             : {
    1073             :         zval args[3],           /* Arguments to userland function */
    1074             :                  retval,                /* Return value - unused */
    1075             :                  *zv;
    1076             : 
    1077             :         /* Set up known arguments */
    1078         258 :         ZVAL_UNDEF(&retval);
    1079         258 :         ZVAL_UNDEF(&args[1]);
    1080         258 :         if (userdata) {
    1081         151 :                 ZVAL_COPY(&args[2], userdata);
    1082             :         }
    1083             : 
    1084         258 :         BG(array_walk_fci).retval = &retval;
    1085         258 :         BG(array_walk_fci).param_count = userdata ? 3 : 2;
    1086         258 :         BG(array_walk_fci).params = args;
    1087         258 :         BG(array_walk_fci).no_separation = 0;
    1088             : 
    1089             :         /* Iterate through hash */
    1090         258 :         zend_hash_internal_pointer_reset(target_hash);
    1091        1392 :         while (!EG(exception) && (zv = zend_hash_get_current_data(target_hash)) != NULL) {
    1092         877 :                 if (Z_TYPE_P(zv) == IS_INDIRECT) {
    1093          12 :                         zv = Z_INDIRECT_P(zv);
    1094          12 :                         if (Z_TYPE_P(zv) == IS_UNDEF) {
    1095           0 :                                 zend_hash_move_forward(target_hash);
    1096           0 :                                 continue;
    1097             :                         }
    1098             :                 }
    1099        1753 :                 if (recursive &&
    1100             :                     (Z_TYPE_P(zv) == IS_ARRAY ||
    1101           8 :                      (Z_ISREF_P(zv) && Z_TYPE_P(Z_REFVAL_P(zv)) == IS_ARRAY))) {
    1102             :                         HashTable *thash;
    1103             :                         zend_fcall_info orig_array_walk_fci;
    1104             :                         zend_fcall_info_cache orig_array_walk_fci_cache;
    1105             : 
    1106         110 :                         if (Z_ISREF_P(zv)) {
    1107           0 :                                 thash = Z_ARRVAL_P(Z_REFVAL_P(zv));
    1108             :                         } else {
    1109         300 :                                 SEPARATE_ZVAL(zv);
    1110         110 :                                 thash = Z_ARRVAL_P(zv);
    1111             :                         }
    1112         110 :                         if (thash->u.v.nApplyCount > 1) {
    1113           0 :                                 php_error_docref(NULL, E_WARNING, "recursion detected");
    1114           0 :                                 if (userdata) {
    1115           0 :                                         zval_ptr_dtor(&args[2]);
    1116             :                                 }
    1117           0 :                                 return 0;
    1118             :                         }
    1119             : 
    1120             :                         /* backup the fcall info and cache */
    1121         110 :                         orig_array_walk_fci = BG(array_walk_fci);
    1122         110 :                         orig_array_walk_fci_cache = BG(array_walk_fci_cache);
    1123             : 
    1124         110 :                         thash->u.v.nApplyCount++;
    1125         110 :                         php_array_walk(thash, userdata, recursive);
    1126         110 :                         thash->u.v.nApplyCount--;
    1127             : 
    1128             :                         /* restore the fcall info and cache */
    1129         110 :                         BG(array_walk_fci) = orig_array_walk_fci;
    1130         110 :                         BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1131             :                 } else {
    1132         767 :                         int was_ref = Z_ISREF_P(zv);
    1133             : 
    1134         767 :                         ZVAL_COPY(&args[0], zv);
    1135             : 
    1136             :                         /* Allocate space for key */
    1137         767 :                         zend_hash_get_current_key_zval(target_hash, &args[1]);
    1138             : 
    1139             :                         /* Call the userland function */
    1140         767 :                         if (zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache)) == SUCCESS) {
    1141        1531 :                                 if (!was_ref && Z_ISREF(args[0])) {
    1142             :                                         /* copy reference back */
    1143             :                                         zval garbage;
    1144             : 
    1145          20 :                                         ZVAL_COPY_VALUE(&garbage, zv);
    1146          20 :                                         ZVAL_COPY_VALUE(zv, &args[0]);
    1147          20 :                                         zval_ptr_dtor(&garbage);
    1148             :                                 } else {
    1149         746 :                                         zval_ptr_dtor(&args[0]);
    1150             :                                 }
    1151         766 :                                 zval_ptr_dtor(&retval);
    1152             :                         } else {
    1153           0 :                                 zval_ptr_dtor(&args[0]);
    1154           0 :                                 if (Z_TYPE(args[1]) != IS_UNDEF) {
    1155           0 :                                         zval_ptr_dtor(&args[1]);
    1156           0 :                                         ZVAL_UNDEF(&args[1]);
    1157             :                                 }
    1158           0 :                                 break;
    1159             :                         }
    1160             :                 }
    1161             : 
    1162         876 :                 if (Z_TYPE(args[1]) != IS_UNDEF) {
    1163         766 :                         zval_ptr_dtor(&args[1]);
    1164         766 :                         ZVAL_UNDEF(&args[1]);
    1165             :                 }
    1166         876 :                 zend_hash_move_forward(target_hash);
    1167             :         }
    1168             : 
    1169         257 :         if (userdata) {
    1170         150 :                 zval_ptr_dtor(&args[2]);
    1171             :         }
    1172         257 :         return 0;
    1173             : }
    1174             : /* }}} */
    1175             : 
    1176             : /* {{{ proto bool array_walk(array input, string funcname [, mixed userdata])
    1177             :    Apply a user function to every member of an array */
    1178         207 : PHP_FUNCTION(array_walk)
    1179             : {
    1180             :         HashTable *array;
    1181         207 :         zval *userdata = NULL;
    1182             :         zend_fcall_info orig_array_walk_fci;
    1183             :         zend_fcall_info_cache orig_array_walk_fci_cache;
    1184             : 
    1185         207 :         orig_array_walk_fci = BG(array_walk_fci);
    1186         207 :         orig_array_walk_fci_cache = BG(array_walk_fci_cache);
    1187             : 
    1188             : #ifndef FAST_ZPP
    1189             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "H/f|z/", &array, &BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
    1190             :                 BG(array_walk_fci) = orig_array_walk_fci;
    1191             :                 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1192             :                 return;
    1193             :         }
    1194             : #else
    1195         207 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1196         798 :                 Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
    1197         459 :                 Z_PARAM_FUNC(BG(array_walk_fci), BG(array_walk_fci_cache))
    1198          99 :                 Z_PARAM_OPTIONAL
    1199         208 :                 Z_PARAM_ZVAL_EX(userdata, 0, 1)
    1200         207 :         ZEND_PARSE_PARAMETERS_END_EX(
    1201             :                 BG(array_walk_fci) = orig_array_walk_fci;
    1202             :                 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1203             :                 return
    1204             :         );
    1205             : #endif
    1206             : 
    1207          99 :         php_array_walk(array, userdata, 0);
    1208          98 :         BG(array_walk_fci) = orig_array_walk_fci;
    1209          98 :         BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1210          98 :         RETURN_TRUE;
    1211             : }
    1212             : /* }}} */
    1213             : 
    1214             : /* {{{ proto bool array_walk_recursive(array input, string funcname [, mixed userdata])
    1215             :    Apply a user function recursively to every member of an array */
    1216         153 : PHP_FUNCTION(array_walk_recursive)
    1217             : {
    1218             :         HashTable *array;
    1219         153 :         zval *userdata = NULL;
    1220             :         zend_fcall_info orig_array_walk_fci;
    1221             :         zend_fcall_info_cache orig_array_walk_fci_cache;
    1222             : 
    1223         153 :         orig_array_walk_fci = BG(array_walk_fci);
    1224         153 :         orig_array_walk_fci_cache = BG(array_walk_fci_cache);
    1225             : 
    1226         153 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "H/f|z/", &array, &BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
    1227         104 :                 BG(array_walk_fci) = orig_array_walk_fci;
    1228         104 :                 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1229         104 :                 return;
    1230             :         }
    1231             : 
    1232          49 :         php_array_walk(array, userdata, 1);
    1233          49 :         BG(array_walk_fci) = orig_array_walk_fci;
    1234          49 :         BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1235          49 :         RETURN_TRUE;
    1236             : }
    1237             : /* }}} */
    1238             : 
    1239             : /* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
    1240             :  * 0 = return boolean
    1241             :  * 1 = return key
    1242             :  */
    1243        6635 : static inline void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
    1244             : {
    1245             :         zval *value,                            /* value to check for */
    1246             :                  *array,                                /* array to check in */
    1247             :                  *entry;                                /* pointer to array entry */
    1248             :         zend_ulong num_idx;
    1249             :         zend_string *str_idx;
    1250        6635 :         zend_bool strict = 0;           /* strict comparison or not */
    1251             : 
    1252             : #ifndef FAST_ZPP
    1253             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "za|b", &value, &array, &strict) == FAILURE) {
    1254             :                 return;
    1255             :         }
    1256             : #else
    1257        6635 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1258        6628 :                 Z_PARAM_ZVAL(value)
    1259       19884 :                 Z_PARAM_ARRAY(array)
    1260        6619 :                 Z_PARAM_OPTIONAL
    1261        7897 :                 Z_PARAM_BOOL(strict)
    1262        6635 :         ZEND_PARSE_PARAMETERS_END();
    1263             : #endif
    1264             : 
    1265        6619 :         if (strict) {
    1266        2814 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1267        1262 :                         ZVAL_DEREF(entry);
    1268        2524 :                         if (fast_is_identical_function(value, entry)) {
    1269          36 :                                 if (behavior == 0) {
    1270          18 :                                         RETURN_TRUE;
    1271             :                                 } else {
    1272          18 :                                         if (str_idx) {
    1273           4 :                                                 RETVAL_STR_COPY(str_idx);
    1274             :                                         } else {
    1275          14 :                                                 RETVAL_LONG(num_idx);
    1276             :                                         }
    1277          18 :                                         return;
    1278             :                                 }
    1279             :                         }
    1280             :                 } ZEND_HASH_FOREACH_END();
    1281             :         } else {
    1282       12586 :                 ZVAL_DEREF(value);
    1283       12586 :                 if (Z_TYPE_P(value) == IS_LONG) {
    1284       17285 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1285       16126 :                                 if (fast_equal_check_long(value, entry)) {
    1286          79 :                                         if (behavior == 0) {
    1287          44 :                                                 RETURN_TRUE;
    1288             :                                         } else {
    1289          35 :                                                 if (str_idx) {
    1290           5 :                                                         RETVAL_STR_COPY(str_idx);
    1291             :                                                 } else {
    1292          30 :                                                         RETVAL_LONG(num_idx);
    1293             :                                                 }
    1294          35 :                                                 return;
    1295             :                                         }
    1296             :                                 }
    1297             :                         } ZEND_HASH_FOREACH_END();
    1298       10110 :                 } else if (Z_TYPE_P(value) == IS_STRING) {
    1299      956219 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1300      955016 :                                 if (fast_equal_check_string(value, entry)) {
    1301        2688 :                                         if (behavior == 0) {
    1302        2614 :                                                 RETURN_TRUE;
    1303             :                                         } else {
    1304          74 :                                                 if (str_idx) {
    1305           8 :                                                         RETVAL_STR_COPY(str_idx);
    1306             :                                                 } else {
    1307          66 :                                                         RETVAL_LONG(num_idx);
    1308             :                                                 }
    1309          74 :                                                 return;
    1310             :                                         }
    1311             :                                 }
    1312             :                         } ZEND_HASH_FOREACH_END();
    1313             :                 } else {
    1314       28767 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1315       28630 :                                 if (fast_equal_check_function(value, entry)) {
    1316        1045 :                                         if (behavior == 0) {
    1317         983 :                                                 RETURN_TRUE;
    1318             :                                         } else {
    1319          62 :                                                 if (str_idx) {
    1320          12 :                                                         RETVAL_STR_COPY(str_idx);
    1321             :                                                 } else {
    1322          50 :                                                         RETVAL_LONG(num_idx);
    1323             :                                                 }
    1324          62 :                                                 return;
    1325             :                                         }
    1326             :                                 }
    1327             :                         } ZEND_HASH_FOREACH_END();
    1328             :                 }
    1329             :         }
    1330             : 
    1331        2771 :         RETURN_FALSE;
    1332             : }
    1333             : /* }}} */
    1334             : 
    1335             : /* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
    1336             :    Checks if the given value exists in the array */
    1337        6115 : PHP_FUNCTION(in_array)
    1338             : {
    1339        6115 :         php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1340        6115 : }
    1341             : /* }}} */
    1342             : 
    1343             : /* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict])
    1344             :    Searches the array for a given value and returns the corresponding key if successful */
    1345         520 : PHP_FUNCTION(array_search)
    1346             : {
    1347         520 :         php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1348         520 : }
    1349             : /* }}} */
    1350             : 
    1351         428 : static int php_valid_var_name(char *var_name, size_t var_name_len) /* {{{ */
    1352             : {
    1353             :         size_t i;
    1354             :         int ch;
    1355             : 
    1356         428 :         if (!var_name_len) {
    1357           4 :                 return 0;
    1358             :         }
    1359             : 
    1360             :         /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
    1361         424 :         ch = (int)((unsigned char *)var_name)[0];
    1362         424 :         if (var_name[0] != '_' &&
    1363             :                 (ch < 65  /* A    */ || /* Z    */ ch > 90)  &&
    1364             :                 (ch < 97  /* a    */ || /* z    */ ch > 122) &&
    1365             :                 (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
    1366             :         ) {
    1367          15 :                 return 0;
    1368             :         }
    1369             : 
    1370             :         /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
    1371         409 :         if (var_name_len > 1) {
    1372         356 :                 i = 1;
    1373             :                 do {
    1374        1115 :                         ch = (int)((unsigned char *)var_name)[i];
    1375        1115 :                         if (var_name[i] != '_' &&
    1376             :                                 (ch < 48  /* 0    */ || /* 9    */ ch > 57)  &&
    1377             :                                 (ch < 65  /* A    */ || /* Z    */ ch > 90)  &&
    1378             :                                 (ch < 97  /* a    */ || /* z    */ ch > 122) &&
    1379             :                                 (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
    1380             :                         ) {
    1381           6 :                                 return 0;
    1382             :                         }
    1383        1109 :                 } while (++i < var_name_len);
    1384             :         }
    1385         403 :         return 1;
    1386             : }
    1387             : /* }}} */
    1388             : 
    1389         237 : PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, size_t var_name_len, zend_bool add_underscore) /* {{{ */
    1390             : {
    1391         474 :         ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0) + var_name_len, 0));
    1392         237 :         memcpy(Z_STRVAL_P(result), Z_STRVAL_P(prefix), Z_STRLEN_P(prefix));
    1393             : 
    1394         237 :         if (add_underscore) {
    1395         237 :                 Z_STRVAL_P(result)[Z_STRLEN_P(prefix)] = '_';
    1396             :         }
    1397             : 
    1398         237 :         memcpy(Z_STRVAL_P(result) + Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1);
    1399             : 
    1400         237 :         return SUCCESS;
    1401             : }
    1402             : /* }}} */
    1403             : 
    1404             : /* {{{ proto int extract(array var_array [, int extract_type [, string prefix]])
    1405             :    Imports variables into symbol table from an array */
    1406         137 : PHP_FUNCTION(extract)
    1407             : {
    1408         137 :         zval *var_array, *prefix = NULL;
    1409         137 :         zend_long extract_type = EXTR_OVERWRITE;
    1410             :         zval *entry;
    1411             :         zend_string *var_name;
    1412             :         zend_ulong num_key;
    1413         137 :         int var_exists, count = 0;
    1414         137 :         int extract_refs = 0;
    1415             :         zend_array *symbol_table;
    1416             : 
    1417             : #ifndef FAST_ZPP
    1418             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|lz/", &var_array, &extract_type, &prefix) == FAILURE) {
    1419             :                 return;
    1420             :         }
    1421             : #else
    1422         137 :         ZEND_PARSE_PARAMETERS_START(1, 3)
    1423         405 :                 Z_PARAM_ARRAY(var_array)
    1424         133 :                 Z_PARAM_OPTIONAL
    1425         363 :                 Z_PARAM_LONG(extract_type)
    1426         179 :                 Z_PARAM_ZVAL_EX(prefix, 0, 1)
    1427         137 :         ZEND_PARSE_PARAMETERS_END();
    1428             : #endif
    1429             : 
    1430         133 :         extract_refs = (extract_type & EXTR_REFS);
    1431         133 :         if (extract_refs) {
    1432          30 :                 SEPARATE_ZVAL(var_array);
    1433             :         }
    1434         133 :         extract_type &= 0xff;
    1435             : 
    1436         133 :         if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) {
    1437           2 :                 php_error_docref(NULL, E_WARNING, "Invalid extract type");
    1438           2 :                 return;
    1439             :         }
    1440             : 
    1441         131 :         if (extract_type > EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS && ZEND_NUM_ARGS() < 3) {
    1442           1 :                 php_error_docref(NULL, E_WARNING, "specified extract type requires the prefix parameter");
    1443           1 :                 return;
    1444             :         }
    1445             : 
    1446         130 :         if (prefix) {
    1447         126 :                 convert_to_string(prefix);
    1448          63 :                 if (Z_STRLEN_P(prefix) && !php_valid_var_name(Z_STRVAL_P(prefix), Z_STRLEN_P(prefix))) {
    1449           0 :                         php_error_docref(NULL, E_WARNING, "prefix is not a valid identifier");
    1450           0 :                         return;
    1451             :                 }
    1452             :         }
    1453             : 
    1454         130 :         symbol_table = zend_rebuild_symbol_table();
    1455             : #if 0
    1456             :         if (!symbol_table) {
    1457             :                 php_error_docref(NULL, E_WARNING, "failed to build symbol table");
    1458             :                 return;
    1459             :         }
    1460             : #endif
    1461             : 
    1462        2284 :         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(var_array), num_key, var_name, entry) {
    1463             :                 zval final_name;
    1464             : 
    1465         699 :                 ZVAL_NULL(&final_name);
    1466         699 :                 var_exists = 0;
    1467             : 
    1468         699 :                 if (var_name) {
    1469         219 :                         var_exists = zend_hash_exists_ind(symbol_table, var_name);
    1470         651 :                 } else if (extract_type == EXTR_PREFIX_ALL || extract_type == EXTR_PREFIX_INVALID) {
    1471         171 :                         zend_string *str = zend_long_to_str(num_key);
    1472         171 :                         php_prefix_varname(&final_name, prefix, str->val, str->len, 1);
    1473             :                         zend_string_release(str);
    1474             :                 } else {
    1475         309 :                         continue;
    1476             :                 }
    1477             : 
    1478         390 :                 switch (extract_type) {
    1479             :                         case EXTR_IF_EXISTS:
    1480          15 :                                 if (!var_exists) break;
    1481             :                                 /* break omitted intentionally */
    1482             : 
    1483             :                         case EXTR_OVERWRITE:
    1484             :                                 /* GLOBALS protection */
    1485         109 :                                 if (var_exists && var_name->len == sizeof("GLOBALS")-1 && !strcmp(var_name->val, "GLOBALS")) {
    1486           3 :                                         break;
    1487             :                                 }
    1488         106 :                                 if (var_exists && var_name->len == sizeof("this")-1  && !strcmp(var_name->val, "this") && EG(scope) && EG(scope)->name->len != 0) {
    1489           0 :                                         break;
    1490             :                                 }
    1491         106 :                                 ZVAL_STR_COPY(&final_name, var_name);
    1492         106 :                                 break;
    1493             : 
    1494             :                         case EXTR_PREFIX_IF_EXISTS:
    1495          15 :                                 if (var_exists) {
    1496          11 :                                         php_prefix_varname(&final_name, prefix, var_name->val, var_name->len, 1);
    1497             :                                 }
    1498          15 :                                 break;
    1499             : 
    1500             :                         case EXTR_PREFIX_SAME:
    1501          17 :                                 if (!var_exists && var_name->len != 0) {
    1502           3 :                                         ZVAL_STR_COPY(&final_name, var_name);
    1503             :                                 }
    1504             :                                 /* break omitted intentionally */
    1505             : 
    1506             :                         case EXTR_PREFIX_ALL:
    1507         181 :                                 if (Z_TYPE(final_name) == IS_NULL && var_name->len != 0) {
    1508          51 :                                         php_prefix_varname(&final_name, prefix, var_name->val, var_name->len, 1);
    1509             :                                 }
    1510         181 :                                 break;
    1511             : 
    1512             :                         case EXTR_PREFIX_INVALID:
    1513          66 :                                 if (Z_TYPE(final_name) == IS_NULL) {
    1514          15 :                                         if (!php_valid_var_name(var_name->val, var_name->len)) {
    1515           4 :                                                 php_prefix_varname(&final_name, prefix, var_name->val, var_name->len, 1);
    1516             :                                         } else {
    1517          11 :                                                 ZVAL_STR_COPY(&final_name, var_name);
    1518             :                                         }
    1519             :                                 }
    1520          66 :                                 break;
    1521             : 
    1522             :                         default:
    1523          15 :                                 if (!var_exists) {
    1524           4 :                                         ZVAL_STR_COPY(&final_name, var_name);
    1525             :                                 }
    1526             :                                 break;
    1527             :                 }
    1528             : 
    1529         390 :                 if (Z_TYPE(final_name) == IS_STRING && php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
    1530         340 :                         if (extract_refs) {
    1531             :                                 zval *orig_var;
    1532             : 
    1533         108 :                                 ZVAL_MAKE_REF(entry);
    1534             :                                 Z_ADDREF_P(entry);
    1535             : 
    1536          54 :                                 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
    1537          31 :                                         if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
    1538          17 :                                                 orig_var = Z_INDIRECT_P(orig_var);
    1539             :                                         }
    1540          31 :                                         zval_ptr_dtor(orig_var);
    1541          31 :                                         ZVAL_COPY_VALUE(orig_var, entry);
    1542             :                                 } else {
    1543          23 :                                         zend_hash_update(symbol_table, Z_STR(final_name), entry);
    1544             :                                 }
    1545             :                         } else {
    1546         286 :                                 if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry);
    1547         286 :                                 zend_hash_update_ind(symbol_table, Z_STR(final_name), entry);
    1548             :                         }
    1549         340 :                         count++;
    1550             :                 }
    1551             :                 zval_dtor(&final_name);
    1552             :         } ZEND_HASH_FOREACH_END();
    1553             : 
    1554         130 :         RETURN_LONG(count);
    1555             : }
    1556             : /* }}} */
    1557             : 
    1558          73 : static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_value, zval *entry) /* {{{ */
    1559             : {
    1560             :         zval *value_ptr, data;
    1561             : 
    1562          73 :         ZVAL_DEREF(entry);
    1563          73 :         if (Z_TYPE_P(entry) == IS_STRING) {
    1564          68 :                 if ((value_ptr = zend_hash_find_ind(eg_active_symbol_table, Z_STR_P(entry))) != NULL) {
    1565          29 :                         ZVAL_DUP(&data, value_ptr);
    1566          29 :                         zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
    1567             :                 }
    1568          39 :         } else if (Z_TYPE_P(entry) == IS_ARRAY) {
    1569          28 :                 if ((Z_ARRVAL_P(entry)->u.v.nApplyCount > 1)) {
    1570           5 :                         php_error_docref(NULL, E_WARNING, "recursion detected");
    1571           5 :                         return;
    1572             :                 }
    1573             : 
    1574          23 :             if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(entry))) {
    1575          23 :                         Z_ARRVAL_P(entry)->u.v.nApplyCount++;
    1576             :                 }
    1577         167 :                 ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(entry), value_ptr) {
    1578          48 :                         php_compact_var(eg_active_symbol_table, return_value, value_ptr);
    1579             :                 } ZEND_HASH_FOREACH_END();
    1580          23 :             if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(entry))) {
    1581          23 :                         Z_ARRVAL_P(entry)->u.v.nApplyCount--;
    1582             :                 }
    1583             :         }
    1584             : }
    1585             : /* }}} */
    1586             : 
    1587             : /* {{{ proto array compact(mixed var_names [, mixed ...])
    1588             :    Creates a hash containing variables and their values */
    1589          14 : PHP_FUNCTION(compact)
    1590             : {
    1591          14 :         zval *args = NULL;      /* function arguments array */
    1592             :         uint32_t num_args, i;
    1593             :         zend_array *symbol_table;
    1594             : 
    1595          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &num_args) == FAILURE) {
    1596           1 :                 return;
    1597             :         }
    1598             : 
    1599          13 :         symbol_table = zend_rebuild_symbol_table();
    1600             : 
    1601             :         /* compact() is probably most used with a single array of var_names
    1602             :            or multiple string names, rather than a combination of both.
    1603             :            So quickly guess a minimum result size based on that */
    1604          30 :         if (ZEND_NUM_ARGS() == 1 && Z_TYPE(args[0]) == IS_ARRAY) {
    1605           8 :                 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
    1606             :         } else {
    1607           5 :                 array_init_size(return_value, ZEND_NUM_ARGS());
    1608             :         }
    1609             : 
    1610          38 :         for (i=0; i<ZEND_NUM_ARGS(); i++) {
    1611          25 :                 php_compact_var(symbol_table, return_value, &args[i]);
    1612             :         }
    1613             : }
    1614             : /* }}} */
    1615             : 
    1616             : /* {{{ proto array array_fill(int start_key, int num, mixed val)
    1617             :    Create an array containing num elements starting with index start_key each initialized to val */
    1618         165 : PHP_FUNCTION(array_fill)
    1619             : {
    1620             :         zval *val;
    1621             :         zend_long start_key, num;
    1622             : 
    1623         165 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "llz", &start_key, &num, &val) == FAILURE) {
    1624          24 :                 return;
    1625             :         }
    1626             : 
    1627         141 :         if (num < 0) {
    1628           2 :                 php_error_docref(NULL, E_WARNING, "Number of elements can't be negative");
    1629           2 :                 RETURN_FALSE;
    1630             :         }
    1631             : 
    1632             :         /* allocate an array for return */
    1633         139 :         array_init_size(return_value, (uint32_t)num);
    1634             : 
    1635         139 :         if (num == 0) {
    1636          26 :                 return;
    1637             :         }
    1638             : 
    1639         113 :         num--;
    1640         113 :         zend_hash_index_update(Z_ARRVAL_P(return_value), start_key, val);
    1641         113 :         Z_TRY_ADDREF_P(val);
    1642             : 
    1643      190136 :         while (num--) {
    1644      189911 :                 if (zend_hash_next_index_insert(Z_ARRVAL_P(return_value), val) != NULL) {
    1645      189910 :                         Z_TRY_ADDREF_P(val);
    1646             :                 } else {
    1647             :                         zval_dtor(return_value);
    1648           1 :                         php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
    1649           1 :                         RETURN_FALSE;
    1650             :                 }
    1651             :         }
    1652             : }
    1653             : /* }}} */
    1654             : 
    1655             : /* {{{ proto array array_fill_keys(array keys, mixed val)
    1656             :    Create an array using the elements of the first parameter as keys each initialized to val */
    1657          24 : PHP_FUNCTION(array_fill_keys)
    1658             : {
    1659             :         zval *keys, *val, *entry;
    1660             : 
    1661          24 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "az", &keys, &val) == FAILURE) {
    1662           6 :                 return;
    1663             :         }
    1664             : 
    1665             :         /* Initialize return array */
    1666          18 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
    1667             : 
    1668          98 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) {
    1669          40 :                 ZVAL_DEREF(entry);
    1670          40 :                 Z_TRY_ADDREF_P(val);
    1671          40 :                 if (Z_TYPE_P(entry) == IS_LONG) {
    1672           8 :                         zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_P(entry), val);
    1673             :                 } else {
    1674          32 :                         zend_string *key = zval_get_string(entry);
    1675          32 :                         zend_symtable_update(Z_ARRVAL_P(return_value), key, val);
    1676             :                         zend_string_release(key);
    1677             :                 }
    1678             :         } ZEND_HASH_FOREACH_END();
    1679             : }
    1680             : /* }}} */
    1681             : 
    1682             : /* {{{ proto array range(mixed low, mixed high[, int step])
    1683             :    Create an array containing the range of integers or characters from low to high (inclusive) */
    1684      100254 : PHP_FUNCTION(range)
    1685             : {
    1686      100254 :         zval *zlow, *zhigh, *zstep = NULL, tmp;
    1687      100254 :         int err = 0, is_step_double = 0;
    1688      100254 :         double step = 1.0;
    1689             : 
    1690      100254 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|z", &zlow, &zhigh, &zstep) == FAILURE) {
    1691           3 :                 RETURN_FALSE;
    1692             :         }
    1693             : 
    1694      100251 :         if (zstep) {
    1695          73 :                 if (Z_TYPE_P(zstep) == IS_DOUBLE ||
    1696          23 :                         (Z_TYPE_P(zstep) == IS_STRING && is_numeric_string(Z_STRVAL_P(zstep), Z_STRLEN_P(zstep), NULL, NULL, 0) == IS_DOUBLE)
    1697             :                 ) {
    1698           8 :                         is_step_double = 1;
    1699             :                 }
    1700             : 
    1701          50 :                 step = zval_get_double(zstep);
    1702             : 
    1703             :                 /* We only want positive step values. */
    1704          25 :                 if (step < 0.0) {
    1705           0 :                         step *= -1;
    1706             :                 }
    1707             :         }
    1708             : 
    1709             :         /* If the range is given as strings, generate an array of characters. */
    1710      200630 :         if (Z_TYPE_P(zlow) == IS_STRING && Z_TYPE_P(zhigh) == IS_STRING && Z_STRLEN_P(zlow) >= 1 && Z_STRLEN_P(zhigh) >= 1) {
    1711             :                 int type1, type2;
    1712             :                 unsigned char low, high;
    1713          63 :                 zend_long lstep = (zend_long) step;
    1714             : 
    1715         126 :                 type1 = is_numeric_string(Z_STRVAL_P(zlow), Z_STRLEN_P(zlow), NULL, NULL, 0);
    1716         126 :                 type2 = is_numeric_string(Z_STRVAL_P(zhigh), Z_STRLEN_P(zhigh), NULL, NULL, 0);
    1717             : 
    1718          63 :                 if (type1 == IS_DOUBLE || type2 == IS_DOUBLE || is_step_double) {
    1719             :                         goto double_str;
    1720          59 :                 } else if (type1 == IS_LONG || type2 == IS_LONG) {
    1721             :                         goto long_str;
    1722             :                 }
    1723             : 
    1724          54 :                 low = (unsigned char)Z_STRVAL_P(zlow)[0];
    1725          54 :                 high = (unsigned char)Z_STRVAL_P(zhigh)[0];
    1726             : 
    1727          54 :                 if (low > high) {            /* Negative Steps */
    1728           2 :                         if (lstep <= 0) {
    1729           1 :                                 err = 1;
    1730           1 :                                 goto err;
    1731             :                         }
    1732             :                         /* Initialize the return_value as an array. */
    1733           1 :                         array_init_size(return_value, (uint32_t)(((low - high) / lstep) + 1));
    1734           1 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    1735           1 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    1736          27 :                                 for (; low >= high; low -= (unsigned int)lstep) {
    1737          26 :                                         if (CG(one_char_string)[low]) {
    1738           0 :                                                 ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]);
    1739             :                                         } else {
    1740          52 :                                                 ZVAL_STRINGL(&tmp, (char*)&low, 1);
    1741             :                                         }
    1742          26 :                                         ZEND_HASH_FILL_ADD(&tmp);
    1743          26 :                                         if (((signed int)low - lstep) < 0) {
    1744           0 :                                                 break;
    1745             :                                         }
    1746             :                                 }
    1747           1 :                         } ZEND_HASH_FILL_END();
    1748          52 :                 } else if (high > low) {     /* Positive Steps */
    1749          50 :                         if (lstep <= 0) {
    1750           2 :                                 err = 1;
    1751           2 :                                 goto err;
    1752             :                         }
    1753          48 :                         array_init_size(return_value, (uint32_t)(((high - low) / lstep) + 1));
    1754          48 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    1755          48 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    1756        1242 :                                 for (; low <= high; low += (unsigned int)lstep) {
    1757        1194 :                                         if (CG(one_char_string)[low]) {
    1758           0 :                                                 ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]);
    1759             :                                         } else {
    1760        2388 :                                                 ZVAL_STRINGL(&tmp, (char*)&low, 1);
    1761             :                                         }
    1762        1194 :                                         ZEND_HASH_FILL_ADD(&tmp);
    1763        1194 :                                         if (((signed int)low + lstep) > 255) {
    1764           0 :                                                 break;
    1765             :                                         }
    1766             :                                 }
    1767          48 :                         } ZEND_HASH_FILL_END();
    1768             :                 } else {
    1769           2 :                         array_init(return_value);
    1770           2 :                         if (CG(one_char_string)[low]) {
    1771           0 :                                 ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]);
    1772             :                         } else {
    1773           4 :                                 ZVAL_STRINGL(&tmp, (char*)&low, 1);
    1774             :                         }
    1775           2 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1776             :                 }
    1777      300576 :         } else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) {
    1778             :                 double low, high, value;
    1779             :                 zend_long i;
    1780             : double_str:
    1781          50 :                 low = zval_get_double(zlow);
    1782          50 :                 high = zval_get_double(zhigh);
    1783          25 :                 i = 0;
    1784             : 
    1785          25 :                 Z_TYPE_INFO(tmp) = IS_DOUBLE;
    1786          25 :                 if (low > high) {            /* Negative steps */
    1787          10 :                         if (low - high < step || step <= 0) {
    1788           1 :                                 err = 1;
    1789           1 :                                 goto err;
    1790             :                         }
    1791             : 
    1792           9 :                         array_init_size(return_value, (uint32_t)(((low - high) / step) + 1));
    1793           9 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    1794           9 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    1795         100 :                         for (value = low; value >= (high - DOUBLE_DRIFT_FIX); value = low - (++i * step)) {
    1796          91 :                                 Z_DVAL(tmp) = value;
    1797          91 :                                 ZEND_HASH_FILL_ADD(&tmp);
    1798             :                         }
    1799           9 :                         } ZEND_HASH_FILL_END();
    1800          15 :                 } else if (high > low) {     /* Positive steps */
    1801          14 :                         if (high - low < step || step <= 0) {
    1802           1 :                                 err = 1;
    1803           1 :                                 goto err;
    1804             :                         }
    1805             : 
    1806          13 :                         array_init_size(return_value, (uint32_t)(((high - low) / step) + 1));
    1807          13 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    1808          13 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    1809         328 :                                 for (value = low; value <= (high + DOUBLE_DRIFT_FIX); value = low + (++i * step)) {
    1810         315 :                                         Z_DVAL(tmp) = value;
    1811         315 :                                         ZEND_HASH_FILL_ADD(&tmp);
    1812             :                                 }
    1813          13 :                         } ZEND_HASH_FILL_END();
    1814             :                 } else {
    1815           1 :                         array_init(return_value);
    1816           1 :                         Z_DVAL(tmp) = low;
    1817           1 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1818             :                 }
    1819             :         } else {
    1820             :                 double low, high;
    1821             :                 zend_long lstep;
    1822             : long_str:
    1823      200344 :                 low = zval_get_double(zlow);
    1824      200344 :                 high = zval_get_double(zhigh);
    1825      100172 :                 lstep = (zend_long) step;
    1826             : 
    1827      100172 :                 Z_TYPE_INFO(tmp) = IS_LONG;
    1828      100172 :                 if (low > high) {            /* Negative steps */
    1829          14 :                         if (low - high < lstep || lstep <= 0) {
    1830           2 :                                 err = 1;
    1831           2 :                                 goto err;
    1832             :                         }
    1833          12 :                         array_init_size(return_value, (uint32_t)(((low - high) / lstep) + 1));
    1834          12 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    1835          12 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    1836          68 :                                 for (; low >= high; low -= lstep) {
    1837          56 :                                         Z_LVAL(tmp) = (zend_long)low;
    1838          56 :                                         ZEND_HASH_FILL_ADD(&tmp);
    1839             :                                 }
    1840          12 :                         } ZEND_HASH_FILL_END();
    1841      100158 :                 } else if (high > low) {     /* Positive steps */
    1842      100137 :                         if (high - low < lstep || lstep <= 0) {
    1843           6 :                                 err = 1;
    1844           6 :                                 goto err;
    1845             :                         }
    1846      100131 :                         array_init_size(return_value, (uint32_t)(((high - low) / lstep) + 1));
    1847      100131 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    1848      100131 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    1849      493568 :                                 for (; low <= high; low += lstep) {
    1850      393437 :                                         Z_LVAL(tmp) = (zend_long)low;
    1851      393437 :                                         ZEND_HASH_FILL_ADD(&tmp);
    1852             :                                 }
    1853      100131 :                         } ZEND_HASH_FILL_END();
    1854             :                 } else {
    1855          21 :                         array_init(return_value);
    1856          21 :                         Z_LVAL(tmp) = (zend_long)low;
    1857          21 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1858             :                 }
    1859             :         }
    1860             : err:
    1861      100251 :         if (err) {
    1862          13 :                 php_error_docref(NULL, E_WARNING, "step exceeds the specified range");
    1863          13 :                 RETURN_FALSE;
    1864             :         }
    1865             : }
    1866             : /* }}} */
    1867             : 
    1868       90054 : static void php_array_data_shuffle(zval *array) /* {{{ */
    1869             : {
    1870             :         uint32_t idx, j, n_elems;
    1871             :         Bucket *p, temp;
    1872             :         HashTable *hash;
    1873             :         zend_long rnd_idx;
    1874             :         uint32_t n_left;
    1875             : 
    1876       90054 :         n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
    1877             : 
    1878       90054 :         if (n_elems < 1) {
    1879           1 :                 return;
    1880             :         }
    1881             : 
    1882       90053 :         hash = Z_ARRVAL_P(array);
    1883       90053 :         n_left = n_elems;
    1884             : 
    1885       90053 :         if (EXPECTED(hash->u.v.nIteratorsCount == 0)) {
    1886       90053 :                 if (hash->nNumUsed != hash->nNumOfElements) {
    1887           7 :                         for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
    1888           5 :                                 p = hash->arData + idx;
    1889          10 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1890           2 :                                 if (j != idx) {
    1891           2 :                                         hash->arData[j] = *p;
    1892             :                                 }
    1893           2 :                                 j++;
    1894             :                         }
    1895             :                 }
    1896      451493 :                 while (--n_left) {
    1897      271387 :                         rnd_idx = php_rand();
    1898      271387 :                         RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
    1899      271387 :                         if (rnd_idx != n_left) {
    1900      173533 :                                 temp = hash->arData[n_left];
    1901      173533 :                                 hash->arData[n_left] = hash->arData[rnd_idx];
    1902      173533 :                                 hash->arData[rnd_idx] = temp;
    1903             :                         }
    1904             :                 }
    1905             :         } else {
    1906           0 :                 uint32_t iter_pos = zend_hash_iterators_lower_pos(hash, 0);
    1907             : 
    1908           0 :                 if (hash->nNumUsed != hash->nNumOfElements) {
    1909           0 :                         for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
    1910           0 :                                 p = hash->arData + idx;
    1911           0 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1912           0 :                                 if (j != idx) {
    1913           0 :                                         hash->arData[j] = *p;
    1914           0 :                                         if (idx == iter_pos) {
    1915             :                                                 zend_hash_iterators_update(hash, idx, j);
    1916           0 :                                                 iter_pos = zend_hash_iterators_lower_pos(hash, iter_pos + 1);
    1917             :                                         }
    1918             :                                 }
    1919           0 :                                 j++;
    1920             :                         }
    1921             :                 }
    1922           0 :                 while (--n_left) {
    1923           0 :                         rnd_idx = php_rand();
    1924           0 :                         RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
    1925           0 :                         if (rnd_idx != n_left) {
    1926           0 :                                 temp = hash->arData[n_left];
    1927           0 :                                 hash->arData[n_left] = hash->arData[rnd_idx];
    1928           0 :                                 hash->arData[rnd_idx] = temp;
    1929           0 :                                 zend_hash_iterators_update(hash, (uint32_t)rnd_idx, n_left);
    1930             :                         }
    1931             :                 }
    1932             :         }
    1933       90053 :         HANDLE_BLOCK_INTERRUPTIONS();
    1934       90053 :         hash->nNumUsed = n_elems;
    1935       90053 :         hash->nInternalPointer = 0;
    1936             : 
    1937      451493 :         for (j = 0; j < n_elems; j++) {
    1938      361440 :                 p = hash->arData + j;
    1939      361440 :                 if (p->key) {
    1940          41 :                         zend_string_release(p->key);
    1941             :                 }
    1942      361440 :                 p->h = j;
    1943      361440 :                 p->key = NULL;
    1944             :         }
    1945       90053 :         hash->nNextFreeElement = n_elems;
    1946       90053 :         if (!(hash->u.flags & HASH_FLAG_PACKED)) {
    1947          15 :                 zend_hash_to_packed(hash);
    1948             :         }
    1949       90053 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1950             : }
    1951             : /* }}} */
    1952             : 
    1953             : /* {{{ proto bool shuffle(array array_arg)
    1954             :    Randomly shuffle the contents of an array */
    1955       90079 : PHP_FUNCTION(shuffle)
    1956             : {
    1957             :         zval *array;
    1958             : 
    1959       90079 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &array) == FAILURE) {
    1960          25 :                 RETURN_FALSE;
    1961             :         }
    1962             : 
    1963       90054 :         php_array_data_shuffle(array);
    1964             : 
    1965       90054 :         RETURN_TRUE;
    1966             : }
    1967             : /* }}} */
    1968             : 
    1969          63 : static void php_splice(HashTable *in_hash, int offset, int length, HashTable *replace, HashTable *removed) /* {{{ */
    1970             : {
    1971             :         HashTable        out_hash;                      /* Output hashtable */
    1972             :         int                      num_in,                        /* Number of entries in the input hashtable */
    1973             :                                  pos;                           /* Current position in the hashtable */
    1974             :         uint         idx;
    1975             :         Bucket          *p;                                     /* Pointer to hash bucket */
    1976             :         zval            *entry;                         /* Hash entry */
    1977          63 :         uint32_t    iter_pos = zend_hash_iterators_lower_pos(in_hash, 0);
    1978             : 
    1979             :         /* Get number of entries in the input hash */
    1980          63 :         num_in = zend_hash_num_elements(in_hash);
    1981             : 
    1982             :         /* Clamp the offset.. */
    1983          63 :         if (offset > num_in) {
    1984           0 :                 offset = num_in;
    1985          63 :         } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
    1986           0 :                 offset = 0;
    1987             :         }
    1988             : 
    1989             :         /* ..and the length */
    1990          63 :         if (length < 0) {
    1991          15 :                 length = num_in - offset + length;
    1992          48 :         } else if (((unsigned)offset + (unsigned)length) > (unsigned)num_in) {
    1993          10 :                 length = num_in - offset;
    1994             :         }
    1995             : 
    1996             :         /* Create and initialize output hash */
    1997          63 :         zend_hash_init(&out_hash, (length > 0 ? num_in - length : 0) + (replace ? zend_hash_num_elements(replace) : 0), NULL, ZVAL_PTR_DTOR, 0);
    1998             : 
    1999             :         /* Start at the beginning of the input hash and copy entries to output hash until offset is reached */
    2000         165 :         for (pos = 0, idx = 0; pos < offset && idx < in_hash->nNumUsed; idx++) {
    2001         102 :                 p = in_hash->arData + idx;
    2002         204 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2003             :                 /* Get entry and increase reference count */
    2004         102 :                 entry = &p->val;
    2005             : 
    2006             :                 /* Update output hash depending on key type */
    2007         102 :                 if (p->key == NULL) {
    2008         101 :                         zend_hash_next_index_insert_new(&out_hash, entry);
    2009             :                 } else {
    2010           1 :                         zend_hash_add_new(&out_hash, p->key, entry);
    2011             :                 }
    2012         102 :                 if (idx == iter_pos) {
    2013           2 :                         if (idx != pos) {
    2014           0 :                                 zend_hash_iterators_update(in_hash, idx, pos);
    2015             :                         }
    2016           2 :                         iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
    2017             :                 }
    2018         102 :                 pos++;
    2019             :         }
    2020             : 
    2021             :         /* If hash for removed entries exists, go until offset+length and copy the entries to it */
    2022          63 :         if (removed != NULL) {
    2023         145 :                 for ( ; pos < offset + length && idx < in_hash->nNumUsed; idx++) {
    2024          93 :                         p = in_hash->arData + idx;
    2025         186 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2026          93 :                         pos++;
    2027          93 :                         entry = &p->val;
    2028          93 :                         if (Z_REFCOUNTED_P(entry)) {
    2029             :                                 Z_ADDREF_P(entry);
    2030             :                         }
    2031          93 :                         if (p->key == NULL) {
    2032          92 :                                 zend_hash_next_index_insert_new(removed, entry);
    2033          92 :                                 zend_hash_index_del(in_hash, p->h);
    2034             :                         } else {
    2035           1 :                                 zend_hash_add_new(removed, p->key, entry);
    2036           1 :                                 if (in_hash == &EG(symbol_table)) {
    2037           0 :                                         zend_delete_global_variable(p->key);
    2038             :                                 } else {
    2039           1 :                                         zend_hash_del(in_hash, p->key);
    2040             :                                 }
    2041             :                         }
    2042             :                 }
    2043             :         } else { /* otherwise just skip those entries */
    2044          11 :                 int pos2 = pos;
    2045             : 
    2046          41 :                 for ( ; pos2 < offset + length && idx < in_hash->nNumUsed; idx++) {
    2047          30 :                         p = in_hash->arData + idx;
    2048          60 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2049          30 :                         pos2++;
    2050          30 :                         if (p->key == NULL) {
    2051          21 :                                 zend_hash_index_del(in_hash, p->h);
    2052             :                         } else {
    2053           9 :                                 if (in_hash == &EG(symbol_table)) {
    2054           9 :                                         zend_delete_global_variable(p->key);
    2055             :                                 } else {
    2056           0 :                                         zend_hash_del(in_hash, p->key);
    2057             :                                 }
    2058             :                         }
    2059             :                 }
    2060             :         }
    2061          63 :         iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos);
    2062             : 
    2063             :         /* If there are entries to insert.. */
    2064          63 :         if (replace) {
    2065         256 :                 ZEND_HASH_FOREACH_VAL_IND(replace, entry) {
    2066          75 :                         if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry);
    2067          75 :                         zend_hash_next_index_insert_new(&out_hash, entry);
    2068          75 :                         pos++;
    2069             :                 } ZEND_HASH_FOREACH_END();
    2070             :         }
    2071             : 
    2072             :         /* Copy the remaining input hash entries to the output hash */
    2073         173 :         for ( ; idx < in_hash->nNumUsed ; idx++) {
    2074         110 :                 p = in_hash->arData + idx;
    2075         220 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2076         110 :                 entry = &p->val;
    2077         110 :                 if (p->key == NULL) {
    2078         109 :                         zend_hash_next_index_insert_new(&out_hash, entry);
    2079             :                 } else {
    2080           1 :                         zend_hash_add_new(&out_hash, p->key, entry);
    2081             :                 }
    2082         110 :                 if (idx == iter_pos) {
    2083           3 :                         if (idx != pos) {
    2084           2 :                                 zend_hash_iterators_update(in_hash, idx, pos);
    2085             :                         }
    2086           3 :                         iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
    2087             :                 }
    2088         110 :                 pos++;
    2089             :         }
    2090             : 
    2091             :         /* replace HashTable data */
    2092          63 :         in_hash->u.v.nIteratorsCount = 0;
    2093          63 :         in_hash->pDestructor = NULL;
    2094          63 :         zend_hash_destroy(in_hash);
    2095             : 
    2096          63 :         in_hash->u.v.flags         = out_hash.u.v.flags;
    2097          63 :         in_hash->nTableSize        = out_hash.nTableSize;
    2098          63 :         in_hash->nTableMask        = out_hash.nTableMask;
    2099          63 :         in_hash->nNumUsed          = out_hash.nNumUsed;
    2100          63 :         in_hash->nNumOfElements    = out_hash.nNumOfElements;
    2101          63 :         in_hash->nNextFreeElement  = out_hash.nNextFreeElement;
    2102          63 :         in_hash->arData            = out_hash.arData;
    2103          63 :         in_hash->pDestructor       = out_hash.pDestructor;
    2104             : 
    2105          63 :         zend_hash_internal_pointer_reset(in_hash);
    2106          63 : }
    2107             : /* }}} */
    2108             : 
    2109             : /* {{{ proto int array_push(array stack, mixed var [, mixed ...])
    2110             :    Pushes elements onto the end of the array */
    2111         700 : PHP_FUNCTION(array_push)
    2112             : {
    2113             :         zval   *args,           /* Function arguments array */
    2114             :                    *stack,              /* Input array */
    2115             :                     new_var;    /* Variable to be pushed */
    2116             :         int i,                          /* Loop counter */
    2117             :                 argc;                   /* Number of function arguments */
    2118             : 
    2119             : 
    2120         700 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/+", &stack, &args, &argc) == FAILURE) {
    2121          28 :                 return;
    2122             :         }
    2123             : 
    2124             :         /* For each subsequent argument, make it a reference, increase refcount, and add it to the end of the array */
    2125        1359 :         for (i = 0; i < argc; i++) {
    2126         688 :                 ZVAL_COPY(&new_var, &args[i]);
    2127             : 
    2128         688 :                 if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var) == NULL) {
    2129           1 :                         if (Z_REFCOUNTED(new_var)) Z_DELREF(new_var);
    2130           1 :                         php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
    2131           1 :                         RETURN_FALSE;
    2132             :                 }
    2133             :         }
    2134             : 
    2135             :         /* Clean up and return the number of values in the stack */
    2136         671 :         RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
    2137             : }
    2138             : /* }}} */
    2139             : 
    2140             : /* {{{ proto mixed array_pop(array stack)
    2141             :    Pops an element off the end of the array */
    2142          74 : PHP_FUNCTION(array_pop)
    2143             : {
    2144             :         zval *stack,    /* Input stack */
    2145             :                  *val;          /* Value to be popped */
    2146             :         uint32_t idx;
    2147             :         Bucket *p;
    2148             : 
    2149             : #ifndef FAST_ZPP
    2150             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &stack) == FAILURE) {
    2151             :                 return;
    2152             :         }
    2153             : #else
    2154          74 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    2155         305 :                 Z_PARAM_ARRAY_EX(stack, 0, 1)
    2156          74 :         ZEND_PARSE_PARAMETERS_END();
    2157             : #endif
    2158             : 
    2159          70 :         if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {
    2160           2 :                 return;
    2161             :         }
    2162             : 
    2163             :         /* Get the last value and copy it into the return value */
    2164          68 :         idx = Z_ARRVAL_P(stack)->nNumUsed;
    2165             :         while (1) {
    2166          77 :                 if (idx == 0) {
    2167           0 :                         return;
    2168             :                 }
    2169          77 :                 idx--;
    2170          77 :                 p = Z_ARRVAL_P(stack)->arData + idx;
    2171          77 :                 val = &p->val;
    2172          77 :                 if (Z_TYPE_P(val) == IS_INDIRECT) {
    2173          10 :                         val = Z_INDIRECT_P(val);
    2174             :                 }
    2175          77 :                 if (Z_TYPE_P(val) != IS_UNDEF) {
    2176          68 :                         break;
    2177             :                 }
    2178           9 :         }
    2179          68 :         ZVAL_DEREF(val);
    2180          68 :         ZVAL_COPY(return_value, val);
    2181             : 
    2182          68 :         if (!p->key && Z_ARRVAL_P(stack)->nNextFreeElement > 0 && p->h >= (zend_ulong)(Z_ARRVAL_P(stack)->nNextFreeElement - 1)) {
    2183          59 :                 Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1;
    2184             :         }
    2185             : 
    2186             :         /* Delete the last value */
    2187          68 :         if (p->key) {
    2188           7 :                 if (Z_ARRVAL_P(stack) == &EG(symbol_table)) {
    2189           3 :                         zend_delete_global_variable(p->key);
    2190             :                 } else {
    2191           4 :                         zend_hash_del(Z_ARRVAL_P(stack), p->key);
    2192             :                 }
    2193             :         } else {
    2194          61 :                 zend_hash_index_del(Z_ARRVAL_P(stack), p->h);
    2195             :         }
    2196             : 
    2197          68 :         zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
    2198             : }
    2199             : /* }}} */
    2200             : 
    2201             : /* {{{ proto mixed array_shift(array stack)
    2202             :    Pops an element off the beginning of the array */
    2203         228 : PHP_FUNCTION(array_shift)
    2204             : {
    2205             :         zval *stack,    /* Input stack */
    2206             :                  *val;          /* Value to be popped */
    2207             :         uint32_t idx;
    2208             :         Bucket *p;
    2209             : 
    2210             : #ifndef FAST_ZPP
    2211             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &stack) == FAILURE) {
    2212             :                 return;
    2213             :         }
    2214             : #else
    2215         228 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    2216         944 :                 Z_PARAM_ARRAY_EX(stack, 0, 1)
    2217         228 :         ZEND_PARSE_PARAMETERS_END();
    2218             : #endif
    2219             : 
    2220         198 :         if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {
    2221           3 :                 return;
    2222             :         }
    2223             : 
    2224             :         /* Get the first value and copy it into the return value */
    2225         195 :         idx = 0;
    2226             :         while (1) {
    2227         203 :                 if (idx == Z_ARRVAL_P(stack)->nNumUsed) {
    2228           0 :                         return;
    2229             :                 }
    2230         203 :                 p = Z_ARRVAL_P(stack)->arData + idx;
    2231         203 :                 val = &p->val;
    2232         203 :                 if (Z_TYPE_P(val) == IS_INDIRECT) {
    2233           0 :                         val = Z_INDIRECT_P(val);
    2234             :                 }
    2235         203 :                 if (Z_TYPE_P(val) != IS_UNDEF) {
    2236         195 :                         break;
    2237             :                 }
    2238           8 :                 idx++;
    2239           8 :         }
    2240         195 :         ZVAL_DEREF(val);
    2241         195 :         ZVAL_COPY(return_value, val);
    2242             : 
    2243             :         /* Delete the first value */
    2244         195 :         if (p->key) {
    2245          26 :                 if (Z_ARRVAL_P(stack) == &EG(symbol_table)) {
    2246           1 :                         zend_delete_global_variable(p->key);
    2247             :                 } else {
    2248          25 :                         zend_hash_del(Z_ARRVAL_P(stack), p->key);
    2249             :                 }
    2250             :         } else {
    2251         169 :                 zend_hash_index_del(Z_ARRVAL_P(stack), p->h);
    2252             :         }
    2253             : 
    2254             :         /* re-index like it did before */
    2255         195 :         if (Z_ARRVAL_P(stack)->u.flags & HASH_FLAG_PACKED) {
    2256         163 :                 uint32_t k = 0;
    2257             : 
    2258         163 :                 if (EXPECTED(Z_ARRVAL_P(stack)->u.v.nIteratorsCount == 0)) {
    2259         583 :                         for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
    2260         444 :                                 p = Z_ARRVAL_P(stack)->arData + idx;
    2261         888 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2262         328 :                                 if (idx != k) {
    2263         328 :                                         Bucket *q = Z_ARRVAL_P(stack)->arData + k;
    2264         328 :                                         q->h = k;
    2265         328 :                                         q->key = NULL;
    2266         328 :                                         ZVAL_COPY_VALUE(&q->val, &p->val);
    2267         328 :                                         ZVAL_UNDEF(&p->val);
    2268             :                                 }
    2269         328 :                                 k++;
    2270             :                         }
    2271             :                 } else {
    2272          24 :                         uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);
    2273             : 
    2274          65 :                         for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
    2275          41 :                                 p = Z_ARRVAL_P(stack)->arData + idx;
    2276          82 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2277          26 :                                 if (idx != k) {
    2278          26 :                                         Bucket *q = Z_ARRVAL_P(stack)->arData + k;
    2279          26 :                                         q->h = k;
    2280          26 :                                         q->key = NULL;
    2281          26 :                                         ZVAL_COPY_VALUE(&q->val, &p->val);
    2282          26 :                                         ZVAL_UNDEF(&p->val);
    2283          26 :                                         if (idx == iter_pos) {
    2284          15 :                                                 zend_hash_iterators_update(Z_ARRVAL_P(stack), idx, k);
    2285          15 :                                                 iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
    2286             :                                         }
    2287             :                                 }
    2288          26 :                                 k++;
    2289             :                         }
    2290             :                 }
    2291         163 :                 Z_ARRVAL_P(stack)->nNumUsed = k;
    2292         163 :                 Z_ARRVAL_P(stack)->nNextFreeElement = k;
    2293             :         } else {
    2294          32 :                 uint32_t k = 0;
    2295          32 :                 int should_rehash = 0;
    2296             : 
    2297         501 :                 for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
    2298         469 :                         p = Z_ARRVAL_P(stack)->arData + idx;
    2299         938 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2300         437 :                         if (p->key == NULL) {
    2301          22 :                                 if (p->h != k) {
    2302          15 :                                         p->h = k++;
    2303          15 :                                         should_rehash = 1;
    2304             :                                 } else {
    2305           7 :                                         k++;
    2306             :                                 }
    2307             :                         }
    2308             :                 }
    2309          32 :                 Z_ARRVAL_P(stack)->nNextFreeElement = k;
    2310          32 :                 if (should_rehash) {
    2311           5 :                         zend_hash_rehash(Z_ARRVAL_P(stack));
    2312             :                 }
    2313             :         }
    2314             : 
    2315         195 :         zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
    2316             : }
    2317             : /* }}} */
    2318             : 
    2319             : /* {{{ proto int array_unshift(array stack, mixed var [, mixed ...])
    2320             :    Pushes elements onto the beginning of the array */
    2321         277 : PHP_FUNCTION(array_unshift)
    2322             : {
    2323             :         zval   *args,                   /* Function arguments array */
    2324             :                    *stack;                      /* Input stack */
    2325             :         HashTable new_hash;             /* New hashtable for the stack */
    2326             :         int argc;                               /* Number of function arguments */
    2327             :         int i;
    2328             :         zend_string *key;
    2329             :         zval *value;
    2330             : 
    2331         277 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/+", &stack, &args, &argc) == FAILURE) {
    2332          51 :                 return;
    2333             :         }
    2334             : 
    2335         226 :         zend_hash_init(&new_hash, zend_hash_num_elements(Z_ARRVAL_P(stack)) + argc, NULL, ZVAL_PTR_DTOR, 0);
    2336         647 :         for (i = 0; i < argc; i++) {
    2337         421 :                 if (Z_REFCOUNTED(args[i])) {
    2338          79 :                         Z_ADDREF(args[i]);
    2339             :                 }
    2340         421 :                 zend_hash_next_index_insert_new(&new_hash, &args[i]);
    2341             :         }
    2342         226 :         if (EXPECTED(Z_ARRVAL_P(stack)->u.v.nIteratorsCount == 0)) {
    2343        1755 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
    2344         755 :                         if (key) {
    2345         310 :                                 zend_hash_add_new(&new_hash, key, value);
    2346             :                         } else {
    2347         445 :                                 zend_hash_next_index_insert_new(&new_hash, value);
    2348             :                         }
    2349             :                 } ZEND_HASH_FOREACH_END();
    2350             :         } else {
    2351             :                 uint32_t old_idx;
    2352           9 :                 uint32_t new_idx = i;
    2353           9 :                 uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);
    2354             : 
    2355          55 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
    2356          23 :                         if (key) {
    2357           0 :                                 zend_hash_add_new(&new_hash, key, value);
    2358             :                         } else {
    2359          23 :                                 zend_hash_next_index_insert_new(&new_hash, value);
    2360             :                         }
    2361          23 :                         old_idx = (Bucket*)value - Z_ARRVAL_P(stack)->arData;
    2362          23 :                         if (old_idx == iter_pos) {
    2363          13 :                                 zend_hash_iterators_update(Z_ARRVAL_P(stack), old_idx, new_idx);
    2364          13 :                                 iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
    2365             :                         }
    2366          23 :                         new_idx++;
    2367             :                 } ZEND_HASH_FOREACH_END();
    2368             :         }
    2369             : 
    2370             :         /* replace HashTable data */
    2371         226 :         Z_ARRVAL_P(stack)->u.v.nIteratorsCount = 0;
    2372         226 :         Z_ARRVAL_P(stack)->pDestructor = NULL;
    2373         226 :         zend_hash_destroy(Z_ARRVAL_P(stack));
    2374             : 
    2375         226 :         Z_ARRVAL_P(stack)->u.v.flags         = new_hash.u.v.flags;
    2376         226 :         Z_ARRVAL_P(stack)->nTableSize        = new_hash.nTableSize;
    2377         226 :         Z_ARRVAL_P(stack)->nTableMask        = new_hash.nTableMask;
    2378         226 :         Z_ARRVAL_P(stack)->nNumUsed          = new_hash.nNumUsed;
    2379         226 :         Z_ARRVAL_P(stack)->nNumOfElements    = new_hash.nNumOfElements;
    2380         226 :         Z_ARRVAL_P(stack)->nNextFreeElement  = new_hash.nNextFreeElement;
    2381         226 :         Z_ARRVAL_P(stack)->arData            = new_hash.arData;
    2382         226 :         Z_ARRVAL_P(stack)->pDestructor       = new_hash.pDestructor;
    2383             :         
    2384         226 :         zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
    2385             : 
    2386             :         /* Clean up and return the number of elements in the stack */
    2387         226 :         RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
    2388             : }
    2389             : /* }}} */
    2390             : 
    2391             : /* {{{ proto array array_splice(array input, int offset [, int length [, array replacement]])
    2392             :    Removes the elements designated by offset and length and replace them with supplied array */
    2393          69 : PHP_FUNCTION(array_splice)
    2394             : {
    2395             :         zval *array,                            /* Input array */
    2396          69 :                  *repl_array = NULL;    /* Replacement array */
    2397          69 :         HashTable  *rem_hash = NULL;
    2398             :         zend_long offset,
    2399          69 :                         length = 0;
    2400             :         int             num_in;                         /* Number of elements in the input array */
    2401             : 
    2402          69 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/l|lz/", &array, &offset, &length, &repl_array) == FAILURE) {
    2403           6 :                 return;
    2404             :         }
    2405             : 
    2406          63 :         num_in = zend_hash_num_elements(Z_ARRVAL_P(array));
    2407             : 
    2408          63 :         if (ZEND_NUM_ARGS() < 3) {
    2409           1 :                 length = num_in;
    2410             :         }
    2411             : 
    2412          63 :         if (ZEND_NUM_ARGS() == 4) {
    2413             :                 /* Make sure the last argument, if passed, is an array */
    2414          62 :                 convert_to_array_ex(repl_array);
    2415             :         }
    2416             : 
    2417             :         /* Don't create the array of removed elements if it's not going
    2418             :          * to be used; e.g. only removing and/or replacing elements */
    2419          63 :         if (USED_RET()) {
    2420          52 :                 zend_long size = length;
    2421             : 
    2422             :                 /* Clamp the offset.. */
    2423          52 :                 if (offset > num_in) {
    2424           0 :                         offset = num_in;
    2425          52 :                 } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
    2426           0 :                         offset = 0;
    2427             :                 }
    2428             : 
    2429             :                 /* ..and the length */
    2430          52 :                 if (length < 0) {
    2431          15 :                         size = num_in - offset + length;
    2432          37 :                 } else if (((zend_ulong) offset + (zend_ulong) length) > (uint32_t) num_in) {
    2433          10 :                         size = num_in - offset;
    2434             :                 }
    2435             : 
    2436             :                 /* Initialize return value */
    2437          52 :                 array_init_size(return_value, size > 0 ? (uint32_t)size : 0);
    2438          52 :                 rem_hash = Z_ARRVAL_P(return_value);
    2439             :         }
    2440             : 
    2441             :         /* Perform splice */
    2442          63 :         php_splice(Z_ARRVAL_P(array), (int)offset, (int)length, repl_array ? Z_ARRVAL_P(repl_array) : NULL, rem_hash);
    2443             : }
    2444             : /* }}} */
    2445             : 
    2446             : /* {{{ proto array array_slice(array input, int offset [, int length [, bool preserve_keys]])
    2447             :    Returns elements specified by offset and length */
    2448         376 : PHP_FUNCTION(array_slice)
    2449             : {
    2450             :         zval     *input,                /* Input array */
    2451         376 :                          *z_length = NULL, /* How many elements to get */
    2452             :                          *entry;                /* An array entry */
    2453             :         zend_long        offset,                /* Offset to get elements from */
    2454         376 :                          length = 0;
    2455         376 :         zend_bool preserve_keys = 0; /* Whether to preserve keys while copying to the new array or not */
    2456             :         int              num_in,                /* Number of elements in the input array */
    2457             :                          pos;                   /* Current position in the array */
    2458             :         zend_string *string_key;
    2459             :         zend_ulong num_key;
    2460             : 
    2461             : #ifndef FAST_ZPP
    2462             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "al|zb", &input, &offset, &z_length, &preserve_keys) == FAILURE) {
    2463             :                 return;
    2464             :         }
    2465             : #else
    2466         376 :         ZEND_PARSE_PARAMETERS_START(2, 4)
    2467        1113 :                 Z_PARAM_ARRAY(input)
    2468        1035 :                 Z_PARAM_LONG(offset)
    2469         345 :                 Z_PARAM_OPTIONAL
    2470         345 :                 Z_PARAM_ZVAL(z_length)
    2471         597 :                 Z_PARAM_BOOL(preserve_keys)
    2472         376 :         ZEND_PARSE_PARAMETERS_END();
    2473             : #endif
    2474             : 
    2475             :         /* Get number of entries in the input hash */
    2476         343 :         num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
    2477             : 
    2478             :         /* We want all entries from offset to the end if length is not passed or is null */
    2479         696 :         if (ZEND_NUM_ARGS() < 3 || Z_TYPE_P(z_length) == IS_NULL) {
    2480          62 :                 length = num_in;
    2481             :         } else {
    2482         562 :                 length = zval_get_long(z_length);
    2483             :         }
    2484             : 
    2485             :         /* Clamp the offset.. */
    2486         343 :         if (offset > num_in) {
    2487          11 :                 array_init(return_value);
    2488          11 :                 return;
    2489         332 :         } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
    2490          10 :                 offset = 0;
    2491             :         }
    2492             : 
    2493             :         /* ..and the length */
    2494         332 :         if (length < 0) {
    2495          71 :                 length = num_in - offset + length;
    2496         261 :         } else if (((zend_ulong) offset + (zend_ulong) length) > (unsigned) num_in) {
    2497          95 :                 length = num_in - offset;
    2498             :         }
    2499             : 
    2500         332 :         if (length <= 0) {
    2501         117 :                 array_init(return_value);
    2502         117 :                 return;
    2503             :         }
    2504             : 
    2505             :         /* Initialize returned array */
    2506         215 :         array_init_size(return_value, (uint32_t)length);
    2507             : 
    2508             :         /* Start at the beginning and go until we hit offset */
    2509         215 :         pos = 0;
    2510         278 :         if (!preserve_keys && (Z_ARRVAL_P(input)->u.flags & HASH_FLAG_PACKED)) {
    2511          63 :                 zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    2512          63 :                 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2513         665 :                         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
    2514         298 :                                 pos++;
    2515         298 :                                 if (pos <= offset) {
    2516          80 :                                         continue;
    2517             :                                 }
    2518         218 :                                 if (pos > offset + length) {
    2519          26 :                                         break;
    2520             :                                 }
    2521         192 :                                 ZEND_HASH_FILL_ADD(entry);
    2522         192 :                                 zval_add_ref(entry);
    2523             :                         } ZEND_HASH_FOREACH_END();
    2524          63 :                 } ZEND_HASH_FILL_END();
    2525             :         } else {
    2526        1361 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, string_key, entry) {
    2527         630 :                         pos++;
    2528         630 :                         if (pos <= offset) {
    2529         149 :                                 continue;
    2530             :                         }
    2531         481 :                         if (pos > offset + length) {
    2532          71 :                                 break;
    2533             :                         }
    2534             : 
    2535         410 :                         if (string_key) {
    2536         136 :                                 entry = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, entry);
    2537             :                         } else {
    2538         274 :                                 if (preserve_keys) {
    2539         150 :                                         entry = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, entry);
    2540             :                                 } else {
    2541         124 :                                         entry = zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), entry);
    2542             :                                 }
    2543             :                         }
    2544         410 :                         zval_add_ref(entry);
    2545             :                 } ZEND_HASH_FOREACH_END();
    2546             :         }
    2547             : }
    2548             : /* }}} */
    2549             : 
    2550          82 : PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */
    2551             : {
    2552             :         zval *src_entry, *dest_entry;
    2553             :         zend_string *string_key;
    2554             : 
    2555         530 :         ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
    2556         229 :                 if (string_key) {
    2557         115 :                         if ((dest_entry = zend_hash_find(dest, string_key)) != NULL) {
    2558          38 :                                 zval *src_zval = src_entry;
    2559          38 :                                 zval *dest_zval = dest_entry;
    2560             :                                 HashTable *thash;
    2561             :                                 zval tmp;
    2562             :                                 int ret;
    2563             : 
    2564          38 :                                 ZVAL_DEREF(src_zval);
    2565          38 :                                 ZVAL_DEREF(dest_zval);
    2566          38 :                                 thash = Z_TYPE_P(dest_zval) == IS_ARRAY ? Z_ARRVAL_P(dest_zval) : NULL;
    2567          38 :                                 if ((thash && thash->u.v.nApplyCount > 1) || (src_entry == dest_entry && Z_ISREF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
    2568           2 :                                         php_error_docref(NULL, E_WARNING, "recursion detected");
    2569           2 :                                         return 0;
    2570             :                                 }
    2571             : 
    2572          36 :                                 if (Z_ISREF_P(dest_entry)) {
    2573           5 :                                         if (Z_REFCOUNT_P(dest_entry) == 1) {
    2574           0 :                                                 ZVAL_UNREF(dest_entry);
    2575             :                                         } else {
    2576             :                                                 Z_DELREF_P(dest_entry);
    2577           5 :                                                 ZVAL_DUP(dest_entry, dest_zval);
    2578             :                                         }
    2579           5 :                                         dest_zval = dest_entry;
    2580             :                                 } else {
    2581          73 :                                         SEPARATE_ZVAL(dest_zval);
    2582             :                                 }
    2583          36 :                                 if (Z_TYPE_P(dest_zval) == IS_NULL) {
    2584           2 :                                         convert_to_array_ex(dest_zval);
    2585           2 :                                         add_next_index_null(dest_zval);
    2586             :                                 } else {
    2587          43 :                                         convert_to_array_ex(dest_zval);
    2588             :                                 }
    2589          36 :                                 ZVAL_UNDEF(&tmp);
    2590          36 :                                 if (Z_TYPE_P(src_zval) == IS_OBJECT) {
    2591           0 :                                         ZVAL_DUP(&tmp, src_zval);
    2592           0 :                                         convert_to_array(&tmp);
    2593           0 :                                         src_zval = &tmp;
    2594             :                                 }
    2595          36 :                                 if (Z_TYPE_P(src_zval) == IS_ARRAY) {
    2596          18 :                                         if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
    2597          16 :                                                 thash->u.v.nApplyCount++;
    2598             :                                         }
    2599          18 :                                         ret = php_array_merge_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval));
    2600          18 :                                         if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
    2601          16 :                                                 thash->u.v.nApplyCount--;
    2602             :                                         }
    2603          18 :                                         if (!ret) {
    2604           8 :                                                 return 0;
    2605             :                                         }
    2606             :                                 } else {
    2607          18 :                                         if (Z_REFCOUNTED_P(src_entry)) {
    2608             :                                                 Z_ADDREF_P(src_entry);
    2609             :                                         }
    2610          18 :                                         zend_hash_next_index_insert(Z_ARRVAL_P(dest_zval), src_zval);
    2611             :                                 }
    2612          28 :                                 zval_ptr_dtor(&tmp);
    2613             :                         } else {
    2614          77 :                                 if (Z_REFCOUNTED_P(src_entry)) {
    2615             :                                         Z_ADDREF_P(src_entry);
    2616             :                                 }
    2617          77 :                                 zend_hash_add_new(dest, string_key, src_entry);
    2618             :                         }
    2619             :                 } else {
    2620         114 :                         if (Z_REFCOUNTED_P(src_entry)) {
    2621             :                                 Z_ADDREF_P(src_entry);
    2622             :                         }
    2623         114 :                         zend_hash_next_index_insert_new(dest, src_entry);
    2624             :                 }
    2625             :         } ZEND_HASH_FOREACH_END();
    2626          72 :         return 1;
    2627             : }
    2628             : /* }}} */
    2629             : 
    2630         194 : PHPAPI int php_array_merge(HashTable *dest, HashTable *src) /* {{{ */
    2631             : {
    2632             :         zval *src_entry;
    2633             :         zend_string *string_key;
    2634             : 
    2635       31596 :         ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
    2636       15689 :                 if (string_key) {
    2637         117 :                         if (Z_REFCOUNTED_P(src_entry)) {
    2638             :                                 Z_ADDREF_P(src_entry);
    2639             :                         }
    2640         117 :                         zend_hash_update(dest, string_key, src_entry);
    2641             :                 } else {
    2642       15572 :                         if (Z_REFCOUNTED_P(src_entry)) {
    2643             :                                 Z_ADDREF_P(src_entry);
    2644             :                         }
    2645       15572 :                         zend_hash_next_index_insert_new(dest, src_entry);
    2646             :                 }
    2647             :         } ZEND_HASH_FOREACH_END();
    2648         194 :         return 1;
    2649             : }
    2650             : /* }}} */
    2651             : 
    2652           5 : PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ */
    2653             : {
    2654             :         zval *src_entry, *dest_entry, *src_zval, *dest_zval;
    2655             :         zend_string *string_key;
    2656             :         zend_ulong num_key;
    2657             :         int ret;
    2658             : 
    2659          16 :         ZEND_HASH_FOREACH_KEY_VAL(src, num_key, string_key, src_entry) {
    2660           7 :                 src_zval = src_entry;
    2661           7 :                 ZVAL_DEREF(src_zval);
    2662           7 :                 if (string_key) {
    2663           6 :                         if (Z_TYPE_P(src_zval) != IS_ARRAY ||
    2664           2 :                                 (dest_entry = zend_hash_find(dest, string_key)) == NULL ||
    2665             :                                 (Z_TYPE_P(dest_entry) != IS_ARRAY &&
    2666           0 :                                  (!Z_ISREF_P(dest_entry) || Z_TYPE_P(Z_REFVAL_P(dest_entry)) != IS_ARRAY))) {
    2667             : 
    2668           2 :                                 if (Z_REFCOUNTED_P(src_entry)) {
    2669             :                                         Z_ADDREF_P(src_entry);
    2670             :                                 }
    2671           2 :                                 zend_hash_update(dest, string_key, src_entry);
    2672             : 
    2673           2 :                                 continue;
    2674             :                         }
    2675             :                 } else {
    2676          10 :                         if (Z_TYPE_P(src_zval) != IS_ARRAY ||
    2677           3 :                                 (dest_entry = zend_hash_index_find(dest, num_key)) == NULL ||
    2678             :                                 (Z_TYPE_P(dest_entry) != IS_ARRAY &&
    2679           0 :                                  (!Z_ISREF_P(dest_entry) || Z_TYPE_P(Z_REFVAL_P(dest_entry)) != IS_ARRAY))) {
    2680             : 
    2681           1 :                                 if (Z_REFCOUNTED_P(src_entry)) {
    2682             :                                         Z_ADDREF_P(src_entry);
    2683             :                                 }
    2684           1 :                                 zend_hash_index_update(dest, num_key, src_entry);
    2685             : 
    2686           1 :                                 continue;
    2687             :                         }
    2688             :                 }
    2689             : 
    2690           4 :                 dest_zval = dest_entry;
    2691           4 :                 ZVAL_DEREF(dest_zval);
    2692          13 :                 if (Z_ARRVAL_P(dest_zval)->u.v.nApplyCount > 1 ||
    2693           4 :                     Z_ARRVAL_P(src_zval)->u.v.nApplyCount > 1 ||
    2694           0 :                     (Z_ISREF_P(src_entry) && Z_ISREF_P(dest_entry) && Z_REF_P(src_entry) == Z_REF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
    2695           1 :                         php_error_docref(NULL, E_WARNING, "recursion detected");
    2696           1 :                         return 0;
    2697             :                 }
    2698           9 :                 SEPARATE_ZVAL(dest_zval);
    2699             : 
    2700           3 :                 if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(dest_zval))) {
    2701           3 :                         Z_ARRVAL_P(dest_zval)->u.v.nApplyCount++;
    2702             :                 }
    2703           3 :                 if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(src_zval))) {
    2704           3 :                         Z_ARRVAL_P(src_zval)->u.v.nApplyCount++;
    2705             :                 }
    2706             : 
    2707           3 :                 ret = php_array_replace_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval));
    2708             : 
    2709           3 :                 if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(dest_zval))) {
    2710           3 :                         Z_ARRVAL_P(dest_zval)->u.v.nApplyCount--;
    2711             :                 }
    2712           3 :                 if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(src_zval))) {
    2713           3 :                         Z_ARRVAL_P(src_zval)->u.v.nApplyCount--;
    2714             :                 }
    2715             : 
    2716           3 :                 if (!ret) {
    2717           2 :                         return 0;
    2718             :                 }
    2719             :         } ZEND_HASH_FOREACH_END();
    2720             : 
    2721           2 :         return 1;
    2722             : }
    2723             : /* }}} */
    2724             : 
    2725         428 : static void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive, int replace) /* {{{ */
    2726             : {
    2727         428 :         zval *args = NULL;
    2728             :         zval *arg;
    2729         428 :         int argc, i, init_size = 0;
    2730             : 
    2731             : #ifndef FAST_ZPP
    2732             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    2733             :                 return;
    2734             :         }
    2735             : #else
    2736         428 :         ZEND_PARSE_PARAMETERS_START(1, -1)
    2737         425 :                 Z_PARAM_VARIADIC('+', args, argc)
    2738         428 :         ZEND_PARSE_PARAMETERS_END();
    2739             : #endif
    2740             : 
    2741        1040 :         for (i = 0; i < argc; i++) {
    2742         738 :                 zval *arg = args + i;
    2743             : 
    2744         738 :                 ZVAL_DEREF(arg);
    2745         738 :                 if (Z_TYPE_P(arg) != IS_ARRAY) {
    2746         123 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    2747         123 :                         RETURN_NULL();
    2748             :                 } else {
    2749         615 :                         int num = zend_hash_num_elements(Z_ARRVAL_P(arg));
    2750             : 
    2751         615 :                         if (num > init_size) {
    2752         445 :                                 init_size = num;
    2753             :                         }
    2754             :                 }
    2755             :         }
    2756             : 
    2757         302 :         array_init_size(return_value, init_size);
    2758             : 
    2759         302 :         if (replace) {
    2760             :                 zend_string *string_key;
    2761             :                 zval *src_entry;
    2762             :                 zend_ulong idx;
    2763             :                 HashTable *src, *dest;
    2764             : 
    2765             :                 /* copy first array */
    2766           3 :                 arg = args;
    2767           3 :                 ZVAL_DEREF(arg);
    2768           3 :                 src  = Z_ARRVAL_P(arg);
    2769           3 :                 dest = Z_ARRVAL_P(return_value);
    2770          21 :                 ZEND_HASH_FOREACH_KEY_VAL(src, idx, string_key, src_entry) {
    2771           9 :                         if (string_key) {
    2772           4 :                                 if (Z_REFCOUNTED_P(src_entry)) {
    2773             :                                         Z_ADDREF_P(src_entry);
    2774             :                                 }
    2775           4 :                                 zend_hash_add_new(dest, string_key, src_entry);
    2776             :                         } else {
    2777           5 :                                 if (Z_REFCOUNTED_P(src_entry)) {
    2778             :                                         Z_ADDREF_P(src_entry);
    2779             :                                 }
    2780           5 :                                 zend_hash_index_add_new(dest, idx, src_entry);
    2781             :                         }
    2782             :                 } ZEND_HASH_FOREACH_END();
    2783             : 
    2784           3 :                 if (recursive) {
    2785           4 :                         for (i = 1; i < argc; i++) {
    2786           2 :                                 arg = args + i;
    2787           2 :                                 ZVAL_DEREF(arg);
    2788           2 :                                 php_array_replace_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg));
    2789             :                         }
    2790             :                 } else {
    2791           2 :                         for (i = 1; i < argc; i++) {
    2792           1 :                                 arg = args + i;
    2793           1 :                                 ZVAL_DEREF(arg);
    2794           1 :                                 zend_hash_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg), zval_add_ref, 1);
    2795             :                         }
    2796             :                 }
    2797             :         } else {
    2798             :                 zend_string *string_key;
    2799             :                 zval *src_entry;
    2800             :                 HashTable *src, *dest;
    2801             : 
    2802             :                 /* copy first array */
    2803         299 :                 arg = args;
    2804         299 :                 ZVAL_DEREF(arg);
    2805         299 :                 src  = Z_ARRVAL_P(arg);
    2806         299 :                 dest = Z_ARRVAL_P(return_value);
    2807       15849 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
    2808        7753 :                         if (string_key) {
    2809         739 :                                 if (Z_REFCOUNTED_P(src_entry)) {
    2810             :                                         Z_ADDREF_P(src_entry);
    2811             :                                 }
    2812         739 :                                 zend_hash_add_new(dest, string_key, src_entry);
    2813             :                         } else {
    2814        7014 :                                 if (Z_REFCOUNTED_P(src_entry)) {
    2815             :                                         Z_ADDREF_P(src_entry);
    2816             :                                 }
    2817        7014 :                                 zend_hash_next_index_insert_new(dest, src_entry);
    2818             :                         }
    2819             :                 } ZEND_HASH_FOREACH_END();
    2820             : 
    2821         299 :                 if (recursive) {
    2822         169 :                         for (i = 1; i < argc; i++) {
    2823          64 :                                 arg = args + i;
    2824          64 :                                 ZVAL_DEREF(arg);
    2825          64 :                                 php_array_merge_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg));
    2826             :                         }
    2827             :                 } else {
    2828         388 :                         for (i = 1; i < argc; i++) {
    2829         194 :                                 arg = args + i;
    2830         194 :                                 ZVAL_DEREF(arg);
    2831         194 :                                 php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg));
    2832             :                         }
    2833             :                 }
    2834             :         }
    2835             : }
    2836             : /* }}} */
    2837             : 
    2838             : /* {{{ proto array array_merge(array arr1, array arr2 [, array ...])
    2839             :    Merges elements from passed arrays into one array */
    2840         247 : PHP_FUNCTION(array_merge)
    2841             : {
    2842         247 :         php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
    2843         247 : }
    2844             : /* }}} */
    2845             : 
    2846             : /* {{{ proto array array_merge_recursive(array arr1, array arr2 [, array ...])
    2847             :    Recursively merges elements from passed arrays into one array */
    2848         178 : PHP_FUNCTION(array_merge_recursive)
    2849             : {
    2850         178 :         php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
    2851         178 : }
    2852             : /* }}} */
    2853             : 
    2854             : /* {{{ proto array array_replace(array arr1, array arr2 [, array ...])
    2855             :    Replaces elements from passed arrays into one array */
    2856           1 : PHP_FUNCTION(array_replace)
    2857             : {
    2858           1 :         php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
    2859           1 : }
    2860             : /* }}} */
    2861             : 
    2862             : /* {{{ proto array array_replace_recursive(array arr1, array arr2 [, array ...])
    2863             :    Recursively replaces elements from passed arrays into one array */
    2864           2 : PHP_FUNCTION(array_replace_recursive)
    2865             : {
    2866           2 :         php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1);
    2867           2 : }
    2868             : /* }}} */
    2869             : 
    2870             : /* {{{ proto array array_keys(array input [, mixed search_value[, bool strict]])
    2871             :    Return just the keys from the input array, optionally only for the specified search_value */
    2872         469 : PHP_FUNCTION(array_keys)
    2873             : {
    2874             :         zval *input,                            /* Input array */
    2875         469 :              *search_value = NULL,      /* Value to search for */
    2876             :              *entry,                            /* An entry in the input array */
    2877             :                new_val;                         /* New value */
    2878         469 :         zend_bool strict = 0;           /* do strict comparison */
    2879             :         zend_ulong num_idx;
    2880             :         zend_string *str_idx;
    2881             : 
    2882             : #ifndef FAST_ZPP
    2883             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|zb", &input, &search_value, &strict) == FAILURE) {
    2884             :                 return;
    2885             :         }
    2886             : #else
    2887         469 :         ZEND_PARSE_PARAMETERS_START(1, 3)
    2888        1401 :                 Z_PARAM_ARRAY(input)
    2889         464 :                 Z_PARAM_OPTIONAL
    2890         464 :                 Z_PARAM_ZVAL(search_value)
    2891          56 :                 Z_PARAM_BOOL(strict)
    2892         469 :         ZEND_PARSE_PARAMETERS_END();
    2893             : #endif
    2894             : 
    2895             :         /* Initialize return array */
    2896         464 :         if (search_value != NULL) {
    2897          28 :                 array_init(return_value);
    2898             : 
    2899          28 :                 if (strict) {
    2900         278 :                         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
    2901         176 :                                 if (fast_is_identical_function(search_value, entry)) {
    2902           9 :                                         if (str_idx) {
    2903           2 :                                                 ZVAL_STR_COPY(&new_val, str_idx);
    2904             :                                         } else {
    2905           7 :                                                 ZVAL_LONG(&new_val, num_idx);
    2906             :                                         }
    2907           9 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
    2908             :                                 }
    2909             :                         } ZEND_HASH_FOREACH_END();
    2910             :                 } else {
    2911         278 :                         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
    2912         176 :                                 if (fast_equal_check_function(search_value, entry)) {
    2913          26 :                                         if (str_idx) {
    2914           7 :                                                 ZVAL_STR_COPY(&new_val, str_idx);
    2915             :                                         } else {
    2916          19 :                                                 ZVAL_LONG(&new_val, num_idx);
    2917             :                                         }
    2918          26 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
    2919             :                                 }
    2920             :                         } ZEND_HASH_FOREACH_END();
    2921             :                 }
    2922             :         } else {
    2923         436 :                 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
    2924         436 :                 zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    2925         436 :                 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2926             :                         /* Go through input array and add keys to the return array */
    2927       20905 :                         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
    2928        6818 :                                 if (str_idx) {
    2929        4920 :                                         ZVAL_STR_COPY(&new_val, str_idx);
    2930             :                                 } else {
    2931        1898 :                                         ZVAL_LONG(&new_val, num_idx);
    2932             :                                 }
    2933        6818 :                                 ZEND_HASH_FILL_ADD(&new_val);
    2934             :                         } ZEND_HASH_FOREACH_END();
    2935         436 :                 } ZEND_HASH_FILL_END();
    2936             :         }
    2937             : }
    2938             : /* }}} */
    2939             : 
    2940             : /* {{{ proto array array_values(array input)
    2941             :    Return just the values from the input array */
    2942          91 : PHP_FUNCTION(array_values)
    2943             : {
    2944             :         zval     *input,                /* Input array */
    2945             :                          *entry;                /* An entry in the input array */
    2946             : 
    2947             : #ifndef FAST_ZPP
    2948             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &input) == FAILURE) {
    2949             :                 return;
    2950             :         }
    2951             : #else
    2952          91 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    2953         261 :                 Z_PARAM_ARRAY(input)
    2954          91 :         ZEND_PARSE_PARAMETERS_END();
    2955             : #endif
    2956             : 
    2957             :         /* Initialize return array */
    2958          60 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
    2959          60 :         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    2960             : 
    2961             :         /* Go through input array and add values to the return array */
    2962          60 :         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2963         400 :                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
    2964         178 :                         if (Z_ISREF_P(entry) && Z_REFCOUNT_P(entry) == 1) {
    2965           3 :                                 entry = Z_REFVAL_P(entry);
    2966             :                         }
    2967         170 :                         Z_TRY_ADDREF_P(entry);
    2968         170 :                         ZEND_HASH_FILL_ADD(entry);
    2969             :                 } ZEND_HASH_FOREACH_END();
    2970          60 :         } ZEND_HASH_FILL_END();
    2971             : }
    2972             : /* }}} */
    2973             : 
    2974             : /* {{{ proto array array_count_values(array input)
    2975             :    Return the value as key and the frequency of that value in input as value */
    2976          20 : PHP_FUNCTION(array_count_values)
    2977             : {
    2978             :         zval    *input,         /* Input array */
    2979             :                         *entry,         /* An entry in the input array */
    2980             :                         *tmp;
    2981             :         HashTable *myht;
    2982             : 
    2983          20 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &input) == FAILURE) {
    2984           3 :                 return;
    2985             :         }
    2986             : 
    2987             :         /* Initialize return array */
    2988          17 :         array_init(return_value);
    2989             : 
    2990             :         /* Go through input array and add values to the return array */
    2991          17 :         myht = Z_ARRVAL_P(input);
    2992         135 :         ZEND_HASH_FOREACH_VAL(myht, entry) {
    2993          59 :                 ZVAL_DEREF(entry);
    2994          59 :                 if (Z_TYPE_P(entry) == IS_LONG) {
    2995          17 :                         if ((tmp = zend_hash_index_find(Z_ARRVAL_P(return_value), Z_LVAL_P(entry))) == NULL) {
    2996             :                                 zval data;
    2997          13 :                                 ZVAL_LONG(&data, 1);
    2998          13 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_P(entry), &data);
    2999             :                         } else {
    3000           4 :                                 Z_LVAL_P(tmp)++;
    3001             :                         }
    3002          42 :                 } else if (Z_TYPE_P(entry) == IS_STRING) {
    3003          66 :                         if ((tmp = zend_symtable_find(Z_ARRVAL_P(return_value), Z_STR_P(entry))) == NULL) {
    3004             :                                 zval data;
    3005          24 :                                 ZVAL_LONG(&data, 1);
    3006          24 :                                 zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
    3007             :                         } else {
    3008           9 :                                 Z_LVAL_P(tmp)++;
    3009             :                         }
    3010             :                 } else {
    3011           9 :                         php_error_docref(NULL, E_WARNING, "Can only count STRING and INTEGER values!");
    3012             :                 }
    3013             :         } ZEND_HASH_FOREACH_END();
    3014             : }
    3015             : /* }}} */
    3016             : 
    3017             : /* {{{ array_column_param_helper
    3018             :  * Specialized conversion rules for array_column() function
    3019             :  */
    3020             : static inline
    3021          45 : zend_bool array_column_param_helper(zval *param,
    3022             :                                     const char *name) {
    3023          45 :         switch (Z_TYPE_P(param)) {
    3024             :                 case IS_DOUBLE:
    3025           2 :                         convert_to_long_ex(param);
    3026             :                         /* fallthrough */
    3027             :                 case IS_LONG:
    3028          11 :                         return 1;
    3029             : 
    3030             :                 case IS_OBJECT:
    3031          10 :                         convert_to_string_ex(param);
    3032             :                         /* fallthrough */
    3033             :                 case IS_STRING:
    3034          30 :                         return 1;
    3035             : 
    3036             :                 default:
    3037           4 :                         php_error_docref(NULL, E_WARNING, "The %s key should be either a string or an integer", name);
    3038           4 :                         return 0;
    3039             :         }
    3040             : }
    3041             : /* }}} */
    3042             : 
    3043             : /* {{{ proto array array_column(array input, mixed column_key[, mixed index_key])
    3044             :    Return the values from a single column in the input array, identified by the
    3045             :    value_key and optionally indexed by the index_key */
    3046          35 : PHP_FUNCTION(array_column)
    3047             : {
    3048          35 :         zval *zcolumn = NULL, *zkey = NULL, *data;
    3049             :         HashTable *arr_hash;
    3050          35 :         zval *zcolval = NULL, *zkeyval = NULL;
    3051             :         HashTable *ht;
    3052             : 
    3053          35 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "hz!|z!", &arr_hash, &zcolumn, &zkey) == FAILURE) {
    3054           4 :                 return;
    3055             :         }
    3056             : 
    3057          77 :         if ((zcolumn && !array_column_param_helper(zcolumn, "column")) ||
    3058          46 :             (zkey && !array_column_param_helper(zkey, "index"))) {
    3059           4 :                 RETURN_FALSE;
    3060             :         }
    3061             : 
    3062          27 :         array_init(return_value);
    3063         201 :         ZEND_HASH_FOREACH_VAL(arr_hash, data) {
    3064          87 :                 if (Z_TYPE_P(data) != IS_ARRAY) {
    3065             :                         /* Skip elemens which are not sub-arrays */
    3066           3 :                         continue;
    3067             :                 }
    3068          84 :                 ht = Z_ARRVAL_P(data);
    3069             : 
    3070          84 :                 if (!zcolumn) {
    3071             :                         /* NULL column ID means use entire subarray as data */
    3072           6 :                         zcolval = data;
    3073             : 
    3074             :                         /* Otherwise, skip if the value doesn't exist in our subarray */
    3075         213 :                 } else if ((Z_TYPE_P(zcolumn) == IS_STRING) &&
    3076          57 :                     ((zcolval = zend_hash_find(ht, Z_STR_P(zcolumn))) == NULL)) {
    3077           9 :                         continue;
    3078         159 :                 } else if ((Z_TYPE_P(zcolumn) == IS_LONG) &&
    3079          21 :                     ((zcolval = zend_hash_index_find(ht, Z_LVAL_P(zcolumn))) == NULL)) {
    3080           6 :                         continue;
    3081             :                 }
    3082             : 
    3083             :                 /* Failure will leave zkeyval alone which will land us on the final else block below
    3084             :                  * which is to append the value as next_index
    3085             :                  */
    3086         148 :                 if (zkey && (Z_TYPE_P(zkey) == IS_STRING)) {
    3087          35 :                         zkeyval = zend_hash_find(ht, Z_STR_P(zkey));
    3088          43 :                 } else if (zkey && (Z_TYPE_P(zkey) == IS_LONG)) {
    3089           9 :                         zkeyval = zend_hash_index_find(ht, Z_LVAL_P(zkey));
    3090             :                 }
    3091             : 
    3092          69 :                 if (Z_REFCOUNTED_P(zcolval)) {
    3093             :                         Z_ADDREF_P(zcolval);
    3094             :                 }
    3095         124 :                 if (zkeyval && Z_TYPE_P(zkeyval) == IS_STRING) {
    3096          21 :                         zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(zkeyval), zcolval);
    3097          73 :                 } else if (zkeyval && Z_TYPE_P(zkeyval) == IS_LONG) {
    3098          12 :                         add_index_zval(return_value, Z_LVAL_P(zkeyval), zcolval);
    3099          38 :                 } else if (zkeyval && Z_TYPE_P(zkeyval) == IS_OBJECT) {
    3100           3 :                         SEPARATE_ZVAL(zkeyval);
    3101           1 :                         convert_to_string(zkeyval);
    3102           1 :                         zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(zkeyval), zcolval);
    3103             :                 } else {
    3104          35 :                         add_next_index_zval(return_value, zcolval);
    3105             :                 }
    3106             :         } ZEND_HASH_FOREACH_END();
    3107             : }
    3108             : /* }}} */
    3109             : 
    3110             : /* {{{ proto array array_reverse(array input [, bool preserve keys])
    3111             :    Return input as a new array with the order of the entries reversed */
    3112         235 : PHP_FUNCTION(array_reverse)
    3113             : {
    3114             :         zval     *input,                                /* Input array */
    3115             :                          *entry;                                /* An entry in the input array */
    3116             :         zend_string *string_key;
    3117             :         zend_ulong        num_key;
    3118         235 :         zend_bool preserve_keys = 0;    /* whether to preserve keys */
    3119             : 
    3120         235 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|b", &input, &preserve_keys) == FAILURE) {
    3121          82 :                 return;
    3122             :         }
    3123             : 
    3124             :         /* Initialize return array */
    3125         153 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
    3126             : 
    3127        1227 :         ZEND_HASH_REVERSE_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, string_key, entry) {
    3128         516 :                 if (string_key) {
    3129         175 :                         entry = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, entry);
    3130             :                 } else {
    3131         341 :                         if (preserve_keys) {
    3132         129 :                                 entry = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, entry);
    3133             :                         } else {
    3134         212 :                                 entry = zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), entry);
    3135             :                         }
    3136             :                 }
    3137             : 
    3138         516 :                 zval_add_ref(entry);
    3139             :         } ZEND_HASH_FOREACH_END();
    3140             : }
    3141             : /* }}} */
    3142             : 
    3143             : /* {{{ proto array array_pad(array input, int pad_size, mixed pad_value)
    3144             :    Returns a copy of input array padded with pad_value to size pad_size */
    3145         199 : PHP_FUNCTION(array_pad)
    3146             : {
    3147             :         zval  *input;           /* Input array */
    3148             :         zval  *pad_value;       /* Padding value obviously */
    3149             :         zend_long pad_size;             /* Size to pad to */
    3150             :         zend_long pad_size_abs; /* Absolute value of pad_size */
    3151             :         zend_long input_size;           /* Size of the input array */
    3152             :         zend_long num_pads;             /* How many pads do we need */
    3153             :         zend_long i;
    3154             :         zend_string *key;
    3155             :         zval *value;
    3156             : 
    3157         199 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "alz", &input, &pad_size, &pad_value) == FAILURE) {
    3158          66 :                 return;
    3159             :         }
    3160             : 
    3161             :         /* Do some initial calculations */
    3162         133 :         input_size = zend_hash_num_elements(Z_ARRVAL_P(input));
    3163         133 :         pad_size_abs = ZEND_ABS(pad_size);
    3164         133 :         if (pad_size_abs < 0 || pad_size_abs - input_size > Z_L(1048576)) {
    3165           3 :                 php_error_docref(NULL, E_WARNING, "You may only pad up to 1048576 elements at a time");
    3166           3 :                 RETURN_FALSE;
    3167             :         }
    3168             : 
    3169         130 :         if (input_size >= pad_size_abs) {
    3170             :                 /* Copy the original array */
    3171          15 :                 ZVAL_COPY(return_value, input);
    3172          15 :                 return;
    3173             :         }
    3174             : 
    3175         115 :         num_pads = pad_size_abs - input_size;
    3176         115 :         array_init_size(return_value, pad_size_abs);
    3177         115 :         if (Z_REFCOUNTED_P(pad_value)) {
    3178          18 :                 GC_REFCOUNT(Z_COUNTED_P(pad_value)) += num_pads;
    3179             :         }
    3180             : 
    3181         115 :         if (pad_size < 0) {
    3182         198 :                 for (i = 0; i < num_pads; i++) {
    3183         141 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), pad_value);
    3184             :                 }
    3185             :         }
    3186             : 
    3187         916 :         ZEND_HASH_FOREACH_STR_KEY_VAL_IND(Z_ARRVAL_P(input), key, value) {
    3188         265 :                 if (Z_REFCOUNTED_P(value)) {
    3189             :                         Z_ADDREF_P(value);
    3190             :                 }
    3191         265 :                 if (key) {
    3192          44 :                         zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
    3193             :                 } else {
    3194         221 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), value);
    3195             :                 }
    3196             :         } ZEND_HASH_FOREACH_END();
    3197             : 
    3198         115 :         if (pad_size > 0) {
    3199         202 :                 for (i = 0; i < num_pads; i++) {
    3200         144 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), pad_value);
    3201             :                 }
    3202             :         }
    3203             : }
    3204             : /* }}} */
    3205             : 
    3206             : /* {{{ proto array array_flip(array input)
    3207             :    Return array with key <-> value flipped */
    3208          69 : PHP_FUNCTION(array_flip)
    3209             : {
    3210             :         zval *array, *entry, data;
    3211             :         zend_ulong num_idx;
    3212             :         zend_string *str_idx;
    3213             : 
    3214          69 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &array) == FAILURE) {
    3215          25 :                 return;
    3216             :         }
    3217             : 
    3218          44 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
    3219             : 
    3220         402 :         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    3221         177 :                 ZVAL_DEREF(entry);
    3222         177 :                 if (Z_TYPE_P(entry) == IS_LONG) {
    3223          80 :                         if (str_idx) {
    3224          17 :                                 ZVAL_STR_COPY(&data, str_idx);
    3225             :                         } else {
    3226          63 :                                 ZVAL_LONG(&data, num_idx);
    3227             :                         }
    3228          80 :                         zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_P(entry), &data);
    3229          97 :                 } else if (Z_TYPE_P(entry) == IS_STRING) {
    3230          82 :                         if (str_idx) {
    3231          35 :                                 ZVAL_STR_COPY(&data, str_idx);
    3232             :                         } else {
    3233          47 :                                 ZVAL_LONG(&data, num_idx);
    3234             :                         }
    3235          82 :                         zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
    3236             :                 } else {
    3237          15 :                         php_error_docref(NULL, E_WARNING, "Can only flip STRING and INTEGER values!");
    3238             :                 }
    3239             :         } ZEND_HASH_FOREACH_END();
    3240             : }
    3241             : /* }}} */
    3242             : 
    3243             : /* {{{ proto array array_change_key_case(array input [, int case=CASE_LOWER])
    3244             :    Retuns an array with all string keys lowercased [or uppercased] */
    3245         200 : PHP_FUNCTION(array_change_key_case)
    3246             : {
    3247             :         zval *array, *entry;
    3248             :         zend_string *string_key;
    3249             :         zend_string *new_key;
    3250             :         zend_ulong num_key;
    3251         200 :         zend_long change_to_upper=0;
    3252             : 
    3253         200 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &array, &change_to_upper) == FAILURE) {
    3254          36 :                 return;
    3255             :         }
    3256             : 
    3257         164 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
    3258             : 
    3259         970 :         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, entry) {
    3260         403 :                 if (!string_key) {
    3261          64 :                         entry = zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry);
    3262             :                 } else {
    3263         339 :                         if (change_to_upper) {
    3264         166 :                                 new_key = php_string_toupper(string_key);
    3265             :                         } else {
    3266         173 :                                 new_key = php_string_tolower(string_key);
    3267             :                         }
    3268         339 :                         entry = zend_hash_update(Z_ARRVAL_P(return_value), new_key, entry);
    3269             :                         zend_string_release(new_key);
    3270             :                 }
    3271             : 
    3272         403 :                 zval_add_ref(entry);
    3273             :         } ZEND_HASH_FOREACH_END();
    3274             : }
    3275             : /* }}} */
    3276             : 
    3277             : struct bucketindex {
    3278             :         Bucket b;
    3279             :         unsigned int i;
    3280             : };
    3281             : 
    3282       64243 : static void array_bucketindex_swap(void *p, void *q) /* {{{ */
    3283             : {
    3284       64243 :         struct bucketindex *f = (struct bucketindex *)p;
    3285       64243 :         struct bucketindex *g = (struct bucketindex *)q;
    3286             :         struct bucketindex t;
    3287       64243 :         t = *f;
    3288       64243 :         *f = *g;
    3289       64243 :         *g = t;
    3290       64243 : }
    3291             : /* }}} */
    3292             : 
    3293             : /* {{{ proto array array_unique(array input [, int sort_flags])
    3294             :    Removes duplicate values from array */
    3295          72 : PHP_FUNCTION(array_unique)
    3296             : {
    3297             :         zval *array;
    3298             :         uint idx;
    3299             :         Bucket *p;
    3300             :         struct bucketindex *arTmp, *cmpdata, *lastkept;
    3301             :         unsigned int i;
    3302          72 :         zend_long sort_type = PHP_SORT_STRING;
    3303             : 
    3304          72 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &array, &sort_type) == FAILURE) {
    3305          27 :                 return;
    3306             :         }
    3307             : 
    3308          45 :         php_set_compare_func(sort_type);
    3309             : 
    3310          45 :         RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array)));
    3311             : 
    3312          45 :         if (Z_ARRVAL_P(array)->nNumOfElements <= 1) {     /* nothing to do */
    3313           2 :                 return;
    3314             :         }
    3315             : 
    3316             :         /* create and sort array with pointers to the target_hash buckets */
    3317          86 :         arTmp = (struct bucketindex *) pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), Z_ARRVAL_P(array)->u.flags & HASH_FLAG_PERSISTENT);
    3318          43 :         if (!arTmp) {
    3319             :                 zval_dtor(return_value);
    3320           0 :                 RETURN_FALSE;
    3321             :         }
    3322       13503 :         for (i = 0, idx = 0; idx < Z_ARRVAL_P(array)->nNumUsed; idx++) {
    3323       13460 :                 p = Z_ARRVAL_P(array)->arData + idx;
    3324       26920 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    3325       26906 :                 if (Z_TYPE(p->val) == IS_INDIRECT && Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF) continue;
    3326       13452 :                 arTmp[i].b = *p;
    3327       13452 :                 arTmp[i].i = i;
    3328       13452 :                 i++;
    3329             :         }
    3330          43 :         ZVAL_UNDEF(&arTmp[i].b.val);
    3331          43 :         zend_sort((void *) arTmp, i, sizeof(struct bucketindex),
    3332             :                         php_array_data_compare, (swap_func_t)array_bucketindex_swap);
    3333             :         /* go through the sorted array and delete duplicates from the copy */
    3334          43 :         lastkept = arTmp;
    3335       26904 :         for (cmpdata = arTmp + 1; Z_TYPE(cmpdata->b.val) != IS_UNDEF; cmpdata++) {
    3336       13409 :                 if (php_array_data_compare(lastkept, cmpdata)) {
    3337       13308 :                         lastkept = cmpdata;
    3338             :                 } else {
    3339         101 :                         if (lastkept->i > cmpdata->i) {
    3340          10 :                                 p = &lastkept->b;
    3341          10 :                                 lastkept = cmpdata;
    3342             :                         } else {
    3343          91 :                                 p = &cmpdata->b;
    3344             :                         }
    3345         101 :                         if (p->key == NULL) {
    3346          85 :                                 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    3347             :                         } else {
    3348          16 :                                 if (Z_ARRVAL_P(return_value) == &EG(symbol_table)) {
    3349           0 :                                         zend_delete_global_variable(p->key);
    3350             :                                 } else {
    3351          16 :                                         zend_hash_del(Z_ARRVAL_P(return_value), p->key);
    3352             :                                 }
    3353             :                         }
    3354             :                 }
    3355             :         }
    3356          43 :         pefree(arTmp, Z_ARRVAL_P(array)->u.flags & HASH_FLAG_PERSISTENT);
    3357             : }
    3358             : /* }}} */
    3359             : 
    3360        1106 : static int zval_compare(zval *first, zval *second) /* {{{ */
    3361             : {
    3362             :         zval result;
    3363             : 
    3364        1106 :         if (Z_TYPE_P(first) == IS_INDIRECT) {
    3365           2 :                 first = Z_INDIRECT_P(first);
    3366             :         }
    3367        1106 :         if (Z_TYPE_P(second) == IS_INDIRECT) {
    3368           2 :                 second = Z_INDIRECT_P(second);
    3369             :         }
    3370        1106 :         if (string_compare_function(&result, first, second) == FAILURE) {
    3371           0 :                 return 0;
    3372             :         }
    3373             : 
    3374        1106 :         if (Z_TYPE(result) == IS_DOUBLE) {
    3375           0 :                 return ZEND_NORMALIZE_BOOL(Z_DVAL(result));
    3376             :         }
    3377             : 
    3378        1106 :         convert_to_long(&result);
    3379        1106 :         return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
    3380             : }
    3381             : /* }}} */
    3382             : 
    3383          44 : static int zval_user_compare(zval *a, zval *b) /* {{{ */
    3384             : {
    3385             :         zval args[2];
    3386             :         zval retval;
    3387             : 
    3388          44 :         if (Z_TYPE_P(a) == IS_INDIRECT) {
    3389           0 :                 a = Z_INDIRECT_P(a);
    3390             :         }
    3391          44 :         if (Z_TYPE_P(b) == IS_INDIRECT) {
    3392           0 :                 b = Z_INDIRECT_P(b);
    3393             :         }
    3394             : 
    3395          44 :         ZVAL_COPY_VALUE(&args[0], a);
    3396          44 :         ZVAL_COPY_VALUE(&args[1], b);
    3397             : 
    3398          44 :         BG(user_compare_fci).param_count = 2;
    3399          44 :         BG(user_compare_fci).params = args;
    3400          44 :         BG(user_compare_fci).retval = &retval;
    3401          44 :         BG(user_compare_fci).no_separation = 0;
    3402             : 
    3403          88 :         if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
    3404          44 :                 zend_long ret = zval_get_long(&retval);
    3405          44 :                 zval_ptr_dtor(&retval);
    3406          44 :                 return ret < 0 ? -1 : ret > 0 ? 1 : 0;;
    3407             :         } else {
    3408           0 :                 return 0;
    3409             :         }
    3410             : }
    3411             : /* }}} */
    3412             : 
    3413         572 : static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type) /* {{{ */
    3414             : {
    3415             :     uint idx;
    3416             :         Bucket *p;
    3417             :         int argc, i;
    3418             :         zval *args;
    3419         572 :         int (*intersect_data_compare_func)(zval *, zval *) = NULL;
    3420             :         zend_bool ok;
    3421             :         zval *val, *data;
    3422             :         int req_args;
    3423             :         char *param_spec;
    3424             : 
    3425             :         /* Get the argument count */
    3426         572 :         argc = ZEND_NUM_ARGS();
    3427         572 :         if (data_compare_type == INTERSECT_COMP_DATA_USER) {
    3428             :                 /* INTERSECT_COMP_DATA_USER - array_uintersect_assoc() */
    3429         112 :                 req_args = 3;
    3430         112 :                 param_spec = "+f";
    3431         112 :                 intersect_data_compare_func = zval_user_compare;
    3432             :         } else {
    3433             :                 /*      INTERSECT_COMP_DATA_NONE - array_intersect_key()
    3434             :                         INTERSECT_COMP_DATA_INTERNAL - array_intersect_assoc() */
    3435         460 :                 req_args = 2;
    3436         460 :                 param_spec = "+";
    3437             : 
    3438         460 :                 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
    3439         279 :                         intersect_data_compare_func = zval_compare;
    3440             :                 }
    3441             :         }
    3442             : 
    3443         572 :         if (argc < req_args) {
    3444           5 :                 php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, argc);
    3445           5 :                 return;
    3446             :         }
    3447             : 
    3448         567 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
    3449          30 :                 return;
    3450             :         }
    3451             : 
    3452        1332 :         for (i = 0; i < argc; i++) {
    3453        2192 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    3454         301 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    3455         301 :                         RETURN_NULL();
    3456             :                 }
    3457             :         }
    3458             : 
    3459         236 :         array_init(return_value);
    3460             : 
    3461        2443 :         for (idx = 0; idx < Z_ARRVAL(args[0])->nNumUsed; idx++) {
    3462        2207 :                 p = Z_ARRVAL(args[0])->arData + idx;
    3463        2207 :                 val = &p->val;
    3464        2207 :                 if (Z_TYPE_P(val) == IS_UNDEF) continue;
    3465        2214 :                 if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) {
    3466          12 :                         ZVAL_UNREF(val);
    3467             :                 }
    3468        2193 :                 if (p->key == NULL) {
    3469        1141 :                         ok = 1;
    3470        1345 :                         for (i = 1; i < argc; i++) {
    3471        1562 :                                 if ((data = zend_hash_index_find(Z_ARRVAL(args[i]), p->h)) == NULL ||
    3472             :                                         (intersect_data_compare_func &&
    3473         354 :                                         intersect_data_compare_func(val, data) != 0)
    3474             :                                 ) {
    3475        1004 :                                         ok = 0;
    3476        1004 :                                         break;
    3477             :                                 }
    3478             :                         }
    3479        1141 :                         if (ok) {
    3480         137 :                                 if (Z_REFCOUNTED_P(val)) {
    3481             :                                         Z_ADDREF_P(val);
    3482             :                                 }
    3483         137 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), p->h, val);
    3484             :                         }
    3485             :                 } else {
    3486        1052 :                         ok = 1;
    3487        1191 :                         for (i = 1; i < argc; i++) {
    3488        1245 :                                 if ((data = zend_hash_find(Z_ARRVAL(args[i]), p->key)) == NULL ||
    3489             :                                         (intersect_data_compare_func &&
    3490         153 :                                         intersect_data_compare_func(val, data) != 0)
    3491             :                                 ) {
    3492         953 :                                         ok = 0;
    3493         953 :                                         break;
    3494             :                                 }
    3495             :                         }
    3496        1052 :                         if (ok) {
    3497          99 :                                 if (Z_REFCOUNTED_P(val)) {
    3498             :                                         Z_ADDREF_P(val);
    3499             :                                 }
    3500          99 :                                 zend_hash_update(Z_ARRVAL_P(return_value), p->key, val);
    3501             :                         }
    3502             :                 }
    3503             :         }
    3504             : }
    3505             : /* }}} */
    3506             : 
    3507         965 : static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type) /* {{{ */
    3508             : {
    3509         965 :         zval *args = NULL;
    3510             :         HashTable *hash;
    3511         965 :         int arr_argc, i, c = 0;
    3512             :         uint idx;
    3513             :         Bucket **lists, *list, **ptrs, *p;
    3514             :         uint32_t req_args;
    3515             :         char *param_spec;
    3516             :         zend_fcall_info fci1, fci2;
    3517         965 :         zend_fcall_info_cache fci1_cache = empty_fcall_info_cache, fci2_cache = empty_fcall_info_cache;
    3518         965 :         zend_fcall_info *fci_key = NULL, *fci_data;
    3519         965 :         zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache;
    3520             :         PHP_ARRAY_CMP_FUNC_VARS;
    3521             : 
    3522             :         int (*intersect_key_compare_func)(const void *, const void *);
    3523             :         int (*intersect_data_compare_func)(const void *, const void *);
    3524             : 
    3525         965 :         if (behavior == INTERSECT_NORMAL) {
    3526         397 :                 intersect_key_compare_func = php_array_key_compare;
    3527             : 
    3528         397 :                 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
    3529             :                         /* array_intersect() */
    3530         283 :                         req_args = 2;
    3531         283 :                         param_spec = "+";
    3532         283 :                         intersect_data_compare_func = php_array_data_compare;
    3533         114 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_USER) {
    3534             :                         /* array_uintersect() */
    3535         114 :                         req_args = 3;
    3536         114 :                         param_spec = "+f";
    3537         114 :                         intersect_data_compare_func = php_array_user_compare;
    3538             :                 } else {
    3539           0 :                         php_error_docref(NULL, E_WARNING, "data_compare_type is %d. This should never happen. Please report as a bug", data_compare_type);
    3540           0 :                         return;
    3541             :                 }
    3542             : 
    3543         397 :                 if (ZEND_NUM_ARGS() < req_args) {
    3544           3 :                         php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
    3545           3 :                         return;
    3546             :                 }
    3547             : 
    3548         394 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
    3549          30 :                         return;
    3550             :                 }
    3551         364 :                 fci_data = &fci1;
    3552         364 :                 fci_data_cache = &fci1_cache;
    3553             : 
    3554         568 :         } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3555             :                 /* INTERSECT_KEY is subset of INTERSECT_ASSOC. When having the former
    3556             :                  * no comparison of the data is done (part of INTERSECT_ASSOC) */
    3557         568 :                 intersect_key_compare_func = php_array_key_compare;
    3558             : 
    3559         568 :                 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
    3560             :                         /* array_intersect_assoc() or array_intersect_key() */
    3561           0 :                         req_args = 2;
    3562           0 :                         param_spec = "+";
    3563           0 :                         intersect_key_compare_func = php_array_key_compare;
    3564           0 :                         intersect_data_compare_func = php_array_data_compare;
    3565         568 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
    3566             :                         /* array_uintersect_assoc() */
    3567           0 :                         req_args = 3;
    3568           0 :                         param_spec = "+f";
    3569           0 :                         intersect_key_compare_func = php_array_key_compare;
    3570           0 :                         intersect_data_compare_func = php_array_user_compare;
    3571           0 :                         fci_data = &fci1;
    3572           0 :                         fci_data_cache = &fci1_cache;
    3573         995 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_USER) {
    3574             :                         /* array_intersect_uassoc() or array_intersect_ukey() */
    3575         427 :                         req_args = 3;
    3576         427 :                         param_spec = "+f";
    3577         427 :                         intersect_key_compare_func = php_array_user_key_compare;
    3578         427 :                         intersect_data_compare_func = php_array_data_compare;
    3579         427 :                         fci_key = &fci1;
    3580         427 :                         fci_key_cache = &fci1_cache;
    3581         282 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_USER) {
    3582             :                         /* array_uintersect_uassoc() */
    3583         141 :                         req_args = 4;
    3584         141 :                         param_spec = "+ff";
    3585         141 :                         intersect_key_compare_func = php_array_user_key_compare;
    3586         141 :                         intersect_data_compare_func = php_array_user_compare;
    3587         141 :                         fci_data = &fci1;
    3588         141 :                         fci_data_cache = &fci1_cache;
    3589         141 :                         fci_key = &fci2;
    3590         141 :                         fci_key_cache = &fci2_cache;
    3591             :                 } else {
    3592           0 :                         php_error_docref(NULL, E_WARNING, "data_compare_type is %d. key_compare_type is %d. This should never happen. Please report as a bug", data_compare_type, key_compare_type);
    3593           0 :                         return;
    3594             :                 }
    3595             : 
    3596         568 :                 if (ZEND_NUM_ARGS() < req_args) {
    3597           5 :                         php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
    3598           5 :                         return;
    3599             :                 }
    3600             : 
    3601         563 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
    3602         160 :                         return;
    3603             :                 }
    3604             : 
    3605             :         } else {
    3606           0 :                 php_error_docref(NULL, E_WARNING, "behavior is %d. This should never happen. Please report as a bug", behavior);
    3607           0 :                 return;
    3608             :         }
    3609             : 
    3610         767 :         PHP_ARRAY_CMP_FUNC_BACKUP();
    3611             : 
    3612             :         /* for each argument, create and sort list with pointers to the hash buckets */
    3613         767 :         lists = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
    3614         767 :         ptrs = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
    3615         767 :         php_set_compare_func(PHP_SORT_STRING);
    3616             : 
    3617         850 :         if (behavior == INTERSECT_NORMAL && data_compare_type == INTERSECT_COMP_DATA_USER) {
    3618          83 :                 BG(user_compare_fci) = *fci_data;
    3619          83 :                 BG(user_compare_fci_cache) = *fci_data_cache;
    3620         684 :         } else if (behavior & INTERSECT_ASSOC && key_compare_type == INTERSECT_COMP_KEY_USER) {
    3621         403 :                 BG(user_compare_fci) = *fci_key;
    3622         403 :                 BG(user_compare_fci_cache) = *fci_key_cache;
    3623             :         }
    3624             : 
    3625        1795 :         for (i = 0; i < arr_argc; i++) {
    3626        3120 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    3627         532 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    3628         532 :                         arr_argc = i; /* only free up to i - 1 */
    3629         532 :                         goto out;
    3630             :                 }
    3631        1028 :                 hash = Z_ARRVAL(args[i]);
    3632        2056 :                 list = (Bucket *) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket), hash->u.flags & HASH_FLAG_PERSISTENT);
    3633        1028 :                 if (!list) {
    3634           0 :                         PHP_ARRAY_CMP_FUNC_RESTORE();
    3635             : 
    3636           0 :                         efree(ptrs);
    3637           0 :                         efree(lists);
    3638           0 :                         RETURN_FALSE;
    3639             :                 }
    3640        1028 :                 lists[i] = list;
    3641        1028 :                 ptrs[i] = list;
    3642        6593 :                 for (idx = 0; idx < hash->nNumUsed; idx++) {
    3643        5565 :                         p = hash->arData + idx;
    3644       11130 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    3645        5530 :                         *list++ = *p;
    3646             :                 }
    3647        1028 :                 ZVAL_UNDEF(&list->val);
    3648        1028 :                 if (hash->nNumOfElements > 1) {
    3649         967 :                         if (behavior == INTERSECT_NORMAL) {
    3650         546 :                                 zend_sort((void *) lists[i], hash->nNumOfElements, 
    3651             :                                                 sizeof(Bucket), intersect_data_compare_func, (swap_func_t)zend_hash_bucket_swap);
    3652         421 :                         } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3653         421 :                                 zend_sort((void *) lists[i], hash->nNumOfElements,
    3654             :                                                 sizeof(Bucket), intersect_key_compare_func, (swap_func_t)zend_hash_bucket_swap);
    3655             :                         }
    3656             :                 }
    3657             :         }
    3658             : 
    3659             :         /* copy the argument array */
    3660         235 :         RETVAL_ARR(zend_array_dup(Z_ARRVAL(args[0])));
    3661             : 
    3662             :         /* go through the lists and look for common values */
    3663        1741 :         while (Z_TYPE(ptrs[0]->val) != IS_UNDEF) {
    3664         747 :                 if ((behavior & INTERSECT_ASSOC) /* triggered also when INTERSECT_KEY */
    3665             :                         && key_compare_type == INTERSECT_COMP_KEY_USER) {
    3666         148 :                         BG(user_compare_fci) = *fci_key;
    3667         148 :                         BG(user_compare_fci_cache) = *fci_key_cache;
    3668             :                 }
    3669             : 
    3670        1250 :                 for (i = 1; i < arr_argc; i++) {
    3671         906 :                         if (behavior & INTERSECT_NORMAL) {
    3672        3974 :                                 while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = intersect_data_compare_func(ptrs[0], ptrs[i])))) {
    3673         874 :                                         ptrs[i]++;
    3674             :                                 }
    3675         164 :                         } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3676         640 :                                 while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = intersect_key_compare_func(ptrs[0], ptrs[i])))) {
    3677          74 :                                         ptrs[i]++;
    3678             :                                 }
    3679         266 :                                 if ((!c && Z_TYPE(ptrs[i]->val) != IS_UNDEF) && (behavior == INTERSECT_ASSOC)) { /* only when INTERSECT_ASSOC */
    3680             :                                         /* this means that ptrs[i] is not NULL so we can compare
    3681             :                                          * and "c==0" is from last operation
    3682             :                                          * in this branch of code we enter only when INTERSECT_ASSOC
    3683             :                                          * since when we have INTERSECT_KEY compare of data is not wanted. */
    3684          40 :                                         if (data_compare_type == INTERSECT_COMP_DATA_USER) {
    3685          12 :                                                 BG(user_compare_fci) = *fci_data;
    3686          12 :                                                 BG(user_compare_fci_cache) = *fci_data_cache;
    3687             :                                         }
    3688          40 :                                         if (intersect_data_compare_func(ptrs[0], ptrs[i]) != 0) {
    3689          19 :                                                 c = 1;
    3690          19 :                                                 if (key_compare_type == INTERSECT_COMP_KEY_USER) {
    3691          19 :                                                         BG(user_compare_fci) = *fci_key;
    3692          19 :                                                         BG(user_compare_fci_cache) = *fci_key_cache;
    3693             :                                                         /* When KEY_USER, the last parameter is always the callback */
    3694             :                                                 }
    3695             :                                                 /* we are going to the break */
    3696             :                                         } else {
    3697             :                                                 /* continue looping */
    3698             :                                         }
    3699             :                                 }
    3700             :                         }
    3701        1812 :                         if (Z_TYPE(ptrs[i]->val) == IS_UNDEF) {
    3702             :                                 /* delete any values corresponding to remains of ptrs[0] */
    3703             :                                 /* and exit because they do not present in at least one of */
    3704             :                                 /* the other arguments */
    3705             :                                 for (;;) {
    3706         698 :                                         p = ptrs[0]++;
    3707        1396 :                                         if (Z_TYPE(p->val) == IS_UNDEF) {
    3708         109 :                                                 goto out;
    3709             :                                         }
    3710         589 :                                         if (p->key == NULL) {
    3711         522 :                                                 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    3712             :                                         } else {
    3713          67 :                                                 zend_hash_del(Z_ARRVAL_P(return_value), p->key);
    3714             :                                         }
    3715         589 :                                 }
    3716             :                         }
    3717         797 :                         if (c) /* here we get if not all are equal */
    3718         294 :                                 break;
    3719         503 :                         ptrs[i]++;
    3720             :                 }
    3721         638 :                 if (c) {
    3722             :                         /* Value of ptrs[0] not in all arguments, delete all entries */
    3723             :                         /* with value < value of ptrs[i] */
    3724             :                         for (;;) {
    3725         678 :                                 p = ptrs[0];
    3726         678 :                                 if (p->key == NULL) {
    3727         564 :                                         zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    3728             :                                 } else {
    3729         114 :                                         zend_hash_del(Z_ARRVAL_P(return_value), p->key);
    3730             :                                 }
    3731        1356 :                                 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
    3732          54 :                                         goto out;
    3733             :                                 }
    3734         624 :                                 if (behavior == INTERSECT_NORMAL) {
    3735         567 :                                         if (0 <= intersect_data_compare_func(ptrs[0], ptrs[i])) {
    3736         183 :                                                 break;
    3737             :                                         }
    3738          57 :                                 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3739             :                                         /* no need of looping because indexes are unique */
    3740          57 :                                         break;
    3741             :                                 }
    3742         384 :                         }
    3743             :                 } else {
    3744             :                         /* ptrs[0] is present in all the arguments */
    3745             :                         /* Skip all entries with same value as ptrs[0] */
    3746             :                         for (;;) {
    3747         804 :                                 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
    3748          66 :                                         goto out;
    3749             :                                 }
    3750         336 :                                 if (behavior == INTERSECT_NORMAL) {
    3751         287 :                                         if (intersect_data_compare_func(ptrs[0] - 1, ptrs[0])) {
    3752         229 :                                                 break;
    3753             :                                         }
    3754          49 :                                 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3755             :                                         /* no need of looping because indexes are unique */
    3756          49 :                                         break;
    3757             :                                 }
    3758          58 :                         }
    3759             :                 }
    3760             :         }
    3761             : out:
    3762        1795 :         for (i = 0; i < arr_argc; i++) {
    3763        1028 :                 hash = Z_ARRVAL(args[i]);
    3764        1028 :                 pefree(lists[i], hash->u.flags & HASH_FLAG_PERSISTENT);
    3765             :         }
    3766             : 
    3767         767 :         PHP_ARRAY_CMP_FUNC_RESTORE();
    3768             : 
    3769         767 :         efree(ptrs);
    3770         767 :         efree(lists);
    3771             : }
    3772             : /* }}} */
    3773             : 
    3774             : /* {{{ proto array array_intersect_key(array arr1, array arr2 [, array ...])
    3775             :    Returns the entries of arr1 that have keys which are present in all the other arguments. Kind of equivalent to array_diff(array_keys($arr1), array_keys($arr2)[,array_keys(...)]). Equivalent of array_intersect_assoc() but does not do compare of the data. */
    3776         181 : PHP_FUNCTION(array_intersect_key)
    3777             : {
    3778         181 :         php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_NONE);
    3779         181 : }
    3780             : /* }}} */
    3781             : 
    3782             : /* {{{ proto array array_intersect_ukey(array arr1, array arr2 [, array ...], callback key_compare_func)
    3783             :    Returns the entries of arr1 that have keys which are present in all the other arguments. Kind of equivalent to array_diff(array_keys($arr1), array_keys($arr2)[,array_keys(...)]). The comparison of the keys is performed by a user supplied function. Equivalent of array_intersect_uassoc() but does not do compare of the data. */
    3784         233 : PHP_FUNCTION(array_intersect_ukey)
    3785             : {
    3786         233 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_KEY, INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_USER);
    3787         233 : }
    3788             : /* }}} */
    3789             : 
    3790             : /* {{{ proto array array_intersect(array arr1, array arr2 [, array ...])
    3791             :    Returns the entries of arr1 that have values which are present in all the other arguments */
    3792         283 : PHP_FUNCTION(array_intersect)
    3793             : {
    3794         283 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_NORMAL, INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_INTERNAL);
    3795         283 : }
    3796             : /* }}} */
    3797             : 
    3798             : /* {{{ proto array array_uintersect(array arr1, array arr2 [, array ...], callback data_compare_func)
    3799             :    Returns the entries of arr1 that have values which are present in all the other arguments. Data is compared by using a user-supplied callback. */
    3800         114 : PHP_FUNCTION(array_uintersect)
    3801             : {
    3802         114 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_NORMAL, INTERSECT_COMP_DATA_USER, INTERSECT_COMP_KEY_INTERNAL);
    3803         114 : }
    3804             : /* }}} */
    3805             : 
    3806             : /* {{{ proto array array_intersect_assoc(array arr1, array arr2 [, array ...])
    3807             :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check */
    3808         279 : PHP_FUNCTION(array_intersect_assoc)
    3809             : {
    3810         279 :         php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_INTERNAL);
    3811         279 : }
    3812             : /* }}} */
    3813             : 
    3814             : /* {{{ proto array array_intersect_uassoc(array arr1, array arr2 [, array ...], callback key_compare_func) U
    3815             :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check and they are compared by using a user-supplied callback. */
    3816         194 : PHP_FUNCTION(array_intersect_uassoc)
    3817             : {
    3818         194 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC, INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_USER);
    3819         194 : }
    3820             : /* }}} */
    3821             : 
    3822             : /* {{{ proto array array_uintersect_assoc(array arr1, array arr2 [, array ...], callback data_compare_func) U
    3823             :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check. Data is compared by using a user-supplied callback. */
    3824         112 : PHP_FUNCTION(array_uintersect_assoc)
    3825             : {
    3826         112 :         php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_USER);
    3827         112 : }
    3828             : /* }}} */
    3829             : 
    3830             : /* {{{ proto array array_uintersect_uassoc(array arr1, array arr2 [, array ...], callback data_compare_func, callback key_compare_func)
    3831             :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check. Both data and keys are compared by using user-supplied callbacks. */
    3832         141 : PHP_FUNCTION(array_uintersect_uassoc)
    3833             : {
    3834         141 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC, INTERSECT_COMP_DATA_USER, INTERSECT_COMP_KEY_USER);
    3835         141 : }
    3836             : /* }}} */
    3837             : 
    3838         420 : static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type) /* {{{ */
    3839             : {
    3840             :     uint idx;
    3841             :         Bucket *p;
    3842             :         int argc, i;
    3843             :         zval *args;
    3844         420 :         int (*diff_data_compare_func)(zval *, zval *) = NULL;
    3845             :         zend_bool ok;
    3846             :         zval *val, *data;
    3847             : 
    3848             :         /* Get the argument count */
    3849         420 :         argc = ZEND_NUM_ARGS();
    3850         420 :         if (data_compare_type == DIFF_COMP_DATA_USER) {
    3851         114 :                 if (argc < 3) {
    3852           1 :                         php_error_docref(NULL, E_WARNING, "at least 3 parameters are required, %d given", ZEND_NUM_ARGS());
    3853           1 :                         return;
    3854             :                 }
    3855         113 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+f", &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
    3856          30 :                         return;
    3857             :                 }
    3858          83 :                 diff_data_compare_func = zval_user_compare;
    3859             :         } else {
    3860         306 :                 if (argc < 2) {
    3861           4 :                         php_error_docref(NULL, E_WARNING, "at least 2 parameters are required, %d given", ZEND_NUM_ARGS());
    3862           4 :                         return;
    3863             :                 }
    3864         302 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    3865           0 :                         return;
    3866             :                 }
    3867         302 :                 if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
    3868         140 :                         diff_data_compare_func = zval_compare;
    3869             :                 }
    3870             :         }
    3871             : 
    3872         859 :         for (i = 0; i < argc; i++) {
    3873        1462 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    3874         257 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    3875         257 :                         RETURN_NULL();
    3876             :                 }
    3877             :         }
    3878             : 
    3879         128 :         array_init(return_value);
    3880             : 
    3881         995 :         for (idx = 0; idx < Z_ARRVAL(args[0])->nNumUsed; idx++) {
    3882         867 :                 p = Z_ARRVAL(args[0])->arData + idx;
    3883         867 :                 val = &p->val;
    3884         867 :                 if (Z_TYPE_P(val) == IS_UNDEF) continue;
    3885         886 :                 if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) {
    3886          12 :                         ZVAL_UNREF(val);
    3887             :                 }
    3888         863 :                 if (p->key == NULL) {
    3889         740 :                         ok = 1;
    3890        1364 :                         for (i = 1; i < argc; i++) {
    3891        1375 :                                 if ((data = zend_hash_index_find(Z_ARRVAL(args[i]), p->h)) != NULL &&
    3892             :                                         (!diff_data_compare_func ||
    3893         601 :                                         diff_data_compare_func(val, data) == 0)
    3894             :                                 ) {
    3895         150 :                                         ok = 0;
    3896         150 :                                         break;
    3897             :                                 }
    3898             :                         }
    3899         740 :                         if (ok) {
    3900         590 :                                 if (Z_REFCOUNTED_P(val)) {
    3901             :                                         Z_ADDREF_P(val);
    3902             :                                 }
    3903         590 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), p->h, val);
    3904             :                         }
    3905             :                 } else {
    3906         123 :                         ok = 1;
    3907         212 :                         for (i = 1; i < argc; i++) {
    3908         179 :                                 if ((data = zend_hash_find(Z_ARRVAL(args[i]), p->key)) != NULL &&
    3909             :                                         (!diff_data_compare_func ||
    3910          42 :                                         diff_data_compare_func(val, data) == 0)
    3911             :                                 ) {
    3912          48 :                                         ok = 0;
    3913          48 :                                         break;
    3914             :                                 }
    3915             :                         }
    3916         123 :                         if (ok) {
    3917          75 :                                 if (Z_REFCOUNTED_P(val)) {
    3918             :                                         Z_ADDREF_P(val);
    3919             :                                 }
    3920          75 :                                 zend_hash_update(Z_ARRVAL_P(return_value), p->key, val);
    3921             :                         }
    3922             :                 }
    3923             :         }
    3924             : }
    3925             : /* }}} */
    3926             : 
    3927         608 : static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type) /* {{{ */
    3928             : {
    3929         608 :         zval *args = NULL;
    3930             :         HashTable *hash;
    3931             :         int arr_argc, i, c;
    3932             :         uint idx;
    3933             :         Bucket **lists, *list, **ptrs, *p;
    3934             :         uint32_t req_args;
    3935             :         char *param_spec;
    3936             :         zend_fcall_info fci1, fci2;
    3937         608 :         zend_fcall_info_cache fci1_cache = empty_fcall_info_cache, fci2_cache = empty_fcall_info_cache;
    3938         608 :         zend_fcall_info *fci_key = NULL, *fci_data;
    3939         608 :         zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache;
    3940             :         PHP_ARRAY_CMP_FUNC_VARS;
    3941             : 
    3942             :         int (*diff_key_compare_func)(const void *, const void *);
    3943             :         int (*diff_data_compare_func)(const void *, const void *);
    3944             : 
    3945         608 :         if (behavior == DIFF_NORMAL) {
    3946         112 :                 diff_key_compare_func = php_array_key_compare;
    3947             : 
    3948         112 :                 if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
    3949             :                         /* array_diff */
    3950           0 :                         req_args = 2;
    3951           0 :                         param_spec = "+";
    3952           0 :                         diff_data_compare_func = php_array_data_compare;
    3953         112 :                 } else if (data_compare_type == DIFF_COMP_DATA_USER) {
    3954             :                         /* array_udiff */
    3955         112 :                         req_args = 3;
    3956         112 :                         param_spec = "+f";
    3957         112 :                         diff_data_compare_func = php_array_user_compare;
    3958             :                 } else {
    3959           0 :                         php_error_docref(NULL, E_WARNING, "data_compare_type is %d. This should never happen. Please report as a bug", data_compare_type);
    3960           0 :                         return;
    3961             :                 }
    3962             : 
    3963         112 :                 if (ZEND_NUM_ARGS() < req_args) {
    3964           1 :                         php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
    3965           1 :                         return;
    3966             :                 }
    3967             : 
    3968         111 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
    3969          30 :                         return;
    3970             :                 }
    3971          81 :                 fci_data = &fci1;
    3972          81 :                 fci_data_cache = &fci1_cache;
    3973             : 
    3974         496 :         } else if (behavior & DIFF_ASSOC) { /* triggered also if DIFF_KEY */
    3975             :                 /* DIFF_KEY is subset of DIFF_ASSOC. When having the former
    3976             :                  * no comparison of the data is done (part of DIFF_ASSOC) */
    3977             : 
    3978         496 :                 if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
    3979             :                         /* array_diff_assoc() or array_diff_key() */
    3980           0 :                         req_args = 2;
    3981           0 :                         param_spec = "+";
    3982           0 :                         diff_key_compare_func = php_array_key_compare;
    3983           0 :                         diff_data_compare_func = php_array_data_compare;
    3984         496 :                 } else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
    3985             :                         /* array_udiff_assoc() */
    3986           0 :                         req_args = 3;
    3987           0 :                         param_spec = "+f";
    3988           0 :                         diff_key_compare_func = php_array_key_compare;
    3989           0 :                         diff_data_compare_func = php_array_user_compare;
    3990           0 :                         fci_data = &fci1;
    3991           0 :                         fci_data_cache = &fci1_cache;
    3992         851 :                 } else if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_USER) {
    3993             :                         /* array_diff_uassoc() or array_diff_ukey() */
    3994         355 :                         req_args = 3;
    3995         355 :                         param_spec = "+f";
    3996         355 :                         diff_key_compare_func = php_array_user_key_compare;
    3997         355 :                         diff_data_compare_func = php_array_data_compare;
    3998         355 :                         fci_key = &fci1;
    3999         355 :                         fci_key_cache = &fci1_cache;
    4000         282 :                 } else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_USER) {
    4001             :                         /* array_udiff_uassoc() */
    4002         141 :                         req_args = 4;
    4003         141 :                         param_spec = "+ff";
    4004         141 :                         diff_key_compare_func = php_array_user_key_compare;
    4005         141 :                         diff_data_compare_func = php_array_user_compare;
    4006         141 :                         fci_data = &fci1;
    4007         141 :                         fci_data_cache = &fci1_cache;
    4008         141 :                         fci_key = &fci2;
    4009         141 :                         fci_key_cache = &fci2_cache;
    4010             :                 } else {
    4011           0 :                         php_error_docref(NULL, E_WARNING, "data_compare_type is %d. key_compare_type is %d. This should never happen. Please report as a bug", data_compare_type, key_compare_type);
    4012           0 :                         return;
    4013             :                 }
    4014             : 
    4015         496 :                 if (ZEND_NUM_ARGS() < req_args) {
    4016           5 :                         php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
    4017           5 :                         return;
    4018             :                 }
    4019             : 
    4020         491 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
    4021         138 :                         return;
    4022             :                 }
    4023             : 
    4024             :         } else {
    4025           0 :                 php_error_docref(NULL, E_WARNING, "behavior is %d. This should never happen. Please report as a bug", behavior);
    4026           0 :                 return;
    4027             :         }
    4028             : 
    4029         434 :         PHP_ARRAY_CMP_FUNC_BACKUP();
    4030             : 
    4031             :         /* for each argument, create and sort list with pointers to the hash buckets */
    4032         434 :         lists = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
    4033         434 :         ptrs = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
    4034         434 :         php_set_compare_func(PHP_SORT_STRING);
    4035             : 
    4036         515 :         if (behavior == DIFF_NORMAL && data_compare_type == DIFF_COMP_DATA_USER) {
    4037          81 :                 BG(user_compare_fci) = *fci_data;
    4038          81 :                 BG(user_compare_fci_cache) = *fci_data_cache;
    4039         353 :         } else if (behavior & DIFF_ASSOC && key_compare_type == DIFF_COMP_KEY_USER) {
    4040         353 :                 BG(user_compare_fci) = *fci_key;
    4041         353 :                 BG(user_compare_fci_cache) = *fci_key_cache;
    4042             :         }
    4043             : 
    4044         923 :         for (i = 0; i < arr_argc; i++) {
    4045        1694 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    4046         358 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    4047         358 :                         arr_argc = i; /* only free up to i - 1 */
    4048         358 :                         goto out;
    4049             :                 }
    4050         489 :                 hash = Z_ARRVAL(args[i]);
    4051         978 :                 list = (Bucket *) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket), hash->u.flags & HASH_FLAG_PERSISTENT);
    4052         489 :                 if (!list) {
    4053           0 :                         PHP_ARRAY_CMP_FUNC_RESTORE();
    4054             : 
    4055           0 :                         efree(ptrs);
    4056           0 :                         efree(lists);
    4057           0 :                         RETURN_FALSE;
    4058             :                 }
    4059         489 :                 lists[i] = list;
    4060         489 :                 ptrs[i] = list;
    4061        1981 :                 for (idx = 0; idx < hash->nNumUsed; idx++) {
    4062        1492 :                         p = hash->arData + idx;
    4063        2984 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    4064        1492 :                         *list++ = *p;
    4065             :                 }
    4066         489 :                 ZVAL_UNDEF(&list->val);
    4067         489 :                 if (hash->nNumOfElements > 1) {
    4068         465 :                         if (behavior == DIFF_NORMAL) {
    4069          81 :                                 zend_sort((void *) lists[i], hash->nNumOfElements,
    4070             :                                                 sizeof(Bucket), diff_data_compare_func, (swap_func_t)zend_hash_bucket_swap);
    4071         384 :                         } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    4072         384 :                                 zend_sort((void *) lists[i], hash->nNumOfElements,
    4073             :                                                 sizeof(Bucket), diff_key_compare_func, (swap_func_t)zend_hash_bucket_swap);
    4074             :                         }
    4075             :                 }
    4076             :         }
    4077             : 
    4078             :         /* copy the argument array */
    4079          76 :         RETVAL_ARR(zend_array_dup(Z_ARRVAL(args[0])));
    4080             : 
    4081             :         /* go through the lists and look for values of ptr[0] that are not in the others */
    4082         532 :         while (Z_TYPE(ptrs[0]->val) != IS_UNDEF) {
    4083         228 :                 if ((behavior & DIFF_ASSOC) /* triggered also when DIFF_KEY */
    4084             :                         &&
    4085             :                         key_compare_type == DIFF_COMP_KEY_USER
    4086             :                 ) {
    4087         212 :                         BG(user_compare_fci) = *fci_key;
    4088         212 :                         BG(user_compare_fci_cache) = *fci_key_cache;
    4089             :                 }
    4090         228 :                 c = 1;
    4091         365 :                 for (i = 1; i < arr_argc; i++) {
    4092         246 :                         Bucket *ptr = ptrs[i];
    4093         246 :                         if (behavior == DIFF_NORMAL) {
    4094          58 :                                 while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = diff_data_compare_func(ptrs[0], ptrs[i])))) {
    4095           5 :                                         ptrs[i]++;
    4096             :                                 }
    4097         230 :                         } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    4098        1938 :                                 while (Z_TYPE(ptr->val) != IS_UNDEF && (0 != (c = diff_key_compare_func(ptrs[0], ptr)))) {
    4099         624 :                                         ptr++;
    4100             :                                 }
    4101             :                         }
    4102         246 :                         if (!c) {
    4103         134 :                                 if (behavior == DIFF_NORMAL) {
    4104          20 :                                         if (Z_TYPE(ptrs[i]->val) != IS_UNDEF) {
    4105          10 :                                                 ptrs[i]++;
    4106             :                                         }
    4107          10 :                                         break;
    4108         124 :                                 } else if (behavior == DIFF_ASSOC) {  /* only when DIFF_ASSOC */
    4109             :                                         /* In this branch is execute only when DIFF_ASSOC. If behavior == DIFF_KEY
    4110             :                                          * data comparison is not needed - skipped. */
    4111         140 :                                         if (Z_TYPE(ptr->val) != IS_UNDEF) {
    4112          70 :                                                 if (data_compare_type == DIFF_COMP_DATA_USER) {
    4113          12 :                                                         BG(user_compare_fci) = *fci_data;
    4114          12 :                                                         BG(user_compare_fci_cache) = *fci_data_cache;
    4115             :                                                 }
    4116          70 :                                                 if (diff_data_compare_func(ptrs[0], ptr) != 0) {
    4117             :                                                         /* the data is not the same */
    4118          25 :                                                         c = -1;
    4119          25 :                                                         if (key_compare_type == DIFF_COMP_KEY_USER) {
    4120          25 :                                                                 BG(user_compare_fci) = *fci_key;
    4121          25 :                                                                 BG(user_compare_fci_cache) = *fci_key_cache;
    4122             :                                                         }
    4123             :                                                 } else {
    4124          45 :                                                         break;
    4125             :                                                         /* we have found the element in other arrays thus we don't want it
    4126             :                                                          * in the return_value -> delete from there */
    4127             :                                                 }
    4128             :                                         }
    4129          54 :                                 } else if (behavior == DIFF_KEY) { /* only when DIFF_KEY */
    4130             :                                         /* the behavior here differs from INTERSECT_KEY in php_intersect
    4131             :                                          * since in the "diff" case we have to remove the entry from
    4132             :                                          * return_value while when doing intersection the entry must not
    4133             :                                          * be deleted. */
    4134          54 :                                         break; /* remove the key */
    4135             :                                 }
    4136             :                         }
    4137             :                 }
    4138         228 :                 if (!c) {
    4139             :                         /* ptrs[0] in one of the other arguments */
    4140             :                         /* delete all entries with value as ptrs[0] */
    4141             :                         for (;;) {
    4142         109 :                                 p = ptrs[0];
    4143         109 :                                 if (p->key == NULL) {
    4144          85 :                                         zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    4145             :                                 } else {
    4146          24 :                                         zend_hash_del(Z_ARRVAL_P(return_value), p->key);
    4147             :                                 }
    4148         218 :                                 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
    4149          30 :                                         goto out;
    4150             :                                 }
    4151          79 :                                 if (behavior == DIFF_NORMAL) {
    4152           7 :                                         if (diff_data_compare_func(ptrs[0] - 1, ptrs[0])) {
    4153           7 :                                                 break;
    4154             :                                         }
    4155          72 :                                 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    4156             :                                         /* in this case no array_key_compare is needed */
    4157          72 :                                         break;
    4158             :                                 }
    4159           0 :                         }
    4160             :                 } else {
    4161             :                         /* ptrs[0] in none of the other arguments */
    4162             :                         /* skip all entries with value as ptrs[0] */
    4163             :                         for (;;) {
    4164         238 :                                 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
    4165          46 :                                         goto out;
    4166             :                                 }
    4167          73 :                                 if (behavior == DIFF_NORMAL) {
    4168           3 :                                         if (diff_data_compare_func(ptrs[0] - 1, ptrs[0])) {
    4169           3 :                                                 break;
    4170             :                                         }
    4171          70 :                                 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    4172             :                                         /* in this case no array_key_compare is needed */
    4173          70 :                                         break;
    4174             :                                 }
    4175           0 :                         }
    4176             :                 }
    4177             :         }
    4178             : out:
    4179         923 :         for (i = 0; i < arr_argc; i++) {
    4180         489 :                 hash = Z_ARRVAL(args[i]);
    4181         489 :                 pefree(lists[i], hash->u.flags & HASH_FLAG_PERSISTENT);
    4182             :         }
    4183             : 
    4184         434 :         PHP_ARRAY_CMP_FUNC_RESTORE();
    4185             : 
    4186         434 :         efree(ptrs);
    4187         434 :         efree(lists);
    4188             : }
    4189             : /* }}} */
    4190             : 
    4191             : /* {{{ proto array array_diff_key(array arr1, array arr2 [, array ...])
    4192             :    Returns the entries of arr1 that have keys which are not present in any of the others arguments. This function is like array_diff() but works on the keys instead of the values. The associativity is preserved. */
    4193         164 : PHP_FUNCTION(array_diff_key)
    4194             : {
    4195         164 :         php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_NONE);
    4196         164 : }
    4197             : /* }}} */
    4198             : 
    4199             : /* {{{ proto array array_diff_ukey(array arr1, array arr2 [, array ...], callback key_comp_func)
    4200             :    Returns the entries of arr1 that have keys which are not present in any of the others arguments. User supplied function is used for comparing the keys. This function is like array_udiff() but works on the keys instead of the values. The associativity is preserved. */
    4201         206 : PHP_FUNCTION(array_diff_ukey)
    4202             : {
    4203         206 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_KEY, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
    4204         206 : }
    4205             : /* }}} */
    4206             : 
    4207             : /* {{{ proto array array_diff(array arr1, array arr2 [, array ...])
    4208             :    Returns the entries of arr1 that have values which are not present in any of the others arguments. */
    4209         138 : PHP_FUNCTION(array_diff)
    4210             : {
    4211             :         zval *args;
    4212             :         int argc, i;
    4213             :         uint32_t num;
    4214             :         HashTable exclude;
    4215             :         zval *value;
    4216             :         zend_string *str, *key;
    4217             :         zend_long idx;
    4218             :         zval dummy;
    4219             : 
    4220         138 :         if (ZEND_NUM_ARGS() < 2) {
    4221           2 :                 php_error_docref(NULL, E_WARNING, "at least 2 parameters are required, %d given", ZEND_NUM_ARGS());
    4222           2 :                 return;
    4223             :         }
    4224             : 
    4225         136 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    4226           0 :                 return;
    4227             :         }
    4228             : 
    4229         272 :         if (Z_TYPE(args[0]) != IS_ARRAY) {
    4230          26 :                 php_error_docref(NULL, E_WARNING, "Argument #1 is not an array");
    4231          26 :                 RETURN_NULL();
    4232             :         }
    4233             : 
    4234             :         /* count number of elements */
    4235         110 :         num = 0;
    4236         197 :         for (i = 1; i < argc; i++) {
    4237         228 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    4238          27 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    4239          27 :                         RETURN_NULL();
    4240             :                 }
    4241          87 :                 num += zend_hash_num_elements(Z_ARRVAL(args[i]));
    4242             :         }
    4243             : 
    4244          83 :         if (num == 0) {
    4245           1 :                 ZVAL_COPY(return_value, &args[0]);
    4246           1 :                 return;
    4247             :         }
    4248             : 
    4249          82 :         ZVAL_NULL(&dummy);
    4250             :         /* create exclude map */
    4251          82 :         zend_hash_init(&exclude, num, NULL, NULL, 0);
    4252         168 :         for (i = 1; i < argc; i++) {
    4253        8375 :                 ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[i]), value) {
    4254        2762 :                         str = zval_get_string(value);
    4255        2762 :                         zend_hash_add(&exclude, str, &dummy);
    4256             :                         zend_string_release(str);
    4257             :                 } ZEND_HASH_FOREACH_END();
    4258             :         }
    4259             : 
    4260             :         /* copy all elements of first array that are not in exclude set */
    4261          82 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
    4262        8347 :         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL(args[0]), idx, key, value) {
    4263        2754 :                 str = zval_get_string(value);
    4264        2754 :                 if (!zend_hash_exists(&exclude, str)) {
    4265         156 :                         if (key) {
    4266          48 :                                 value = zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
    4267             :                         } else {
    4268         108 :                                 value = zend_hash_index_add_new(Z_ARRVAL_P(return_value), idx, value);
    4269             :                         }
    4270         156 :                         zval_add_ref(value);
    4271             :                 }
    4272             :                 zend_string_release(str);
    4273             :         } ZEND_HASH_FOREACH_END();
    4274             : 
    4275          82 :         zend_hash_destroy(&exclude);
    4276             : }
    4277             : /* }}} */
    4278             : 
    4279             : /* {{{ proto array array_udiff(array arr1, array arr2 [, array ...], callback data_comp_func)
    4280             :    Returns the entries of arr1 that have values which are not present in any of the others arguments. Elements are compared by user supplied function. */
    4281         112 : PHP_FUNCTION(array_udiff)
    4282             : {
    4283         112 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_NORMAL, DIFF_COMP_DATA_USER, DIFF_COMP_KEY_INTERNAL);
    4284         112 : }
    4285             : /* }}} */
    4286             : 
    4287             : /* {{{ proto array array_diff_assoc(array arr1, array arr2 [, array ...])
    4288             :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal */
    4289         142 : PHP_FUNCTION(array_diff_assoc)
    4290             : {
    4291         142 :         php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_INTERNAL);
    4292         142 : }
    4293             : /* }}} */
    4294             : 
    4295             : /* {{{ proto array array_diff_uassoc(array arr1, array arr2 [, array ...], callback data_comp_func)
    4296             :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Elements are compared by user supplied function. */
    4297         149 : PHP_FUNCTION(array_diff_uassoc)
    4298             : {
    4299         149 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
    4300         149 : }
    4301             : /* }}} */
    4302             : 
    4303             : /* {{{ proto array array_udiff_assoc(array arr1, array arr2 [, array ...], callback key_comp_func)
    4304             :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Keys are compared by user supplied function. */
    4305         114 : PHP_FUNCTION(array_udiff_assoc)
    4306             : {
    4307         114 :         php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_USER);
    4308         114 : }
    4309             : /* }}} */
    4310             : 
    4311             : /* {{{ proto array array_udiff_uassoc(array arr1, array arr2 [, array ...], callback data_comp_func, callback key_comp_func)
    4312             :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Keys and elements are compared by user supplied functions. */
    4313         141 : PHP_FUNCTION(array_udiff_uassoc)
    4314             : {
    4315         141 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_USER, DIFF_COMP_KEY_USER);
    4316         141 : }
    4317             : /* }}} */
    4318             : 
    4319             : #define MULTISORT_ORDER 0
    4320             : #define MULTISORT_TYPE  1
    4321             : #define MULTISORT_LAST  2
    4322             : 
    4323         197 : PHPAPI int php_multisort_compare(const void *a, const void *b) /* {{{ */
    4324             : {
    4325         197 :         Bucket *ab = *(Bucket **)a;
    4326         197 :         Bucket *bb = *(Bucket **)b;
    4327             :         int r;
    4328             :         zend_long result;
    4329             :         zval temp;
    4330             : 
    4331         197 :         r = 0;
    4332             :         do {
    4333             : 
    4334         203 :                 php_set_compare_func(ARRAYG(multisort_flags)[MULTISORT_TYPE][r]);
    4335             : 
    4336         203 :                 ARRAYG(compare_func)(&temp, &ab[r].val, &bb[r].val);
    4337         203 :                 result = ARRAYG(multisort_flags)[MULTISORT_ORDER][r] * Z_LVAL(temp);
    4338         203 :                 if (result != 0) {
    4339         173 :                         return result > 0 ? 1 : -1;
    4340             :                 }
    4341          30 :                 r++;
    4342          60 :         } while (Z_TYPE(ab[r].val) != IS_UNDEF);
    4343             : 
    4344          24 :         return 0;
    4345             : }
    4346             : /* }}} */
    4347             : 
    4348             : #define MULTISORT_ABORT                                         \
    4349             :         for (k = 0; k < MULTISORT_LAST; k++) \
    4350             :                 efree(ARRAYG(multisort_flags)[k]);      \
    4351             :         efree(arrays);                                                  \
    4352             :         RETURN_FALSE;
    4353             : 
    4354         165 : static void array_bucket_p_sawp(void *p, void *q) /* {{{ */ {
    4355             :         Bucket *t;
    4356         165 :         Bucket **f = (Bucket **)p;
    4357         165 :         Bucket **g = (Bucket **)q;
    4358             : 
    4359         165 :         t = *f;
    4360         165 :         *f = *g;
    4361         165 :         *g = t;
    4362         165 : }
    4363             : /* }}} */
    4364             : 
    4365             : /* {{{ proto bool array_multisort(array ar1 [, SORT_ASC|SORT_DESC [, SORT_REGULAR|SORT_NUMERIC|SORT_STRING|SORT_NATURAL|SORT_FLAG_CASE]] [, array ar2 [, SORT_ASC|SORT_DESC [, SORT_REGULAR|SORT_NUMERIC|SORT_STRING|SORT_NATURAL|SORT_FLAG_CASE]], ...])
    4366             :    Sort multiple arrays at once similar to how ORDER BY clause works in SQL */
    4367         109 : PHP_FUNCTION(array_multisort)
    4368             : {
    4369             :         zval*                   args;
    4370             :         zval**                  arrays;
    4371             :         Bucket**                indirect;
    4372             :         uint            idx;
    4373             :         Bucket*                 p;
    4374             :         HashTable*              hash;
    4375             :         int                             argc;
    4376             :         int                             array_size;
    4377         109 :         int                             num_arrays = 0;
    4378             :         int                             parse_state[MULTISORT_LAST];   /* 0 - flag not allowed 1 - flag allowed */
    4379         109 :         int                             sort_order = PHP_SORT_ASC;
    4380         109 :         int                             sort_type  = PHP_SORT_REGULAR;
    4381             :         int                             i, k, n;
    4382             : 
    4383         109 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    4384           1 :                 return;
    4385             :         }
    4386             : 
    4387             :         /* Allocate space for storing pointers to input arrays and sort flags. */
    4388         108 :         arrays = (zval **)ecalloc(argc, sizeof(zval *));
    4389         324 :         for (i = 0; i < MULTISORT_LAST; i++) {
    4390         216 :                 parse_state[i] = 0;
    4391         216 :                 ARRAYG(multisort_flags)[i] = (int *)ecalloc(argc, sizeof(int));
    4392             :         }
    4393             : 
    4394             :         /* Here we go through the input arguments and parse them. Each one can
    4395             :          * be either an array or a sort flag which follows an array. If not
    4396             :          * specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
    4397             :          * accordingly. There can't be two sort flags of the same type after an
    4398             :          * array, and the very first argument has to be an array. */
    4399         268 :         for (i = 0; i < argc; i++) {
    4400         235 :                 zval *arg = &args[i];
    4401             : 
    4402         235 :                 ZVAL_DEREF(arg);
    4403         235 :                 if (Z_TYPE_P(arg) == IS_ARRAY) {
    4404         205 :                         SEPARATE_ARRAY(arg);
    4405             :                         /* We see the next array, so we update the sort flags of
    4406             :                          * the previous array and reset the sort flags. */
    4407         100 :                         if (i > 0) {
    4408          17 :                                 ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays - 1] = sort_order;
    4409          17 :                                 ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays - 1] = sort_type;
    4410          17 :                                 sort_order = PHP_SORT_ASC;
    4411          17 :                                 sort_type = PHP_SORT_REGULAR;
    4412             :                         }
    4413         100 :                         arrays[num_arrays++] = arg;
    4414             : 
    4415             :                         /* Next one may be an array or a list of sort flags. */
    4416         300 :                         for (k = 0; k < MULTISORT_LAST; k++) {
    4417         200 :                                 parse_state[k] = 1;
    4418             :                         }
    4419         135 :                 } else if (Z_TYPE_P(arg) == IS_LONG) {
    4420          72 :                         switch (Z_LVAL_P(arg) & ~PHP_SORT_FLAG_CASE) {
    4421             :                                 case PHP_SORT_ASC:
    4422             :                                 case PHP_SORT_DESC:
    4423             :                                         /* flag allowed here */
    4424          15 :                                         if (parse_state[MULTISORT_ORDER] == 1) {
    4425             :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    4426          14 :                                                 sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? -1 : 1;
    4427          14 :                                                 parse_state[MULTISORT_ORDER] = 0;
    4428             :                                         } else {
    4429           1 :                                                 php_error_docref(NULL, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1);
    4430           1 :                                                 MULTISORT_ABORT;
    4431             :                                         }
    4432          14 :                                         break;
    4433             : 
    4434             :                                 case PHP_SORT_REGULAR:
    4435             :                                 case PHP_SORT_NUMERIC:
    4436             :                                 case PHP_SORT_STRING:
    4437             :                                 case PHP_SORT_NATURAL:
    4438             : #if HAVE_STRCOLL
    4439             :                                 case PHP_SORT_LOCALE_STRING:
    4440             : #endif
    4441             :                                         /* flag allowed here */
    4442          51 :                                         if (parse_state[MULTISORT_TYPE] == 1) {
    4443             :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    4444          46 :                                                 sort_type = (int)Z_LVAL_P(arg);
    4445          46 :                                                 parse_state[MULTISORT_TYPE] = 0;
    4446             :                                         } else {
    4447           5 :                                                 php_error_docref(NULL, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1);
    4448           5 :                                                 MULTISORT_ABORT;
    4449             :                                         }
    4450          46 :                                         break;
    4451             : 
    4452             :                                 default:
    4453           6 :                                         php_error_docref(NULL, E_WARNING, "Argument #%d is an unknown sort flag", i + 1);
    4454           6 :                                         MULTISORT_ABORT;
    4455             :                                         break;
    4456             : 
    4457             :                         }
    4458             :                 } else {
    4459          63 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is expected to be an array or a sort flag", i + 1);
    4460          63 :                         MULTISORT_ABORT;
    4461             :                 }
    4462             :         }
    4463             :         /* Take care of the last array sort flags. */
    4464          33 :         ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays - 1] = sort_order;
    4465          33 :         ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays - 1] = sort_type;
    4466             : 
    4467             :         /* Make sure the arrays are of the same size. */
    4468          33 :         array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
    4469          80 :         for (i = 0; i < num_arrays; i++) {
    4470          50 :                 if (zend_hash_num_elements(Z_ARRVAL_P(arrays[i])) != array_size) {
    4471           3 :                         php_error_docref(NULL, E_WARNING, "Array sizes are inconsistent");
    4472           3 :                         MULTISORT_ABORT;
    4473             :                 }
    4474             :         }
    4475             : 
    4476             :         /* If all arrays are empty we don't need to do anything. */
    4477          30 :         if (array_size < 1) {
    4478           6 :                 for (k = 0; k < MULTISORT_LAST; k++) {
    4479           4 :                         efree(ARRAYG(multisort_flags)[k]);
    4480             :                 }
    4481           2 :                 efree(arrays);
    4482           2 :                 RETURN_TRUE;
    4483             :         }
    4484             : 
    4485             :         /* Create the indirection array. This array is of size MxN, where
    4486             :          * M is the number of entries in each input array and N is the number
    4487             :          * of the input arrays + 1. The last column is NULL to indicate the end
    4488             :          * of the row. */
    4489          28 :         indirect = (Bucket **)safe_emalloc(array_size, sizeof(Bucket *), 0);
    4490         149 :         for (i = 0; i < array_size; i++) {
    4491         121 :                 indirect[i] = (Bucket *)safe_emalloc((num_arrays + 1), sizeof(Bucket), 0);
    4492             :         }
    4493          68 :         for (i = 0; i < num_arrays; i++) {
    4494          40 :                 k = 0;
    4495         221 :                 for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++) {
    4496         181 :                         p = Z_ARRVAL_P(arrays[i])->arData + idx;
    4497         362 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    4498         180 :                         indirect[k][i] = *p;
    4499         180 :                         k++;
    4500             :                 }
    4501             :         }
    4502         149 :         for (k = 0; k < array_size; k++) {
    4503         121 :                 ZVAL_UNDEF(&indirect[k][num_arrays].val);
    4504             :         }
    4505             : 
    4506             :         /* Do the actual sort magic - bada-bim, bada-boom. */
    4507          28 :         zend_qsort(indirect, array_size, sizeof(Bucket *), php_multisort_compare, (swap_func_t)array_bucket_p_sawp);
    4508             : 
    4509             :         /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
    4510          28 :         HANDLE_BLOCK_INTERRUPTIONS();
    4511          68 :         for (i = 0; i < num_arrays; i++) {
    4512             :                 int repack;
    4513             : 
    4514          40 :                 hash = Z_ARRVAL_P(arrays[i]);
    4515          40 :                 hash->nNumUsed = array_size;
    4516          40 :                 hash->nInternalPointer = 0;
    4517          40 :                 repack = !(hash->u.flags & HASH_FLAG_PACKED);
    4518             : 
    4519         220 :                 for (n = 0, k = 0; k < array_size; k++) {
    4520         180 :                         hash->arData[k] = indirect[k][i];
    4521         180 :                         if (hash->arData[k].key == NULL) {
    4522         130 :                                 hash->arData[k].h = n++;
    4523             :                         } else {
    4524          50 :                                 repack = 0;
    4525             :                         }
    4526             :                 }
    4527          40 :                 hash->nNextFreeElement = array_size;
    4528          40 :                 if (repack) {
    4529           0 :                         zend_hash_to_packed(hash);
    4530             :                 } else {
    4531          40 :                         zend_hash_rehash(hash);
    4532             :                 }
    4533             :         }
    4534          28 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    4535             : 
    4536             :         /* Clean up. */
    4537         149 :         for (i = 0; i < array_size; i++) {
    4538         121 :                 efree(indirect[i]);
    4539             :         }
    4540          28 :         efree(indirect);
    4541          84 :         for (k = 0; k < MULTISORT_LAST; k++) {
    4542          56 :                 efree(ARRAYG(multisort_flags)[k]);
    4543             :         }
    4544          28 :         efree(arrays);
    4545          28 :         RETURN_TRUE;
    4546             : }
    4547             : /* }}} */
    4548             : 
    4549             : /* {{{ proto mixed array_rand(array input [, int num_req])
    4550             :    Return key/keys for random entry/entries in the array */
    4551         363 : PHP_FUNCTION(array_rand)
    4552             : {
    4553             :         zval *input;
    4554         363 :         zend_long randval, num_req = 1;
    4555             :         int num_avail;
    4556             :         zend_string *string_key;
    4557             :         zend_ulong num_key;
    4558             : 
    4559         363 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &input, &num_req) == FAILURE) {
    4560          32 :                 return;
    4561             :         }
    4562             : 
    4563         331 :         num_avail = zend_hash_num_elements(Z_ARRVAL_P(input));
    4564             : 
    4565         331 :         if (ZEND_NUM_ARGS() > 1) {
    4566         313 :                 if (num_req <= 0 || num_req > num_avail) {
    4567          21 :                         php_error_docref(NULL, E_WARNING, "Second argument has to be between 1 and the number of elements in the array");
    4568          21 :                         return;
    4569             :                 }
    4570             :         }
    4571             : 
    4572             :         /* Make the return value an array only if we need to pass back more than one result. */
    4573         310 :         if (num_req > 1) {
    4574          25 :                 array_init_size(return_value, (uint32_t)num_req);
    4575             :         }
    4576             : 
    4577             :         /* We can't use zend_hash_index_find() because the array may have string keys or gaps. */
    4578        2325 :         ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(input), num_key, string_key) {
    4579        1154 :                 if (!num_req) {
    4580           9 :                         break;
    4581             :                 }
    4582             : 
    4583        1145 :                 randval = php_rand();
    4584             : 
    4585        1145 :                 if ((double) (randval / (PHP_RAND_MAX + 1.0)) < (double) num_req / (double) num_avail) {
    4586             :                         /* If we are returning a single result, just do it. */
    4587         760 :                         if (Z_TYPE_P(return_value) != IS_ARRAY) {
    4588         284 :                                 if (string_key) {
    4589           7 :                                         RETURN_STR_COPY(string_key);
    4590             :                                 } else {
    4591         277 :                                         RETURN_LONG(num_key);
    4592             :                                 }
    4593             :                         } else {
    4594             :                                 /* Append the result to the return value. */
    4595         476 :                                 if (string_key) {
    4596          19 :                                         add_next_index_str(return_value, zend_string_copy(string_key));
    4597             :                                 } else {
    4598         457 :                                         add_next_index_long(return_value, num_key);
    4599             :                                 }
    4600             :                         }
    4601         476 :                         num_req--;
    4602             :                 }
    4603         861 :                 num_avail--;
    4604             :         } ZEND_HASH_FOREACH_END();
    4605             : }
    4606             : /* }}} */
    4607             : 
    4608             : /* {{{ proto mixed array_sum(array input)
    4609             :    Returns the sum of the array entries */
    4610          63 : PHP_FUNCTION(array_sum)
    4611             : {
    4612             :         zval *input,
    4613             :                  *entry,
    4614             :                  entry_n;
    4615             : 
    4616          63 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &input) == FAILURE) {
    4617          25 :                 return;
    4618             :         }
    4619             : 
    4620          38 :         ZVAL_LONG(return_value, 0);
    4621             : 
    4622      404350 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
    4623      404308 :                 if (Z_TYPE_P(entry) == IS_ARRAY || Z_TYPE_P(entry) == IS_OBJECT) {
    4624           8 :                         continue;
    4625             :                 }
    4626      202148 :                 ZVAL_DUP(&entry_n, entry);
    4627      202148 :                 convert_scalar_to_number(&entry_n);
    4628             :                 fast_add_function(return_value, return_value, &entry_n);
    4629             :         } ZEND_HASH_FOREACH_END();
    4630             : }
    4631             : /* }}} */
    4632             : 
    4633             : /* {{{ proto mixed array_product(array input)
    4634             :    Returns the product of the array entries */
    4635          53 : PHP_FUNCTION(array_product)
    4636             : {
    4637             :         zval *input,
    4638             :                  *entry,
    4639             :                  entry_n;
    4640             :         double dval;
    4641             : 
    4642          53 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &input) == FAILURE) {
    4643          29 :                 return;
    4644             :         }
    4645             : 
    4646          24 :         ZVAL_LONG(return_value, 1);
    4647          24 :         if (!zend_hash_num_elements(Z_ARRVAL_P(input))) {
    4648           2 :                 return;
    4649             :         }
    4650             : 
    4651        2086 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
    4652        2063 :                 if (Z_TYPE_P(entry) == IS_ARRAY || Z_TYPE_P(entry) == IS_OBJECT) {
    4653           2 :                         continue;
    4654             :                 }
    4655        1030 :                 ZVAL_DUP(&entry_n, entry);
    4656        1030 :                 convert_scalar_to_number(&entry_n);
    4657             : 
    4658        2053 :                 if (Z_TYPE(entry_n) == IS_LONG && Z_TYPE_P(return_value) == IS_LONG) {
    4659          28 :                         dval = (double)Z_LVAL_P(return_value) * (double)Z_LVAL(entry_n);
    4660          28 :                         if ( (double)ZEND_LONG_MIN <= dval && dval <= (double)ZEND_LONG_MAX ) {
    4661          27 :                                 Z_LVAL_P(return_value) *= Z_LVAL(entry_n);
    4662          27 :                                 continue;
    4663             :                         }
    4664             :                 }
    4665        1003 :                 convert_to_double(return_value);
    4666        1003 :                 convert_to_double(&entry_n);
    4667        1003 :                 Z_DVAL_P(return_value) *= Z_DVAL(entry_n);
    4668             :         } ZEND_HASH_FOREACH_END();
    4669             : }
    4670             : /* }}} */
    4671             : 
    4672             : /* {{{ proto mixed array_reduce(array input, mixed callback [, mixed initial])
    4673             :    Iteratively reduce the array to a single value via the callback. */
    4674          73 : PHP_FUNCTION(array_reduce)
    4675             : {
    4676             :         zval *input;
    4677             :         zval args[2];
    4678             :         zval *operand;
    4679             :         zval result;
    4680             :         zval retval;
    4681             :         zend_fcall_info fci;
    4682          73 :         zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
    4683          73 :         zval *initial = NULL;
    4684             :         HashTable *htbl;
    4685             : 
    4686          73 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "af|z", &input, &fci, &fci_cache, &initial) == FAILURE) {
    4687           5 :                 return;
    4688             :         }
    4689             : 
    4690             : 
    4691          68 :         if (ZEND_NUM_ARGS() > 2) {
    4692          16 :                 ZVAL_DUP(&result, initial);
    4693             :         } else {
    4694          52 :                 ZVAL_NULL(&result);
    4695             :         }
    4696             : 
    4697             :         /* (zval **)input points to an element of argument stack
    4698             :          * the base pointer of which is subject to change.
    4699             :          * thus we need to keep the pointer to the hashtable for safety */
    4700          68 :         htbl = Z_ARRVAL_P(input);
    4701             : 
    4702          68 :         if (zend_hash_num_elements(htbl) == 0) {
    4703           3 :                 RETURN_ZVAL(&result, 1, 1);
    4704             :         }
    4705             : 
    4706          67 :         fci.retval = &retval;
    4707          67 :         fci.param_count = 2;
    4708          67 :         fci.no_separation = 0;
    4709             : 
    4710       43555 :         ZEND_HASH_FOREACH_VAL(htbl, operand) {
    4711       21744 :                 ZVAL_COPY(&args[0], &result);
    4712       21744 :                 ZVAL_COPY(&args[1], operand);
    4713       21744 :                 fci.params = args;
    4714             : 
    4715       65232 :                 if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
    4716       21744 :                         zval_ptr_dtor(&args[1]);
    4717       21744 :                         zval_ptr_dtor(&args[0]);
    4718       21744 :                         zval_ptr_dtor(&result);
    4719       21744 :                         ZVAL_COPY_VALUE(&result, &retval);
    4720             :                 } else {
    4721           0 :                         zval_ptr_dtor(&args[1]);
    4722           0 :                         zval_ptr_dtor(&args[0]);
    4723           0 :                         return;
    4724             :                 }
    4725             :         } ZEND_HASH_FOREACH_END();
    4726             : 
    4727         201 :         RETVAL_ZVAL(&result, 1, 1);
    4728             : }
    4729             : /* }}} */
    4730             : 
    4731             : /* {{{ proto array array_filter(array input [, mixed callback])
    4732             :    Filters elements from the array via the callback. */
    4733         124 : PHP_FUNCTION(array_filter)
    4734             : {
    4735             :         zval *array;
    4736             :         zval *operand;
    4737             :         zval *key;
    4738             :         zval args[2];
    4739             :         zval retval;
    4740         124 :         zend_bool have_callback = 0;
    4741         124 :         zend_long use_type = 0;
    4742             :         zend_string *string_key;
    4743         124 :         zend_fcall_info fci = empty_fcall_info;
    4744         124 :         zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
    4745             :         zend_ulong num_key;
    4746             : 
    4747         124 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|fl", &array, &fci, &fci_cache, &use_type) == FAILURE) {
    4748          59 :                 return;
    4749             :         }
    4750             : 
    4751          65 :         array_init(return_value);
    4752          65 :         if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) {
    4753           1 :                 return;
    4754             :         }
    4755             : 
    4756          64 :         if (ZEND_NUM_ARGS() > 1) {
    4757          52 :                 have_callback = 1;
    4758          52 :                 fci.no_separation = 0;
    4759          52 :                 fci.retval = &retval;
    4760          52 :                 if (use_type == ARRAY_FILTER_USE_BOTH) {
    4761           4 :                         fci.param_count = 2;
    4762           4 :                         key = &args[1];
    4763             :                 } else {
    4764          48 :                         fci.param_count = 1;
    4765          48 :                         key = &args[0];
    4766             :                 }
    4767             :         }
    4768             : 
    4769        2262 :         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, operand) {
    4770        1099 :                 if (have_callback) {
    4771        1038 :                         if (use_type) {
    4772             :                                 /* Set up the key */
    4773          26 :                                 if (!string_key) {
    4774          20 :                                         ZVAL_LONG(key, num_key);
    4775             :                                 } else {
    4776           6 :                                         ZVAL_STR_COPY(key, string_key);
    4777             :                                 }
    4778             :                         }
    4779        1038 :                         if (use_type != ARRAY_FILTER_USE_KEY) {
    4780        1034 :                                 ZVAL_COPY(&args[0], operand);
    4781             :                         }
    4782        1038 :                         fci.params = args;
    4783             : 
    4784        1038 :                         if (zend_call_function(&fci, &fci_cache) == SUCCESS) {
    4785        1038 :                                 zval_ptr_dtor(&args[0]);
    4786        1038 :                                 if (use_type == ARRAY_FILTER_USE_BOTH) {
    4787          22 :                                         zval_ptr_dtor(&args[1]);
    4788             :                                 }
    4789        1038 :                                 if (!Z_ISUNDEF(retval)) {
    4790        1038 :                                         int retval_true = zend_is_true(&retval);
    4791             : 
    4792        1038 :                                         zval_ptr_dtor(&retval);
    4793        1038 :                                         if (!retval_true) {
    4794         145 :                                                 continue;
    4795             :                                         }
    4796             :                                 } else {
    4797           0 :                                         continue;
    4798             :                                 }
    4799             :                         } else {
    4800           0 :                                 zval_ptr_dtor(&args[0]);
    4801           0 :                                 if (use_type == ARRAY_FILTER_USE_BOTH) {
    4802           0 :                                         zval_ptr_dtor(&args[1]);
    4803             :                                 }
    4804           0 :                                 return;
    4805             :                         }
    4806          61 :                 } else if (!zend_is_true(operand)) {
    4807          26 :                         continue;
    4808             :                 }
    4809             : 
    4810         928 :                 if (string_key) {
    4811          17 :                         operand = zend_hash_update(Z_ARRVAL_P(return_value), string_key, operand);
    4812             :                 } else {
    4813         911 :                         operand = zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, operand);
    4814             :                 }
    4815         928 :                 zval_add_ref(operand);
    4816             :         } ZEND_HASH_FOREACH_END();
    4817             : }
    4818             : /* }}} */
    4819             : 
    4820             : /* {{{ proto array array_map(mixed callback, array input1 [, array input2 ,...])
    4821             :    Applies the callback to the elements in given arrays. */
    4822         281 : PHP_FUNCTION(array_map)
    4823             : {
    4824         281 :         zval *arrays = NULL;
    4825         281 :         int n_arrays = 0;
    4826             :         zval result;
    4827         281 :         zend_fcall_info fci = empty_fcall_info;
    4828         281 :         zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
    4829             :         int i;
    4830         281 :         uint32_t k, maxlen = 0;
    4831             : 
    4832             : #ifndef FAST_ZPP
    4833             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "f!+", &fci, &fci_cache, &arrays, &n_arrays) == FAILURE) {
    4834             :                 return;
    4835             :         }
    4836             : #else
    4837         281 :         ZEND_PARSE_PARAMETERS_START(2, -1)
    4838         837 :                 Z_PARAM_FUNC_EX(fci, fci_cache, 1, 0)
    4839         237 :                 Z_PARAM_VARIADIC('+', arrays, n_arrays)
    4840         281 :         ZEND_PARSE_PARAMETERS_END();
    4841             : #endif
    4842             : 
    4843         237 :         RETVAL_NULL();
    4844             : 
    4845         237 :         if (n_arrays == 1) {
    4846             :                 zend_ulong num_key;
    4847             :                 zend_string *str_key;
    4848             :                 zval *zv, arg;
    4849             : 
    4850         213 :                 if (Z_TYPE(arrays[0]) != IS_ARRAY) {
    4851          26 :                         php_error_docref(NULL, E_WARNING, "Argument #%d should be an array", 2);
    4852          26 :                         return;
    4853             :                 }
    4854         187 :                 maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[0]));
    4855             : 
    4856             :                 /* Short-circuit: if no callback and only one array, just return it. */
    4857         187 :                 if (!ZEND_FCI_INITIALIZED(fci)) {
    4858           6 :                         RETVAL_ZVAL(&arrays[0], 1, 0);
    4859           3 :                         return;
    4860             :                 }
    4861             : 
    4862         184 :                 array_init_size(return_value, maxlen);
    4863             : 
    4864        1865 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(arrays[0]), num_key, str_key, zv) {
    4865         834 :                         fci.retval = &result;
    4866         834 :                         fci.param_count = 1;
    4867         834 :                         fci.params = &arg;
    4868         834 :                         fci.no_separation = 0;
    4869             : 
    4870         834 :                         ZVAL_COPY(&arg, zv);
    4871             : 
    4872        1668 :                         if (zend_call_function(&fci, &fci_cache) != SUCCESS || Z_TYPE(result) == IS_UNDEF) {
    4873             :                                 zval_dtor(return_value);
    4874           1 :                                 zval_ptr_dtor(&arg);
    4875           1 :                                 RETURN_NULL();
    4876             :                         } else {
    4877         833 :                                 zval_ptr_dtor(&arg);
    4878             :                         }
    4879         833 :                         if (str_key) {
    4880          96 :                                 zend_hash_add_new(Z_ARRVAL_P(return_value), str_key, &result);
    4881             :                         } else {
    4882         737 :                                 zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &result);
    4883             :                         }
    4884             :                 } ZEND_HASH_FOREACH_END();
    4885             :         } else {
    4886          24 :                 uint32_t *array_pos = (HashPosition *)ecalloc(n_arrays, sizeof(HashPosition));
    4887             : 
    4888          79 :                 for (i = 0; i < n_arrays; i++) {
    4889         110 :                         if (Z_TYPE(arrays[i]) != IS_ARRAY) {
    4890           0 :                                 php_error_docref(NULL, E_WARNING, "Argument #%d should be an array", i + 2);
    4891           0 :                                 efree(array_pos);
    4892           0 :                                 return;
    4893             :                         }
    4894          55 :                         if (zend_hash_num_elements(Z_ARRVAL(arrays[i])) > maxlen) {
    4895          24 :                                 maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[i]));
    4896             :                         }
    4897             :                 }
    4898             : 
    4899          24 :                 array_init_size(return_value, maxlen);
    4900             : 
    4901          24 :                 if (!ZEND_FCI_INITIALIZED(fci)) {
    4902             :                         zval zv;
    4903             : 
    4904             :                         /* We iterate through all the arrays at once. */
    4905          24 :                         for (k = 0; k < maxlen; k++) {
    4906             : 
    4907             :                                 /* If no callback, the result will be an array, consisting of current
    4908             :                                  * entries from all arrays. */
    4909          17 :                                 array_init_size(&result, n_arrays);
    4910             : 
    4911          63 :                                 for (i = 0; i < n_arrays; i++) {
    4912             :                                         /* If this array still has elements, add the current one to the
    4913             :                                          * parameter list, otherwise use null value. */
    4914          46 :                                         uint32_t pos = array_pos[i];
    4915             :                                         while (1) {
    4916          46 :                                                 if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
    4917           0 :                                                         ZVAL_NULL(&zv);
    4918           0 :                                                         break;
    4919          92 :                                                 } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
    4920          46 :                                                         ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arData[pos].val);
    4921          46 :                                                         array_pos[i] = pos + 1;
    4922          46 :                                                         break;
    4923             :                                                 }
    4924           0 :                                                 pos++;
    4925           0 :                                         }
    4926             : 
    4927          46 :                                         zend_hash_next_index_insert_new(Z_ARRVAL(result), &zv);
    4928             :                                 }
    4929             : 
    4930          17 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &result);
    4931             :                         }
    4932             :                 } else {
    4933          17 :                         zval *params = (zval *)safe_emalloc(n_arrays, sizeof(zval), 0);
    4934             : 
    4935             :                         /* We iterate through all the arrays at once. */
    4936          65 :                         for (k = 0; k < maxlen; k++) {
    4937         152 :                                 for (i = 0; i < n_arrays; i++) {
    4938             :                                         /* If this array still has elements, add the current one to the
    4939             :                                          * parameter list, otherwise use null value. */
    4940         103 :                                         uint32_t pos = array_pos[i];
    4941             :                                         while (1) {
    4942         103 :                                                 if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
    4943          12 :                                                         ZVAL_NULL(&params[i]);
    4944          12 :                                                         break;
    4945         182 :                                                 } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
    4946          91 :                                                         ZVAL_COPY(&params[i], &Z_ARRVAL(arrays[i])->arData[pos].val);
    4947          91 :                                                         array_pos[i] = pos + 1;
    4948          91 :                                                         break;
    4949             :                                                 }
    4950           0 :                                                 pos++;
    4951           0 :                                         }
    4952             :                                 }
    4953             : 
    4954          49 :                                 fci.retval = &result;
    4955          49 :                                 fci.param_count = n_arrays;
    4956          49 :                                 fci.params = params;
    4957          49 :                                 fci.no_separation = 0;
    4958             : 
    4959          98 :                                 if (zend_call_function(&fci, &fci_cache) != SUCCESS || Z_TYPE(result) == IS_UNDEF) {
    4960           1 :                                         efree(array_pos);
    4961             :                                         zval_dtor(return_value);
    4962           3 :                                         for (i = 0; i < n_arrays; i++) {
    4963           2 :                                                 zval_ptr_dtor(&params[i]);
    4964             :                                         }
    4965           1 :                                         efree(params);
    4966           1 :                                         RETURN_NULL();
    4967             :                                 } else {
    4968         149 :                                         for (i = 0; i < n_arrays; i++) {
    4969         101 :                                                 zval_ptr_dtor(&params[i]);
    4970             :                                         }
    4971             :                                 }
    4972             : 
    4973          48 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &result);
    4974             :                         }
    4975             : 
    4976          16 :                         efree(params);
    4977             :                 }
    4978          23 :                 efree(array_pos);
    4979             :         }
    4980             : }
    4981             : /* }}} */
    4982             : 
    4983             : /* {{{ proto bool array_key_exists(mixed key, array search)
    4984             :    Checks if the given key or index exists in the array */
    4985      142681 : PHP_FUNCTION(array_key_exists)
    4986             : {
    4987             :         zval *key;                                      /* key to check for */
    4988             :         HashTable *array;                       /* array to check in */
    4989             : 
    4990             : #ifndef FAST_ZPP
    4991             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zH", &key, &array) == FAILURE) {
    4992             :                 return;
    4993             :         }
    4994             : #else
    4995      142681 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    4996      142675 :                 Z_PARAM_ZVAL(key)
    4997      428025 :                 Z_PARAM_ARRAY_OR_OBJECT_HT(array)
    4998      142681 :         ZEND_PARSE_PARAMETERS_END();
    4999             : #endif
    5000             : 
    5001      285292 :         switch (Z_TYPE_P(key)) {
    5002             :                 case IS_STRING:
    5003      284676 :                         if (zend_symtable_exists(array, Z_STR_P(key))) {
    5004       10347 :                                 RETURN_TRUE;
    5005             :                         }
    5006      131991 :                         RETURN_FALSE;
    5007             :                 case IS_LONG:
    5008         235 :                         if (zend_hash_index_exists(array, Z_LVAL_P(key))) {
    5009         101 :                                 RETURN_TRUE;
    5010             :                         }
    5011         134 :                         RETURN_FALSE;
    5012             :                 case IS_NULL:
    5013          55 :                         if (zend_hash_exists(array, STR_EMPTY_ALLOC())) {
    5014          27 :                                 RETURN_TRUE;
    5015             :                         }
    5016          28 :                         RETURN_FALSE;
    5017             : 
    5018             :                 default:
    5019          18 :                         php_error_docref(NULL, E_WARNING, "The first argument should be either a string or an integer");
    5020          18 :                         RETURN_FALSE;
    5021             :         }
    5022             : }
    5023             : /* }}} */
    5024             : 
    5025             : /* {{{ proto array array_chunk(array input, int size [, bool preserve_keys])
    5026             :    Split array into chunks */
    5027         521 : PHP_FUNCTION(array_chunk)
    5028             : {
    5029         521 :         int argc = ZEND_NUM_ARGS(), num_in;
    5030         521 :         zend_long size, current = 0;
    5031             :         zend_string *str_key;
    5032             :         zend_ulong num_key;
    5033         521 :         zend_bool preserve_keys = 0;
    5034         521 :         zval *input = NULL;
    5035             :         zval chunk;
    5036             :         zval *entry;
    5037             : 
    5038         521 :         if (zend_parse_parameters(argc, "al|b", &input, &size, &preserve_keys) == FAILURE) {
    5039         106 :                 return;
    5040             :         }
    5041             :         /* Do bounds checking for size parameter. */
    5042         415 :         if (size < 1) {
    5043         107 :                 php_error_docref(NULL, E_WARNING, "Size parameter expected to be greater than 0");
    5044         107 :                 return;
    5045             :         }
    5046             : 
    5047         308 :         num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
    5048             : 
    5049         308 :         if (size > num_in) {
    5050          34 :                 size = num_in > 0 ? num_in : 1;
    5051             :         }
    5052             : 
    5053         308 :         array_init_size(return_value, (uint32_t)(((num_in - 1) / size) + 1));
    5054             : 
    5055         308 :         ZVAL_UNDEF(&chunk);
    5056             : 
    5057        3340 :         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, str_key, entry) {
    5058             :                 /* If new chunk, create and initialize it. */
    5059        1468 :                 if (Z_TYPE(chunk) == IS_UNDEF) {
    5060         683 :                         array_init_size(&chunk, (uint32_t)size);
    5061             :                 }
    5062             : 
    5063             :                 /* Add entry to the chunk, preserving keys if necessary. */
    5064        1468 :                 if (preserve_keys) {
    5065         507 :                         if (str_key) {
    5066          93 :                                 entry = zend_hash_update(Z_ARRVAL(chunk), str_key, entry);
    5067             :                         } else {
    5068         414 :                                 entry = zend_hash_index_update(Z_ARRVAL(chunk), num_key, entry);
    5069             :                         }
    5070             :                 } else {
    5071         961 :                         entry = zend_hash_next_index_insert(Z_ARRVAL(chunk), entry);
    5072             :                 }
    5073        1468 :                 zval_add_ref(entry);
    5074             : 
    5075             :                 /* If reached the chunk size, add it to the result array, and reset the
    5076             :                  * pointer. */
    5077        1468 :                 if (!(++current % size)) {
    5078         576 :                         add_next_index_zval(return_value, &chunk);
    5079         576 :                         ZVAL_UNDEF(&chunk);
    5080             :                 }
    5081             :         } ZEND_HASH_FOREACH_END();
    5082             : 
    5083             :         /* Add the final chunk if there is one. */
    5084         308 :         if (Z_TYPE(chunk) != IS_UNDEF) {
    5085         107 :                 add_next_index_zval(return_value, &chunk);
    5086             :         }
    5087             : }
    5088             : /* }}} */
    5089             : 
    5090             : /* {{{ proto array array_combine(array keys, array values)
    5091             :    Creates an array by using the elements of the first parameter as keys and the elements of the second as the corresponding values */
    5092         118 : PHP_FUNCTION(array_combine)
    5093             : {
    5094             :         zval *values, *keys;
    5095         118 :         uint32_t pos_values = 0;
    5096             :         zval *entry_keys, *entry_values;
    5097             :         int num_keys, num_values;
    5098             : 
    5099         118 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa", &keys, &values) == FAILURE) {
    5100          51 :                 return;
    5101             :         }
    5102             : 
    5103          67 :         num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys));
    5104          67 :         num_values = zend_hash_num_elements(Z_ARRVAL_P(values));
    5105             : 
    5106          67 :         if (num_keys != num_values) {
    5107           3 :                 php_error_docref(NULL, E_WARNING, "Both parameters should have an equal number of elements");
    5108           3 :                 RETURN_FALSE;
    5109             :         }
    5110             : 
    5111          64 :         array_init_size(return_value, num_keys);
    5112             : 
    5113          64 :         if (!num_keys) {
    5114           4 :                 return;
    5115             :         }
    5116             : 
    5117         440 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry_keys) {
    5118             :                 while (1) {
    5119         194 :                         if (pos_values >= Z_ARRVAL_P(values)->nNumUsed) {
    5120           0 :                                 break;
    5121         388 :                         } else if (Z_TYPE(Z_ARRVAL_P(values)->arData[pos_values].val) != IS_UNDEF) {
    5122         181 :                                 entry_values = &Z_ARRVAL_P(values)->arData[pos_values].val;
    5123         181 :                                 if (Z_TYPE_P(entry_keys) == IS_LONG) {
    5124          43 :                                         entry_values = zend_hash_index_update(Z_ARRVAL_P(return_value),
    5125             :                                                 Z_LVAL_P(entry_keys), entry_values);
    5126             :                                 } else {
    5127         138 :                                         zend_string *key = zval_get_string(entry_keys);
    5128         276 :                                         entry_values = zend_symtable_update(Z_ARRVAL_P(return_value),
    5129             :                                                 key, entry_values);
    5130             :                                         zend_string_release(key);
    5131             :                                 }
    5132         181 :                                 zval_add_ref(entry_values);
    5133         181 :                                 pos_values++;
    5134         181 :                                 break;
    5135             :                         }
    5136          13 :                         pos_values++;
    5137          13 :                 }
    5138             :         } ZEND_HASH_FOREACH_END();
    5139             : }
    5140             : /* }}} */
    5141             : 
    5142             : /*
    5143             :  * Local variables:
    5144             :  * tab-width: 4
    5145             :  * c-basic-offset: 4
    5146             :  * End:
    5147             :  * vim600: noet sw=4 ts=4 fdm=marker
    5148             :  * vim<600: noet sw=4 ts=4
    5149             :  */

Generated by: LCOV version 1.10

Generated at Thu, 21 May 2015 19:59:05 +0000 (7 days ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.