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