php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
array.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Andi Gutmans <andi@php.net> |
14 | Zeev Suraski <zeev@php.net> |
15 | Rasmus Lerdorf <rasmus@php.net> |
16 | Andrei Zmievski <andrei@php.net> |
17 | Stig Venaas <venaas@php.net> |
18 | Jason Greene <jason@php.net> |
19 +----------------------------------------------------------------------+
20*/
21
22#include "php.h"
23#include "php_ini.h"
24#include <stdarg.h>
25#include <stdlib.h>
26#include <math.h>
27#include <time.h>
28#include <string.h>
29#include "zend_globals.h"
30#include "zend_interfaces.h"
31#include "php_array.h"
32#include "basic_functions.h"
33#include "php_string.h"
34#include "php_math.h"
35#include "zend_smart_str.h"
36#include "zend_bitset.h"
37#include "zend_exceptions.h"
40
41/* {{{ defines */
42
43#define DIFF_NORMAL 1
44#define DIFF_KEY 2
45#define DIFF_ASSOC 6
46#define DIFF_COMP_DATA_NONE -1
47#define DIFF_COMP_DATA_INTERNAL 0
48#define DIFF_COMP_DATA_USER 1
49#define DIFF_COMP_KEY_INTERNAL 0
50#define DIFF_COMP_KEY_USER 1
51
52#define INTERSECT_NORMAL 1
53#define INTERSECT_KEY 2
54#define INTERSECT_ASSOC 6
55#define INTERSECT_COMP_DATA_NONE -1
56#define INTERSECT_COMP_DATA_INTERNAL 0
57#define INTERSECT_COMP_DATA_USER 1
58#define INTERSECT_COMP_KEY_INTERNAL 0
59#define INTERSECT_COMP_KEY_USER 1
60/* }}} */
61
63
64/* {{{ php_array_init_globals */
65static void php_array_init_globals(zend_array_globals *array_globals)
66{
67 memset(array_globals, 0, sizeof(zend_array_globals));
68}
69/* }}} */
70
71PHP_MINIT_FUNCTION(array) /* {{{ */
72{
73 ZEND_INIT_MODULE_GLOBALS(array, php_array_init_globals, NULL);
74
75 return SUCCESS;
76}
77/* }}} */
78
79PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
80{
81#ifdef ZTS
82 ts_free_id(array_globals_id);
83#endif
84
85 return SUCCESS;
86}
87/* }}} */
88
89static zend_never_inline ZEND_COLD int stable_sort_fallback(Bucket *a, Bucket *b) {
90 if (Z_EXTRA(a->val) > Z_EXTRA(b->val)) {
91 return 1;
92 } else if (Z_EXTRA(a->val) < Z_EXTRA(b->val)) {
93 return -1;
94 } else {
95 return 0;
96 }
97}
98
99#define RETURN_STABLE_SORT(a, b, result) do { \
100 int _result = (result); \
101 if (EXPECTED(_result)) { \
102 return _result; \
103 } \
104 return stable_sort_fallback((a), (b)); \
105} while (0)
106
107/* Generate inlined unstable and stable variants, and non-inlined reversed variants. */
108#define DEFINE_SORT_VARIANTS(name) \
109 static zend_never_inline int php_array_##name##_unstable(Bucket *a, Bucket *b) { \
110 return php_array_##name##_unstable_i(a, b); \
111 } \
112 static zend_never_inline int php_array_##name(Bucket *a, Bucket *b) { \
113 RETURN_STABLE_SORT(a, b, php_array_##name##_unstable_i(a, b)); \
114 } \
115 static zend_never_inline int php_array_reverse_##name##_unstable(Bucket *a, Bucket *b) { \
116 return php_array_##name##_unstable(a, b) * -1; \
117 } \
118 static zend_never_inline int php_array_reverse_##name(Bucket *a, Bucket *b) { \
119 RETURN_STABLE_SORT(a, b, php_array_reverse_##name##_unstable(a, b)); \
120 } \
121
122static zend_always_inline int php_array_key_compare_unstable_i(Bucket *f, Bucket *s) /* {{{ */
123{
124 zval first;
125 zval second;
126
127 if (f->key == NULL && s->key == NULL) {
128 return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
129 } else if (f->key && s->key) {
130 return zendi_smart_strcmp(f->key, s->key);
131 }
132 if (f->key) {
133 ZVAL_STR(&first, f->key);
134 } else {
135 ZVAL_LONG(&first, f->h);
136 }
137 if (s->key) {
138 ZVAL_STR(&second, s->key);
139 } else {
140 ZVAL_LONG(&second, s->h);
141 }
142 return zend_compare(&first, &second);
143}
144/* }}} */
145
146static zend_always_inline int php_array_key_compare_numeric_unstable_i(Bucket *f, Bucket *s) /* {{{ */
147{
148 if (f->key == NULL && s->key == NULL) {
149 return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
150 } else {
151 double d1, d2;
152 if (f->key) {
153 d1 = zend_strtod(f->key->val, NULL);
154 } else {
155 d1 = (double)(zend_long)f->h;
156 }
157 if (s->key) {
158 d2 = zend_strtod(s->key->val, NULL);
159 } else {
160 d2 = (double)(zend_long)s->h;
161 }
162 return ZEND_THREEWAY_COMPARE(d1, d2);
163 }
164}
165/* }}} */
166
167static zend_always_inline int php_array_key_compare_string_case_unstable_i(Bucket *f, Bucket *s) /* {{{ */
168{
169 const char *s1, *s2;
170 size_t l1, l2;
171 char buf1[MAX_LENGTH_OF_LONG + 1];
172 char buf2[MAX_LENGTH_OF_LONG + 1];
173
174 if (f->key) {
175 s1 = f->key->val;
176 l1 = f->key->len;
177 } else {
178 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
179 l1 = buf1 + sizeof(buf1) - 1 - s1;
180 }
181 if (s->key) {
182 s2 = s->key->val;
183 l2 = s->key->len;
184 } else {
185 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
186 l2 = buf2 + sizeof(buf2) - 1 - s2;
187 }
188 return zend_binary_strcasecmp_l(s1, l1, s2, l2);
189}
190/* }}} */
191
192static zend_always_inline int php_array_key_compare_string_unstable_i(Bucket *f, Bucket *s) /* {{{ */
193{
194 const char *s1, *s2;
195 size_t l1, l2;
196 char buf1[MAX_LENGTH_OF_LONG + 1];
197 char buf2[MAX_LENGTH_OF_LONG + 1];
198
199 if (f->key) {
200 s1 = f->key->val;
201 l1 = f->key->len;
202 } else {
203 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
204 l1 = buf1 + sizeof(buf1) - 1 - s1;
205 }
206 if (s->key) {
207 s2 = s->key->val;
208 l2 = s->key->len;
209 } else {
210 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
211 l2 = buf2 + sizeof(buf2) - 1 - s2;
212 }
213 return zend_binary_strcmp(s1, l1, s2, l2);
214}
215/* }}} */
216
217static int php_array_key_compare_string_natural_general(Bucket *f, Bucket *s, int fold_case) /* {{{ */
218{
219 const char *s1, *s2;
220 size_t l1, l2;
221 char buf1[MAX_LENGTH_OF_LONG + 1];
222 char buf2[MAX_LENGTH_OF_LONG + 1];
223
224 if (f->key) {
225 s1 = f->key->val;
226 l1 = f->key->len;
227 } else {
228 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
229 l1 = buf1 + sizeof(buf1) - 1 - s1;
230 }
231 if (s->key) {
232 s2 = s->key->val;
233 l2 = s->key->len;
234 } else {
235 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
236 l2 = buf2 + sizeof(buf2) - 1 - s2;
237 }
238 return strnatcmp_ex(s1, l1, s2, l2, fold_case);
239}
240/* }}} */
241
242static int php_array_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */
243{
244 RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, 1));
245}
246/* }}} */
247
248static int php_array_reverse_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */
249{
250 RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, 1));
251}
252/* }}} */
253
254static int php_array_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */
255{
256 RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, 0));
257}
258/* }}} */
259
260static int php_array_reverse_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */
261{
262 RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, 0));
263}
264/* }}} */
265
266static zend_always_inline int php_array_key_compare_string_locale_unstable_i(Bucket *f, Bucket *s) /* {{{ */
267{
268 const char *s1, *s2;
269 char buf1[MAX_LENGTH_OF_LONG + 1];
270 char buf2[MAX_LENGTH_OF_LONG + 1];
271
272 if (f->key) {
273 s1 = f->key->val;
274 } else {
275 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
276 }
277 if (s->key) {
278 s2 = s->key->val;
279 } else {
280 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
281 }
282 return strcoll(s1, s2);
283}
284/* }}} */
285
286static zend_always_inline int php_array_data_compare_unstable_i(Bucket *f, Bucket *s) /* {{{ */
287{
288 int result = zend_compare(&f->val, &s->val);
289 /* Special enums handling for array_unique. We don't want to add this logic to zend_compare as
290 * that would be observable via comparison operators. */
291 zval *rhs = &s->val;
292 ZVAL_DEREF(rhs);
293 if (UNEXPECTED(Z_TYPE_P(rhs) == IS_OBJECT)
295 && (Z_OBJCE_P(rhs)->ce_flags & ZEND_ACC_ENUM)) {
296 zval *lhs = &f->val;
297 ZVAL_DEREF(lhs);
298 if (Z_TYPE_P(lhs) == IS_OBJECT && (Z_OBJCE_P(lhs)->ce_flags & ZEND_ACC_ENUM)) {
299 // Order doesn't matter, we just need to group the same enum values
300 uintptr_t lhs_uintptr = (uintptr_t)Z_OBJ_P(lhs);
301 uintptr_t rhs_uintptr = (uintptr_t)Z_OBJ_P(rhs);
302 return lhs_uintptr == rhs_uintptr ? 0 : (lhs_uintptr < rhs_uintptr ? -1 : 1);
303 } else {
304 // Shift enums to the end of the array
305 return -1;
306 }
307 }
308 return result;
309}
310/* }}} */
311
312static zend_always_inline int php_array_data_compare_numeric_unstable_i(Bucket *f, Bucket *s) /* {{{ */
313{
314 return numeric_compare_function(&f->val, &s->val);
315}
316/* }}} */
317
318static zend_always_inline int php_array_data_compare_string_case_unstable_i(Bucket *f, Bucket *s) /* {{{ */
319{
320 return string_case_compare_function(&f->val, &s->val);
321}
322/* }}} */
323
324static zend_always_inline int php_array_data_compare_string_unstable_i(Bucket *f, Bucket *s) /* {{{ */
325{
326 return string_compare_function(&f->val, &s->val);
327}
328/* }}} */
329
330static int php_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case) /* {{{ */
331{
332 zend_string *tmp_str1, *tmp_str2;
333 zend_string *str1 = zval_get_tmp_string(&f->val, &tmp_str1);
334 zend_string *str2 = zval_get_tmp_string(&s->val, &tmp_str2);
335
336 int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
337
338 zend_tmp_string_release(tmp_str1);
339 zend_tmp_string_release(tmp_str2);
340 return result;
341}
342/* }}} */
343
344static zend_always_inline int php_array_natural_compare_unstable_i(Bucket *a, Bucket *b) /* {{{ */
345{
346 return php_array_natural_general_compare(a, b, 0);
347}
348/* }}} */
349
350static zend_always_inline int php_array_natural_case_compare_unstable_i(Bucket *a, Bucket *b) /* {{{ */
351{
352 return php_array_natural_general_compare(a, b, 1);
353}
354/* }}} */
355
356static int php_array_data_compare_string_locale_unstable_i(Bucket *f, Bucket *s) /* {{{ */
357{
358 return string_locale_compare_function(&f->val, &s->val);
359}
360/* }}} */
361
363DEFINE_SORT_VARIANTS(key_compare_numeric);
364DEFINE_SORT_VARIANTS(key_compare_string_case);
365DEFINE_SORT_VARIANTS(key_compare_string);
366DEFINE_SORT_VARIANTS(key_compare_string_locale);
368DEFINE_SORT_VARIANTS(data_compare_numeric);
369DEFINE_SORT_VARIANTS(data_compare_string_case);
370DEFINE_SORT_VARIANTS(data_compare_string);
371DEFINE_SORT_VARIANTS(data_compare_string_locale);
372DEFINE_SORT_VARIANTS(natural_compare);
373DEFINE_SORT_VARIANTS(natural_case_compare);
374
375static bucket_compare_func_t php_get_key_compare_func(zend_long sort_type, int reverse) /* {{{ */
376{
377 switch (sort_type & ~PHP_SORT_FLAG_CASE) {
378 case PHP_SORT_NUMERIC:
379 if (reverse) {
380 return php_array_reverse_key_compare_numeric;
381 } else {
382 return php_array_key_compare_numeric;
383 }
384 break;
385
386 case PHP_SORT_STRING:
387 if (sort_type & PHP_SORT_FLAG_CASE) {
388 if (reverse) {
389 return php_array_reverse_key_compare_string_case;
390 } else {
391 return php_array_key_compare_string_case;
392 }
393 } else {
394 if (reverse) {
395 return php_array_reverse_key_compare_string;
396 } else {
397 return php_array_key_compare_string;
398 }
399 }
400 break;
401
402 case PHP_SORT_NATURAL:
403 if (sort_type & PHP_SORT_FLAG_CASE) {
404 if (reverse) {
405 return php_array_reverse_key_compare_string_natural_case;
406 } else {
407 return php_array_key_compare_string_natural_case;
408 }
409 } else {
410 if (reverse) {
411 return php_array_reverse_key_compare_string_natural;
412 } else {
413 return php_array_key_compare_string_natural;
414 }
415 }
416 break;
417
419 if (reverse) {
420 return php_array_reverse_key_compare_string_locale;
421 } else {
422 return php_array_key_compare_string_locale;
423 }
424 break;
425
426 case PHP_SORT_REGULAR:
427 default:
428 if (reverse) {
429 return php_array_reverse_key_compare;
430 } else {
431 return php_array_key_compare;
432 }
433 break;
434 }
435 return NULL;
436}
437/* }}} */
438
439static bucket_compare_func_t php_get_data_compare_func(zend_long sort_type, int reverse) /* {{{ */
440{
441 switch (sort_type & ~PHP_SORT_FLAG_CASE) {
442 case PHP_SORT_NUMERIC:
443 if (reverse) {
444 return php_array_reverse_data_compare_numeric;
445 } else {
446 return php_array_data_compare_numeric;
447 }
448 break;
449
450 case PHP_SORT_STRING:
451 if (sort_type & PHP_SORT_FLAG_CASE) {
452 if (reverse) {
453 return php_array_reverse_data_compare_string_case;
454 } else {
455 return php_array_data_compare_string_case;
456 }
457 } else {
458 if (reverse) {
459 return php_array_reverse_data_compare_string;
460 } else {
461 return php_array_data_compare_string;
462 }
463 }
464 break;
465
466 case PHP_SORT_NATURAL:
467 if (sort_type & PHP_SORT_FLAG_CASE) {
468 if (reverse) {
469 return php_array_reverse_natural_case_compare;
470 } else {
471 return php_array_natural_case_compare;
472 }
473 } else {
474 if (reverse) {
475 return php_array_reverse_natural_compare;
476 } else {
477 return php_array_natural_compare;
478 }
479 }
480 break;
481
483 if (reverse) {
484 return php_array_reverse_data_compare_string_locale;
485 } else {
486 return php_array_data_compare_string_locale;
487 }
488 break;
489
490 case PHP_SORT_REGULAR:
491 default:
492 if (reverse) {
493 return php_array_reverse_data_compare;
494 } else {
495 return php_array_data_compare;
496 }
497 break;
498 }
499 return NULL;
500}
501/* }}} */
502
503static bucket_compare_func_t php_get_data_compare_func_unstable(zend_long sort_type, int reverse) /* {{{ */
504{
505 switch (sort_type & ~PHP_SORT_FLAG_CASE) {
506 case PHP_SORT_NUMERIC:
507 if (reverse) {
508 return php_array_reverse_data_compare_numeric_unstable;
509 } else {
510 return php_array_data_compare_numeric_unstable;
511 }
512 break;
513
514 case PHP_SORT_STRING:
515 if (sort_type & PHP_SORT_FLAG_CASE) {
516 if (reverse) {
517 return php_array_reverse_data_compare_string_case_unstable;
518 } else {
519 return php_array_data_compare_string_case_unstable;
520 }
521 } else {
522 if (reverse) {
523 return php_array_reverse_data_compare_string_unstable;
524 } else {
525 return php_array_data_compare_string_unstable;
526 }
527 }
528 break;
529
530 case PHP_SORT_NATURAL:
531 if (sort_type & PHP_SORT_FLAG_CASE) {
532 if (reverse) {
533 return php_array_reverse_natural_case_compare_unstable;
534 } else {
535 return php_array_natural_case_compare_unstable;
536 }
537 } else {
538 if (reverse) {
539 return php_array_reverse_natural_compare_unstable;
540 } else {
541 return php_array_natural_compare_unstable;
542 }
543 }
544 break;
545
547 if (reverse) {
548 return php_array_reverse_data_compare_string_locale_unstable;
549 } else {
550 return php_array_data_compare_string_locale_unstable;
551 }
552 break;
553
554 case PHP_SORT_REGULAR:
555 default:
556 if (reverse) {
557 return php_array_reverse_data_compare_unstable;
558 } else {
559 return php_array_data_compare_unstable;
560 }
561 break;
562 }
563 return NULL;
564}
565/* }}} */
566
567/* {{{ Sort an array by key value in reverse order */
569{
570 zval *array;
571 zend_long sort_type = PHP_SORT_REGULAR;
573
575 Z_PARAM_ARRAY_EX(array, 0, 1)
577 Z_PARAM_LONG(sort_type)
579
580 cmp = php_get_key_compare_func(sort_type, 1);
581
582 zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
583
585}
586/* }}} */
587
588/* {{{ Sort an array by key */
590{
591 zval *array;
592 zend_long sort_type = PHP_SORT_REGULAR;
594
596 Z_PARAM_ARRAY_EX(array, 0, 1)
598 Z_PARAM_LONG(sort_type)
600
601 cmp = php_get_key_compare_func(sort_type, 0);
602
603 zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
604
606}
607/* }}} */
608
610{
611 zend_long cnt = 0;
612 zval *element;
613
614 if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
615 if (GC_IS_RECURSIVE(ht)) {
616 php_error_docref(NULL, E_WARNING, "Recursion detected");
617 return 0;
618 }
620 }
621
622 cnt = zend_hash_num_elements(ht);
623 ZEND_HASH_FOREACH_VAL(ht, element) {
624 ZVAL_DEREF(element);
625 if (Z_TYPE_P(element) == IS_ARRAY) {
626 cnt += php_count_recursive(Z_ARRVAL_P(element));
627 }
629
631 return cnt;
632}
633/* }}} */
634
635/* {{{ Count the number of elements in a variable (usually an array) */
637{
638 zval *array;
640 zend_long cnt;
641
643 Z_PARAM_ZVAL(array)
647
649 zend_argument_value_error(2, "must be either COUNT_NORMAL or COUNT_RECURSIVE");
651 }
652
653 switch (Z_TYPE_P(array)) {
654 case IS_ARRAY:
655 if (mode != PHP_COUNT_RECURSIVE) {
656 cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
657 } else {
658 cnt = php_count_recursive(Z_ARRVAL_P(array));
659 }
660 RETURN_LONG(cnt);
661 break;
662 case IS_OBJECT: {
663 zval retval;
664 /* first, we check if the handler is defined */
665 zend_object *zobj = Z_OBJ_P(array);
666 if (zobj->handlers->count_elements) {
667 RETVAL_LONG(1);
668 if (SUCCESS == zobj->handlers->count_elements(zobj, &Z_LVAL_P(return_value))) {
669 return;
670 }
671 if (EG(exception)) {
673 }
674 }
675 /* if not and the object implements Countable we call its count() method */
676 if (instanceof_function(zobj->ce, zend_ce_countable)) {
677 zend_function *count_fn = zend_hash_find_ptr(&zobj->ce->function_table, ZSTR_KNOWN(ZEND_STR_COUNT));
678 zend_call_known_instance_method_with_0_params(count_fn, zobj, &retval);
679 if (Z_TYPE(retval) != IS_UNDEF) {
680 RETVAL_LONG(zval_get_long(&retval));
682 }
683 return;
684 }
685 }
687 default:
688 zend_argument_type_error(1, "must be of type Countable|array, %s given", zend_zval_value_name(array));
690 }
691}
692/* }}} */
693
694static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
695{
696 zval *array;
697
699 Z_PARAM_ARRAY_EX(array, 0, 1)
701
702 if (fold_case) {
703 zend_array_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0);
704 } else {
705 zend_array_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0);
706 }
707
709}
710/* }}} */
711
712/* {{{ Sort an array using natural sort */
717/* }}} */
718
719/* {{{ Sort an array using case-insensitive natural sort */
724/* }}} */
725
726/* {{{ Sort an array and maintain index association */
728{
729 zval *array;
730 zend_long sort_type = PHP_SORT_REGULAR;
732
734 Z_PARAM_ARRAY_EX(array, 0, 1)
736 Z_PARAM_LONG(sort_type)
738
739 cmp = php_get_data_compare_func(sort_type, 0);
740
741 zend_array_sort(Z_ARRVAL_P(array), cmp, 0);
742
744}
745/* }}} */
746
747/* {{{ Sort an array in reverse order and maintain index association */
749{
750 zval *array;
751 zend_long sort_type = PHP_SORT_REGULAR;
753
755 Z_PARAM_ARRAY_EX(array, 0, 1)
757 Z_PARAM_LONG(sort_type)
759
760 cmp = php_get_data_compare_func(sort_type, 1);
761
762 zend_array_sort(Z_ARRVAL_P(array), cmp, 0);
763
765}
766/* }}} */
767
768/* {{{ Sort an array */
770{
771 zval *array;
772 zend_long sort_type = PHP_SORT_REGULAR;
774
776 Z_PARAM_ARRAY_EX(array, 0, 1)
778 Z_PARAM_LONG(sort_type)
780
781 cmp = php_get_data_compare_func(sort_type, 0);
782
783 zend_array_sort(Z_ARRVAL_P(array), cmp, 1);
784
786}
787/* }}} */
788
789/* {{{ Sort an array in reverse order */
791{
792 zval *array;
793 zend_long sort_type = PHP_SORT_REGULAR;
795
797 Z_PARAM_ARRAY_EX(array, 0, 1)
799 Z_PARAM_LONG(sort_type)
801
802 cmp = php_get_data_compare_func(sort_type, 1);
803
804 zend_array_sort(Z_ARRVAL_P(array), cmp, 1);
805
807}
808/* }}} */
809
810static inline int php_array_user_compare_unstable(Bucket *f, Bucket *s) /* {{{ */
811{
812 zval args[2];
813 zval retval;
814 bool call_failed;
815
816 ZVAL_COPY(&args[0], &f->val);
817 ZVAL_COPY(&args[1], &s->val);
818
819 BG(user_compare_fci).param_count = 2;
820 BG(user_compare_fci).params = args;
821 BG(user_compare_fci).retval = &retval;
822 call_failed = zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE || Z_TYPE(retval) == IS_UNDEF;
823 zval_ptr_dtor(&args[1]);
824 zval_ptr_dtor(&args[0]);
825 if (UNEXPECTED(call_failed)) {
826 return 0;
827 }
828
832 "Returning bool from comparison function is deprecated, "
833 "return an integer less than, equal to, or greater than zero");
835 }
836
837 if (Z_TYPE(retval) == IS_FALSE) {
838 /* Retry with swapped operands. */
839 ZVAL_COPY(&args[0], &s->val);
840 ZVAL_COPY(&args[1], &f->val);
841 call_failed = zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE || Z_TYPE(retval) == IS_UNDEF;
842 zval_ptr_dtor(&args[1]);
843 zval_ptr_dtor(&args[0]);
844 if (call_failed) {
845 return 0;
846 }
847
848 zend_long ret = zval_get_long(&retval);
850 return -ZEND_NORMALIZE_BOOL(ret);
851 }
852 }
853
854 zend_long ret = zval_get_long(&retval);
856 return ZEND_NORMALIZE_BOOL(ret);
857}
858/* }}} */
859
860static int php_array_user_compare(Bucket *a, Bucket *b) /* {{{ */
861{
862 RETURN_STABLE_SORT(a, b, php_array_user_compare_unstable(a, b));
863}
864/* }}} */
865
866#define PHP_ARRAY_CMP_FUNC_VARS \
867 zend_fcall_info old_user_compare_fci; \
868 zend_fcall_info_cache old_user_compare_fci_cache \
869
870#define PHP_ARRAY_CMP_FUNC_BACKUP() \
871 old_user_compare_fci = BG(user_compare_fci); \
872 old_user_compare_fci_cache = BG(user_compare_fci_cache); \
873 ARRAYG(compare_deprecation_thrown) = 0; \
874 BG(user_compare_fci_cache) = empty_fcall_info_cache; \
875
876#define PHP_ARRAY_CMP_FUNC_RESTORE() \
877 BG(user_compare_fci) = old_user_compare_fci; \
878 BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
879
880static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compare_func, bool renumber) /* {{{ */
881{
882 zval *array;
883 zend_array *arr;
885
887
889 Z_PARAM_ARRAY_EX2(array, 0, 1, 0)
890 Z_PARAM_FUNC(BG(user_compare_fci), BG(user_compare_fci_cache))
892
893 arr = Z_ARR_P(array);
894 if (zend_hash_num_elements(arr) == 0) {
897 }
898
899 /* Copy array, so the in-place modifications will not be visible to the callback function */
900 arr = zend_array_dup(arr);
901
902 zend_array_sort(arr, compare_func, renumber);
903
905 ZVAL_COPY_VALUE(&garbage, array);
906 ZVAL_ARR(array, arr);
908
911}
912/* }}} */
913
914/* {{{ Sort an array by values using a user-defined comparison function */
916{
917 php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 1);
918}
919/* }}} */
920
921/* {{{ Sort an array with a user-defined comparison function and maintain index association */
923{
924 php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 0);
925}
926/* }}} */
927
928static inline int php_array_user_key_compare_unstable(Bucket *f, Bucket *s) /* {{{ */
929{
930 zval args[2];
931 zval retval;
932 bool call_failed;
933
934 if (f->key == NULL) {
935 ZVAL_LONG(&args[0], f->h);
936 } else {
937 ZVAL_STR_COPY(&args[0], f->key);
938 }
939 if (s->key == NULL) {
940 ZVAL_LONG(&args[1], s->h);
941 } else {
942 ZVAL_STR_COPY(&args[1], s->key);
943 }
944
945 BG(user_compare_fci).param_count = 2;
946 BG(user_compare_fci).params = args;
947 BG(user_compare_fci).retval = &retval;
948 call_failed = zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE || Z_TYPE(retval) == IS_UNDEF;
949 zval_ptr_dtor(&args[1]);
950 zval_ptr_dtor(&args[0]);
951 if (UNEXPECTED(call_failed)) {
952 return 0;
953 }
954
958 "Returning bool from comparison function is deprecated, "
959 "return an integer less than, equal to, or greater than zero");
961 }
962
963 if (Z_TYPE(retval) == IS_FALSE) {
964 /* Retry with swapped operands. */
965 if (s->key == NULL) {
966 ZVAL_LONG(&args[0], s->h);
967 } else {
968 ZVAL_STR_COPY(&args[0], s->key);
969 }
970 if (f->key == NULL) {
971 ZVAL_LONG(&args[1], f->h);
972 } else {
973 ZVAL_STR_COPY(&args[1], f->key);
974 }
975
976 call_failed = zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE || Z_TYPE(retval) == IS_UNDEF;
977 zval_ptr_dtor(&args[1]);
978 zval_ptr_dtor(&args[0]);
979 if (call_failed) {
980 return 0;
981 }
982
983 zend_long ret = zval_get_long(&retval);
985 return -ZEND_NORMALIZE_BOOL(ret);
986 }
987 }
988
989 zend_long result = zval_get_long(&retval);
992}
993/* }}} */
994
995static int php_array_user_key_compare(Bucket *a, Bucket *b) /* {{{ */
996{
997 RETURN_STABLE_SORT(a, b, php_array_user_key_compare_unstable(a, b));
998}
999/* }}} */
1000
1001/* {{{ Sort an array by keys using a user-defined comparison function */
1003{
1004 php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, 0);
1005}
1006/* }}} */
1007
1008static inline HashTable *get_ht_for_iap(zval *zv, bool separate) {
1009 if (EXPECTED(Z_TYPE_P(zv) == IS_ARRAY)) {
1010 return Z_ARRVAL_P(zv);
1011 }
1012
1015 "Calling %s() on an object is deprecated", get_active_function_name());
1016
1018 if (separate && zobj->properties && UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
1019 if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
1020 GC_DELREF(zobj->properties);
1021 }
1022 zobj->properties = zend_array_dup(zobj->properties);
1023 }
1024 return zobj->handlers->get_properties(zobj);
1025}
1026
1027static zval *php_array_iter_seek_current(HashTable *array, bool forward_direction)
1028{
1029 zval *entry;
1030
1031 while (true) {
1032 if ((entry = zend_hash_get_current_data(array)) == NULL) {
1033 return NULL;
1034 }
1035
1036 ZVAL_DEINDIRECT(entry);
1037
1038 /* Possible with an uninitialized typed property */
1039 if (UNEXPECTED(Z_TYPE_P(entry) == IS_UNDEF)) {
1041 if (forward_direction) {
1042 result = zend_hash_move_forward(array);
1043 } else {
1044 result = zend_hash_move_backwards(array);
1045 }
1046 if (result != SUCCESS) {
1047 return NULL;
1048 }
1049 } else {
1050 break;
1051 }
1052 }
1053
1054 return entry;
1055}
1056
1057static void php_array_iter_return_current(zval *return_value, HashTable *array, bool forward_direction)
1058{
1059 zval *entry = php_array_iter_seek_current(array, forward_direction);
1060 if (EXPECTED(entry)) {
1061 RETURN_COPY_DEREF(entry);
1062 } else {
1064 }
1065}
1066
1067/* {{{ Advances array argument's internal pointer to the last element and return it */
1069{
1070 zval *array_zv;
1071
1073 Z_PARAM_ARRAY_OR_OBJECT_EX(array_zv, 0, 1)
1075
1076 HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
1077 if (zend_hash_num_elements(array) == 0) {
1078 /* array->nInternalPointer is already 0 if the array is empty, even after removing elements */
1080 }
1081 zend_hash_internal_pointer_end(array);
1082
1083 if (USED_RET()) {
1084 php_array_iter_return_current(return_value, array, false);
1085 }
1086}
1087/* }}} */
1088
1089/* {{{ Move array argument's internal pointer to the previous element and return it */
1091{
1092 zval *array_zv;
1093
1095 Z_PARAM_ARRAY_OR_OBJECT_EX(array_zv, 0, 1)
1097
1098 HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
1099 if (zend_hash_num_elements(array) == 0) {
1100 /* array->nInternalPointer is already 0 if the array is empty, even after removing elements */
1102 }
1103 zend_hash_move_backwards(array);
1104
1105 if (USED_RET()) {
1106 php_array_iter_return_current(return_value, array, false);
1107 }
1108}
1109/* }}} */
1110
1111/* {{{ Move array argument's internal pointer to the next element and return it */
1113{
1114 zval *array_zv;
1115
1117 Z_PARAM_ARRAY_OR_OBJECT_EX(array_zv, 0, 1)
1119
1120 HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
1121 if (zend_hash_num_elements(array) == 0) {
1122 /* array->nInternalPointer is already 0 if the array is empty, even after removing elements */
1124 }
1125 zend_hash_move_forward(array);
1126
1127 if (USED_RET()) {
1128 php_array_iter_return_current(return_value, array, true);
1129 }
1130}
1131/* }}} */
1132
1133/* {{{ Set array argument's internal pointer to the first element and return it */
1135{
1136 zval *array_zv;
1137
1139 Z_PARAM_ARRAY_OR_OBJECT_EX(array_zv, 0, 1)
1141
1142 HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
1143 if (zend_hash_num_elements(array) == 0) {
1144 /* array->nInternalPointer is already 0 if the array is empty, even after removing elements */
1146 }
1147 zend_hash_internal_pointer_reset(array);
1148
1149 if (USED_RET()) {
1150 php_array_iter_return_current(return_value, array, true);
1151 }
1152}
1153/* }}} */
1154
1155/* {{{ Return the element currently pointed to by the internal array pointer */
1157{
1158 zval *array_zv;
1159
1161 Z_PARAM_ARRAY_OR_OBJECT(array_zv)
1163
1164 HashTable *array = get_ht_for_iap(array_zv, /* separate */ false);
1165 php_array_iter_return_current(return_value, array, true);
1166}
1167/* }}} */
1168
1169/* {{{ Return the key of the element currently pointed to by the internal array pointer */
1171{
1172 zval *array_zv;
1173
1175 Z_PARAM_ARRAY_OR_OBJECT(array_zv)
1177
1178 HashTable *array = get_ht_for_iap(array_zv, /* separate */ false);
1179 zval *entry = php_array_iter_seek_current(array, true);
1180 if (EXPECTED(entry)) {
1181 zend_hash_get_current_key_zval(array, return_value);
1182 }
1183}
1184/* }}} */
1185
1186static int php_data_compare(const void *f, const void *s) /* {{{ */
1187{
1188 return zend_compare((zval*)f, (zval*)s);
1189}
1190/* }}} */
1191
1192/* {{{
1193 * proto mixed min(array values)
1194 * proto mixed min(mixed arg1 [, mixed arg2 [, mixed ...]])
1195 Return the lowest value in an array or a series of arguments */
1197{
1198 uint32_t argc;
1199 zval *args = NULL;
1200
1202 Z_PARAM_VARIADIC('+', args, argc)
1204
1205 /* mixed min ( array $values ) */
1206 if (argc == 1) {
1207 if (Z_TYPE(args[0]) != IS_ARRAY) {
1208 zend_argument_type_error(1, "must be of type array, %s given", zend_zval_value_name(&args[0]));
1209 RETURN_THROWS();
1210 } else {
1211 zval *result = zend_hash_minmax(Z_ARRVAL(args[0]), php_data_compare, 0);
1212 if (result) {
1214 } else {
1215 zend_argument_value_error(1, "must contain at least one element");
1216 RETURN_THROWS();
1217 }
1218 }
1219 } else {
1220 /* mixed min ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
1221 zval *min;
1222 uint32_t i;
1223
1224 min = &args[0];
1225 zend_long min_lval;
1226 double min_dval;
1227
1228 if (Z_TYPE_P(min) == IS_LONG) {
1229 min_lval = Z_LVAL_P(min);
1230
1231 for (i = 1; i < argc; i++) {
1232 if (EXPECTED(Z_TYPE(args[i]) == IS_LONG)) {
1233 if (min_lval > Z_LVAL(args[i])) {
1234 min_lval = Z_LVAL(args[i]);
1235 min = &args[i];
1236 }
1237 } else if (Z_TYPE(args[i]) == IS_DOUBLE && (zend_dval_to_lval((double) min_lval) == min_lval)) {
1238 /* if min_lval can be exactly represented as a double, go to double dedicated code */
1239 min_dval = (double) min_lval;
1240 goto double_compare;
1241 } else {
1242 goto generic_compare;
1243 }
1244 }
1245
1246 RETURN_LONG(min_lval);
1247 } else if (Z_TYPE_P(min) == IS_DOUBLE) {
1248 min_dval = Z_DVAL_P(min);
1249
1250 for (i = 1; i < argc; i++) {
1251 if (EXPECTED(Z_TYPE(args[i]) == IS_DOUBLE)) {
1252 double_compare:
1253 if (min_dval > Z_DVAL(args[i])) {
1254 min_dval = Z_DVAL(args[i]);
1255 min = &args[i];
1256 }
1257 } else if (Z_TYPE(args[i]) == IS_LONG && (zend_dval_to_lval((double) Z_LVAL(args[i])) == Z_LVAL(args[i]))) {
1258 /* if the value can be exactly represented as a double, use double dedicated code otherwise generic */
1259 if (min_dval > (double)Z_LVAL(args[i])) {
1260 min_dval = (double)Z_LVAL(args[i]);
1261 min = &args[i];
1262 }
1263 } else {
1264 goto generic_compare;
1265 }
1266 }
1267 } else {
1268 for (i = 1; i < argc; i++) {
1269 generic_compare:
1270 if (zend_compare(&args[i], min) < 0) {
1271 min = &args[i];
1272 }
1273 }
1274 }
1275
1277 }
1278}
1279/* }}} */
1280
1282{
1283 zval *lhs, *rhs;
1284
1285 Z_FLF_PARAM_ZVAL(1, lhs);
1286 Z_FLF_PARAM_ZVAL(2, rhs);
1287
1288 double lhs_dval;
1289
1290 if (Z_TYPE_P(lhs) == IS_LONG) {
1291 zend_long lhs_lval = Z_LVAL_P(lhs);
1292
1293 if (EXPECTED(Z_TYPE_P(rhs) == IS_LONG)) {
1294 RETURN_COPY_VALUE(lhs_lval < Z_LVAL_P(rhs) ? lhs : rhs);
1295 } else if (Z_TYPE_P(rhs) == IS_DOUBLE && (zend_dval_to_lval((double) lhs_lval) == lhs_lval)) {
1296 /* if lhs_lval can be exactly represented as a double, go to double dedicated code */
1297 lhs_dval = (double) lhs_lval;
1298 goto double_compare;
1299 } else {
1300 goto generic_compare;
1301 }
1302 } else if (Z_TYPE_P(lhs) == IS_DOUBLE) {
1303 lhs_dval = Z_DVAL_P(lhs);
1304
1305 if (EXPECTED(Z_TYPE_P(rhs) == IS_DOUBLE)) {
1306double_compare:
1307 RETURN_COPY_VALUE(lhs_dval < Z_DVAL_P(rhs) ? lhs : rhs);
1308 } else if (Z_TYPE_P(rhs) == IS_LONG && (zend_dval_to_lval((double) Z_LVAL_P(rhs)) == Z_LVAL_P(rhs))) {
1309 /* if the value can be exactly represented as a double, use double dedicated code otherwise generic */
1310 RETURN_COPY_VALUE(lhs_dval < (double)Z_LVAL_P(rhs) ? lhs : rhs);
1311 } else {
1312 goto generic_compare;
1313 }
1314 } else {
1315generic_compare:
1316 RETURN_COPY(zend_compare(lhs, rhs) < 0 ? lhs : rhs);
1317 }
1318}
1319
1320/* {{{
1321 * proto mixed max(array values)
1322 * proto mixed max(mixed arg1 [, mixed arg2 [, mixed ...]])
1323 Return the highest value in an array or a series of arguments */
1325{
1326 zval *args = NULL;
1327 uint32_t argc;
1328
1330 Z_PARAM_VARIADIC('+', args, argc)
1332
1333 /* mixed max ( array $values ) */
1334 if (argc == 1) {
1335 if (Z_TYPE(args[0]) != IS_ARRAY) {
1336 zend_argument_type_error(1, "must be of type array, %s given", zend_zval_value_name(&args[0]));
1337 RETURN_THROWS();
1338 } else {
1339 zval *result = zend_hash_minmax(Z_ARRVAL(args[0]), php_data_compare, 1);
1340 if (result) {
1342 } else {
1343 zend_argument_value_error(1, "must contain at least one element");
1344 RETURN_THROWS();
1345 }
1346 }
1347 } else {
1348 /* mixed max ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
1349 zval *max;
1350 uint32_t i;
1351
1352 max = &args[0];
1353 zend_long max_lval;
1354 double max_dval;
1355
1356 if (Z_TYPE_P(max) == IS_LONG) {
1357 max_lval = Z_LVAL_P(max);
1358
1359 for (i = 1; i < argc; i++) {
1360 if (EXPECTED(Z_TYPE(args[i]) == IS_LONG)) {
1361 if (max_lval < Z_LVAL(args[i])) {
1362 max_lval = Z_LVAL(args[i]);
1363 max = &args[i];
1364 }
1365 } else if (Z_TYPE(args[i]) == IS_DOUBLE && (zend_dval_to_lval((double) max_lval) == max_lval)) {
1366 /* if max_lval can be exactly represented as a double, go to double dedicated code */
1367 max_dval = (double) max_lval;
1368 goto double_compare;
1369 } else {
1370 goto generic_compare;
1371 }
1372 }
1373
1374 RETURN_LONG(max_lval);
1375 } else if (Z_TYPE_P(max) == IS_DOUBLE) {
1376 max_dval = Z_DVAL_P(max);
1377
1378 for (i = 1; i < argc; i++) {
1379 if (EXPECTED(Z_TYPE(args[i]) == IS_DOUBLE)) {
1380 double_compare:
1381 if (max_dval < Z_DVAL(args[i])) {
1382 max_dval = Z_DVAL(args[i]);
1383 max = &args[i];
1384 }
1385 } else if (Z_TYPE(args[i]) == IS_LONG && (zend_dval_to_lval((double) Z_LVAL(args[i])) == Z_LVAL(args[i]))) {
1386 /* if the value can be exactly represented as a double, use double dedicated code otherwise generic */
1387 if (max_dval < (double)Z_LVAL(args[i])) {
1388 max_dval = (double)Z_LVAL(args[i]);
1389 max = &args[i];
1390 }
1391 } else {
1392 goto generic_compare;
1393 }
1394 }
1395 } else {
1396 for (i = 1; i < argc; i++) {
1397 generic_compare:
1398 if (zend_compare(&args[i], max) > 0) {
1399 max = &args[i];
1400 }
1401 }
1402 }
1403
1405 }
1406}
1407/* }}} */
1408
1410{
1411 zval *lhs, *rhs;
1412
1413 Z_FLF_PARAM_ZVAL(1, lhs);
1414 Z_FLF_PARAM_ZVAL(2, rhs);
1415
1416 double lhs_dval;
1417
1418 if (Z_TYPE_P(lhs) == IS_LONG) {
1419 zend_long lhs_lval = Z_LVAL_P(lhs);
1420
1421 if (EXPECTED(Z_TYPE_P(rhs) == IS_LONG)) {
1422 RETURN_COPY_VALUE(lhs_lval >= Z_LVAL_P(rhs) ? lhs : rhs);
1423 } else if (Z_TYPE_P(rhs) == IS_DOUBLE && (zend_dval_to_lval((double) lhs_lval) == lhs_lval)) {
1424 /* if lhs_lval can be exactly represented as a double, go to double dedicated code */
1425 lhs_dval = (double) lhs_lval;
1426 goto double_compare;
1427 } else {
1428 goto generic_compare;
1429 }
1430 } else if (Z_TYPE_P(lhs) == IS_DOUBLE) {
1431 lhs_dval = Z_DVAL_P(lhs);
1432
1433 if (EXPECTED(Z_TYPE_P(rhs) == IS_DOUBLE)) {
1434double_compare:
1435 RETURN_COPY_VALUE(lhs_dval >= Z_DVAL_P(rhs) ? lhs : rhs);
1436 } else if (Z_TYPE_P(rhs) == IS_LONG && (zend_dval_to_lval((double) Z_LVAL_P(rhs)) == Z_LVAL_P(rhs))) {
1437 /* if the value can be exactly represented as a double, use double dedicated code otherwise generic */
1438 RETURN_COPY_VALUE(lhs_dval >= (double)Z_LVAL_P(rhs) ? lhs : rhs);
1439 } else {
1440 goto generic_compare;
1441 }
1442 } else {
1443generic_compare:
1444 RETURN_COPY(zend_compare(lhs, rhs) >= 0 ? lhs : rhs);
1445 }
1446}
1447
1452
1453static zend_result php_array_walk(
1454 php_array_walk_context *context, zval *array, zval *userdata, bool recursive)
1455{
1456 zval args[3], /* Arguments to userland function */
1457 retval, /* Return value - unused */
1458 *zv;
1459 HashTable *target_hash = HASH_OF(array);
1461 uint32_t ht_iter;
1463
1464 /* Create a local copy of fci, as we want to use different arguments at different
1465 * levels of recursion. */
1466 zend_fcall_info fci = context->fci;
1467
1468 if (zend_hash_num_elements(target_hash) == 0) {
1469 return result;
1470 }
1471
1472 /* Set up known arguments */
1473 ZVAL_UNDEF(&args[1]);
1474 if (userdata) {
1475 ZVAL_COPY(&args[2], userdata);
1476 }
1477
1478 fci.retval = &retval;
1479 fci.param_count = userdata ? 3 : 2;
1480 fci.params = args;
1481
1483 ht_iter = zend_hash_iterator_add(target_hash, pos);
1484
1485 /* Iterate through hash */
1486 do {
1487 /* Retrieve value */
1488 zv = zend_hash_get_current_data_ex(target_hash, &pos);
1489 if (zv == NULL) {
1490 break;
1491 }
1492
1493 /* Skip undefined indirect elements */
1494 if (Z_TYPE_P(zv) == IS_INDIRECT) {
1495 zv = Z_INDIRECT_P(zv);
1496 if (Z_TYPE_P(zv) == IS_UNDEF) {
1497 zend_hash_move_forward_ex(target_hash, &pos);
1498 continue;
1499 }
1500
1501 /* Add type source for property references. */
1502 if (Z_TYPE_P(zv) != IS_REFERENCE && Z_TYPE_P(array) == IS_OBJECT) {
1504 zend_get_typed_property_info_for_slot(Z_OBJ_P(array), zv);
1505 if (prop_info) {
1506 ZVAL_NEW_REF(zv, zv);
1508 }
1509 }
1510 }
1511
1512 /* Ensure the value is a reference. Otherwise the location of the value may be freed. */
1514
1515 /* Retrieve key */
1516 zend_hash_get_current_key_zval_ex(target_hash, &args[1], &pos);
1517
1518 /* Move to next element already now -- this mirrors the approach used by foreach
1519 * and ensures proper behavior with regard to modifications. */
1520 zend_hash_move_forward_ex(target_hash, &pos);
1521
1522 /* Back up hash position, as it may change */
1523 EG(ht_iterators)[ht_iter].pos = pos;
1524
1525 if (recursive && Z_TYPE_P(Z_REFVAL_P(zv)) == IS_ARRAY) {
1526 HashTable *thash;
1527 zval ref;
1528 ZVAL_COPY_VALUE(&ref, zv);
1529
1530 ZVAL_DEREF(zv);
1532 thash = Z_ARRVAL_P(zv);
1533 if (GC_IS_RECURSIVE(thash)) {
1534 zend_throw_error(NULL, "Recursion detected");
1535 result = FAILURE;
1536 break;
1537 }
1538
1539 Z_ADDREF(ref);
1540 GC_PROTECT_RECURSION(thash);
1541 result = php_array_walk(context, zv, userdata, recursive);
1542 if (Z_TYPE_P(Z_REFVAL(ref)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL(ref))) {
1543 /* If the hashtable changed in the meantime, we'll "leak" this apply count
1544 * increment -- our reference to thash is no longer valid. */
1546 }
1547 zval_ptr_dtor(&ref);
1548 } else {
1549 ZVAL_COPY(&args[0], zv);
1550
1551 /* Call the userland function */
1552 result = zend_call_function(&fci, &context->fci_cache);
1553 if (result == SUCCESS) {
1555 }
1556
1557 zval_ptr_dtor(&args[0]);
1558 }
1559
1560 if (Z_TYPE(args[1]) != IS_UNDEF) {
1561 zval_ptr_dtor(&args[1]);
1562 ZVAL_UNDEF(&args[1]);
1563 }
1564
1565 if (result == FAILURE) {
1566 break;
1567 }
1568
1569 /* Reload array and position -- both may have changed */
1570 if (Z_TYPE_P(array) == IS_ARRAY) {
1571 pos = zend_hash_iterator_pos_ex(ht_iter, array);
1572 target_hash = Z_ARRVAL_P(array);
1573 } else if (Z_TYPE_P(array) == IS_OBJECT) {
1574 target_hash = Z_OBJPROP_P(array);
1575 pos = zend_hash_iterator_pos(ht_iter, target_hash);
1576 } else {
1577 zend_type_error("Iterated value is no longer an array or object");
1578 result = FAILURE;
1579 break;
1580 }
1581 } while (!EG(exception));
1582
1583 if (userdata) {
1584 zval_ptr_dtor(&args[2]);
1585 }
1586 zend_hash_iterator_del(ht_iter);
1587 return result;
1588}
1589
1590/* {{{ Apply a user function to every member of an array */
1592{
1593 zval *array;
1594 zval *userdata = NULL;
1596
1598 Z_PARAM_ARRAY_OR_OBJECT_EX(array, 0, 1)
1599 Z_PARAM_FUNC(context.fci, context.fci_cache)
1601 Z_PARAM_ZVAL(userdata)
1603
1604 php_array_walk(&context, array, userdata, /* recursive */ false);
1606}
1607/* }}} */
1608
1609/* {{{ Apply a user function recursively to every member of an array */
1611{
1612 zval *array;
1613 zval *userdata = NULL;
1615
1617 Z_PARAM_ARRAY_OR_OBJECT_EX(array, 0, 1)
1618 Z_PARAM_FUNC(context.fci, context.fci_cache)
1620 Z_PARAM_ZVAL(userdata)
1622
1623 php_array_walk(&context, array, userdata, /* recursive */ true);
1625}
1626/* }}} */
1627
1628/* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
1629 * 0 = return boolean
1630 * 1 = return key
1631 */
1632static inline void _php_search_array(zval *return_value, zval *value, zval *array, bool strict, int behavior) /* {{{ */
1633{
1634 zval *entry; /* pointer to array entry */
1635 zend_ulong num_idx;
1636 zend_string *str_idx;
1637
1638 if (strict) {
1639 if (Z_TYPE_P(value) == IS_LONG) {
1640 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1641 ZVAL_DEREF(entry);
1642 if (Z_TYPE_P(entry) == IS_LONG && Z_LVAL_P(entry) == Z_LVAL_P(value)) {
1643 if (behavior == 0) {
1645 } else {
1646 if (str_idx) {
1647 RETURN_STR_COPY(str_idx);
1648 } else {
1649 RETURN_LONG(num_idx);
1650 }
1651 }
1652 }
1654 } else {
1655 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1656 ZVAL_DEREF(entry);
1657 if (fast_is_identical_function(value, entry)) {
1658 if (behavior == 0) {
1660 } else {
1661 if (str_idx) {
1662 RETURN_STR_COPY(str_idx);
1663 } else {
1664 RETURN_LONG(num_idx);
1665 }
1666 }
1667 }
1669 }
1670 } else {
1671 if (Z_TYPE_P(value) == IS_LONG) {
1672 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1673 if (fast_equal_check_long(value, entry)) {
1674 if (behavior == 0) {
1676 } else {
1677 if (str_idx) {
1678 RETURN_STR_COPY(str_idx);
1679 } else {
1680 RETURN_LONG(num_idx);
1681 }
1682 }
1683 }
1685 } else if (Z_TYPE_P(value) == IS_STRING) {
1686 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1687 if (fast_equal_check_string(value, entry)) {
1688 if (behavior == 0) {
1690 } else {
1691 if (str_idx) {
1692 RETURN_STR_COPY(str_idx);
1693 } else {
1694 RETURN_LONG(num_idx);
1695 }
1696 }
1697 }
1699 } else {
1700 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
1701 if (fast_equal_check_function(value, entry)) {
1702 if (behavior == 0) {
1704 } else {
1705 if (str_idx) {
1706 RETURN_STR_COPY(str_idx);
1707 } else {
1708 RETURN_LONG(num_idx);
1709 }
1710 }
1711 }
1713 }
1714 }
1715
1717}
1718/* }}} */
1719
1720/* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
1721 * 0 = return boolean
1722 * 1 = return key
1723 */
1724static inline void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
1725{
1726 zval *value, /* value to check for */
1727 *array; /* array to check in */
1728 bool strict = 0; /* strict comparison or not */
1729
1732 Z_PARAM_ARRAY(array)
1734 Z_PARAM_BOOL(strict)
1736
1737 _php_search_array(return_value, value, array, strict, behavior);
1738}
1739
1740/* {{{ Checks if the given value exists in the array */
1742{
1743 php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1744}
1745/* }}} */
1746
1748{
1749 zval *value, *array;
1750
1752 Z_FLF_PARAM_ARRAY(2, array);
1753
1754 _php_search_array(return_value, value, array, false, 0);
1755
1756flf_clean:;
1757}
1758
1760{
1761 zval *value, *array;
1762 bool strict;
1763
1765 Z_FLF_PARAM_ARRAY(2, array);
1766 Z_FLF_PARAM_BOOL(3, strict);
1767
1768 _php_search_array(return_value, value, array, strict, 0);
1769
1770flf_clean:;
1771}
1772
1773/* {{{ Searches the array for a given value and returns the corresponding key if successful */
1775{
1776 php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1777}
1778/* }}} */
1779
1780static zend_always_inline int php_valid_var_name(const char *var_name, size_t var_name_len) /* {{{ */
1781{
1782#if 1
1783 /* first 256 bits for first character, and second 256 bits for the next */
1784 static const uint32_t charset[8] = {
1785 /* 31 0 63 32 95 64 127 96 */
1786 0x00000000, 0x00000000, 0x87fffffe, 0x07fffffe,
1787 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
1788 static const uint32_t charset2[8] = {
1789 /* 31 0 63 32 95 64 127 96 */
1790 0x00000000, 0x03ff0000, 0x87fffffe, 0x07fffffe,
1791 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
1792#endif
1793 size_t i;
1794 uint32_t ch;
1795
1796 if (UNEXPECTED(!var_name_len)) {
1797 return 0;
1798 }
1799
1800 /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
1801 ch = (uint32_t)((unsigned char *)var_name)[0];
1802#if 1
1804#else
1805 if (var_name[0] != '_' &&
1809 ) {
1810#endif
1811 return 0;
1812 }
1813
1814 /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
1815 if (var_name_len > 1) {
1816 i = 1;
1817 do {
1818 ch = (uint32_t)((unsigned char *)var_name)[i];
1819#if 1
1820 if (UNEXPECTED(!ZEND_BIT_TEST(charset2, ch))) {
1821#else
1822 if (var_name[i] != '_' &&
1827 ) {
1828#endif
1829 return 0;
1830 }
1831 } while (++i < var_name_len);
1832 }
1833 return 1;
1834}
1835/* }}} */
1836
1837PHPAPI int php_prefix_varname(zval *result, zend_string *prefix, const char *var_name, size_t var_name_len, bool add_underscore) /* {{{ */
1838{
1839 ZVAL_NEW_STR(result, zend_string_alloc(ZSTR_LEN(prefix) + (add_underscore ? 1 : 0) + var_name_len, 0));
1841
1842 if (add_underscore) {
1844 }
1845
1846 memcpy(Z_STRVAL_P(result) + ZSTR_LEN(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1);
1847
1848 return SUCCESS;
1849}
1850/* }}} */
1851
1852static zend_long php_extract_ref_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */
1853{
1854 zend_long count = 0;
1856 zval *entry, *orig_var;
1857
1858 if (HT_IS_PACKED(arr)) {
1859 return 0;
1860 }
1862 if (!var_name) {
1863 continue;
1864 }
1865 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
1866 if (orig_var) {
1867 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1868 orig_var = Z_INDIRECT_P(orig_var);
1869 if (Z_TYPE_P(orig_var) == IS_UNDEF) {
1870 continue;
1871 }
1872 }
1873 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
1874 continue;
1875 }
1876 if (zend_string_equals_literal(var_name, "GLOBALS")) {
1877 continue;
1878 }
1879 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
1880 zend_throw_error(NULL, "Cannot re-assign $this");
1881 return -1;
1882 }
1883 if (Z_ISREF_P(entry)) {
1884 Z_ADDREF_P(entry);
1885 } else {
1886 ZVAL_MAKE_REF_EX(entry, 2);
1887 }
1888 zval_ptr_dtor(orig_var);
1889 ZVAL_REF(orig_var, Z_REF_P(entry));
1890 count++;
1891 }
1893
1894 return count;
1895}
1896/* }}} */
1897
1898static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */
1899{
1900 zend_long count = 0;
1902 zval *entry, *orig_var;
1903
1904 if (HT_IS_PACKED(arr)) {
1905 return 0;
1906 }
1908 if (!var_name) {
1909 continue;
1910 }
1911 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
1912 if (orig_var) {
1913 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1914 orig_var = Z_INDIRECT_P(orig_var);
1915 if (Z_TYPE_P(orig_var) == IS_UNDEF) {
1916 continue;
1917 }
1918 }
1919 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
1920 continue;
1921 }
1922 if (zend_string_equals_literal(var_name, "GLOBALS")) {
1923 continue;
1924 }
1925 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
1926 zend_throw_error(NULL, "Cannot re-assign $this");
1927 return -1;
1928 }
1929 ZVAL_DEREF(entry);
1930 ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
1931 if (UNEXPECTED(EG(exception))) {
1932 return -1;
1933 }
1934 count++;
1935 }
1937
1938 return count;
1939}
1940/* }}} */
1941
1942static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */
1943{
1944 zend_long count = 0;
1946 zval *entry, *orig_var;
1947
1948 if (HT_IS_PACKED(arr)) {
1949 return 0;
1950 }
1952 if (!var_name) {
1953 continue;
1954 }
1955 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
1956 continue;
1957 }
1958 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
1959 zend_throw_error(NULL, "Cannot re-assign $this");
1960 return -1;
1961 }
1962 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
1963 if (orig_var) {
1964 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
1965 orig_var = Z_INDIRECT_P(orig_var);
1966 }
1967 if (zend_string_equals_literal(var_name, "GLOBALS")) {
1968 continue;
1969 }
1970 if (Z_ISREF_P(entry)) {
1971 Z_ADDREF_P(entry);
1972 } else {
1973 ZVAL_MAKE_REF_EX(entry, 2);
1974 }
1975 zval garbage;
1976 ZVAL_COPY_VALUE(&garbage, orig_var);
1977 ZVAL_REF(orig_var, Z_REF_P(entry));
1979 } else {
1980 if (Z_ISREF_P(entry)) {
1981 Z_ADDREF_P(entry);
1982 } else {
1983 ZVAL_MAKE_REF_EX(entry, 2);
1984 }
1985 zend_hash_add_new(symbol_table, var_name, entry);
1986 }
1987 count++;
1989
1990 return count;
1991}
1992/* }}} */
1993
1994static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */
1995{
1996 zend_long count = 0;
1998 zval *entry, *orig_var;
1999
2000 if (HT_IS_PACKED(arr)) {
2001 return 0;
2002 }
2004 if (!var_name) {
2005 continue;
2006 }
2007 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
2008 continue;
2009 }
2010 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
2011 zend_throw_error(NULL, "Cannot re-assign $this");
2012 return -1;
2013 }
2014 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
2015 if (orig_var) {
2016 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2017 orig_var = Z_INDIRECT_P(orig_var);
2018 }
2019 if (zend_string_equals_literal(var_name, "GLOBALS")) {
2020 continue;
2021 }
2022 ZVAL_DEREF(entry);
2023 ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
2024 if (UNEXPECTED(EG(exception))) {
2025 return -1;
2026 }
2027 } else {
2028 ZVAL_DEREF(entry);
2029 Z_TRY_ADDREF_P(entry);
2030 zend_hash_add_new(symbol_table, var_name, entry);
2031 }
2032 count++;
2034
2035 return count;
2036}
2037/* }}} */
2038
2039static zend_long php_extract_ref_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
2040{
2041 zend_long count = 0;
2043 zval *entry, *orig_var, final_name;
2044
2045 if (HT_IS_PACKED(arr)) {
2046 return 0;
2047 }
2049 if (!var_name) {
2050 continue;
2051 }
2052 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
2053 if (orig_var) {
2054 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2055 orig_var = Z_INDIRECT_P(orig_var);
2056 if (Z_TYPE_P(orig_var) == IS_UNDEF) {
2057 if (Z_ISREF_P(entry)) {
2058 Z_ADDREF_P(entry);
2059 } else {
2060 ZVAL_MAKE_REF_EX(entry, 2);
2061 }
2062 ZVAL_REF(orig_var, Z_REF_P(entry));
2063 count++;
2064 continue;
2065 }
2066 }
2068 if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2069 if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) {
2070 zend_throw_error(NULL, "Cannot re-assign $this");
2071 return -1;
2072 } else {
2073 if (Z_ISREF_P(entry)) {
2074 Z_ADDREF_P(entry);
2075 } else {
2076 ZVAL_MAKE_REF_EX(entry, 2);
2077 }
2078 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2079 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2080 orig_var = Z_INDIRECT_P(orig_var);
2081 }
2082 zval_ptr_dtor(orig_var);
2083 ZVAL_REF(orig_var, Z_REF_P(entry));
2084 } else {
2085 zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2086 }
2087 count++;
2088 }
2089 }
2090 zval_ptr_dtor_str(&final_name);
2091 }
2093
2094 return count;
2095}
2096/* }}} */
2097
2098static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
2099{
2100 zend_long count = 0;
2102 zval *entry, *orig_var, final_name;
2103
2104 if (HT_IS_PACKED(arr)) {
2105 return 0;
2106 }
2108 if (!var_name) {
2109 continue;
2110 }
2111 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
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 }
2122 if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2123 if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) {
2124 zend_throw_error(NULL, "Cannot re-assign $this");
2125 return -1;
2126 } else {
2127 ZVAL_DEREF(entry);
2128 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2129 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2130 orig_var = Z_INDIRECT_P(orig_var);
2131 }
2132 ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
2133 if (UNEXPECTED(EG(exception))) {
2134 zend_string_release_ex(Z_STR(final_name), 0);
2135 return -1;
2136 }
2137 } else {
2138 Z_TRY_ADDREF_P(entry);
2139 zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2140 }
2141 count++;
2142 }
2143 }
2144 zval_ptr_dtor_str(&final_name);
2145 }
2147
2148 return count;
2149}
2150/* }}} */
2151
2152static zend_long php_extract_ref_prefix_same(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
2153{
2154 zend_long count = 0;
2156 zval *entry, *orig_var, final_name;
2157
2158 if (HT_IS_PACKED(arr)) {
2159 return 0;
2160 }
2162 if (!var_name) {
2163 continue;
2164 }
2165 if (ZSTR_LEN(var_name) == 0) {
2166 continue;
2167 }
2168 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
2169 if (orig_var) {
2170 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2171 orig_var = Z_INDIRECT_P(orig_var);
2172 if (Z_TYPE_P(orig_var) == IS_UNDEF) {
2173 if (Z_ISREF_P(entry)) {
2174 Z_ADDREF_P(entry);
2175 } else {
2176 ZVAL_MAKE_REF_EX(entry, 2);
2177 }
2178 ZVAL_REF(orig_var, Z_REF_P(entry));
2179 count++;
2180 continue;
2181 }
2182 }
2183prefix:
2185 if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2186 if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) {
2187 zend_throw_error(NULL, "Cannot re-assign $this");
2188 return -1;
2189 } else {
2190 if (Z_ISREF_P(entry)) {
2191 Z_ADDREF_P(entry);
2192 } else {
2193 ZVAL_MAKE_REF_EX(entry, 2);
2194 }
2195 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2196 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2197 orig_var = Z_INDIRECT_P(orig_var);
2198 }
2199 zval_ptr_dtor(orig_var);
2200 ZVAL_REF(orig_var, Z_REF_P(entry));
2201 } else {
2202 zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2203 }
2204 count++;
2205 }
2206 }
2207 zval_ptr_dtor_str(&final_name);
2208 } else {
2209 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
2210 continue;
2211 }
2212 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
2213 goto prefix;
2214 }
2215 if (Z_ISREF_P(entry)) {
2216 Z_ADDREF_P(entry);
2217 } else {
2218 ZVAL_MAKE_REF_EX(entry, 2);
2219 }
2220 zend_hash_add_new(symbol_table, var_name, entry);
2221 count++;
2222 }
2224
2225 return count;
2226}
2227/* }}} */
2228
2229static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
2230{
2231 zend_long count = 0;
2233 zval *entry, *orig_var, final_name;
2234
2235 if (HT_IS_PACKED(arr)) {
2236 return 0;
2237 }
2239 if (!var_name) {
2240 continue;
2241 }
2242 if (ZSTR_LEN(var_name) == 0) {
2243 continue;
2244 }
2245 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
2246 if (orig_var) {
2247 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2248 orig_var = Z_INDIRECT_P(orig_var);
2249 if (Z_TYPE_P(orig_var) == IS_UNDEF) {
2250 ZVAL_COPY_DEREF(orig_var, entry);
2251 count++;
2252 continue;
2253 }
2254 }
2255prefix:
2257 if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2258 if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) {
2259 zend_throw_error(NULL, "Cannot re-assign $this");
2260 return -1;
2261 } else {
2262 ZVAL_DEREF(entry);
2263 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2264 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2265 orig_var = Z_INDIRECT_P(orig_var);
2266 }
2267 ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
2268 if (UNEXPECTED(EG(exception))) {
2269 zend_string_release_ex(Z_STR(final_name), 0);
2270 return -1;
2271 }
2272 } else {
2273 Z_TRY_ADDREF_P(entry);
2274 zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2275 }
2276 count++;
2277 }
2278 }
2279 zval_ptr_dtor_str(&final_name);
2280 } else {
2281 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
2282 continue;
2283 }
2284 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
2285 goto prefix;
2286 }
2287 ZVAL_DEREF(entry);
2288 Z_TRY_ADDREF_P(entry);
2289 zend_hash_add_new(symbol_table, var_name, entry);
2290 count++;
2291 }
2293
2294 return count;
2295}
2296/* }}} */
2297
2298static zend_long php_extract_ref_prefix_all(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
2299{
2300 zend_long count = 0;
2302 zend_ulong num_key;
2303 zval *entry, *orig_var, final_name;
2304
2305 ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, var_name, entry) {
2306 if (var_name) {
2307 if (ZSTR_LEN(var_name) == 0) {
2308 continue;
2309 }
2311 } else {
2312 zend_string *str = zend_long_to_str(num_key);
2313 php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
2314 zend_string_release_ex(str, 0);
2315 }
2316 if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2317 if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) {
2318 zend_throw_error(NULL, "Cannot re-assign $this");
2319 return -1;
2320 } else {
2321 if (Z_ISREF_P(entry)) {
2322 Z_ADDREF_P(entry);
2323 } else {
2324 ZVAL_MAKE_REF_EX(entry, 2);
2325 }
2326 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2327 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2328 orig_var = Z_INDIRECT_P(orig_var);
2329 }
2330 zval_ptr_dtor(orig_var);
2331 ZVAL_REF(orig_var, Z_REF_P(entry));
2332 } else {
2333 zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2334 }
2335 count++;
2336 }
2337 }
2338 zval_ptr_dtor_str(&final_name);
2340
2341 return count;
2342}
2343/* }}} */
2344
2345static zend_long php_extract_prefix_all(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
2346{
2347 zend_long count = 0;
2349 zend_ulong num_key;
2350 zval *entry, *orig_var, final_name;
2351
2352 ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, var_name, entry) {
2353 if (var_name) {
2354 if (ZSTR_LEN(var_name) == 0) {
2355 continue;
2356 }
2358 } else {
2359 zend_string *str = zend_long_to_str(num_key);
2360 php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
2361 zend_string_release_ex(str, 0);
2362 }
2363 if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2364 if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) {
2365 zend_throw_error(NULL, "Cannot re-assign $this");
2366 return -1;
2367 } else {
2368 ZVAL_DEREF(entry);
2369 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2370 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2371 orig_var = Z_INDIRECT_P(orig_var);
2372 }
2373 ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
2374 if (UNEXPECTED(EG(exception))) {
2375 zend_string_release_ex(Z_STR(final_name), 0);
2376 return -1;
2377 }
2378 } else {
2379 Z_TRY_ADDREF_P(entry);
2380 zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2381 }
2382 count++;
2383 }
2384 }
2385 zval_ptr_dtor_str(&final_name);
2387
2388 return count;
2389}
2390/* }}} */
2391
2392static zend_long php_extract_ref_prefix_invalid(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
2393{
2394 zend_long count = 0;
2396 zend_ulong num_key;
2397 zval *entry, *orig_var, final_name;
2398
2399 ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, var_name, entry) {
2400 if (var_name) {
2401 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))
2402 || zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
2404 if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2405 zval_ptr_dtor_str(&final_name);
2406 continue;
2407 }
2408 } else {
2409 ZVAL_STR_COPY(&final_name, var_name);
2410 }
2411 } else {
2412 zend_string *str = zend_long_to_str(num_key);
2413 php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
2414 zend_string_release_ex(str, 0);
2415 if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2416 zval_ptr_dtor_str(&final_name);
2417 continue;
2418 }
2419 }
2420 if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) {
2421 zend_throw_error(NULL, "Cannot re-assign $this");
2422 return -1;
2423 } else {
2424 if (Z_ISREF_P(entry)) {
2425 Z_ADDREF_P(entry);
2426 } else {
2427 ZVAL_MAKE_REF_EX(entry, 2);
2428 }
2429 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2430 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2431 orig_var = Z_INDIRECT_P(orig_var);
2432 }
2433 zval_ptr_dtor(orig_var);
2434 ZVAL_REF(orig_var, Z_REF_P(entry));
2435 } else {
2436 zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2437 }
2438 count++;
2439 }
2440 zval_ptr_dtor_str(&final_name);
2442
2443 return count;
2444}
2445/* }}} */
2446
2447static zend_long php_extract_prefix_invalid(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
2448{
2449 zend_long count = 0;
2451 zend_ulong num_key;
2452 zval *entry, *orig_var, final_name;
2453
2454 ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, var_name, entry) {
2455 if (var_name) {
2456 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))
2457 || zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
2459 if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2460 zval_ptr_dtor_str(&final_name);
2461 continue;
2462 }
2463 } else {
2464 ZVAL_STR_COPY(&final_name, var_name);
2465 }
2466 } else {
2467 zend_string *str = zend_long_to_str(num_key);
2468 php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
2469 zend_string_release_ex(str, 0);
2470 if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
2471 zval_ptr_dtor_str(&final_name);
2472 continue;
2473 }
2474 }
2475 if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) {
2476 zend_throw_error(NULL, "Cannot re-assign $this");
2477 return -1;
2478 } else {
2479 ZVAL_DEREF(entry);
2480 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
2481 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2482 orig_var = Z_INDIRECT_P(orig_var);
2483 }
2484 ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
2485 if (UNEXPECTED(EG(exception))) {
2486 zend_string_release_ex(Z_STR(final_name), 0);
2487 return -1;
2488 }
2489 } else {
2490 Z_TRY_ADDREF_P(entry);
2491 zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
2492 }
2493 count++;
2494 }
2495 zval_ptr_dtor_str(&final_name);
2497
2498 return count;
2499}
2500/* }}} */
2501
2502static zend_long php_extract_ref_skip(zend_array *arr, zend_array *symbol_table) /* {{{ */
2503{
2504 zend_long count = 0;
2506 zval *entry, *orig_var;
2507
2508 if (HT_IS_PACKED(arr)) {
2509 return 0;
2510 }
2512 if (!var_name) {
2513 continue;
2514 }
2515 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
2516 continue;
2517 }
2518 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
2519 continue;
2520 }
2521 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
2522 if (orig_var) {
2523 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2524 orig_var = Z_INDIRECT_P(orig_var);
2525 if (Z_TYPE_P(orig_var) == IS_UNDEF) {
2526 if (Z_ISREF_P(entry)) {
2527 Z_ADDREF_P(entry);
2528 } else {
2529 ZVAL_MAKE_REF_EX(entry, 2);
2530 }
2531 ZVAL_REF(orig_var, Z_REF_P(entry));
2532 count++;
2533 }
2534 }
2535 } else {
2536 if (Z_ISREF_P(entry)) {
2537 Z_ADDREF_P(entry);
2538 } else {
2539 ZVAL_MAKE_REF_EX(entry, 2);
2540 }
2541 zend_hash_add_new(symbol_table, var_name, entry);
2542 count++;
2543 }
2545
2546 return count;
2547}
2548/* }}} */
2549
2550static zend_long php_extract_skip(zend_array *arr, zend_array *symbol_table) /* {{{ */
2551{
2552 zend_long count = 0;
2554 zval *entry, *orig_var;
2555
2556 if (HT_IS_PACKED(arr)) {
2557 return 0;
2558 }
2560 if (!var_name) {
2561 continue;
2562 }
2563 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
2564 continue;
2565 }
2566 if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) {
2567 continue;
2568 }
2569 orig_var = zend_hash_find_known_hash(symbol_table, var_name);
2570 if (orig_var) {
2571 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
2572 orig_var = Z_INDIRECT_P(orig_var);
2573 if (Z_TYPE_P(orig_var) == IS_UNDEF) {
2574 ZVAL_COPY_DEREF(orig_var, entry);
2575 count++;
2576 }
2577 }
2578 } else {
2579 ZVAL_DEREF(entry);
2580 Z_TRY_ADDREF_P(entry);
2581 zend_hash_add_new(symbol_table, var_name, entry);
2582 count++;
2583 }
2585
2586 return count;
2587}
2588/* }}} */
2589
2590/* {{{ Imports variables into symbol table from an array */
2592{
2593 zval *var_array_param;
2594 zend_long extract_refs;
2595 zend_long extract_type = PHP_EXTR_OVERWRITE;
2598 zend_array *symbol_table;
2599
2601 Z_PARAM_ARRAY_EX2(var_array_param, 0, 1, 0)
2603 Z_PARAM_LONG(extract_type)
2606
2607 extract_refs = (extract_type & PHP_EXTR_REFS);
2608 if (extract_refs) {
2609 SEPARATE_ARRAY(var_array_param);
2610 }
2611 extract_type &= 0xff;
2612
2613 if (extract_type < PHP_EXTR_OVERWRITE || extract_type > PHP_EXTR_IF_EXISTS) {
2614 zend_argument_value_error(2, "must be a valid extract type");
2615 RETURN_THROWS();
2616 }
2617
2618 if (extract_type > PHP_EXTR_SKIP && extract_type <= PHP_EXTR_PREFIX_IF_EXISTS && ZEND_NUM_ARGS() < 3) {
2619 zend_argument_value_error(3, "is required when using this extract type");
2620 RETURN_THROWS();
2621 }
2622
2623 if (prefix) {
2624 if (ZSTR_LEN(prefix) && !php_valid_var_name(ZSTR_VAL(prefix), ZSTR_LEN(prefix))) {
2625 zend_argument_value_error(3, "must be a valid identifier");
2626 RETURN_THROWS();
2627 }
2628 }
2629
2630 if (zend_forbid_dynamic_call() == FAILURE) {
2631 return;
2632 }
2633
2634 symbol_table = zend_rebuild_symbol_table();
2635 ZEND_ASSERT(symbol_table && "A symbol table should always be available here");
2636
2637 if (extract_refs) {
2638 switch (extract_type) {
2639 case PHP_EXTR_IF_EXISTS:
2640 count = php_extract_ref_if_exists(Z_ARRVAL_P(var_array_param), symbol_table);
2641 break;
2642 case PHP_EXTR_OVERWRITE:
2643 count = php_extract_ref_overwrite(Z_ARRVAL_P(var_array_param), symbol_table);
2644 break;
2646 count = php_extract_ref_prefix_if_exists(Z_ARRVAL_P(var_array_param), symbol_table, prefix);
2647 break;
2649 count = php_extract_ref_prefix_same(Z_ARRVAL_P(var_array_param), symbol_table, prefix);
2650 break;
2652 count = php_extract_ref_prefix_all(Z_ARRVAL_P(var_array_param), symbol_table, prefix);
2653 break;
2655 count = php_extract_ref_prefix_invalid(Z_ARRVAL_P(var_array_param), symbol_table, prefix);
2656 break;
2657 default:
2658 count = php_extract_ref_skip(Z_ARRVAL_P(var_array_param), symbol_table);
2659 break;
2660 }
2661 } else {
2662 /* The array might be stored in a local variable that will be overwritten */
2663 zval array_copy;
2664 ZVAL_COPY(&array_copy, var_array_param);
2665 switch (extract_type) {
2666 case PHP_EXTR_IF_EXISTS:
2667 count = php_extract_if_exists(Z_ARRVAL(array_copy), symbol_table);
2668 break;
2669 case PHP_EXTR_OVERWRITE:
2670 count = php_extract_overwrite(Z_ARRVAL(array_copy), symbol_table);
2671 break;
2673 count = php_extract_prefix_if_exists(Z_ARRVAL(array_copy), symbol_table, prefix);
2674 break;
2676 count = php_extract_prefix_same(Z_ARRVAL(array_copy), symbol_table, prefix);
2677 break;
2679 count = php_extract_prefix_all(Z_ARRVAL(array_copy), symbol_table, prefix);
2680 break;
2682 count = php_extract_prefix_invalid(Z_ARRVAL(array_copy), symbol_table, prefix);
2683 break;
2684 default:
2685 count = php_extract_skip(Z_ARRVAL(array_copy), symbol_table);
2686 break;
2687 }
2688 zval_ptr_dtor(&array_copy);
2689 }
2690
2692}
2693/* }}} */
2694
2695static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_value, zval *entry, uint32_t pos) /* {{{ */
2696{
2698
2699 ZVAL_DEREF(entry);
2700 if (Z_TYPE_P(entry) == IS_STRING) {
2701 if ((value_ptr = zend_hash_find_ind(eg_active_symbol_table, Z_STR_P(entry))) != NULL) {
2705 } else if (zend_string_equals(Z_STR_P(entry), ZSTR_KNOWN(ZEND_STR_THIS))) {
2706 zend_object *object = zend_get_this_object(EG(current_execute_data));
2707 if (object) {
2708 ZVAL_OBJ_COPY(&data, object);
2710 }
2711 } else {
2712 php_error_docref_unchecked(NULL, E_WARNING, "Undefined variable $%S", Z_STR_P(entry));
2713 }
2714 } else if (Z_TYPE_P(entry) == IS_ARRAY) {
2715 if (Z_REFCOUNTED_P(entry)) {
2716 if (Z_IS_RECURSIVE_P(entry)) {
2717 zend_throw_error(NULL, "Recursion detected");
2718 return;
2719 }
2720 Z_PROTECT_RECURSION_P(entry);
2721 }
2723 php_compact_var(eg_active_symbol_table, return_value, value_ptr, pos);
2725 if (Z_REFCOUNTED_P(entry)) {
2727 }
2728 } else {
2729 php_error_docref(NULL, E_WARNING, "Argument #%d must be string or array of strings, %s given", pos, zend_zval_value_name(entry));
2730 return;
2731 }
2732}
2733/* }}} */
2734
2735/* {{{ Creates a hash containing variables and their values */
2737{
2738 zval *args = NULL; /* function arguments array */
2739 uint32_t num_args, i;
2740 zend_array *symbol_table;
2741
2745
2746 if (zend_forbid_dynamic_call() == FAILURE) {
2747 return;
2748 }
2749
2750 symbol_table = zend_rebuild_symbol_table();
2751 ZEND_ASSERT(symbol_table && "A symbol table should always be available here");
2752
2753 /* compact() is probably most used with a single array of var_names
2754 or multiple string names, rather than a combination of both.
2755 So quickly guess a minimum result size based on that */
2756 if (num_args && Z_TYPE(args[0]) == IS_ARRAY) {
2757 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
2758 } else {
2760 }
2761
2762 for (i = 0; i < num_args; i++) {
2763 php_compact_var(symbol_table, return_value, &args[i], i + 1);
2764 }
2765}
2766/* }}} */
2767
2768/* {{{ Create an array containing num elements starting with index start_key each initialized to val */
2770{
2771 zval *val;
2772 zend_long start_key, num;
2773
2775 Z_PARAM_LONG(start_key)
2776 Z_PARAM_LONG(num)
2779
2780 if (EXPECTED(num > 0)) {
2781 if (sizeof(num) > 4 && UNEXPECTED(num > INT_MAX)) {
2782 zend_argument_value_error(2, "is too large");
2783 RETURN_THROWS();
2784 } else if (UNEXPECTED(start_key > ZEND_LONG_MAX - num + 1)) {
2785 zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
2786 RETURN_THROWS();
2787 } else if (EXPECTED(start_key >= 0) && EXPECTED(start_key < num)) {
2788 /* create packed array */
2789 zval *zv;
2790
2791 array_init_size(return_value, (uint32_t)(start_key + num));
2793 Z_ARRVAL_P(return_value)->nNumUsed = (uint32_t)(start_key + num);
2794 Z_ARRVAL_P(return_value)->nNumOfElements = (uint32_t)num;
2795 Z_ARRVAL_P(return_value)->nNextFreeElement = (zend_long)(start_key + num);
2796
2797 if (Z_REFCOUNTED_P(val)) {
2798 GC_ADDREF_EX(Z_COUNTED_P(val), (uint32_t)num);
2799 }
2800
2801 zv = Z_ARRVAL_P(return_value)->arPacked;
2802
2803 while (start_key--) {
2804 ZVAL_UNDEF(zv);
2805 zv++;
2806 }
2807 while (num--) {
2809 zv++;
2810 }
2811 } else {
2812 /* create hash */
2813 array_init_size(return_value, (uint32_t)num);
2815 if (Z_REFCOUNTED_P(val)) {
2816 GC_ADDREF_EX(Z_COUNTED_P(val), (uint32_t)num);
2817 }
2819 while (--num) {
2821 start_key++;
2822 }
2823 }
2824 } else if (EXPECTED(num == 0)) {
2826 } else {
2827 zend_argument_value_error(2, "must be greater than or equal to 0");
2828 RETURN_THROWS();
2829 }
2830}
2831/* }}} */
2832
2833/* {{{ Create an array using the elements of the first parameter as keys each initialized to val */
2835{
2836 zval *keys, *val, *entry;
2837
2839 Z_PARAM_ARRAY(keys)
2842
2843 /* Initialize return array */
2844 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
2845
2846 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) {
2847 ZVAL_DEREF(entry);
2849 if (Z_TYPE_P(entry) == IS_LONG) {
2851 } else {
2852 zend_string *tmp_key;
2853 zend_string *key = zval_get_tmp_string(entry, &tmp_key);
2854 zend_symtable_update(Z_ARRVAL_P(return_value), key, val);
2855 zend_tmp_string_release(tmp_key);
2856 }
2858}
2859/* }}} */
2860
2861#define RANGE_CHECK_DOUBLE_INIT_ARRAY(start, end, _step) do { \
2862 double __calc_size = ((start - end) / (_step)) + 1; \
2863 if (__calc_size >= (double)HT_MAX_SIZE) { \
2864 zend_value_error(\
2865 "The supplied range exceeds the maximum array size: start=%0.1f end=%0.1f step=%0.1f", end, start, (_step)); \
2866 RETURN_THROWS(); \
2867 } \
2868 size = (uint32_t)_php_math_round(__calc_size, 0, PHP_ROUND_HALF_UP); \
2869 array_init_size(return_value, size); \
2870 zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); \
2871 } while (0)
2872
2873#define RANGE_CHECK_LONG_INIT_ARRAY(start, end, _step) do { \
2874 zend_ulong __calc_size = ((zend_ulong) start - end) / (_step); \
2875 if (__calc_size >= HT_MAX_SIZE - 1) { \
2876 zend_value_error(\
2877 "The supplied range exceeds the maximum array size: start=" ZEND_LONG_FMT " end=" ZEND_LONG_FMT " step=" ZEND_LONG_FMT, end, start, (_step)); \
2878 RETURN_THROWS(); \
2879 } \
2880 size = (uint32_t)(__calc_size + 1); \
2881 array_init_size(return_value, size); \
2882 zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); \
2883 } while (0)
2884
2885/* Process input for the range() function
2886 * 0 on exceptions
2887 * IS_LONG if only interpretable as int
2888 * IS_DOUBLE if only interpretable as float
2889 * IS_STRING if only interpretable as string
2890 * IS_ARRAY (as IS_LONG < IS_STRING < IS_ARRAY) for ambiguity of single byte strings which contains a digit */
2891static uint8_t php_range_process_input(const zval *input, uint32_t arg_num, zend_long /* restrict */ *lval, double /* restrict */ *dval)
2892{
2893 switch (Z_TYPE_P(input)) {
2894 case IS_LONG:
2895 *lval = Z_LVAL_P(input);
2896 *dval = (double) Z_LVAL_P(input);
2897 return IS_LONG;
2898 case IS_DOUBLE:
2899 *dval = Z_DVAL_P(input);
2900 check_dval_value:
2901 if (zend_isinf(*dval)) {
2902 zend_argument_value_error(arg_num, "must be a finite number, INF provided");
2903 return 0;
2904 }
2905 if (zend_isnan(*dval)) {
2906 zend_argument_value_error(arg_num, "must be a finite number, NAN provided");
2907 return 0;
2908 }
2909 return IS_DOUBLE;
2910 case IS_STRING: {
2911 /* Process strings:
2912 * - Empty strings are converted to 0 with a diagnostic
2913 * - Check if string is numeric and store the values in passed pointer
2914 * - If numeric float, this means it cannot be a numeric string with only one byte GOTO IS_DOUBLE
2915 * - If numeric int, check it is one byte or not
2916 * - If it one byte, return IS_ARRAY as IS_LONG < IS_STRING < IS_ARRAY
2917 * - If not should only be interpreted as int, return IS_LONG;
2918 * - Otherwise is a string and return IS_STRING */
2919 if (Z_STRLEN_P(input) == 0) {
2920 const char *arg_name = get_active_function_arg_name(arg_num);
2921 php_error_docref(NULL, E_WARNING, "Argument #%d ($%s) must not be empty, casted to 0", arg_num, arg_name);
2922 if (UNEXPECTED(EG(exception))) {
2923 return 0;
2924 }
2925 *lval = 0;
2926 *dval = 0.0;
2927 return IS_LONG;
2928 }
2929 uint8_t type = is_numeric_str_function(Z_STR_P(input), lval, dval);
2930 if (type == IS_DOUBLE) {
2931 goto check_dval_value;
2932 }
2933 if (type == IS_LONG) {
2934 *dval = (double) *lval;
2935 if (Z_STRLEN_P(input) == 1) {
2936 return IS_ARRAY;
2937 } else {
2938 return IS_LONG;
2939 }
2940 }
2941 if (Z_STRLEN_P(input) != 1) {
2942 const char *arg_name = get_active_function_arg_name(arg_num);
2943 php_error_docref(NULL, E_WARNING, "Argument #%d ($%s) must be a single byte, subsequent bytes are ignored", arg_num, arg_name);
2944 if (UNEXPECTED(EG(exception))) {
2945 return 0;
2946 }
2947 }
2948 /* Set fall back values to 0 in case the other argument is not a string */
2949 *lval = 0;
2950 *dval = 0.0;
2951 return IS_STRING;
2952 }
2954 }
2955}
2956
2957/* {{{ Create an array containing the range of integers or characters from low to high (inclusive) */
2959{
2960 zval *user_start, *user_end, *user_step = NULL, tmp;
2961 bool is_step_double = false;
2962 bool is_step_negative = false;
2963 double step_double = 1.0;
2964 zend_long step = 1;
2965
2967 Z_PARAM_NUMBER_OR_STR(user_start)
2968 Z_PARAM_NUMBER_OR_STR(user_end)
2970 Z_PARAM_NUMBER(user_step)
2972
2973 if (user_step) {
2974 if (UNEXPECTED(Z_TYPE_P(user_step) == IS_DOUBLE)) {
2975 step_double = Z_DVAL_P(user_step);
2976
2977 if (zend_isinf(step_double)) {
2978 zend_argument_value_error(3, "must be a finite number, INF provided");
2979 RETURN_THROWS();
2980 }
2981 if (zend_isnan(step_double)) {
2982 zend_argument_value_error(3, "must be a finite number, NAN provided");
2983 RETURN_THROWS();
2984 }
2985
2986 /* We only want positive step values. */
2987 if (step_double < 0.0) {
2988 is_step_negative = true;
2989 step_double *= -1;
2990 }
2991 step = zend_dval_to_lval(step_double);
2992 if (!zend_is_long_compatible(step_double, step)) {
2993 is_step_double = true;
2994 }
2995 } else {
2996 step = Z_LVAL_P(user_step);
2997 /* We only want positive step values. */
2998 if (step < 0) {
2999 if (UNEXPECTED(step == ZEND_LONG_MIN)) {
3000 zend_argument_value_error(3, "must be greater than " ZEND_LONG_FMT, step);
3001 RETURN_THROWS();
3002 }
3003 is_step_negative = true;
3004 step *= -1;
3005 }
3006 step_double = (double) step;
3007 }
3008 if (step_double == 0.0) {
3009 zend_argument_value_error(3, "cannot be 0");
3010 RETURN_THROWS();
3011 }
3012 }
3013
3014 uint8_t start_type;
3015 double start_double;
3016 zend_long start_long;
3017 uint8_t end_type;
3018 double end_double;
3019 zend_long end_long;
3020
3021 start_type = php_range_process_input(user_start, 1, &start_long, &start_double);
3022 if (start_type == 0) {
3023 RETURN_THROWS();
3024 }
3025 end_type = php_range_process_input(user_end, 2, &end_long, &end_double);
3026 if (end_type == 0) {
3027 RETURN_THROWS();
3028 }
3029
3030 /* If the range is given as strings, generate an array of characters. */
3031 if (start_type >= IS_STRING || end_type >= IS_STRING) {
3032 /* If one of the inputs is NOT a string nor single-byte string */
3033 if (UNEXPECTED(start_type < IS_STRING || end_type < IS_STRING)) {
3034 if (start_type < IS_STRING) {
3035 if (end_type != IS_ARRAY) {
3036 php_error_docref(NULL, E_WARNING, "Argument #1 ($start) must be a single byte string if"
3037 " argument #2 ($end) is a single byte string, argument #2 ($end) converted to 0");
3038 }
3039 end_type = IS_LONG;
3040 } else if (end_type < IS_STRING) {
3041 if (start_type != IS_ARRAY) {
3042 php_error_docref(NULL, E_WARNING, "Argument #2 ($end) must be a single byte string if"
3043 " argument #1 ($start) is a single byte string, argument #1 ($start) converted to 0");
3044 }
3045 start_type = IS_LONG;
3046 }
3047 if (UNEXPECTED(EG(exception))) {
3048 RETURN_THROWS();
3049 }
3050 goto handle_numeric_inputs;
3051 }
3052
3053 if (is_step_double) {
3054 /* Only emit warning if one of the input is not a numeric digit */
3055 if (start_type == IS_STRING || end_type == IS_STRING) {
3056 php_error_docref(NULL, E_WARNING, "Argument #3 ($step) must be of type int when generating an array"
3057 " of characters, inputs converted to 0");
3058 }
3059 if (UNEXPECTED(EG(exception))) {
3060 RETURN_THROWS();
3061 }
3062 end_type = IS_LONG;
3063 start_type = IS_LONG;
3064 goto handle_numeric_inputs;
3065 }
3066
3067 /* Generate array of characters */
3068 unsigned char low = (unsigned char)Z_STRVAL_P(user_start)[0];
3069 unsigned char high = (unsigned char)Z_STRVAL_P(user_end)[0];
3070
3071 /* Decreasing char range */
3072 if (low > high) {
3073 if (low - high < step) {
3074 goto boundary_error;
3075 }
3076 /* Initialize the return_value as an array. */
3077 array_init_size(return_value, (uint32_t)(((low - high) / step) + 1));
3080 for (; low >= high; low -= (unsigned int)step) {
3083 if (((signed int)low - step) < 0) {
3084 break;
3085 }
3086 }
3088 } else if (high > low) { /* Increasing char range */
3089 if (is_step_negative) {
3090 goto negative_step_error;
3091 }
3092 if (high - low < step) {
3093 goto boundary_error;
3094 }
3095 array_init_size(return_value, (uint32_t)(((high - low) / step) + 1));
3098 for (; low <= high; low += (unsigned int)step) {
3101 if (((signed int)low + step) > 255) {
3102 break;
3103 }
3104 }
3106 } else {
3108 ZVAL_CHAR(&tmp, low);
3110 }
3111 return;
3112 }
3113
3114 handle_numeric_inputs:
3115 if (start_type == IS_DOUBLE || end_type == IS_DOUBLE || is_step_double) {
3116 double element;
3117 uint32_t i, size;
3118
3119 /* Decreasing float range */
3120 if (start_double > end_double) {
3121 if (start_double - end_double < step_double) {
3122 goto boundary_error;
3123 }
3124
3125 RANGE_CHECK_DOUBLE_INIT_ARRAY(start_double, end_double, step_double);
3126
3128 for (i = 0, element = start_double; i < size && element >= end_double; ++i, element = start_double - (i * step_double)) {
3131 }
3133 } else if (end_double > start_double) { /* Increasing float range */
3134 if (is_step_negative) {
3135 goto negative_step_error;
3136 }
3137 if (end_double - start_double < step_double) {
3138 goto boundary_error;
3139 }
3140
3141 RANGE_CHECK_DOUBLE_INIT_ARRAY(end_double, start_double, step_double);
3142
3144 for (i = 0, element = start_double; i < size && element <= end_double; ++i, element = start_double + (i * step_double)) {
3147 }
3149 } else {
3151 ZVAL_DOUBLE(&tmp, start_double);
3153 }
3154 } else {
3155 ZEND_ASSERT(start_type == IS_LONG && end_type == IS_LONG && !is_step_double);
3156 /* unsigned_step is a zend_ulong so that comparisons to it don't overflow, i.e. low - high < lstep */
3157 zend_ulong unsigned_step= (zend_ulong)step;
3158 uint32_t i, size;
3159
3160 /* Decreasing int range */
3161 if (start_long > end_long) {
3162 if ((zend_ulong)start_long - end_long < unsigned_step) {
3163 goto boundary_error;
3164 }
3165
3166 RANGE_CHECK_LONG_INIT_ARRAY(start_long, end_long, unsigned_step);
3167
3169 for (i = 0; i < size; ++i) {
3170 ZEND_HASH_FILL_SET_LONG(start_long - (i * unsigned_step));
3172 }
3174 } else if (end_long > start_long) { /* Increasing int range */
3175 if (is_step_negative) {
3176 goto negative_step_error;
3177 }
3178 if ((zend_ulong)end_long - start_long < unsigned_step) {
3179 goto boundary_error;
3180 }
3181
3182 RANGE_CHECK_LONG_INIT_ARRAY(end_long, start_long, unsigned_step);
3183
3185 for (i = 0; i < size; ++i) {
3186 ZEND_HASH_FILL_SET_LONG(start_long + (i * unsigned_step));
3188 }
3190 } else {
3192 ZVAL_LONG(&tmp, start_long);
3194 }
3195 }
3196 return;
3197
3198negative_step_error:
3199 zend_argument_value_error(3, "must be greater than 0 for increasing ranges");
3200 RETURN_THROWS();
3201
3202boundary_error:
3203 zend_argument_value_error(3, "must be less than the range spanned by argument #1 ($start) and argument #2 ($end)");
3204 RETURN_THROWS();
3205}
3206/* }}} */
3207
3208#undef RANGE_CHECK_DOUBLE_INIT_ARRAY
3209#undef RANGE_CHECK_LONG_INIT_ARRAY
3210
3211/* {{{ php_array_data_shuffle */
3213{
3214 const php_random_algo *algo = engine.algo;
3215 void *state = engine.state;
3216
3217 int64_t idx, j, n_elems, rnd_idx, n_left;
3218 zval *zv, temp;
3219 HashTable *hash;
3220
3221 n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
3222
3223 if (n_elems < 1) {
3224 return true;
3225 }
3226
3227 hash = Z_ARRVAL_P(array);
3228 n_left = n_elems;
3229
3230 if (!HT_IS_PACKED(hash)) {
3232 Bucket *p = hash->arData;
3233 zend_long i = hash->nNumUsed;
3234
3235 for (; i > 0; p++, i--) {
3236 if (p->key) {
3237 zend_string_release(p->key);
3238 p->key = NULL;
3239 }
3240 }
3241 }
3243 }
3244
3246 if (hash->nNumUsed != hash->nNumOfElements) {
3247 for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
3248 zv = hash->arPacked + idx;
3249 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
3250 if (j != idx) {
3251 ZVAL_COPY_VALUE(&hash->arPacked[j], zv);
3252 }
3253 j++;
3254 }
3255 }
3256 while (--n_left) {
3257 rnd_idx = algo->range(state, 0, n_left);
3258 if (EG(exception)) {
3259 return false;
3260 }
3261 if (rnd_idx != n_left) {
3262 ZVAL_COPY_VALUE(&temp, &hash->arPacked[n_left]);
3263 ZVAL_COPY_VALUE(&hash->arPacked[n_left], &hash->arPacked[rnd_idx]);
3264 ZVAL_COPY_VALUE(&hash->arPacked[rnd_idx], &temp);
3265 }
3266 }
3267 } else {
3269
3270 if (hash->nNumUsed != hash->nNumOfElements) {
3271 for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
3272 zv = hash->arPacked + idx;
3273 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
3274 if (j != idx) {
3275 ZVAL_COPY_VALUE(&hash->arPacked[j], zv);
3276 if (idx == iter_pos) {
3277 zend_hash_iterators_update(hash, idx, j);
3278 iter_pos = zend_hash_iterators_lower_pos(hash, iter_pos + 1);
3279 }
3280 }
3281 j++;
3282 }
3283 }
3284 while (--n_left) {
3285 rnd_idx = algo->range(state, 0, n_left);
3286 if (EG(exception)) {
3287 return false;
3288 }
3289 if (rnd_idx != n_left) {
3290 ZVAL_COPY_VALUE(&temp, &hash->arPacked[n_left]);
3291 ZVAL_COPY_VALUE(&hash->arPacked[n_left], &hash->arPacked[rnd_idx]);
3292 ZVAL_COPY_VALUE(&hash->arPacked[rnd_idx], &temp);
3293 zend_hash_iterators_update(hash, (uint32_t)rnd_idx, n_left);
3294 }
3295 }
3296 }
3297 hash->nNumUsed = n_elems;
3298 hash->nInternalPointer = 0;
3299 hash->nNextFreeElement = n_elems;
3300
3301 return true;
3302}
3303/* }}} */
3304
3305/* {{{ Randomly shuffle the contents of an array */
3307{
3308 zval *array;
3309
3311 Z_PARAM_ARRAY_EX(array, 0, 1)
3313
3314 php_array_data_shuffle(php_random_default_engine(), array);
3315
3317}
3318/* }}} */
3319
3320static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, HashTable *replace, HashTable *removed) /* {{{ */
3321{
3322 HashTable out_hash; /* Output hashtable */
3323 zend_long num_in; /* Number of entries in the input hashtable */
3324 zend_long pos; /* Current position in the hashtable */
3325 uint32_t idx;
3326 zval *entry; /* Hash entry */
3327 uint32_t iter_pos = zend_hash_iterators_lower_pos(in_hash, 0);
3328
3329 /* Get number of entries in the input hash */
3330 num_in = zend_hash_num_elements(in_hash);
3331
3332 /* Clamp the offset.. */
3333 if (offset > num_in) {
3334 offset = num_in;
3335 } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
3336 offset = 0;
3337 }
3338
3339 /* ..and the length */
3340 if (length < 0) {
3341 length = num_in - offset + length;
3342 } else if (((unsigned)offset + (unsigned)length) > (unsigned)num_in) {
3343 length = num_in - offset;
3344 }
3345
3346 /* Create and initialize output hash */
3347 zend_hash_init(&out_hash, (length > 0 ? num_in - length : 0) + (replace ? zend_hash_num_elements(replace) : 0), NULL, ZVAL_PTR_DTOR, 0);
3348
3349 if (HT_IS_PACKED(in_hash)) {
3350 /* Start at the beginning of the input hash and copy entries to output hash until offset is reached */
3351 entry = in_hash->arPacked;
3352 for (pos = 0, idx = 0; pos < offset && idx < in_hash->nNumUsed; idx++, entry++) {
3353 if (Z_TYPE_P(entry) == IS_UNDEF) continue;
3354
3355 zend_hash_next_index_insert_new(&out_hash, entry);
3356 if (idx == iter_pos) {
3357 if ((zend_long)idx != pos) {
3358 zend_hash_iterators_update(in_hash, idx, pos);
3359 }
3360 iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
3361 }
3362 pos++;
3363 }
3364
3365 /* If hash for removed entries exists, go until offset+length and copy the entries to it */
3366 if (removed != NULL) {
3367 for ( ; pos - offset < length && idx < in_hash->nNumUsed; idx++, entry++) {
3368 if (Z_TYPE_P(entry) == IS_UNDEF) continue;
3369 pos++;
3370 Z_TRY_ADDREF_P(entry);
3371 zend_hash_next_index_insert_new(removed, entry);
3372 zend_hash_packed_del_val(in_hash, entry);
3373 /* Bump iterator positions to the element after replacement. */
3374 if (idx == iter_pos) {
3375 zend_hash_iterators_update(in_hash, idx, offset + length);
3376 iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
3377 }
3378 }
3379 } else { /* otherwise just skip those entries */
3380 zend_long pos2 = pos;
3381
3382 for ( ; pos2 - offset < length && idx < in_hash->nNumUsed; idx++, entry++) {
3383 if (Z_TYPE_P(entry) == IS_UNDEF) continue;
3384 pos2++;
3385 zend_hash_packed_del_val(in_hash, entry);
3386 /* Bump iterator positions to the element after replacement. */
3387 if (idx == iter_pos) {
3388 zend_hash_iterators_update(in_hash, idx, offset + length);
3389 iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
3390 }
3391 }
3392 }
3393
3394 /* If there are entries to insert.. */
3395 if (replace) {
3396 ZEND_HASH_FOREACH_VAL(replace, entry) {
3397 Z_TRY_ADDREF_P(entry);
3398 zend_hash_next_index_insert_new(&out_hash, entry);
3399 pos++;
3401 }
3402
3403 /* Copy the remaining input hash entries to the output hash */
3404 entry = in_hash->arPacked + idx;
3405 for ( ; idx < in_hash->nNumUsed ; idx++, entry++) {
3406 if (Z_TYPE_P(entry) == IS_UNDEF) continue;
3407 zend_hash_next_index_insert_new(&out_hash, entry);
3408 if (idx == iter_pos) {
3409 if ((zend_long)idx != pos) {
3410 zend_hash_iterators_update(in_hash, idx, pos);
3411 }
3412 iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
3413 }
3414 pos++;
3415 }
3416 } else {
3417 Bucket *p = in_hash->arData;
3418
3419 /* Start at the beginning of the input hash and copy entries to output hash until offset is reached */
3420 for (pos = 0, idx = 0; pos < offset && idx < in_hash->nNumUsed; idx++, p++) {
3421 if (Z_TYPE(p->val) == IS_UNDEF) continue;
3422 entry = &p->val;
3423
3424 /* Update output hash depending on key type */
3425 if (p->key == NULL) {
3426 zend_hash_next_index_insert_new(&out_hash, entry);
3427 } else {
3428 zend_hash_add_new(&out_hash, p->key, entry);
3429 }
3430 if (idx == iter_pos) {
3431 if ((zend_long)idx != pos) {
3432 zend_hash_iterators_update(in_hash, idx, pos);
3433 }
3434 iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
3435 }
3436 pos++;
3437 }
3438
3439 /* If hash for removed entries exists, go until offset+length and copy the entries to it */
3440 if (removed != NULL) {
3441 for ( ; pos - offset < length && idx < in_hash->nNumUsed; idx++, p++) {
3442 if (Z_TYPE(p->val) == IS_UNDEF) continue;
3443 pos++;
3444 entry = &p->val;
3445 Z_TRY_ADDREF_P(entry);
3446 if (p->key == NULL) {
3447 zend_hash_next_index_insert_new(removed, entry);
3448 } else {
3449 zend_hash_add_new(removed, p->key, entry);
3450 }
3451 zend_hash_del_bucket(in_hash, p);
3452 }
3453 } else { /* otherwise just skip those entries */
3454 zend_long pos2 = pos;
3455
3456 for ( ; pos2 - offset < length && idx < in_hash->nNumUsed; idx++, p++) {
3457 if (Z_TYPE(p->val) == IS_UNDEF) continue;
3458 pos2++;
3459 zend_hash_del_bucket(in_hash, p);
3460 }
3461 }
3462 iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos);
3463
3464 /* If there are entries to insert.. */
3465 if (replace) {
3466 ZEND_HASH_FOREACH_VAL(replace, entry) {
3467 Z_TRY_ADDREF_P(entry);
3468 zend_hash_next_index_insert_new(&out_hash, entry);
3469 pos++;
3471 }
3472
3473 /* Copy the remaining input hash entries to the output hash */
3474 for ( ; idx < in_hash->nNumUsed ; idx++, p++) {
3475 if (Z_TYPE(p->val) == IS_UNDEF) continue;
3476 entry = &p->val;
3477 if (p->key == NULL) {
3478 zend_hash_next_index_insert_new(&out_hash, entry);
3479 } else {
3480 zend_hash_add_new(&out_hash, p->key, entry);
3481 }
3482 if (idx == iter_pos) {
3483 if ((zend_long)idx != pos) {
3484 zend_hash_iterators_update(in_hash, idx, pos);
3485 }
3486 iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
3487 }
3488 pos++;
3489 }
3490 }
3491
3492 /* replace HashTable data */
3493 HT_SET_ITERATORS_COUNT(&out_hash, HT_ITERATORS_COUNT(in_hash));
3494 HT_SET_ITERATORS_COUNT(in_hash, 0);
3495 in_hash->pDestructor = NULL;
3496 zend_hash_destroy(in_hash);
3497
3498 HT_FLAGS(in_hash) = HT_FLAGS(&out_hash);
3499 in_hash->nTableSize = out_hash.nTableSize;
3500 in_hash->nTableMask = out_hash.nTableMask;
3501 in_hash->nNumUsed = out_hash.nNumUsed;
3502 in_hash->nNumOfElements = out_hash.nNumOfElements;
3503 in_hash->nNextFreeElement = out_hash.nNextFreeElement;
3504 in_hash->arData = out_hash.arData;
3505 in_hash->pDestructor = out_hash.pDestructor;
3506
3507 zend_hash_internal_pointer_reset(in_hash);
3508}
3509/* }}} */
3510
3511/* {{{ Pushes elements onto the end of the array */
3513{
3514 zval *args, /* Function arguments array */
3515 *stack, /* Input array */
3516 new_var; /* Variable to be pushed */
3517 uint32_t argc; /* Number of function arguments */
3518
3519
3521 Z_PARAM_ARRAY_EX(stack, 0, 1)
3522 Z_PARAM_VARIADIC('+', args, argc)
3524
3525 /* For each subsequent argument, make it a reference, increase refcount, and add it to the end of the array */
3526 for (uint32_t i = 0; i < argc; i++) {
3527 ZVAL_COPY(&new_var, &args[i]);
3528
3529 if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var) == NULL) {
3530 Z_TRY_DELREF(new_var);
3531 zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
3532 RETURN_THROWS();
3533 }
3534 }
3535
3536 /* Clean up and return the number of values in the stack */
3537 RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
3538}
3539/* }}} */
3540
3541/* {{{ Pops an element off the end of the array */
3543{
3544 zval *stack, /* Input stack */
3545 *val; /* Value to be popped */
3546 uint32_t idx;
3547
3549 Z_PARAM_ARRAY_EX(stack, 0, 1)
3551
3552 if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {
3553 return;
3554 }
3555
3556 if (HT_IS_PACKED(Z_ARRVAL_P(stack))) {
3557 /* Get the last value and copy it into the return value */
3558 idx = Z_ARRVAL_P(stack)->nNumUsed;
3559 while (1) {
3560 if (idx == 0) {
3561 return;
3562 }
3563 idx--;
3564 val = Z_ARRVAL_P(stack)->arPacked + idx;
3565 if (Z_TYPE_P(val) != IS_UNDEF) {
3566 break;
3567 }
3568 }
3570 ZVAL_UNDEF(val);
3571
3572 if (idx == (Z_ARRVAL_P(stack)->nNextFreeElement - 1)) {
3573 Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1;
3574 }
3575
3576 /* Delete the last value */
3578 } else {
3579 Bucket *p;
3580
3581 /* Get the last value and copy it into the return value */
3582 idx = Z_ARRVAL_P(stack)->nNumUsed;
3583 while (1) {
3584 if (idx == 0) {
3585 return;
3586 }
3587 idx--;
3588 p = Z_ARRVAL_P(stack)->arData + idx;
3589 val = &p->val;
3590 if (Z_TYPE_P(val) != IS_UNDEF) {
3591 break;
3592 }
3593 }
3595 ZVAL_UNDEF(val);
3596
3597 if (!p->key && (zend_long)p->h == (Z_ARRVAL_P(stack)->nNextFreeElement - 1)) {
3598 Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1;
3599 }
3600
3601 /* Delete the last value */
3603 }
3604 zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
3605
3606 if (Z_ISREF_P(return_value)) {
3607 zend_unwrap_reference(return_value);
3608 }
3609}
3610/* }}} */
3611
3612/* {{{ Pops an element off the beginning of the array */
3614{
3615 zval *stack, /* Input stack */
3616 *val; /* Value to be popped */
3617 uint32_t idx;
3618
3620 Z_PARAM_ARRAY_EX(stack, 0, 1)
3622
3623 if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {
3624 return;
3625 }
3626
3627 /* re-index like it did before */
3628 if (HT_IS_PACKED(Z_ARRVAL_P(stack))) {
3629 uint32_t k = 0;
3630
3631 /* Get the first value and copy it into the return value */
3632 idx = 0;
3633 while (1) {
3634 if (idx == Z_ARRVAL_P(stack)->nNumUsed) {
3635 return;
3636 }
3637 val = Z_ARRVAL_P(stack)->arPacked + idx;
3638 if (Z_TYPE_P(val) != IS_UNDEF) {
3639 break;
3640 }
3641 idx++;
3642 }
3644 ZVAL_UNDEF(val);
3645
3646 /* Delete the first value */
3648
3649 if (EXPECTED(!HT_HAS_ITERATORS(Z_ARRVAL_P(stack)))) {
3650 for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
3651 val = Z_ARRVAL_P(stack)->arPacked + idx;
3652 if (Z_TYPE_P(val) == IS_UNDEF) continue;
3653 if (idx != k) {
3654 zval *q = Z_ARRVAL_P(stack)->arPacked + k;
3655 ZVAL_COPY_VALUE(q, val);
3656 ZVAL_UNDEF(val);
3657 }
3658 k++;
3659 }
3660 } else {
3661 uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);
3662
3663 for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
3664 val = Z_ARRVAL_P(stack)->arPacked + idx;
3665 if (Z_TYPE_P(val) == IS_UNDEF) continue;
3666 if (idx != k) {
3667 zval *q = Z_ARRVAL_P(stack)->arPacked + k;
3668 ZVAL_COPY_VALUE(q, val);
3669 ZVAL_UNDEF(val);
3670 if (idx == iter_pos) {
3671 zend_hash_iterators_update(Z_ARRVAL_P(stack), idx, k);
3672 iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
3673 }
3674 }
3675 k++;
3676 }
3677 }
3678 Z_ARRVAL_P(stack)->nNumUsed = k;
3679 Z_ARRVAL_P(stack)->nNextFreeElement = k;
3680 } else {
3681 uint32_t k = 0;
3682 int should_rehash = 0;
3683 Bucket *p;
3684
3685 /* Get the first value and copy it into the return value */
3686 idx = 0;
3687 while (1) {
3688 if (idx == Z_ARRVAL_P(stack)->nNumUsed) {
3689 return;
3690 }
3691 p = Z_ARRVAL_P(stack)->arData + idx;
3692 val = &p->val;
3693 if (Z_TYPE_P(val) != IS_UNDEF) {
3694 break;
3695 }
3696 idx++;
3697 }
3699 ZVAL_UNDEF(val);
3700
3701 /* Delete the first value */
3703
3704 for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
3705 p = Z_ARRVAL_P(stack)->arData + idx;
3706 if (Z_TYPE(p->val) == IS_UNDEF) continue;
3707 if (p->key == NULL) {
3708 if (p->h != k) {
3709 p->h = k++;
3710 should_rehash = 1;
3711 } else {
3712 k++;
3713 }
3714 }
3715 }
3716 Z_ARRVAL_P(stack)->nNextFreeElement = k;
3717 if (should_rehash) {
3719 }
3720 }
3721
3722 zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
3723
3724 if (Z_ISREF_P(return_value)) {
3725 zend_unwrap_reference(return_value);
3726 }
3727}
3728/* }}} */
3729
3730/* {{{ Pushes elements onto the beginning of the array */
3732{
3733 zval *args, /* Function arguments array */
3734 *stack; /* Input stack */
3735 HashTable new_hash; /* New hashtable for the stack */
3736 uint32_t argc; /* Number of function arguments */
3738 zval *value;
3739
3741 Z_PARAM_ARRAY_EX(stack, 0, 1)
3742 Z_PARAM_VARIADIC('+', args, argc)
3744
3745 zend_hash_init(&new_hash, zend_hash_num_elements(Z_ARRVAL_P(stack)) + argc, NULL, ZVAL_PTR_DTOR, 0);
3746 for (uint32_t i = 0; i < argc; i++) {
3747 Z_TRY_ADDREF(args[i]);
3748 zend_hash_next_index_insert_new(&new_hash, &args[i]);
3749 }
3750
3752 if (key) {
3753 zend_hash_add_new(&new_hash, key, value);
3754 } else {
3756 }
3758
3759 if (UNEXPECTED(HT_HAS_ITERATORS(Z_ARRVAL_P(stack)))) {
3763 }
3764
3765 /* replace HashTable data */
3766 Z_ARRVAL_P(stack)->pDestructor = NULL;
3768
3769 HT_FLAGS(Z_ARRVAL_P(stack)) = HT_FLAGS(&new_hash);
3770 Z_ARRVAL_P(stack)->nTableSize = new_hash.nTableSize;
3771 Z_ARRVAL_P(stack)->nTableMask = new_hash.nTableMask;
3772 Z_ARRVAL_P(stack)->nNumUsed = new_hash.nNumUsed;
3773 Z_ARRVAL_P(stack)->nNumOfElements = new_hash.nNumOfElements;
3774 Z_ARRVAL_P(stack)->nNextFreeElement = new_hash.nNextFreeElement;
3775 Z_ARRVAL_P(stack)->arData = new_hash.arData;
3776 Z_ARRVAL_P(stack)->pDestructor = new_hash.pDestructor;
3777
3778 zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
3779
3780 /* Clean up and return the number of elements in the stack */
3781 RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
3782}
3783/* }}} */
3784
3785/* {{{ Removes the elements designated by offset and length and replace them with supplied array */
3787{
3788 zval *array, /* Input array */
3789 *repl_array = NULL; /* Replacement array */
3790 HashTable *rem_hash = NULL;
3792 length = 0;
3793 bool length_is_null = 1;
3794 int num_in; /* Number of elements in the input array */
3795
3797 Z_PARAM_ARRAY_EX(array, 0, 1)
3800 Z_PARAM_LONG_OR_NULL(length, length_is_null)
3801 Z_PARAM_ZVAL(repl_array)
3803
3804 num_in = zend_hash_num_elements(Z_ARRVAL_P(array));
3805
3806 if (length_is_null) {
3807 length = num_in;
3808 }
3809
3810 if (ZEND_NUM_ARGS() == 4) {
3811 /* Make sure the last argument, if passed, is an array */
3812 convert_to_array(repl_array);
3813 }
3814
3815 /* Don't create the array of removed elements if it's not going
3816 * to be used; e.g. only removing and/or replacing elements */
3817 if (USED_RET()) {
3818 zend_long size = length;
3819
3820 /* Clamp the offset.. */
3821 if (offset > num_in) {
3822 offset = num_in;
3823 } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
3824 offset = 0;
3825 }
3826
3827 /* ..and the length */
3828 if (length < 0) {
3829 size = num_in - offset + length;
3830 } else if (((zend_ulong) offset + (zend_ulong) length) > (uint32_t) num_in) {
3831 size = num_in - offset;
3832 }
3833
3834 /* Initialize return value */
3835 array_init_size(return_value, size > 0 ? (uint32_t)size : 0);
3836 rem_hash = Z_ARRVAL_P(return_value);
3837 } else {
3838 /* The return value will not be used, but make sure it still has the correct type. */
3840 }
3841
3842 /* Perform splice */
3843 php_splice(Z_ARRVAL_P(array), offset, length, repl_array ? Z_ARRVAL_P(repl_array) : NULL, rem_hash);
3844}
3845/* }}} */
3846
3847/* {{{ find_bucket_at_offset(HashTable* ht, zend_long offset)
3848 Finds the bucket at the given valid offset */
3849static inline Bucket* find_bucket_at_offset(HashTable* ht, zend_long offset)
3850{
3851 zend_long pos;
3852 Bucket *bucket;
3853 ZEND_ASSERT(offset >= 0 && offset <= ht->nNumOfElements);
3854 if (HT_IS_WITHOUT_HOLES(ht)) {
3855 /* There's no need to iterate over the array to filter out holes if there are no holes */
3856 /* This properly handles both packed and unpacked arrays. */
3857 return ht->arData + offset;
3858 }
3859 /* Otherwise, this code has to iterate over the HashTable and skip holes in the array. */
3860 pos = 0;
3862 if (pos >= offset) {
3863 /* This is the bucket of the array element at the requested offset */
3864 return bucket;
3865 }
3866 ++pos;
3868
3869 /* Return a pointer to the end of the bucket array. */
3870 return ht->arData + ht->nNumUsed;
3871}
3872/* }}} */
3873
3874/* {{{ find_bucket_at_offset(HashTable* ht, zend_long offset)
3875 Finds the bucket at the given valid offset */
3876static inline zval* find_packed_val_at_offset(HashTable* ht, zend_long offset)
3877{
3878 zend_long pos;
3879 zval *zv;
3880 ZEND_ASSERT(offset >= 0 && offset <= ht->nNumOfElements);
3881 if (HT_IS_WITHOUT_HOLES(ht)) {
3882 /* There's no need to iterate over the array to filter out holes if there are no holes */
3883 /* This properly handles both packed and unpacked arrays. */
3884 return ht->arPacked + offset;
3885 }
3886 /* Otherwise, this code has to iterate over the HashTable and skip holes in the array. */
3887 pos = 0;
3889 if (pos >= offset) {
3890 /* This is the bucket of the array element at the requested offset */
3891 return zv;
3892 }
3893 ++pos;
3895
3896 /* Return a pointer to the end of the bucket array. */
3897 return ht->arPacked + ht->nNumUsed;
3898}
3899/* }}} */
3900
3901/* {{{ Returns elements specified by offset and length */
3903{
3904 zval *input; /* Input array */
3905 zval *entry; /* An array entry */
3906 zend_long offset; /* Offset to get elements from */
3907 zend_long length = 0; /* How many elements to get */
3908 bool length_is_null = 1; /* Whether an explicit length has been omitted */
3909 bool preserve_keys = 0; /* Whether to preserve keys while copying to the new array */
3910 uint32_t num_in; /* Number of elements in the input array */
3911 zend_string *string_key;
3912 zend_ulong num_key;
3913
3915 Z_PARAM_ARRAY(input)
3918 Z_PARAM_LONG_OR_NULL(length, length_is_null)
3919 Z_PARAM_BOOL(preserve_keys)
3921
3922 /* Get number of entries in the input hash */
3923 num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
3924
3925 /* We want all entries from offset to the end if length is not passed or is null */
3926 if (length_is_null) {
3927 length = num_in;
3928 }
3929
3930 /* Clamp the offset.. */
3931 if (offset > (zend_long) num_in) {
3933 } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
3934 offset = 0;
3935 }
3936
3937 /* ..and the length */
3938 if (length < 0) {
3939 length = num_in - offset + length;
3940 } else if (((zend_ulong) offset + (zend_ulong) length) > (unsigned) num_in) {
3941 length = num_in - offset;
3942 }
3943
3944 if (length <= 0) {
3946 }
3947
3948 /* Initialize returned array */
3949 array_init_size(return_value, (uint32_t)length);
3950
3951 // Contains modified variants of ZEND_HASH_FOREACH_VAL
3952 {
3953 HashTable *ht = Z_ARRVAL_P(input);
3954
3955 /* Start at the beginning and go until we hit offset */
3956 if (HT_IS_PACKED(ht)) {
3957 zval *zv = find_packed_val_at_offset(ht, offset);
3958 zval *end = ht->arPacked + ht->nNumUsed;
3959
3960 if (!preserve_keys
3961 || (offset == 0 && HT_IS_WITHOUT_HOLES(ht))) {
3964 for (; zv != end; zv++) {
3965 if (__fill_idx >= length) {
3966 break;
3967 }
3968 if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) {
3969 continue;
3970 }
3971 entry = zv;
3972 if (UNEXPECTED(Z_ISREF_P(entry)) &&
3973 UNEXPECTED(Z_REFCOUNT_P(entry) == 1)) {
3974 entry = Z_REFVAL_P(entry);
3975 }
3976 Z_TRY_ADDREF_P(entry);
3977 ZEND_HASH_FILL_ADD(entry);
3978 }
3980 } else {
3981 zend_long n = 0; /* Current number of elements */
3982 zend_long idx = zv - ht->arPacked;
3983
3984 for (; zv != end; zv++, idx++) {
3985 if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) {
3986 continue;
3987 }
3988 if (n >= length) {
3989 break;
3990 }
3991 n++;
3993 zval_add_ref(entry);
3994 }
3995 }
3996 } else {
3997 zend_long n = 0; /* Current number of elements */
3998 Bucket *p = find_bucket_at_offset(ht, offset);
3999 Bucket *end = ht->arData + ht->nNumUsed;
4000
4001 for (; p != end; p++) {
4002 entry = &p->val;
4003 if (UNEXPECTED(Z_TYPE_P(entry) == IS_UNDEF)) {
4004 continue;
4005 }
4006 if (n >= length) {
4007 break;
4008 }
4009 n++;
4010 num_key = p->h;
4011 string_key = p->key;
4012
4013 if (string_key) {
4014 entry = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, entry);
4015 } else {
4016 if (preserve_keys) {
4017 entry = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, entry);
4018 } else {
4020 }
4021 }
4022 zval_add_ref(entry);
4023 }
4024 }
4025 }
4026}
4027/* }}} */
4028
4030{
4031 zval *src_entry, *dest_entry;
4032 zend_string *string_key;
4033
4034 ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
4035 if (string_key) {
4036 if ((dest_entry = zend_hash_find_known_hash(dest, string_key)) != NULL) {
4037 zval *src_zval = src_entry;
4038 zval *dest_zval = dest_entry;
4039 HashTable *thash;
4040 zval tmp;
4041 int ret;
4042
4043 ZVAL_DEREF(src_zval);
4044 ZVAL_DEREF(dest_zval);
4045 thash = Z_TYPE_P(dest_zval) == IS_ARRAY ? Z_ARRVAL_P(dest_zval) : NULL;
4046 if ((thash && GC_IS_RECURSIVE(thash)) || (src_entry == dest_entry && Z_ISREF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
4047 zend_throw_error(NULL, "Recursion detected");
4048 return 0;
4049 }
4050
4051 ZEND_ASSERT(!Z_ISREF_P(dest_entry) || Z_REFCOUNT_P(dest_entry) > 1);
4052 dest_zval = dest_entry;
4053
4054 if (Z_TYPE_P(dest_zval) == IS_NULL) {
4055 convert_to_array(dest_zval);
4056 add_next_index_null(dest_zval);
4057 } else {
4058 convert_to_array(dest_zval);
4059 }
4060 SEPARATE_ZVAL(dest_zval);
4061
4062 ZVAL_UNDEF(&tmp);
4063 if (Z_TYPE_P(src_zval) == IS_OBJECT) {
4064 ZVAL_COPY(&tmp, src_zval);
4065 convert_to_array(&tmp);
4066 src_zval = &tmp;
4067 }
4068 if (Z_TYPE_P(src_zval) == IS_ARRAY) {
4069 if (thash) {
4071 }
4072 ret = php_array_merge_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval));
4073 if (thash) {
4075 }
4076 if (!ret) {
4077 return 0;
4078 }
4079 } else {
4080 Z_TRY_ADDREF_P(src_zval);
4081 zval *zv = zend_hash_next_index_insert(Z_ARRVAL_P(dest_zval), src_zval);
4082 if (EXPECTED(!zv)) {
4083 Z_TRY_DELREF_P(src_zval);
4085 return 0;
4086 }
4087 }
4088 zval_ptr_dtor(&tmp);
4089 } else {
4090 zval *zv = zend_hash_add_new(dest, string_key, src_entry);
4092 }
4093 } else {
4094 zval *zv = zend_hash_next_index_insert(dest, src_entry);
4095 if (UNEXPECTED(!zv)) {
4097 return 0;
4098 }
4100 }
4102 return 1;
4103}
4104/* }}} */
4105
4106PHPAPI int php_array_merge(HashTable *dest, HashTable *src) /* {{{ */
4107{
4108 zval *src_entry;
4109 zend_string *string_key;
4110
4111 if (HT_IS_PACKED(dest) && HT_IS_PACKED(src)) {
4112 zend_hash_extend(dest, zend_hash_num_elements(dest) + zend_hash_num_elements(src), 1);
4113 ZEND_HASH_FILL_PACKED(dest) {
4114 ZEND_HASH_PACKED_FOREACH_VAL(src, src_entry) {
4115 if (UNEXPECTED(Z_ISREF_P(src_entry)) &&
4116 UNEXPECTED(Z_REFCOUNT_P(src_entry) == 1)) {
4117 src_entry = Z_REFVAL_P(src_entry);
4118 }
4119 Z_TRY_ADDREF_P(src_entry);
4120 ZEND_HASH_FILL_ADD(src_entry);
4123 } else {
4124 ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
4125 if (UNEXPECTED(Z_ISREF_P(src_entry) &&
4126 Z_REFCOUNT_P(src_entry) == 1)) {
4127 src_entry = Z_REFVAL_P(src_entry);
4128 }
4129 Z_TRY_ADDREF_P(src_entry);
4130 if (string_key) {
4131 zend_hash_update(dest, string_key, src_entry);
4132 } else {
4133 zend_hash_next_index_insert_new(dest, src_entry);
4134 }
4136 }
4137 return 1;
4138}
4139/* }}} */
4140
4142{
4143 zval *src_entry, *dest_entry, *src_zval, *dest_zval;
4144 zend_string *string_key;
4145 zend_ulong num_key;
4146 int ret;
4147
4148 ZEND_HASH_FOREACH_KEY_VAL(src, num_key, string_key, src_entry) {
4149 src_zval = src_entry;
4150 ZVAL_DEREF(src_zval);
4151 if (string_key) {
4152 if (Z_TYPE_P(src_zval) != IS_ARRAY ||
4153 (dest_entry = zend_hash_find_known_hash(dest, string_key)) == NULL ||
4154 (Z_TYPE_P(dest_entry) != IS_ARRAY &&
4155 (!Z_ISREF_P(dest_entry) || Z_TYPE_P(Z_REFVAL_P(dest_entry)) != IS_ARRAY))) {
4156
4157 zval *zv = zend_hash_update(dest, string_key, src_entry);
4159 continue;
4160 }
4161 } else {
4162 if (Z_TYPE_P(src_zval) != IS_ARRAY ||
4163 (dest_entry = zend_hash_index_find(dest, num_key)) == NULL ||
4164 (Z_TYPE_P(dest_entry) != IS_ARRAY &&
4165 (!Z_ISREF_P(dest_entry) || Z_TYPE_P(Z_REFVAL_P(dest_entry)) != IS_ARRAY))) {
4166
4167 zval *zv = zend_hash_index_update(dest, num_key, src_entry);
4169 continue;
4170 }
4171 }
4172
4173 dest_zval = dest_entry;
4174 ZVAL_DEREF(dest_zval);
4175 if (Z_IS_RECURSIVE_P(dest_zval) ||
4176 Z_IS_RECURSIVE_P(src_zval) ||
4177 (Z_ISREF_P(src_entry) && Z_ISREF_P(dest_entry) && Z_REF_P(src_entry) == Z_REF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
4178 zend_throw_error(NULL, "Recursion detected");
4179 return 0;
4180 }
4181
4182 ZEND_ASSERT(!Z_ISREF_P(dest_entry) || Z_REFCOUNT_P(dest_entry) > 1);
4183 SEPARATE_ZVAL(dest_entry);
4184 dest_zval = dest_entry;
4185
4186 if (Z_REFCOUNTED_P(dest_zval)) {
4187 Z_PROTECT_RECURSION_P(dest_zval);
4188 }
4189 if (Z_REFCOUNTED_P(src_zval)) {
4190 Z_PROTECT_RECURSION_P(src_zval);
4191 }
4192
4193 ret = php_array_replace_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval));
4194
4195 if (Z_REFCOUNTED_P(dest_zval)) {
4196 Z_UNPROTECT_RECURSION_P(dest_zval);
4197 }
4198 if (Z_REFCOUNTED_P(src_zval)) {
4199 Z_UNPROTECT_RECURSION_P(src_zval);
4200 }
4201
4202 if (!ret) {
4203 return 0;
4204 }
4206
4207 return 1;
4208}
4209/* }}} */
4210
4211static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) /* {{{ */
4212{
4213 zval *args = NULL;
4214 zval *arg;
4215 uint32_t argc, i;
4216 HashTable *dest;
4217
4219 Z_PARAM_VARIADIC('+', args, argc)
4221
4222
4223 for (i = 0; i < argc; i++) {
4224 zval *arg = args + i;
4225
4226 if (Z_TYPE_P(arg) != IS_ARRAY) {
4227 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(arg));
4228 RETURN_THROWS();
4229 }
4230 }
4231
4232 /* copy first array if necessary */
4233 arg = args;
4234 bool in_place = zend_may_modify_arg_in_place(arg);
4235 if (in_place) {
4236 dest = Z_ARRVAL_P(arg);
4237 } else {
4238 dest = zend_array_dup(Z_ARRVAL_P(arg));
4239 }
4240
4241 ZVAL_ARR(return_value, dest);
4242
4243 if (recursive) {
4244 for (i = 1; i < argc; i++) {
4245 arg = args + i;
4247 }
4248 } else {
4249 for (i = 1; i < argc; i++) {
4250 arg = args + i;
4252 }
4253 }
4254
4255 if (in_place) {
4256 GC_ADDREF(dest);
4257 }
4258}
4259/* }}} */
4260
4261static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) /* {{{ */
4262{
4263 zval *args = NULL;
4264 zval *arg;
4265 uint32_t argc, i;
4266 zval *src_entry;
4267 HashTable *src, *dest;
4268 uint32_t count = 0;
4269
4271 Z_PARAM_VARIADIC('+', args, argc)
4273
4274 if (argc == 0) {
4276 }
4277
4278 for (i = 0; i < argc; i++) {
4279 zval *arg = args + i;
4280
4281 if (Z_TYPE_P(arg) != IS_ARRAY) {
4282 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(arg));
4283 RETURN_THROWS();
4284 }
4285 count += zend_hash_num_elements(Z_ARRVAL_P(arg));
4286 }
4287
4288 if (argc == 2) {
4289 zval *ret = NULL;
4290
4291 if (zend_hash_num_elements(Z_ARRVAL(args[0])) == 0) {
4292 ret = &args[1];
4293 } else if (zend_hash_num_elements(Z_ARRVAL(args[1])) == 0) {
4294 ret = &args[0];
4295 }
4296 if (ret) {
4297 if (HT_IS_PACKED(Z_ARRVAL_P(ret))) {
4300 return;
4301 }
4302 } else {
4303 bool copy = 1;
4304 zend_string *string_key;
4305
4307 if (!string_key) {
4308 copy = 0;
4309 break;
4310 }
4312 if (copy) {
4314 return;
4315 }
4316 }
4317 }
4318 }
4319
4320 arg = args;
4321 src = Z_ARRVAL_P(arg);
4322 /* copy first array if necessary */
4323 bool in_place = false;
4324 if (HT_IS_PACKED(src)) {
4325 /* Note: If it has holes, it might get sequentialized */
4326 if (HT_IS_WITHOUT_HOLES(src) && zend_may_modify_arg_in_place(arg)) {
4327 dest = src;
4328 in_place = true;
4329 ZVAL_ARR(return_value, dest);
4330 } else {
4332 dest = Z_ARRVAL_P(return_value);
4333
4335 ZEND_HASH_FILL_PACKED(dest) {
4336 ZEND_HASH_PACKED_FOREACH_VAL(src, src_entry) {
4337 if (UNEXPECTED(Z_ISREF_P(src_entry) &&
4338 Z_REFCOUNT_P(src_entry) == 1)) {
4339 src_entry = Z_REFVAL_P(src_entry);
4340 }
4341 Z_TRY_ADDREF_P(src_entry);
4342 ZEND_HASH_FILL_ADD(src_entry);
4345 }
4346 } else {
4348 dest = Z_ARRVAL_P(return_value);
4349
4350 zend_string *string_key;
4352 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
4353 if (UNEXPECTED(Z_ISREF_P(src_entry) &&
4354 Z_REFCOUNT_P(src_entry) == 1)) {
4355 src_entry = Z_REFVAL_P(src_entry);
4356 }
4357 Z_TRY_ADDREF_P(src_entry);
4358 if (EXPECTED(string_key)) {
4359 _zend_hash_append(dest, string_key, src_entry);
4360 } else {
4361 zend_hash_next_index_insert_new(dest, src_entry);
4362 }
4364 }
4365 if (recursive) {
4366 for (i = 1; i < argc; i++) {
4367 arg = args + i;
4369 }
4370 } else {
4371 for (i = 1; i < argc; i++) {
4372 arg = args + i;
4374 }
4375 }
4376
4377 if (in_place) {
4378 GC_ADDREF(dest);
4379 }
4380}
4381/* }}} */
4382
4383/* {{{ Merges elements from passed arrays into one array */
4385{
4386 php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4387}
4388/* }}} */
4389
4390/* {{{ Recursively merges elements from passed arrays into one array */
4392{
4393 php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4394}
4395/* }}} */
4396
4397/* {{{ Replaces elements from passed arrays into one array */
4399{
4400 php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4401}
4402/* }}} */
4403
4404/* {{{ Recursively replaces elements from passed arrays into one array */
4406{
4407 php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4408}
4409/* }}} */
4410
4411/* {{{ Return just the keys from the input array, optionally only for the specified search_value */
4413{
4414 zval *input, /* Input array */
4415 *search_value = NULL, /* Value to search for */
4416 *entry, /* An entry in the input array */
4417 new_val; /* New value */
4418 bool strict = 0; /* do strict comparison */
4419 zend_ulong num_idx;
4420 zend_string *str_idx;
4421 zend_array *arrval;
4422 zend_ulong elem_count;
4423
4425 Z_PARAM_ARRAY(input)
4427 Z_PARAM_ZVAL(search_value)
4428 Z_PARAM_BOOL(strict)
4430 arrval = Z_ARRVAL_P(input);
4431 elem_count = zend_hash_num_elements(arrval);
4432
4433 /* Base case: empty input */
4434 if (!elem_count) {
4435 RETURN_COPY(input);
4436 }
4437
4438 /* Initialize return array */
4439 if (search_value != NULL) {
4441
4442 if (strict) {
4443 ZEND_HASH_FOREACH_KEY_VAL(arrval, num_idx, str_idx, entry) {
4444 ZVAL_DEREF(entry);
4445 if (fast_is_identical_function(search_value, entry)) {
4446 if (str_idx) {
4447 ZVAL_STR_COPY(&new_val, str_idx);
4448 } else {
4449 ZVAL_LONG(&new_val, num_idx);
4450 }
4452 }
4454 } else {
4455 ZEND_HASH_FOREACH_KEY_VAL(arrval, num_idx, str_idx, entry) {
4456 if (fast_equal_check_function(search_value, entry)) {
4457 if (str_idx) {
4458 ZVAL_STR_COPY(&new_val, str_idx);
4459 } else {
4460 ZVAL_LONG(&new_val, num_idx);
4461 }
4463 }
4465 }
4466 } else {
4467 array_init_size(return_value, elem_count);
4470 if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval)) {
4471 /* Optimistic case: range(0..n-1) for vector-like packed array */
4472 zend_ulong lval = 0;
4473
4474 for (; lval < elem_count; ++lval) {
4477 }
4478 } else {
4479 /* Go through input array and add keys to the return array */
4480 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
4481 if (str_idx) {
4483 } else {
4484 ZEND_HASH_FILL_SET_LONG(num_idx);
4485 }
4488 }
4490 }
4491}
4492/* }}} */
4493
4494/* {{{ Get the key of the first element of the array */
4496{
4497 zval *stack; /* Input stack */
4498
4500 Z_PARAM_ARRAY(stack)
4502
4503 HashTable *target_hash = Z_ARRVAL_P (stack);
4504 HashPosition pos = 0;
4506}
4507/* }}} */
4508
4509/* {{{ Get the key of the last element of the array */
4511{
4512 zval *stack; /* Input stack */
4514
4516 Z_PARAM_ARRAY(stack)
4518
4519 HashTable *target_hash = Z_ARRVAL_P (stack);
4522}
4523/* }}} */
4524
4525/* {{{ Return just the values from the input array */
4527{
4528 zval *input; /* Input array */
4529 zend_array *arrval;
4530 zend_long arrlen;
4531
4533 Z_PARAM_ARRAY(input)
4535
4536 arrval = Z_ARRVAL_P(input);
4537
4538 /* Return empty input as is */
4539 arrlen = zend_hash_num_elements(arrval);
4540 if (!arrlen) {
4542 }
4543
4544 /* Return vector-like packed arrays as-is */
4545 if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval) &&
4546 arrval->nNextFreeElement == arrlen) {
4547 RETURN_COPY(input);
4548 }
4549
4551}
4552/* }}} */
4553
4554/* {{{ Return the value as key and the frequency of that value in input as value */
4556{
4557 zval *input, /* Input array */
4558 *entry, /* An entry in the input array */
4559 *tmp;
4560 HashTable *myht;
4561
4563 Z_PARAM_ARRAY(input)
4565
4566 /* Initialize return array */
4568
4569 /* Go through input array and add values to the return array */
4570 myht = Z_ARRVAL_P(input);
4571 ZEND_HASH_FOREACH_VAL(myht, entry) {
4572 ZVAL_DEREF(entry);
4573 if (Z_TYPE_P(entry) == IS_LONG) {
4574 if ((tmp = zend_hash_index_find(Z_ARRVAL_P(return_value), Z_LVAL_P(entry))) == NULL) {
4575 zval data;
4576 ZVAL_LONG(&data, 1);
4578 } else {
4579 Z_LVAL_P(tmp)++;
4580 }
4581 } else if (Z_TYPE_P(entry) == IS_STRING) {
4582 if ((tmp = zend_symtable_find(Z_ARRVAL_P(return_value), Z_STR_P(entry))) == NULL) {
4583 zval data;
4584 ZVAL_LONG(&data, 1);
4585 zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
4586 } else {
4587 Z_LVAL_P(tmp)++;
4588 }
4589 } else {
4590 php_error_docref(NULL, E_WARNING, "Can only count string and integer values, entry skipped");
4591 }
4593}
4594/* }}} */
4595
4596static inline zval *array_column_fetch_prop(zval *data, zend_string *name_str, zend_long name_long, void **cache_slot, zval *rv) /* {{{ */
4597{
4598 zval *prop = NULL;
4599
4600 if (Z_TYPE_P(data) == IS_OBJECT) {
4601 zend_string *tmp_str;
4602 /* If name is an integer convert integer to string */
4603 if (name_str == NULL) {
4604 tmp_str = zend_long_to_str(name_long);
4605 } else {
4606 tmp_str = zend_string_copy(name_str);
4607 }
4608 /* The has_property check is first performed in "exists" mode (which returns true for
4609 * properties that are null but exist) and then in "has" mode to handle objects that
4610 * implement __isset (which is not called in "exists" mode). */
4611 if (Z_OBJ_HANDLER_P(data, has_property)(Z_OBJ_P(data), tmp_str, ZEND_PROPERTY_EXISTS, cache_slot)
4612 || Z_OBJ_HANDLER_P(data, has_property)(Z_OBJ_P(data), tmp_str, ZEND_PROPERTY_ISSET, cache_slot)) {
4613 prop = Z_OBJ_HANDLER_P(data, read_property)(Z_OBJ_P(data), tmp_str, BP_VAR_R, cache_slot, rv);
4614 if (prop) {
4615 ZVAL_DEREF(prop);
4616 if (prop != rv) {
4617 Z_TRY_ADDREF_P(prop);
4618 }
4619 }
4620 }
4621 zend_string_release(tmp_str);
4622 } else if (Z_TYPE_P(data) == IS_ARRAY) {
4623 /* Name is a string */
4624 if (name_str != NULL) {
4625 prop = zend_symtable_find(Z_ARRVAL_P(data), name_str);
4626 } else {
4627 prop = zend_hash_index_find(Z_ARRVAL_P(data), name_long);
4628 }
4629 if (prop) {
4630 ZVAL_DEREF(prop);
4631 Z_TRY_ADDREF_P(prop);
4632 }
4633 }
4634
4635 return prop;
4636}
4637/* }}} */
4638
4639/* {{{ Return the values from a single column in the input array, identified by the
4640 value_key and optionally indexed by the index_key */
4642{
4643 HashTable *input;
4644 zval *colval, *data, rv;
4645 zend_string *column_str = NULL;
4646 zend_long column_long = 0;
4647 bool column_is_null = 0;
4648 zend_string *index_str = NULL;
4649 zend_long index_long = 0;
4650 bool index_is_null = 1;
4651
4653 Z_PARAM_ARRAY_HT(input)
4654 Z_PARAM_STR_OR_LONG_OR_NULL(column_str, column_long, column_is_null)
4656 Z_PARAM_STR_OR_LONG_OR_NULL(index_str, index_long, index_is_null)
4658
4659 void* cache_slot_column[3] = { NULL, NULL, NULL };
4660 void* cache_slot_index[3] = { NULL, NULL, NULL };
4661
4662 array_init_size(return_value, zend_hash_num_elements(input));
4663 /* Index param is not passed */
4664 if (index_is_null) {
4667 ZEND_HASH_FOREACH_VAL(input, data) {
4669 if (column_is_null) {
4671 colval = data;
4672 } else if ((colval = array_column_fetch_prop(data, column_str, column_long, cache_slot_column, &rv)) == NULL) {
4673 continue;
4674 }
4675 ZEND_HASH_FILL_ADD(colval);
4678 } else {
4679 ZEND_HASH_FOREACH_VAL(input, data) {
4681
4682 if (column_is_null) {
4684 colval = data;
4685 } else if ((colval = array_column_fetch_prop(data, column_str, column_long, cache_slot_column, &rv)) == NULL) {
4686 continue;
4687 }
4688
4689 zval rv;
4690 zval *keyval = array_column_fetch_prop(data, index_str, index_long, cache_slot_index, &rv);
4691 if (keyval) {
4692 array_set_zval_key(Z_ARRVAL_P(return_value), keyval, colval);
4693 zval_ptr_dtor(colval);
4694 zval_ptr_dtor(keyval);
4695 } else {
4697 }
4699 }
4700}
4701/* }}} */
4702
4703/* {{{ Return input as a new array with the order of the entries reversed */
4705{
4706 zval *input, /* Input array */
4707 *entry; /* An entry in the input array */
4708 zend_string *string_key;
4709 zend_ulong num_key;
4710 bool preserve_keys = 0; /* whether to preserve keys */
4711
4713 Z_PARAM_ARRAY(input)
4715 Z_PARAM_BOOL(preserve_keys)
4717
4718 /* Initialize return array */
4719 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
4720 if (HT_IS_PACKED(Z_ARRVAL_P(input)) && !preserve_keys) {
4724 if (UNEXPECTED(Z_ISREF_P(entry) &&
4725 Z_REFCOUNT_P(entry) == 1)) {
4726 entry = Z_REFVAL_P(entry);
4727 }
4728 Z_TRY_ADDREF_P(entry);
4729 ZEND_HASH_FILL_ADD(entry);
4732 } else {
4733 ZEND_HASH_REVERSE_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, string_key, entry) {
4734 if (string_key) {
4735 entry = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, entry);
4736 } else {
4737 if (preserve_keys) {
4738 entry = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, entry);
4739 } else {
4741 }
4742 }
4743 zval_add_ref(entry);
4745 }
4746}
4747/* }}} */
4748
4749/* {{{ Returns a copy of input array padded with pad_value to size pad_size */
4751{
4752 zval *input; /* Input array */
4753 zval *pad_value; /* Padding value obviously */
4754 zend_long pad_size; /* Size to pad to */
4755 zend_long pad_size_abs; /* Absolute value of pad_size */
4756 zend_long input_size; /* Size of the input array */
4757 zend_long num_pads; /* How many pads do we need */
4758 zend_long i;
4760 zval *value;
4761
4763 Z_PARAM_ARRAY(input)
4764 Z_PARAM_LONG(pad_size)
4765 Z_PARAM_ZVAL(pad_value)
4767
4768 if (pad_size < Z_L(-HT_MAX_SIZE) || pad_size > Z_L(HT_MAX_SIZE)) {
4769 zend_argument_value_error(2, "must not exceed the maximum allowed array size");
4770 RETURN_THROWS();
4771 }
4772
4773 /* Do some initial calculations */
4774 input_size = zend_hash_num_elements(Z_ARRVAL_P(input));
4775 pad_size_abs = ZEND_ABS(pad_size);
4776
4777 if (input_size >= pad_size_abs) {
4778 /* Copy the original array */
4779 ZVAL_COPY(return_value, input);
4780 return;
4781 }
4782
4783 num_pads = pad_size_abs - input_size;
4784 if (Z_REFCOUNTED_P(pad_value)) {
4785 GC_ADDREF_EX(Z_COUNTED_P(pad_value), num_pads);
4786 }
4787
4788 array_init_size(return_value, pad_size_abs);
4789 if (HT_IS_PACKED(Z_ARRVAL_P(input))) {
4791
4792 if (pad_size < 0) {
4794 for (i = 0; i < num_pads; i++) {
4795 ZEND_HASH_FILL_ADD(pad_value);
4796 }
4798 }
4799
4806
4807 if (pad_size > 0) {
4809 for (i = 0; i < num_pads; i++) {
4810 ZEND_HASH_FILL_ADD(pad_value);
4811 }
4813 }
4814 } else {
4815 if (pad_size < 0) {
4816 for (i = 0; i < num_pads; i++) {
4818 }
4819 }
4820
4823 if (key) {
4825 } else {
4827 }
4829
4830 if (pad_size > 0) {
4831 for (i = 0; i < num_pads; i++) {
4833 }
4834 }
4835 }
4836}
4837/* }}} */
4838
4839/* {{{ Return array with key <-> value flipped */
4841{
4842 zval *array, *entry, data;
4843 zend_ulong num_idx;
4844 zend_string *str_idx;
4845
4847 Z_PARAM_ARRAY(array)
4849
4850 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
4851
4852 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
4853 ZVAL_DEREF(entry);
4854 if (Z_TYPE_P(entry) == IS_LONG) {
4855 if (str_idx) {
4856 ZVAL_STR_COPY(&data, str_idx);
4857 } else {
4858 ZVAL_LONG(&data, num_idx);
4859 }
4861 } else if (Z_TYPE_P(entry) == IS_STRING) {
4862 if (str_idx) {
4863 ZVAL_STR_COPY(&data, str_idx);
4864 } else {
4865 ZVAL_LONG(&data, num_idx);
4866 }
4867 zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
4868 } else {
4869 php_error_docref(NULL, E_WARNING, "Can only flip string and integer values, entry skipped");
4870 }
4872}
4873/* }}} */
4874
4875/* {{{ Returns an array with all string keys lowercased [or uppercased] */
4877{
4878 zval *array, *entry;
4879 zend_string *string_key;
4880 zend_string *new_key;
4881 zend_ulong num_key;
4882 zend_long change_to_upper=0;
4883
4885 Z_PARAM_ARRAY(array)
4887 Z_PARAM_LONG(change_to_upper)
4889
4890 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
4891
4892 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, entry) {
4893 if (!string_key) {
4894 entry = zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry);
4895 } else {
4896 if (change_to_upper) {
4897 new_key = zend_string_toupper(string_key);
4898 } else {
4899 new_key = zend_string_tolower(string_key);
4900 }
4901 entry = zend_hash_update(Z_ARRVAL_P(return_value), new_key, entry);
4902 zend_string_release_ex(new_key, 0);
4903 }
4904
4905 zval_add_ref(entry);
4907}
4908/* }}} */
4909
4912 unsigned int i;
4913};
4914
4915static void array_bucketindex_swap(void *p, void *q)
4916{
4917 struct bucketindex *f = (struct bucketindex *)p;
4918 struct bucketindex *g = (struct bucketindex *)q;
4919 struct bucketindex t;
4920 t = *f;
4921 *f = *g;
4922 *g = t;
4923}
4924
4925/* {{{ Removes duplicate values from array */
4927{
4928 zval *array;
4929 Bucket *p;
4930 zend_long sort_type = PHP_SORT_STRING;
4932 struct bucketindex *arTmp, *cmpdata, *lastkept;
4933 uint32_t i, idx;
4934
4936 Z_PARAM_ARRAY(array)
4938 Z_PARAM_LONG(sort_type)
4940
4941 if (Z_ARRVAL_P(array)->nNumOfElements <= 1) { /* nothing to do */
4942 ZVAL_COPY(return_value, array);
4943 return;
4944 }
4945
4946 if (sort_type == PHP_SORT_STRING) {
4947 HashTable seen;
4948 zend_long num_key;
4949 zend_string *str_key;
4950 zval *val;
4951
4952 zend_hash_init(&seen, zend_hash_num_elements(Z_ARRVAL_P(array)), NULL, NULL, 0);
4954
4955 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, str_key, val) {
4956 zval *retval;
4957 if (Z_TYPE_P(val) == IS_STRING) {
4959 } else {
4960 zend_string *tmp_str_val;
4961 zend_string *str_val = zval_get_tmp_string(val, &tmp_str_val);
4962 retval = zend_hash_add_empty_element(&seen, str_val);
4963 zend_tmp_string_release(tmp_str_val);
4964 }
4965
4966 if (retval) {
4967 /* First occurrence of the value */
4968 if (UNEXPECTED(Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1)) {
4969 ZVAL_DEREF(val);
4970 }
4972
4973 if (str_key) {
4975 } else {
4977 }
4978 }
4980
4981 zend_hash_destroy(&seen);
4982 return;
4983 }
4984
4985 cmp = php_get_data_compare_func_unstable(sort_type, 0);
4986
4987 bool in_place = zend_may_modify_arg_in_place(array);
4988 if (in_place) {
4989 RETVAL_ARR(Z_ARRVAL_P(array));
4990 } else {
4992 }
4993
4994 /* create and sort array with pointers to the target_hash buckets */
4995 arTmp = pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), GC_FLAGS(Z_ARRVAL_P(array)) & IS_ARRAY_PERSISTENT);
4996 if (HT_IS_PACKED(Z_ARRVAL_P(array))) {
4997 zval *zv = Z_ARRVAL_P(array)->arPacked;
4998 for (i = 0, idx = 0; idx < Z_ARRVAL_P(array)->nNumUsed; idx++, zv++) {
4999 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
5000 ZVAL_COPY_VALUE(&arTmp[i].b.val, zv);
5001 arTmp[i].b.h = idx;
5002 arTmp[i].b.key = NULL;
5003 arTmp[i].i = i;
5004 i++;
5005 }
5006 } else {
5007 p = Z_ARRVAL_P(array)->arData;
5008 for (i = 0, idx = 0; idx < Z_ARRVAL_P(array)->nNumUsed; idx++, p++) {
5009 if (Z_TYPE(p->val) == IS_UNDEF) continue;
5010 arTmp[i].b = *p;
5011 arTmp[i].i = i;
5012 i++;
5013 }
5014 }
5015 ZVAL_UNDEF(&arTmp[i].b.val);
5016 zend_sort((void *) arTmp, i, sizeof(struct bucketindex),
5017 (compare_func_t) cmp, (swap_func_t) array_bucketindex_swap);
5018 /* go through the sorted array and delete duplicates from the copy */
5019 lastkept = arTmp;
5020 for (cmpdata = arTmp + 1; Z_TYPE(cmpdata->b.val) != IS_UNDEF; cmpdata++) {
5021 if (cmp(&lastkept->b, &cmpdata->b)) {
5022 lastkept = cmpdata;
5023 } else {
5024 if (lastkept->i > cmpdata->i) {
5025 p = &lastkept->b;
5026 lastkept = cmpdata;
5027 } else {
5028 p = &cmpdata->b;
5029 }
5030 if (p->key == NULL) {
5032 } else {
5034 }
5035 }
5036 }
5038
5039 if (in_place) {
5041 }
5042}
5043/* }}} */
5044
5045static int zval_compare(zval *first, zval *second) /* {{{ */
5046{
5047 return string_compare_function(first, second);
5048}
5049/* }}} */
5050
5051static int zval_user_compare(zval *a, zval *b) /* {{{ */
5052{
5053 zval args[2];
5054 zval retval;
5055
5056 ZVAL_COPY_VALUE(&args[0], a);
5057 ZVAL_COPY_VALUE(&args[1], b);
5058
5059 BG(user_compare_fci).param_count = 2;
5060 BG(user_compare_fci).params = args;
5061 BG(user_compare_fci).retval = &retval;
5062
5063 if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
5064 zend_long ret = zval_get_long(&retval);
5066 return ZEND_NORMALIZE_BOOL(ret);
5067 } else {
5068 return 0;
5069 }
5070}
5071/* }}} */
5072
5073static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type) /* {{{ */
5074{
5075 uint32_t argc, i;
5076 zval *args;
5077 int (*intersect_data_compare_func)(zval *, zval *) = NULL;
5078 bool ok;
5079 zval *val, *data;
5080 char *param_spec;
5082 zend_ulong h;
5083
5084 /* Get the argument count */
5085 argc = ZEND_NUM_ARGS();
5086 if (data_compare_type == INTERSECT_COMP_DATA_USER) {
5087 /* INTERSECT_COMP_DATA_USER - array_uintersect_assoc() */
5088 param_spec = "+f";
5089 intersect_data_compare_func = zval_user_compare;
5090 } else {
5091 /* INTERSECT_COMP_DATA_NONE - array_intersect_key()
5092 INTERSECT_COMP_DATA_INTERNAL - array_intersect_assoc() */
5093 param_spec = "+";
5094
5095 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
5096 intersect_data_compare_func = zval_compare;
5097 }
5098 }
5099
5100 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
5101 RETURN_THROWS();
5102 }
5103
5104 for (i = 0; i < argc; i++) {
5105 if (Z_TYPE(args[i]) != IS_ARRAY) {
5106 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i]));
5107 RETURN_THROWS();
5108 }
5109 }
5110
5112
5113 /* Iterate over keys of the first array, to compute keys that are in all of the other arrays. */
5115 if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) {
5116 val = Z_REFVAL_P(val);
5117 }
5118 if (key == NULL) {
5119 ok = 1;
5120 for (i = 1; i < argc; i++) {
5121 if ((data = zend_hash_index_find(Z_ARRVAL(args[i]), h)) == NULL ||
5122 (intersect_data_compare_func &&
5123 intersect_data_compare_func(val, data) != 0)
5124 ) {
5125 ok = 0;
5126 break;
5127 }
5128 }
5129 if (ok) {
5132 }
5133 } else {
5134 ok = 1;
5135 for (i = 1; i < argc; i++) {
5137 (intersect_data_compare_func &&
5138 intersect_data_compare_func(val, data) != 0)
5139 ) {
5140 ok = 0;
5141 break;
5142 }
5143 }
5144 if (ok) {
5147 }
5148 }
5150}
5151/* }}} */
5152
5153static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type) /* {{{ */
5154{
5155 zval *args = NULL;
5156 HashTable *hash;
5157 uint32_t arr_argc, i;
5158 int c = 0;
5159 uint32_t idx;
5160 Bucket **lists, *list, **ptrs, *p;
5161 char *param_spec;
5162 zend_fcall_info fci1, fci2;
5164 zend_fcall_info *fci_key = NULL, *fci_data;
5165 zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache;
5167 bool in_place = false;
5168
5169 bucket_compare_func_t intersect_key_compare_func;
5170 bucket_compare_func_t intersect_data_compare_func;
5171
5172 if (behavior == INTERSECT_NORMAL) {
5173 intersect_key_compare_func = php_array_key_compare_string;
5174
5175 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
5176 /* array_intersect() */
5177 param_spec = "+";
5178 intersect_data_compare_func = php_array_data_compare_string_unstable;
5179 } else if (data_compare_type == INTERSECT_COMP_DATA_USER) {
5180 /* array_uintersect() */
5181 param_spec = "+f";
5182 intersect_data_compare_func = php_array_user_compare_unstable;
5183 } else {
5184 ZEND_ASSERT(0 && "Invalid data_compare_type");
5185 return;
5186 }
5187
5188 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
5189 RETURN_THROWS();
5190 }
5191 fci_data = &fci1;
5192 fci_data_cache = &fci1_cache;
5193
5194 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
5195 /* INTERSECT_KEY is subset of INTERSECT_ASSOC. When having the former
5196 * no comparison of the data is done (part of INTERSECT_ASSOC) */
5197
5198 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
5199 /* array_intersect_assoc() or array_intersect_key() */
5200 param_spec = "+";
5201 intersect_key_compare_func = php_array_key_compare_string_unstable;
5202 intersect_data_compare_func = php_array_data_compare_string_unstable;
5203 } else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
5204 /* array_uintersect_assoc() */
5205 param_spec = "+f";
5206 intersect_key_compare_func = php_array_key_compare_string_unstable;
5207 intersect_data_compare_func = php_array_user_compare_unstable;
5208 fci_data = &fci1;
5209 fci_data_cache = &fci1_cache;
5210 } else if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_USER) {
5211 /* array_intersect_uassoc() or array_intersect_ukey() */
5212 param_spec = "+f";
5213 intersect_key_compare_func = php_array_user_key_compare_unstable;
5214 intersect_data_compare_func = php_array_data_compare_string_unstable;
5215 fci_key = &fci1;
5216 fci_key_cache = &fci1_cache;
5217 } else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_USER) {
5218 /* array_uintersect_uassoc() */
5219 param_spec = "+ff";
5220 intersect_key_compare_func = php_array_user_key_compare_unstable;
5221 intersect_data_compare_func = php_array_user_compare_unstable;
5222 fci_data = &fci1;
5223 fci_data_cache = &fci1_cache;
5224 fci_key = &fci2;
5225 fci_key_cache = &fci2_cache;
5226 } else {
5227 ZEND_ASSERT(0 && "Invalid data_compare_type / key_compare_type");
5228 return;
5229 }
5230
5231 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
5232 RETURN_THROWS();
5233 }
5234
5235 } else {
5236 ZEND_ASSERT(0 && "Invalid behavior");
5237 return;
5238 }
5239
5241
5242 /* for each argument, create and sort list with pointers to the hash buckets */
5243 lists = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
5244 ptrs = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
5245
5246 if (behavior == INTERSECT_NORMAL && data_compare_type == INTERSECT_COMP_DATA_USER) {
5247 BG(user_compare_fci) = *fci_data;
5248 BG(user_compare_fci_cache) = *fci_data_cache;
5249 } else if ((behavior & INTERSECT_ASSOC) && key_compare_type == INTERSECT_COMP_KEY_USER) {
5250 BG(user_compare_fci) = *fci_key;
5251 BG(user_compare_fci_cache) = *fci_key_cache;
5252 }
5253
5254 for (i = 0; i < arr_argc; i++) {
5255 if (Z_TYPE(args[i]) != IS_ARRAY) {
5256 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i]));
5257 arr_argc = i; /* only free up to i - 1 */
5258 goto out;
5259 }
5260 hash = Z_ARRVAL(args[i]);
5261 list = (Bucket *) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket), GC_FLAGS(hash) & IS_ARRAY_PERSISTENT);
5262 lists[i] = list;
5263 ptrs[i] = list;
5264 if (HT_IS_PACKED(hash)) {
5265 zval *zv = hash->arPacked;
5266 for (idx = 0; idx < hash->nNumUsed; idx++, zv++) {
5267 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
5268 ZVAL_COPY_VALUE(&list->val, zv);
5269 list->h = idx;
5270 list->key = NULL;
5271 list++;
5272 }
5273 } else {
5274 p = hash->arData;
5275 for (idx = 0; idx < hash->nNumUsed; idx++, p++) {
5276 if (Z_TYPE(p->val) == IS_UNDEF) continue;
5277 *list++ = *p;
5278 }
5279 }
5280 ZVAL_UNDEF(&list->val);
5281 if (hash->nNumOfElements > 1) {
5282 if (behavior == INTERSECT_NORMAL) {
5283 zend_sort((void *) lists[i], hash->nNumOfElements,
5284 sizeof(Bucket), (compare_func_t) intersect_data_compare_func,
5286 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
5287 zend_sort((void *) lists[i], hash->nNumOfElements,
5288 sizeof(Bucket), (compare_func_t) intersect_key_compare_func,
5290 }
5291 }
5292 }
5293
5294 /* copy the argument array if necessary */
5295 in_place = zend_may_modify_arg_in_place(&args[0]);
5296 if (in_place) {
5298 } else {
5300 }
5301
5302 /* go through the lists and look for common values */
5303 while (Z_TYPE(ptrs[0]->val) != IS_UNDEF) {
5304 if ((behavior & INTERSECT_ASSOC) /* triggered also when INTERSECT_KEY */
5305 && key_compare_type == INTERSECT_COMP_KEY_USER) {
5306 BG(user_compare_fci) = *fci_key;
5307 BG(user_compare_fci_cache) = *fci_key_cache;
5308 }
5309
5310 for (i = 1; i < arr_argc; i++) {
5311 if (behavior & INTERSECT_NORMAL) {
5312 while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = intersect_data_compare_func(ptrs[0], ptrs[i])))) {
5313 ptrs[i]++;
5314 }
5315 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
5316 while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = intersect_key_compare_func(ptrs[0], ptrs[i])))) {
5317 ptrs[i]++;
5318 }
5319 if ((!c && Z_TYPE(ptrs[i]->val) != IS_UNDEF) && (behavior == INTERSECT_ASSOC)) { /* only when INTERSECT_ASSOC */
5320 /* this means that ptrs[i] is not NULL so we can compare
5321 * and "c==0" is from last operation
5322 * in this branch of code we enter only when INTERSECT_ASSOC
5323 * since when we have INTERSECT_KEY compare of data is not wanted. */
5324 if (data_compare_type == INTERSECT_COMP_DATA_USER) {
5325 BG(user_compare_fci) = *fci_data;
5326 BG(user_compare_fci_cache) = *fci_data_cache;
5327 }
5328 if (intersect_data_compare_func(ptrs[0], ptrs[i]) != 0) {
5329 c = 1;
5330 if (key_compare_type == INTERSECT_COMP_KEY_USER) {
5331 BG(user_compare_fci) = *fci_key;
5332 BG(user_compare_fci_cache) = *fci_key_cache;
5333 /* When KEY_USER, the last parameter is always the callback */
5334 }
5335 /* we are going to the break */
5336 } else {
5337 /* continue looping */
5338 }
5339 }
5340 }
5341 if (Z_TYPE(ptrs[i]->val) == IS_UNDEF) {
5342 /* delete any values corresponding to remains of ptrs[0] */
5343 /* and exit because they do not present in at least one of */
5344 /* the other arguments */
5345 for (;;) {
5346 p = ptrs[0]++;
5347 if (Z_TYPE(p->val) == IS_UNDEF) {
5348 goto out;
5349 }
5350 if (p->key == NULL) {
5352 } else {
5354 }
5355 }
5356 }
5357 if (c) /* here we get if not all are equal */
5358 break;
5359 ptrs[i]++;
5360 }
5361 if (c) {
5362 /* Value of ptrs[0] not in all arguments, delete all entries */
5363 /* with value < value of ptrs[i] */
5364 for (;;) {
5365 p = ptrs[0];
5366 if (p->key == NULL) {
5368 } else {
5370 }
5371 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
5372 goto out;
5373 }
5374 if (behavior == INTERSECT_NORMAL) {
5375 if (0 <= intersect_data_compare_func(ptrs[0], ptrs[i])) {
5376 break;
5377 }
5378 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
5379 /* no need of looping because indexes are unique */
5380 break;
5381 }
5382 }
5383 } else {
5384 /* ptrs[0] is present in all the arguments */
5385 /* Skip all entries with same value as ptrs[0] */
5386 for (;;) {
5387 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
5388 goto out;
5389 }
5390 if (behavior == INTERSECT_NORMAL) {
5391 if (intersect_data_compare_func(ptrs[0] - 1, ptrs[0])) {
5392 break;
5393 }
5394 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
5395 /* no need of looping because indexes are unique */
5396 break;
5397 }
5398 }
5399 }
5400 }
5401out:
5402 for (i = 0; i < arr_argc; i++) {
5403 hash = Z_ARRVAL(args[i]);
5405 }
5406
5408
5409 efree(ptrs);
5410 efree(lists);
5411
5412 if (in_place) {
5414 }
5415}
5416/* }}} */
5417
5418/* {{{ Returns the entries of arr1 that have keys which are present in all the other arguments. Kind of equivalent to array_diff(array_keys($arr1), array_keys($arr2)[,array_keys(...)]). Equivalent of array_intersect_assoc() but does not do compare of the data. */
5423/* }}} */
5424
5425/* {{{ Returns the entries of arr1 that have keys which are present in all the other arguments. Kind of equivalent to array_diff(array_keys($arr1), array_keys($arr2)[,array_keys(...)]). The comparison of the keys is performed by a user supplied function. Equivalent of array_intersect_uassoc() but does not do compare of the data. */
5430/* }}} */
5431
5432/* {{{ Returns the entries of arr1 that have values which are present in all the other arguments */
5437/* }}} */
5438
5439/* {{{ Returns the entries of arr1 that have values which are present in all the other arguments. Data is compared by using a user-supplied callback. */
5444/* }}} */
5445
5446/* {{{ Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check */
5451/* }}} */
5452
5453/* {{{ Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check and they are compared by using a user-supplied callback. */
5458/* }}} */
5459
5460/* {{{ Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check. Data is compared by using a user-supplied callback. */
5465/* }}} */
5466
5467/* {{{ Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check. Both data and keys are compared by using user-supplied callbacks. */
5472/* }}} */
5473
5474static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type) /* {{{ */
5475{
5476 uint32_t argc, i;
5477 zval *args;
5478 int (*diff_data_compare_func)(zval *, zval *) = NULL;
5479 bool ok;
5480 zval *val, *data;
5482 zend_ulong h;
5483
5484 /* Get the argument count */
5485 argc = ZEND_NUM_ARGS();
5486 if (data_compare_type == DIFF_COMP_DATA_USER) {
5487 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+f", &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
5488 RETURN_THROWS();
5489 }
5490 diff_data_compare_func = zval_user_compare;
5491 } else {
5492 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
5493 RETURN_THROWS();
5494 }
5495 if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
5496 diff_data_compare_func = zval_compare;
5497 }
5498 }
5499
5500 for (i = 0; i < argc; i++) {
5501 if (Z_TYPE(args[i]) != IS_ARRAY) {
5502 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i]));
5503 RETURN_THROWS();
5504 }
5505 }
5506
5508
5509 /* Iterate over keys of the first array, to compute keys that aren't in the other arrays. */
5511 if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) {
5512 val = Z_REFVAL_P(val);
5513 }
5514 if (key == NULL) {
5515 ok = 1;
5516 for (i = 1; i < argc; i++) {
5517 if ((data = zend_hash_index_find(Z_ARRVAL(args[i]), h)) != NULL &&
5518 (!diff_data_compare_func ||
5519 diff_data_compare_func(val, data) == 0)
5520 ) {
5521 ok = 0;
5522 break;
5523 }
5524 }
5525 if (ok) {
5528 }
5529 } else {
5530 ok = 1;
5531 for (i = 1; i < argc; i++) {
5533 (!diff_data_compare_func ||
5534 diff_data_compare_func(val, data) == 0)
5535 ) {
5536 ok = 0;
5537 break;
5538 }
5539 }
5540 if (ok) {
5543 }
5544 }
5546}
5547/* }}} */
5548
5549static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type) /* {{{ */
5550{
5551 zval *args = NULL;
5552 HashTable *hash;
5553 uint32_t arr_argc, i;
5554 int c;
5555 uint32_t idx;
5556 Bucket **lists, *list, **ptrs, *p;
5557 char *param_spec;
5558 zend_fcall_info fci1, fci2;
5560 zend_fcall_info *fci_key = NULL, *fci_data;
5561 zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache;
5563
5564 bucket_compare_func_t diff_key_compare_func;
5565 bucket_compare_func_t diff_data_compare_func;
5566
5567 if (behavior == DIFF_NORMAL) {
5568 diff_key_compare_func = php_array_key_compare_string_unstable;
5569
5570 if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
5571 /* array_diff */
5572 param_spec = "+";
5573 diff_data_compare_func = php_array_data_compare_string_unstable;
5574 } else if (data_compare_type == DIFF_COMP_DATA_USER) {
5575 /* array_udiff */
5576 param_spec = "+f";
5577 diff_data_compare_func = php_array_user_compare_unstable;
5578 } else {
5579 ZEND_ASSERT(0 && "Invalid data_compare_type");
5580 return;
5581 }
5582
5583 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
5584 RETURN_THROWS();
5585 }
5586 fci_data = &fci1;
5587 fci_data_cache = &fci1_cache;
5588
5589 } else if (behavior & DIFF_ASSOC) { /* triggered also if DIFF_KEY */
5590 /* DIFF_KEY is subset of DIFF_ASSOC. When having the former
5591 * no comparison of the data is done (part of DIFF_ASSOC) */
5592
5593 if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
5594 /* array_diff_assoc() or array_diff_key() */
5595 param_spec = "+";
5596 diff_key_compare_func = php_array_key_compare_string_unstable;
5597 diff_data_compare_func = php_array_data_compare_string_unstable;
5598 } else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
5599 /* array_udiff_assoc() */
5600 param_spec = "+f";
5601 diff_key_compare_func = php_array_key_compare_string_unstable;
5602 diff_data_compare_func = php_array_user_compare_unstable;
5603 fci_data = &fci1;
5604 fci_data_cache = &fci1_cache;
5605 } else if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_USER) {
5606 /* array_diff_uassoc() or array_diff_ukey() */
5607 param_spec = "+f";
5608 diff_key_compare_func = php_array_user_key_compare_unstable;
5609 diff_data_compare_func = php_array_data_compare_string_unstable;
5610 fci_key = &fci1;
5611 fci_key_cache = &fci1_cache;
5612 } else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_USER) {
5613 /* array_udiff_uassoc() */
5614 param_spec = "+ff";
5615 diff_key_compare_func = php_array_user_key_compare_unstable;
5616 diff_data_compare_func = php_array_user_compare_unstable;
5617 fci_data = &fci1;
5618 fci_data_cache = &fci1_cache;
5619 fci_key = &fci2;
5620 fci_key_cache = &fci2_cache;
5621 } else {
5622 ZEND_ASSERT(0 && "Invalid data_compare_type / key_compare_type");
5623 return;
5624 }
5625
5626 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
5627 RETURN_THROWS();
5628 }
5629
5630 } else {
5631 ZEND_ASSERT(0 && "Invalid behavior");
5632 return;
5633 }
5634
5636
5637 /* for each argument, create and sort list with pointers to the hash buckets */
5638 lists = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
5639 ptrs = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
5640
5641 if (behavior == DIFF_NORMAL && data_compare_type == DIFF_COMP_DATA_USER) {
5642 BG(user_compare_fci) = *fci_data;
5643 BG(user_compare_fci_cache) = *fci_data_cache;
5644 } else if ((behavior & DIFF_ASSOC) && key_compare_type == DIFF_COMP_KEY_USER) {
5645 BG(user_compare_fci) = *fci_key;
5646 BG(user_compare_fci_cache) = *fci_key_cache;
5647 }
5648
5649 for (i = 0; i < arr_argc; i++) {
5650 if (Z_TYPE(args[i]) != IS_ARRAY) {
5651 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i]));
5652 arr_argc = i; /* only free up to i - 1 */
5653 goto out;
5654 }
5655 hash = Z_ARRVAL(args[i]);
5656 list = (Bucket *) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket), GC_FLAGS(hash) & IS_ARRAY_PERSISTENT);
5657 lists[i] = list;
5658 ptrs[i] = list;
5659 if (HT_IS_PACKED(hash)) {
5660 zval *zv = hash->arPacked;
5661 for (idx = 0; idx < hash->nNumUsed; idx++, zv++) {
5662 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
5663 ZVAL_COPY_VALUE(&list->val, zv);
5664 list->h = idx;
5665 list->key = NULL;
5666 list++;
5667 }
5668 } else {
5669 p = hash->arData;
5670 for (idx = 0; idx < hash->nNumUsed; idx++, p++) {
5671 if (Z_TYPE(p->val) == IS_UNDEF) continue;
5672 *list++ = *p;
5673 }
5674 }
5675 ZVAL_UNDEF(&list->val);
5676 if (hash->nNumOfElements > 1) {
5677 if (behavior == DIFF_NORMAL) {
5678 zend_sort((void *) lists[i], hash->nNumOfElements,
5679 sizeof(Bucket), (compare_func_t) diff_data_compare_func,
5681 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
5682 zend_sort((void *) lists[i], hash->nNumOfElements,
5683 sizeof(Bucket), (compare_func_t) diff_key_compare_func,
5685 }
5686 }
5687 }
5688
5689 /* copy the argument array */
5691
5692 /* go through the lists and look for values of ptr[0] that are not in the others */
5693 while (Z_TYPE(ptrs[0]->val) != IS_UNDEF) {
5694 if ((behavior & DIFF_ASSOC) /* triggered also when DIFF_KEY */
5695 &&
5696 key_compare_type == DIFF_COMP_KEY_USER
5697 ) {
5698 BG(user_compare_fci) = *fci_key;
5699 BG(user_compare_fci_cache) = *fci_key_cache;
5700 }
5701 c = 1;
5702 for (i = 1; i < arr_argc; i++) {
5703 Bucket *ptr = ptrs[i];
5704 if (behavior == DIFF_NORMAL) {
5705 while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = diff_data_compare_func(ptrs[0], ptrs[i])))) {
5706 ptrs[i]++;
5707 }
5708 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
5709 while (Z_TYPE(ptr->val) != IS_UNDEF && (0 != (c = diff_key_compare_func(ptrs[0], ptr)))) {
5710 ptr++;
5711 }
5712 }
5713 if (!c) {
5714 if (behavior == DIFF_NORMAL) {
5715 if (Z_TYPE(ptrs[i]->val) != IS_UNDEF) {
5716 ptrs[i]++;
5717 }
5718 break;
5719 } else if (behavior == DIFF_ASSOC) { /* only when DIFF_ASSOC */
5720 /* In this branch is execute only when DIFF_ASSOC. If behavior == DIFF_KEY
5721 * data comparison is not needed - skipped. */
5722 if (Z_TYPE(ptr->val) != IS_UNDEF) {
5723 if (data_compare_type == DIFF_COMP_DATA_USER) {
5724 BG(user_compare_fci) = *fci_data;
5725 BG(user_compare_fci_cache) = *fci_data_cache;
5726 }
5727 if (diff_data_compare_func(ptrs[0], ptr) != 0) {
5728 /* the data is not the same */
5729 c = -1;
5730 if (key_compare_type == DIFF_COMP_KEY_USER) {
5731 BG(user_compare_fci) = *fci_key;
5732 BG(user_compare_fci_cache) = *fci_key_cache;
5733 }
5734 } else {
5735 break;
5736 /* we have found the element in other arrays thus we don't want it
5737 * in the return_value -> delete from there */
5738 }
5739 }
5740 } else if (behavior == DIFF_KEY) { /* only when DIFF_KEY */
5741 /* the behavior here differs from INTERSECT_KEY in php_intersect
5742 * since in the "diff" case we have to remove the entry from
5743 * return_value while when doing intersection the entry must not
5744 * be deleted. */
5745 break; /* remove the key */
5746 }
5747 }
5748 }
5749 if (!c) {
5750 /* ptrs[0] in one of the other arguments */
5751 /* delete all entries with value as ptrs[0] */
5752 for (;;) {
5753 p = ptrs[0];
5754 if (p->key == NULL) {
5756 } else {
5758 }
5759 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
5760 goto out;
5761 }
5762 if (behavior == DIFF_NORMAL) {
5763 if (diff_data_compare_func(ptrs[0] - 1, ptrs[0])) {
5764 break;
5765 }
5766 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
5767 /* in this case no array_key_compare is needed */
5768 break;
5769 }
5770 }
5771 } else {
5772 /* ptrs[0] in none of the other arguments */
5773 /* skip all entries with value as ptrs[0] */
5774 for (;;) {
5775 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
5776 goto out;
5777 }
5778 if (behavior == DIFF_NORMAL) {
5779 if (diff_data_compare_func(ptrs[0] - 1, ptrs[0])) {
5780 break;
5781 }
5782 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
5783 /* in this case no array_key_compare is needed */
5784 break;
5785 }
5786 }
5787 }
5788 }
5789out:
5790 for (i = 0; i < arr_argc; i++) {
5791 hash = Z_ARRVAL(args[i]);
5793 }
5794
5796
5797 efree(ptrs);
5798 efree(lists);
5799}
5800/* }}} */
5801
5802/* {{{ Returns the entries of arr1 that have keys which are not present in any of the others arguments. This function is like array_diff() but works on the keys instead of the values. The associativity is preserved. */
5807/* }}} */
5808
5809/* {{{ Returns the entries of arr1 that have keys which are not present in any of the others arguments. User supplied function is used for comparing the keys. This function is like array_udiff() but works on the keys instead of the values. The associativity is preserved. */
5814/* }}} */
5815
5816/* {{{ Returns the entries of arr1 that have values which are not present in any of the others arguments. */
5818{
5819 zval *args;
5820 uint32_t argc, i;
5821 uint32_t num;
5822 HashTable exclude;
5823 zval *value;
5824 zend_string *str, *tmp_str, *key;
5825 zend_long idx;
5826 zval dummy;
5827
5829 Z_PARAM_VARIADIC('+', args, argc)
5831
5832 if (Z_TYPE(args[0]) != IS_ARRAY) {
5833 zend_argument_type_error(1, "must be of type array, %s given", zend_zval_value_name(&args[0]));
5834 RETURN_THROWS();
5835 }
5836
5837 num = zend_hash_num_elements(Z_ARRVAL(args[0]));
5838 if (num == 0) {
5839 for (i = 1; i < argc; i++) {
5840 if (Z_TYPE(args[i]) != IS_ARRAY) {
5841 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i]));
5842 RETURN_THROWS();
5843 }
5844 }
5846 } else if (num == 1) {
5847 int found = 0;
5848 zend_string *search_str, *tmp_search_str;
5849
5850 value = NULL;
5852 break;
5854
5855 if (!value) {
5856 for (i = 1; i < argc; i++) {
5857 if (Z_TYPE(args[i]) != IS_ARRAY) {
5858 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i]));
5859 RETURN_THROWS();
5860 }
5861 }
5863 }
5864
5865 search_str = zval_get_tmp_string(value, &tmp_search_str);
5866
5867 for (i = 1; i < argc; i++) {
5868 if (Z_TYPE(args[i]) != IS_ARRAY) {
5869 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i]));
5870 RETURN_THROWS();
5871 }
5872 if (!found) {
5874 str = zval_get_tmp_string(value, &tmp_str);
5875 if (zend_string_equals(search_str, str)) {
5876 zend_tmp_string_release(tmp_str);
5877 found = 1;
5878 break;
5879 }
5880 zend_tmp_string_release(tmp_str);
5882 }
5883 }
5884
5885 zend_tmp_string_release(tmp_search_str);
5886
5887 if (found) {
5889 } else {
5891 }
5892 return;
5893 }
5894
5895 /* count number of elements */
5896 num = 0;
5897 for (i = 1; i < argc; i++) {
5898 if (Z_TYPE(args[i]) != IS_ARRAY) {
5899 zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i]));
5900 RETURN_THROWS();
5901 }
5902 num += zend_hash_num_elements(Z_ARRVAL(args[i]));
5903 }
5904
5905 if (num == 0) {
5907 return;
5908 }
5909
5910 ZVAL_NULL(&dummy);
5911 /* create exclude map */
5912 zend_hash_init(&exclude, num, NULL, NULL, 0);
5913 for (i = 1; i < argc; i++) {
5915 str = zval_get_tmp_string(value, &tmp_str);
5916 zend_hash_add(&exclude, str, &dummy);
5917 zend_tmp_string_release(tmp_str);
5919 }
5920
5921 /* copy all elements of first array that are not in exclude set */
5922 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
5924 str = zval_get_tmp_string(value, &tmp_str);
5925 if (!zend_hash_exists(&exclude, str)) {
5926 if (key) {
5928 } else {
5930 }
5932 }
5933 zend_tmp_string_release(tmp_str);
5935
5936 zend_hash_destroy(&exclude);
5937}
5938/* }}} */
5939
5940/* {{{ Returns the entries of arr1 that have values which are not present in any of the others arguments. Elements are compared by user supplied function. */
5945/* }}} */
5946
5947/* {{{ Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal */
5952/* }}} */
5953
5954/* {{{ Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Elements are compared by user supplied function. */
5959/* }}} */
5960
5961/* {{{ Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Keys are compared by user supplied function. */
5966/* }}} */
5967
5968/* {{{ Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Keys and elements are compared by user supplied functions. */
5973/* }}} */
5974
5975#define MULTISORT_ORDER 0
5976#define MULTISORT_TYPE 1
5977#define MULTISORT_LAST 2
5978
5979PHPAPI int php_multisort_compare(const void *a, const void *b) /* {{{ */
5980{
5981 Bucket *ab = *(Bucket **)a;
5982 Bucket *bb = *(Bucket **)b;
5983 int r;
5985
5986 r = 0;
5987 do {
5988 result = ARRAYG(multisort_func)[r](&ab[r], &bb[r]);
5989 if (result != 0) {
5990 return result > 0 ? 1 : -1;
5991 }
5992 r++;
5993 } while (Z_TYPE(ab[r].val) != IS_UNDEF);
5994
5995 return stable_sort_fallback(&ab[r], &bb[r]);
5996}
5997/* }}} */
5998
5999#define MULTISORT_ABORT \
6000 efree(func); \
6001 efree(arrays); \
6002 return;
6003
6004static void array_bucket_p_sawp(void *p, void *q) /* {{{ */ {
6005 Bucket *t;
6006 Bucket **f = (Bucket **)p;
6007 Bucket **g = (Bucket **)q;
6008
6009 t = *f;
6010 *f = *g;
6011 *g = t;
6012}
6013/* }}} */
6014
6015/* {{{ Sort multiple arrays at once similar to how ORDER BY clause works in SQL */
6017{
6018 zval* args;
6019 zval** arrays;
6020 Bucket** indirect;
6021 uint32_t idx;
6022 HashTable* hash;
6023 uint32_t argc;
6024 uint32_t array_size;
6025 uint32_t num_arrays = 0;
6026 int parse_state[MULTISORT_LAST]; /* 0 - flag not allowed 1 - flag allowed */
6027 int sort_order = PHP_SORT_ASC;
6028 int sort_type = PHP_SORT_REGULAR;
6029 uint32_t i, k, n;
6031
6033 Z_PARAM_VARIADIC('+', args, argc)
6035
6036 /* Allocate space for storing pointers to input arrays and sort flags. */
6037 arrays = (zval **)ecalloc(argc, sizeof(zval *));
6038 for (i = 0; i < MULTISORT_LAST; i++) {
6039 parse_state[i] = 0;
6040 }
6042
6043 /* Here we go through the input arguments and parse them. Each one can
6044 * be either an array or a sort flag which follows an array. If not
6045 * specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
6046 * accordingly. There can't be two sort flags of the same type after an
6047 * array, and the very first argument has to be an array. */
6048 for (i = 0; i < argc; i++) {
6049 zval *arg = &args[i];
6050
6051 ZVAL_DEREF(arg);
6052 if (Z_TYPE_P(arg) == IS_ARRAY) {
6054 /* We see the next array, so we update the sort flags of
6055 * the previous array and reset the sort flags. */
6056 if (i > 0) {
6057 ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);
6058 sort_order = PHP_SORT_ASC;
6059 sort_type = PHP_SORT_REGULAR;
6060 }
6061 arrays[num_arrays++] = arg;
6062
6063 /* Next one may be an array or a list of sort flags. */
6064 for (k = 0; k < MULTISORT_LAST; k++) {
6065 parse_state[k] = 1;
6066 }
6067 } else if (Z_TYPE_P(arg) == IS_LONG) {
6068 switch (Z_LVAL_P(arg) & ~PHP_SORT_FLAG_CASE) {
6069 case PHP_SORT_ASC:
6070 case PHP_SORT_DESC:
6071 /* flag allowed here */
6072 if (parse_state[MULTISORT_ORDER] == 1) {
6073 /* Save the flag and make sure then next arg is not the current flag. */
6075 parse_state[MULTISORT_ORDER] = 0;
6076 } else {
6077 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
6079 }
6080 break;
6081
6082 case PHP_SORT_REGULAR:
6083 case PHP_SORT_NUMERIC:
6084 case PHP_SORT_STRING:
6085 case PHP_SORT_NATURAL:
6087 /* flag allowed here */
6088 if (parse_state[MULTISORT_TYPE] == 1) {
6089 /* Save the flag and make sure then next arg is not the current flag. */
6090 sort_type = (int)Z_LVAL_P(arg);
6091 parse_state[MULTISORT_TYPE] = 0;
6092 } else {
6093 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
6095 }
6096 break;
6097
6098 default:
6099 zend_argument_value_error(i + 1, "must be a valid sort flag");
6101 break;
6102
6103 }
6104 } else {
6105 zend_argument_type_error(i + 1, "must be an array or a sort flag");
6107 }
6108 }
6109 /* Take care of the last array sort flags. */
6110 ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);
6111
6112 /* Make sure the arrays are of the same size. */
6113 array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
6114 for (i = 1; i < num_arrays; i++) {
6115 if (zend_hash_num_elements(Z_ARRVAL_P(arrays[i])) != array_size) {
6116 zend_value_error("Array sizes are inconsistent");
6118 }
6119 }
6120
6121 /* If all arrays are empty we don't need to do anything. */
6122 if (array_size < 1) {
6123 efree(func);
6124 efree(arrays);
6126 }
6127
6128 /* Create the indirection array. This array is of size MxN, where
6129 * M is the number of entries in each input array and N is the number
6130 * of the input arrays + 1. The last column is UNDEF to indicate the end
6131 * of the row. It also stores the original position for stable sorting. */
6132 indirect = (Bucket **)safe_emalloc(array_size, sizeof(Bucket *), 0);
6133 /* Move num_arrays multiplication to size because it's essentially impossible to overflow. */
6134 Bucket *indirects = (Bucket *)safe_emalloc(array_size, sizeof(Bucket) * (num_arrays + 1), 0);
6135 for (i = 0; i < array_size; i++) {
6136 indirect[i] = indirects + (i * (num_arrays + 1));
6137 }
6138 for (i = 0; i < num_arrays; i++) {
6139 k = 0;
6140 if (HT_IS_PACKED(Z_ARRVAL_P(arrays[i]))) {
6141 zval *zv = Z_ARRVAL_P(arrays[i])->arPacked;
6142 for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++, zv++) {
6143 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
6144 ZVAL_COPY_VALUE(&indirect[k][i].val, zv);
6145 indirect[k][i].h = idx;
6146 indirect[k][i].key = NULL;
6147 k++;
6148 }
6149 } else {
6150 Bucket *p = Z_ARRVAL_P(arrays[i])->arData;
6151 for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++, p++) {
6152 if (Z_TYPE(p->val) == IS_UNDEF) continue;
6153 indirect[k][i] = *p;
6154 k++;
6155 }
6156 }
6157 }
6158 for (k = 0; k < array_size; k++) {
6159 ZVAL_UNDEF(&indirect[k][num_arrays].val);
6160 Z_EXTRA_P(&indirect[k][num_arrays].val) = k;
6161 }
6162
6163 /* Do the actual sort magic - bada-bim, bada-boom. */
6164 zend_sort(indirect, array_size, sizeof(Bucket *), php_multisort_compare, (swap_func_t)array_bucket_p_sawp);
6165 if (EG(exception)) {
6166 goto clean_up;
6167 }
6168
6169 /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
6170 for (i = 0; i < num_arrays; i++) {
6171 hash = Z_ARRVAL_P(arrays[i]);
6172 hash->nNumUsed = array_size;
6173 hash->nNextFreeElement = array_size;
6174 hash->nInternalPointer = 0;
6175 if (HT_IS_PACKED(hash)) {
6176 for (k = 0; k < array_size; k++) {
6177 ZVAL_COPY_VALUE(&hash->arPacked[k], &indirect[k][i].val);
6178 }
6179 } else {
6180 bool repack = true;
6181
6182 for (n = 0, k = 0; k < array_size; k++) {
6183 hash->arData[k] = indirect[k][i];
6184 if (hash->arData[k].key == NULL) {
6185 hash->arData[k].h = n++;
6186 } else {
6187 repack = false;
6188 }
6189 }
6190 if (repack) {
6192 } else {
6194 }
6195 }
6196 }
6198
6199clean_up:
6200 efree(indirects);
6201 efree(indirect);
6202 efree(func);
6203 efree(arrays);
6204}
6205/* }}} */
6206
6207/* {{{ php_array_pick_keys */
6209{
6210 const php_random_algo *algo = engine.algo;
6211 void *state = engine.state;
6212
6213 HashTable *ht = Z_ARRVAL_P(input);
6214 uint32_t num_avail = zend_hash_num_elements(ht);
6215 zend_long i, randval;
6216 zend_string *string_key;
6217 zend_ulong num_key;
6218 zval *zv;
6219 Bucket *b;
6220 zend_bitset bitset;
6221 int negative_bitset = 0;
6222 uint32_t bitset_len;
6223 ALLOCA_FLAG(use_heap);
6224
6225 if (num_avail == 0) {
6226 if (!silent) {
6228 }
6229 return false;
6230 }
6231
6232 if (num_req == 1) {
6233 if (num_avail < ht->nNumUsed - (ht->nNumUsed >> 1)) {
6234 /* If less than 1/2 of elements are used, don't sample. Instead search for a
6235 * specific offset using linear scan. */
6236 i = 0;
6237 randval = algo->range(state, 0, num_avail - 1);
6238 if (EG(exception)) {
6239 return false;
6240 }
6241 ZEND_HASH_FOREACH_KEY(ht, num_key, string_key) {
6242 if (i == randval) {
6243 if (string_key) {
6244 ZVAL_STR_COPY(retval, string_key);
6245 } else {
6246 ZVAL_LONG(retval, num_key);
6247 }
6248 return true;
6249 }
6250 i++;
6252 }
6253
6254 /* Sample random buckets until we hit one that is not empty.
6255 * The worst case probability of hitting an empty element is 1-1/2. The worst case
6256 * probability of hitting N empty elements in a row is (1-1/2)**N.
6257 * For N=10 this becomes smaller than 0.1%. */
6258 if (HT_IS_PACKED(ht)) {
6259 do {
6260 randval = algo->range(state, 0, ht->nNumUsed - 1);
6261 if (EG(exception)) {
6262 return false;
6263 }
6264 zv = &ht->arPacked[randval];
6265 if (!Z_ISUNDEF_P(zv)) {
6266 ZVAL_LONG(retval, randval);
6267 return true;
6268 }
6269 } while (true);
6270 } else {
6271 do {
6272 randval = algo->range(state, 0, ht->nNumUsed - 1);
6273 if (EG(exception)) {
6274 return false;
6275 }
6276 b = &ht->arData[randval];
6277 if (!Z_ISUNDEF(b->val)) {
6278 if (b->key) {
6280 } else {
6281 ZVAL_LONG(retval, b->h);
6282 }
6283 return true;
6284 }
6285 } while (true);
6286 }
6287 }
6288
6289 if (num_req <= 0 || num_req > num_avail) {
6290 if (!silent) {
6291 zend_argument_value_error(2, "must be between 1 and the number of elements in argument #1 ($array)");
6292 }
6293 return false;
6294 }
6295
6296 /* Make the return value an array only if we need to pass back more than one result. */
6297 array_init_size(retval, (uint32_t) num_req);
6298 if (num_req > (num_avail >> 1)) {
6299 negative_bitset = 1;
6300 num_req = num_avail - num_req;
6301 }
6302
6303 bitset_len = zend_bitset_len(num_avail);
6304 bitset = ZEND_BITSET_ALLOCA(bitset_len, use_heap);
6305 zend_bitset_clear(bitset, bitset_len);
6306
6307 i = num_req;
6308 int failures = 0;
6309 while (i) {
6310 randval = algo->range(state, 0, num_avail - 1);
6311 if (EG(exception)) {
6312 goto fail;
6313 }
6314 if (zend_bitset_in(bitset, randval)) {
6315 if (++failures > PHP_RANDOM_RANGE_ATTEMPTS) {
6316 if (!silent) {
6317 zend_throw_error(random_ce_Random_BrokenRandomEngineError, "Failed to generate an acceptable random number in %d attempts", PHP_RANDOM_RANGE_ATTEMPTS);
6318 }
6319
6320 goto fail;
6321 }
6322 } else {
6323 zend_bitset_incl(bitset, randval);
6324 i--;
6325 failures = 0;
6326 }
6327 }
6328
6331 /* We can't use zend_hash_index_find()
6332 * because the array may have string keys or gaps. */
6333 ZEND_HASH_FOREACH_KEY(ht, num_key, string_key) {
6334 if (zend_bitset_in(bitset, i) ^ negative_bitset) {
6335 if (string_key) {
6336 ZEND_HASH_FILL_SET_STR_COPY(string_key);
6337 } else {
6338 ZEND_HASH_FILL_SET_LONG(num_key);
6339 }
6341 }
6342 i++;
6345
6346 free_alloca(bitset, use_heap);
6347
6348 return true;
6349
6350 fail:
6351 free_alloca(bitset, use_heap);
6352
6353 return false;
6354}
6355/* }}} */
6356
6357/* {{{ Return key/keys for random entry/entries in the array */
6359{
6360 zval *input;
6361 zend_long num_req = 1;
6362
6364 Z_PARAM_ARRAY(input)
6366 Z_PARAM_LONG(num_req)
6368
6370 php_random_default_engine(),
6371 input,
6372 num_req,
6374 false)
6375 ) {
6376 RETURN_THROWS();
6377 }
6378}
6379/* }}} */
6380
6381/* Wrapper for array_sum and array_product */
6382static void php_array_binop(INTERNAL_FUNCTION_PARAMETERS, const char *op_name, binary_op_type op, zend_long initial)
6383{
6384 HashTable *input;
6385 zval *entry;
6386
6388 Z_PARAM_ARRAY_HT(input)
6390
6391 if (zend_hash_num_elements(input) == 0) {
6392 RETURN_LONG(initial);
6393 }
6394
6395 ZVAL_LONG(return_value, initial);
6396 ZEND_HASH_FOREACH_VAL(input, entry) {
6397 /* For objects we try to cast them to a numeric type */
6398 if (Z_TYPE_P(entry) == IS_OBJECT) {
6399 zval dst;
6400 zend_result status = Z_OBJ_HT_P(entry)->cast_object(Z_OBJ_P(entry), &dst, _IS_NUMBER);
6401
6402 /* Do not type error for BC */
6403 if (status == FAILURE || (Z_TYPE(dst) != IS_LONG && Z_TYPE(dst) != IS_DOUBLE)) {
6404 php_error_docref(NULL, E_WARNING, "%s is not supported on type %s",
6405 op_name, zend_zval_type_name(entry));
6406 continue;
6407 }
6408 op(return_value, return_value, &dst);
6409 continue;
6410 }
6411
6413 if (status == FAILURE) {
6416 /* BC resources: previously resources were cast to int */
6417 if (Z_TYPE_P(entry) == IS_RESOURCE) {
6418 zval tmp;
6419 ZVAL_LONG(&tmp, Z_RES_HANDLE_P(entry));
6420 op(return_value, return_value, &tmp);
6421 }
6422 /* BC non numeric strings: previously were cast to 0 */
6423 else if (Z_TYPE_P(entry) == IS_STRING) {
6424 zval tmp;
6425 ZVAL_LONG(&tmp, 0);
6426 op(return_value, return_value, &tmp);
6427 }
6428 php_error_docref(NULL, E_WARNING, "%s is not supported on type %s",
6429 op_name, zend_zval_type_name(entry));
6430 }
6432}
6433
6434/* {{{ Returns the sum of the array entries */
6436{
6437 php_array_binop(INTERNAL_FUNCTION_PARAM_PASSTHRU, "Addition", add_function, 0);
6438}
6439/* }}} */
6440
6441/* {{{ Returns the product of the array entries */
6443{
6444 php_array_binop(INTERNAL_FUNCTION_PARAM_PASSTHRU, "Multiplication", mul_function, 1);
6445}
6446/* }}} */
6447
6448/* {{{ Iteratively reduce the array to a single value via the callback. */
6450{
6451 zval *input;
6452 zval args[2];
6453 zval *operand;
6454 zval retval;
6455 zend_fcall_info fci;
6457 zval *initial = NULL;
6458 HashTable *htbl;
6459
6461 Z_PARAM_ARRAY(input)
6462 Z_PARAM_FUNC(fci, fci_cache)
6464 Z_PARAM_ZVAL(initial)
6466
6467
6468 if (ZEND_NUM_ARGS() > 2) {
6469 ZVAL_COPY(return_value, initial);
6470 } else {
6472 }
6473
6474 /* (zval **)input points to an element of argument stack
6475 * the base pointer of which is subject to change.
6476 * thus we need to keep the pointer to the hashtable for safety */
6477 htbl = Z_ARRVAL_P(input);
6478
6479 if (zend_hash_num_elements(htbl) == 0) {
6480 return;
6481 }
6482
6483 fci.retval = &retval;
6484 fci.param_count = 2;
6485
6486 ZEND_HASH_FOREACH_VAL(htbl, operand) {
6488 ZVAL_COPY(&args[1], operand);
6489 fci.params = args;
6490
6491 if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
6492 zval_ptr_dtor(&args[1]);
6493 zval_ptr_dtor(&args[0]);
6496 zend_unwrap_reference(return_value);
6497 }
6498 } else {
6499 zval_ptr_dtor(&args[1]);
6500 zval_ptr_dtor(&args[0]);
6501 RETURN_NULL();
6502 }
6504}
6505/* }}} */
6506
6507/* {{{ Filters elements from the array via the callback. */
6509{
6510 zval *array;
6511 zval *operand;
6512 zval *key;
6513 zval args[2];
6514 zval retval;
6515 bool have_callback = 0;
6516 zend_long use_type = 0;
6517 zend_string *string_key;
6520 zend_ulong num_key;
6521
6523 Z_PARAM_ARRAY(array)
6525 Z_PARAM_FUNC_OR_NULL(fci, fci_cache)
6526 Z_PARAM_LONG(use_type)
6528
6529 if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) {
6531 return;
6532 }
6534
6535 if (ZEND_FCI_INITIALIZED(fci)) {
6536 have_callback = 1;
6537 fci.retval = &retval;
6538 if (use_type == ARRAY_FILTER_USE_BOTH) {
6539 fci.param_count = 2;
6540 key = &args[1];
6541 } else {
6542 fci.param_count = 1;
6543 key = &args[0];
6544 }
6545 }
6546
6547 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, operand) {
6548 if (have_callback) {
6549 if (use_type) {
6550 /* Set up the key */
6551 if (!string_key) {
6552 ZVAL_LONG(key, num_key);
6553 } else {
6554 ZVAL_STR_COPY(key, string_key);
6555 }
6556 }
6557 if (use_type != ARRAY_FILTER_USE_KEY) {
6558 ZVAL_COPY(&args[0], operand);
6559 }
6560 fci.params = args;
6561
6562 if (zend_call_function(&fci, &fci_cache) == SUCCESS) {
6563 bool retval_true;
6564
6565 zval_ptr_dtor(&args[0]);
6566 if (use_type == ARRAY_FILTER_USE_BOTH) {
6567 zval_ptr_dtor(&args[1]);
6568 }
6569 retval_true = zend_is_true(&retval);
6571 if (!retval_true) {
6572 continue;
6573 }
6574 } else {
6575 zval_ptr_dtor(&args[0]);
6576 if (use_type == ARRAY_FILTER_USE_BOTH) {
6577 zval_ptr_dtor(&args[1]);
6578 }
6579 return;
6580 }
6581 } else if (!zend_is_true(operand)) {
6582 continue;
6583 }
6584
6585 if (string_key) {
6586 operand = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, operand);
6587 } else {
6588 operand = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, operand);
6589 }
6590 zval_add_ref(operand);
6592}
6593/* }}} */
6594
6595/* {{{ Internal function to find an array element for a user closure. */
6596static zend_result php_array_find(const HashTable *array, zend_fcall_info fci, zend_fcall_info_cache fci_cache, zval *result_key, zval *result_value, bool negate_condition)
6597{
6598 zend_ulong num_key;
6599 zend_string *str_key;
6600 zval retval;
6601 zval args[2];
6602 zval *operand;
6603
6604 if (result_value != NULL) {
6605 ZVAL_UNDEF(result_value);
6606 }
6607
6608 if (result_key != NULL) {
6609 ZVAL_UNDEF(result_key);
6610 }
6611
6612 if (zend_hash_num_elements(array) == 0) {
6613 return SUCCESS;
6614 }
6615
6617
6618 fci.retval = &retval;
6619 fci.param_count = 2;
6620 fci.params = args;
6621
6622 ZEND_HASH_FOREACH_KEY_VAL(array, num_key, str_key, operand) {
6623 /* Set up the key */
6624 if (!str_key) {
6625 ZVAL_LONG(&args[1], num_key);
6626 } else {
6627 ZVAL_STR_COPY(&args[1], str_key);
6628 }
6629
6630 ZVAL_COPY(&args[0], operand);
6631
6632 zend_result result = zend_call_function(&fci, &fci_cache);
6634 if (EXPECTED(!Z_ISUNDEF(retval))) {
6635 int retval_true;
6636
6637 retval_true = zend_is_true(&retval);
6639
6640 /* This negates the condition, if negate_condition is true. Otherwise it does nothing with `retval_true`. */
6641 retval_true ^= negate_condition;
6642
6643 if (retval_true) {
6644 if (result_value != NULL) {
6645 ZVAL_COPY_DEREF(result_value, &args[0]);
6646 }
6647
6648 if (result_key != NULL) {
6649 ZVAL_COPY(result_key, &args[1]);
6650 }
6651
6652 zval_ptr_dtor(&args[0]);
6653 zval_ptr_dtor(&args[1]);
6654
6655 return SUCCESS;
6656 }
6657 }
6658
6659 zval_ptr_dtor(&args[0]);
6660 zval_ptr_dtor(&args[1]);
6661
6662 if (UNEXPECTED(Z_ISUNDEF(retval))) {
6663 return FAILURE;
6664 }
6666
6667 return SUCCESS;
6668}
6669/* }}} */
6670
6671/* {{{ Search within an array and returns the first found element value. */
6673{
6674 zval *array = NULL;
6675 zend_fcall_info fci;
6677
6679 Z_PARAM_ARRAY(array)
6680 Z_PARAM_FUNC(fci, fci_cache)
6682
6683 if (php_array_find(Z_ARR_P(array), fci, fci_cache, NULL, return_value, false) != SUCCESS) {
6684 RETURN_THROWS();
6685 }
6686
6687 if (Z_TYPE_P(return_value) == IS_UNDEF) {
6688 RETURN_NULL();
6689 }
6690}
6691/* }}} */
6692
6693/* {{{ Search within an array and returns the first found element key. */
6695{
6696 zval *array = NULL;
6697 zend_fcall_info fci;
6699
6701 Z_PARAM_ARRAY(array)
6702 Z_PARAM_FUNC(fci, fci_cache)
6704
6705 if (php_array_find(Z_ARR_P(array), fci, fci_cache, return_value, NULL, false) != SUCCESS) {
6706 RETURN_THROWS();
6707 }
6708
6709 if (Z_TYPE_P(return_value) == IS_UNDEF) {
6710 RETURN_NULL();
6711 }
6712}
6713/* }}} */
6714
6715/* {{{ Checks if at least one array element satisfies a callback function. */
6717{
6718 zval *array = NULL;
6719 zend_fcall_info fci;
6721
6723 Z_PARAM_ARRAY(array)
6724 Z_PARAM_FUNC(fci, fci_cache)
6726
6727 if (php_array_find(Z_ARR_P(array), fci, fci_cache, return_value, NULL, false) != SUCCESS) {
6728 RETURN_THROWS();
6729 }
6730
6733 zval_ptr_dtor_str(return_value);
6734 }
6736}
6737/* }}} */
6738
6739/* {{{ Checks if all array elements satisfy a callback function. */
6741{
6742 zval *array = NULL;
6743 zend_fcall_info fci;
6745
6747 Z_PARAM_ARRAY(array)
6748 Z_PARAM_FUNC(fci, fci_cache)
6750
6751 if (php_array_find(Z_ARR_P(array), fci, fci_cache, return_value, NULL, true) != SUCCESS) {
6752 RETURN_THROWS();
6753 }
6754
6757 zval_ptr_dtor_str(return_value);
6758 }
6760}
6761/* }}} */
6762
6763/* {{{ Applies the callback to the elements in given arrays. */
6765{
6766 zval *arrays = NULL;
6767 int n_arrays = 0;
6768 zval result;
6771 int i;
6772 uint32_t k, maxlen = 0;
6773
6775 Z_PARAM_FUNC_OR_NULL(fci, fci_cache)
6776 Z_PARAM_VARIADIC('+', arrays, n_arrays)
6778
6779 if (n_arrays == 1) {
6780 zend_ulong num_key;
6781 zend_string *str_key;
6782 zval *zv, arg;
6783 int ret;
6784
6785 if (Z_TYPE(arrays[0]) != IS_ARRAY) {
6786 zend_argument_type_error(2, "must be of type array, %s given", zend_zval_value_name(&arrays[0]));
6787 RETURN_THROWS();
6788 }
6789 maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[0]));
6790
6791 /* Short-circuit: if no callback and only one array, just return it. */
6792 if (!ZEND_FCI_INITIALIZED(fci) || !maxlen) {
6793 ZVAL_COPY(return_value, &arrays[0]);
6794 return;
6795 }
6796
6799
6800 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(arrays[0]), num_key, str_key, zv) {
6801 fci.retval = &result;
6802 fci.param_count = 1;
6803 fci.params = &arg;
6804
6805 ZVAL_COPY(&arg, zv);
6806 ret = zend_call_function(&fci, &fci_cache);
6807 i_zval_ptr_dtor(&arg);
6808 if (ret != SUCCESS || Z_TYPE(result) == IS_UNDEF) {
6810 RETURN_NULL();
6811 }
6812 if (str_key) {
6813 _zend_hash_append(Z_ARRVAL_P(return_value), str_key, &result);
6814 } else {
6816 }
6818 } else {
6819 uint32_t *array_pos = (HashPosition *)ecalloc(n_arrays, sizeof(HashPosition));
6820
6821 for (i = 0; i < n_arrays; i++) {
6822 if (Z_TYPE(arrays[i]) != IS_ARRAY) {
6823 zend_argument_type_error(i + 2, "must be of type array, %s given", zend_zval_value_name(&arrays[i]));
6824 efree(array_pos);
6825 RETURN_THROWS();
6826 }
6827 if (zend_hash_num_elements(Z_ARRVAL(arrays[i])) > maxlen) {
6828 maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[i]));
6829 }
6830 }
6831
6833
6834 if (!ZEND_FCI_INITIALIZED(fci)) {
6835 zval zv;
6836
6837 /* We iterate through all the arrays at once. */
6838 for (k = 0; k < maxlen; k++) {
6839
6840 /* If no callback, the result will be an array, consisting of current
6841 * entries from all arrays. */
6842 array_init_size(&result, n_arrays);
6843
6844 for (i = 0; i < n_arrays; i++) {
6845 /* If this array still has elements, add the current one to the
6846 * parameter list, otherwise use null value. */
6847 uint32_t pos = array_pos[i];
6848 if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
6849 while (1) {
6850 if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
6851 ZVAL_NULL(&zv);
6852 break;
6853 } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
6854 ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arPacked[pos]);
6855 array_pos[i] = pos + 1;
6856 break;
6857 }
6858 pos++;
6859 }
6860 } else {
6861 while (1) {
6862 if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
6863 ZVAL_NULL(&zv);
6864 break;
6865 } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
6866 ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arData[pos].val);
6867 array_pos[i] = pos + 1;
6868 break;
6869 }
6870 pos++;
6871 }
6872 }
6874 }
6875
6877 }
6878 } else {
6879 zval *params = (zval *)safe_emalloc(n_arrays, sizeof(zval), 0);
6880
6881 /* We iterate through all the arrays at once. */
6882 for (k = 0; k < maxlen; k++) {
6883 for (i = 0; i < n_arrays; i++) {
6884 /* If this array still has elements, add the current one to the
6885 * parameter list, otherwise use null value. */
6886 uint32_t pos = array_pos[i];
6887 if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
6888 while (1) {
6889 if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
6890 ZVAL_NULL(&params[i]);
6891 break;
6892 } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
6893 ZVAL_COPY(&params[i], &Z_ARRVAL(arrays[i])->arPacked[pos]);
6894 array_pos[i] = pos + 1;
6895 break;
6896 }
6897 pos++;
6898 }
6899 } else {
6900 while (1) {
6901 if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
6902 ZVAL_NULL(&params[i]);
6903 break;
6904 } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
6905 ZVAL_COPY(&params[i], &Z_ARRVAL(arrays[i])->arData[pos].val);
6906 array_pos[i] = pos + 1;
6907 break;
6908 }
6909 pos++;
6910 }
6911 }
6912 }
6913
6914 fci.retval = &result;
6915 fci.param_count = n_arrays;
6916 fci.params = params;
6917
6918 if (zend_call_function(&fci, &fci_cache) != SUCCESS || Z_TYPE(result) == IS_UNDEF) {
6919 efree(array_pos);
6921 for (i = 0; i < n_arrays; i++) {
6922 zval_ptr_dtor(&params[i]);
6923 }
6924 efree(params);
6925 RETURN_NULL();
6926 } else {
6927 for (i = 0; i < n_arrays; i++) {
6928 zval_ptr_dtor(&params[i]);
6929 }
6930 }
6931
6933 }
6934
6935 efree(params);
6936 }
6937 efree(array_pos);
6938 }
6939}
6940/* }}} */
6941
6942/* {{{ Checks if the given key or index exists in the array */
6944{
6945 zval *key;
6946 HashTable *ht;
6947
6952
6953 switch (Z_TYPE_P(key)) {
6954 case IS_STRING:
6955 RETVAL_BOOL(zend_symtable_exists(ht, Z_STR_P(key)));
6956 break;
6957 case IS_LONG:
6958 RETVAL_BOOL(zend_hash_index_exists(ht, Z_LVAL_P(key)));
6959 break;
6960 case IS_NULL:
6961 RETVAL_BOOL(zend_hash_exists(ht, ZSTR_EMPTY_ALLOC()));
6962 break;
6963 case IS_DOUBLE:
6964 RETVAL_BOOL(zend_hash_index_exists(ht, zend_dval_to_lval_safe(Z_DVAL_P(key))));
6965 break;
6966 case IS_FALSE:
6967 RETVAL_BOOL(zend_hash_index_exists(ht, 0));
6968 break;
6969 case IS_TRUE:
6970 RETVAL_BOOL(zend_hash_index_exists(ht, 1));
6971 break;
6972 case IS_RESOURCE:
6974 RETVAL_BOOL(zend_hash_index_exists(ht, Z_RES_HANDLE_P(key)));
6975 break;
6976 default:
6977 zend_argument_type_error(1, "must be a valid array offset type");
6978 break;
6979 }
6980}
6981/* }}} */
6982
6983/* {{{ Split array into chunks */
6985{
6986 int num_in;
6987 zend_long size, current = 0;
6988 zend_string *str_key;
6989 zend_ulong num_key;
6990 bool preserve_keys = 0;
6991 zval *input = NULL;
6992 zval chunk;
6993 zval *entry;
6994
6996 Z_PARAM_ARRAY(input)
6999 Z_PARAM_BOOL(preserve_keys)
7001
7002 /* Do bounds checking for size parameter. */
7003 if (size < 1) {
7004 zend_argument_value_error(2, "must be greater than 0");
7005 RETURN_THROWS();
7006 }
7007
7008 num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
7009
7010 if (size > num_in) {
7011 if (num_in == 0) {
7013 return;
7014 }
7015 size = num_in;
7016 }
7017
7018 array_init_size(return_value, (uint32_t)(((num_in - 1) / size) + 1));
7019
7020 ZVAL_UNDEF(&chunk);
7021
7022 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, str_key, entry) {
7023 /* If new chunk, create and initialize it. */
7024 if (Z_TYPE(chunk) == IS_UNDEF) {
7025 array_init_size(&chunk, (uint32_t)size);
7026 }
7027
7028 /* Add entry to the chunk, preserving keys if necessary. */
7029 if (preserve_keys) {
7030 if (str_key) {
7031 entry = zend_hash_add_new(Z_ARRVAL(chunk), str_key, entry);
7032 } else {
7033 entry = zend_hash_index_add_new(Z_ARRVAL(chunk), num_key, entry);
7034 }
7035 } else {
7036 entry = zend_hash_next_index_insert(Z_ARRVAL(chunk), entry);
7037 }
7038 zval_add_ref(entry);
7039
7040 /* If reached the chunk size, add it to the result array, and reset the
7041 * pointer. */
7042 if (!(++current % size)) {
7043 add_next_index_zval(return_value, &chunk);
7044 ZVAL_UNDEF(&chunk);
7045 }
7047
7048 /* Add the final chunk if there is one. */
7049 if (Z_TYPE(chunk) != IS_UNDEF) {
7050 add_next_index_zval(return_value, &chunk);
7051 }
7052}
7053/* }}} */
7054
7055/* {{{ Creates an array by using the elements of the first parameter as keys and the elements of the second as the corresponding values */
7057{
7058 HashTable *values, *keys;
7059 uint32_t pos_values = 0;
7060 zval *entry_keys, *entry_values;
7061 int num_keys, num_values;
7062
7064 Z_PARAM_ARRAY_HT(keys)
7065 Z_PARAM_ARRAY_HT(values)
7067
7068 num_keys = zend_hash_num_elements(keys);
7069 num_values = zend_hash_num_elements(values);
7070
7071 if (num_keys != num_values) {
7072 zend_argument_value_error(1, "and argument #2 ($values) must have the same number of elements");
7073 RETURN_THROWS();
7074 }
7075
7076 if (!num_keys) {
7078 }
7079
7080 array_init_size(return_value, num_keys);
7081 ZEND_HASH_FOREACH_VAL(keys, entry_keys) {
7082 while (1) {
7083 if (pos_values >= values->nNumUsed) {
7084 break;
7085 }
7086 entry_values = ZEND_HASH_ELEMENT(values, pos_values);
7087 if (Z_TYPE_P(entry_values) != IS_UNDEF) {
7088 if (Z_TYPE_P(entry_keys) == IS_LONG) {
7090 Z_LVAL_P(entry_keys), entry_values);
7091 } else {
7092 zend_string *tmp_key;
7093 zend_string *key = zval_get_tmp_string(entry_keys, &tmp_key);
7094 entry_values = zend_symtable_update(Z_ARRVAL_P(return_value),
7095 key, entry_values);
7096 zend_tmp_string_release(tmp_key);
7097 }
7098 zval_add_ref(entry_values);
7099 pos_values++;
7100 break;
7101 }
7102 pos_values++;
7103 }
7105}
7106/* }}} */
bool exception
Definition assert.c:30
#define BG(v)
array_slice(array $array, int $offset, ?int $length=null, bool $preserve_keys=false)
array_find_key(array $array, callable $callback)
array_intersect_key(array $array, array ... $arrays)
array_fill(int $start_index, int $count, mixed $value)
array_chunk(array $array, int $length, bool $preserve_keys=false)
array_key_exists($key, array $array)
array_intersect_uassoc(array $array,... $rest)
array_key_first(array $array)
array_shift(array &$array)
array_reverse(array $array, bool $preserve_keys=false)
array_sum(array $array)
array_product(array $array)
array_rand(array $array, int $num=1)
krsort(array &$array, int $flags=SORT_REGULAR)
in_array(mixed $needle, array $haystack, bool $strict=false)
array_keys(array $array, mixed $filter_value=UNKNOWN, bool $strict=false)
array_values(array $array)
array_udiff(array $array,... $rest)
array_merge(array ... $arrays)
array_replace(array $array, array ... $replacements)
array_diff_key(array $array, array ... $arrays)
array_flip(array $array)
array_intersect(array $array, array ... $arrays)
array_unique(array $array, int $flags=SORT_STRING)
array_diff_uassoc(array $array,... $rest)
array_find(array $array, callable $callback)
prev(array|object &$array)
strcoll(string $string1, string $string2)
array_intersect_assoc(array $array, array ... $arrays)
copy(string $from, string $to, $context=null)
array_uintersect(array $array,... $rest)
array_count_values(array $array)
array_filter(array $array, ?callable $callback=null, int $mode=0)
array_reduce(array $array, callable $callback, mixed $initial=null)
array_all(array $array, callable $callback)
array_map(?callable $callback, array $array, array ... $arrays)
array_diff_assoc(array $array, array ... $arrays)
array_uintersect_assoc(array $array,... $rest)
usort(array &$array, callable $callback)
rsort(array &$array, int $flags=SORT_REGULAR)
array_fill_keys(array $keys, mixed $value)
array_replace_recursive(array $array, array ... $replacements)
array_search(mixed $needle, array $haystack, bool $strict=false)
reset(array|object &$array)
count(Countable|array $value, int $mode=COUNT_NORMAL)
array_key_last(array $array)
natcasesort(array &$array)
array_diff_ukey(array $array,... $rest)
array_pop(array &$array)
array_pad(array $array, int $length, mixed $value)
arsort(array &$array, int $flags=SORT_REGULAR)
array_splice(array &$array, int $offset, ?int $length=null, mixed $replacement=[])
array_udiff_uassoc(array $array,... $rest)
compact($var_name,... $var_names)
array_any(array $array, callable $callback)
natsort(array &$array)
array_merge_recursive(array ... $arrays)
ksort(array &$array, int $flags=SORT_REGULAR)
array_walk(array|object &$array, callable $callback, mixed $arg=UNKNOWN)
uasort(array &$array, callable $callback)
array_diff(array $array, array ... $arrays)
asort(array &$array, int $flags=SORT_REGULAR)
array_multisort(&$array, &... $rest)
shuffle(array &$array)
extract(array &$array, int $flags=EXTR_OVERWRITE, string $prefix="")
uksort(array &$array, callable $callback)
array_intersect_ukey(array $array,... $rest)
array_walk_recursive(array|object &$array, callable $callback, mixed $arg=UNKNOWN)
array_push(array &$array, mixed ... $values)
array_udiff_assoc(array $array,... $rest)
array_column(array $array, int|string|null $column_key, int|string|null $index_key=null)
array_change_key_case(array $array, int $case=CASE_LOWER)
array_unshift(array &$array, mixed ... $values)
array_uintersect_uassoc(array $array,... $rest)
array_combine(array $keys, array $values)
char s[4]
Definition cdf.c:77
DNS_STATUS status
Definition dns_win32.c:49
#define max(a, b)
Definition exif.c:60
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
zend_long ch
Definition ffi.c:4580
zend_long n
Definition ffi.c:4979
new_type size
Definition ffi.c:4365
void * ptr
Definition ffi.c:3814
memcpy(ptr1, ptr2, size)
zval * arg
Definition ffi.c:3975
memset(ptr, 0, type->size)
zval * val
Definition ffi.c:4262
HashTable * ht
Definition ffi.c:4838
zend_long offset
char * mode
zend_long maxlen
#define NULL
Definition gdcache.h:45
#define prefix
hash(string $algo, string $data, bool $binary=false, array $options=[])
Definition hash.stub.php:12
#define SUCCESS
Definition hash_sha3.c:261
again j
for( $i=0;$i< 0x1E;$i++)
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
enum entity_charset charset
Definition html_tables.h:39
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
PHPAPI ZEND_COLD void php_error_docref_unchecked(const char *docref, int type, const char *format,...)
Definition main.c:1178
#define next(ls)
Definition minilua.c:2661
#define PHP_FUNCTION
Definition php.h:364
#define PHP_MSHUTDOWN_FUNCTION
Definition php.h:401
#define PHP_MINIT_FUNCTION
Definition php.h:400
#define INT_MAX
Definition php.h:237
#define PHPAPI
Definition php.h:71
#define PHP_EXTR_OVERWRITE
Definition php_array.h:37
#define PHP_SORT_STRING
Definition php_array.h:52
#define PHP_EXTR_SKIP
Definition php_array.h:38
#define ARRAY_FILTER_USE_BOTH
Definition php_array.h:62
#define PHP_EXTR_REFS
Definition php_array.h:45
#define PHP_COUNT_NORMAL
Definition php_array.h:59
#define ARRAY_FILTER_USE_KEY
Definition php_array.h:63
#define PHP_EXTR_PREFIX_INVALID
Definition php_array.h:41
#define PHP_SORT_FLAG_CASE
Definition php_array.h:57
bucket_compare_func_t * multisort_func
Definition php_array.h:66
#define PHP_EXTR_PREFIX_SAME
Definition php_array.h:39
#define PHP_SORT_REGULAR
Definition php_array.h:50
#define PHP_SORT_NUMERIC
Definition php_array.h:51
#define PHP_EXTR_PREFIX_IF_EXISTS
Definition php_array.h:42
#define PHP_SORT_NATURAL
Definition php_array.h:56
#define PHP_EXTR_IF_EXISTS
Definition php_array.h:43
#define PHP_COUNT_RECURSIVE
Definition php_array.h:60
bool compare_deprecation_thrown
Definition php_array.h:67
#define PHP_SORT_DESC
Definition php_array.h:53
#define PHP_SORT_LOCALE_STRING
Definition php_array.h:55
#define PHP_EXTR_PREFIX_ALL
Definition php_array.h:40
#define ARRAYG(v)
Definition php_array.h:70
#define PHP_SORT_ASC
Definition php_array.h:54
unsigned const char * end
Definition php_ffi.h:51
unsigned const char * pos
Definition php_ffi.h:52
collator_compare_func_t compare_func
Definition php_intl.h:49
#define min(a, b)
struct _php_random_algo_with_state php_random_algo_with_state
struct _php_random_algo php_random_algo
#define PHP_RANDOM_RANGE_ATTEMPTS
Definition php_random.h:57
PHPAPI zend_class_entry * random_ce_Random_BrokenRandomEngineError
unsigned char key[REFLECTION_KEY_LEN]
PHPAPI int strnatcmp_ex(char const *a, size_t a_len, char const *b, size_t b_len, bool is_case_insensitive)
Definition strnatcmp.c:88
zend_constant * data
bool fail
Definition session.c:1065
zval * current
Definition session.c:1024
zval rv
Definition session.c:1024
zend_string * var_name
Definition session.c:966
p
Definition session.c:1105
#define DEFINE_SORT_VARIANTS(name)
Definition array.c:108
#define INTERSECT_KEY
Definition array.c:53
#define PHP_ARRAY_CMP_FUNC_VARS
Definition array.c:866
#define INTERSECT_ASSOC
Definition array.c:54
#define INTERSECT_COMP_KEY_INTERNAL
Definition array.c:58
#define INTERSECT_NORMAL
Definition array.c:52
#define DIFF_KEY
Definition array.c:44
#define INTERSECT_COMP_KEY_USER
Definition array.c:59
#define DIFF_COMP_KEY_INTERNAL
Definition array.c:49
#define INTERSECT_COMP_DATA_NONE
Definition array.c:55
PHPAPI int php_prefix_varname(zval *result, zend_string *prefix, const char *var_name, size_t var_name_len, bool add_underscore)
Definition array.c:1837
#define RANGE_CHECK_LONG_INIT_ARRAY(start, end, _step)
Definition array.c:2873
#define MULTISORT_ORDER
Definition array.c:5975
#define INTERSECT_COMP_DATA_USER
Definition array.c:57
PHPAPI int php_multisort_compare(const void *a, const void *b)
Definition array.c:5979
#define MULTISORT_TYPE
Definition array.c:5976
#define INTERSECT_COMP_DATA_INTERNAL
Definition array.c:56
#define PHP_ARRAY_CMP_FUNC_BACKUP()
Definition array.c:870
#define DIFF_COMP_DATA_NONE
Definition array.c:46
#define DIFF_ASSOC
Definition array.c:45
#define DIFF_COMP_KEY_USER
Definition array.c:50
#define DIFF_COMP_DATA_INTERNAL
Definition array.c:47
PHPAPI zend_long php_count_recursive(HashTable *ht)
Definition array.c:609
#define PHP_ARRAY_CMP_FUNC_RESTORE()
Definition array.c:876
PHPAPI bool php_array_data_shuffle(php_random_algo_with_state engine, zval *array)
Definition array.c:3212
PHPAPI int php_array_merge(HashTable *dest, HashTable *src)
Definition array.c:4106
PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src)
Definition array.c:4141
#define MULTISORT_ABORT
Definition array.c:5999
#define MULTISORT_LAST
Definition array.c:5977
#define DIFF_COMP_DATA_USER
Definition array.c:48
#define RANGE_CHECK_DOUBLE_INIT_ARRAY(start, end, _step)
Definition array.c:2861
PHPAPI bool php_array_pick_keys(php_random_algo_with_state engine, zval *input, zend_long num_req, zval *retval, bool silent)
Definition array.c:6208
#define DIFF_NORMAL
Definition array.c:43
PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src)
Definition array.c:4029
#define RETURN_STABLE_SORT(a, b, result)
Definition array.c:99
zend_ulong h
Definition zend_types.h:382
zend_string * key
Definition zend_types.h:383
zval val
Definition zend_types.h:381
zend_long(* range)(void *state, zend_long min, zend_long max)
Definition php_random.h:91
zend_long nNextFreeElement
Definition zend_types.h:410
uint32_t nNumUsed
Definition zend_types.h:406
uint32_t nTableSize
Definition zend_types.h:408
dtor_func_t pDestructor
Definition zend_types.h:411
Bucket * arData
Definition zend_types.h:403
zval * arPacked
Definition zend_types.h:404
uint32_t nTableMask
Definition zend_types.h:400
uint32_t nNumOfElements
Definition zend_types.h:407
uint32_t param_count
Definition zend_API.h:51
char val[1]
Definition zend_types.h:377
Bucket b
Definition array.c:4911
unsigned int i
Definition array.c:4912
Definition dce.c:49
zend_fcall_info fci
Definition array.c:1449
zend_fcall_info_cache fci_cache
Definition array.c:1450
$obj a
Definition test.php:84
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_type_error(const char *format,...)
Definition zend.c:1824
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
Definition zend.c:1849
#define INTERNAL_FUNCTION_PARAMETERS
Definition zend.h:49
#define USED_RET()
Definition zend.h:52
#define INTERNAL_FUNCTION_PARAM_PASSTHRU
Definition zend.h:50
ZEND_API zend_result add_next_index_null(zval *arg)
Definition zend_API.c:2141
ZEND_API zend_result array_set_zval_key(HashTable *ht, zval *key, zval *value)
Definition zend_API.c:2231
ZEND_API const char * zend_zval_value_name(const zval *arg)
Definition zend_API.c:148
ZEND_API const char * zend_zval_type_name(const zval *arg)
Definition zend_API.c:167
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API ZEND_COLD void zend_argument_must_not_be_empty_error(uint32_t arg_num)
Definition zend_API.c:443
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:423
#define Z_PARAM_FUNC(dest_fci, dest_fcc)
Definition zend_API.h:1824
#define Z_PARAM_NUMBER(dest)
Definition zend_API.h:1914
ZEND_API const zend_fcall_info empty_fcall_info
#define RETURN_COPY_DEREF(zv)
Definition zend_API.h:1056
ZEND_API const zend_fcall_info_cache empty_fcall_info_cache
#define ZEND_NUM_ARGS()
Definition zend_API.h:530
struct _zend_fcall_info_cache zend_fcall_info_cache
#define Z_PARAM_ARRAY_EX2(dest, check_null, deref, separate)
Definition zend_API.h:1671
#define RETURN_COPY(zv)
Definition zend_API.h:1054
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define RETURN_FALSE
Definition zend_API.h:1058
#define RETURN_NULL()
Definition zend_API.h:1036
#define ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor, globals_dtor)
Definition zend_API.h:272
#define ZEND_DECLARE_MODULE_GLOBALS(module_name)
Definition zend_API.h:268
#define ZEND_TRY_ASSIGN_COPY_EX(zv, other_zv, strict)
Definition zend_API.h:1462
#define array_init_size(arg, size)
Definition zend_API.h:538
#define RETURN_ARR(r)
Definition zend_API.h:1050
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define Z_PARAM_ARRAY_OR_OBJECT_EX(dest, check_null, separate)
Definition zend_API.h:1697
#define ZEND_FCI_INITIALIZED(fci)
Definition zend_API.h:340
#define RETVAL_ARR(r)
Definition zend_API.h:1024
#define ZEND_PARSE_PARAMETERS_END_EX(failure)
Definition zend_API.h:1630
#define Z_PARAM_STR(dest)
Definition zend_API.h:2086
#define Z_PARAM_STR_OR_LONG_OR_NULL(dest_str, dest_long, is_null)
Definition zend_API.h:2168
#define ZVAL_CHAR(z, c)
Definition zend_API.h:978
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_NUMBER_OR_STR(dest)
Definition zend_API.h:1925
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define Z_PARAM_VARIADIC(spec, dest, dest_num)
Definition zend_API.h:2124
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETVAL_EMPTY_ARRAY()
Definition zend_API.h:1025
#define RETURN_BOOL(b)
Definition zend_API.h:1035
struct _zend_fcall_info zend_fcall_info
#define RETURN_THROWS()
Definition zend_API.h:1060
#define HASH_OF(p)
Definition zend_API.h:1062
#define RETVAL_TRUE
Definition zend_API.h:1033
#define Z_PARAM_ARRAY_HT(dest)
Definition zend_API.h:1852
#define RETVAL_BOOL(b)
Definition zend_API.h:1009
#define Z_PARAM_LONG_OR_NULL(dest, is_null)
Definition zend_API.h:1899
#define RETURN_COPY_VALUE(zv)
Definition zend_API.h:1055
#define RETVAL_LONG(l)
Definition zend_API.h:1011
#define Z_PARAM_ARRAY_EX(dest, check_null, separate)
Definition zend_API.h:1679
#define Z_PARAM_BOOL(dest)
Definition zend_API.h:1726
#define RETURN_EMPTY_ARRAY()
Definition zend_API.h:1051
#define Z_PARAM_ARRAY(dest)
Definition zend_API.h:1682
ZEND_API zend_array * zend_rebuild_symbol_table(void)
#define Z_PARAM_ZVAL(dest)
Definition zend_API.h:2100
#define Z_PARAM_FUNC_OR_NULL(dest_fci, dest_fcc)
Definition zend_API.h:1830
ZEND_API zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
#define RETURN_TRUE
Definition zend_API.h:1059
#define Z_PARAM_ARRAY_OR_OBJECT(dest)
Definition zend_API.h:1700
#define RETVAL_COPY_VALUE(zv)
Definition zend_API.h:1029
#define RETURN_STR_COPY(s)
Definition zend_API.h:1042
#define array_init(arg)
Definition zend_API.h:537
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define efree(ptr)
Definition zend_alloc.h:155
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define pemalloc(size, persistent)
Definition zend_alloc.h:189
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
zend_ulong * zend_bitset
Definition zend_bitset.h:29
#define ZEND_BITSET_ALLOCA(n, use_heap)
Definition zend_bitset.h:44
struct _zval_struct zval
uint32_t num_args
zend_string_release_ex(func->internal_function.function_name, 0)
execute_data func
zval * args
#define BP_VAR_R
zend_result(ZEND_FASTCALL * binary_op_type)(zval *, zval *, zval *)
#define ZEND_ACC_ENUM
struct _zend_property_info zend_property_info
#define E_WARNING
Definition zend_errors.h:24
#define E_DEPRECATED
Definition zend_errors.h:37
ZEND_API void zend_clear_exception(void)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim)
ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element(void)
ZEND_API const char * get_active_function_name(void)
ZEND_API zend_object * zend_get_this_object(zend_execute_data *ex)
ZEND_API const char * get_active_function_arg_name(uint32_t arg_num)
#define ZEND_REF_ADD_TYPE_SOURCE(ref, source)
#define Z_FLF_PARAM_ARRAY(arg_num, dest)
union _zend_function zend_function
#define Z_FLF_PARAM_ZVAL(arg_num, dest)
#define Z_FLF_PARAM_BOOL(arg_num, dest)
#define ZEND_FRAMELESS_FUNCTION(name, arity)
#define EG(v)
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2744
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API void zend_hash_bucket_swap(Bucket *p, Bucket *q)
Definition zend_hash.c:2933
ZEND_API void ZEND_FASTCALL zend_hash_real_init_packed(HashTable *ht)
Definition zend_hash.c:330
ZEND_API HashTable * zend_array_to_list(HashTable *source)
Definition zend_hash.c:2526
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2773
ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht)
Definition zend_hash.c:1328
ZEND_API zval *ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag)
Definition zend_hash.c:3224
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData)
Definition zend_hash.c:1229
ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
Definition zend_hash.c:537
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
Definition zend_hash.c:1224
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2733
ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, bool packed)
Definition zend_hash.c:322
ZEND_API void ZEND_FASTCALL zend_hash_iterators_advance(HashTable *ht, HashPosition step)
Definition zend_hash.c:724
ZEND_API zval *ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2915
ZEND_API zval *ZEND_FASTCALL zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData)
Definition zend_hash.c:1214
ZEND_API void ZEND_FASTCALL zend_hash_packed_del_val(HashTable *ht, zval *zv)
Definition zend_hash.c:1517
ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, bool overwrite)
Definition zend_hash.c:2547
ZEND_API void ZEND_FASTCALL zend_hash_del_bucket(HashTable *ht, Bucket *p)
Definition zend_hash.c:1526
ZEND_API zval *ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:1007
ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
Definition zend_hash.c:1692
ZEND_API zval *ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key)
Definition zend_hash.c:2679
ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, const HashPosition *pos)
Definition zend_hash.c:2870
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
Definition zend_hash.c:608
ZEND_API zval *ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData)
Definition zend_hash.c:1219
ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht)
Definition zend_hash.c:374
ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed)
Definition zend_hash.c:396
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
Definition zend_hash.c:1808
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval *array)
Definition zend_hash.c:627
ZEND_API HashTable *ZEND_FASTCALL zend_array_dup(HashTable *source)
Definition zend_hash.c:2438
ZEND_API zval *ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:997
ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht)
Definition zend_hash.c:338
ZEND_API zval *ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key)
Definition zend_hash.c:1067
ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
Definition zend_hash.c:1534
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
Definition zend_hash.c:2668
ZEND_API zval *ZEND_FASTCALL zend_hash_add(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:992
ZEND_API zval *ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
Definition zend_hash.c:2701
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start)
Definition zend_hash.c:694
ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx)
Definition zend_hash.c:649
#define ZEND_HASH_FILL_ADD(_val)
Definition zend_hash.h:1570
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define ZEND_HASH_ELEMENT(__ht, _idx)
Definition zend_hash.h:1005
#define ZEND_HASH_MAP_FOREACH_BUCKET(ht, _bucket)
Definition zend_hash.h:1298
#define ZEND_HASH_FILL_SET_DOUBLE(_val)
Definition zend_hash.h:1553
#define HT_IS_WITHOUT_HOLES(ht)
Definition zend_hash.h:62
#define ZEND_HASH_FILL_PACKED(ht)
Definition zend_hash.h:1528
int(* bucket_compare_func_t)(Bucket *a, Bucket *b)
Definition zend_hash.h:299
#define ZEND_HASH_PACKED_REVERSE_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1483
#define ZEND_HASH_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val)
Definition zend_hash.h:1187
#define ZEND_HASH_FILL_END()
Definition zend_hash.h:1582
#define ZEND_HASH_FOREACH_KEY(ht, _h, _key)
Definition zend_hash.h:1146
#define HT_HAS_STATIC_KEYS_ONLY(ht)
Definition zend_hash.h:65
#define HT_IS_PACKED(ht)
Definition zend_hash.h:59
#define HT_ITERATORS_COUNT(ht)
Definition zend_hash.h:74
#define HT_SET_ITERATORS_COUNT(ht, iters)
Definition zend_hash.h:78
#define HT_HAS_ITERATORS(ht)
Definition zend_hash.h:76
#define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val)
Definition zend_hash.h:1181
#define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val)
Definition zend_hash.h:1166
#define ZEND_HASH_FILL_SET_LONG(_val)
Definition zend_hash.h:1550
#define ZEND_HASH_FILL_SET_INTERNED_STR(_val)
Definition zend_hash.h:1562
#define HT_FLAGS(ht)
Definition zend_hash.h:50
#define ZEND_HASH_PACKED_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1479
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define ZEND_HASH_FILL_NEXT()
Definition zend_hash.h:1565
#define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(ht, _key, _val)
Definition zend_hash.h:1374
#define ZEND_HASH_FOREACH_STR_KEY(ht, _key)
Definition zend_hash.h:1138
#define ZEND_HASH_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1102
#define ZEND_HASH_FILL_SET_STR_COPY(_val)
Definition zend_hash.h:1559
ZEND_API zend_class_entry * zend_ce_countable
int32_t zend_long
Definition zend_long.h:42
#define MAX_LENGTH_OF_LONG
Definition zend_long.h:109
#define ZEND_LONG_MIN
Definition zend_long.h:46
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_ABS
Definition zend_long.h:105
#define ZEND_LONG_FMT
Definition zend_long.h:87
#define Z_L(i)
Definition zend_long.h:48
#define ZEND_LONG_MAX
Definition zend_long.h:45
struct _zend_string zend_string
#define ZEND_PROPERTY_ISSET
#define ZEND_PROPERTY_EXISTS
ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2)
ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2)
ZEND_API zend_string *ZEND_FASTCALL zend_long_to_str(zend_long num)
ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2)
ZEND_API zend_result ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2)
ZEND_API void ZEND_FASTCALL convert_to_array(zval *op)
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2)
ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2)
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
ZEND_API uint8_t ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval)
ZEND_API zend_result ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2)
ZEND_API int ZEND_FASTCALL string_compare_function(zval *op1, zval *op2)
ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2)
ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2)
#define ZEND_UNCOMPARABLE
#define ALLOCA_FLAG(name)
#define ZEND_NORMALIZE_BOOL(n)
#define zend_never_inline
#define zend_isinf(a)
#define ZEND_FALLTHROUGH
#define EXPECTED(condition)
#define ZEND_THREEWAY_COMPARE(a, b)
#define zend_always_inline
#define ZEND_ASSERT(c)
#define ZEND_BIT_TEST(bits, bit)
#define free_alloca(p, use_heap)
#define zend_isnan(a)
#define ZEND_COLD
#define EMPTY_SWITCH_DEFAULT_CASE()
#define UNEXPECTED(condition)
struct _zend_array zend_array
struct _zend_object zend_object
ZEND_API void zend_sort(void *base, size_t nmemb, size_t siz, compare_func_t cmp, swap_func_t swp)
Definition zend_sort.c:248
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_KNOWN(idx)
#define zend_string_equals_literal(str, literal)
#define ZSTR_EMPTY_ALLOC()
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define ZSTR_CHAR(c)
#define d1
#define dval(x)
ZEND_API double zend_strtod(const char *s00, const char **se)
#define Z_OBJ_HANDLER_P(zv_p, hf)
Definition zend_types.h:996
int(* compare_func_t)(const void *, const void *)
Definition zend_types.h:104
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define IS_TRUE
Definition zend_types.h:603
#define ZVAL_STR(z, s)
#define GC_PROTECT_RECURSION(p)
Definition zend_types.h:868
#define Z_ISREF_P(zval_p)
Definition zend_types.h:954
#define Z_TRY_ADDREF_P(pz)
#define ZVAL_UNDEF(z)
#define Z_DVAL(zval)
Definition zend_types.h:968
#define Z_REFVAL_P(zval_p)
#define IS_FALSE
Definition zend_types.h:602
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define Z_ISUNDEF_P(zval_p)
Definition zend_types.h:957
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_NULL(z)
#define ZVAL_DEREF(z)
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
#define Z_REFCOUNTED_P(zval_p)
Definition zend_types.h:921
#define ZVAL_STR_COPY(z, s)
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_RESOURCE
Definition zend_types.h:609
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_ARRAY
Definition zend_types.h:607
#define Z_OBJ_HT_P(zval_p)
Definition zend_types.h:993
#define ZVAL_COPY_DEREF(z, v)
#define IS_DOUBLE
Definition zend_types.h:605
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
#define Z_COUNTED_P(zval_p)
Definition zend_types.h:699
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define ZVAL_NEW_REF(z, r)
#define Z_STR(zval)
Definition zend_types.h:971
#define GC_DELREF(p)
Definition zend_types.h:710
#define GC_FLAGS(p)
Definition zend_types.h:756
#define GC_ADDREF(p)
Definition zend_types.h:709
#define Z_REFVAL(zval)
#define Z_ADDREF_P(pz)
#define Z_UNPROTECT_RECURSION_P(zv)
Definition zend_types.h:889
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define GC_TRY_UNPROTECT_RECURSION(p)
Definition zend_types.h:880
#define GC_ADDREF_EX(p, rc)
Definition zend_types.h:711
#define IS_NULL
Definition zend_types.h:601
#define Z_OBJCE_P(zval_p)
#define Z_STRVAL(zval)
Definition zend_types.h:974
@ FAILURE
Definition zend_types.h:61
#define Z_TRY_ADDREF(z)
#define Z_STRLEN(zval)
Definition zend_types.h:977
#define IS_OBJECT
Definition zend_types.h:608
#define GC_TRY_PROTECT_RECURSION(p)
Definition zend_types.h:876
#define Z_EXTRA(zval)
Definition zend_types.h:695
#define Z_ADDREF(z)
#define IS_LONG
Definition zend_types.h:604
#define ZVAL_ARR(z, a)
#define IS_REFERENCE
Definition zend_types.h:610
#define Z_RES_HANDLE_P(zval_p)
#define ZVAL_NEW_STR(z, s)
#define ZVAL_MAKE_REF(zv)
#define ZVAL_COPY(z, v)
uint32_t HashPosition
Definition zend_types.h:548
#define GC_UNPROTECT_RECURSION(p)
Definition zend_types.h:872
struct _Bucket Bucket
void(* swap_func_t)(void *, void *)
Definition zend_types.h:105
#define Z_INDIRECT_P(zval_p)
#define Z_REF_P(zval_p)
#define Z_OBJPROP_P(zval_p)
#define ZVAL_DOUBLE(z, d)
#define ZVAL_OBJ_COPY(z, o)
#define Z_PROTECT_RECURSION_P(zv)
Definition zend_types.h:888
#define Z_REFCOUNT_P(pz)
#define ZVAL_MAKE_REF_EX(z, refcount)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define IS_ARRAY_IMMUTABLE
Definition zend_types.h:823
#define ZVAL_REF(z, r)
#define IS_ARRAY_PERSISTENT
Definition zend_types.h:824
#define _IS_NUMBER
Definition zend_types.h:630
#define SEPARATE_ARRAY(zv)
#define GC_REFCOUNT(p)
Definition zend_types.h:707
#define GC_IS_RECURSIVE(p)
Definition zend_types.h:865
#define Z_TYPE(zval)
Definition zend_types.h:659
#define Z_DVAL_P(zval_p)
Definition zend_types.h:969
#define IS_INDIRECT
Definition zend_types.h:623
#define Z_TRY_DELREF(z)
#define SEPARATE_ZVAL(zv)
#define Z_ARRVAL(zval)
Definition zend_types.h:986
#define Z_ARR_P(zval_p)
Definition zend_types.h:984
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_COPY_VALUE(z, v)
#define GC_IMMUTABLE
Definition zend_types.h:780
#define Z_EXTRA_P(zval_p)
Definition zend_types.h:696
#define Z_LVAL(zval)
Definition zend_types.h:965
#define ZVAL_DEINDIRECT(z)
#define Z_IS_RECURSIVE_P(zv)
Definition zend_types.h:887
#define Z_TRY_DELREF_P(pz)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
ZEND_API void zval_add_ref(zval *p)
#define ZVAL_PTR_DTOR
zval retval
double d2
zval * return_value
zend_property_info * prop_info
uint32_t arg_num
value_ptr
bool result
zend_refcounted * garbage
zval * ret
value
zend_object * zobj
out($f, $s)