1 /*
2 * This file is part of the Zephir.
3 *
4 * (c) Phalcon Team <team@zephir-lang.com>
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code. If you did not receive
8 * a copy of the license it is available through the world-wide-web at the
9 * following url: https://docs.zephir-lang.com/en/latest/license
10 */
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include <php.h>
17 #include "php_ext.h"
18 #include <ext/standard/php_array.h>
19 #include <Zend/zend_hash.h>
20 #include <Zend/zend_interfaces.h>
21
22 #include "kernel/main.h"
23 #include "kernel/memory.h"
24 #include "kernel/debug.h"
25 #include "kernel/array.h"
26 #include "kernel/operators.h"
27 #include "kernel/backtrace.h"
28 #include "kernel/object.h"
29 #include "kernel/fcall.h"
30
zephir_create_array(zval * return_value,uint32_t size,int initialize)31 void ZEPHIR_FASTCALL zephir_create_array(zval *return_value, uint32_t size, int initialize)
32 {
33 uint32_t i;
34 zval null_value;
35 HashTable *hashTable;
36 ZVAL_NULL(&null_value);
37
38 array_init_size(return_value, size);
39 hashTable = Z_ARRVAL_P(return_value);
40 if (size > 0) {
41 zend_hash_real_init(hashTable, 0);
42 if (initialize) {
43 for (i = 0; i < size; i++) {
44 zend_hash_next_index_insert(hashTable, &null_value);
45 }
46 }
47 }
48 }
49
50 /**
51 * Simple convenience function which ensures that you are dealing with an array and you can
52 * eliminate noise from your code.
53 *
54 * It's a bit strange but the refcount for an empty array is always zero somehow.
55 * There is another strange phenomenon: these zvals does not have any type_flag value.
56 * Thus we should recreate a new empty array so that it has correct refcount
57 * value and type_flag. This magic behavior was introduced since PHP 7.3.
58 *
59 * Steps to reproduce:
60 *
61 * Userland:
62 * $object->method([10 => []]);
63 *
64 * Zephir:
65 * public function method(array p)
66 * {
67 * let p[10]["str"] = "foo";
68 * }
69 */
70 void
zephir_ensure_array(zval * zv)71 ZEPHIR_FASTCALL zephir_ensure_array(zval *zv)
72 {
73 if (
74 Z_TYPE_P(zv) == IS_ARRAY &&
75 zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0 &&
76 (!Z_REFCOUNTED_P(zv) || Z_REFCOUNT_P(zv) < 1)
77 ) {
78 zephir_create_array(zv, 0, 0);
79 }
80 }
81
zephir_array_isset_fetch(zval * fetched,const zval * arr,zval * index,int readonly)82 int zephir_array_isset_fetch(zval *fetched, const zval *arr, zval *index, int readonly)
83 {
84 HashTable *h;
85 zval *result;
86
87 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
88 zend_long ZEPHIR_LAST_CALL_STATUS;
89 zval exist;
90 ZVAL_UNDEF(&exist);
91 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, index);
92 if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
93 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(fetched, (zval *)arr, "offsetget", NULL, 0, index);
94 if (readonly) {
95 Z_TRY_DELREF_P(fetched);
96 }
97
98 return 1;
99 }
100
101 ZVAL_NULL(fetched);
102
103 return 0;
104 } else if (UNEXPECTED(Z_TYPE_P(arr) != IS_ARRAY)) {
105 ZVAL_NULL(fetched);
106
107 return 0;
108 }
109
110 h = Z_ARRVAL_P(arr);
111 switch (Z_TYPE_P(index)) {
112 case IS_NULL:
113 result = zend_hash_str_find(h, SL(""));
114 break;
115
116 case IS_DOUBLE:
117 result = zend_hash_index_find(h, (zend_ulong)Z_DVAL_P(index));
118 break;
119
120 case IS_LONG:
121 case IS_RESOURCE:
122 result = zend_hash_index_find(h, Z_LVAL_P(index));
123 break;
124
125 case IS_TRUE:
126 case IS_FALSE:
127 result = zend_hash_index_find(h, Z_TYPE_P(index) == IS_TRUE ? 1 : 0);
128 break;
129
130 case IS_STRING:
131 result = zend_symtable_str_find(h, (Z_STRLEN_P(index) ? Z_STRVAL_P(index) : ""), Z_STRLEN_P(index));
132 break;
133
134 default:
135 zend_error(E_WARNING, "Illegal offset type %d", Z_TYPE_P(index));
136 return 0;
137 }
138
139 if (result != NULL) {
140 zephir_ensure_array(result);
141
142 if (!readonly) {
143 ZVAL_COPY(fetched, result);
144 } else {
145 ZVAL_COPY_VALUE(fetched, result);
146 }
147
148 return 1;
149 }
150
151 ZVAL_NULL(fetched);
152
153 return 0;
154 }
155
zephir_array_isset_string_fetch(zval * fetched,const zval * arr,char * index,uint32_t index_length,int readonly)156 int zephir_array_isset_string_fetch(zval *fetched, const zval *arr, char *index, uint32_t index_length, int readonly)
157 {
158 zval *zv;
159 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
160 zend_long ZEPHIR_LAST_CALL_STATUS;
161 zval exist, offset;
162 ZVAL_UNDEF(&exist);
163 ZVAL_STRINGL(&offset, index, index_length);
164
165 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, &offset);
166 zval_ptr_dtor(&offset);
167 if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
168 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(fetched, (zval *)arr, "offsetget", NULL, 0, &offset);
169 if (readonly) {
170 Z_TRY_DELREF_P(fetched);
171 }
172 return 1;
173 }
174
175 ZVAL_NULL(fetched);
176
177 return 0;
178 } else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
179 if ((zv = zend_hash_str_find(Z_ARRVAL_P(arr), index, index_length)) != NULL) {
180 zephir_ensure_array(zv);
181
182 if (!readonly) {
183 ZVAL_COPY(fetched, zv);
184 } else {
185 ZVAL_COPY_VALUE(fetched, zv);
186 }
187 return 1;
188 }
189 }
190
191 ZVAL_NULL(fetched);
192
193 return 0;
194 }
195
zephir_array_isset_long_fetch(zval * fetched,const zval * arr,unsigned long index,int readonly)196 int zephir_array_isset_long_fetch(zval *fetched, const zval *arr, unsigned long index, int readonly)
197 {
198 zval *zv;
199
200 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
201 zend_long ZEPHIR_LAST_CALL_STATUS;
202 zval exist, offset;
203 ZVAL_UNDEF(&exist);
204 ZVAL_LONG(&offset, index);
205 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, &offset);
206 if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
207 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(fetched, (zval *)arr, "offsetget", NULL, 0, &offset);
208 if (readonly) {
209 Z_TRY_DELREF_P(fetched);
210 }
211
212 return 1;
213 }
214
215 ZVAL_NULL(fetched);
216
217 return 0;
218 } else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
219 if ((zv = zend_hash_index_find(Z_ARRVAL_P(arr), index)) != NULL) {
220 zephir_ensure_array(zv);
221
222 if (!readonly) {
223 ZVAL_COPY(fetched, zv);
224 } else {
225 ZVAL_COPY_VALUE(fetched, zv);
226 }
227 return 1;
228 }
229 }
230
231 ZVAL_NULL(fetched);
232
233 return 0;
234 }
235
zephir_array_isset(const zval * arr,zval * index)236 int ZEPHIR_FASTCALL zephir_array_isset(const zval *arr, zval *index)
237 {
238 HashTable *h;
239
240 if (UNEXPECTED(!arr)) {
241 return 0;
242 }
243
244 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
245 zend_long ZEPHIR_LAST_CALL_STATUS;
246 zval exist;
247 ZVAL_UNDEF(&exist);
248 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, index);
249 if (zend_is_true(&exist)) {
250 return 1;
251 }
252
253 return 0;
254 } else if (UNEXPECTED(Z_TYPE_P(arr) != IS_ARRAY)) {
255 return 0;
256 }
257
258 h = Z_ARRVAL_P(arr);
259 switch (Z_TYPE_P(index)) {
260 case IS_NULL:
261 return zend_hash_str_exists(h, SL(""));
262
263 case IS_DOUBLE:
264 return zend_hash_index_exists(h, (zend_ulong)Z_DVAL_P(index));
265
266 case IS_TRUE:
267 case IS_FALSE:
268 return zend_hash_index_exists(h, Z_TYPE_P(index) == IS_TRUE ? 1 : 0);
269
270 case IS_LONG:
271 case IS_RESOURCE:
272 return zend_hash_index_exists(h, Z_LVAL_P(index));
273
274 case IS_STRING:
275 return zend_symtable_str_exists(h, Z_STRVAL_P(index), Z_STRLEN_P(index));
276
277 default:
278 zend_error(E_WARNING, "Illegal offset type");
279 return 0;
280 }
281 }
282
zephir_array_isset_string(const zval * arr,const char * index,uint32_t index_length)283 int ZEPHIR_FASTCALL zephir_array_isset_string(const zval *arr, const char *index, uint32_t index_length)
284 {
285 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
286 zend_long ZEPHIR_LAST_CALL_STATUS;
287 zval exist, offset;
288 ZVAL_UNDEF(&exist);
289 ZVAL_STRINGL(&offset, index, index_length);
290 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, &offset);
291 zval_ptr_dtor(&offset);
292 if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
293 return 1;
294 }
295
296 return 0;
297 } else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
298 return zend_hash_str_exists(Z_ARRVAL_P(arr), index, index_length);
299 }
300
301 return 0;
302 }
303
zephir_array_isset_long(const zval * arr,unsigned long index)304 int ZEPHIR_FASTCALL zephir_array_isset_long(const zval *arr, unsigned long index)
305 {
306 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
307 zend_long ZEPHIR_LAST_CALL_STATUS;
308 zval exist, offset;
309 ZVAL_UNDEF(&exist);
310 ZVAL_LONG(&offset, index);
311 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, &offset);
312 if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
313 return 1;
314 }
315
316 return 0;
317 } else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
318 return zend_hash_index_exists(Z_ARRVAL_P(arr), index);
319 }
320
321 return 0;
322 }
323
zephir_array_unset(zval * arr,zval * index,int flags)324 int ZEPHIR_FASTCALL zephir_array_unset(zval *arr, zval *index, int flags)
325 {
326 HashTable *ht;
327
328 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
329 zend_long ZEPHIR_LAST_CALL_STATUS;
330 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetunset", NULL, 0, index);
331 if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
332 return 1;
333 }
334
335 return 0;
336 } else if (Z_TYPE_P(arr) != IS_ARRAY) {
337 return 0;
338 }
339
340 if ((flags & PH_SEPARATE) == PH_SEPARATE) {
341 SEPARATE_ZVAL_IF_NOT_REF(arr);
342 }
343
344 ht = Z_ARRVAL_P(arr);
345
346 switch (Z_TYPE_P(index)) {
347 case IS_NULL:
348 return (zend_hash_str_del(ht, "", 1) == SUCCESS);
349
350 case IS_DOUBLE:
351 return (zend_hash_index_del(ht, (zend_ulong)Z_DVAL_P(index)) == SUCCESS);
352
353 case IS_TRUE:
354 return (zend_hash_index_del(ht, 1) == SUCCESS);
355
356 case IS_FALSE:
357 return (zend_hash_index_del(ht, 0) == SUCCESS);
358
359 case IS_LONG:
360 case IS_RESOURCE:
361 return (zend_hash_index_del(ht, Z_LVAL_P(index)) == SUCCESS);
362
363 case IS_STRING:
364 return (zend_symtable_del(ht, Z_STR_P(index)) == SUCCESS);
365
366 default:
367 zend_error(E_WARNING, "Illegal offset type");
368 return 0;
369 }
370 }
371
zephir_array_unset_string(zval * arr,const char * index,uint32_t index_length,int flags)372 int ZEPHIR_FASTCALL zephir_array_unset_string(zval *arr, const char *index, uint32_t index_length, int flags)
373 {
374 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
375 zend_long ZEPHIR_LAST_CALL_STATUS;
376 zval offset;
377 ZVAL_STRINGL(&offset, index, index_length);
378 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetunset", NULL, 0, &offset);
379 zval_ptr_dtor(&offset);
380 if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
381 return 1;
382 }
383
384 return 0;
385 } else if (Z_TYPE_P(arr) != IS_ARRAY) {
386 return 0;
387 }
388
389 if ((flags & PH_SEPARATE) == PH_SEPARATE) {
390 SEPARATE_ZVAL_IF_NOT_REF(arr);
391 }
392
393 return zend_hash_str_del(Z_ARRVAL_P(arr), index, index_length);
394 }
395
zephir_array_unset_long(zval * arr,unsigned long index,int flags)396 int ZEPHIR_FASTCALL zephir_array_unset_long(zval *arr, unsigned long index, int flags)
397 {
398 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
399 zend_long ZEPHIR_LAST_CALL_STATUS;
400 zval offset;
401 ZVAL_LONG(&offset, index);
402 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetunset", NULL, 0, &offset);
403
404 if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
405 return 1;
406 }
407
408 return 0;
409 } else if (Z_TYPE_P(arr) != IS_ARRAY) {
410 return 0;
411 }
412
413 if ((flags & PH_SEPARATE) == PH_SEPARATE) {
414 SEPARATE_ZVAL_IF_NOT_REF(arr);
415 }
416
417 return zend_hash_index_del(Z_ARRVAL_P(arr), index);
418 }
419
zephir_array_append(zval * arr,zval * value,int flags ZEPHIR_DEBUG_PARAMS)420 int zephir_array_append(zval *arr, zval *value, int flags ZEPHIR_DEBUG_PARAMS)
421 {
422 if (Z_TYPE_P(arr) != IS_ARRAY) {
423 zend_error(E_WARNING, "Cannot use a scalar value as an array in %s on line %d", file, line);
424 return FAILURE;
425 }
426
427 if ((flags & PH_SEPARATE) == PH_SEPARATE) {
428 SEPARATE_ZVAL_IF_NOT_REF(arr);
429 }
430
431 Z_TRY_ADDREF_P(value);
432 return add_next_index_zval(arr, value);
433 }
434
zephir_array_fetch(zval * return_value,zval * arr,zval * index,int flags ZEPHIR_DEBUG_PARAMS)435 int zephir_array_fetch(zval *return_value, zval *arr, zval *index, int flags ZEPHIR_DEBUG_PARAMS)
436 {
437 zval *zv;
438 HashTable *ht;
439 int result = SUCCESS, found = 0;
440 zend_ulong uidx = 0;
441 char *sidx = NULL;
442
443 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
444 zend_long ZEPHIR_LAST_CALL_STATUS;
445 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(return_value, arr, "offsetget", NULL, 0, index);
446 if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
447 if ((flags & PH_READONLY) == PH_READONLY) {
448 Z_TRY_DELREF_P(return_value);
449 }
450 return SUCCESS;
451 }
452
453 return FAILURE;
454 } else if (Z_TYPE_P(arr) == IS_ARRAY) {
455 ht = Z_ARRVAL_P(arr);
456 switch (Z_TYPE_P(index)) {
457 case IS_NULL:
458 found = (zv = zend_hash_str_find(ht, SL(""))) != NULL;
459 sidx = "";
460 break;
461
462 case IS_DOUBLE:
463 uidx = (zend_ulong)Z_DVAL_P(index);
464 found = (zv = zend_hash_index_find(ht, uidx)) != NULL;
465 break;
466
467 case IS_LONG:
468 case IS_RESOURCE:
469 uidx = Z_LVAL_P(index);
470 found = (zv = zend_hash_index_find(ht, uidx)) != NULL;
471 break;
472
473 case IS_FALSE:
474 uidx = 0;
475 found = (zv = zend_hash_index_find(ht, uidx)) != NULL;
476 break;
477
478 case IS_TRUE:
479 uidx = 1;
480 found = (zv = zend_hash_index_find(ht, uidx)) != NULL;
481 break;
482
483 case IS_STRING:
484 sidx = Z_STRLEN_P(index) ? Z_STRVAL_P(index) : "";
485 found = (zv = zend_symtable_str_find(ht, Z_STRVAL_P(index), Z_STRLEN_P(index))) != NULL;
486 break;
487
488 default:
489 if ((flags & PH_NOISY) == PH_NOISY) {
490 zend_error(E_WARNING, "Illegal offset type in %s on line %d", file, line);
491 }
492 result = FAILURE;
493 break;
494 }
495
496 if (result != FAILURE && found == 1) {
497 if ((flags & PH_READONLY) == PH_READONLY) {
498 ZVAL_COPY_VALUE(return_value, zv);
499 } else {
500 ZVAL_COPY(return_value, zv);
501 }
502 return SUCCESS;
503 }
504
505 if ((flags & PH_NOISY) == PH_NOISY) {
506 if (sidx == NULL) {
507 zend_error(E_NOTICE, "Undefined index: %ld in %s on line %d", uidx, file, line);
508 } else {
509 zend_error(E_NOTICE, "Undefined index: %s in %s on line %d", sidx, file, line);
510 }
511 }
512 }
513
514 ZVAL_NULL(return_value);
515 return FAILURE;
516 }
517
zephir_array_fetch_string(zval * return_value,zval * arr,const char * index,uint32_t index_length,int flags ZEPHIR_DEBUG_PARAMS)518 int zephir_array_fetch_string(zval *return_value, zval *arr, const char *index, uint32_t index_length, int flags ZEPHIR_DEBUG_PARAMS)
519 {
520 zval *zv;
521
522 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
523 zend_long ZEPHIR_LAST_CALL_STATUS;
524 zval offset;
525 ZVAL_STRINGL(&offset, index, index_length);
526 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(return_value, arr, "offsetget", NULL, 0, &offset);
527 zval_ptr_dtor(&offset);
528 if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
529 if ((flags & PH_READONLY) == PH_READONLY) {
530 Z_TRY_DELREF_P(return_value);
531 }
532 return SUCCESS;
533 }
534
535 return FAILURE;
536 } else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
537 if ((zv = zend_hash_str_find(Z_ARRVAL_P(arr), index, index_length)) != NULL) {
538
539 if ((flags & PH_READONLY) == PH_READONLY) {
540 ZVAL_COPY_VALUE(return_value, zv);
541 } else {
542 ZVAL_COPY(return_value, zv);
543 }
544 return SUCCESS;
545 }
546 if ((flags & PH_NOISY) == PH_NOISY) {
547 zend_error(E_NOTICE, "Undefined index: %s", index);
548 }
549 } else {
550 if ((flags & PH_NOISY) == PH_NOISY) {
551 zend_error(E_NOTICE, "Cannot use a scalar value as an array in %s on line %d", file, line);
552 }
553 }
554
555 if (return_value == NULL) {
556 zend_error(E_ERROR, "No return value passed to zephir_array_fetch_string");
557 return FAILURE;
558 }
559
560 ZVAL_NULL(return_value);
561 return FAILURE;
562 }
563
zephir_array_fetch_long(zval * return_value,zval * arr,unsigned long index,int flags ZEPHIR_DEBUG_PARAMS)564 int zephir_array_fetch_long(zval *return_value, zval *arr, unsigned long index, int flags ZEPHIR_DEBUG_PARAMS)
565 {
566 zval *zv;
567
568 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
569 zend_long ZEPHIR_LAST_CALL_STATUS;
570 zval offset;
571 ZVAL_LONG(&offset, index);
572 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(return_value, arr, "offsetget", NULL, 0, &offset);
573 if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
574 if ((flags & PH_READONLY) == PH_READONLY) {
575 Z_TRY_DELREF_P(return_value);
576 }
577 return SUCCESS;
578 }
579
580 return FAILURE;
581 } else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
582 if ((zv = zend_hash_index_find(Z_ARRVAL_P(arr), index)) != NULL) {
583
584 if ((flags & PH_READONLY) == PH_READONLY) {
585 ZVAL_COPY_VALUE(return_value, zv);
586 } else {
587 ZVAL_COPY(return_value, zv);
588 }
589 return SUCCESS;
590 }
591 if ((flags & PH_NOISY) == PH_NOISY) {
592 zend_error(E_NOTICE, "Undefined index: %lu", index);
593 }
594 } else {
595 if ((flags & PH_NOISY) == PH_NOISY) {
596 zend_error(E_NOTICE, "Cannot use a scalar value as an array in %s on line %d", file, line);
597 }
598 }
599
600 if (return_value == NULL) {
601 zend_error(E_ERROR, "No return value passed to zephir_array_fetch_string");
602 return FAILURE;
603 }
604
605 ZVAL_NULL(return_value);
606 return FAILURE;
607 }
608
609 /**
610 * Appends every element of an array at the end of the left array
611 */
zephir_merge_append(zval * left,zval * values)612 void zephir_merge_append(zval *left, zval *values)
613 {
614 if (Z_TYPE_P(left) != IS_ARRAY) {
615 zend_error(E_NOTICE, "First parameter of zephir_merge_append must be an array");
616 return;
617 }
618
619 if (Z_TYPE_P(values) == IS_ARRAY) {
620 zval *tmp;
621
622 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(values), tmp) {
623
624 Z_TRY_ADDREF_P(tmp);
625 add_next_index_zval(left, tmp);
626
627 } ZEND_HASH_FOREACH_END();
628
629 } else {
630 Z_TRY_ADDREF_P(values);
631 add_next_index_zval(left, values);
632 }
633 }
634
zephir_array_update_zval(zval * arr,zval * index,zval * value,int flags)635 int zephir_array_update_zval(zval *arr, zval *index, zval *value, int flags)
636 {
637 HashTable *ht;
638 zval *ret = NULL;
639
640 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
641 zend_long ZEPHIR_LAST_CALL_STATUS;
642 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetset", NULL, 0, index, value);
643 if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
644 return SUCCESS;
645 }
646
647 return FAILURE;
648 } else if (Z_TYPE_P(arr) != IS_ARRAY) {
649 zend_error(E_WARNING, "Cannot use a scalar value as an array (2)");
650 return FAILURE;
651 }
652
653 if ((flags & PH_CTOR) == PH_CTOR) {
654 zval new_zv;
655 //Z_TRY_DELREF_P(value); //?
656 ZVAL_DUP(&new_zv, value);
657 value = &new_zv;
658 }
659
660 if ((flags & PH_SEPARATE) == PH_SEPARATE) {
661 SEPARATE_ZVAL_IF_NOT_REF(arr);
662 }
663
664 if ((flags & PH_COPY) == PH_COPY) {
665 Z_TRY_ADDREF_P(value);
666 }
667
668 ht = Z_ARRVAL_P(arr);
669
670 switch (Z_TYPE_P(index)) {
671 case IS_NULL:
672 ret = zend_symtable_str_update(ht, "", 1, value);
673 break;
674
675 case IS_DOUBLE:
676 ret = zend_hash_index_update(ht, (zend_ulong)Z_DVAL_P(index), value);
677 break;
678
679 case IS_LONG:
680 case IS_RESOURCE:
681 ret = zend_hash_index_update(ht, Z_LVAL_P(index), value);
682 break;
683
684 case IS_TRUE:
685 case IS_FALSE:
686 ret = zend_hash_index_update(ht, Z_TYPE_P(index) == IS_TRUE ? 1 : 0, value);
687 break;
688
689 case IS_STRING:
690 ret = zend_symtable_str_update(ht, Z_STRVAL_P(index), Z_STRLEN_P(index), value);
691 break;
692
693 default:
694 zend_error(E_WARNING, "Illegal offset type");
695 return FAILURE;
696 }
697
698 return ret != NULL ? FAILURE : SUCCESS;
699 }
700
zephir_array_update_string(zval * arr,const char * index,uint32_t index_length,zval * value,int flags)701 int zephir_array_update_string(zval *arr, const char *index, uint32_t index_length, zval *value, int flags)
702 {
703
704 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
705 zend_long ZEPHIR_LAST_CALL_STATUS;
706 zval offset;
707 ZVAL_STRINGL(&offset, index, index_length);
708 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetset", NULL, 0, &offset, value);
709 zval_ptr_dtor(&offset);
710 if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
711 return SUCCESS;
712 }
713
714 return FAILURE;
715 } else if (Z_TYPE_P(arr) != IS_ARRAY) {
716 zend_error(E_WARNING, "Cannot use a scalar value as an array (3)");
717 return FAILURE;
718 }
719
720 if ((flags & PH_CTOR) == PH_CTOR) {
721 zval new_value;
722
723 ZVAL_DUP(&new_value, value);
724 value = &new_value;
725 } else if ((flags & PH_COPY) == PH_COPY) {
726 Z_TRY_ADDREF_P(value);
727 }
728
729 if ((flags & PH_SEPARATE) == PH_SEPARATE) {
730 SEPARATE_ZVAL_IF_NOT_REF(arr);
731 }
732
733 return zend_hash_str_update(Z_ARRVAL_P(arr), index, index_length, value) ? SUCCESS : FAILURE;
734 }
735
zephir_array_update_long(zval * arr,unsigned long index,zval * value,int flags ZEPHIR_DEBUG_PARAMS)736 int zephir_array_update_long(zval *arr, unsigned long index, zval *value, int flags ZEPHIR_DEBUG_PARAMS)
737 {
738 if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
739 zend_long ZEPHIR_LAST_CALL_STATUS;
740 zval offset;
741 ZVAL_LONG(&offset, index);
742 ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetset", NULL, 0, &offset, value);
743 if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
744 return SUCCESS;
745 }
746
747 return FAILURE;
748 } else if (Z_TYPE_P(arr) != IS_ARRAY) {
749 zend_error(E_WARNING, "Cannot use a scalar value as an array in %s on line %d", file, line);
750 return FAILURE;
751 }
752
753 if ((flags & PH_CTOR) == PH_CTOR) {
754 zval new_value;
755
756 ZVAL_DUP(&new_value, value);
757 value = &new_value;
758 } else if ((flags & PH_COPY) == PH_COPY) {
759 Z_TRY_ADDREF_P(value);
760 }
761
762 if ((flags & PH_SEPARATE) == PH_SEPARATE) {
763 SEPARATE_ZVAL_IF_NOT_REF(arr);
764 }
765
766 return zend_hash_index_update(Z_ARRVAL_P(arr), index, value) ? SUCCESS : FAILURE;
767 }
768
zephir_array_keys(zval * return_value,zval * input)769 void zephir_array_keys(zval *return_value, zval *input)
770 {
771 zval *entry, new_val;
772 zend_ulong num_idx;
773 zend_string *str_idx;
774
775 if (EXPECTED(Z_TYPE_P(input) == IS_ARRAY)) {
776 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
777 zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
778 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
779 /* Go through input array and add keys to the return array */
780 ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
781 if (str_idx) {
782 ZVAL_STR_COPY(&new_val, str_idx);
783 } else {
784 ZVAL_LONG(&new_val, num_idx);
785 }
786 ZEND_HASH_FILL_ADD(&new_val);
787 } ZEND_HASH_FOREACH_END();
788 } ZEND_HASH_FILL_END();
789 }
790
791 entry = NULL;
792 str_idx = NULL;
793 num_idx = 0;
794 ZVAL_UNDEF(&new_val);
795 }
796
zephir_array_key_exists(zval * arr,zval * key)797 int zephir_array_key_exists(zval *arr, zval *key)
798 {
799 HashTable *h = Z_ARRVAL_P(arr);
800 if (h) {
801 switch (Z_TYPE_P(key)) {
802 case IS_STRING:
803 return zend_symtable_exists(h, Z_STR_P(key));
804
805 case IS_LONG:
806 return zend_hash_index_exists(h, Z_LVAL_P(key));
807
808 case IS_NULL:
809 return zend_hash_str_exists(h, "", 1);
810
811 default:
812 zend_error(E_WARNING, "The key should be either a string or an integer");
813 return 0;
814 }
815 }
816
817 return 0;
818 }
819
820 /**
821 * Implementation of Multiple array-offset update
822 */
zephir_array_update_multi_ex(zval * arr,zval * value,const char * types,int types_length,int types_count,va_list ap)823 void zephir_array_update_multi_ex(zval *arr, zval *value, const char *types, int types_length, int types_count, va_list ap)
824 {
825 char *s;
826 zval *item;
827 zval pzv;
828 zend_array *p;
829 int i, j, l, ll, re_update, must_continue, wrap_tmp;
830
831 ZVAL_UNDEF(&pzv);
832
833 if (Z_TYPE_P(arr) != IS_ARRAY) {
834 zend_error(E_ERROR, "Cannot use a scalar value as an array (multi)");
835 return;
836 }
837 p = Z_ARRVAL_P(arr);
838
839 for (i = 0; i < types_length; ++i) {
840 zval tmp;
841 zval fetched;
842 ZVAL_UNDEF(&fetched);
843
844 re_update = 0;
845 must_continue = 0;
846 wrap_tmp = 0;
847
848 ZVAL_ARR(&pzv, p);
849 switch (types[i]) {
850
851 case 's':
852 s = va_arg(ap, char*);
853 l = va_arg(ap, int);
854 if (zephir_array_isset_string_fetch(&fetched, &pzv, s, l, 1)) {
855 if (Z_TYPE(fetched) == IS_ARRAY) {
856 if (i == (types_length - 1)) {
857 re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
858 zephir_array_update_string(&pzv, s, l, value, PH_COPY | PH_SEPARATE);
859 p = Z_ARRVAL(pzv);
860 } else {
861 re_update = !Z_REFCOUNTED(fetched) || (Z_REFCOUNT(fetched) > 1 && !Z_ISREF(fetched));
862 if (re_update) {
863 ZVAL_DUP(&tmp, &fetched);
864 zephir_array_update_string(&pzv, s, l, &tmp, 0);
865 p = Z_ARRVAL(tmp);
866 } else {
867 p = Z_ARRVAL(fetched);
868 }
869 }
870 must_continue = 1;
871 }
872 }
873
874 if (!must_continue) {
875 ZVAL_ARR(&pzv, p);
876 re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
877 if (i == (types_length - 1)) {
878 zephir_array_update_string(&pzv, s, l, value, PH_COPY | PH_SEPARATE);
879 p = Z_ARRVAL(pzv);
880 } else {
881 array_init(&tmp);
882 zephir_array_update_string(&pzv, s, l, &tmp, PH_SEPARATE);
883 p = Z_ARRVAL(pzv);
884 if (re_update) {
885 wrap_tmp = 1;
886 } else {
887 p = Z_ARRVAL(tmp);
888 }
889 }
890 }
891 break;
892
893 case 'l':
894 ll = va_arg(ap, long);
895 if (zephir_array_isset_long_fetch(&fetched, &pzv, ll, 1)) {
896 if (Z_TYPE(fetched) == IS_ARRAY) {
897 if (i == (types_length - 1)) {
898 re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
899 zephir_array_update_long(&pzv, ll, value, PH_COPY | PH_SEPARATE ZEPHIR_DEBUG_PARAMS_DUMMY);
900 p = Z_ARRVAL(pzv);
901 } else {
902 re_update = !Z_REFCOUNTED(fetched) || (Z_REFCOUNT(fetched) > 1 && !Z_ISREF(fetched));
903 if (re_update) {
904 ZVAL_DUP(&tmp, &fetched);
905 zephir_array_update_long(&pzv, ll, &tmp, 0 ZEPHIR_DEBUG_PARAMS_DUMMY);
906 p = Z_ARRVAL(tmp);
907 } else {
908 p = Z_ARRVAL(fetched);
909 }
910 }
911 must_continue = 1;
912 }
913 }
914
915 if (!must_continue) {
916 ZVAL_ARR(&pzv, p);
917 re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
918 if (i == (types_length - 1)) {
919 zephir_array_update_long(&pzv, ll, value, PH_COPY | PH_SEPARATE ZEPHIR_DEBUG_PARAMS_DUMMY);
920 p = Z_ARRVAL(pzv);
921 } else {
922 array_init(&tmp);
923 zephir_array_update_long(&pzv, ll, &tmp, PH_SEPARATE ZEPHIR_DEBUG_PARAMS_DUMMY);
924 p = Z_ARRVAL(pzv);
925 if (re_update) {
926 wrap_tmp = 1;
927 } else {
928 p = Z_ARRVAL(tmp);
929 }
930 }
931 }
932 break;
933
934 case 'z':
935 item = va_arg(ap, zval*);
936 if (zephir_array_isset_fetch(&fetched, &pzv, item, 1)) {
937 if (Z_TYPE(fetched) == IS_ARRAY) {
938 if (i == (types_length - 1)) {
939 re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
940 zephir_array_update_zval(&pzv, item, value, PH_COPY | PH_SEPARATE);
941 p = Z_ARRVAL(pzv);
942 } else {
943 re_update = !Z_REFCOUNTED(fetched) || (Z_REFCOUNT(fetched) > 1 && !Z_ISREF(fetched));
944 if (re_update) {
945 ZVAL_DUP(&tmp, &fetched);
946 zephir_array_update_zval(&pzv, item, &tmp, 0);
947 p = Z_ARRVAL(tmp);
948 } else {
949 p = Z_ARRVAL(fetched);
950 }
951 }
952 must_continue = 1;
953 }
954 }
955
956 if (!must_continue) {
957 ZVAL_ARR(&pzv, p);
958 re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
959 if (i == (types_length - 1)) {
960 zephir_array_update_zval(&pzv, item, value, PH_COPY | PH_SEPARATE);
961 p = Z_ARRVAL(pzv);
962 } else {
963 array_init(&tmp);
964 zephir_array_update_zval(&pzv, item, &tmp, PH_SEPARATE);
965 p = Z_ARRVAL(pzv);
966 if (re_update) {
967 wrap_tmp = 1;
968 } else {
969 p = Z_ARRVAL(tmp);
970 }
971 }
972 }
973 break;
974
975 case 'a':
976 re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
977 if (re_update) {
978 zephir_array_append(&pzv, value, PH_COPY | PH_SEPARATE ZEPHIR_DEBUG_PARAMS_DUMMY);
979 } else {
980 zephir_array_append(&pzv, value, PH_COPY ZEPHIR_DEBUG_PARAMS_DUMMY);
981 }
982
983 p = Z_ARRVAL(pzv);
984 break;
985 }
986 }
987 }
988
zephir_array_update_multi(zval * arr,zval * value,const char * types,int types_length,int types_count,...)989 int zephir_array_update_multi(zval *arr, zval *value, const char *types, int types_length, int types_count, ...)
990 {
991 va_list ap;
992 va_start(ap, types_count);
993 SEPARATE_ZVAL_IF_NOT_REF(arr);
994
995 zephir_array_update_multi_ex(arr, value, types, types_length, types_count, ap);
996 va_end(ap);
997
998 return 0;
999 }
1000
1001 /**
1002 * Fast in_array function
1003 */
zephir_fast_in_array(zval * value,zval * haystack)1004 int zephir_fast_in_array(zval *value, zval *haystack)
1005 {
1006 zval *entry;
1007 zend_ulong num_idx;
1008 zend_string *str_idx;
1009
1010 if (Z_TYPE_P(haystack) != IS_ARRAY) {
1011 return 0;
1012 }
1013
1014 if (Z_TYPE_P(value) == IS_STRING) {
1015 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(haystack), num_idx, str_idx, entry) {
1016 if (fast_equal_check_string(value, entry)) {
1017 return 1;
1018 }
1019 } ZEND_HASH_FOREACH_END();
1020 } else {
1021 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(haystack), num_idx, str_idx, entry) {
1022 if (fast_equal_check_function(value, entry)) {
1023 return 1;
1024 }
1025 } ZEND_HASH_FOREACH_END();
1026 }
1027
1028 return 0;
1029 }
1030
1031 /**
1032 * Fast array merge
1033 */
zephir_fast_array_merge(zval * return_value,zval * array1,zval * array2)1034 void zephir_fast_array_merge(zval *return_value, zval *array1, zval *array2)
1035 {
1036 int init_size, num;
1037
1038 if (Z_TYPE_P(array1) != IS_ARRAY) {
1039 zend_error(E_WARNING, "First argument is not an array");
1040 RETURN_NULL();
1041 }
1042
1043 if (Z_TYPE_P(array2) != IS_ARRAY) {
1044 zend_error(E_WARNING, "Second argument is not an array");
1045 RETURN_NULL();
1046 }
1047
1048 init_size = zend_hash_num_elements(Z_ARRVAL_P(array1));
1049 num = zend_hash_num_elements(Z_ARRVAL_P(array2));
1050 if (num > init_size) {
1051 init_size = num;
1052 }
1053
1054 array_init_size(return_value, init_size);
1055
1056 php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(array1));
1057
1058 php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(array2));
1059 }
1060