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