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: 2054 2201 93.3 %
Date: 2014-12-13 Functions: 108 108 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 13 Dec 2014 06:16:22 +0000 (8 days ago)

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