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

Generated by: LCOV version 1.10

Generated at Wed, 22 Oct 2014 07:24:58 +0000 (3 days ago)

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