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