1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 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@php.net>                                 |
16    |          Zeev Suraski <zeev@php.net>                                 |
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 #include "php.h"
25 #include "php_ini.h"
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include <time.h>
30 #include <stdio.h>
31 #include <string.h>
32 #ifdef PHP_WIN32
33 #include "win32/unistd.h"
34 #endif
35 #include "zend_globals.h"
36 #include "zend_interfaces.h"
37 #include "php_globals.h"
38 #include "php_array.h"
39 #include "basic_functions.h"
40 #include "php_string.h"
41 #include "php_rand.h"
42 #include "php_math.h"
43 #include "zend_smart_str.h"
44 #include "zend_bitset.h"
45 #include "ext/spl/spl_array.h"
46 
47 /* {{{ defines */
48 #define EXTR_OVERWRITE			0
49 #define EXTR_SKIP				1
50 #define EXTR_PREFIX_SAME		2
51 #define	EXTR_PREFIX_ALL			3
52 #define	EXTR_PREFIX_INVALID		4
53 #define	EXTR_PREFIX_IF_EXISTS	5
54 #define	EXTR_IF_EXISTS			6
55 
56 #define EXTR_REFS				0x100
57 
58 #define CASE_LOWER				0
59 #define CASE_UPPER				1
60 
61 #define DIFF_NORMAL			1
62 #define DIFF_KEY			2
63 #define DIFF_ASSOC			6
64 #define DIFF_COMP_DATA_NONE    -1
65 #define DIFF_COMP_DATA_INTERNAL 0
66 #define DIFF_COMP_DATA_USER     1
67 #define DIFF_COMP_KEY_INTERNAL  0
68 #define DIFF_COMP_KEY_USER      1
69 
70 #define INTERSECT_NORMAL		1
71 #define INTERSECT_KEY			2
72 #define INTERSECT_ASSOC			6
73 #define INTERSECT_COMP_DATA_NONE    -1
74 #define INTERSECT_COMP_DATA_INTERNAL 0
75 #define INTERSECT_COMP_DATA_USER     1
76 #define INTERSECT_COMP_KEY_INTERNAL  0
77 #define INTERSECT_COMP_KEY_USER      1
78 /* }}} */
79 
80 ZEND_DECLARE_MODULE_GLOBALS(array)
81 
82 /* {{{ php_array_init_globals
83 */
php_array_init_globals(zend_array_globals *array_globals)84 static void php_array_init_globals(zend_array_globals *array_globals)
85 {
86 	memset(array_globals, 0, sizeof(zend_array_globals));
87 }
88 /* }}} */
89 
PHP_MINIT_FUNCTIONnull90 PHP_MINIT_FUNCTION(array) /* {{{ */
91 {
92 	ZEND_INIT_MODULE_GLOBALS(array, php_array_init_globals, NULL);
93 
94 	REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", EXTR_OVERWRITE, CONST_CS | CONST_PERSISTENT);
95 	REGISTER_LONG_CONSTANT("EXTR_SKIP", EXTR_SKIP, CONST_CS | CONST_PERSISTENT);
96 	REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT);
97 	REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT);
98 	REGISTER_LONG_CONSTANT("EXTR_PREFIX_INVALID", EXTR_PREFIX_INVALID, CONST_CS | CONST_PERSISTENT);
99 	REGISTER_LONG_CONSTANT("EXTR_PREFIX_IF_EXISTS", EXTR_PREFIX_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
100 	REGISTER_LONG_CONSTANT("EXTR_IF_EXISTS", EXTR_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
101 	REGISTER_LONG_CONSTANT("EXTR_REFS", EXTR_REFS, CONST_CS | CONST_PERSISTENT);
102 
103 	REGISTER_LONG_CONSTANT("SORT_ASC", PHP_SORT_ASC, CONST_CS | CONST_PERSISTENT);
104 	REGISTER_LONG_CONSTANT("SORT_DESC", PHP_SORT_DESC, CONST_CS | CONST_PERSISTENT);
105 
106 	REGISTER_LONG_CONSTANT("SORT_REGULAR", PHP_SORT_REGULAR, CONST_CS | CONST_PERSISTENT);
107 	REGISTER_LONG_CONSTANT("SORT_NUMERIC", PHP_SORT_NUMERIC, CONST_CS | CONST_PERSISTENT);
108 	REGISTER_LONG_CONSTANT("SORT_STRING", PHP_SORT_STRING, CONST_CS | CONST_PERSISTENT);
109 	REGISTER_LONG_CONSTANT("SORT_LOCALE_STRING", PHP_SORT_LOCALE_STRING, CONST_CS | CONST_PERSISTENT);
110 	REGISTER_LONG_CONSTANT("SORT_NATURAL", PHP_SORT_NATURAL, CONST_CS | CONST_PERSISTENT);
111 	REGISTER_LONG_CONSTANT("SORT_FLAG_CASE", PHP_SORT_FLAG_CASE, CONST_CS | CONST_PERSISTENT);
112 
113 	REGISTER_LONG_CONSTANT("CASE_LOWER", CASE_LOWER, CONST_CS | CONST_PERSISTENT);
114 	REGISTER_LONG_CONSTANT("CASE_UPPER", CASE_UPPER, CONST_CS | CONST_PERSISTENT);
115 
116 	REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
117 	REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
118 
119 	REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT);
120 	REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT);
121 
122 	return SUCCESS;
123 }
124 /* }}} */
125 
PHP_MSHUTDOWN_FUNCTIONnull126 PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
127 {
128 #ifdef ZTS
129 	ts_free_id(array_globals_id);
130 #endif
131 
132 	return SUCCESS;
133 }
134 /* }}} */
135 
php_array_key_compare(const void *a, const void *b)136 static int php_array_key_compare(const void *a, const void *b) /* {{{ */
137 {
138 	Bucket *f = (Bucket *) a;
139 	Bucket *s = (Bucket *) b;
140 	zend_uchar t;
141 	zend_long l1, l2;
142 	double d;
143 
144 	if (f->key == NULL) {
145 		if (s->key == NULL) {
146 			return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
147 		} else {
148 			l1 = (zend_long)f->h;
149 			t = is_numeric_string(s->key->val, s->key->len, &l2, &d, 1);
150 			if (t == IS_LONG) {
151 				/* pass */
152 			} else if (t == IS_DOUBLE) {
153 				return ZEND_NORMALIZE_BOOL((double)l1 - d);
154 			} else {
155 				l2 = 0;
156 			}
157 		}
158 	} else {
159 		if (s->key) {
160 			return zendi_smart_strcmp(f->key, s->key);
161 		} else {
162 			l2 = (zend_long)s->h;
163 			t = is_numeric_string(f->key->val, f->key->len, &l1, &d, 1);
164 			if (t == IS_LONG) {
165 				/* pass */
166 			} else if (t == IS_DOUBLE) {
167 				return ZEND_NORMALIZE_BOOL(d - (double)l2);
168 			} else {
169 				l1 = 0;
170 			}
171 		}
172 	}
173 	return ZEND_NORMALIZE_BOOL(l1 - l2);
174 }
175 /* }}} */
176 
php_array_reverse_key_compare(const void *a, const void *b)177 static int php_array_reverse_key_compare(const void *a, const void *b) /* {{{ */
178 {
179 	return php_array_key_compare(b, a);
180 }
181 /* }}} */
182 
php_array_key_compare_numeric(const void *a, const void *b)183 static int php_array_key_compare_numeric(const void *a, const void *b) /* {{{ */
184 {
185 	Bucket *f = (Bucket *) a;
186 	Bucket *s = (Bucket *) b;
187 
188 	if (f->key == NULL && s->key == NULL) {
189 		return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
190 	} else {
191 		double d1, d2;
192 		if (f->key) {
193 			d1 = zend_strtod(f->key->val, NULL);
194 		} else {
195 			d1 = (double)(zend_long)f->h;
196 		}
197 		if (s->key) {
198 			d2 = zend_strtod(s->key->val, NULL);
199 		} else {
200 			d2 = (double)(zend_long)s->h;
201 		}
202 		return ZEND_NORMALIZE_BOOL(d1 - d2);
203 	}
204 }
205 /* }}} */
206 
php_array_reverse_key_compare_numeric(const void *a, const void *b)207 static int php_array_reverse_key_compare_numeric(const void *a, const void *b) /* {{{ */
208 {
209 	return php_array_key_compare_numeric(b, a);
210 }
211 /* }}} */
212 
php_array_key_compare_string_case(const void *a, const void *b)213 static int php_array_key_compare_string_case(const void *a, const void *b) /* {{{ */
214 {
215 	Bucket *f = (Bucket *) a;
216 	Bucket *s = (Bucket *) b;
217 	const char *s1, *s2;
218 	size_t l1, l2;
219 	char buf1[MAX_LENGTH_OF_LONG + 1];
220 	char buf2[MAX_LENGTH_OF_LONG + 1];
221 
222 	if (f->key) {
223 		s1 = f->key->val;
224 		l1 = f->key->len;
225 	} else {
226 		s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
227 		l1 = buf1 + sizeof(buf1) - 1 - s1;
228 	}
229 	if (s->key) {
230 		s2 = s->key->val;
231 		l2 = s->key->len;
232 	} else {
233 		s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
234 		l2 = buf2 + sizeof(buf2) - 1 - s1;
235 	}
236 	return zend_binary_strcasecmp_l(s1, l1, s2, l2);
237 }
238 /* }}} */
239 
php_array_reverse_key_compare_string_case(const void *a, const void *b)240 static int php_array_reverse_key_compare_string_case(const void *a, const void *b) /* {{{ */
241 {
242 	return php_array_key_compare_string_case(b, a);
243 }
244 /* }}} */
245 
php_array_key_compare_string(const void *a, const void *b)246 static int php_array_key_compare_string(const void *a, const void *b) /* {{{ */
247 {
248 	Bucket *f = (Bucket *) a;
249 	Bucket *s = (Bucket *) b;
250 	const char *s1, *s2;
251 	size_t l1, l2;
252 	char buf1[MAX_LENGTH_OF_LONG + 1];
253 	char buf2[MAX_LENGTH_OF_LONG + 1];
254 
255 	if (f->key) {
256 		s1 = f->key->val;
257 		l1 = f->key->len;
258 	} else {
259 		s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
260 		l1 = buf1 + sizeof(buf1) - 1 - s1;
261 	}
262 	if (s->key) {
263 		s2 = s->key->val;
264 		l2 = s->key->len;
265 	} else {
266 		s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
267 		l2 = buf2 + sizeof(buf2) - 1 - s2;
268 	}
269 	return zend_binary_strcmp(s1, l1, s2, l2);
270 }
271 /* }}} */
272 
php_array_reverse_key_compare_string(const void *a, const void *b)273 static int php_array_reverse_key_compare_string(const void *a, const void *b) /* {{{ */
274 {
275 	return php_array_key_compare_string(b, a);
276 }
277 /* }}} */
278 
php_array_key_compare_string_natural_general(const void *a, const void *b, int fold_case)279 static int php_array_key_compare_string_natural_general(const void *a, const void *b, int fold_case) /* {{{ */
280 {
281 	Bucket *f = (Bucket *) a;
282 	Bucket *s = (Bucket *) b;
283 	const char *s1, *s2;
284 	size_t l1, l2;
285 	char buf1[MAX_LENGTH_OF_LONG + 1];
286 	char buf2[MAX_LENGTH_OF_LONG + 1];
287 
288 	if (f->key) {
289 		s1 = f->key->val;
290 		l1 = f->key->len;
291 	} else {
292 		s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
293 		l1 = buf1 + sizeof(buf1) - 1 - s1;
294 	}
295 	if (s->key) {
296 		s2 = s->key->val;
297 		l2 = s->key->len;
298 	} else {
299 		s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
300 		l2 = buf2 + sizeof(buf2) - 1 - s1;
301 	}
302 	return strnatcmp_ex(s1, l1, s2, l2, fold_case);
303 }
304 /* }}} */
305 
php_array_key_compare_string_natural_case(const void *a, const void *b)306 static int php_array_key_compare_string_natural_case(const void *a, const void *b) /* {{{ */
307 {
308 	return php_array_key_compare_string_natural_general(a, b, 1);
309 }
310 /* }}} */
311 
php_array_reverse_key_compare_string_natural_case(const void *a, const void *b)312 static int php_array_reverse_key_compare_string_natural_case(const void *a, const void *b) /* {{{ */
313 {
314 	return php_array_key_compare_string_natural_general(b, a, 1);
315 }
316 /* }}} */
317 
php_array_key_compare_string_natural(const void *a, const void *b)318 static int php_array_key_compare_string_natural(const void *a, const void *b) /* {{{ */
319 {
320 	return php_array_key_compare_string_natural_general(a, b, 0);
321 }
322 /* }}} */
323 
php_array_reverse_key_compare_string_natural(const void *a, const void *b)324 static int php_array_reverse_key_compare_string_natural(const void *a, const void *b) /* {{{ */
325 {
326 	return php_array_key_compare_string_natural_general(b, a, 0);
327 }
328 /* }}} */
329 
php_array_key_compare_string_locale(const void *a, const void *b)330 static int php_array_key_compare_string_locale(const void *a, const void *b) /* {{{ */
331 {
332 	Bucket *f = (Bucket *) a;
333 	Bucket *s = (Bucket *) b;
334 	const char *s1, *s2;
335 	char buf1[MAX_LENGTH_OF_LONG + 1];
336 	char buf2[MAX_LENGTH_OF_LONG + 1];
337 
338 	if (f->key) {
339 		s1 = f->key->val;
340 	} else {
341 		s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
342 	}
343 	if (s->key) {
344 		s2 = s->key->val;
345 	} else {
346 		s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
347 	}
348 	return strcoll(s1, s2);
349 }
350 /* }}} */
351 
php_array_reverse_key_compare_string_locale(const void *a, const void *b)352 static int php_array_reverse_key_compare_string_locale(const void *a, const void *b) /* {{{ */
353 {
354 	return php_array_key_compare_string_locale(b, a);
355 }
356 /* }}} */
357 
358 /* Numbers are always smaller than strings int this function as it
359  * anyway doesn't make much sense to compare two different data types.
360  * This keeps it consistent and simple.
361  *
362  * This is not correct any more, depends on what compare_func is set to.
363  */
php_array_data_compare(const void *a, const void *b)364 static int php_array_data_compare(const void *a, const void *b) /* {{{ */
365 {
366 	Bucket *f;
367 	Bucket *s;
368 	zval result;
369 	zval *first;
370 	zval *second;
371 
372 	f = (Bucket *) a;
373 	s = (Bucket *) b;
374 
375 	first = &f->val;
376 	second = &s->val;
377 
378 	if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
379 		first = Z_INDIRECT_P(first);
380 	}
381 	if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
382 		second = Z_INDIRECT_P(second);
383 	}
384 	if (compare_function(&result, first, second) == FAILURE) {
385 		return 0;
386 	}
387 
388 	ZEND_ASSERT(Z_TYPE(result) == IS_LONG);
389 	return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
390 }
391 /* }}} */
392 
php_array_reverse_data_compare(const void *a, const void *b)393 static int php_array_reverse_data_compare(const void *a, const void *b) /* {{{ */
394 {
395 	return php_array_data_compare(a, b) * -1;
396 }
397 /* }}} */
398 
php_array_data_compare_numeric(const void *a, const void *b)399 static int php_array_data_compare_numeric(const void *a, const void *b) /* {{{ */
400 {
401 	Bucket *f;
402 	Bucket *s;
403 	zval *first;
404 	zval *second;
405 
406 	f = (Bucket *) a;
407 	s = (Bucket *) b;
408 
409 	first = &f->val;
410 	second = &s->val;
411 
412 	if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
413 		first = Z_INDIRECT_P(first);
414 	}
415 	if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
416 		second = Z_INDIRECT_P(second);
417 	}
418 
419 	return numeric_compare_function(first, second);
420 }
421 /* }}} */
422 
php_array_reverse_data_compare_numeric(const void *a, const void *b)423 static int php_array_reverse_data_compare_numeric(const void *a, const void *b) /* {{{ */
424 {
425 	return php_array_data_compare_numeric(b, a);
426 }
427 /* }}} */
428 
php_array_data_compare_string_case(const void *a, const void *b)429 static int php_array_data_compare_string_case(const void *a, const void *b) /* {{{ */
430 {
431 	Bucket *f;
432 	Bucket *s;
433 	zval *first;
434 	zval *second;
435 
436 	f = (Bucket *) a;
437 	s = (Bucket *) b;
438 
439 	first = &f->val;
440 	second = &s->val;
441 
442 	if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
443 		first = Z_INDIRECT_P(first);
444 	}
445 	if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
446 		second = Z_INDIRECT_P(second);
447 	}
448 
449 	return string_case_compare_function(first, second);
450 }
451 /* }}} */
452 
php_array_reverse_data_compare_string_case(const void *a, const void *b)453 static int php_array_reverse_data_compare_string_case(const void *a, const void *b) /* {{{ */
454 {
455 	return php_array_data_compare_string_case(b, a);
456 }
457 /* }}} */
458 
php_array_data_compare_string(const void *a, const void *b)459 static int php_array_data_compare_string(const void *a, const void *b) /* {{{ */
460 {
461 	Bucket *f;
462 	Bucket *s;
463 	zval *first;
464 	zval *second;
465 
466 	f = (Bucket *) a;
467 	s = (Bucket *) b;
468 
469 	first = &f->val;
470 	second = &s->val;
471 
472 	if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
473 		first = Z_INDIRECT_P(first);
474 	}
475 	if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
476 		second = Z_INDIRECT_P(second);
477 	}
478 
479 	return string_compare_function(first, second);
480 }
481 /* }}} */
482 
php_array_reverse_data_compare_string(const void *a, const void *b)483 static int php_array_reverse_data_compare_string(const void *a, const void *b) /* {{{ */
484 {
485 	return php_array_data_compare_string(b, a);
486 }
487 /* }}} */
488 
php_array_natural_general_compare(const void *a, const void *b, int fold_case)489 static int php_array_natural_general_compare(const void *a, const void *b, int fold_case) /* {{{ */
490 {
491 	Bucket *f = (Bucket *) a;
492 	Bucket *s = (Bucket *) b;
493 	zend_string *tmp_str1, *tmp_str2;
494 	zend_string *str1 = zval_get_tmp_string(&f->val, &tmp_str1);
495 	zend_string *str2 = zval_get_tmp_string(&s->val, &tmp_str2);
496 
497 	int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
498 
499 	zend_tmp_string_release(tmp_str1);
500 	zend_tmp_string_release(tmp_str2);
501 	return result;
502 }
503 /* }}} */
504 
php_array_natural_compare(const void *a, const void *b)505 static int php_array_natural_compare(const void *a, const void *b) /* {{{ */
506 {
507 	return php_array_natural_general_compare(a, b, 0);
508 }
509 /* }}} */
510 
php_array_reverse_natural_compare(const void *a, const void *b)511 static int php_array_reverse_natural_compare(const void *a, const void *b) /* {{{ */
512 {
513 	return php_array_natural_general_compare(b, a, 0);
514 }
515 /* }}} */
516 
php_array_natural_case_compare(const void *a, const void *b)517 static int php_array_natural_case_compare(const void *a, const void *b) /* {{{ */
518 {
519 	return php_array_natural_general_compare(a, b, 1);
520 }
521 /* }}} */
522 
php_array_reverse_natural_case_compare(const void *a, const void *b)523 static int php_array_reverse_natural_case_compare(const void *a, const void *b) /* {{{ */
524 {
525 	return php_array_natural_general_compare(b, a, 1);
526 }
527 /* }}} */
528 
php_array_data_compare_string_locale(const void *a, const void *b)529 static int php_array_data_compare_string_locale(const void *a, const void *b) /* {{{ */
530 {
531 	Bucket *f;
532 	Bucket *s;
533 	zval *first;
534 	zval *second;
535 
536 	f = (Bucket *) a;
537 	s = (Bucket *) b;
538 
539 	first = &f->val;
540 	second = &s->val;
541 
542 	if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
543 		first = Z_INDIRECT_P(first);
544 	}
545 	if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
546 		second = Z_INDIRECT_P(second);
547 	}
548 
549 	return string_locale_compare_function(first, second);
550 }
551 /* }}} */
552 
php_array_reverse_data_compare_string_locale(const void *a, const void *b)553 static int php_array_reverse_data_compare_string_locale(const void *a, const void *b) /* {{{ */
554 {
555 	return php_array_data_compare_string_locale(b, a);
556 }
557 /* }}} */
558 
php_get_key_compare_func(zend_long sort_type, int reverse)559 static compare_func_t php_get_key_compare_func(zend_long sort_type, int reverse) /* {{{ */
560 {
561 	switch (sort_type & ~PHP_SORT_FLAG_CASE) {
562 		case PHP_SORT_NUMERIC:
563 			if (reverse) {
564 				return php_array_reverse_key_compare_numeric;
565 			} else {
566 				return php_array_key_compare_numeric;
567 			}
568 			break;
569 
570 		case PHP_SORT_STRING:
571 			if (sort_type & PHP_SORT_FLAG_CASE) {
572 				if (reverse) {
573 					return php_array_reverse_key_compare_string_case;
574 				} else {
575 					return php_array_key_compare_string_case;
576 				}
577 			} else {
578 				if (reverse) {
579 					return php_array_reverse_key_compare_string;
580 				} else {
581 					return php_array_key_compare_string;
582 				}
583 			}
584 			break;
585 
586 		case PHP_SORT_NATURAL:
587 			if (sort_type & PHP_SORT_FLAG_CASE) {
588 				if (reverse) {
589 					return php_array_reverse_key_compare_string_natural_case;
590 				} else {
591 					return php_array_key_compare_string_natural_case;
592 				}
593 			} else {
594 				if (reverse) {
595 					return php_array_reverse_key_compare_string_natural;
596 				} else {
597 					return php_array_key_compare_string_natural;
598 				}
599 			}
600 			break;
601 
602 		case PHP_SORT_LOCALE_STRING:
603 			if (reverse) {
604 				return php_array_reverse_key_compare_string_locale;
605 			} else {
606 				return php_array_key_compare_string_locale;
607 			}
608 			break;
609 
610 		case PHP_SORT_REGULAR:
611 		default:
612 			if (reverse) {
613 				return php_array_reverse_key_compare;
614 			} else {
615 				return php_array_key_compare;
616 			}
617 			break;
618 	}
619 	return NULL;
620 }
621 /* }}} */
622 
php_get_data_compare_func(zend_long sort_type, int reverse)623 static compare_func_t php_get_data_compare_func(zend_long sort_type, int reverse) /* {{{ */
624 {
625 	switch (sort_type & ~PHP_SORT_FLAG_CASE) {
626 		case PHP_SORT_NUMERIC:
627 			if (reverse) {
628 				return php_array_reverse_data_compare_numeric;
629 			} else {
630 				return php_array_data_compare_numeric;
631 			}
632 			break;
633 
634 		case PHP_SORT_STRING:
635 			if (sort_type & PHP_SORT_FLAG_CASE) {
636 				if (reverse) {
637 					return php_array_reverse_data_compare_string_case;
638 				} else {
639 					return php_array_data_compare_string_case;
640 				}
641 			} else {
642 				if (reverse) {
643 					return php_array_reverse_data_compare_string;
644 				} else {
645 					return php_array_data_compare_string;
646 				}
647 			}
648 			break;
649 
650 		case PHP_SORT_NATURAL:
651 			if (sort_type & PHP_SORT_FLAG_CASE) {
652 				if (reverse) {
653 					return php_array_reverse_natural_case_compare;
654 				} else {
655 					return php_array_natural_case_compare;
656 				}
657 			} else {
658 				if (reverse) {
659 					return php_array_reverse_natural_compare;
660 				} else {
661 					return php_array_natural_compare;
662 				}
663 			}
664 			break;
665 
666 		case PHP_SORT_LOCALE_STRING:
667 			if (reverse) {
668 				return php_array_reverse_data_compare_string_locale;
669 			} else {
670 				return php_array_data_compare_string_locale;
671 			}
672 			break;
673 
674 		case PHP_SORT_REGULAR:
675 		default:
676 			if (reverse) {
677 				return php_array_reverse_data_compare;
678 			} else {
679 				return php_array_data_compare;
680 			}
681 			break;
682 	}
683 	return NULL;
684 }
685 /* }}} */
686 
687 /* {{{ proto bool krsort(array &array_arg [, int sort_flags])
688    Sort an array by key value in reverse order */
PHP_FUNCTIONnull689 PHP_FUNCTION(krsort)
690 {
691 	zval *array;
692 	zend_long sort_type = PHP_SORT_REGULAR;
693 	compare_func_t cmp;
694 
695 	ZEND_PARSE_PARAMETERS_START(1, 2)
696 		Z_PARAM_ARRAY_EX(array, 0, 1)
697 		Z_PARAM_OPTIONAL
698 		Z_PARAM_LONG(sort_type)
699 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
700 
701 	cmp = php_get_key_compare_func(sort_type, 1);
702 
703 	if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
704 		RETURN_FALSE;
705 	}
706 	RETURN_TRUE;
707 }
708 /* }}} */
709 
710 /* {{{ proto bool ksort(array &array_arg [, int sort_flags])
711    Sort an array by key */
PHP_FUNCTIONnull712 PHP_FUNCTION(ksort)
713 {
714 	zval *array;
715 	zend_long sort_type = PHP_SORT_REGULAR;
716 	compare_func_t cmp;
717 
718 	ZEND_PARSE_PARAMETERS_START(1, 2)
719 		Z_PARAM_ARRAY_EX(array, 0, 1)
720 		Z_PARAM_OPTIONAL
721 		Z_PARAM_LONG(sort_type)
722 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
723 
724 	cmp = php_get_key_compare_func(sort_type, 0);
725 
726 	if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
727 		RETURN_FALSE;
728 	}
729 	RETURN_TRUE;
730 }
731 /* }}} */
732 
php_count_recursive(HashTable *ht)733 PHPAPI zend_long php_count_recursive(HashTable *ht) /* {{{ */
734 {
735 	zend_long cnt = 0;
736 	zval *element;
737 
738 	if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
739 		if (GC_IS_RECURSIVE(ht)) {
740 			php_error_docref(NULL, E_WARNING, "recursion detected");
741 			return 0;
742 		}
743 		GC_PROTECT_RECURSION(ht);
744 	}
745 
746 	cnt = zend_array_count(ht);
747 	ZEND_HASH_FOREACH_VAL(ht, element) {
748 		ZVAL_DEREF(element);
749 		if (Z_TYPE_P(element) == IS_ARRAY) {
750 			cnt += php_count_recursive(Z_ARRVAL_P(element));
751 		}
752 	} ZEND_HASH_FOREACH_END();
753 
754 	if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
755 		GC_UNPROTECT_RECURSION(ht);
756 	}
757 
758 	return cnt;
759 }
760 /* }}} */
761 
762 /* {{{ proto int count(mixed var [, int mode])
763    Count the number of elements in a variable (usually an array) */
PHP_FUNCTIONnull764 PHP_FUNCTION(count)
765 {
766 	zval *array;
767 	zend_long mode = COUNT_NORMAL;
768 	zend_long cnt;
769 
770 	ZEND_PARSE_PARAMETERS_START(1, 2)
771 		Z_PARAM_ZVAL(array)
772 		Z_PARAM_OPTIONAL
773 		Z_PARAM_LONG(mode)
774 	ZEND_PARSE_PARAMETERS_END();
775 
776 	switch (Z_TYPE_P(array)) {
777 		case IS_NULL:
778 			php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");
779 			RETURN_LONG(0);
780 			break;
781 		case IS_ARRAY:
782 			if (mode != COUNT_RECURSIVE) {
783 				cnt = zend_array_count(Z_ARRVAL_P(array));
784 			} else {
785 				cnt = php_count_recursive(Z_ARRVAL_P(array));
786 			}
787 			RETURN_LONG(cnt);
788 			break;
789 		case IS_OBJECT: {
790 			zval retval;
791 			/* first, we check if the handler is defined */
792 			if (Z_OBJ_HT_P(array)->count_elements) {
793 				RETVAL_LONG(1);
794 				if (SUCCESS == Z_OBJ_HT(*array)->count_elements(array, &Z_LVAL_P(return_value))) {
795 					return;
796 				}
797 				if (EG(exception)) {
798 					return;
799 				}
800 			}
801 			/* if not and the object implements Countable we call its count() method */
802 			if (instanceof_function(Z_OBJCE_P(array), zend_ce_countable)) {
803 				zend_call_method_with_0_params(array, NULL, NULL, "count", &retval);
804 				if (Z_TYPE(retval) != IS_UNDEF) {
805 					RETVAL_LONG(zval_get_long(&retval));
806 					zval_ptr_dtor(&retval);
807 				}
808 				return;
809 			}
810 
811 			/* If There's no handler and it doesn't implement Countable then add a warning */
812 			php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");
813 			RETURN_LONG(1);
814 			break;
815 		}
816 		default:
817 			php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");
818 			RETURN_LONG(1);
819 			break;
820 	}
821 }
822 /* }}} */
823 
php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case)824 static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
825 {
826 	zval *array;
827 
828 	ZEND_PARSE_PARAMETERS_START(1, 1)
829 		Z_PARAM_ARRAY_EX(array, 0, 1)
830 	ZEND_PARSE_PARAMETERS_END();
831 
832 	if (fold_case) {
833 		if (zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0) == FAILURE) {
834 			return;
835 		}
836 	} else {
837 		if (zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0) == FAILURE) {
838 			return;
839 		}
840 	}
841 
842 	RETURN_TRUE;
843 }
844 /* }}} */
845 
846 /* {{{ proto void natsort(array &array_arg)
847    Sort an array using natural sort */
PHP_FUNCTIONnull848 PHP_FUNCTION(natsort)
849 {
850 	php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
851 }
852 /* }}} */
853 
854 /* {{{ proto void natcasesort(array &array_arg)
855    Sort an array using case-insensitive natural sort */
PHP_FUNCTIONnull856 PHP_FUNCTION(natcasesort)
857 {
858 	php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
859 }
860 /* }}} */
861 
862 /* {{{ proto bool asort(array &array_arg [, int sort_flags])
863    Sort an array and maintain index association */
PHP_FUNCTIONnull864 PHP_FUNCTION(asort)
865 {
866 	zval *array;
867 	zend_long sort_type = PHP_SORT_REGULAR;
868 	compare_func_t cmp;
869 
870 	ZEND_PARSE_PARAMETERS_START(1, 2)
871 		Z_PARAM_ARRAY_EX(array, 0, 1)
872 		Z_PARAM_OPTIONAL
873 		Z_PARAM_LONG(sort_type)
874 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
875 
876 	cmp = php_get_data_compare_func(sort_type, 0);
877 
878 	if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
879 		RETURN_FALSE;
880 	}
881 	RETURN_TRUE;
882 }
883 /* }}} */
884 
885 /* {{{ proto bool arsort(array &array_arg [, int sort_flags])
886    Sort an array in reverse order and maintain index association */
PHP_FUNCTIONnull887 PHP_FUNCTION(arsort)
888 {
889 	zval *array;
890 	zend_long sort_type = PHP_SORT_REGULAR;
891 	compare_func_t cmp;
892 
893 	ZEND_PARSE_PARAMETERS_START(1, 2)
894 		Z_PARAM_ARRAY_EX(array, 0, 1)
895 		Z_PARAM_OPTIONAL
896 		Z_PARAM_LONG(sort_type)
897 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
898 
899 	cmp = php_get_data_compare_func(sort_type, 1);
900 
901 	if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
902 		RETURN_FALSE;
903 	}
904 	RETURN_TRUE;
905 }
906 /* }}} */
907 
908 /* {{{ proto bool sort(array &array_arg [, int sort_flags])
909    Sort an array */
PHP_FUNCTIONnull910 PHP_FUNCTION(sort)
911 {
912 	zval *array;
913 	zend_long sort_type = PHP_SORT_REGULAR;
914 	compare_func_t cmp;
915 
916 	ZEND_PARSE_PARAMETERS_START(1, 2)
917 		Z_PARAM_ARRAY_EX(array, 0, 1)
918 		Z_PARAM_OPTIONAL
919 		Z_PARAM_LONG(sort_type)
920 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
921 
922 	cmp = php_get_data_compare_func(sort_type, 0);
923 
924 	if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) == FAILURE) {
925 		RETURN_FALSE;
926 	}
927 	RETURN_TRUE;
928 }
929 /* }}} */
930 
931 /* {{{ proto bool rsort(array &array_arg [, int sort_flags])
932    Sort an array in reverse order */
PHP_FUNCTIONnull933 PHP_FUNCTION(rsort)
934 {
935 	zval *array;
936 	zend_long sort_type = PHP_SORT_REGULAR;
937 	compare_func_t cmp;
938 
939 	ZEND_PARSE_PARAMETERS_START(1, 2)
940 		Z_PARAM_ARRAY_EX(array, 0, 1)
941 		Z_PARAM_OPTIONAL
942 		Z_PARAM_LONG(sort_type)
943 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
944 
945 	cmp = php_get_data_compare_func(sort_type, 1);
946 
947 	if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) == FAILURE) {
948 		RETURN_FALSE;
949 	}
950 	RETURN_TRUE;
951 }
952 /* }}} */
953 
php_array_user_compare(const void *a, const void *b)954 static int php_array_user_compare(const void *a, const void *b) /* {{{ */
955 {
956 	Bucket *f;
957 	Bucket *s;
958 	zval args[2];
959 	zval retval;
960 
961 	f = (Bucket *) a;
962 	s = (Bucket *) b;
963 
964 	ZVAL_COPY(&args[0], &f->val);
965 	ZVAL_COPY(&args[1], &s->val);
966 
967 	BG(user_compare_fci).param_count = 2;
968 	BG(user_compare_fci).params = args;
969 	BG(user_compare_fci).retval = &retval;
970 	BG(user_compare_fci).no_separation = 0;
971 	if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
972 		zend_long ret = zval_get_long(&retval);
973 		zval_ptr_dtor(&retval);
974 		zval_ptr_dtor(&args[1]);
975 		zval_ptr_dtor(&args[0]);
976 		return ZEND_NORMALIZE_BOOL(ret);
977 	} else {
978 		zval_ptr_dtor(&args[1]);
979 		zval_ptr_dtor(&args[0]);
980 		return 0;
981 	}
982 }
983 /* }}} */
984 
985 /* check if comparison function is valid */
986 #define PHP_ARRAY_CMP_FUNC_CHECK(func_name)	\
987 	if (!zend_is_callable(*func_name, 0, NULL)) {	\
988 		php_error_docref(NULL, E_WARNING, "Invalid comparison function");	\
989 		BG(user_compare_fci) = old_user_compare_fci; \
990 		BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
991 		RETURN_FALSE;	\
992 	}	\
993 
994 	/* Clear FCI cache otherwise : for example the same or other array with
995 	 * (partly) the same key values has been sorted with uasort() or
996 	 * other sorting function the comparison is cached, however the name
997 	 * of the function for comparison is not respected. see bug #28739 AND #33295
998 	 *
999 	 * Following defines will assist in backup / restore values. */
1000 
1001 #define PHP_ARRAY_CMP_FUNC_VARS \
1002 	zend_fcall_info old_user_compare_fci; \
1003 	zend_fcall_info_cache old_user_compare_fci_cache \
1004 
1005 #define PHP_ARRAY_CMP_FUNC_BACKUP() \
1006 	old_user_compare_fci = BG(user_compare_fci); \
1007 	old_user_compare_fci_cache = BG(user_compare_fci_cache); \
1008 	BG(user_compare_fci_cache) = empty_fcall_info_cache; \
1009 
1010 #define PHP_ARRAY_CMP_FUNC_RESTORE() \
1011 	zend_release_fcall_info_cache(&BG(user_compare_fci_cache)); \
1012 	BG(user_compare_fci) = old_user_compare_fci; \
1013 	BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
1014 
php_usort(INTERNAL_FUNCTION_PARAMETERS, compare_func_t compare_func, zend_bool renumber)1015 static void php_usort(INTERNAL_FUNCTION_PARAMETERS, compare_func_t compare_func, zend_bool renumber) /* {{{ */
1016 {
1017 	zval *array;
1018 	zend_array *arr;
1019 	zend_bool retval;
1020 	PHP_ARRAY_CMP_FUNC_VARS;
1021 
1022 	PHP_ARRAY_CMP_FUNC_BACKUP();
1023 
1024 	ZEND_PARSE_PARAMETERS_START(2, 2)
1025 		Z_PARAM_ARRAY_EX2(array, 0, 1, 0)
1026 		Z_PARAM_FUNC(BG(user_compare_fci), BG(user_compare_fci_cache))
1027 	ZEND_PARSE_PARAMETERS_END_EX( PHP_ARRAY_CMP_FUNC_RESTORE(); return );
1028 
1029 	arr = Z_ARR_P(array);
1030 	if (zend_hash_num_elements(arr) == 0)  {
1031 		PHP_ARRAY_CMP_FUNC_RESTORE();
1032 		RETURN_TRUE;
1033 	}
1034 
1035 	/* Copy array, so the in-place modifications will not be visible to the callback function */
1036 	arr = zend_array_dup(arr);
1037 
1038 	retval = zend_hash_sort(arr, compare_func, renumber) != FAILURE;
1039 
1040 	zval_ptr_dtor(array);
1041 	ZVAL_ARR(array, arr);
1042 
1043 	PHP_ARRAY_CMP_FUNC_RESTORE();
1044 	RETURN_BOOL(retval);
1045 }
1046 /* }}} */
1047 
1048 /* {{{ proto bool usort(array array_arg, string cmp_function)
1049    Sort an array by values using a user-defined comparison function */
PHP_FUNCTIONnull1050 PHP_FUNCTION(usort)
1051 {
1052 	php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 1);
1053 }
1054 /* }}} */
1055 
1056 /* {{{ proto bool uasort(array array_arg, string cmp_function)
1057    Sort an array with a user-defined comparison function and maintain index association */
PHP_FUNCTIONnull1058 PHP_FUNCTION(uasort)
1059 {
1060 	php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 0);
1061 }
1062 /* }}} */
1063 
php_array_user_key_compare(const void *a, const void *b)1064 static int php_array_user_key_compare(const void *a, const void *b) /* {{{ */
1065 {
1066 	Bucket *f;
1067 	Bucket *s;
1068 	zval args[2];
1069 	zval retval;
1070 	zend_long result;
1071 
1072 	f = (Bucket *) a;
1073 	s = (Bucket *) b;
1074 
1075 	if (f->key == NULL) {
1076 		ZVAL_LONG(&args[0], f->h);
1077 	} else {
1078 		ZVAL_STR_COPY(&args[0], f->key);
1079 	}
1080 	if (s->key == NULL) {
1081 		ZVAL_LONG(&args[1], s->h);
1082 	} else {
1083 		ZVAL_STR_COPY(&args[1], s->key);
1084 	}
1085 
1086 	BG(user_compare_fci).param_count = 2;
1087 	BG(user_compare_fci).params = args;
1088 	BG(user_compare_fci).retval = &retval;
1089 	BG(user_compare_fci).no_separation = 0;
1090 	if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1091 		result = zval_get_long(&retval);
1092 		zval_ptr_dtor(&retval);
1093 	} else {
1094 		result = 0;
1095 	}
1096 
1097 	zval_ptr_dtor(&args[0]);
1098 	zval_ptr_dtor(&args[1]);
1099 
1100 	return ZEND_NORMALIZE_BOOL(result);
1101 }
1102 /* }}} */
1103 
1104 /* {{{ proto bool uksort(array array_arg, string cmp_function)
1105    Sort an array by keys using a user-defined comparison function */
PHP_FUNCTIONnull1106 PHP_FUNCTION(uksort)
1107 {
1108 	php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, 0);
1109 }
1110 /* }}} */
1111 
1112 /* {{{ proto mixed end(array array_arg)
1113    Advances array argument's internal pointer to the last element and return it */
PHP_FUNCTIONnull1114 PHP_FUNCTION(end)
1115 {
1116 	HashTable *array;
1117 	zval *entry;
1118 
1119 	ZEND_PARSE_PARAMETERS_START(1, 1)
1120 		Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
1121 	ZEND_PARSE_PARAMETERS_END();
1122 
1123 	zend_hash_internal_pointer_end(array);
1124 
1125 	if (USED_RET()) {
1126 		if ((entry = zend_hash_get_current_data(array)) == NULL) {
1127 			RETURN_FALSE;
1128 		}
1129 
1130 		if (Z_TYPE_P(entry) == IS_INDIRECT) {
1131 			entry = Z_INDIRECT_P(entry);
1132 		}
1133 
1134 		ZVAL_COPY_DEREF(return_value, entry);
1135 	}
1136 }
1137 /* }}} */
1138 
1139 /* {{{ proto mixed prev(array array_arg)
1140    Move array argument's internal pointer to the previous element and return it */
PHP_FUNCTIONnull1141 PHP_FUNCTION(prev)
1142 {
1143 	HashTable *array;
1144 	zval *entry;
1145 
1146 	ZEND_PARSE_PARAMETERS_START(1, 1)
1147 		Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
1148 	ZEND_PARSE_PARAMETERS_END();
1149 
1150 	zend_hash_move_backwards(array);
1151 
1152 	if (USED_RET()) {
1153 		if ((entry = zend_hash_get_current_data(array)) == NULL) {
1154 			RETURN_FALSE;
1155 		}
1156 
1157 		if (Z_TYPE_P(entry) == IS_INDIRECT) {
1158 			entry = Z_INDIRECT_P(entry);
1159 		}
1160 
1161 		ZVAL_COPY_DEREF(return_value, entry);
1162 	}
1163 }
1164 /* }}} */
1165 
1166 /* {{{ proto mixed next(array array_arg)
1167    Move array argument's internal pointer to the next element and return it */
PHP_FUNCTIONnull1168 PHP_FUNCTION(next)
1169 {
1170 	HashTable *array;
1171 	zval *entry;
1172 
1173 	ZEND_PARSE_PARAMETERS_START(1, 1)
1174 		Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
1175 	ZEND_PARSE_PARAMETERS_END();
1176 
1177 	zend_hash_move_forward(array);
1178 
1179 	if (USED_RET()) {
1180 		if ((entry = zend_hash_get_current_data(array)) == NULL) {
1181 			RETURN_FALSE;
1182 		}
1183 
1184 		if (Z_TYPE_P(entry) == IS_INDIRECT) {
1185 			entry = Z_INDIRECT_P(entry);
1186 		}
1187 
1188 		ZVAL_COPY_DEREF(return_value, entry);
1189 	}
1190 }
1191 /* }}} */
1192 
1193 /* {{{ proto mixed reset(array array_arg)
1194    Set array argument's internal pointer to the first element and return it */
PHP_FUNCTIONnull1195 PHP_FUNCTION(reset)
1196 {
1197 	HashTable *array;
1198 	zval *entry;
1199 
1200 	ZEND_PARSE_PARAMETERS_START(1, 1)
1201 		Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
1202 	ZEND_PARSE_PARAMETERS_END();
1203 
1204 	zend_hash_internal_pointer_reset(array);
1205 
1206 	if (USED_RET()) {
1207 		if ((entry = zend_hash_get_current_data(array)) == NULL) {
1208 			RETURN_FALSE;
1209 		}
1210 
1211 		if (Z_TYPE_P(entry) == IS_INDIRECT) {
1212 			entry = Z_INDIRECT_P(entry);
1213 		}
1214 
1215 		ZVAL_COPY_DEREF(return_value, entry);
1216 	}
1217 }
1218 /* }}} */
1219 
1220 /* {{{ proto mixed current(array array_arg)
1221    Return the element currently pointed to by the internal array pointer */
PHP_FUNCTIONnull1222 PHP_FUNCTION(current)
1223 {
1224 	HashTable *array;
1225 	zval *entry;
1226 
1227 	ZEND_PARSE_PARAMETERS_START(1, 1)
1228 		Z_PARAM_ARRAY_OR_OBJECT_HT(array)
1229 	ZEND_PARSE_PARAMETERS_END();
1230 
1231 	if ((entry = zend_hash_get_current_data(array)) == NULL) {
1232 		RETURN_FALSE;
1233 	}
1234 
1235 	if (Z_TYPE_P(entry) == IS_INDIRECT) {
1236 		entry = Z_INDIRECT_P(entry);
1237 	}
1238 
1239 	ZVAL_COPY_DEREF(return_value, entry);
1240 }
1241 /* }}} */
1242 
1243 /* {{{ proto mixed key(array array_arg)
1244    Return the key of the element currently pointed to by the internal array pointer */
PHP_FUNCTIONnull1245 PHP_FUNCTION(key)
1246 {
1247 	HashTable *array;
1248 
1249 	ZEND_PARSE_PARAMETERS_START(1, 1)
1250 		Z_PARAM_ARRAY_OR_OBJECT_HT(array)
1251 	ZEND_PARSE_PARAMETERS_END();
1252 
1253 	zend_hash_get_current_key_zval(array, return_value);
1254 }
1255 /* }}} */
1256 
1257 /* {{{ proto mixed min(mixed arg1 [, mixed arg2 [, mixed ...]])
1258    Return the lowest value in an array or a series of arguments */
PHP_FUNCTIONnull1259 PHP_FUNCTION(min)
1260 {
1261 	int argc;
1262 	zval *args = NULL;
1263 
1264 	ZEND_PARSE_PARAMETERS_START(1, -1)
1265 		Z_PARAM_VARIADIC('+', args, argc)
1266 	ZEND_PARSE_PARAMETERS_END();
1267 
1268 	/* mixed min ( array $values ) */
1269 	if (argc == 1) {
1270 		zval *result;
1271 
1272 		if (Z_TYPE(args[0]) != IS_ARRAY) {
1273 			php_error_docref(NULL, E_WARNING, "When only one parameter is given, it must be an array");
1274 			RETVAL_NULL();
1275 		} else {
1276 			if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 0)) != NULL) {
1277 				ZVAL_COPY_DEREF(return_value, result);
1278 			} else {
1279 				php_error_docref(NULL, E_WARNING, "Array must contain at least one element");
1280 				RETVAL_FALSE;
1281 			}
1282 		}
1283 	} else {
1284 		/* mixed min ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
1285 		zval *min, result;
1286 		int i;
1287 
1288 		min = &args[0];
1289 
1290 		for (i = 1; i < argc; i++) {
1291 			is_smaller_function(&result, &args[i], min);
1292 			if (Z_TYPE(result) == IS_TRUE) {
1293 				min = &args[i];
1294 			}
1295 		}
1296 
1297 		ZVAL_COPY(return_value, min);
1298 	}
1299 }
1300 /* }}} */
1301 
1302 /* {{{ proto mixed max(mixed arg1 [, mixed arg2 [, mixed ...]])
1303    Return the highest value in an array or a series of arguments */
PHP_FUNCTIONnull1304 PHP_FUNCTION(max)
1305 {
1306 	zval *args = NULL;
1307 	int argc;
1308 
1309 	ZEND_PARSE_PARAMETERS_START(1, -1)
1310 		Z_PARAM_VARIADIC('+', args, argc)
1311 	ZEND_PARSE_PARAMETERS_END();
1312 
1313 	/* mixed max ( array $values ) */
1314 	if (argc == 1) {
1315 		zval *result;
1316 
1317 		if (Z_TYPE(args[0]) != IS_ARRAY) {
1318 			php_error_docref(NULL, E_WARNING, "When only one parameter is given, it must be an array");
1319 			RETVAL_NULL();
1320 		} else {
1321 			if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 1)) != NULL) {
1322 				ZVAL_COPY_DEREF(return_value, result);
1323 			} else {
1324 				php_error_docref(NULL, E_WARNING, "Array must contain at least one element");
1325 				RETVAL_FALSE;
1326 			}
1327 		}
1328 	} else {
1329 		/* mixed max ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
1330 		zval *max, result;
1331 		int i;
1332 
1333 		max = &args[0];
1334 
1335 		for (i = 1; i < argc; i++) {
1336 			is_smaller_or_equal_function(&result, &args[i], max);
1337 			if (Z_TYPE(result) == IS_FALSE) {
1338 				max = &args[i];
1339 			}
1340 		}
1341 
1342 		ZVAL_COPY(return_value, max);
1343 	}
1344 }
1345 /* }}} */
1346 
php_array_walk(zval *array, zval *userdata, int recursive)1347 static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
1348 {
1349 	zval args[3],		/* Arguments to userland function */
1350 		 retval,		/* Return value - unused */
1351 		 *zv;
1352 	HashTable *target_hash = HASH_OF(array);
1353 	HashPosition pos;
1354 	uint32_t ht_iter;
1355 	int result = SUCCESS;
1356 
1357 	/* Set up known arguments */
1358 	ZVAL_UNDEF(&args[1]);
1359 	if (userdata) {
1360 		ZVAL_COPY(&args[2], userdata);
1361 	}
1362 
1363 	BG(array_walk_fci).retval = &retval;
1364 	BG(array_walk_fci).param_count = userdata ? 3 : 2;
1365 	BG(array_walk_fci).params = args;
1366 	BG(array_walk_fci).no_separation = 0;
1367 
1368 	zend_hash_internal_pointer_reset_ex(target_hash, &pos);
1369 	ht_iter = zend_hash_iterator_add(target_hash, pos);
1370 
1371 	/* Iterate through hash */
1372 	do {
1373 		/* Retrieve value */
1374 		zv = zend_hash_get_current_data_ex(target_hash, &pos);
1375 		if (zv == NULL) {
1376 			break;
1377 		}
1378 
1379 		/* Skip undefined indirect elements */
1380 		if (Z_TYPE_P(zv) == IS_INDIRECT) {
1381 			zv = Z_INDIRECT_P(zv);
1382 			if (Z_TYPE_P(zv) == IS_UNDEF) {
1383 				zend_hash_move_forward_ex(target_hash, &pos);
1384 				continue;
1385 			}
1386 
1387 			/* Add type source for property references. */
1388 			if (Z_TYPE_P(zv) != IS_REFERENCE && Z_TYPE_P(array) == IS_OBJECT) {
1389 				zend_property_info *prop_info =
1390 					zend_get_typed_property_info_for_slot(Z_OBJ_P(array), zv);
1391 				if (prop_info) {
1392 					ZVAL_NEW_REF(zv, zv);
1393 					ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(zv), prop_info);
1394 				}
1395 			}
1396 		}
1397 
1398 		/* Ensure the value is a reference. Otherwise the location of the value may be freed. */
1399 		ZVAL_MAKE_REF(zv);
1400 
1401 		/* Retrieve key */
1402 		zend_hash_get_current_key_zval_ex(target_hash, &args[1], &pos);
1403 
1404 		/* Move to next element already now -- this mirrors the approach used by foreach
1405 		 * and ensures proper behavior with regard to modifications. */
1406 		zend_hash_move_forward_ex(target_hash, &pos);
1407 
1408 		/* Back up hash position, as it may change */
1409 		EG(ht_iterators)[ht_iter].pos = pos;
1410 
1411 		if (recursive && Z_TYPE_P(Z_REFVAL_P(zv)) == IS_ARRAY) {
1412 			HashTable *thash;
1413 			zend_fcall_info orig_array_walk_fci;
1414 			zend_fcall_info_cache orig_array_walk_fci_cache;
1415 			zval ref;
1416 			ZVAL_COPY_VALUE(&ref, zv);
1417 
1418 			ZVAL_DEREF(zv);
1419 			SEPARATE_ARRAY(zv);
1420 			thash = Z_ARRVAL_P(zv);
1421 			if (GC_IS_RECURSIVE(thash)) {
1422 				php_error_docref(NULL, E_WARNING, "recursion detected");
1423 				result = FAILURE;
1424 				break;
1425 			}
1426 
1427 			/* backup the fcall info and cache */
1428 			orig_array_walk_fci = BG(array_walk_fci);
1429 			orig_array_walk_fci_cache = BG(array_walk_fci_cache);
1430 
1431 			Z_ADDREF(ref);
1432 			GC_PROTECT_RECURSION(thash);
1433 			result = php_array_walk(zv, userdata, recursive);
1434 			if (Z_TYPE_P(Z_REFVAL(ref)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL(ref))) {
1435 				/* If the hashtable changed in the meantime, we'll "leak" this apply count
1436 				 * increment -- our reference to thash is no longer valid. */
1437 				GC_UNPROTECT_RECURSION(thash);
1438 			}
1439 			zval_ptr_dtor(&ref);
1440 
1441 			/* restore the fcall info and cache */
1442 			BG(array_walk_fci) = orig_array_walk_fci;
1443 			BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1444 		} else {
1445 			ZVAL_COPY(&args[0], zv);
1446 
1447 			/* Call the userland function */
1448 			result = zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache));
1449 			if (result == SUCCESS) {
1450 				zval_ptr_dtor(&retval);
1451 			}
1452 
1453 			zval_ptr_dtor(&args[0]);
1454 		}
1455 
1456 		if (Z_TYPE(args[1]) != IS_UNDEF) {
1457 			zval_ptr_dtor(&args[1]);
1458 			ZVAL_UNDEF(&args[1]);
1459 		}
1460 
1461 		if (result == FAILURE) {
1462 			break;
1463 		}
1464 
1465 		/* Reload array and position -- both may have changed */
1466 		if (Z_TYPE_P(array) == IS_ARRAY) {
1467 			pos = zend_hash_iterator_pos_ex(ht_iter, array);
1468 			target_hash = Z_ARRVAL_P(array);
1469 		} else if (Z_TYPE_P(array) == IS_OBJECT) {
1470 			target_hash = Z_OBJPROP_P(array);
1471 			pos = zend_hash_iterator_pos(ht_iter, target_hash);
1472 		} else {
1473 			php_error_docref(NULL, E_WARNING, "Iterated value is no longer an array or object");
1474 			result = FAILURE;
1475 			break;
1476 		}
1477 	} while (!EG(exception));
1478 
1479 	if (userdata) {
1480 		zval_ptr_dtor(&args[2]);
1481 	}
1482 	zend_hash_iterator_del(ht_iter);
1483 	return result;
1484 }
1485 /* }}} */
1486 
1487 /* {{{ proto bool array_walk(array input, string funcname [, mixed userdata])
1488    Apply a user function to every member of an array */
PHP_FUNCTIONnull1489 PHP_FUNCTION(array_walk)
1490 {
1491 	zval *array;
1492 	zval *userdata = NULL;
1493 	zend_fcall_info orig_array_walk_fci;
1494 	zend_fcall_info_cache orig_array_walk_fci_cache;
1495 
1496 	orig_array_walk_fci = BG(array_walk_fci);
1497 	orig_array_walk_fci_cache = BG(array_walk_fci_cache);
1498 
1499 	ZEND_PARSE_PARAMETERS_START(2, 3)
1500 		Z_PARAM_ARRAY_OR_OBJECT_EX(array, 0, 1)
1501 		Z_PARAM_FUNC(BG(array_walk_fci), BG(array_walk_fci_cache))
1502 		Z_PARAM_OPTIONAL
1503 		Z_PARAM_ZVAL(userdata)
1504 	ZEND_PARSE_PARAMETERS_END_EX(
1505 		BG(array_walk_fci) = orig_array_walk_fci;
1506 		BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1507 		return
1508 	);
1509 
1510 	php_array_walk(array, userdata, 0);
1511 	zend_release_fcall_info_cache(&BG(array_walk_fci_cache));
1512 	BG(array_walk_fci) = orig_array_walk_fci;
1513 	BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1514 	RETURN_TRUE;
1515 }
1516 /* }}} */
1517 
1518 /* {{{ proto bool array_walk_recursive(array input, string funcname [, mixed userdata])
1519    Apply a user function recursively to every member of an array */
PHP_FUNCTIONnull1520 PHP_FUNCTION(array_walk_recursive)
1521 {
1522 	zval *array;
1523 	zval *userdata = NULL;
1524 	zend_fcall_info orig_array_walk_fci;
1525 	zend_fcall_info_cache orig_array_walk_fci_cache;
1526 
1527 	orig_array_walk_fci = BG(array_walk_fci);
1528 	orig_array_walk_fci_cache = BG(array_walk_fci_cache);
1529 
1530 	ZEND_PARSE_PARAMETERS_START(2, 3)
1531 		Z_PARAM_ARRAY_OR_OBJECT_EX(array, 0, 1)
1532 		Z_PARAM_FUNC(BG(array_walk_fci), BG(array_walk_fci_cache))
1533 		Z_PARAM_OPTIONAL
1534 		Z_PARAM_ZVAL(userdata)
1535 	ZEND_PARSE_PARAMETERS_END_EX(
1536 		BG(array_walk_fci) = orig_array_walk_fci;
1537 		BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1538 		return
1539 	);
1540 
1541 	php_array_walk(array, userdata, 1);
1542 	zend_release_fcall_info_cache(&BG(array_walk_fci_cache));
1543 	BG(array_walk_fci) = orig_array_walk_fci;
1544 	BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1545 	RETURN_TRUE;
1546 }
1547 /* }}} */
1548 
1549 /* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
1550  * 0 = return boolean
1551  * 1 = return key
1552  */
php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)1553 static inline void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
1554 {
1555 	zval *value,				/* value to check for */
1556 		 *array,				/* array to check in */
1557 		 *entry;				/* pointer to array entry */
1558 	zend_ulong num_idx;
1559 	zend_string *str_idx;
1560 	zend_bool strict = 0;		/* strict comparison or not */
1561 
1562 	ZEND_PARSE_PARAMETERS_START(2, 3)
1563 		Z_PARAM_ZVAL(value)
1564 		Z_PARAM_ARRAY(array)
1565 		Z_PARAM_OPTIONAL
1566 		Z_PARAM_BOOL(strict)
1567 	ZEND_PARSE_PARAMETERS_END();
1568 
1569 	if (strict) {
1570 		if (Z_TYPE_P(value) == IS_LONG) {
1571 			ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1572 				ZVAL_DEREF(entry);
1573 				if (Z_TYPE_P(entry) == IS_LONG && Z_LVAL_P(entry) == Z_LVAL_P(value)) {
1574 					if (behavior == 0) {
1575 						RETURN_TRUE;
1576 					} else {
1577 						if (str_idx) {
1578 							RETVAL_STR_COPY(str_idx);
1579 						} else {
1580 							RETVAL_LONG(num_idx);
1581 						}
1582 						return;
1583 					}
1584 				}
1585 			} ZEND_HASH_FOREACH_END();
1586 		} else {
1587 			ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1588 				ZVAL_DEREF(entry);
1589 				if (fast_is_identical_function(value, entry)) {
1590 					if (behavior == 0) {
1591 						RETURN_TRUE;
1592 					} else {
1593 						if (str_idx) {
1594 							RETVAL_STR_COPY(str_idx);
1595 						} else {
1596 							RETVAL_LONG(num_idx);
1597 						}
1598 						return;
1599 					}
1600 				}
1601 			} ZEND_HASH_FOREACH_END();
1602 		}
1603 	} else {
1604 		if (Z_TYPE_P(value) == IS_LONG) {
1605 			ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1606 				if (fast_equal_check_long(value, entry)) {
1607 					if (behavior == 0) {
1608 						RETURN_TRUE;
1609 					} else {
1610 						if (str_idx) {
1611 							RETVAL_STR_COPY(str_idx);
1612 						} else {
1613 							RETVAL_LONG(num_idx);
1614 						}
1615 						return;
1616 					}
1617 				}
1618 			} ZEND_HASH_FOREACH_END();
1619 		} else if (Z_TYPE_P(value) == IS_STRING) {
1620 			ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1621 				if (fast_equal_check_string(value, entry)) {
1622 					if (behavior == 0) {
1623 						RETURN_TRUE;
1624 					} else {
1625 						if (str_idx) {
1626 							RETVAL_STR_COPY(str_idx);
1627 						} else {
1628 							RETVAL_LONG(num_idx);
1629 						}
1630 						return;
1631 					}
1632 				}
1633 			} ZEND_HASH_FOREACH_END();
1634 		} else {
1635 			ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1636 				if (fast_equal_check_function(value, entry)) {
1637 					if (behavior == 0) {
1638 						RETURN_TRUE;
1639 					} else {
1640 						if (str_idx) {
1641 							RETVAL_STR_COPY(str_idx);
1642 						} else {
1643 							RETVAL_LONG(num_idx);
1644 						}
1645 						return;
1646 					}
1647 				}
1648 			} ZEND_HASH_FOREACH_END();
1649  		}
1650 	}
1651 
1652 	RETURN_FALSE;
1653 }
1654 /* }}} */
1655 
1656 /* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
1657    Checks if the given value exists in the array */
PHP_FUNCTIONnull1658 PHP_FUNCTION(in_array)
1659 {
1660 	php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1661 }
1662 /* }}} */
1663 
1664 /* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict])
1665    Searches the array for a given value and returns the corresponding key if successful */
PHP_FUNCTIONnull1666 PHP_FUNCTION(array_search)
1667 {
1668 	php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1669 }
1670 /* }}} */
1671 
php_valid_var_name(const char *var_name, size_t var_name_len)1672 static zend_always_inline int php_valid_var_name(const char *var_name, size_t var_name_len) /* {{{ */
1673 {
1674 #if 1
1675 	/* first 256 bits for first character, and second 256 bits for the next */
1676 	static const uint32_t charset[8] = {
1677 	     /*  31      0   63     32   95     64   127    96 */
1678 			0x00000000, 0x00000000, 0x87fffffe, 0x07fffffe,
1679 			0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
1680 	static const uint32_t charset2[8] = {
1681 	     /*  31      0   63     32   95     64   127    96 */
1682 			0x00000000, 0x03ff0000, 0x87fffffe, 0x07fffffe,
1683 			0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
1684 #endif
1685 	size_t i;
1686 	uint32_t ch;
1687 
1688 	if (UNEXPECTED(!var_name_len)) {
1689 		return 0;
1690 	}
1691 
1692 	/* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
1693 	ch = (uint32_t)((unsigned char *)var_name)[0];
1694 #if 1
1695 	if (UNEXPECTED(!ZEND_BIT_TEST(charset, ch))) {
1696 #else
1697 	if (var_name[0] != '_' &&
1698 		(ch < 65  /* A    */ || /* Z    */ ch > 90)  &&
1699 		(ch < 97  /* a    */ || /* z    */ ch > 122) &&
1700 		(ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
1701 	) {
1702 #endif
1703 		return 0;
1704 	}
1705 
1706 	/* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
1707 	if (var_name_len > 1) {
1708 		i = 1;
1709 		do {
1710 			ch = (uint32_t)((unsigned char *)var_name)[i];
1711 #if 1
1712 			if (UNEXPECTED(!ZEND_BIT_TEST(charset2, ch))) {
1713 #else
1714 			if (var_name[i] != '_' &&
1715 				(ch < 48  /* 0    */ || /* 9    */ ch > 57)  &&
1716 				(ch < 65  /* A    */ || /* Z    */ ch > 90)  &&
1717 				(ch < 97  /* a    */ || /* z    */ ch > 122) &&
1718 				(ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
1719 			) {
1720 #endif
1721 				return 0;
1722 			}
1723 		} while (++i < var_name_len);
1724 	}
1725 	return 1;
1726 }
1727 /* }}} */
1728 
1729 PHPAPI int php_prefix_varname(zval *result, const zval *prefix, const char *var_name, size_t var_name_len, zend_bool add_underscore) /* {{{ */
1730 {
1731 	ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0) + var_name_len, 0));
1732 	memcpy(Z_STRVAL_P(result), Z_STRVAL_P(prefix), Z_STRLEN_P(prefix));
1733 
1734 	if (add_underscore) {
1735 		Z_STRVAL_P(result)[Z_STRLEN_P(prefix)] = '_';
1736 	}
1737 
1738 	memcpy(Z_STRVAL_P(result) + Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1);
1739 
1740 	return SUCCESS;
1741 }
1742 /* }}} */
1743 
1744 static zend_long php_extract_ref_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */
1745 {
1746 	zend_long count = 0;
1747 	zend_string *var_name;
1748 	zval *entry, *orig_var;
1749 
1750 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
1751 		if (!var_name) {
1752 			continue;
1753 		}
1754 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
1755 		if (orig_var) {
1756 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1757 				orig_var = Z_INDIRECT_P(orig_var);
1758 				if (Z_TYPE_P(orig_var) == IS_UNDEF) {
1759 					continue;
1760 				}
1761 			}
1762 			if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
1763 				continue;
1764 			}
1765 			if (zend_string_equals_literal(var_name, "GLOBALS")) {
1766 				continue;
1767 			}
1768 			if (zend_string_equals_literal(var_name, "this")) {
1769 				zend_throw_error(NULL, "Cannot re-assign $this");
1770 				return -1;
1771 			}
1772 			if (Z_ISREF_P(entry)) {
1773 				Z_ADDREF_P(entry);
1774 			} else {
1775 				ZVAL_MAKE_REF_EX(entry, 2);
1776 			}
1777 			zval_ptr_dtor(orig_var);
1778 			ZVAL_REF(orig_var, Z_REF_P(entry));
1779 			count++;
1780 		}
1781 	} ZEND_HASH_FOREACH_END();
1782 
1783 	return count;
1784 }
1785 /* }}} */
1786 
1787 static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */
1788 {
1789 	zend_long count = 0;
1790 	zend_string *var_name;
1791 	zval *entry, *orig_var;
1792 
1793 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
1794 		if (!var_name) {
1795 			continue;
1796 		}
1797 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
1798 		if (orig_var) {
1799 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1800 				orig_var = Z_INDIRECT_P(orig_var);
1801 				if (Z_TYPE_P(orig_var) == IS_UNDEF) {
1802 					continue;
1803 				}
1804 			}
1805 			if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
1806 				continue;
1807 			}
1808 			if (zend_string_equals_literal(var_name, "GLOBALS")) {
1809 				continue;
1810 			}
1811 			if (zend_string_equals_literal(var_name, "this")) {
1812 				zend_throw_error(NULL, "Cannot re-assign $this");
1813 				return -1;
1814 			}
1815 			ZVAL_DEREF(entry);
1816 			ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
1817 			if (UNEXPECTED(EG(exception))) {
1818 				return -1;
1819 			}
1820 			count++;
1821 		}
1822 	} ZEND_HASH_FOREACH_END();
1823 
1824 	return count;
1825 }
1826 /* }}} */
1827 
1828 static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */
1829 {
1830 	zend_long count = 0;
1831 	zend_string *var_name;
1832 	zval *entry, *orig_var;
1833 
1834 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
1835 		if (!var_name) {
1836 			continue;
1837 		}
1838 		if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
1839 			continue;
1840 		}
1841 		if (zend_string_equals_literal(var_name, "this")) {
1842 			zend_throw_error(NULL, "Cannot re-assign $this");
1843 			return -1;
1844 		}
1845 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
1846 		if (orig_var) {
1847 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1848 				orig_var = Z_INDIRECT_P(orig_var);
1849 			}
1850 			if (zend_string_equals_literal(var_name, "GLOBALS")) {
1851 				continue;
1852 			}
1853 			if (Z_ISREF_P(entry)) {
1854 				Z_ADDREF_P(entry);
1855 			} else {
1856 				ZVAL_MAKE_REF_EX(entry, 2);
1857 			}
1858 			zval_ptr_dtor(orig_var);
1859 			ZVAL_REF(orig_var, Z_REF_P(entry));
1860 		} else {
1861 			if (Z_ISREF_P(entry)) {
1862 				Z_ADDREF_P(entry);
1863 			} else {
1864 				ZVAL_MAKE_REF_EX(entry, 2);
1865 			}
1866 			zend_hash_add_new(symbol_table, var_name, entry);
1867 		}
1868 		count++;
1869 	} ZEND_HASH_FOREACH_END();
1870 
1871 	return count;
1872 }
1873 /* }}} */
1874 
1875 static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */
1876 {
1877 	zend_long count = 0;
1878 	zend_string *var_name;
1879 	zval *entry, *orig_var;
1880 
1881 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
1882 		if (!var_name) {
1883 			continue;
1884 		}
1885 		if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
1886 			continue;
1887 		}
1888 		if (zend_string_equals_literal(var_name, "this")) {
1889 			zend_throw_error(NULL, "Cannot re-assign $this");
1890 			return -1;
1891 		}
1892 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
1893 		if (orig_var) {
1894 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1895 				orig_var = Z_INDIRECT_P(orig_var);
1896 			}
1897 			if (zend_string_equals_literal(var_name, "GLOBALS")) {
1898 				continue;
1899 			}
1900 			ZVAL_DEREF(entry);
1901 			ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
1902 			if (UNEXPECTED(EG(exception))) {
1903 				return -1;
1904 			}
1905 		} else {
1906 			ZVAL_DEREF(entry);
1907 			Z_TRY_ADDREF_P(entry);
1908 			zend_hash_add_new(symbol_table, var_name, entry);
1909 		}
1910 		count++;
1911 	} ZEND_HASH_FOREACH_END();
1912 
1913 	return count;
1914 }
1915 /* }}} */
1916 
1917 static zend_long php_extract_ref_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zval *prefix) /* {{{ */
1918 {
1919 	zend_long count = 0;
1920 	zend_string *var_name;
1921 	zval *entry, *orig_var, final_name;
1922 
1923 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
1924 		if (!var_name) {
1925 			continue;
1926 		}
1927 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
1928 		if (orig_var) {
1929 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1930 				orig_var = Z_INDIRECT_P(orig_var);
1931 				if (Z_TYPE_P(orig_var) == IS_UNDEF) {
1932 					if (Z_ISREF_P(entry)) {
1933 						Z_ADDREF_P(entry);
1934 					} else {
1935 						ZVAL_MAKE_REF_EX(entry, 2);
1936 					}
1937 					ZVAL_REF(orig_var, Z_REF_P(entry));
1938 					count++;
1939 					continue;
1940 				}
1941 			}
1942 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
1943 			if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
1944 				if (zend_string_equals_literal(Z_STR(final_name), "this")) {
1945 					zend_throw_error(NULL, "Cannot re-assign $this");
1946 					return -1;
1947 				} else {
1948 					if (Z_ISREF_P(entry)) {
1949 						Z_ADDREF_P(entry);
1950 					} else {
1951 						ZVAL_MAKE_REF_EX(entry, 2);
1952 					}
1953 					if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
1954 						if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1955 							orig_var = Z_INDIRECT_P(orig_var);
1956 						}
1957 						zval_ptr_dtor(orig_var);
1958 						ZVAL_REF(orig_var, Z_REF_P(entry));
1959 					} else {
1960 						zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
1961 					}
1962 					count++;
1963 				}
1964 			}
1965 			zval_ptr_dtor_str(&final_name);
1966 		}
1967 	} ZEND_HASH_FOREACH_END();
1968 
1969 	return count;
1970 }
1971 /* }}} */
1972 
1973 static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zval *prefix) /* {{{ */
1974 {
1975 	zend_long count = 0;
1976 	zend_string *var_name;
1977 	zval *entry, *orig_var, final_name;
1978 
1979 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
1980 		if (!var_name) {
1981 			continue;
1982 		}
1983 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
1984 		if (orig_var) {
1985 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1986 				orig_var = Z_INDIRECT_P(orig_var);
1987 				if (Z_TYPE_P(orig_var) == IS_UNDEF) {
1988 					ZVAL_COPY_DEREF(orig_var, entry);
1989 					count++;
1990 					continue;
1991 				}
1992 			}
1993 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
1994 			if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
1995 				if (zend_string_equals_literal(Z_STR(final_name), "this")) {
1996 					zend_throw_error(NULL, "Cannot re-assign $this");
1997 					return -1;
1998 				} else {
1999 					ZVAL_DEREF(entry);
2000 					if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2001 						if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2002 							orig_var = Z_INDIRECT_P(orig_var);
2003 						}
2004 						ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
2005 						if (UNEXPECTED(EG(exception))) {
2006 							zend_string_release_ex(Z_STR(final_name), 0);
2007 							return -1;
2008 						}
2009 					} else {
2010 						Z_TRY_ADDREF_P(entry);
2011 						zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2012 					}
2013 					count++;
2014 				}
2015 			}
2016 			zval_ptr_dtor_str(&final_name);
2017 		}
2018 	} ZEND_HASH_FOREACH_END();
2019 
2020 	return count;
2021 }
2022 /* }}} */
2023 
2024 static zend_long php_extract_ref_prefix_same(zend_array *arr, zend_array *symbol_table, zval *prefix) /* {{{ */
2025 {
2026 	zend_long count = 0;
2027 	zend_string *var_name;
2028 	zval *entry, *orig_var, final_name;
2029 
2030 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
2031 		if (!var_name) {
2032 			continue;
2033 		}
2034 		if (ZSTR_LEN(var_name) == 0) {
2035 			continue;
2036 		}
2037 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
2038 		if (orig_var) {
2039 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2040 				orig_var = Z_INDIRECT_P(orig_var);
2041 				if (Z_TYPE_P(orig_var) == IS_UNDEF) {
2042 					if (Z_ISREF_P(entry)) {
2043 						Z_ADDREF_P(entry);
2044 					} else {
2045 						ZVAL_MAKE_REF_EX(entry, 2);
2046 					}
2047 					ZVAL_REF(orig_var, Z_REF_P(entry));
2048 					count++;
2049 					continue;
2050 				}
2051 			}
2052 prefix:
2053 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
2054 			if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2055 				if (zend_string_equals_literal(Z_STR(final_name), "this")) {
2056 					zend_throw_error(NULL, "Cannot re-assign $this");
2057 					return -1;
2058 				} else {
2059 					if (Z_ISREF_P(entry)) {
2060 						Z_ADDREF_P(entry);
2061 					} else {
2062 						ZVAL_MAKE_REF_EX(entry, 2);
2063 					}
2064 					if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2065 						if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2066 							orig_var = Z_INDIRECT_P(orig_var);
2067 						}
2068 						zval_ptr_dtor(orig_var);
2069 						ZVAL_REF(orig_var, Z_REF_P(entry));
2070 					} else {
2071 						zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2072 					}
2073 					count++;
2074 				}
2075 			}
2076 			zval_ptr_dtor_str(&final_name);
2077 		} else {
2078 			if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
2079 				continue;
2080 			}
2081 			if (zend_string_equals_literal(var_name, "this")) {
2082 				goto prefix;
2083 			}
2084 			if (Z_ISREF_P(entry)) {
2085 				Z_ADDREF_P(entry);
2086 			} else {
2087 				ZVAL_MAKE_REF_EX(entry, 2);
2088 			}
2089 			zend_hash_add_new(symbol_table, var_name, entry);
2090 			count++;
2091 		}
2092 	} ZEND_HASH_FOREACH_END();
2093 
2094 	return count;
2095 }
2096 /* }}} */
2097 
2098 static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_table, zval *prefix) /* {{{ */
2099 {
2100 	zend_long count = 0;
2101 	zend_string *var_name;
2102 	zval *entry, *orig_var, final_name;
2103 
2104 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
2105 		if (!var_name) {
2106 			continue;
2107 		}
2108 		if (ZSTR_LEN(var_name) == 0) {
2109 			continue;
2110 		}
2111 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
2112 		if (orig_var) {
2113 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2114 				orig_var = Z_INDIRECT_P(orig_var);
2115 				if (Z_TYPE_P(orig_var) == IS_UNDEF) {
2116 					ZVAL_COPY_DEREF(orig_var, entry);
2117 					count++;
2118 					continue;
2119 				}
2120 			}
2121 prefix:
2122 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
2123 			if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2124 				if (zend_string_equals_literal(Z_STR(final_name), "this")) {
2125 					zend_throw_error(NULL, "Cannot re-assign $this");
2126 					return -1;
2127 				} else {
2128 					ZVAL_DEREF(entry);
2129 					if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2130 						if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2131 							orig_var = Z_INDIRECT_P(orig_var);
2132 						}
2133 						ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
2134 						if (UNEXPECTED(EG(exception))) {
2135 							zend_string_release_ex(Z_STR(final_name), 0);
2136 							return -1;
2137 						}
2138 					} else {
2139 						Z_TRY_ADDREF_P(entry);
2140 						zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2141 					}
2142 					count++;
2143 				}
2144 			}
2145 			zval_ptr_dtor_str(&final_name);
2146 		} else {
2147 			if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
2148 				continue;
2149 			}
2150 			if (zend_string_equals_literal(var_name, "this")) {
2151 				goto prefix;
2152 			}
2153 			ZVAL_DEREF(entry);
2154 			Z_TRY_ADDREF_P(entry);
2155 			zend_hash_add_new(symbol_table, var_name, entry);
2156 			count++;
2157 		}
2158 	} ZEND_HASH_FOREACH_END();
2159 
2160 	return count;
2161 }
2162 /* }}} */
2163 
2164 static zend_long php_extract_ref_prefix_all(zend_array *arr, zend_array *symbol_table, zval *prefix) /* {{{ */
2165 {
2166 	zend_long count = 0;
2167 	zend_string *var_name;
2168 	zend_ulong num_key;
2169 	zval *entry, *orig_var, final_name;
2170 
2171 	ZEND_HASH_FOREACH_KEY_VAL_IND(arr, num_key, var_name, entry) {
2172 		if (var_name) {
2173 			if (ZSTR_LEN(var_name) == 0) {
2174 				continue;
2175 			}
2176 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
2177 		} else {
2178 			zend_string *str = zend_long_to_str(num_key);
2179 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
2180 			zend_string_release_ex(str, 0);
2181 		}
2182 		if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2183 			if (zend_string_equals_literal(Z_STR(final_name), "this")) {
2184 				zend_throw_error(NULL, "Cannot re-assign $this");
2185 				return -1;
2186 			} else {
2187 				if (Z_ISREF_P(entry)) {
2188 					Z_ADDREF_P(entry);
2189 				} else {
2190 					ZVAL_MAKE_REF_EX(entry, 2);
2191 				}
2192 				if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2193 					if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2194 						orig_var = Z_INDIRECT_P(orig_var);
2195 					}
2196 					zval_ptr_dtor(orig_var);
2197 					ZVAL_REF(orig_var, Z_REF_P(entry));
2198 				} else {
2199 					zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2200 				}
2201 				count++;
2202 			}
2203 		}
2204 		zval_ptr_dtor_str(&final_name);
2205 	} ZEND_HASH_FOREACH_END();
2206 
2207 	return count;
2208 }
2209 /* }}} */
2210 
2211 static zend_long php_extract_prefix_all(zend_array *arr, zend_array *symbol_table, zval *prefix) /* {{{ */
2212 {
2213 	zend_long count = 0;
2214 	zend_string *var_name;
2215 	zend_ulong num_key;
2216 	zval *entry, *orig_var, final_name;
2217 
2218 	ZEND_HASH_FOREACH_KEY_VAL_IND(arr, num_key, var_name, entry) {
2219 		if (var_name) {
2220 			if (ZSTR_LEN(var_name) == 0) {
2221 				continue;
2222 			}
2223 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
2224 		} else {
2225 			zend_string *str = zend_long_to_str(num_key);
2226 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
2227 			zend_string_release_ex(str, 0);
2228 		}
2229 		if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2230 			if (zend_string_equals_literal(Z_STR(final_name), "this")) {
2231 				zend_throw_error(NULL, "Cannot re-assign $this");
2232 				return -1;
2233 			} else {
2234 				ZVAL_DEREF(entry);
2235 				if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2236 					if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2237 						orig_var = Z_INDIRECT_P(orig_var);
2238 					}
2239 					ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
2240 					if (UNEXPECTED(EG(exception))) {
2241 						zend_string_release_ex(Z_STR(final_name), 0);
2242 						return -1;
2243 					}
2244 				} else {
2245 					Z_TRY_ADDREF_P(entry);
2246 					zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2247 				}
2248 				count++;
2249 			}
2250 		}
2251 		zval_ptr_dtor_str(&final_name);
2252 	} ZEND_HASH_FOREACH_END();
2253 
2254 	return count;
2255 }
2256 /* }}} */
2257 
2258 static zend_long php_extract_ref_prefix_invalid(zend_array *arr, zend_array *symbol_table, zval *prefix) /* {{{ */
2259 {
2260 	zend_long count = 0;
2261 	zend_string *var_name;
2262 	zend_ulong num_key;
2263 	zval *entry, *orig_var, final_name;
2264 
2265 	ZEND_HASH_FOREACH_KEY_VAL_IND(arr, num_key, var_name, entry) {
2266 		if (var_name) {
2267 			if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))
2268 			 || zend_string_equals_literal(var_name, "this")) {
2269 				php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
2270 				if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2271 					zval_ptr_dtor_str(&final_name);
2272 					continue;
2273 				}
2274 			} else {
2275 				ZVAL_STR_COPY(&final_name, var_name);
2276 			}
2277 		} else {
2278 			zend_string *str = zend_long_to_str(num_key);
2279 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
2280 			zend_string_release_ex(str, 0);
2281 			if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2282 				zval_ptr_dtor_str(&final_name);
2283 				continue;
2284 			}
2285 		}
2286 		if (zend_string_equals_literal(Z_STR(final_name), "this")) {
2287 			zend_throw_error(NULL, "Cannot re-assign $this");
2288 			return -1;
2289 		} else {
2290 			if (Z_ISREF_P(entry)) {
2291 				Z_ADDREF_P(entry);
2292 			} else {
2293 				ZVAL_MAKE_REF_EX(entry, 2);
2294 			}
2295 			if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2296 				if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2297 					orig_var = Z_INDIRECT_P(orig_var);
2298 				}
2299 				zval_ptr_dtor(orig_var);
2300 				ZVAL_REF(orig_var, Z_REF_P(entry));
2301 			} else {
2302 				zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2303 			}
2304 			count++;
2305 		}
2306 		zval_ptr_dtor_str(&final_name);
2307 	} ZEND_HASH_FOREACH_END();
2308 
2309 	return count;
2310 }
2311 /* }}} */
2312 
2313 static zend_long php_extract_prefix_invalid(zend_array *arr, zend_array *symbol_table, zval *prefix) /* {{{ */
2314 {
2315 	zend_long count = 0;
2316 	zend_string *var_name;
2317 	zend_ulong num_key;
2318 	zval *entry, *orig_var, final_name;
2319 
2320 	ZEND_HASH_FOREACH_KEY_VAL_IND(arr, num_key, var_name, entry) {
2321 		if (var_name) {
2322 			if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))
2323 			 || zend_string_equals_literal(var_name, "this")) {
2324 				php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
2325 				if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2326 					zval_ptr_dtor_str(&final_name);
2327 					continue;
2328 				}
2329 			} else {
2330 				ZVAL_STR_COPY(&final_name, var_name);
2331 			}
2332 		} else {
2333 			zend_string *str = zend_long_to_str(num_key);
2334 			php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
2335 			zend_string_release_ex(str, 0);
2336 			if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2337 				zval_ptr_dtor_str(&final_name);
2338 				continue;
2339 			}
2340 		}
2341 		if (zend_string_equals_literal(Z_STR(final_name), "this")) {
2342 			zend_throw_error(NULL, "Cannot re-assign $this");
2343 			return -1;
2344 		} else {
2345 			ZVAL_DEREF(entry);
2346 			if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2347 				if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2348 					orig_var = Z_INDIRECT_P(orig_var);
2349 				}
2350 				ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
2351 				if (UNEXPECTED(EG(exception))) {
2352 					zend_string_release_ex(Z_STR(final_name), 0);
2353 					return -1;
2354 				}
2355 			} else {
2356 				Z_TRY_ADDREF_P(entry);
2357 				zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2358 			}
2359 			count++;
2360 		}
2361 		zval_ptr_dtor_str(&final_name);
2362 	} ZEND_HASH_FOREACH_END();
2363 
2364 	return count;
2365 }
2366 /* }}} */
2367 
2368 static zend_long php_extract_ref_skip(zend_array *arr, zend_array *symbol_table) /* {{{ */
2369 {
2370 	zend_long count = 0;
2371 	zend_string *var_name;
2372 	zval *entry, *orig_var;
2373 
2374 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
2375 		if (!var_name) {
2376 			continue;
2377 		}
2378 		if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
2379 			continue;
2380 		}
2381 		if (zend_string_equals_literal(var_name, "this")) {
2382 			continue;
2383 		}
2384 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
2385 		if (orig_var) {
2386 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2387 				orig_var = Z_INDIRECT_P(orig_var);
2388 				if (Z_TYPE_P(orig_var) == IS_UNDEF) {
2389 					if (Z_ISREF_P(entry)) {
2390 						Z_ADDREF_P(entry);
2391 					} else {
2392 						ZVAL_MAKE_REF_EX(entry, 2);
2393 					}
2394 					ZVAL_REF(orig_var, Z_REF_P(entry));
2395 					count++;
2396 				}
2397 			}
2398 		} else {
2399 			if (Z_ISREF_P(entry)) {
2400 				Z_ADDREF_P(entry);
2401 			} else {
2402 				ZVAL_MAKE_REF_EX(entry, 2);
2403 			}
2404 			zend_hash_add_new(symbol_table, var_name, entry);
2405 			count++;
2406 		}
2407 	} ZEND_HASH_FOREACH_END();
2408 
2409 	return count;
2410 }
2411 /* }}} */
2412 
2413 static zend_long php_extract_skip(zend_array *arr, zend_array *symbol_table) /* {{{ */
2414 {
2415 	zend_long count = 0;
2416 	zend_string *var_name;
2417 	zval *entry, *orig_var;
2418 
2419 	ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
2420 		if (!var_name) {
2421 			continue;
2422 		}
2423 		if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
2424 			continue;
2425 		}
2426 		if (zend_string_equals_literal(var_name, "this")) {
2427 			continue;
2428 		}
2429 		orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
2430 		if (orig_var) {
2431 			if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2432 				orig_var = Z_INDIRECT_P(orig_var);
2433 				if (Z_TYPE_P(orig_var) == IS_UNDEF) {
2434 					ZVAL_COPY_DEREF(orig_var, entry);
2435 					count++;
2436 				}
2437 			}
2438 		} else {
2439 			ZVAL_DEREF(entry);
2440 			Z_TRY_ADDREF_P(entry);
2441 			zend_hash_add_new(symbol_table, var_name, entry);
2442 			count++;
2443 		}
2444 	} ZEND_HASH_FOREACH_END();
2445 
2446 	return count;
2447 }
2448 /* }}} */
2449 
2450 /* {{{ proto int extract(array var_array [, int extract_type [, string prefix]])
2451    Imports variables into symbol table from an array */
2452 PHP_FUNCTION(extract)
2453 {
2454 	zval *var_array_param, *prefix = NULL;
2455 	zend_long extract_refs;
2456 	zend_long extract_type = EXTR_OVERWRITE;
2457 	zend_long count;
2458 	zend_array *symbol_table;
2459 
2460 	ZEND_PARSE_PARAMETERS_START(1, 3)
2461 		Z_PARAM_ARRAY_EX2(var_array_param, 0, 1, 0)
2462 		Z_PARAM_OPTIONAL
2463 		Z_PARAM_LONG(extract_type)
2464 		Z_PARAM_ZVAL(prefix)
2465 	ZEND_PARSE_PARAMETERS_END();
2466 
2467 	extract_refs = (extract_type & EXTR_REFS);
2468 	if (extract_refs) {
2469 		SEPARATE_ARRAY(var_array_param);
2470 	}
2471 	extract_type &= 0xff;
2472 
2473 	if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) {
2474 		php_error_docref(NULL, E_WARNING, "Invalid extract type");
2475 		return;
2476 	}
2477 
2478 	if (extract_type > EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS && ZEND_NUM_ARGS() < 3) {
2479 		php_error_docref(NULL, E_WARNING, "specified extract type requires the prefix parameter");
2480 		return;
2481 	}
2482 
2483 	if (prefix) {
2484 		if (!try_convert_to_string(prefix)) {
2485 			return;
2486 		}
2487 
2488 		if (Z_STRLEN_P(prefix) && !php_valid_var_name(Z_STRVAL_P(prefix), Z_STRLEN_P(prefix))) {
2489 			php_error_docref(NULL, E_WARNING, "prefix is not a valid identifier");
2490 			return;
2491 		}
2492 	}
2493 
2494 	if (zend_forbid_dynamic_call("extract()") == FAILURE) {
2495 		return;
2496 	}
2497 
2498 	symbol_table = zend_rebuild_symbol_table();
2499 
2500 	if (extract_refs) {
2501 		switch (extract_type) {
2502 			case EXTR_IF_EXISTS:
2503 				count = php_extract_ref_if_exists(Z_ARRVAL_P(var_array_param), symbol_table);
2504 				break;
2505 			case EXTR_OVERWRITE:
2506 				count = php_extract_ref_overwrite(Z_ARRVAL_P(var_array_param), symbol_table);
2507 				break;
2508 			case EXTR_PREFIX_IF_EXISTS:
2509 				count = php_extract_ref_prefix_if_exists(Z_ARRVAL_P(var_array_param), symbol_table, prefix);
2510 				break;
2511 			case EXTR_PREFIX_SAME:
2512 				count = php_extract_ref_prefix_same(Z_ARRVAL_P(var_array_param), symbol_table, prefix);
2513 				break;
2514 			case EXTR_PREFIX_ALL:
2515 				count = php_extract_ref_prefix_all(Z_ARRVAL_P(var_array_param), symbol_table, prefix);
2516 				break;
2517 			case EXTR_PREFIX_INVALID:
2518 				count = php_extract_ref_prefix_invalid(Z_ARRVAL_P(var_array_param), symbol_table, prefix);
2519 				break;
2520 			default:
2521 				count = php_extract_ref_skip(Z_ARRVAL_P(var_array_param), symbol_table);
2522 				break;
2523 		}
2524 	} else {
2525 		/* The array might be stored in a local variable that will be overwritten */
2526 		zval array_copy;
2527 		ZVAL_COPY(&array_copy, var_array_param);
2528 		switch (extract_type) {
2529 			case EXTR_IF_EXISTS:
2530 				count = php_extract_if_exists(Z_ARRVAL(array_copy), symbol_table);
2531 				break;
2532 			case EXTR_OVERWRITE:
2533 				count = php_extract_overwrite(Z_ARRVAL(array_copy), symbol_table);
2534 				break;
2535 			case EXTR_PREFIX_IF_EXISTS:
2536 				count = php_extract_prefix_if_exists(Z_ARRVAL(array_copy), symbol_table, prefix);
2537 				break;
2538 			case EXTR_PREFIX_SAME:
2539 				count = php_extract_prefix_same(Z_ARRVAL(array_copy), symbol_table, prefix);
2540 				break;
2541 			case EXTR_PREFIX_ALL:
2542 				count = php_extract_prefix_all(Z_ARRVAL(array_copy), symbol_table, prefix);
2543 				break;
2544 			case EXTR_PREFIX_INVALID:
2545 				count = php_extract_prefix_invalid(Z_ARRVAL(array_copy), symbol_table, prefix);
2546 				break;
2547 			default:
2548 				count = php_extract_skip(Z_ARRVAL(array_copy), symbol_table);
2549 				break;
2550 		}
2551 		zval_ptr_dtor(&array_copy);
2552 	}
2553 
2554 	RETURN_LONG(count);
2555 }
2556 /* }}} */
2557 
2558 static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_value, zval *entry) /* {{{ */
2559 {
2560 	zval *value_ptr, data;
2561 
2562 	ZVAL_DEREF(entry);
2563 	if (Z_TYPE_P(entry) == IS_STRING) {
2564 		if ((value_ptr = zend_hash_find_ind(eg_active_symbol_table, Z_STR_P(entry))) != NULL) {
2565 			ZVAL_DEREF(value_ptr);
2566 			Z_TRY_ADDREF_P(value_ptr);
2567 			zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), value_ptr);
2568 		} else if (zend_string_equals_literal(Z_STR_P(entry), "this")) {
2569 			zend_object *object = zend_get_this_object(EG(current_execute_data));
2570 			if (object) {
2571 				GC_ADDREF(object);
2572 				ZVAL_OBJ(&data, object);
2573 				zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
2574 			}
2575 		} else {
2576 			php_error_docref(NULL, E_NOTICE, "Undefined variable: %s", ZSTR_VAL(Z_STR_P(entry)));
2577 		}
2578 	} else if (Z_TYPE_P(entry) == IS_ARRAY) {
2579 	    if (Z_REFCOUNTED_P(entry)) {
2580 			if (Z_IS_RECURSIVE_P(entry)) {
2581 				php_error_docref(NULL, E_WARNING, "recursion detected");
2582 				return;
2583 			}
2584 			Z_PROTECT_RECURSION_P(entry);
2585 		}
2586 		ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(entry), value_ptr) {
2587 			php_compact_var(eg_active_symbol_table, return_value, value_ptr);
2588 		} ZEND_HASH_FOREACH_END();
2589 	    if (Z_REFCOUNTED_P(entry)) {
2590 			Z_UNPROTECT_RECURSION_P(entry);
2591 		}
2592 	}
2593 }
2594 /* }}} */
2595 
2596 /* {{{ proto array compact(mixed var_names [, mixed ...])
2597    Creates a hash containing variables and their values */
2598 PHP_FUNCTION(compact)
2599 {
2600 	zval *args = NULL;	/* function arguments array */
2601 	uint32_t num_args, i;
2602 	zend_array *symbol_table;
2603 
2604 	ZEND_PARSE_PARAMETERS_START(1, -1)
2605 		Z_PARAM_VARIADIC('+', args, num_args)
2606 	ZEND_PARSE_PARAMETERS_END();
2607 
2608 	if (zend_forbid_dynamic_call("compact()") == FAILURE) {
2609 		return;
2610 	}
2611 
2612 	symbol_table = zend_rebuild_symbol_table();
2613 	if (UNEXPECTED(symbol_table == NULL)) {
2614 		return;
2615 	}
2616 
2617 	/* compact() is probably most used with a single array of var_names
2618 	   or multiple string names, rather than a combination of both.
2619 	   So quickly guess a minimum result size based on that */
2620 	if (num_args && Z_TYPE(args[0]) == IS_ARRAY) {
2621 		array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
2622 	} else {
2623 		array_init_size(return_value, num_args);
2624 	}
2625 
2626 	for (i = 0; i < num_args; i++) {
2627 		php_compact_var(symbol_table, return_value, &args[i]);
2628 	}
2629 }
2630 /* }}} */
2631 
2632 /* {{{ proto array array_fill(int start_key, int num, mixed val)
2633    Create an array containing num elements starting with index start_key each initialized to val */
2634 PHP_FUNCTION(array_fill)
2635 {
2636 	zval *val;
2637 	zend_long start_key, num;
2638 
2639 	ZEND_PARSE_PARAMETERS_START(3, 3)
2640 		Z_PARAM_LONG(start_key)
2641 		Z_PARAM_LONG(num)
2642 		Z_PARAM_ZVAL(val)
2643 	ZEND_PARSE_PARAMETERS_END();
2644 
2645 	if (EXPECTED(num > 0)) {
2646 		if (sizeof(num) > 4 && UNEXPECTED(EXPECTED(num > 0x7fffffff))) {
2647 			php_error_docref(NULL, E_WARNING, "Too many elements");
2648 			RETURN_FALSE;
2649 		} else if (UNEXPECTED(start_key > ZEND_LONG_MAX - num + 1)) {
2650 			php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
2651 			RETURN_FALSE;
2652 		} else if (EXPECTED(start_key >= 0) && EXPECTED(start_key < num)) {
2653 			/* create packed array */
2654 			Bucket *p;
2655 			zend_long n;
2656 
2657 			array_init_size(return_value, (uint32_t)(start_key + num));
2658 			zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
2659 			Z_ARRVAL_P(return_value)->nNumUsed = (uint32_t)(start_key + num);
2660 			Z_ARRVAL_P(return_value)->nNumOfElements = (uint32_t)num;
2661 			Z_ARRVAL_P(return_value)->nNextFreeElement = (zend_long)(start_key + num);
2662 
2663 			if (Z_REFCOUNTED_P(val)) {
2664 				GC_ADDREF_EX(Z_COUNTED_P(val), (uint32_t)num);
2665 			}
2666 
2667 			p = Z_ARRVAL_P(return_value)->arData;
2668 			n = start_key;
2669 
2670 			while (start_key--) {
2671 				ZVAL_UNDEF(&p->val);
2672 				p++;
2673 			}
2674 			while (num--) {
2675 				ZVAL_COPY_VALUE(&p->val, val);
2676 				p->h = n++;
2677 				p->key = NULL;
2678 				p++;
2679 			}
2680 		} else {
2681 			/* create hash */
2682 			array_init_size(return_value, (uint32_t)num);
2683 			zend_hash_real_init_mixed(Z_ARRVAL_P(return_value));
2684 			if (Z_REFCOUNTED_P(val)) {
2685 				GC_ADDREF_EX(Z_COUNTED_P(val), (uint32_t)num);
2686 			}
2687 			zend_hash_index_add_new(Z_ARRVAL_P(return_value), start_key, val);
2688 			while (--num) {
2689 				zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), val);
2690 				start_key++;
2691 			}
2692 		}
2693 	} else if (EXPECTED(num == 0)) {
2694 		RETURN_EMPTY_ARRAY();
2695 	} else {
2696 		php_error_docref(NULL, E_WARNING, "Number of elements can't be negative");
2697 		RETURN_FALSE;
2698 	}
2699 }
2700 /* }}} */
2701 
2702 /* {{{ proto array array_fill_keys(array keys, mixed val)
2703    Create an array using the elements of the first parameter as keys each initialized to val */
2704 PHP_FUNCTION(array_fill_keys)
2705 {
2706 	zval *keys, *val, *entry;
2707 
2708 	ZEND_PARSE_PARAMETERS_START(2, 2)
2709 		Z_PARAM_ARRAY(keys)
2710 		Z_PARAM_ZVAL(val)
2711 	ZEND_PARSE_PARAMETERS_END();
2712 
2713 	/* Initialize return array */
2714 	array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
2715 
2716 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) {
2717 		ZVAL_DEREF(entry);
2718 		Z_TRY_ADDREF_P(val);
2719 		if (Z_TYPE_P(entry) == IS_LONG) {
2720 			zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_P(entry), val);
2721 		} else {
2722 			zend_string *tmp_key;
2723 			zend_string *key = zval_get_tmp_string(entry, &tmp_key);
2724 			zend_symtable_update(Z_ARRVAL_P(return_value), key, val);
2725 			zend_tmp_string_release(tmp_key);
2726 		}
2727 	} ZEND_HASH_FOREACH_END();
2728 }
2729 /* }}} */
2730 
2731 #define RANGE_CHECK_DOUBLE_INIT_ARRAY(start, end) do { \
2732 		double __calc_size = ((start - end) / step) + 1; \
2733 		if (__calc_size >= (double)HT_MAX_SIZE) { \
2734 			php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=%0.0f end=%0.0f", end, start); \
2735 			RETURN_FALSE; \
2736 		} \
2737 		size = (uint32_t)_php_math_round(__calc_size, 0, PHP_ROUND_HALF_UP); \
2738 		array_init_size(return_value, size); \
2739 		zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); \
2740 	} while (0)
2741 
2742 #define RANGE_CHECK_LONG_INIT_ARRAY(start, end) do { \
2743 		zend_ulong __calc_size = ((zend_ulong) start - end) / lstep; \
2744 		if (__calc_size >= HT_MAX_SIZE - 1) { \
2745 			php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=" ZEND_LONG_FMT " end=" ZEND_LONG_FMT, end, start); \
2746 			RETURN_FALSE; \
2747 		} \
2748 		size = (uint32_t)(__calc_size + 1); \
2749 		array_init_size(return_value, size); \
2750 		zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); \
2751 	} while (0)
2752 
2753 /* {{{ proto array range(mixed low, mixed high[, int step])
2754    Create an array containing the range of integers or characters from low to high (inclusive) */
2755 PHP_FUNCTION(range)
2756 {
2757 	zval *zlow, *zhigh, *zstep = NULL, tmp;
2758 	int err = 0, is_step_double = 0;
2759 	double step = 1.0;
2760 
2761 	ZEND_PARSE_PARAMETERS_START(2, 3)
2762 		Z_PARAM_ZVAL(zlow)
2763 		Z_PARAM_ZVAL(zhigh)
2764 		Z_PARAM_OPTIONAL
2765 		Z_PARAM_ZVAL(zstep)
2766 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
2767 
2768 	if (zstep) {
2769 		if (Z_TYPE_P(zstep) == IS_DOUBLE) {
2770 			is_step_double = 1;
2771 		} else if (Z_TYPE_P(zstep) == IS_STRING) {
2772 			int type = is_numeric_string(Z_STRVAL_P(zstep), Z_STRLEN_P(zstep), NULL, NULL, 0);
2773 			if (type == IS_DOUBLE) {
2774 				is_step_double = 1;
2775 			}
2776 			if (type == 0) {
2777 				/* bad number */
2778 				php_error_docref(NULL, E_WARNING, "Invalid range string - must be numeric");
2779 				RETURN_FALSE;
2780 			}
2781 		}
2782 
2783 		step = zval_get_double(zstep);
2784 
2785 		/* We only want positive step values. */
2786 		if (step < 0.0) {
2787 			step *= -1;
2788 		}
2789 	}
2790 
2791 	/* If the range is given as strings, generate an array of characters. */
2792 	if (Z_TYPE_P(zlow) == IS_STRING && Z_TYPE_P(zhigh) == IS_STRING && Z_STRLEN_P(zlow) >= 1 && Z_STRLEN_P(zhigh) >= 1) {
2793 		int type1, type2;
2794 		unsigned char low, high;
2795 		zend_long lstep = (zend_long) step;
2796 
2797 		type1 = is_numeric_string(Z_STRVAL_P(zlow), Z_STRLEN_P(zlow), NULL, NULL, 0);
2798 		type2 = is_numeric_string(Z_STRVAL_P(zhigh), Z_STRLEN_P(zhigh), NULL, NULL, 0);
2799 
2800 		if (type1 == IS_DOUBLE || type2 == IS_DOUBLE || is_step_double) {
2801 			goto double_str;
2802 		} else if (type1 == IS_LONG || type2 == IS_LONG) {
2803 			goto long_str;
2804 		}
2805 
2806 		low = (unsigned char)Z_STRVAL_P(zlow)[0];
2807 		high = (unsigned char)Z_STRVAL_P(zhigh)[0];
2808 
2809 		if (low > high) {		/* Negative Steps */
2810 			if (lstep <= 0) {
2811 				err = 1;
2812 				goto err;
2813 			}
2814 			/* Initialize the return_value as an array. */
2815 			array_init_size(return_value, (uint32_t)(((low - high) / lstep) + 1));
2816 			zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
2817 			ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
2818 				for (; low >= high; low -= (unsigned int)lstep) {
2819 					ZEND_HASH_FILL_SET_INTERNED_STR(ZSTR_CHAR(low));
2820 					ZEND_HASH_FILL_NEXT();
2821 					if (((signed int)low - lstep) < 0) {
2822 						break;
2823 					}
2824 				}
2825 			} ZEND_HASH_FILL_END();
2826 		} else if (high > low) {	/* Positive Steps */
2827 			if (lstep <= 0) {
2828 				err = 1;
2829 				goto err;
2830 			}
2831 			array_init_size(return_value, (uint32_t)(((high - low) / lstep) + 1));
2832 			zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
2833 			ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
2834 				for (; low <= high; low += (unsigned int)lstep) {
2835 					ZEND_HASH_FILL_SET_INTERNED_STR(ZSTR_CHAR(low));
2836 					ZEND_HASH_FILL_NEXT();
2837 					if (((signed int)low + lstep) > 255) {
2838 						break;
2839 					}
2840 				}
2841 			} ZEND_HASH_FILL_END();
2842 		} else {
2843 			array_init(return_value);
2844 			ZVAL_INTERNED_STR(&tmp, ZSTR_CHAR(low));
2845 			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
2846 		}
2847 	} else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) {
2848 		double low, high, element;
2849 		uint32_t i, size;
2850 double_str:
2851 		low = zval_get_double(zlow);
2852 		high = zval_get_double(zhigh);
2853 
2854 		if (zend_isinf(high) || zend_isinf(low)) {
2855 			php_error_docref(NULL, E_WARNING, "Invalid range supplied: start=%0.0f end=%0.0f", low, high);
2856 			RETURN_FALSE;
2857 		}
2858 
2859 		if (low > high) { 		/* Negative steps */
2860 			if (low - high < step || step <= 0) {
2861 				err = 1;
2862 				goto err;
2863 			}
2864 
2865 			RANGE_CHECK_DOUBLE_INIT_ARRAY(low, high);
2866 
2867 			ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
2868 				for (i = 0, element = low; i < size && element >= high; ++i, element = low - (i * step)) {
2869 					ZEND_HASH_FILL_SET_DOUBLE(element);
2870 					ZEND_HASH_FILL_NEXT();
2871 				}
2872 			} ZEND_HASH_FILL_END();
2873 		} else if (high > low) { 	/* Positive steps */
2874 			if (high - low < step || step <= 0) {
2875 				err = 1;
2876 				goto err;
2877 			}
2878 
2879 			RANGE_CHECK_DOUBLE_INIT_ARRAY(high, low);
2880 
2881 			ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
2882 				for (i = 0, element = low; i < size && element <= high; ++i, element = low + (i * step)) {
2883 					ZEND_HASH_FILL_SET_DOUBLE(element);
2884 					ZEND_HASH_FILL_NEXT();
2885 				}
2886 			} ZEND_HASH_FILL_END();
2887 		} else {
2888 			array_init(return_value);
2889 			ZVAL_DOUBLE(&tmp, low);
2890 			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
2891 		}
2892 	} else {
2893 		zend_long low, high;
2894 		/* lstep is a zend_ulong so that comparisons to it don't overflow, i.e. low - high < lstep */
2895 		zend_ulong lstep;
2896 		uint32_t i, size;
2897 long_str:
2898 		low = zval_get_long(zlow);
2899 		high = zval_get_long(zhigh);
2900 
2901 		if (step <= 0) {
2902 			err = 1;
2903 			goto err;
2904 		}
2905 
2906 		lstep = (zend_ulong)step;
2907 		if (step <= 0) {
2908 			err = 1;
2909 			goto err;
2910 		}
2911 
2912 		if (low > high) { 		/* Negative steps */
2913 			if ((zend_ulong)low - high < lstep) {
2914 				err = 1;
2915 				goto err;
2916 			}
2917 
2918 			RANGE_CHECK_LONG_INIT_ARRAY(low, high);
2919 
2920 			ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
2921 				for (i = 0; i < size; ++i) {
2922 					ZEND_HASH_FILL_SET_LONG(low - (i * lstep));
2923 					ZEND_HASH_FILL_NEXT();
2924 				}
2925 			} ZEND_HASH_FILL_END();
2926 		} else if (high > low) { 	/* Positive steps */
2927 			if ((zend_ulong)high - low < lstep) {
2928 				err = 1;
2929 				goto err;
2930 			}
2931 
2932 			RANGE_CHECK_LONG_INIT_ARRAY(high, low);
2933 
2934 			ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
2935 				for (i = 0; i < size; ++i) {
2936 					ZEND_HASH_FILL_SET_LONG(low + (i * lstep));
2937 					ZEND_HASH_FILL_NEXT();
2938 				}
2939 			} ZEND_HASH_FILL_END();
2940 		} else {
2941 			array_init(return_value);
2942 			ZVAL_LONG(&tmp, low);
2943 			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
2944 		}
2945 	}
2946 err:
2947 	if (err) {
2948 		php_error_docref(NULL, E_WARNING, "step exceeds the specified range");
2949 		RETURN_FALSE;
2950 	}
2951 }
2952 /* }}} */
2953 
2954 #undef RANGE_CHECK_DOUBLE_INIT_ARRAY
2955 #undef RANGE_CHECK_LONG_INIT_ARRAY
2956 
2957 static void php_array_data_shuffle(zval *array) /* {{{ */
2958 {
2959 	uint32_t idx, j, n_elems;
2960 	Bucket *p, temp;
2961 	HashTable *hash;
2962 	zend_long rnd_idx;
2963 	uint32_t n_left;
2964 
2965 	n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
2966 
2967 	if (n_elems < 1) {
2968 		return;
2969 	}
2970 
2971 	hash = Z_ARRVAL_P(array);
2972 	n_left = n_elems;
2973 
2974 	if (EXPECTED(!HT_HAS_ITERATORS(hash))) {
2975 		if (hash->nNumUsed != hash->nNumOfElements) {
2976 			for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
2977 				p = hash->arData + idx;
2978 				if (Z_TYPE(p->val) == IS_UNDEF) continue;
2979 				if (j != idx) {
2980 					hash->arData[j] = *p;
2981 				}
2982 				j++;
2983 			}
2984 		}
2985 		while (--n_left) {
2986 			rnd_idx = php_mt_rand_range(0, n_left);
2987 			if (rnd_idx != n_left) {
2988 				temp = hash->arData[n_left];
2989 				hash->arData[n_left] = hash->arData[rnd_idx];
2990 				hash->arData[rnd_idx] = temp;
2991 			}
2992 		}
2993 	} else {
2994 		uint32_t iter_pos = zend_hash_iterators_lower_pos(hash, 0);
2995 
2996 		if (hash->nNumUsed != hash->nNumOfElements) {
2997 			for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
2998 				p = hash->arData + idx;
2999 				if (Z_TYPE(p->val) == IS_UNDEF) continue;
3000 				if (j != idx) {
3001 					hash->arData[j] = *p;
3002 					if (idx == iter_pos) {
3003 						zend_hash_iterators_update(hash, idx, j);
3004 						iter_pos = zend_hash_iterators_lower_pos(hash, iter_pos + 1);
3005 					}
3006 				}
3007 				j++;
3008 			}
3009 		}
3010 		while (--n_left) {
3011 			rnd_idx = php_mt_rand_range(0, n_left);
3012 			if (rnd_idx != n_left) {
3013 				temp = hash->arData[n_left];
3014 				hash->arData[n_left] = hash->arData[rnd_idx];
3015 				hash->arData[rnd_idx] = temp;
3016 				zend_hash_iterators_update(hash, (uint32_t)rnd_idx, n_left);
3017 			}
3018 		}
3019 	}
3020 	hash->nNumUsed = n_elems;
3021 	hash->nInternalPointer = 0;
3022 
3023 	for (j = 0; j < n_elems; j++) {
3024 		p = hash->arData + j;
3025 		if (p->key) {
3026 			zend_string_release_ex(p->key, 0);
3027 		}
3028 		p->h = j;
3029 		p->key = NULL;
3030 	}
3031 	hash->nNextFreeElement = n_elems;
3032 	if (!(HT_FLAGS(hash) & HASH_FLAG_PACKED)) {
3033 		zend_hash_to_packed(hash);
3034 	}
3035 }
3036 /* }}} */
3037 
3038 /* {{{ proto bool shuffle(array array_arg)
3039    Randomly shuffle the contents of an array */
3040 PHP_FUNCTION(shuffle)
3041 {
3042 	zval *array;
3043 
3044 	ZEND_PARSE_PARAMETERS_START(1, 1)
3045 		Z_PARAM_ARRAY_EX(array, 0, 1)
3046 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
3047 
3048 	php_array_data_shuffle(array);
3049 
3050 	RETURN_TRUE;
3051 }
3052 /* }}} */
3053 
3054 static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, HashTable *replace, HashTable *removed) /* {{{ */
3055 {
3056 	HashTable 	 out_hash;			/* Output hashtable */
3057 	zend_long	 num_in;			/* Number of entries in the input hashtable */
3058 	zend_long	 pos;				/* Current position in the hashtable */
3059 	uint32_t     idx;
3060 	Bucket		*p;					/* Pointer to hash bucket */
3061 	zval		*entry;				/* Hash entry */
3062 	uint32_t    iter_pos = zend_hash_iterators_lower_pos(in_hash, 0);
3063 
3064 	/* Get number of entries in the input hash */
3065 	num_in = zend_hash_num_elements(in_hash);
3066 
3067 	/* Clamp the offset.. */
3068 	if (offset > num_in) {
3069 		offset = num_in;
3070 	} else if (offset < 0 && (offset = (num_in + offset)) < 0) {
3071 		offset = 0;
3072 	}
3073 
3074 	/* ..and the length */
3075 	if (length < 0) {
3076 		length = num_in - offset + length;
3077 	} else if (((unsigned)offset + (unsigned)length) > (unsigned)num_in) {
3078 		length = num_in - offset;
3079 	}
3080 
3081 	/* Create and initialize output hash */
3082 	zend_hash_init(&out_hash, (length > 0 ? num_in - length : 0) + (replace ? zend_hash_num_elements(replace) : 0), NULL, ZVAL_PTR_DTOR, 0);
3083 
3084 	/* Start at the beginning of the input hash and copy entries to output hash until offset is reached */
3085 	for (pos = 0, idx = 0; pos < offset && idx < in_hash->nNumUsed; idx++) {
3086 		p = in_hash->arData + idx;
3087 		if (Z_TYPE(p->val) == IS_UNDEF) continue;
3088 		/* Get entry and increase reference count */
3089 		entry = &p->val;
3090 
3091 		/* Update output hash depending on key type */
3092 		if (p->key == NULL) {
3093 			zend_hash_next_index_insert_new(&out_hash, entry);
3094 		} else {
3095 			zend_hash_add_new(&out_hash, p->key, entry);
3096 		}
3097 		if (idx == iter_pos) {
3098 			if ((zend_long)idx != pos) {
3099 				zend_hash_iterators_update(in_hash, idx, pos);
3100 			}
3101 			iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
3102 		}
3103 		pos++;
3104 	}
3105 
3106 	/* If hash for removed entries exists, go until offset+length and copy the entries to it */
3107 	if (removed != NULL) {
3108 		for ( ; pos < offset + length && idx < in_hash->nNumUsed; idx++) {
3109 			p = in_hash->arData + idx;
3110 			if (Z_TYPE(p->val) == IS_UNDEF) continue;
3111 			pos++;
3112 			entry = &p->val;
3113 			Z_TRY_ADDREF_P(entry);
3114 			if (p->key == NULL) {
3115 				zend_hash_next_index_insert_new(removed, entry);
3116 				zend_hash_del_bucket(in_hash, p);
3117 			} else {
3118 				zend_hash_add_new(removed, p->key, entry);
3119 				if (in_hash == &EG(symbol_table)) {
3120 					zend_delete_global_variable(p->key);
3121 				} else {
3122 					zend_hash_del_bucket(in_hash, p);
3123 				}
3124 			}
3125 		}
3126 	} else { /* otherwise just skip those entries */
3127 		int pos2 = pos;
3128 
3129 		for ( ; pos2 < offset + length && idx < in_hash->nNumUsed; idx++) {
3130 			p = in_hash->arData + idx;
3131 			if (Z_TYPE(p->val) == IS_UNDEF) continue;
3132 			pos2++;
3133 			if (p->key && in_hash == &EG(symbol_table)) {
3134 				zend_delete_global_variable(p->key);
3135 			} else {
3136 				zend_hash_del_bucket(in_hash, p);
3137 			}
3138 		}
3139 	}
3140 	iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos);
3141 
3142 	/* If there are entries to insert.. */
3143 	if (replace) {
3144 		ZEND_HASH_FOREACH_VAL_IND(replace, entry) {
3145 			Z_TRY_ADDREF_P(entry);
3146 			zend_hash_next_index_insert_new(&out_hash, entry);
3147 			pos++;
3148 		} ZEND_HASH_FOREACH_END();
3149 	}
3150 
3151 	/* Copy the remaining input hash entries to the output hash */
3152 	for ( ; idx < in_hash->nNumUsed ; idx++) {
3153 		p = in_hash->arData + idx;
3154 		if (Z_TYPE(p->val) == IS_UNDEF) continue;
3155 		entry = &p->val;
3156 		if (p->key == NULL) {
3157 			zend_hash_next_index_insert_new(&out_hash, entry);
3158 		} else {
3159 			zend_hash_add_new(&out_hash, p->key, entry);
3160 		}
3161 		if (idx == iter_pos) {
3162 			if ((zend_long)idx != pos) {
3163 				zend_hash_iterators_update(in_hash, idx, pos);
3164 			}
3165 			iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
3166 		}
3167 		pos++;
3168 	}
3169 
3170 	/* replace HashTable data */
3171 	HT_SET_ITERATORS_COUNT(&out_hash, HT_ITERATORS_COUNT(in_hash));
3172 	HT_SET_ITERATORS_COUNT(in_hash, 0);
3173 	in_hash->pDestructor = NULL;
3174 	zend_hash_destroy(in_hash);
3175 
3176 	HT_FLAGS(in_hash)          = HT_FLAGS(&out_hash);
3177 	in_hash->nTableSize        = out_hash.nTableSize;
3178 	in_hash->nTableMask        = out_hash.nTableMask;
3179 	in_hash->nNumUsed          = out_hash.nNumUsed;
3180 	in_hash->nNumOfElements    = out_hash.nNumOfElements;
3181 	in_hash->nNextFreeElement  = out_hash.nNextFreeElement;
3182 	in_hash->arData            = out_hash.arData;
3183 	in_hash->pDestructor       = out_hash.pDestructor;
3184 
3185 	zend_hash_internal_pointer_reset(in_hash);
3186 }
3187 /* }}} */
3188 
3189 /* {{{ proto int array_push(array stack, mixed var [, mixed ...])
3190    Pushes elements onto the end of the array */
3191 PHP_FUNCTION(array_push)
3192 {
3193 	zval   *args,		/* Function arguments array */
3194 		   *stack,		/* Input array */
3195 		    new_var;	/* Variable to be pushed */
3196 	int i,				/* Loop counter */
3197 		argc;			/* Number of function arguments */
3198 
3199 
3200 	ZEND_PARSE_PARAMETERS_START(1, -1)
3201 		Z_PARAM_ARRAY_EX(stack, 0, 1)
3202 		Z_PARAM_VARIADIC('+', args, argc)
3203 	ZEND_PARSE_PARAMETERS_END();
3204 
3205 	/* For each subsequent argument, make it a reference, increase refcount, and add it to the end of the array */
3206 	for (i = 0; i < argc; i++) {
3207 		ZVAL_COPY(&new_var, &args[i]);
3208 
3209 		if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var) == NULL) {
3210 			Z_TRY_DELREF(new_var);
3211 			php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
3212 			RETURN_FALSE;
3213 		}
3214 	}
3215 
3216 	/* Clean up and return the number of values in the stack */
3217 	RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
3218 }
3219 /* }}} */
3220 
3221 /* {{{ proto mixed array_pop(array stack)
3222    Pops an element off the end of the array */
3223 PHP_FUNCTION(array_pop)
3224 {
3225 	zval *stack,	/* Input stack */
3226 		 *val;		/* Value to be popped */
3227 	uint32_t idx;
3228 	Bucket *p;
3229 
3230 	ZEND_PARSE_PARAMETERS_START(1, 1)
3231 		Z_PARAM_ARRAY_EX(stack, 0, 1)
3232 	ZEND_PARSE_PARAMETERS_END();
3233 
3234 	if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {
3235 		return;
3236 	}
3237 
3238 	/* Get the last value and copy it into the return value */
3239 	idx = Z_ARRVAL_P(stack)->nNumUsed;
3240 	while (1) {
3241 		if (idx == 0) {
3242 			return;
3243 		}
3244 		idx--;
3245 		p = Z_ARRVAL_P(stack)->arData + idx;
3246 		val = &p->val;
3247 		if (Z_TYPE_P(val) == IS_INDIRECT) {
3248 			val = Z_INDIRECT_P(val);
3249 		}
3250 		if (Z_TYPE_P(val) != IS_UNDEF) {
3251 			break;
3252 		}
3253 	}
3254 	ZVAL_COPY_DEREF(return_value, val);
3255 
3256 	if (!p->key && Z_ARRVAL_P(stack)->nNextFreeElement > 0 && p->h >= (zend_ulong)(Z_ARRVAL_P(stack)->nNextFreeElement - 1)) {
3257 		Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1;
3258 	}
3259 
3260 	/* Delete the last value */
3261 	if (p->key && Z_ARRVAL_P(stack) == &EG(symbol_table)) {
3262 		zend_delete_global_variable(p->key);
3263 	} else {
3264 		zend_hash_del_bucket(Z_ARRVAL_P(stack), p);
3265 	}
3266 
3267 	zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
3268 }
3269 /* }}} */
3270 
3271 /* {{{ proto mixed array_shift(array stack)
3272    Pops an element off the beginning of the array */
3273 PHP_FUNCTION(array_shift)
3274 {
3275 	zval *stack,	/* Input stack */
3276 		 *val;		/* Value to be popped */
3277 	uint32_t idx;
3278 	Bucket *p;
3279 
3280 	ZEND_PARSE_PARAMETERS_START(1, 1)
3281 		Z_PARAM_ARRAY_EX(stack, 0, 1)
3282 	ZEND_PARSE_PARAMETERS_END();
3283 
3284 	if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {
3285 		return;
3286 	}
3287 
3288 	/* Get the first value and copy it into the return value */
3289 	idx = 0;
3290 	while (1) {
3291 		if (idx == Z_ARRVAL_P(stack)->nNumUsed) {
3292 			return;
3293 		}
3294 		p = Z_ARRVAL_P(stack)->arData + idx;
3295 		val = &p->val;
3296 		if (Z_TYPE_P(val) == IS_INDIRECT) {
3297 			val = Z_INDIRECT_P(val);
3298 		}
3299 		if (Z_TYPE_P(val) != IS_UNDEF) {
3300 			break;
3301 		}
3302 		idx++;
3303 	}
3304 	ZVAL_COPY_DEREF(return_value, val);
3305 
3306 	/* Delete the first value */
3307 	if (p->key && Z_ARRVAL_P(stack) == &EG(symbol_table)) {
3308 		zend_delete_global_variable(p->key);
3309 	} else {
3310 		zend_hash_del_bucket(Z_ARRVAL_P(stack), p);
3311 	}
3312 
3313 	/* re-index like it did before */
3314 	if (HT_FLAGS(Z_ARRVAL_P(stack)) & HASH_FLAG_PACKED) {
3315 		uint32_t k = 0;
3316 
3317 		if (EXPECTED(!HT_HAS_ITERATORS(Z_ARRVAL_P(stack)))) {
3318 			for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
3319 				p = Z_ARRVAL_P(stack)->arData + idx;
3320 				if (Z_TYPE(p->val) == IS_UNDEF) continue;
3321 				if (idx != k) {
3322 					Bucket *q = Z_ARRVAL_P(stack)->arData + k;
3323 					q->h = k;
3324 					q->key = NULL;
3325 					ZVAL_COPY_VALUE(&q->val, &p->val);
3326 					ZVAL_UNDEF(&p->val);
3327 				}
3328 				k++;
3329 			}
3330 		} else {
3331 			uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);
3332 
3333 			for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
3334 				p = Z_ARRVAL_P(stack)->arData + idx;
3335 				if (Z_TYPE(p->val) == IS_UNDEF) continue;
3336 				if (idx != k) {
3337 					Bucket *q = Z_ARRVAL_P(stack)->arData + k;
3338 					q->h = k;
3339 					q->key = NULL;
3340 					ZVAL_COPY_VALUE(&q->val, &p->val);
3341 					ZVAL_UNDEF(&p->val);
3342 					if (idx == iter_pos) {
3343 						zend_hash_iterators_update(Z_ARRVAL_P(stack), idx, k);
3344 						iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
3345 					}
3346 				}
3347 				k++;
3348 			}
3349 		}
3350 		Z_ARRVAL_P(stack)->nNumUsed = k;
3351 		Z_ARRVAL_P(stack)->nNextFreeElement = k;
3352 	} else {
3353 		uint32_t k = 0;
3354 		int should_rehash = 0;
3355 
3356 		for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
3357 			p = Z_ARRVAL_P(stack)->arData + idx;
3358 			if (Z_TYPE(p->val) == IS_UNDEF) continue;
3359 			if (p->key == NULL) {
3360 				if (p->h != k) {
3361 					p->h = k++;
3362 					should_rehash = 1;
3363 				} else {
3364 					k++;
3365 				}
3366 			}
3367 		}
3368 		Z_ARRVAL_P(stack)->nNextFreeElement = k;
3369 		if (should_rehash) {
3370 			zend_hash_rehash(Z_ARRVAL_P(stack));
3371 		}
3372 	}
3373 
3374