This source file includes following definitions.
- ZEND_DECLARE_MODULE_GLOBALS
- PHP_MINIT_FUNCTION
- PHP_MSHUTDOWN_FUNCTION
- php_set_compare_func
- php_array_key_compare
- php_array_reverse_key_compare
- PHP_FUNCTION
- PHP_FUNCTION
- php_count_recursive
- PHP_FUNCTION
- php_array_data_compare
- php_array_reverse_data_compare
- php_array_natural_general_compare
- php_array_natural_compare
- php_array_natural_case_compare
- php_natsort
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- php_array_user_compare
- 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
- _phpi_pop
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- 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
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- 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
- 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 "php_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 #define DOUBLE_DRIFT_FIX 0.000000000000001
86
87
88 ZEND_DECLARE_MODULE_GLOBALS(array)
89
90
91
92 static void php_array_init_globals(zend_array_globals *array_globals)
93 {
94 memset(array_globals, 0, sizeof(zend_array_globals));
95 }
96
97
98 PHP_MINIT_FUNCTION(array)
99 {
100 ZEND_INIT_MODULE_GLOBALS(array, php_array_init_globals, NULL);
101
102 REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", EXTR_OVERWRITE, CONST_CS | CONST_PERSISTENT);
103 REGISTER_LONG_CONSTANT("EXTR_SKIP", EXTR_SKIP, CONST_CS | CONST_PERSISTENT);
104 REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT);
105 REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT);
106 REGISTER_LONG_CONSTANT("EXTR_PREFIX_INVALID", EXTR_PREFIX_INVALID, CONST_CS | CONST_PERSISTENT);
107 REGISTER_LONG_CONSTANT("EXTR_PREFIX_IF_EXISTS", EXTR_PREFIX_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
108 REGISTER_LONG_CONSTANT("EXTR_IF_EXISTS", EXTR_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
109 REGISTER_LONG_CONSTANT("EXTR_REFS", EXTR_REFS, CONST_CS | CONST_PERSISTENT);
110
111 REGISTER_LONG_CONSTANT("SORT_ASC", PHP_SORT_ASC, CONST_CS | CONST_PERSISTENT);
112 REGISTER_LONG_CONSTANT("SORT_DESC", PHP_SORT_DESC, CONST_CS | CONST_PERSISTENT);
113
114 REGISTER_LONG_CONSTANT("SORT_REGULAR", PHP_SORT_REGULAR, CONST_CS | CONST_PERSISTENT);
115 REGISTER_LONG_CONSTANT("SORT_NUMERIC", PHP_SORT_NUMERIC, CONST_CS | CONST_PERSISTENT);
116 REGISTER_LONG_CONSTANT("SORT_STRING", PHP_SORT_STRING, CONST_CS | CONST_PERSISTENT);
117 REGISTER_LONG_CONSTANT("SORT_LOCALE_STRING", PHP_SORT_LOCALE_STRING, CONST_CS | CONST_PERSISTENT);
118 REGISTER_LONG_CONSTANT("SORT_NATURAL", PHP_SORT_NATURAL, CONST_CS | CONST_PERSISTENT);
119 REGISTER_LONG_CONSTANT("SORT_FLAG_CASE", PHP_SORT_FLAG_CASE, CONST_CS | CONST_PERSISTENT);
120
121 REGISTER_LONG_CONSTANT("CASE_LOWER", CASE_LOWER, CONST_CS | CONST_PERSISTENT);
122 REGISTER_LONG_CONSTANT("CASE_UPPER", CASE_UPPER, CONST_CS | CONST_PERSISTENT);
123
124 REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
125 REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
126
127 REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT);
128 REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT);
129
130 return SUCCESS;
131 }
132
133
134 PHP_MSHUTDOWN_FUNCTION(array)
135 {
136 #ifdef ZTS
137 ts_free_id(array_globals_id);
138 #endif
139
140 return SUCCESS;
141 }
142
143
144 static void php_set_compare_func(int sort_type TSRMLS_DC)
145 {
146 switch (sort_type & ~PHP_SORT_FLAG_CASE) {
147 case PHP_SORT_NUMERIC:
148 ARRAYG(compare_func) = numeric_compare_function;
149 break;
150
151 case PHP_SORT_STRING:
152 ARRAYG(compare_func) = sort_type & PHP_SORT_FLAG_CASE ? string_case_compare_function : string_compare_function;
153 break;
154
155 case PHP_SORT_NATURAL:
156 ARRAYG(compare_func) = sort_type & PHP_SORT_FLAG_CASE ? string_natural_case_compare_function : string_natural_compare_function;
157 break;
158
159 #if HAVE_STRCOLL
160 case PHP_SORT_LOCALE_STRING:
161 ARRAYG(compare_func) = string_locale_compare_function;
162 break;
163 #endif
164
165 case PHP_SORT_REGULAR:
166 default:
167 ARRAYG(compare_func) = compare_function;
168 break;
169 }
170 }
171
172
173 static int php_array_key_compare(const void *a, const void *b TSRMLS_DC)
174 {
175 Bucket *f;
176 Bucket *s;
177 zval result;
178 zval first;
179 zval second;
180
181 f = *((Bucket **) a);
182 s = *((Bucket **) b);
183
184 if (f->nKeyLength == 0) {
185 Z_TYPE(first) = IS_LONG;
186 Z_LVAL(first) = f->h;
187 } else {
188 Z_TYPE(first) = IS_STRING;
189 Z_STRVAL(first) = (char*)f->arKey;
190 Z_STRLEN(first) = f->nKeyLength - 1;
191 }
192
193 if (s->nKeyLength == 0) {
194 Z_TYPE(second) = IS_LONG;
195 Z_LVAL(second) = s->h;
196 } else {
197 Z_TYPE(second) = IS_STRING;
198 Z_STRVAL(second) = (char*)s->arKey;
199 Z_STRLEN(second) = s->nKeyLength - 1;
200 }
201
202 if (ARRAYG(compare_func)(&result, &first, &second TSRMLS_CC) == FAILURE) {
203 return 0;
204 }
205
206 if (Z_TYPE(result) == IS_DOUBLE) {
207 if (Z_DVAL(result) < 0) {
208 return -1;
209 } else if (Z_DVAL(result) > 0) {
210 return 1;
211 } else {
212 return 0;
213 }
214 }
215
216 convert_to_long(&result);
217
218 if (Z_LVAL(result) < 0) {
219 return -1;
220 } else if (Z_LVAL(result) > 0) {
221 return 1;
222 }
223
224 return 0;
225 }
226
227
228 static int php_array_reverse_key_compare(const void *a, const void *b TSRMLS_DC)
229 {
230 return php_array_key_compare(a, b TSRMLS_CC) * -1;
231 }
232
233
234
235
236 PHP_FUNCTION(krsort)
237 {
238 zval *array;
239 long sort_type = PHP_SORT_REGULAR;
240
241 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
242 RETURN_FALSE;
243 }
244
245 php_set_compare_func(sort_type TSRMLS_CC);
246
247 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_key_compare, 0 TSRMLS_CC) == FAILURE) {
248 RETURN_FALSE;
249 }
250 RETURN_TRUE;
251 }
252
253
254
255
256 PHP_FUNCTION(ksort)
257 {
258 zval *array;
259 long sort_type = PHP_SORT_REGULAR;
260
261 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
262 RETURN_FALSE;
263 }
264
265 php_set_compare_func(sort_type TSRMLS_CC);
266
267 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_key_compare, 0 TSRMLS_CC) == FAILURE) {
268 RETURN_FALSE;
269 }
270 RETURN_TRUE;
271 }
272
273
274 PHPAPI int php_count_recursive(zval *array, long mode TSRMLS_DC)
275 {
276 long cnt = 0;
277 zval **element;
278
279 if (Z_TYPE_P(array) == IS_ARRAY) {
280 if (Z_ARRVAL_P(array)->nApplyCount > 1) {
281 php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
282 return 0;
283 }
284
285 cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
286 if (mode == COUNT_RECURSIVE) {
287 HashPosition pos;
288
289 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
290 zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **) &element, &pos) == SUCCESS;
291 zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)
292 ) {
293 Z_ARRVAL_P(array)->nApplyCount++;
294 cnt += php_count_recursive(*element, COUNT_RECURSIVE TSRMLS_CC);
295 Z_ARRVAL_P(array)->nApplyCount--;
296 }
297 }
298 }
299
300 return cnt;
301 }
302
303
304
305
306 PHP_FUNCTION(count)
307 {
308 zval *array;
309 long mode = COUNT_NORMAL;
310
311 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) {
312 return;
313 }
314
315 switch (Z_TYPE_P(array)) {
316 case IS_NULL:
317 RETURN_LONG(0);
318 break;
319 case IS_ARRAY:
320 RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));
321 break;
322 case IS_OBJECT: {
323 #ifdef HAVE_SPL
324 zval *retval;
325 #endif
326
327 if (Z_OBJ_HT_P(array)->count_elements) {
328 RETVAL_LONG(1);
329 if (SUCCESS == Z_OBJ_HT(*array)->count_elements(array, &Z_LVAL_P(return_value) TSRMLS_CC)) {
330 return;
331 }
332 }
333 #ifdef HAVE_SPL
334
335 if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Countable TSRMLS_CC)) {
336 zend_call_method_with_0_params(&array, NULL, NULL, "count", &retval);
337 if (retval) {
338 convert_to_long_ex(&retval);
339 RETVAL_LONG(Z_LVAL_P(retval));
340 zval_ptr_dtor(&retval);
341 }
342 return;
343 }
344 #endif
345 }
346 default:
347 RETURN_LONG(1);
348 break;
349 }
350 }
351
352
353
354
355
356
357
358
359 static int php_array_data_compare(const void *a, const void *b TSRMLS_DC)
360 {
361 Bucket *f;
362 Bucket *s;
363 zval result;
364 zval *first;
365 zval *second;
366
367 f = *((Bucket **) a);
368 s = *((Bucket **) b);
369
370 first = *((zval **) f->pData);
371 second = *((zval **) s->pData);
372
373 if (ARRAYG(compare_func)(&result, first, second TSRMLS_CC) == FAILURE) {
374 return 0;
375 }
376
377 if (Z_TYPE(result) == IS_DOUBLE) {
378 if (Z_DVAL(result) < 0) {
379 return -1;
380 } else if (Z_DVAL(result) > 0) {
381 return 1;
382 } else {
383 return 0;
384 }
385 }
386
387 convert_to_long(&result);
388
389 if (Z_LVAL(result) < 0) {
390 return -1;
391 } else if (Z_LVAL(result) > 0) {
392 return 1;
393 }
394
395 return 0;
396 }
397
398
399 static int php_array_reverse_data_compare(const void *a, const void *b TSRMLS_DC)
400 {
401 return php_array_data_compare(a, b TSRMLS_CC) * -1;
402 }
403
404
405 static int php_array_natural_general_compare(const void *a, const void *b, int fold_case)
406 {
407 Bucket *f, *s;
408 zval *fval, *sval;
409 zval first, second;
410 int result;
411
412 f = *((Bucket **) a);
413 s = *((Bucket **) b);
414
415 fval = *((zval **) f->pData);
416 sval = *((zval **) s->pData);
417 first = *fval;
418 second = *sval;
419
420 if (Z_TYPE_P(fval) != IS_STRING) {
421 zval_copy_ctor(&first);
422 convert_to_string(&first);
423 }
424
425 if (Z_TYPE_P(sval) != IS_STRING) {
426 zval_copy_ctor(&second);
427 convert_to_string(&second);
428 }
429
430 result = strnatcmp_ex(Z_STRVAL(first), Z_STRLEN(first), Z_STRVAL(second), Z_STRLEN(second), fold_case);
431
432 if (Z_TYPE_P(fval) != IS_STRING) {
433 zval_dtor(&first);
434 }
435
436 if (Z_TYPE_P(sval) != IS_STRING) {
437 zval_dtor(&second);
438 }
439
440 return result;
441 }
442
443
444 static int php_array_natural_compare(const void *a, const void *b TSRMLS_DC)
445 {
446 return php_array_natural_general_compare(a, b, 0);
447 }
448
449
450 static int php_array_natural_case_compare(const void *a, const void *b TSRMLS_DC)
451 {
452 return php_array_natural_general_compare(a, b, 1);
453 }
454
455
456 static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
457 {
458 zval *array;
459
460 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
461 return;
462 }
463
464 if (fold_case) {
465 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_case_compare, 0 TSRMLS_CC) == FAILURE) {
466 return;
467 }
468 } else {
469 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_compare, 0 TSRMLS_CC) == FAILURE) {
470 return;
471 }
472 }
473
474 RETURN_TRUE;
475 }
476
477
478
479
480 PHP_FUNCTION(natsort)
481 {
482 php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
483 }
484
485
486
487
488 PHP_FUNCTION(natcasesort)
489 {
490 php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
491 }
492
493
494
495
496 PHP_FUNCTION(asort)
497 {
498 zval *array;
499 long sort_type = PHP_SORT_REGULAR;
500
501 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
502 RETURN_FALSE;
503 }
504
505 php_set_compare_func(sort_type TSRMLS_CC);
506
507 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 0 TSRMLS_CC) == FAILURE) {
508 RETURN_FALSE;
509 }
510 RETURN_TRUE;
511 }
512
513
514
515
516 PHP_FUNCTION(arsort)
517 {
518 zval *array;
519 long sort_type = PHP_SORT_REGULAR;
520
521 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
522 RETURN_FALSE;
523 }
524
525 php_set_compare_func(sort_type TSRMLS_CC);
526
527 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 0 TSRMLS_CC) == FAILURE) {
528 RETURN_FALSE;
529 }
530 RETURN_TRUE;
531 }
532
533
534
535
536 PHP_FUNCTION(sort)
537 {
538 zval *array;
539 long sort_type = PHP_SORT_REGULAR;
540
541 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
542 RETURN_FALSE;
543 }
544
545 php_set_compare_func(sort_type TSRMLS_CC);
546
547 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 1 TSRMLS_CC) == FAILURE) {
548 RETURN_FALSE;
549 }
550 RETURN_TRUE;
551 }
552
553
554
555
556 PHP_FUNCTION(rsort)
557 {
558 zval *array;
559 long sort_type = PHP_SORT_REGULAR;
560
561 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
562 RETURN_FALSE;
563 }
564
565 php_set_compare_func(sort_type TSRMLS_CC);
566
567 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 1 TSRMLS_CC) == FAILURE) {
568 RETURN_FALSE;
569 }
570 RETURN_TRUE;
571 }
572
573
574 static int php_array_user_compare(const void *a, const void *b TSRMLS_DC)
575 {
576 Bucket *f;
577 Bucket *s;
578 zval **args[2];
579 zval *retval_ptr = NULL;
580
581 f = *((Bucket **) a);
582 s = *((Bucket **) b);
583
584 args[0] = (zval **) f->pData;
585 args[1] = (zval **) s->pData;
586
587 BG(user_compare_fci).param_count = 2;
588 BG(user_compare_fci).params = args;
589 BG(user_compare_fci).retval_ptr_ptr = &retval_ptr;
590 BG(user_compare_fci).no_separation = 0;
591 if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache) TSRMLS_CC) == SUCCESS && retval_ptr) {
592 long retval;
593
594 convert_to_long_ex(&retval_ptr);
595 retval = Z_LVAL_P(retval_ptr);
596 zval_ptr_dtor(&retval_ptr);
597 return retval < 0 ? -1 : retval > 0 ? 1 : 0;
598 } else {
599 return 0;
600 }
601 }
602
603
604
605 #define PHP_ARRAY_CMP_FUNC_CHECK(func_name) \
606 if (!zend_is_callable(*func_name, 0, NULL TSRMLS_CC)) { \
607 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid comparison function"); \
608 BG(user_compare_fci) = old_user_compare_fci; \
609 BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
610 RETURN_FALSE; \
611 } \
612
613
614
615
616
617
618
619
620 #define PHP_ARRAY_CMP_FUNC_VARS \
621 zend_fcall_info old_user_compare_fci; \
622 zend_fcall_info_cache old_user_compare_fci_cache \
623
624 #define PHP_ARRAY_CMP_FUNC_BACKUP() \
625 old_user_compare_fci = BG(user_compare_fci); \
626 old_user_compare_fci_cache = BG(user_compare_fci_cache); \
627 BG(user_compare_fci_cache) = empty_fcall_info_cache; \
628
629 #define PHP_ARRAY_CMP_FUNC_RESTORE() \
630 BG(user_compare_fci) = old_user_compare_fci; \
631 BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
632
633
634
635 PHP_FUNCTION(usort)
636 {
637 zval *array;
638 unsigned int refcount;
639 PHP_ARRAY_CMP_FUNC_VARS;
640
641 PHP_ARRAY_CMP_FUNC_BACKUP();
642
643 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
644 PHP_ARRAY_CMP_FUNC_RESTORE();
645 return;
646 }
647
648
649
650
651
652
653
654 Z_UNSET_ISREF_P(array);
655 refcount = Z_REFCOUNT_P(array);
656
657 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 1 TSRMLS_CC) == FAILURE) {
658 RETVAL_FALSE;
659 } else {
660 if (refcount > Z_REFCOUNT_P(array)) {
661 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
662 RETVAL_FALSE;
663 } else {
664 RETVAL_TRUE;
665 }
666 }
667
668 if (Z_REFCOUNT_P(array) > 1) {
669 Z_SET_ISREF_P(array);
670 }
671
672 PHP_ARRAY_CMP_FUNC_RESTORE();
673 }
674
675
676
677
678 PHP_FUNCTION(uasort)
679 {
680 zval *array;
681 unsigned int refcount;
682 PHP_ARRAY_CMP_FUNC_VARS;
683
684 PHP_ARRAY_CMP_FUNC_BACKUP();
685
686 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
687 PHP_ARRAY_CMP_FUNC_RESTORE();
688 return;
689 }
690
691
692
693
694
695
696
697 Z_UNSET_ISREF_P(array);
698 refcount = Z_REFCOUNT_P(array);
699
700 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 0 TSRMLS_CC) == FAILURE) {
701 RETVAL_FALSE;
702 } else {
703 if (refcount > Z_REFCOUNT_P(array)) {
704 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
705 RETVAL_FALSE;
706 } else {
707 RETVAL_TRUE;
708 }
709 }
710
711 if (Z_REFCOUNT_P(array) > 1) {
712 Z_SET_ISREF_P(array);
713 }
714
715 PHP_ARRAY_CMP_FUNC_RESTORE();
716 }
717
718
719 static int php_array_user_key_compare(const void *a, const void *b TSRMLS_DC)
720 {
721 Bucket *f;
722 Bucket *s;
723 zval *key1, *key2;
724 zval **args[2];
725 zval *retval_ptr = NULL;
726 long result;
727
728 ALLOC_INIT_ZVAL(key1);
729 ALLOC_INIT_ZVAL(key2);
730 args[0] = &key1;
731 args[1] = &key2;
732
733 f = *((Bucket **) a);
734 s = *((Bucket **) b);
735
736 if (f->nKeyLength == 0) {
737 Z_LVAL_P(key1) = f->h;
738 Z_TYPE_P(key1) = IS_LONG;
739 } else {
740 Z_STRVAL_P(key1) = estrndup(f->arKey, f->nKeyLength - 1);
741 Z_STRLEN_P(key1) = f->nKeyLength - 1;
742 Z_TYPE_P(key1) = IS_STRING;
743 }
744 if (s->nKeyLength == 0) {
745 Z_LVAL_P(key2) = s->h;
746 Z_TYPE_P(key2) = IS_LONG;
747 } else {
748 Z_STRVAL_P(key2) = estrndup(s->arKey, s->nKeyLength - 1);
749 Z_STRLEN_P(key2) = s->nKeyLength - 1;
750 Z_TYPE_P(key2) = IS_STRING;
751 }
752
753 BG(user_compare_fci).param_count = 2;
754 BG(user_compare_fci).params = args;
755 BG(user_compare_fci).retval_ptr_ptr = &retval_ptr;
756 BG(user_compare_fci).no_separation = 0;
757 if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache) TSRMLS_CC) == SUCCESS && retval_ptr) {
758 convert_to_long_ex(&retval_ptr);
759 result = Z_LVAL_P(retval_ptr);
760 zval_ptr_dtor(&retval_ptr);
761 } else {
762 result = 0;
763 }
764
765 zval_ptr_dtor(&key1);
766 zval_ptr_dtor(&key2);
767
768 return result;
769 }
770
771
772
773
774 PHP_FUNCTION(uksort)
775 {
776 zval *array;
777 unsigned int refcount;
778 PHP_ARRAY_CMP_FUNC_VARS;
779
780 PHP_ARRAY_CMP_FUNC_BACKUP();
781
782 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
783 PHP_ARRAY_CMP_FUNC_RESTORE();
784 return;
785 }
786
787
788
789
790
791
792
793 Z_UNSET_ISREF_P(array);
794 refcount = Z_REFCOUNT_P(array);
795
796 if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_key_compare, 0 TSRMLS_CC) == FAILURE) {
797 RETVAL_FALSE;
798 } else {
799 if (refcount > Z_REFCOUNT_P(array)) {
800 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
801 RETVAL_FALSE;
802 } else {
803 RETVAL_TRUE;
804 }
805 }
806
807 if (Z_REFCOUNT_P(array) > 1) {
808 Z_SET_ISREF_P(array);
809 }
810
811 PHP_ARRAY_CMP_FUNC_RESTORE();
812 }
813
814
815
816
817 PHP_FUNCTION(end)
818 {
819 HashTable *array;
820 zval **entry;
821
822 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
823 return;
824 }
825
826 zend_hash_internal_pointer_end(array);
827
828 if (return_value_used) {
829 if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
830 RETURN_FALSE;
831 }
832
833 RETURN_ZVAL_FAST(*entry);
834 }
835 }
836
837
838
839
840 PHP_FUNCTION(prev)
841 {
842 HashTable *array;
843 zval **entry;
844
845 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
846 return;
847 }
848
849 zend_hash_move_backwards(array);
850
851 if (return_value_used) {
852 if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
853 RETURN_FALSE;
854 }
855
856 RETURN_ZVAL_FAST(*entry);
857 }
858 }
859
860
861
862
863 PHP_FUNCTION(next)
864 {
865 HashTable *array;
866 zval **entry;
867
868 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
869 return;
870 }
871
872 zend_hash_move_forward(array);
873
874 if (return_value_used) {
875 if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
876 RETURN_FALSE;
877 }
878
879 RETURN_ZVAL_FAST(*entry);
880 }
881 }
882
883
884
885
886 PHP_FUNCTION(reset)
887 {
888 HashTable *array;
889 zval **entry;
890
891 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
892 return;
893 }
894
895 zend_hash_internal_pointer_reset(array);
896
897 if (return_value_used) {
898 if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
899 RETURN_FALSE;
900 }
901
902 RETURN_ZVAL_FAST(*entry);
903 }
904 }
905
906
907
908
909 PHP_FUNCTION(current)
910 {
911 HashTable *array;
912 zval **entry;
913
914 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
915 return;
916 }
917
918 if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
919 RETURN_FALSE;
920 }
921
922 RETURN_ZVAL_FAST(*entry);
923 }
924
925
926
927
928 PHP_FUNCTION(key)
929 {
930 HashTable *array;
931
932 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
933 return;
934 }
935
936 zend_hash_get_current_key_zval(array, return_value);
937 }
938
939
940
941
942 PHP_FUNCTION(min)
943 {
944 int argc;
945 zval ***args = NULL;
946
947 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
948 return;
949 }
950
951 php_set_compare_func(PHP_SORT_REGULAR TSRMLS_CC);
952
953
954 if (argc == 1) {
955 zval **result;
956
957 if (Z_TYPE_PP(args[0]) != IS_ARRAY) {
958 php_error_docref(NULL TSRMLS_CC, E_WARNING, "When only one parameter is given, it must be an array");
959 RETVAL_NULL();
960 } else {
961 if (zend_hash_minmax(Z_ARRVAL_PP(args[0]), php_array_data_compare, 0, (void **) &result TSRMLS_CC) == SUCCESS) {
962 RETVAL_ZVAL_FAST(*result);
963 } else {
964 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array must contain at least one element");
965 RETVAL_FALSE;
966 }
967 }
968 } else {
969
970 zval **min, result;
971 int i;
972
973 min = args[0];
974
975 for (i = 1; i < argc; i++) {
976 is_smaller_function(&result, *args[i], *min TSRMLS_CC);
977 if (Z_LVAL(result) == 1) {
978 min = args[i];
979 }
980 }
981
982 RETVAL_ZVAL_FAST(*min);
983 }
984
985 if (args) {
986 efree(args);
987 }
988 }
989
990
991
992
993 PHP_FUNCTION(max)
994 {
995 zval ***args = NULL;
996 int argc;
997
998 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
999 return;
1000 }
1001
1002 php_set_compare_func(PHP_SORT_REGULAR TSRMLS_CC);
1003
1004
1005 if (argc == 1) {
1006 zval **result;
1007
1008 if (Z_TYPE_PP(args[0]) != IS_ARRAY) {
1009 php_error_docref(NULL TSRMLS_CC, E_WARNING, "When only one parameter is given, it must be an array");
1010 RETVAL_NULL();
1011 } else {
1012 if (zend_hash_minmax(Z_ARRVAL_PP(args[0]), php_array_data_compare, 1, (void **) &result TSRMLS_CC) == SUCCESS) {
1013 RETVAL_ZVAL_FAST(*result);
1014 } else {
1015 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array must contain at least one element");
1016 RETVAL_FALSE;
1017 }
1018 }
1019 } else {
1020
1021 zval **max, result;
1022 int i;
1023
1024 max = args[0];
1025
1026 for (i = 1; i < argc; i++) {
1027 is_smaller_or_equal_function(&result, *args[i], *max TSRMLS_CC);
1028 if (Z_LVAL(result) == 0) {
1029 max = args[i];
1030 }
1031 }
1032
1033 RETVAL_ZVAL_FAST(*max);
1034 }
1035
1036 if (args) {
1037 efree(args);
1038 }
1039 }
1040
1041
1042 static int php_array_walk(HashTable *target_hash, zval *userdata, int recursive TSRMLS_DC)
1043 {
1044 zval **args[3],
1045 *retval_ptr = NULL,
1046 *key=NULL;
1047
1048
1049 args[1] = &key;
1050 args[2] = &userdata;
1051 if (userdata) {
1052 Z_ADDREF_P(userdata);
1053 }
1054
1055 BG(array_walk_fci).retval_ptr_ptr = &retval_ptr;
1056 BG(array_walk_fci).param_count = userdata ? 3 : 2;
1057 BG(array_walk_fci).params = args;
1058 BG(array_walk_fci).no_separation = 0;
1059
1060
1061 zend_hash_internal_pointer_reset(target_hash);
1062 while (!EG(exception) && zend_hash_get_current_data(target_hash, (void **)&args[0]) == SUCCESS) {
1063 if (recursive && Z_TYPE_PP(args[0]) == IS_ARRAY) {
1064 HashTable *thash;
1065 zend_fcall_info orig_array_walk_fci;
1066 zend_fcall_info_cache orig_array_walk_fci_cache;
1067
1068 SEPARATE_ZVAL_IF_NOT_REF(args[0]);
1069 thash = Z_ARRVAL_PP(args[0]);
1070 if (thash->nApplyCount > 1) {
1071 php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
1072 if (userdata) {
1073 zval_ptr_dtor(&userdata);
1074 }
1075 return 0;
1076 }
1077
1078
1079 orig_array_walk_fci = BG(array_walk_fci);
1080 orig_array_walk_fci_cache = BG(array_walk_fci_cache);
1081
1082 thash->nApplyCount++;
1083 php_array_walk(thash, userdata, recursive TSRMLS_CC);
1084 thash->nApplyCount--;
1085
1086
1087 BG(array_walk_fci) = orig_array_walk_fci;
1088 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1089 } else {
1090
1091 MAKE_STD_ZVAL(key);
1092 zend_hash_get_current_key_zval(target_hash, key);
1093
1094
1095 if (zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache) TSRMLS_CC) == SUCCESS) {
1096 if (retval_ptr) {
1097 zval_ptr_dtor(&retval_ptr);
1098 }
1099 } else {
1100 if (key) {
1101 zval_ptr_dtor(&key);
1102 key = NULL;
1103 }
1104 break;
1105 }
1106 }
1107
1108 if (key) {
1109 zval_ptr_dtor(&key);
1110 key = NULL;
1111 }
1112 zend_hash_move_forward(target_hash);
1113 }
1114
1115 if (userdata) {
1116 zval_ptr_dtor(&userdata);
1117 }
1118 return 0;
1119 }
1120
1121
1122
1123
1124 PHP_FUNCTION(array_walk)
1125 {
1126 HashTable *array;
1127 zval *userdata = NULL;
1128 zend_fcall_info orig_array_walk_fci;
1129 zend_fcall_info_cache orig_array_walk_fci_cache;
1130
1131 orig_array_walk_fci = BG(array_walk_fci);
1132 orig_array_walk_fci_cache = BG(array_walk_fci_cache);
1133
1134 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Hf|z/", &array, &BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
1135 BG(array_walk_fci) = orig_array_walk_fci;
1136 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1137 return;
1138 }
1139
1140 php_array_walk(array, userdata, 0 TSRMLS_CC);
1141 BG(array_walk_fci) = orig_array_walk_fci;
1142 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1143 RETURN_TRUE;
1144 }
1145
1146
1147
1148
1149 PHP_FUNCTION(array_walk_recursive)
1150 {
1151 HashTable *array;
1152 zval *userdata = NULL;
1153 zend_fcall_info orig_array_walk_fci;
1154 zend_fcall_info_cache orig_array_walk_fci_cache;
1155
1156 orig_array_walk_fci = BG(array_walk_fci);
1157 orig_array_walk_fci_cache = BG(array_walk_fci_cache);
1158
1159 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Hf|z/", &array, &BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
1160 BG(array_walk_fci) = orig_array_walk_fci;
1161 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1162 return;
1163 }
1164
1165 php_array_walk(array, userdata, 1 TSRMLS_CC);
1166 BG(array_walk_fci) = orig_array_walk_fci;
1167 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
1168 RETURN_TRUE;
1169 }
1170
1171
1172
1173
1174
1175
1176 static void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
1177 {
1178 zval *value,
1179 *array,
1180 **entry,
1181 res;
1182 HashPosition pos;
1183 zend_bool strict = 0;
1184 int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
1185
1186 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za|b", &value, &array, &strict) == FAILURE) {
1187 return;
1188 }
1189
1190 if (strict) {
1191 is_equal_func = is_identical_function;
1192 }
1193
1194 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
1195 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {
1196 is_equal_func(&res, value, *entry TSRMLS_CC);
1197 if (Z_LVAL(res)) {
1198 if (behavior == 0) {
1199 RETURN_TRUE;
1200 } else {
1201 zend_hash_get_current_key_zval_ex(Z_ARRVAL_P(array), return_value, &pos);
1202 return;
1203 }
1204 }
1205 zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos);
1206 }
1207
1208 RETURN_FALSE;
1209 }
1210
1211
1212
1213
1214 PHP_FUNCTION(in_array)
1215 {
1216 php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1217 }
1218
1219
1220
1221
1222 PHP_FUNCTION(array_search)
1223 {
1224 php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1225 }
1226
1227
1228 static int php_valid_var_name(char *var_name, int var_name_len)
1229 {
1230 int i, ch;
1231
1232 if (!var_name || !var_name_len) {
1233 return 0;
1234 }
1235
1236
1237 ch = (int)((unsigned char *)var_name)[0];
1238 if (var_name[0] != '_' &&
1239 (ch < 65 || ch > 90) &&
1240 (ch < 97 || ch > 122) &&
1241 (ch < 127 || ch > 255)
1242 ) {
1243 return 0;
1244 }
1245
1246
1247 if (var_name_len > 1) {
1248 for (i = 1; i < var_name_len; i++) {
1249 ch = (int)((unsigned char *)var_name)[i];
1250 if (var_name[i] != '_' &&
1251 (ch < 48 || ch > 57) &&
1252 (ch < 65 || ch > 90) &&
1253 (ch < 97 || ch > 122) &&
1254 (ch < 127 || ch > 255)
1255 ) {
1256 return 0;
1257 }
1258 }
1259 }
1260 return 1;
1261 }
1262
1263
1264 PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, int var_name_len, zend_bool add_underscore TSRMLS_DC)
1265 {
1266 Z_STRLEN_P(result) = Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0) + var_name_len;
1267 Z_TYPE_P(result) = IS_STRING;
1268 Z_STRVAL_P(result) = emalloc(Z_STRLEN_P(result) + 1);
1269 memcpy(Z_STRVAL_P(result), Z_STRVAL_P(prefix), Z_STRLEN_P(prefix));
1270
1271 if (add_underscore) {
1272 Z_STRVAL_P(result)[Z_STRLEN_P(prefix)] = '_';
1273 }
1274
1275 memcpy(Z_STRVAL_P(result) + Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1);
1276
1277 return SUCCESS;
1278 }
1279
1280
1281
1282
1283 PHP_FUNCTION(extract)
1284 {
1285 zval *var_array, *prefix = NULL;
1286 long extract_type = EXTR_OVERWRITE;
1287 zval **entry, *data;
1288 char *var_name;
1289 ulong num_key;
1290 uint var_name_len;
1291 int var_exists, key_type, count = 0;
1292 int extract_refs = 0;
1293 HashPosition pos;
1294
1295 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|lz/", &var_array, &extract_type, &prefix) == FAILURE) {
1296 return;
1297 }
1298
1299 extract_refs = (extract_type & EXTR_REFS);
1300 extract_type &= 0xff;
1301
1302 if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) {
1303 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid extract type");
1304 return;
1305 }
1306
1307 if (extract_type > EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS && ZEND_NUM_ARGS() < 3) {
1308 php_error_docref(NULL TSRMLS_CC, E_WARNING, "specified extract type requires the prefix parameter");
1309 return;
1310 }
1311
1312 if (prefix) {
1313 convert_to_string(prefix);
1314 if (Z_STRLEN_P(prefix) && !php_valid_var_name(Z_STRVAL_P(prefix), Z_STRLEN_P(prefix))) {
1315 php_error_docref(NULL TSRMLS_CC, E_WARNING, "prefix is not a valid identifier");
1316 return;
1317 }
1318 }
1319
1320 if (!EG(active_symbol_table)) {
1321 zend_rebuild_symbol_table(TSRMLS_C);
1322 }
1323
1324
1325
1326
1327 if (!extract_refs) {
1328 SEPARATE_ARG_IF_REF(var_array);
1329 }
1330
1331 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
1332 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&entry, &pos) == SUCCESS) {
1333 zval final_name;
1334
1335 ZVAL_NULL(&final_name);
1336
1337 key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &var_name, &var_name_len, &num_key, 0, &pos);
1338 var_exists = 0;
1339
1340 if (key_type == HASH_KEY_IS_STRING) {
1341 var_name_len--;
1342 var_exists = zend_hash_exists(EG(active_symbol_table), var_name, var_name_len + 1);
1343 } else if (key_type == HASH_KEY_IS_LONG && (extract_type == EXTR_PREFIX_ALL || extract_type == EXTR_PREFIX_INVALID)) {
1344 zval num;
1345
1346 ZVAL_LONG(&num, num_key);
1347 convert_to_string(&num);
1348 php_prefix_varname(&final_name, prefix, Z_STRVAL(num), Z_STRLEN(num), 1 TSRMLS_CC);
1349 zval_dtor(&num);
1350 } else {
1351 zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
1352 continue;
1353 }
1354
1355 switch (extract_type) {
1356 case EXTR_IF_EXISTS:
1357 if (!var_exists) break;
1358
1359
1360 case EXTR_OVERWRITE:
1361
1362 if (var_exists && var_name_len == sizeof("GLOBALS")-1 && !strcmp(var_name, "GLOBALS")) {
1363 break;
1364 }
1365 if (var_exists && var_name_len == sizeof("this")-1 && !strcmp(var_name, "this") && EG(scope) && EG(scope)->name_length != 0) {
1366 break;
1367 }
1368 ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
1369 break;
1370
1371 case EXTR_PREFIX_IF_EXISTS:
1372 if (var_exists) {
1373 php_prefix_varname(&final_name, prefix, var_name, var_name_len, 1 TSRMLS_CC);
1374 }
1375 break;
1376
1377 case EXTR_PREFIX_SAME:
1378 if (!var_exists && var_name_len != 0) {
1379 ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
1380 }
1381
1382
1383 case EXTR_PREFIX_ALL:
1384 if (Z_TYPE(final_name) == IS_NULL && var_name_len != 0) {
1385 php_prefix_varname(&final_name, prefix, var_name, var_name_len, 1 TSRMLS_CC);
1386 }
1387 break;
1388
1389 case EXTR_PREFIX_INVALID:
1390 if (Z_TYPE(final_name) == IS_NULL) {
1391 if (!php_valid_var_name(var_name, var_name_len)) {
1392 php_prefix_varname(&final_name, prefix, var_name, var_name_len, 1 TSRMLS_CC);
1393 } else {
1394 ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
1395 }
1396 }
1397 break;
1398
1399 default:
1400 if (!var_exists) {
1401 ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
1402 }
1403 break;
1404 }
1405
1406 if (Z_TYPE(final_name) != IS_NULL && php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
1407 if (extract_refs) {
1408 zval **orig_var;
1409
1410 SEPARATE_ZVAL_TO_MAKE_IS_REF(entry);
1411 zval_add_ref(entry);
1412
1413 if (zend_hash_find(EG(active_symbol_table), Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, (void **) &orig_var) == SUCCESS) {
1414 zval_ptr_dtor(orig_var);
1415 *orig_var = *entry;
1416 } else {
1417 zend_hash_update(EG(active_symbol_table), Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, (void **) entry, sizeof(zval *), NULL);
1418 }
1419 } else {
1420 MAKE_STD_ZVAL(data);
1421 *data = **entry;
1422 zval_copy_ctor(data);
1423
1424 ZEND_SET_SYMBOL_WITH_LENGTH(EG(active_symbol_table), Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, data, 1, 0);
1425 }
1426 count++;
1427 }
1428 zval_dtor(&final_name);
1429
1430 zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
1431 }
1432
1433 if (!extract_refs) {
1434 zval_ptr_dtor(&var_array);
1435 }
1436
1437 RETURN_LONG(count);
1438 }
1439
1440
1441 static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_value, zval *entry TSRMLS_DC)
1442 {
1443 zval **value_ptr, *value, *data;
1444
1445 if (Z_TYPE_P(entry) == IS_STRING) {
1446 if (zend_hash_find(eg_active_symbol_table, Z_STRVAL_P(entry), Z_STRLEN_P(entry) + 1, (void **)&value_ptr) != FAILURE) {
1447 value = *value_ptr;
1448 ALLOC_ZVAL(data);
1449 MAKE_COPY_ZVAL(&value, data);
1450
1451 zend_hash_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(entry), Z_STRLEN_P(entry) + 1, &data, sizeof(zval *), NULL);
1452 }
1453 }
1454 else if (Z_TYPE_P(entry) == IS_ARRAY) {
1455 HashPosition pos;
1456
1457 if ((Z_ARRVAL_P(entry)->nApplyCount > 1)) {
1458 php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
1459 return;
1460 }
1461
1462 Z_ARRVAL_P(entry)->nApplyCount++;
1463
1464 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos);
1465 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), (void**)&value_ptr, &pos) == SUCCESS) {
1466 value = *value_ptr;
1467
1468 php_compact_var(eg_active_symbol_table, return_value, value TSRMLS_CC);
1469 zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos);
1470 }
1471 Z_ARRVAL_P(entry)->nApplyCount--;
1472 }
1473 }
1474
1475
1476
1477
1478 PHP_FUNCTION(compact)
1479 {
1480 zval ***args = NULL;
1481 int num_args, i;
1482
1483 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
1484 return;
1485 }
1486
1487 if (!EG(active_symbol_table)) {
1488 zend_rebuild_symbol_table(TSRMLS_C);
1489 }
1490
1491
1492
1493
1494 if (ZEND_NUM_ARGS() == 1 && Z_TYPE_PP(args[0]) == IS_ARRAY) {
1495 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_PP(args[0])));
1496 } else {
1497 array_init_size(return_value, ZEND_NUM_ARGS());
1498 }
1499
1500 for (i=0; i<ZEND_NUM_ARGS(); i++) {
1501 php_compact_var(EG(active_symbol_table), return_value, *args[i] TSRMLS_CC);
1502 }
1503
1504 if (args) {
1505 efree(args);
1506 }
1507 }
1508
1509
1510
1511
1512 PHP_FUNCTION(array_fill)
1513 {
1514 zval *val;
1515 long start_key, num;
1516
1517 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "llz", &start_key, &num, &val) == FAILURE) {
1518 return;
1519 }
1520
1521 if (num < 0) {
1522 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements can't be negative");
1523 RETURN_FALSE;
1524 }
1525
1526
1527 array_init_size(return_value, num);
1528
1529 if (num == 0) {
1530 return;
1531 }
1532
1533 num--;
1534 zend_hash_index_update(Z_ARRVAL_P(return_value), start_key, &val, sizeof(zval *), NULL);
1535 zval_add_ref(&val);
1536
1537 while (num--) {
1538 if (zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &val, sizeof(zval *), NULL) == SUCCESS) {
1539 zval_add_ref(&val);
1540 } else {
1541 zval_dtor(return_value);
1542 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to the array as the next element is already occupied");
1543 RETURN_FALSE;
1544 }
1545 }
1546 }
1547
1548
1549
1550
1551 PHP_FUNCTION(array_fill_keys)
1552 {
1553 zval *keys, *val, **entry;
1554 HashPosition pos;
1555
1556 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az", &keys, &val) == FAILURE) {
1557 return;
1558 }
1559
1560
1561 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
1562
1563 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
1564 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&entry, &pos) == SUCCESS) {
1565
1566 if (Z_TYPE_PP(entry) == IS_LONG) {
1567 zval_add_ref(&val);
1568 zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &val, sizeof(zval *), NULL);
1569 } else {
1570 zval key, *key_ptr = *entry;
1571
1572 if (Z_TYPE_PP(entry) != IS_STRING) {
1573 key = **entry;
1574 zval_copy_ctor(&key);
1575 convert_to_string(&key);
1576 key_ptr = &key;
1577 }
1578
1579 zval_add_ref(&val);
1580 zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(key_ptr), Z_STRLEN_P(key_ptr) + 1, &val, sizeof(zval *), NULL);
1581
1582 if (key_ptr != *entry) {
1583 zval_dtor(&key);
1584 }
1585 }
1586
1587 zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
1588 }
1589 }
1590
1591
1592
1593
1594 PHP_FUNCTION(range)
1595 {
1596 zval *zlow, *zhigh, *zstep = NULL;
1597 int err = 0, is_step_double = 0;
1598 double step = 1.0;
1599
1600 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z/|z/", &zlow, &zhigh, &zstep) == FAILURE) {
1601 RETURN_FALSE;
1602 }
1603
1604 if (zstep) {
1605 if (Z_TYPE_P(zstep) == IS_DOUBLE ||
1606 (Z_TYPE_P(zstep) == IS_STRING && is_numeric_string(Z_STRVAL_P(zstep), Z_STRLEN_P(zstep), NULL, NULL, 0) == IS_DOUBLE)
1607 ) {
1608 is_step_double = 1;
1609 }
1610
1611 convert_to_double_ex(&zstep);
1612 step = Z_DVAL_P(zstep);
1613
1614
1615 if (step < 0.0) {
1616 step *= -1;
1617 }
1618 }
1619
1620
1621 array_init(return_value);
1622
1623
1624 if (Z_TYPE_P(zlow) == IS_STRING && Z_TYPE_P(zhigh) == IS_STRING && Z_STRLEN_P(zlow) >= 1 && Z_STRLEN_P(zhigh) >= 1) {
1625 int type1, type2;
1626 unsigned char *low, *high;
1627 long lstep = (long) step;
1628
1629 type1 = is_numeric_string(Z_STRVAL_P(zlow), Z_STRLEN_P(zlow), NULL, NULL, 0);
1630 type2 = is_numeric_string(Z_STRVAL_P(zhigh), Z_STRLEN_P(zhigh), NULL, NULL, 0);
1631
1632 if (type1 == IS_DOUBLE || type2 == IS_DOUBLE || is_step_double) {
1633 goto double_str;
1634 } else if (type1 == IS_LONG || type2 == IS_LONG) {
1635 goto long_str;
1636 }
1637
1638 convert_to_string(zlow);
1639 convert_to_string(zhigh);
1640 low = (unsigned char *)Z_STRVAL_P(zlow);
1641 high = (unsigned char *)Z_STRVAL_P(zhigh);
1642
1643 if (*low > *high) {
1644 unsigned char ch = *low;
1645
1646 if (lstep <= 0) {
1647 err = 1;
1648 goto err;
1649 }
1650 for (; ch >= *high; ch -= (unsigned int)lstep) {
1651 add_next_index_stringl(return_value, (const char *)&ch, 1, 1);
1652 if (((signed int)ch - lstep) < 0) {
1653 break;
1654 }
1655 }
1656 } else if (*high > *low) {
1657 unsigned char ch = *low;
1658
1659 if (lstep <= 0) {
1660 err = 1;
1661 goto err;
1662 }
1663 for (; ch <= *high; ch += (unsigned int)lstep) {
1664 add_next_index_stringl(return_value, (const char *)&ch, 1, 1);
1665 if (((signed int)ch + lstep) > 255) {
1666 break;
1667 }
1668 }
1669 } else {
1670 add_next_index_stringl(return_value, (const char *)low, 1, 1);
1671 }
1672
1673 } else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) {
1674 double low, high, value;
1675 long i;
1676 double_str:
1677 convert_to_double(zlow);
1678 convert_to_double(zhigh);
1679 low = Z_DVAL_P(zlow);
1680 high = Z_DVAL_P(zhigh);
1681 i = 0;
1682
1683 if (low > high) {
1684 if (low - high < step || step <= 0) {
1685 err = 1;
1686 goto err;
1687 }
1688
1689 for (value = low; value >= (high - DOUBLE_DRIFT_FIX); value = low - (++i * step)) {
1690 add_next_index_double(return_value, value);
1691 }
1692 } else if (high > low) {
1693 if (high - low < step || step <= 0) {
1694 err = 1;
1695 goto err;
1696 }
1697
1698 for (value = low; value <= (high + DOUBLE_DRIFT_FIX); value = low + (++i * step)) {
1699 add_next_index_double(return_value, value);
1700 }
1701 } else {
1702 add_next_index_double(return_value, low);
1703 }
1704 } else {
1705 double low, high;
1706 long lstep;
1707 long_str:
1708 convert_to_double(zlow);
1709 convert_to_double(zhigh);
1710 low = Z_DVAL_P(zlow);
1711 high = Z_DVAL_P(zhigh);
1712 lstep = (long) step;
1713
1714 if (low > high) {
1715 if (low - high < lstep || lstep <= 0) {
1716 err = 1;
1717 goto err;
1718 }
1719 for (; low >= high; low -= lstep) {
1720 add_next_index_long(return_value, (long)low);
1721 }
1722 } else if (high > low) {
1723 if (high - low < lstep || lstep <= 0) {
1724 err = 1;
1725 goto err;
1726 }
1727 for (; low <= high; low += lstep) {
1728 add_next_index_long(return_value, (long)low);
1729 }
1730 } else {
1731 add_next_index_long(return_value, (long)low);
1732 }
1733 }
1734 err:
1735 if (err) {
1736 php_error_docref(NULL TSRMLS_CC, E_WARNING, "step exceeds the specified range");
1737 zval_dtor(return_value);
1738 RETURN_FALSE;
1739 }
1740 }
1741
1742
1743 static void php_array_data_shuffle(zval *array TSRMLS_DC)
1744 {
1745 Bucket **elems, *temp;
1746 HashTable *hash;
1747 int j, n_elems, rnd_idx, n_left;
1748
1749 n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
1750
1751 if (n_elems < 1) {
1752 return;
1753 }
1754
1755 elems = (Bucket **)safe_emalloc(n_elems, sizeof(Bucket *), 0);
1756 hash = Z_ARRVAL_P(array);
1757 n_left = n_elems;
1758
1759 for (j = 0, temp = hash->pListHead; temp; temp = temp->pListNext)
1760 elems[j++] = temp;
1761 while (--n_left) {
1762 rnd_idx = php_rand(TSRMLS_C);
1763 RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
1764 if (rnd_idx != n_left) {
1765 temp = elems[n_left];
1766 elems[n_left] = elems[rnd_idx];
1767 elems[rnd_idx] = temp;
1768 }
1769 }
1770
1771 HANDLE_BLOCK_INTERRUPTIONS();
1772 hash->pListHead = elems[0];
1773 hash->pListTail = NULL;
1774 hash->pInternalPointer = hash->pListHead;
1775
1776 for (j = 0; j < n_elems; j++) {
1777 if (hash->pListTail) {
1778 hash->pListTail->pListNext = elems[j];
1779 }
1780 elems[j]->pListLast = hash->pListTail;
1781 elems[j]->pListNext = NULL;
1782 hash->pListTail = elems[j];
1783 }
1784 temp = hash->pListHead;
1785 j = 0;
1786 zend_hash_reindex(hash, 0);
1787 HANDLE_UNBLOCK_INTERRUPTIONS();
1788
1789 efree(elems);
1790 }
1791
1792
1793
1794
1795 PHP_FUNCTION(shuffle)
1796 {
1797 zval *array;
1798
1799 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
1800 RETURN_FALSE;
1801 }
1802
1803 php_array_data_shuffle(array TSRMLS_CC);
1804
1805 RETURN_TRUE;
1806 }
1807
1808
1809 PHPAPI void php_splice(HashTable *ht, zend_uint offset, zend_uint length, zval ***list, zend_uint list_count, HashTable *removed TSRMLS_DC)
1810 {
1811 zend_hash_splice(ht, sizeof(zval *), (copy_ctor_func_t) zval_add_ref, offset, length, (void **) list, list_count, removed);
1812
1813 zend_hash_internal_pointer_reset(ht);
1814
1815 if (ht == &EG(symbol_table)) {
1816 zend_reset_all_cv(&EG(symbol_table) TSRMLS_CC);
1817 }
1818 }
1819
1820
1821
1822
1823 PHP_FUNCTION(array_push)
1824 {
1825 zval ***args,
1826 *stack,
1827 *new_var;
1828 int i,
1829 argc;
1830
1831
1832 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a+", &stack, &args, &argc) == FAILURE) {
1833 return;
1834 }
1835
1836
1837 for (i = 0; i < argc; i++) {
1838 new_var = *args[i];
1839 Z_ADDREF_P(new_var);
1840
1841 if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var, sizeof(zval *), NULL) == FAILURE) {
1842 Z_DELREF_P(new_var);
1843 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to the array as the next element is already occupied");
1844 efree(args);
1845 RETURN_FALSE;
1846 }
1847 }
1848
1849
1850 efree(args);
1851 RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
1852 }
1853
1854
1855
1856 static void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int off_the_end)
1857 {
1858 zval *stack,
1859 **val;
1860 char *key = NULL;
1861 uint key_len = 0;
1862 ulong index;
1863
1864 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &stack) == FAILURE) {
1865 return;
1866 }
1867
1868 if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {
1869 return;
1870 }
1871
1872
1873 if (off_the_end) {
1874 zend_hash_internal_pointer_end(Z_ARRVAL_P(stack));
1875 } else {
1876 zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
1877 }
1878 zend_hash_get_current_data(Z_ARRVAL_P(stack), (void **)&val);
1879 RETVAL_ZVAL_FAST(*val);
1880
1881
1882 zend_hash_get_current_key_ex(Z_ARRVAL_P(stack), &key, &key_len, &index, 0, NULL);
1883 if (key && Z_ARRVAL_P(stack) == &EG(symbol_table)) {
1884 zend_delete_global_variable(key, key_len - 1 TSRMLS_CC);
1885 } else {
1886 zend_hash_del_key_or_index(Z_ARRVAL_P(stack), key, key_len, index, (key) ? HASH_DEL_KEY : HASH_DEL_INDEX);
1887 }
1888
1889
1890 if (!off_the_end) {
1891 zend_hash_reindex(Z_ARRVAL_P(stack), 1);
1892 } else if (!key_len && Z_ARRVAL_P(stack)->nNextFreeElement > 0 && index >= Z_ARRVAL_P(stack)->nNextFreeElement - 1) {
1893 Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1;
1894 }
1895
1896 zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
1897 }
1898
1899
1900
1901
1902 PHP_FUNCTION(array_pop)
1903 {
1904 _phpi_pop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1905 }
1906
1907
1908
1909
1910 PHP_FUNCTION(array_shift)
1911 {
1912 _phpi_pop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1913 }
1914
1915
1916
1917
1918 PHP_FUNCTION(array_unshift)
1919 {
1920 zval ***args,
1921 *stack;
1922 int argc;
1923
1924 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a+", &stack, &args, &argc) == FAILURE) {
1925 return;
1926 }
1927
1928
1929 php_splice(Z_ARRVAL_P(stack), 0, 0, args, argc, NULL TSRMLS_CC);
1930
1931
1932 efree(args);
1933 RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
1934 }
1935
1936
1937
1938
1939 PHP_FUNCTION(array_splice)
1940 {
1941 zval *array,
1942 **repl_array = NULL,
1943 ***repl = NULL;
1944 HashTable *rem_hash = NULL;
1945 Bucket *p;
1946 long i,
1947 offset,
1948 length = 0,
1949 repl_num = 0;
1950 int num_in;
1951
1952 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|lZ", &array, &offset, &length, &repl_array) == FAILURE) {
1953 return;
1954 }
1955
1956 num_in = zend_hash_num_elements(Z_ARRVAL_P(array));
1957
1958 if (ZEND_NUM_ARGS() < 3) {
1959 length = num_in;
1960 }
1961
1962 if (repl_array) {
1963
1964 convert_to_array_ex(repl_array);
1965
1966
1967 repl_num = zend_hash_num_elements(Z_ARRVAL_PP(repl_array));
1968 repl = (zval ***)safe_emalloc(repl_num, sizeof(zval **), 0);
1969 for (p = Z_ARRVAL_PP(repl_array)->pListHead, i = 0; p; p = p->pListNext, i++) {
1970 repl[i] = ((zval **)p->pData);
1971 }
1972 }
1973
1974
1975 if (offset < 0 && (offset = num_in + offset) < 0) {
1976 offset = 0;
1977 } else if (offset > num_in) {
1978 offset = num_in;
1979 }
1980
1981
1982 if (length < 0 && (length = num_in - offset + length) < 0) {
1983 length = 0;
1984 } else if ((unsigned long) offset + (unsigned long) length > (unsigned) num_in) {
1985 length = num_in - offset;
1986 }
1987
1988
1989
1990 if (return_value_used) {
1991 array_init_size(return_value, length);
1992 rem_hash = Z_ARRVAL_P(return_value);
1993 }
1994
1995
1996 php_splice(Z_ARRVAL_P(array), offset, length, repl, repl_num, rem_hash TSRMLS_CC);
1997
1998
1999 if (repl) {
2000 efree(repl);
2001 }
2002 }
2003
2004
2005
2006
2007 PHP_FUNCTION(array_slice)
2008 {
2009 zval *input,
2010 **z_length = NULL,
2011 **entry;
2012 long offset,
2013 length = 0;
2014 zend_bool preserve_keys = 0;
2015 int num_in,
2016 pos;
2017 char *string_key;
2018 uint string_key_len;
2019 ulong num_key;
2020 HashPosition hpos;
2021
2022 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|Zb", &input, &offset, &z_length, &preserve_keys) == FAILURE) {
2023 return;
2024 }
2025
2026
2027 num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
2028
2029
2030 if (ZEND_NUM_ARGS() < 3 || Z_TYPE_PP(z_length) == IS_NULL) {
2031 length = num_in;
2032 } else {
2033 convert_to_long_ex(z_length);
2034 length = Z_LVAL_PP(z_length);
2035 }
2036
2037
2038 if (offset > num_in) {
2039 array_init(return_value);
2040 return;
2041 } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
2042 offset = 0;
2043 }
2044
2045
2046 if (length < 0) {
2047 length = num_in - offset + length;
2048 } else if (((unsigned long) offset + (unsigned long) length) > (unsigned) num_in) {
2049 length = num_in - offset;
2050 }
2051
2052
2053 array_init_size(return_value, length > 0 ? length : 0);
2054
2055 if (length <= 0) {
2056 return;
2057 }
2058
2059
2060 pos = 0;
2061 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &hpos);
2062 while (pos < offset && zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &hpos) == SUCCESS) {
2063 pos++;
2064 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &hpos);
2065 }
2066
2067
2068 while (pos < offset + length && zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &hpos) == SUCCESS) {
2069
2070 zval_add_ref(entry);
2071
2072 switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 0, &hpos)) {
2073 case HASH_KEY_IS_STRING:
2074 zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, entry, sizeof(zval *), NULL);
2075 break;
2076
2077 case HASH_KEY_IS_LONG:
2078 if (preserve_keys) {
2079 zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry, sizeof(zval *), NULL);
2080 } else {
2081 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), entry, sizeof(zval *), NULL);
2082 }
2083 break;
2084 }
2085 pos++;
2086 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &hpos);
2087 }
2088 }
2089
2090
2091 PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS_DC)
2092 {
2093 zval **src_entry, **dest_entry;
2094 char *string_key;
2095 uint string_key_len;
2096 ulong num_key;
2097 HashPosition pos;
2098
2099 zend_hash_internal_pointer_reset_ex(src, &pos);
2100 while (zend_hash_get_current_data_ex(src, (void **)&src_entry, &pos) == SUCCESS) {
2101 switch (zend_hash_get_current_key_ex(src, &string_key, &string_key_len, &num_key, 0, &pos)) {
2102 case HASH_KEY_IS_STRING:
2103 if (recursive && zend_hash_find(dest, string_key, string_key_len, (void **)&dest_entry) == SUCCESS) {
2104 HashTable *thash = Z_TYPE_PP(dest_entry) == IS_ARRAY ? Z_ARRVAL_PP(dest_entry) : NULL;
2105 zval *src_zval;
2106 zval *tmp = NULL;
2107
2108 if ((thash && thash->nApplyCount > 1) || (*src_entry == *dest_entry && Z_ISREF_PP(dest_entry) && (Z_REFCOUNT_PP(dest_entry) % 2))) {
2109 php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
2110 return 0;
2111 }
2112 SEPARATE_ZVAL(dest_entry);
2113
2114 if (Z_TYPE_PP(dest_entry) == IS_NULL) {
2115 convert_to_array_ex(dest_entry);
2116 add_next_index_null(*dest_entry);
2117 } else {
2118 convert_to_array_ex(dest_entry);
2119 }
2120 if (Z_TYPE_PP(src_entry) == IS_OBJECT) {
2121 ALLOC_ZVAL(src_zval);
2122 INIT_PZVAL_COPY(src_zval, *src_entry);
2123 zval_copy_ctor(src_zval);
2124 convert_to_array(src_zval);
2125 tmp = src_zval;
2126 } else {
2127 src_zval = *src_entry;
2128 }
2129 if (Z_TYPE_P(src_zval) == IS_ARRAY) {
2130 if (thash) {
2131 thash->nApplyCount++;
2132 }
2133 if (!php_array_merge(Z_ARRVAL_PP(dest_entry), Z_ARRVAL_P(src_zval), recursive TSRMLS_CC)) {
2134 if (thash) {
2135 thash->nApplyCount--;
2136 }
2137 return 0;
2138 }
2139 if (thash) {
2140 thash->nApplyCount--;
2141 }
2142 } else {
2143 Z_ADDREF_PP(src_entry);
2144 zend_hash_next_index_insert(Z_ARRVAL_PP(dest_entry), &src_zval, sizeof(zval *), NULL);
2145 }
2146 if (tmp) {
2147 zval_ptr_dtor(&tmp);
2148 }
2149 } else {
2150 Z_ADDREF_PP(src_entry);
2151 zend_hash_update(dest, string_key, string_key_len, src_entry, sizeof(zval *), NULL);
2152 }
2153 break;
2154
2155 case HASH_KEY_IS_LONG:
2156 Z_ADDREF_PP(src_entry);
2157 zend_hash_next_index_insert(dest, src_entry, sizeof(zval *), NULL);
2158 break;
2159 }
2160 zend_hash_move_forward_ex(src, &pos);
2161 }
2162 return 1;
2163 }
2164
2165
2166 PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src TSRMLS_DC)
2167 {
2168 zval **src_entry, **dest_entry;
2169 char *string_key;
2170 uint string_key_len;
2171 ulong num_key;
2172 HashPosition pos;
2173
2174 for (zend_hash_internal_pointer_reset_ex(src, &pos);
2175 zend_hash_get_current_data_ex(src, (void **)&src_entry, &pos) == SUCCESS;
2176 zend_hash_move_forward_ex(src, &pos)) {
2177 switch (zend_hash_get_current_key_ex(src, &string_key, &string_key_len, &num_key, 0, &pos)) {
2178 case HASH_KEY_IS_STRING:
2179 if (Z_TYPE_PP(src_entry) != IS_ARRAY ||
2180 zend_hash_find(dest, string_key, string_key_len, (void **)&dest_entry) == FAILURE ||
2181 Z_TYPE_PP(dest_entry) != IS_ARRAY) {
2182
2183 Z_ADDREF_PP(src_entry);
2184 zend_hash_update(dest, string_key, string_key_len, src_entry, sizeof(zval *), NULL);
2185
2186 continue;
2187 }
2188 break;
2189
2190 case HASH_KEY_IS_LONG:
2191 if (Z_TYPE_PP(src_entry) != IS_ARRAY ||
2192 zend_hash_index_find(dest, num_key, (void **)&dest_entry) == FAILURE ||
2193 Z_TYPE_PP(dest_entry) != IS_ARRAY) {
2194
2195 Z_ADDREF_PP(src_entry);
2196 zend_hash_index_update(dest, num_key, src_entry, sizeof(zval *), NULL);
2197
2198 continue;
2199 }
2200 break;
2201 }
2202
2203 if (Z_ARRVAL_PP(dest_entry)->nApplyCount > 1 || Z_ARRVAL_PP(src_entry)->nApplyCount > 1 || (*src_entry == *dest_entry && Z_ISREF_PP(dest_entry) && (Z_REFCOUNT_PP(dest_entry) % 2))) {
2204 php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
2205 return 0;
2206 }
2207 SEPARATE_ZVAL(dest_entry);
2208 Z_ARRVAL_PP(dest_entry)->nApplyCount++;
2209 Z_ARRVAL_PP(src_entry)->nApplyCount++;
2210
2211
2212 if (!php_array_replace_recursive(Z_ARRVAL_PP(dest_entry), Z_ARRVAL_PP(src_entry) TSRMLS_CC)) {
2213 Z_ARRVAL_PP(dest_entry)->nApplyCount--;
2214 Z_ARRVAL_PP(src_entry)->nApplyCount--;
2215 return 0;
2216 }
2217 Z_ARRVAL_PP(dest_entry)->nApplyCount--;
2218 Z_ARRVAL_PP(src_entry)->nApplyCount--;
2219 }
2220
2221 return 1;
2222 }
2223
2224
2225 static void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive, int replace)
2226 {
2227 zval ***args = NULL;
2228 int argc, i, init_size = 0;
2229
2230 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
2231 return;
2232 }
2233
2234 for (i = 0; i < argc; i++) {
2235 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
2236 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1);
2237 efree(args);
2238 RETURN_NULL();
2239 } else {
2240 int num = zend_hash_num_elements(Z_ARRVAL_PP(args[i]));
2241
2242 if (num > init_size) {
2243 init_size = num;
2244 }
2245 }
2246 }
2247
2248 array_init_size(return_value, init_size);
2249
2250 for (i = 0; i < argc; i++) {
2251 if (!replace) {
2252 php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]), recursive TSRMLS_CC);
2253 } else if (recursive && i > 0) {
2254 php_array_replace_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]) TSRMLS_CC);
2255 } else {
2256 zend_hash_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *), 1);
2257 }
2258 }
2259
2260 efree(args);
2261 }
2262
2263
2264
2265
2266 PHP_FUNCTION(array_merge)
2267 {
2268 php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
2269 }
2270
2271
2272
2273
2274 PHP_FUNCTION(array_merge_recursive)
2275 {
2276 php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
2277 }
2278
2279
2280
2281
2282 PHP_FUNCTION(array_replace)
2283 {
2284 php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
2285 }
2286
2287
2288
2289
2290 PHP_FUNCTION(array_replace_recursive)
2291 {
2292 php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1);
2293 }
2294
2295
2296
2297
2298 PHP_FUNCTION(array_keys)
2299 {
2300 zval *input,
2301 *search_value = NULL,
2302 **entry,
2303 res,
2304 *new_val;
2305 int add_key;
2306 zend_bool strict = 0;
2307 HashPosition pos;
2308 int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
2309
2310 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zb", &input, &search_value, &strict) == FAILURE) {
2311 return;
2312 }
2313
2314 if (strict) {
2315 is_equal_func = is_identical_function;
2316 }
2317
2318
2319 if (search_value != NULL) {
2320 array_init(return_value);
2321 } else {
2322 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
2323 }
2324 add_key = 1;
2325
2326
2327 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
2328 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS) {
2329 if (search_value != NULL) {
2330 is_equal_func(&res, search_value, *entry TSRMLS_CC);
2331 add_key = zval_is_true(&res);
2332 }
2333
2334 if (add_key) {
2335 MAKE_STD_ZVAL(new_val);
2336 zend_hash_get_current_key_zval_ex(Z_ARRVAL_P(input), new_val, &pos);
2337 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
2338 }
2339
2340 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
2341 }
2342 }
2343
2344
2345
2346
2347 PHP_FUNCTION(array_values)
2348 {
2349 zval *input,
2350 **entry;
2351 HashPosition pos;
2352
2353 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &input) == FAILURE) {
2354 return;
2355 }
2356
2357
2358 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
2359
2360
2361 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
2362 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS) {
2363 zval_add_ref(entry);
2364 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), entry, sizeof(zval *), NULL);
2365 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
2366 }
2367 }
2368
2369
2370
2371
2372 PHP_FUNCTION(array_count_values)
2373 {
2374 zval *input,
2375 **entry,
2376 **tmp;
2377 HashTable *myht;
2378 HashPosition pos;
2379
2380 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &input) == FAILURE) {
2381 return;
2382 }
2383
2384
2385 array_init(return_value);
2386
2387
2388 myht = Z_ARRVAL_P(input);
2389 zend_hash_internal_pointer_reset_ex(myht, &pos);
2390 while (zend_hash_get_current_data_ex(myht, (void **)&entry, &pos) == SUCCESS) {
2391 if (Z_TYPE_PP(entry) == IS_LONG) {
2392 if (zend_hash_index_find(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), (void **)&tmp) == FAILURE) {
2393 zval *data;
2394 MAKE_STD_ZVAL(data);
2395 ZVAL_LONG(data, 1);
2396 zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &data, sizeof(data), NULL);
2397 } else {
2398 Z_LVAL_PP(tmp)++;
2399 }
2400 } else if (Z_TYPE_PP(entry) == IS_STRING) {
2401 if (zend_symtable_find(Z_ARRVAL_P(return_value), Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, (void**)&tmp) == FAILURE) {
2402 zval *data;
2403 MAKE_STD_ZVAL(data);
2404 ZVAL_LONG(data, 1);
2405 zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, &data, sizeof(data), NULL);
2406 } else {
2407 Z_LVAL_PP(tmp)++;
2408 }
2409 } else {
2410 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only count STRING and INTEGER values!");
2411 }
2412
2413 zend_hash_move_forward_ex(myht, &pos);
2414 }
2415 }
2416
2417
2418
2419
2420
2421 static inline
2422 zend_bool array_column_param_helper(zval **param,
2423 const char *name TSRMLS_DC) {
2424 switch (Z_TYPE_PP(param)) {
2425 case IS_DOUBLE:
2426 convert_to_long_ex(param);
2427
2428 case IS_LONG:
2429 return 1;
2430
2431 case IS_OBJECT:
2432 convert_to_string_ex(param);
2433
2434 case IS_STRING:
2435 return 1;
2436
2437 default:
2438 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The %s key should be either a string or an integer", name);
2439 return 0;
2440 }
2441 }
2442
2443
2444
2445
2446 PHP_FUNCTION(array_column)
2447 {
2448 zval **zcolumn = NULL, **zkey = NULL, **data;
2449 HashTable *arr_hash;
2450 HashPosition pointer;
2451
2452 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "hZ!|Z!", &arr_hash, &zcolumn, &zkey) == FAILURE) {
2453 return;
2454 }
2455
2456 if ((zcolumn && !array_column_param_helper(zcolumn, "column" TSRMLS_CC)) ||
2457 (zkey && !array_column_param_helper(zkey, "index" TSRMLS_CC))) {
2458 RETURN_FALSE;
2459 }
2460
2461 array_init(return_value);
2462 for (zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
2463 zend_hash_get_current_data_ex(arr_hash, (void**)&data, &pointer) == SUCCESS;
2464 zend_hash_move_forward_ex(arr_hash, &pointer)) {
2465 zval **zcolval, **zkeyval = NULL;
2466 HashTable *ht;
2467
2468 if (Z_TYPE_PP(data) != IS_ARRAY) {
2469
2470 continue;
2471 }
2472 ht = Z_ARRVAL_PP(data);
2473
2474 if (!zcolumn) {
2475
2476 zcolval = data;
2477
2478
2479 } else if ((Z_TYPE_PP(zcolumn) == IS_STRING) &&
2480 (zend_hash_find(ht, Z_STRVAL_PP(zcolumn), Z_STRLEN_PP(zcolumn) + 1, (void**)&zcolval) == FAILURE)) {
2481 continue;
2482 } else if ((Z_TYPE_PP(zcolumn) == IS_LONG) &&
2483 (zend_hash_index_find(ht, Z_LVAL_PP(zcolumn), (void**)&zcolval) == FAILURE)) {
2484 continue;
2485 }
2486
2487
2488
2489
2490 if (zkey && (Z_TYPE_PP(zkey) == IS_STRING)) {
2491 zend_hash_find(ht, Z_STRVAL_PP(zkey), Z_STRLEN_PP(zkey) + 1, (void**)&zkeyval);
2492 } else if (zkey && (Z_TYPE_PP(zkey) == IS_LONG)) {
2493 zend_hash_index_find(ht, Z_LVAL_PP(zkey), (void**)&zkeyval);
2494 }
2495
2496 Z_ADDREF_PP(zcolval);
2497 if (zkeyval && Z_TYPE_PP(zkeyval) == IS_STRING) {
2498 add_assoc_zval(return_value, Z_STRVAL_PP(zkeyval), *zcolval);
2499 } else if (zkeyval && Z_TYPE_PP(zkeyval) == IS_LONG) {
2500 add_index_zval(return_value, Z_LVAL_PP(zkeyval), *zcolval);
2501 } else if (zkeyval && Z_TYPE_PP(zkeyval) == IS_OBJECT) {
2502 SEPARATE_ZVAL(zkeyval);
2503 convert_to_string(*zkeyval);
2504 add_assoc_zval(return_value, Z_STRVAL_PP(zkeyval), *zcolval);
2505 } else {
2506 add_next_index_zval(return_value, *zcolval);
2507 }
2508 }
2509 }
2510
2511
2512
2513
2514 PHP_FUNCTION(array_reverse)
2515 {
2516 zval *input,
2517 **entry;
2518 char *string_key;
2519 uint string_key_len;
2520 ulong num_key;
2521 zend_bool preserve_keys = 0;
2522 HashPosition pos;
2523
2524 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &input, &preserve_keys) == FAILURE) {
2525 return;
2526 }
2527
2528
2529 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
2530
2531 zend_hash_internal_pointer_end_ex(Z_ARRVAL_P(input), &pos);
2532 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS) {
2533 zval_add_ref(entry);
2534
2535 switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 0, &pos)) {
2536 case HASH_KEY_IS_STRING:
2537 zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, entry, sizeof(zval *), NULL);
2538 break;
2539
2540 case HASH_KEY_IS_LONG:
2541 if (preserve_keys) {
2542 zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry, sizeof(zval *), NULL);
2543 } else {
2544 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), entry, sizeof(zval *), NULL);
2545 }
2546 break;
2547 }
2548
2549 zend_hash_move_backwards_ex(Z_ARRVAL_P(input), &pos);
2550 }
2551 }
2552
2553
2554
2555
2556 PHP_FUNCTION(array_pad)
2557 {
2558 zval *input;
2559 zval *pad_value;
2560 zval ***pads;
2561 long pad_size;
2562 long pad_size_abs;
2563 int input_size;
2564 int num_pads;
2565 int do_pad;
2566 int i;
2567
2568 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "alz", &input, &pad_size, &pad_value) == FAILURE) {
2569 return;
2570 }
2571
2572
2573 input_size = zend_hash_num_elements(Z_ARRVAL_P(input));
2574 pad_size_abs = abs(pad_size);
2575 if (pad_size_abs < 0) {
2576 php_error_docref(NULL TSRMLS_CC, E_WARNING, "You may only pad up to 1048576 elements at a time");
2577 zval_dtor(return_value);
2578 RETURN_FALSE;
2579 }
2580 do_pad = (input_size >= pad_size_abs) ? 0 : 1;
2581
2582
2583 RETVAL_ZVAL(input, 1, 0);
2584
2585
2586 if (!do_pad) {
2587 return;
2588 }
2589
2590
2591 num_pads = pad_size_abs - input_size;
2592 if (num_pads > 1048576) {
2593 php_error_docref(NULL TSRMLS_CC, E_WARNING, "You may only pad up to 1048576 elements at a time");
2594 zval_dtor(return_value);
2595 RETURN_FALSE;
2596 }
2597 pads = (zval ***)safe_emalloc(num_pads, sizeof(zval **), 0);
2598 for (i = 0; i < num_pads; i++) {
2599 pads[i] = &pad_value;
2600 }
2601
2602
2603 if (pad_size > 0) {
2604 php_splice(Z_ARRVAL_P(return_value), input_size, 0, pads, num_pads, NULL TSRMLS_CC);
2605 } else {
2606 php_splice(Z_ARRVAL_P(return_value), 0, 0, pads, num_pads, NULL TSRMLS_CC);
2607 }
2608
2609
2610 efree(pads);
2611 }
2612
2613
2614
2615
2616 PHP_FUNCTION(array_flip)
2617 {
2618 zval *array, **entry, *data;
2619 HashPosition pos;
2620
2621 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
2622 return;
2623 }
2624
2625 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
2626
2627 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
2628 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {
2629 MAKE_STD_ZVAL(data);
2630 zend_hash_get_current_key_zval_ex(Z_ARRVAL_P(array), data, &pos);
2631
2632 if (Z_TYPE_PP(entry) == IS_LONG) {
2633 zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &data, sizeof(data), NULL);
2634 } else if (Z_TYPE_PP(entry) == IS_STRING) {
2635 zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, &data, sizeof(data), NULL);
2636 } else {
2637 zval_ptr_dtor(&data);
2638 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only flip STRING and INTEGER values!");
2639 }
2640
2641 zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos);
2642 }
2643 }
2644
2645
2646
2647
2648 PHP_FUNCTION(array_change_key_case)
2649 {
2650 zval *array, **entry;
2651 char *string_key;
2652 char *new_key;
2653 uint str_key_len;
2654 ulong num_key;
2655 long change_to_upper=0;
2656 HashPosition pos;
2657
2658 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &change_to_upper) == FAILURE) {
2659 return;
2660 }
2661
2662 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
2663
2664 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
2665 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {
2666 zval_add_ref(entry);
2667
2668 switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &str_key_len, &num_key, 0, &pos)) {
2669 case HASH_KEY_IS_LONG:
2670 zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry, sizeof(entry), NULL);
2671 break;
2672 case HASH_KEY_IS_STRING:
2673 new_key = estrndup(string_key, str_key_len - 1);
2674 if (change_to_upper) {
2675 php_strtoupper(new_key, str_key_len - 1);
2676 } else {
2677 php_strtolower(new_key, str_key_len - 1);
2678 }
2679 zend_hash_update(Z_ARRVAL_P(return_value), new_key, str_key_len, entry, sizeof(entry), NULL);
2680 efree(new_key);
2681 break;
2682 }
2683
2684 zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos);
2685 }
2686 }
2687
2688
2689
2690
2691 PHP_FUNCTION(array_unique)
2692 {
2693 zval *array, *tmp;
2694 Bucket *p;
2695 struct bucketindex {
2696 Bucket *b;
2697 unsigned int i;
2698 };
2699 struct bucketindex *arTmp, *cmpdata, *lastkept;
2700 unsigned int i;
2701 long sort_type = PHP_SORT_STRING;
2702
2703 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
2704 return;
2705 }
2706
2707 php_set_compare_func(sort_type TSRMLS_CC);
2708
2709 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
2710 zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_P(array), (copy_ctor_func_t) zval_add_ref, (void *)&tmp, sizeof(zval*));
2711
2712 if (Z_ARRVAL_P(array)->nNumOfElements <= 1) {
2713 return;
2714 }
2715
2716
2717 arTmp = (struct bucketindex *) pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), Z_ARRVAL_P(array)->persistent);
2718 if (!arTmp) {
2719 zval_dtor(return_value);
2720 RETURN_FALSE;
2721 }
2722 for (i = 0, p = Z_ARRVAL_P(array)->pListHead; p; i++, p = p->pListNext) {
2723 arTmp[i].b = p;
2724 arTmp[i].i = i;
2725 }
2726 arTmp[i].b = NULL;
2727 zend_qsort((void *) arTmp, i, sizeof(struct bucketindex), php_array_data_compare TSRMLS_CC);
2728
2729
2730 lastkept = arTmp;
2731 for (cmpdata = arTmp + 1; cmpdata->b; cmpdata++) {
2732 if (php_array_data_compare(lastkept, cmpdata TSRMLS_CC)) {
2733 lastkept = cmpdata;
2734 } else {
2735 if (lastkept->i > cmpdata->i) {
2736 p = lastkept->b;
2737 lastkept = cmpdata;
2738 } else {
2739 p = cmpdata->b;
2740 }
2741 if (p->nKeyLength == 0) {
2742 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
2743 } else {
2744 if (Z_ARRVAL_P(return_value) == &EG(symbol_table)) {
2745 zend_delete_global_variable(p->arKey, p->nKeyLength - 1 TSRMLS_CC);
2746 } else {
2747 zend_hash_quick_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h);
2748 }
2749 }
2750 }
2751 }
2752 pefree(arTmp, Z_ARRVAL_P(array)->persistent);
2753 }
2754
2755
2756 static int zval_compare(zval **a, zval **b TSRMLS_DC)
2757 {
2758 zval result;
2759 zval *first;
2760 zval *second;
2761
2762 first = *((zval **) a);
2763 second = *((zval **) b);
2764
2765 if (string_compare_function(&result, first, second TSRMLS_CC) == FAILURE) {
2766 return 0;
2767 }
2768
2769 if (Z_TYPE(result) == IS_DOUBLE) {
2770 if (Z_DVAL(result) < 0) {
2771 return -1;
2772 } else if (Z_DVAL(result) > 0) {
2773 return 1;
2774 } else {
2775 return 0;
2776 }
2777 }
2778
2779 convert_to_long(&result);
2780
2781 if (Z_LVAL(result) < 0) {
2782 return -1;
2783 } else if (Z_LVAL(result) > 0) {
2784 return 1;
2785 }
2786
2787 return 0;
2788 }
2789
2790
2791 static int zval_user_compare(zval **a, zval **b TSRMLS_DC)
2792 {
2793 zval **args[2];
2794 zval *retval_ptr = NULL;
2795
2796 args[0] = (zval **) a;
2797 args[1] = (zval **) b;
2798
2799 BG(user_compare_fci).param_count = 2;
2800 BG(user_compare_fci).params = args;
2801 BG(user_compare_fci).retval_ptr_ptr = &retval_ptr;
2802 BG(user_compare_fci).no_separation = 0;
2803
2804 if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache) TSRMLS_CC) == SUCCESS && retval_ptr) {
2805 long retval;
2806
2807 convert_to_long_ex(&retval_ptr);
2808 retval = Z_LVAL_P(retval_ptr);
2809 zval_ptr_dtor(&retval_ptr);
2810 return retval < 0 ? -1 : retval > 0 ? 1 : 0;;
2811 } else {
2812 return 0;
2813 }
2814 }
2815
2816
2817 static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type)
2818 {
2819 Bucket *p;
2820 int argc, i;
2821 zval ***args;
2822 int (*intersect_data_compare_func)(zval **, zval ** TSRMLS_DC) = NULL;
2823 zend_bool ok;
2824 zval **data;
2825 int req_args;
2826 char *param_spec;
2827
2828
2829 argc = ZEND_NUM_ARGS();
2830 if (data_compare_type == INTERSECT_COMP_DATA_USER) {
2831
2832 req_args = 3;
2833 param_spec = "+f";
2834 intersect_data_compare_func = zval_user_compare;
2835 } else {
2836
2837
2838 req_args = 2;
2839 param_spec = "+";
2840
2841 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
2842 intersect_data_compare_func = zval_compare;
2843 }
2844 }
2845
2846 if (argc < req_args) {
2847 php_error_docref(NULL TSRMLS_CC, E_WARNING, "at least %d parameters are required, %d given", req_args, argc);
2848 return;
2849 }
2850
2851 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, param_spec, &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
2852 return;
2853 }
2854
2855 for (i = 0; i < argc; i++) {
2856 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
2857 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1);
2858 RETVAL_NULL();
2859 goto out;
2860 }
2861 }
2862
2863 array_init(return_value);
2864
2865 for (p = Z_ARRVAL_PP(args[0])->pListHead; p != NULL; p = p->pListNext) {
2866 if (p->nKeyLength == 0) {
2867 ok = 1;
2868 for (i = 1; i < argc; i++) {
2869 if (zend_hash_index_find(Z_ARRVAL_PP(args[i]), p->h, (void**)&data) == FAILURE ||
2870 (intersect_data_compare_func &&
2871 intersect_data_compare_func((zval**)p->pData, data TSRMLS_CC) != 0)
2872 ) {
2873 ok = 0;
2874 break;
2875 }
2876 }
2877 if (ok) {
2878 Z_ADDREF_PP((zval**)p->pData);
2879 zend_hash_index_update(Z_ARRVAL_P(return_value), p->h, p->pData, sizeof(zval*), NULL);
2880 }
2881 } else {
2882 ok = 1;
2883 for (i = 1; i < argc; i++) {
2884 if (zend_hash_quick_find(Z_ARRVAL_PP(args[i]), p->arKey, p->nKeyLength, p->h, (void**)&data) == FAILURE ||
2885 (intersect_data_compare_func &&
2886 intersect_data_compare_func((zval**)p->pData, data TSRMLS_CC) != 0)
2887 ) {
2888 ok = 0;
2889 break;
2890 }
2891 }
2892 if (ok) {
2893 Z_ADDREF_PP((zval**)p->pData);
2894 zend_hash_quick_update(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h, p->pData, sizeof(zval*), NULL);
2895 }
2896 }
2897 }
2898 out:
2899 efree(args);
2900 }
2901
2902
2903 static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type)
2904 {
2905 zval ***args = NULL;
2906 HashTable *hash;
2907 int arr_argc, i, c = 0;
2908 Bucket ***lists, **list, ***ptrs, *p;
2909 int req_args;
2910 char *param_spec;
2911 zend_fcall_info fci1, fci2;
2912 zend_fcall_info_cache fci1_cache = empty_fcall_info_cache, fci2_cache = empty_fcall_info_cache;
2913 zend_fcall_info *fci_key = NULL, *fci_data;
2914 zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache;
2915 PHP_ARRAY_CMP_FUNC_VARS;
2916
2917 int (*intersect_key_compare_func)(const void *, const void * TSRMLS_DC);
2918 int (*intersect_data_compare_func)(const void *, const void * TSRMLS_DC);
2919
2920 if (behavior == INTERSECT_NORMAL) {
2921 intersect_key_compare_func = php_array_key_compare;
2922
2923 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
2924
2925 req_args = 2;
2926 param_spec = "+";
2927 intersect_data_compare_func = php_array_data_compare;
2928 } else if (data_compare_type == INTERSECT_COMP_DATA_USER) {
2929
2930 req_args = 3;
2931 param_spec = "+f";
2932 intersect_data_compare_func = php_array_user_compare;
2933 } else {
2934 php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_compare_type is %d. This should never happen. Please report as a bug", data_compare_type);
2935 return;
2936 }
2937
2938 if (ZEND_NUM_ARGS() < req_args) {
2939 php_error_docref(NULL TSRMLS_CC, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
2940 return;
2941 }
2942
2943 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
2944 return;
2945 }
2946 fci_data = &fci1;
2947 fci_data_cache = &fci1_cache;
2948
2949 } else if (behavior & INTERSECT_ASSOC) {
2950
2951
2952 intersect_key_compare_func = php_array_key_compare;
2953
2954 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
2955
2956 req_args = 2;
2957 param_spec = "+";
2958 intersect_key_compare_func = php_array_key_compare;
2959 intersect_data_compare_func = php_array_data_compare;
2960 } else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
2961
2962 req_args = 3;
2963 param_spec = "+f";
2964 intersect_key_compare_func = php_array_key_compare;
2965 intersect_data_compare_func = php_array_user_compare;
2966 fci_data = &fci1;
2967 fci_data_cache = &fci1_cache;
2968 } else if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_USER) {
2969
2970 req_args = 3;
2971 param_spec = "+f";
2972 intersect_key_compare_func = php_array_user_key_compare;
2973 intersect_data_compare_func = php_array_data_compare;
2974 fci_key = &fci1;
2975 fci_key_cache = &fci1_cache;
2976 } else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_USER) {
2977
2978 req_args = 4;
2979 param_spec = "+ff";
2980 intersect_key_compare_func = php_array_user_key_compare;
2981 intersect_data_compare_func = php_array_user_compare;
2982 fci_data = &fci1;
2983 fci_data_cache = &fci1_cache;
2984 fci_key = &fci2;
2985 fci_key_cache = &fci2_cache;
2986 } else {
2987 php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_compare_type is %d. key_compare_type is %d. This should never happen. Please report as a bug", data_compare_type, key_compare_type);
2988 return;
2989 }
2990
2991 if (ZEND_NUM_ARGS() < req_args) {
2992 php_error_docref(NULL TSRMLS_CC, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
2993 return;
2994 }
2995
2996 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
2997 return;
2998 }
2999
3000 } else {
3001 php_error_docref(NULL TSRMLS_CC, E_WARNING, "behavior is %d. This should never happen. Please report as a bug", behavior);
3002 return;
3003 }
3004
3005 PHP_ARRAY_CMP_FUNC_BACKUP();
3006
3007
3008 lists = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0);
3009 ptrs = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0);
3010 php_set_compare_func(PHP_SORT_STRING TSRMLS_CC);
3011
3012 if (behavior == INTERSECT_NORMAL && data_compare_type == INTERSECT_COMP_DATA_USER) {
3013 BG(user_compare_fci) = *fci_data;
3014 BG(user_compare_fci_cache) = *fci_data_cache;
3015 } else if (behavior & INTERSECT_ASSOC && key_compare_type == INTERSECT_COMP_KEY_USER) {
3016 BG(user_compare_fci) = *fci_key;
3017 BG(user_compare_fci_cache) = *fci_key_cache;
3018 }
3019
3020 for (i = 0; i < arr_argc; i++) {
3021 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
3022 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1);
3023 arr_argc = i;
3024 goto out;
3025 }
3026 hash = Z_ARRVAL_PP(args[i]);
3027 list = (Bucket **) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket *), hash->persistent);
3028 if (!list) {
3029 PHP_ARRAY_CMP_FUNC_RESTORE();
3030
3031 efree(ptrs);
3032 efree(lists);
3033 efree(args);
3034 RETURN_FALSE;
3035 }
3036 lists[i] = list;
3037 ptrs[i] = list;
3038 for (p = hash->pListHead; p; p = p->pListNext) {
3039 *list++ = p;
3040 }
3041 *list = NULL;
3042 if (behavior == INTERSECT_NORMAL) {
3043 zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), intersect_data_compare_func TSRMLS_CC);
3044 } else if (behavior & INTERSECT_ASSOC) {
3045 zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), intersect_key_compare_func TSRMLS_CC);
3046 }
3047 }
3048
3049
3050 RETVAL_ZVAL(*args[0], 1, 0);
3051 if (return_value->value.ht == &EG(symbol_table)) {
3052 HashTable *ht;
3053 zval *tmp;
3054
3055 ALLOC_HASHTABLE(ht);
3056 zend_hash_init(ht, zend_hash_num_elements(return_value->value.ht), NULL, ZVAL_PTR_DTOR, 0);
3057 zend_hash_copy(ht, return_value->value.ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
3058 return_value->value.ht = ht;
3059 }
3060
3061
3062 while (*ptrs[0]) {
3063 if ((behavior & INTERSECT_ASSOC)
3064 &&
3065 key_compare_type == INTERSECT_COMP_KEY_USER) {
3066
3067 BG(user_compare_fci) = *fci_key;
3068 BG(user_compare_fci_cache) = *fci_key_cache;
3069 }
3070
3071 for (i = 1; i < arr_argc; i++) {
3072 if (behavior & INTERSECT_NORMAL) {
3073 while (*ptrs[i] && (0 < (c = intersect_data_compare_func(ptrs[0], ptrs[i] TSRMLS_CC)))) {
3074 ptrs[i]++;
3075 }
3076 } else if (behavior & INTERSECT_ASSOC) {
3077 while (*ptrs[i] && (0 < (c = intersect_key_compare_func(ptrs[0], ptrs[i] TSRMLS_CC)))) {
3078 ptrs[i]++;
3079 }
3080 if ((!c && *ptrs[i]) && (behavior == INTERSECT_ASSOC)) {
3081
3082
3083
3084
3085 if (data_compare_type == INTERSECT_COMP_DATA_USER) {
3086 BG(user_compare_fci) = *fci_data;
3087 BG(user_compare_fci_cache) = *fci_data_cache;
3088 }
3089 if (intersect_data_compare_func(ptrs[0], ptrs[i] TSRMLS_CC) != 0) {
3090 c = 1;
3091 if (key_compare_type == INTERSECT_COMP_KEY_USER) {
3092 BG(user_compare_fci) = *fci_key;
3093 BG(user_compare_fci_cache) = *fci_key_cache;
3094
3095 }
3096
3097 } else {
3098
3099 }
3100 }
3101 }
3102 if (!*ptrs[i]) {
3103
3104
3105
3106 for (;;) {
3107 p = *ptrs[0]++;
3108 if (!p) {
3109 goto out;
3110 }
3111 if (p->nKeyLength == 0) {
3112 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
3113 } else {
3114 zend_hash_quick_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h);
3115 }
3116 }
3117 }
3118 if (c)
3119 break;
3120 ptrs[i]++;
3121 }
3122 if (c) {
3123
3124
3125 for (;;) {
3126 p = *ptrs[0];
3127 if (p->nKeyLength == 0) {
3128 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
3129 } else {
3130 zend_hash_quick_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h);
3131 }
3132 if (!*++ptrs[0]) {
3133 goto out;
3134 }
3135 if (behavior == INTERSECT_NORMAL) {
3136 if (0 <= intersect_data_compare_func(ptrs[0], ptrs[i] TSRMLS_CC)) {
3137 break;
3138 }
3139 } else if (behavior & INTERSECT_ASSOC) {
3140
3141 break;
3142 }
3143 }
3144 } else {
3145
3146
3147 for (;;) {
3148 if (!*++ptrs[0]) {
3149 goto out;
3150 }
3151 if (behavior == INTERSECT_NORMAL) {
3152 if (intersect_data_compare_func(ptrs[0] - 1, ptrs[0] TSRMLS_CC)) {
3153 break;
3154 }
3155 } else if (behavior & INTERSECT_ASSOC) {
3156
3157 break;
3158 }
3159 }
3160 }
3161 }
3162 out:
3163 for (i = 0; i < arr_argc; i++) {
3164 hash = Z_ARRVAL_PP(args[i]);
3165 pefree(lists[i], hash->persistent);
3166 }
3167
3168 PHP_ARRAY_CMP_FUNC_RESTORE();
3169
3170 efree(ptrs);
3171 efree(lists);
3172 efree(args);
3173 }
3174
3175
3176
3177
3178 PHP_FUNCTION(array_intersect_key)
3179 {
3180 php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_NONE);
3181 }
3182
3183
3184
3185
3186 PHP_FUNCTION(array_intersect_ukey)
3187 {
3188 php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_KEY, INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_USER);
3189 }
3190
3191
3192
3193
3194 PHP_FUNCTION(array_intersect)
3195 {
3196 php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_NORMAL, INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_INTERNAL);
3197 }
3198
3199
3200
3201
3202 PHP_FUNCTION(array_uintersect)
3203 {
3204 php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_NORMAL, INTERSECT_COMP_DATA_USER, INTERSECT_COMP_KEY_INTERNAL);
3205 }
3206
3207
3208
3209
3210 PHP_FUNCTION(array_intersect_assoc)
3211 {
3212 php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_INTERNAL);
3213 }
3214
3215
3216
3217
3218 PHP_FUNCTION(array_intersect_uassoc)
3219 {
3220 php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC, INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_USER);
3221 }
3222
3223
3224
3225
3226 PHP_FUNCTION(array_uintersect_assoc)
3227 {
3228 php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_USER);
3229 }
3230
3231
3232
3233
3234 PHP_FUNCTION(array_uintersect_uassoc)
3235 {
3236 php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC, INTERSECT_COMP_DATA_USER, INTERSECT_COMP_KEY_USER);
3237 }
3238
3239
3240 static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type)
3241 {
3242 Bucket *p;
3243 int argc, i;
3244 zval ***args;
3245 int (*diff_data_compare_func)(zval **, zval ** TSRMLS_DC) = NULL;
3246 zend_bool ok;
3247 zval **data;
3248
3249
3250 argc = ZEND_NUM_ARGS();
3251 if (data_compare_type == DIFF_COMP_DATA_USER) {
3252 if (argc < 3) {
3253 php_error_docref(NULL TSRMLS_CC, E_WARNING, "at least 3 parameters are required, %d given", ZEND_NUM_ARGS());
3254 return;
3255 }
3256 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+f", &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
3257 return;
3258 }
3259 diff_data_compare_func = zval_user_compare;
3260 } else {
3261 if (argc < 2) {
3262 php_error_docref(NULL TSRMLS_CC, E_WARNING, "at least 2 parameters are required, %d given", ZEND_NUM_ARGS());
3263 return;
3264 }
3265 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
3266 return;
3267 }
3268 if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
3269 diff_data_compare_func = zval_compare;
3270 }
3271 }
3272
3273 for (i = 0; i < argc; i++) {
3274 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
3275 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1);
3276 RETVAL_NULL();
3277 goto out;
3278 }
3279 }
3280
3281 array_init(return_value);
3282
3283 for (p = Z_ARRVAL_PP(args[0])->pListHead; p != NULL; p = p->pListNext) {
3284 if (p->nKeyLength == 0) {
3285 ok = 1;
3286 for (i = 1; i < argc; i++) {
3287 if (zend_hash_index_find(Z_ARRVAL_PP(args[i]), p->h, (void**)&data) == SUCCESS &&
3288 (!diff_data_compare_func ||
3289 diff_data_compare_func((zval**)p->pData, data TSRMLS_CC) == 0)
3290 ) {
3291 ok = 0;
3292 break;
3293 }
3294 }
3295 if (ok) {
3296 Z_ADDREF_PP((zval**)p->pData);
3297 zend_hash_index_update(Z_ARRVAL_P(return_value), p->h, p->pData, sizeof(zval*), NULL);
3298 }
3299 } else {
3300 ok = 1;
3301 for (i = 1; i < argc; i++) {
3302 if (zend_hash_quick_find(Z_ARRVAL_PP(args[i]), p->arKey, p->nKeyLength, p->h, (void**)&data) == SUCCESS &&
3303 (!diff_data_compare_func ||
3304 diff_data_compare_func((zval**)p->pData, data TSRMLS_CC) == 0)
3305 ) {
3306 ok = 0;
3307 break;
3308 }
3309 }
3310 if (ok) {
3311 Z_ADDREF_PP((zval**)p->pData);
3312 zend_hash_quick_update(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h, p->pData, sizeof(zval*), NULL);
3313 }
3314 }
3315 }
3316 out:
3317 efree(args);
3318 }
3319
3320
3321 static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type)
3322 {
3323 zval ***args = NULL;
3324 HashTable *hash;
3325 int arr_argc, i, c;
3326 Bucket ***lists, **list, ***ptrs, *p;
3327 int req_args;
3328 char *param_spec;
3329 zend_fcall_info fci1, fci2;
3330 zend_fcall_info_cache fci1_cache = empty_fcall_info_cache, fci2_cache = empty_fcall_info_cache;
3331 zend_fcall_info *fci_key = NULL, *fci_data;
3332 zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache;
3333 PHP_ARRAY_CMP_FUNC_VARS;
3334
3335 int (*diff_key_compare_func)(const void *, const void * TSRMLS_DC);
3336 int (*diff_data_compare_func)(const void *, const void * TSRMLS_DC);
3337
3338 if (behavior == DIFF_NORMAL) {
3339 diff_key_compare_func = php_array_key_compare;
3340
3341 if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
3342
3343 req_args = 2;
3344 param_spec = "+";
3345 diff_data_compare_func = php_array_data_compare;
3346 } else if (data_compare_type == DIFF_COMP_DATA_USER) {
3347
3348 req_args = 3;
3349 param_spec = "+f";
3350 diff_data_compare_func = php_array_user_compare;
3351 } else {
3352 php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_compare_type is %d. This should never happen. Please report as a bug", data_compare_type);
3353 return;
3354 }
3355
3356 if (ZEND_NUM_ARGS() < req_args) {
3357 php_error_docref(NULL TSRMLS_CC, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
3358 return;
3359 }
3360
3361 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
3362 return;
3363 }
3364 fci_data = &fci1;
3365 fci_data_cache = &fci1_cache;
3366
3367 } else if (behavior & DIFF_ASSOC) {
3368
3369
3370
3371 if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
3372
3373 req_args = 2;
3374 param_spec = "+";
3375 diff_key_compare_func = php_array_key_compare;
3376 diff_data_compare_func = php_array_data_compare;
3377 } else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
3378
3379 req_args = 3;
3380 param_spec = "+f";
3381 diff_key_compare_func = php_array_key_compare;
3382 diff_data_compare_func = php_array_user_compare;
3383 fci_data = &fci1;
3384 fci_data_cache = &fci1_cache;
3385 } else if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_USER) {
3386
3387 req_args = 3;
3388 param_spec = "+f";
3389 diff_key_compare_func = php_array_user_key_compare;
3390 diff_data_compare_func = php_array_data_compare;
3391 fci_key = &fci1;
3392 fci_key_cache = &fci1_cache;
3393 } else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_USER) {
3394
3395 req_args = 4;
3396 param_spec = "+ff";
3397 diff_key_compare_func = php_array_user_key_compare;
3398 diff_data_compare_func = php_array_user_compare;
3399 fci_data = &fci1;
3400 fci_data_cache = &fci1_cache;
3401 fci_key = &fci2;
3402 fci_key_cache = &fci2_cache;
3403 } else {
3404 php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_compare_type is %d. key_compare_type is %d. This should never happen. Please report as a bug", data_compare_type, key_compare_type);
3405 return;
3406 }
3407
3408 if (ZEND_NUM_ARGS() < req_args) {
3409 php_error_docref(NULL TSRMLS_CC, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
3410 return;
3411 }
3412
3413 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
3414 return;
3415 }
3416
3417 } else {
3418 php_error_docref(NULL TSRMLS_CC, E_WARNING, "behavior is %d. This should never happen. Please report as a bug", behavior);
3419 return;
3420 }
3421
3422 PHP_ARRAY_CMP_FUNC_BACKUP();
3423
3424
3425 lists = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0);
3426 ptrs = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0);
3427 php_set_compare_func(PHP_SORT_STRING TSRMLS_CC);
3428
3429 if (behavior == DIFF_NORMAL && data_compare_type == DIFF_COMP_DATA_USER) {
3430 BG(user_compare_fci) = *fci_data;
3431 BG(user_compare_fci_cache) = *fci_data_cache;
3432 } else if (behavior & DIFF_ASSOC && key_compare_type == DIFF_COMP_KEY_USER) {
3433 BG(user_compare_fci) = *fci_key;
3434 BG(user_compare_fci_cache) = *fci_key_cache;
3435 }
3436
3437 for (i = 0; i < arr_argc; i++) {
3438 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
3439 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1);
3440 arr_argc = i;
3441 goto out;
3442 }
3443 hash = Z_ARRVAL_PP(args[i]);
3444 list = (Bucket **) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket *), hash->persistent);
3445 if (!list) {
3446 PHP_ARRAY_CMP_FUNC_RESTORE();
3447
3448 efree(ptrs);
3449 efree(lists);
3450 efree(args);
3451 RETURN_FALSE;
3452 }
3453 lists[i] = list;
3454 ptrs[i] = list;
3455 for (p = hash->pListHead; p; p = p->pListNext) {
3456 *list++ = p;
3457 }
3458 *list = NULL;
3459 if (behavior == DIFF_NORMAL) {
3460 zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), diff_data_compare_func TSRMLS_CC);
3461 } else if (behavior & DIFF_ASSOC) {
3462 zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), diff_key_compare_func TSRMLS_CC);
3463 }
3464 }
3465
3466
3467 RETVAL_ZVAL(*args[0], 1, 0);
3468 if (return_value->value.ht == &EG(symbol_table)) {
3469 HashTable *ht;
3470 zval *tmp;
3471
3472 ALLOC_HASHTABLE(ht);
3473 zend_hash_init(ht, zend_hash_num_elements(return_value->value.ht), NULL, ZVAL_PTR_DTOR, 0);
3474 zend_hash_copy(ht, return_value->value.ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
3475 return_value->value.ht = ht;
3476 }
3477
3478
3479 while (*ptrs[0]) {
3480 if ((behavior & DIFF_ASSOC)
3481 &&
3482 key_compare_type == DIFF_COMP_KEY_USER
3483 ) {
3484 BG(user_compare_fci) = *fci_key;
3485 BG(user_compare_fci_cache) = *fci_key_cache;
3486 }
3487 c = 1;
3488 for (i = 1; i < arr_argc; i++) {
3489 Bucket **ptr = ptrs[i];
3490 if (behavior == DIFF_NORMAL) {
3491 while (*ptrs[i] && (0 < (c = diff_data_compare_func(ptrs[0], ptrs[i] TSRMLS_CC)))) {
3492 ptrs[i]++;
3493 }
3494 } else if (behavior & DIFF_ASSOC) {
3495 while (*ptr && (0 != (c = diff_key_compare_func(ptrs[0], ptr TSRMLS_CC)))) {
3496 ptr++;
3497 }
3498 }
3499 if (!c) {
3500 if (behavior == DIFF_NORMAL) {
3501 if (*ptrs[i]) {
3502 ptrs[i]++;
3503 }
3504 break;
3505 } else if (behavior == DIFF_ASSOC) {
3506
3507
3508 if (*ptr) {
3509 if (data_compare_type == DIFF_COMP_DATA_USER) {
3510 BG(user_compare_fci) = *fci_data;
3511 BG(user_compare_fci_cache) = *fci_data_cache;
3512 }
3513 if (diff_data_compare_func(ptrs[0], ptr TSRMLS_CC) != 0) {
3514
3515 c = -1;
3516 if (key_compare_type == DIFF_COMP_KEY_USER) {
3517 BG(user_compare_fci) = *fci_key;
3518 BG(user_compare_fci_cache) = *fci_key_cache;
3519 }
3520 } else {
3521 break;
3522
3523
3524 }
3525 }
3526 } else if (behavior == DIFF_KEY) {
3527
3528
3529
3530
3531 break;
3532 }
3533 }
3534 }
3535 if (!c) {
3536
3537
3538 for (;;) {
3539 p = *ptrs[0];
3540 if (p->nKeyLength == 0) {
3541 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
3542 } else {
3543 zend_hash_quick_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h);
3544 }
3545 if (!*++ptrs[0]) {
3546 goto out;
3547 }
3548 if (behavior == DIFF_NORMAL) {
3549 if (diff_data_compare_func(ptrs[0] - 1, ptrs[0] TSRMLS_CC)) {
3550 break;
3551 }
3552 } else if (behavior & DIFF_ASSOC) {
3553
3554 break;
3555 }
3556 }
3557 } else {
3558
3559
3560 for (;;) {
3561 if (!*++ptrs[0]) {
3562 goto out;
3563 }
3564 if (behavior == DIFF_NORMAL) {
3565 if (diff_data_compare_func(ptrs[0] - 1, ptrs[0] TSRMLS_CC)) {
3566 break;
3567 }
3568 } else if (behavior & DIFF_ASSOC) {
3569
3570 break;
3571 }
3572 }
3573 }
3574 }
3575 out:
3576 for (i = 0; i < arr_argc; i++) {
3577 hash = Z_ARRVAL_PP(args[i]);
3578 pefree(lists[i], hash->persistent);
3579 }
3580
3581 PHP_ARRAY_CMP_FUNC_RESTORE();
3582
3583 efree(ptrs);
3584 efree(lists);
3585 efree(args);
3586 }
3587
3588
3589
3590
3591 PHP_FUNCTION(array_diff_key)
3592 {
3593 php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_NONE);
3594 }
3595
3596
3597
3598
3599 PHP_FUNCTION(array_diff_ukey)
3600 {
3601 php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_KEY, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
3602 }
3603
3604
3605
3606
3607 PHP_FUNCTION(array_diff)
3608 {
3609 php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_NORMAL, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_INTERNAL);
3610 }
3611
3612
3613
3614
3615 PHP_FUNCTION(array_udiff)
3616 {
3617 php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_NORMAL, DIFF_COMP_DATA_USER, DIFF_COMP_KEY_INTERNAL);
3618 }
3619
3620
3621
3622
3623 PHP_FUNCTION(array_diff_assoc)
3624 {
3625 php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_INTERNAL);
3626 }
3627
3628
3629
3630
3631 PHP_FUNCTION(array_diff_uassoc)
3632 {
3633 php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
3634 }
3635
3636
3637
3638
3639 PHP_FUNCTION(array_udiff_assoc)
3640 {
3641 php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_USER);
3642 }
3643
3644
3645
3646
3647 PHP_FUNCTION(array_udiff_uassoc)
3648 {
3649 php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_USER, DIFF_COMP_KEY_USER);
3650 }
3651
3652
3653 #define MULTISORT_ORDER 0
3654 #define MULTISORT_TYPE 1
3655 #define MULTISORT_LAST 2
3656
3657 PHPAPI int php_multisort_compare(const void *a, const void *b TSRMLS_DC)
3658 {
3659 Bucket **ab = *(Bucket ***)a;
3660 Bucket **bb = *(Bucket ***)b;
3661 int r;
3662 int result = 0;
3663 zval temp;
3664
3665 r = 0;
3666 do {
3667 php_set_compare_func(ARRAYG(multisort_flags)[MULTISORT_TYPE][r] TSRMLS_CC);
3668
3669 ARRAYG(compare_func)(&temp, *((zval **)ab[r]->pData), *((zval **)bb[r]->pData) TSRMLS_CC);
3670 result = ARRAYG(multisort_flags)[MULTISORT_ORDER][r] * Z_LVAL(temp);
3671 if (result != 0) {
3672 return result;
3673 }
3674 r++;
3675 } while (ab[r] != NULL);
3676
3677 return result;
3678 }
3679
3680
3681 #define MULTISORT_ABORT \
3682 for (k = 0; k < MULTISORT_LAST; k++) \
3683 efree(ARRAYG(multisort_flags)[k]); \
3684 efree(arrays); \
3685 efree(args); \
3686 RETURN_FALSE;
3687
3688
3689
3690 PHP_FUNCTION(array_multisort)
3691 {
3692 zval*** args;
3693 zval*** arrays;
3694 Bucket*** indirect;
3695 Bucket* p;
3696 HashTable* hash;
3697 int argc;
3698 int array_size;
3699 int num_arrays = 0;
3700 int parse_state[MULTISORT_LAST];
3701 int sort_order = PHP_SORT_ASC;
3702 int sort_type = PHP_SORT_REGULAR;
3703 int i, k;
3704
3705 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
3706 return;
3707 }
3708
3709
3710 arrays = (zval ***)ecalloc(argc, sizeof(zval **));
3711 for (i = 0; i < MULTISORT_LAST; i++) {
3712 parse_state[i] = 0;
3713 ARRAYG(multisort_flags)[i] = (int *)ecalloc(argc, sizeof(int));
3714 }
3715
3716
3717
3718
3719
3720
3721 for (i = 0; i < argc; i++) {
3722 if (Z_TYPE_PP(args[i]) == IS_ARRAY) {
3723
3724
3725 if (i > 0) {
3726 ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays - 1] = sort_order;
3727 ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays - 1] = sort_type;
3728 sort_order = PHP_SORT_ASC;
3729 sort_type = PHP_SORT_REGULAR;
3730 }
3731 arrays[num_arrays++] = args[i];
3732
3733
3734 for (k = 0; k < MULTISORT_LAST; k++) {
3735 parse_state[k] = 1;
3736 }
3737 } else if (Z_TYPE_PP(args[i]) == IS_LONG) {
3738 switch (Z_LVAL_PP(args[i]) & ~PHP_SORT_FLAG_CASE) {
3739 case PHP_SORT_ASC:
3740 case PHP_SORT_DESC:
3741
3742 if (parse_state[MULTISORT_ORDER] == 1) {
3743
3744 sort_order = Z_LVAL_PP(args[i]) == PHP_SORT_DESC ? -1 : 1;
3745 parse_state[MULTISORT_ORDER] = 0;
3746 } else {
3747 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1);
3748 MULTISORT_ABORT;
3749 }
3750 break;
3751
3752 case PHP_SORT_REGULAR:
3753 case PHP_SORT_NUMERIC:
3754 case PHP_SORT_STRING:
3755 case PHP_SORT_NATURAL:
3756 #if HAVE_STRCOLL
3757 case PHP_SORT_LOCALE_STRING:
3758 #endif
3759
3760 if (parse_state[MULTISORT_TYPE] == 1) {
3761
3762 sort_type = Z_LVAL_PP(args[i]);
3763 parse_state[MULTISORT_TYPE] = 0;
3764 } else {
3765 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1);
3766 MULTISORT_ABORT;
3767 }
3768 break;
3769
3770 default:
3771 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is an unknown sort flag", i + 1);
3772 MULTISORT_ABORT;
3773 break;
3774
3775 }
3776 } else {
3777 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or a sort flag", i + 1);
3778 MULTISORT_ABORT;
3779 }
3780 }
3781
3782 ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays - 1] = sort_order;
3783 ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays - 1] = sort_type;
3784
3785
3786 array_size = zend_hash_num_elements(Z_ARRVAL_PP(arrays[0]));
3787 for (i = 0; i < num_arrays; i++) {
3788 if (zend_hash_num_elements(Z_ARRVAL_PP(arrays[i])) != array_size) {
3789 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array sizes are inconsistent");
3790 MULTISORT_ABORT;
3791 }
3792 }
3793
3794
3795 if (array_size < 1) {
3796 for (k = 0; k < MULTISORT_LAST; k++) {
3797 efree(ARRAYG(multisort_flags)[k]);
3798 }
3799 efree(arrays);
3800 efree(args);
3801 RETURN_TRUE;
3802 }
3803
3804
3805
3806
3807
3808 indirect = (Bucket ***)safe_emalloc(array_size, sizeof(Bucket **), 0);
3809 for (i = 0; i < array_size; i++) {
3810 indirect[i] = (Bucket **)safe_emalloc((num_arrays + 1), sizeof(Bucket *), 0);
3811 }
3812 for (i = 0; i < num_arrays; i++) {
3813 k = 0;
3814 for (p = Z_ARRVAL_PP(arrays[i])->pListHead; p; p = p->pListNext, k++) {
3815 indirect[k][i] = p;
3816 }
3817 }
3818 for (k = 0; k < array_size; k++) {
3819 indirect[k][num_arrays] = NULL;
3820 }
3821
3822
3823 zend_qsort(indirect, array_size, sizeof(Bucket **), php_multisort_compare TSRMLS_CC);
3824
3825
3826 HANDLE_BLOCK_INTERRUPTIONS();
3827 for (i = 0; i < num_arrays; i++) {
3828 hash = Z_ARRVAL_PP(arrays[i]);
3829 hash->pListHead = indirect[0][i];;
3830 hash->pListTail = NULL;
3831 hash->pInternalPointer = hash->pListHead;
3832
3833 for (k = 0; k < array_size; k++) {
3834 if (hash->pListTail) {
3835 hash->pListTail->pListNext = indirect[k][i];
3836 }
3837 indirect[k][i]->pListLast = hash->pListTail;
3838 indirect[k][i]->pListNext = NULL;
3839 hash->pListTail = indirect[k][i];
3840 }
3841
3842 zend_hash_reindex(hash, 1);
3843 }
3844 HANDLE_UNBLOCK_INTERRUPTIONS();
3845
3846
3847 for (i = 0; i < array_size; i++) {
3848 efree(indirect[i]);
3849 }
3850 efree(indirect);
3851 for (k = 0; k < MULTISORT_LAST; k++) {
3852 efree(ARRAYG(multisort_flags)[k]);
3853 }
3854 efree(arrays);
3855 efree(args);
3856 RETURN_TRUE;
3857 }
3858
3859
3860
3861
3862 PHP_FUNCTION(array_rand)
3863 {
3864 zval *input;
3865 long randval, num_req = 1;
3866 int num_avail, key_type;
3867 char *string_key;
3868 uint string_key_len;
3869 ulong num_key;
3870 HashPosition pos;
3871
3872 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &input, &num_req) == FAILURE) {
3873 return;
3874 }
3875
3876 num_avail = zend_hash_num_elements(Z_ARRVAL_P(input));
3877
3878 if (ZEND_NUM_ARGS() > 1) {
3879 if (num_req <= 0 || num_req > num_avail) {
3880 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second argument has to be between 1 and the number of elements in the array");
3881 return;
3882 }
3883 }
3884
3885
3886 if (num_req > 1) {
3887 array_init_size(return_value, num_req);
3888 }
3889
3890
3891 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
3892 while (num_req && (key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 0, &pos)) != HASH_KEY_NON_EXISTENT) {
3893
3894 randval = php_rand(TSRMLS_C);
3895
3896 if ((double) (randval / (PHP_RAND_MAX + 1.0)) < (double) num_req / (double) num_avail) {
3897
3898 if (Z_TYPE_P(return_value) != IS_ARRAY) {
3899 if (key_type == HASH_KEY_IS_STRING) {
3900 RETURN_STRINGL(string_key, string_key_len - 1, 1);
3901 } else {
3902 RETURN_LONG(num_key);
3903 }
3904 } else {
3905
3906 if (key_type == HASH_KEY_IS_STRING) {
3907 add_next_index_stringl(return_value, string_key, string_key_len - 1, 1);
3908 } else {
3909 add_next_index_long(return_value, num_key);
3910 }
3911 }
3912 num_req--;
3913 }
3914 num_avail--;
3915 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
3916 }
3917 }
3918
3919
3920
3921
3922 PHP_FUNCTION(array_sum)
3923 {
3924 zval *input,
3925 **entry,
3926 entry_n;
3927 HashPosition pos;
3928
3929 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &input) == FAILURE) {
3930 return;
3931 }
3932
3933 ZVAL_LONG(return_value, 0);
3934
3935 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
3936 zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS;
3937 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos)
3938 ) {
3939 if (Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT) {
3940 continue;
3941 }
3942 entry_n = **entry;
3943 zval_copy_ctor(&entry_n);
3944 convert_scalar_to_number(&entry_n TSRMLS_CC);
3945 fast_add_function(return_value, return_value, &entry_n TSRMLS_CC);
3946 }
3947 }
3948
3949
3950
3951
3952 PHP_FUNCTION(array_product)
3953 {
3954 zval *input,
3955 **entry,
3956 entry_n;
3957 HashPosition pos;
3958 double dval;
3959
3960 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &input) == FAILURE) {
3961 return;
3962 }
3963
3964 ZVAL_LONG(return_value, 1);
3965 if (!zend_hash_num_elements(Z_ARRVAL_P(input))) {
3966 return;
3967 }
3968
3969 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
3970 zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS;
3971 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos)
3972 ) {
3973 if (Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT) {
3974 continue;
3975 }
3976 entry_n = **entry;
3977 zval_copy_ctor(&entry_n);
3978 convert_scalar_to_number(&entry_n TSRMLS_CC);
3979
3980 if (Z_TYPE(entry_n) == IS_LONG && Z_TYPE_P(return_value) == IS_LONG) {
3981 dval = (double)Z_LVAL_P(return_value) * (double)Z_LVAL(entry_n);
3982 if ( (double)LONG_MIN <= dval && dval <= (double)LONG_MAX ) {
3983 Z_LVAL_P(return_value) *= Z_LVAL(entry_n);
3984 continue;
3985 }
3986 }
3987 convert_to_double(return_value);
3988 convert_to_double(&entry_n);
3989 Z_DVAL_P(return_value) *= Z_DVAL(entry_n);
3990 }
3991 }
3992
3993
3994
3995
3996 PHP_FUNCTION(array_reduce)
3997 {
3998 zval *input;
3999 zval **args[2];
4000 zval **operand;
4001 zval *result = NULL;
4002 zval *retval;
4003 zend_fcall_info fci;
4004 zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
4005 zval *initial = NULL;
4006 HashPosition pos;
4007 HashTable *htbl;
4008
4009 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af|z", &input, &fci, &fci_cache, &initial) == FAILURE) {
4010 return;
4011 }
4012
4013 if (ZEND_NUM_ARGS() > 2) {
4014 ALLOC_ZVAL(result);
4015 MAKE_COPY_ZVAL(&initial, result);
4016 } else {
4017 MAKE_STD_ZVAL(result);
4018 ZVAL_NULL(result);
4019 }
4020
4021
4022
4023
4024 htbl = Z_ARRVAL_P(input);
4025
4026 if (zend_hash_num_elements(htbl) == 0) {
4027 if (result) {
4028 RETVAL_ZVAL(result, 1, 1);
4029 }
4030 return;
4031 }
4032
4033 fci.retval_ptr_ptr = &retval;
4034 fci.param_count = 2;
4035 fci.no_separation = 0;
4036
4037 zend_hash_internal_pointer_reset_ex(htbl, &pos);
4038 while (zend_hash_get_current_data_ex(htbl, (void **)&operand, &pos) == SUCCESS) {
4039
4040 if (result) {
4041 args[0] = &result;
4042 args[1] = operand;
4043 fci.params = args;
4044
4045 if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && retval) {
4046 zval_ptr_dtor(&result);
4047 result = retval;
4048 } else {
4049 php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the reduction callback");
4050 return;
4051 }
4052 } else {
4053 result = *operand;
4054 zval_add_ref(&result);
4055 }
4056 zend_hash_move_forward_ex(htbl, &pos);
4057 }
4058 RETVAL_ZVAL(result, 1, 1);
4059 }
4060
4061
4062
4063
4064 PHP_FUNCTION(array_filter)
4065 {
4066 zval *array;
4067 zval **operand;
4068 zval **args[2];
4069 zval *retval = NULL;
4070 zval *key = NULL;
4071 zend_bool have_callback = 0;
4072 long use_type = 0;
4073 char *string_key;
4074 zend_fcall_info fci = empty_fcall_info;
4075 zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
4076 uint string_key_len;
4077 ulong num_key;
4078 HashPosition pos;
4079
4080 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|fl", &array, &fci, &fci_cache, &use_type) == FAILURE) {
4081 return;
4082 }
4083
4084 array_init(return_value);
4085 if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) {
4086 return;
4087 }
4088
4089 if (ZEND_NUM_ARGS() > 1) {
4090 have_callback = 1;
4091 fci.no_separation = 0;
4092 fci.retval_ptr_ptr = &retval;
4093
4094 if (use_type == ARRAY_FILTER_USE_BOTH) {
4095 fci.param_count = 2;
4096 args[1] = &key;
4097 } else {
4098 fci.param_count = 1;
4099 if (use_type == ARRAY_FILTER_USE_KEY) {
4100 args[0] = &key;
4101 }
4102 }
4103 }
4104
4105 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
4106 zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&operand, &pos) == SUCCESS;
4107 zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)
4108 ) {
4109 int key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &string_key_len, &num_key, 0, &pos);
4110
4111 if (have_callback) {
4112 if (use_type) {
4113 MAKE_STD_ZVAL(key);
4114
4115 switch (key_type) {
4116 case HASH_KEY_IS_LONG:
4117 Z_TYPE_P(key) = IS_LONG;
4118 Z_LVAL_P(key) = num_key;
4119 break;
4120
4121 case HASH_KEY_IS_STRING:
4122 ZVAL_STRINGL(key, string_key, string_key_len - 1, 1);
4123 break;
4124 }
4125 }
4126
4127 if (use_type != ARRAY_FILTER_USE_KEY) {
4128 args[0] = operand;
4129 }
4130 fci.params = args;
4131
4132 if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && retval) {
4133 int retval_true = zend_is_true(retval);
4134
4135 zval_ptr_dtor(&retval);
4136 if (use_type) {
4137 zval_ptr_dtor(&key);
4138 }
4139 if (!retval_true) {
4140 continue;
4141 }
4142 } else {
4143 php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the filter callback");
4144 return;
4145 }
4146 } else if (!zend_is_true(*operand)) {
4147 continue;
4148 }
4149
4150 zval_add_ref(operand);
4151 switch (key_type) {
4152 case HASH_KEY_IS_STRING:
4153 zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, operand, sizeof(zval *), NULL);
4154 break;
4155
4156 case HASH_KEY_IS_LONG:
4157 zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, operand, sizeof(zval *), NULL);
4158 break;
4159 }
4160 }
4161 }
4162
4163
4164
4165
4166 PHP_FUNCTION(array_map)
4167 {
4168 zval ***arrays = NULL;
4169 int n_arrays = 0;
4170 zval ***params;
4171 zval *result, *null;
4172 HashPosition *array_pos;
4173 zval **args;
4174 zend_fcall_info fci = empty_fcall_info;
4175 zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
4176 int i, k, maxlen = 0;
4177 int *array_len;
4178
4179 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f!+", &fci, &fci_cache, &arrays, &n_arrays) == FAILURE) {
4180 return;
4181 }
4182
4183 RETVAL_NULL();
4184
4185 args = (zval **)safe_emalloc(n_arrays, sizeof(zval *), 0);
4186 array_len = (int *)safe_emalloc(n_arrays, sizeof(int), 0);
4187 array_pos = (HashPosition *)safe_emalloc(n_arrays, sizeof(HashPosition), 0);
4188
4189 for (i = 0; i < n_arrays; i++) {
4190 if (Z_TYPE_PP(arrays[i]) != IS_ARRAY) {
4191 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d should be an array", i + 2);
4192 efree(arrays);
4193 efree(args);
4194 efree(array_len);
4195 efree(array_pos);
4196 return;
4197 }
4198 SEPARATE_ZVAL_IF_NOT_REF(arrays[i]);
4199 args[i] = *arrays[i];
4200 array_len[i] = zend_hash_num_elements(Z_ARRVAL_PP(arrays[i]));
4201 if (array_len[i] > maxlen) {
4202 maxlen = array_len[i];
4203 }
4204 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(arrays[i]), &array_pos[i]);
4205 }
4206
4207 efree(arrays);
4208
4209
4210 if (!ZEND_FCI_INITIALIZED(fci) && n_arrays == 1) {
4211 RETVAL_ZVAL(args[0], 1, 0);
4212 efree(array_len);
4213 efree(array_pos);
4214 efree(args);
4215 return;
4216 }
4217
4218 array_init_size(return_value, maxlen);
4219 params = (zval ***)safe_emalloc(n_arrays, sizeof(zval **), 0);
4220 MAKE_STD_ZVAL(null);
4221 ZVAL_NULL(null);
4222
4223
4224 for (k = 0; k < maxlen; k++) {
4225 uint str_key_len;
4226 ulong num_key;
4227 char *str_key;
4228 int key_type = 0;
4229
4230
4231
4232 if (!ZEND_FCI_INITIALIZED(fci)) {
4233 MAKE_STD_ZVAL(result);
4234 array_init_size(result, n_arrays);
4235 }
4236
4237 for (i = 0; i < n_arrays; i++) {
4238
4239
4240 if (k < array_len[i]) {
4241 zend_hash_get_current_data_ex(Z_ARRVAL_P(args[i]), (void **)¶ms[i], &array_pos[i]);
4242
4243
4244
4245 if (n_arrays == 1) {
4246 key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(args[0]), &str_key, &str_key_len, &num_key, 0, &array_pos[i]);
4247 }
4248 zend_hash_move_forward_ex(Z_ARRVAL_P(args[i]), &array_pos[i]);
4249 } else {
4250 params[i] = &null;
4251 }
4252
4253 if (!ZEND_FCI_INITIALIZED(fci)) {
4254 zval_add_ref(params[i]);
4255 add_next_index_zval(result, *params[i]);
4256 }
4257 }
4258
4259 if (ZEND_FCI_INITIALIZED(fci)) {
4260 fci.retval_ptr_ptr = &result;
4261 fci.param_count = n_arrays;
4262 fci.params = params;
4263 fci.no_separation = 0;
4264
4265 if (zend_call_function(&fci, &fci_cache TSRMLS_CC) != SUCCESS || !result) {
4266 php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the map callback");
4267 efree(array_len);
4268 efree(args);
4269 efree(array_pos);
4270 zval_dtor(return_value);
4271 zval_ptr_dtor(&null);
4272 efree(params);
4273 RETURN_NULL();
4274 }
4275 }
4276
4277 if (n_arrays > 1) {
4278 add_next_index_zval(return_value, result);
4279 } else {
4280 if (key_type == HASH_KEY_IS_STRING) {
4281 add_assoc_zval_ex(return_value, str_key, str_key_len, result);
4282 } else {
4283 add_index_zval(return_value, num_key, result);
4284 }
4285 }
4286 }
4287
4288 zval_ptr_dtor(&null);
4289 efree(params);
4290 efree(array_len);
4291 efree(array_pos);
4292 efree(args);
4293 }
4294
4295
4296
4297
4298 PHP_FUNCTION(array_key_exists)
4299 {
4300 zval *key;
4301 HashTable *array;
4302
4303 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zH", &key, &array) == FAILURE) {
4304 return;
4305 }
4306
4307 switch (Z_TYPE_P(key)) {
4308 case IS_STRING:
4309 if (zend_symtable_exists(array, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1)) {
4310 RETURN_TRUE;
4311 }
4312 RETURN_FALSE;
4313 case IS_LONG:
4314 if (zend_hash_index_exists(array, Z_LVAL_P(key))) {
4315 RETURN_TRUE;
4316 }
4317 RETURN_FALSE;
4318 case IS_NULL:
4319 if (zend_hash_exists(array, "", 1)) {
4320 RETURN_TRUE;
4321 }
4322 RETURN_FALSE;
4323
4324 default:
4325 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be either a string or an integer");
4326 RETURN_FALSE;
4327 }
4328 }
4329
4330
4331
4332
4333 PHP_FUNCTION(array_chunk)
4334 {
4335 int argc = ZEND_NUM_ARGS(), key_type, num_in;
4336 long size, current = 0;
4337 char *str_key;
4338 uint str_key_len;
4339 ulong num_key;
4340 zend_bool preserve_keys = 0;
4341 zval *input = NULL;
4342 zval *chunk = NULL;
4343 zval **entry;
4344 HashPosition pos;
4345
4346 if (zend_parse_parameters(argc TSRMLS_CC, "al|b", &input, &size, &preserve_keys) == FAILURE) {
4347 return;
4348 }
4349
4350 if (size < 1) {
4351 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size parameter expected to be greater than 0");
4352 return;
4353 }
4354
4355 num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
4356
4357 if (size > num_in) {
4358 size = num_in > 0 ? num_in : 1;
4359 }
4360
4361 array_init_size(return_value, ((num_in - 1) / size) + 1);
4362
4363 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
4364 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void**)&entry, &pos) == SUCCESS) {
4365
4366 if (!chunk) {
4367 MAKE_STD_ZVAL(chunk);
4368 array_init_size(chunk, size);
4369 }
4370
4371
4372 zval_add_ref(entry);
4373
4374 if (preserve_keys) {
4375 key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &str_key, &str_key_len, &num_key, 0, &pos);
4376 switch (key_type) {
4377 case HASH_KEY_IS_STRING:
4378 add_assoc_zval_ex(chunk, str_key, str_key_len, *entry);
4379 break;
4380 default:
4381 add_index_zval(chunk, num_key, *entry);
4382 break;
4383 }
4384 } else {
4385 add_next_index_zval(chunk, *entry);
4386 }
4387
4388
4389
4390 if (!(++current % size)) {
4391 add_next_index_zval(return_value, chunk);
4392 chunk = NULL;
4393 }
4394
4395 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
4396 }
4397
4398
4399 if (chunk) {
4400 add_next_index_zval(return_value, chunk);
4401 }
4402 }
4403
4404
4405
4406
4407 PHP_FUNCTION(array_combine)
4408 {
4409 zval *values, *keys;
4410 HashPosition pos_values, pos_keys;
4411 zval **entry_keys, **entry_values;
4412 int num_keys, num_values;
4413
4414 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "aa", &keys, &values) == FAILURE) {
4415 return;
4416 }
4417
4418 num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys));
4419 num_values = zend_hash_num_elements(Z_ARRVAL_P(values));
4420
4421 if (num_keys != num_values) {
4422 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Both parameters should have an equal number of elements");
4423 RETURN_FALSE;
4424 }
4425
4426 array_init_size(return_value, num_keys);
4427
4428 if (!num_keys) {
4429 return;
4430 }
4431
4432 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos_keys);
4433 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos_values);
4434 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&entry_keys, &pos_keys) == SUCCESS &&
4435 zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&entry_values, &pos_values) == SUCCESS
4436 ) {
4437 if (Z_TYPE_PP(entry_keys) == IS_LONG) {
4438 zval_add_ref(entry_values);
4439 add_index_zval(return_value, Z_LVAL_PP(entry_keys), *entry_values);
4440 } else {
4441 zval key, *key_ptr = *entry_keys;
4442
4443 if (Z_TYPE_PP(entry_keys) != IS_STRING) {
4444 key = **entry_keys;
4445 zval_copy_ctor(&key);
4446 convert_to_string(&key);
4447 key_ptr = &key;
4448 }
4449
4450 zval_add_ref(entry_values);
4451 add_assoc_zval_ex(return_value, Z_STRVAL_P(key_ptr), Z_STRLEN_P(key_ptr) + 1, *entry_values);
4452
4453 if (key_ptr != *entry_keys) {
4454 zval_dtor(&key);
4455 }
4456 }
4457
4458 zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos_keys);
4459 zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos_values);
4460 }
4461 }
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471