1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
17 | Andrei Zmievski <andrei@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 /* $Id$ */
22
23 #include "zend.h"
24 #include "zend_execute.h"
25 #include "zend_API.h"
26 #include "zend_modules.h"
27 #include "zend_constants.h"
28 #include "zend_exceptions.h"
29 #include "zend_closures.h"
30
31 #ifdef HAVE_STDARG_H
32 #include <stdarg.h>
33 #endif
34
35 /* these variables are true statics/globals, and have to be mutex'ed on every access */
36 ZEND_API HashTable module_registry;
37
38 /* this function doesn't check for too many parameters */
zend_get_parameters(int ht,int param_count,...)39 ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */
40 {
41 void **p;
42 int arg_count;
43 va_list ptr;
44 zval **param, *param_ptr;
45 TSRMLS_FETCH();
46
47 p = zend_vm_stack_top(TSRMLS_C) - 1;
48 arg_count = (int)(zend_uintptr_t) *p;
49
50 if (param_count>arg_count) {
51 return FAILURE;
52 }
53
54 va_start(ptr, param_count);
55
56 while (param_count-->0) {
57 param = va_arg(ptr, zval **);
58 param_ptr = *(p-arg_count);
59 if (!PZVAL_IS_REF(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) {
60 zval *new_tmp;
61
62 ALLOC_ZVAL(new_tmp);
63 *new_tmp = *param_ptr;
64 zval_copy_ctor(new_tmp);
65 INIT_PZVAL(new_tmp);
66 param_ptr = new_tmp;
67 Z_DELREF_P((zval *) *(p-arg_count));
68 *(p-arg_count) = param_ptr;
69 }
70 *param = param_ptr;
71 arg_count--;
72 }
73 va_end(ptr);
74
75 return SUCCESS;
76 }
77 /* }}} */
78
_zend_get_parameters_array(int ht,int param_count,zval ** argument_array TSRMLS_DC)79 ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval **argument_array TSRMLS_DC) /* {{{ */
80 {
81 void **p;
82 int arg_count;
83 zval *param_ptr;
84
85 p = zend_vm_stack_top(TSRMLS_C) - 1;
86 arg_count = (int)(zend_uintptr_t) *p;
87
88 if (param_count>arg_count) {
89 return FAILURE;
90 }
91
92 while (param_count-->0) {
93 param_ptr = *(p-arg_count);
94 if (!PZVAL_IS_REF(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) {
95 zval *new_tmp;
96
97 ALLOC_ZVAL(new_tmp);
98 *new_tmp = *param_ptr;
99 zval_copy_ctor(new_tmp);
100 INIT_PZVAL(new_tmp);
101 param_ptr = new_tmp;
102 Z_DELREF_P((zval *) *(p-arg_count));
103 *(p-arg_count) = param_ptr;
104 }
105 *(argument_array++) = param_ptr;
106 arg_count--;
107 }
108
109 return SUCCESS;
110 }
111 /* }}} */
112
113 /* Zend-optimized Extended functions */
114 /* this function doesn't check for too many parameters */
zend_get_parameters_ex(int param_count,...)115 ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */
116 {
117 void **p;
118 int arg_count;
119 va_list ptr;
120 zval ***param;
121 TSRMLS_FETCH();
122
123 p = zend_vm_stack_top(TSRMLS_C) - 1;
124 arg_count = (int)(zend_uintptr_t) *p;
125
126 if (param_count>arg_count) {
127 return FAILURE;
128 }
129
130 va_start(ptr, param_count);
131 while (param_count-->0) {
132 param = va_arg(ptr, zval ***);
133 *param = (zval **) p-(arg_count--);
134 }
135 va_end(ptr);
136
137 return SUCCESS;
138 }
139 /* }}} */
140
_zend_get_parameters_array_ex(int param_count,zval *** argument_array TSRMLS_DC)141 ZEND_API int _zend_get_parameters_array_ex(int param_count, zval ***argument_array TSRMLS_DC) /* {{{ */
142 {
143 void **p;
144 int arg_count;
145
146 p = zend_vm_stack_top(TSRMLS_C) - 1;
147 arg_count = (int)(zend_uintptr_t) *p;
148
149 if (param_count>arg_count) {
150 return FAILURE;
151 }
152
153 while (param_count-->0) {
154 zval **value = (zval**)(p-arg_count);
155
156 *(argument_array++) = value;
157 arg_count--;
158 }
159
160 return SUCCESS;
161 }
162 /* }}} */
163
zend_copy_parameters_array(int param_count,zval * argument_array TSRMLS_DC)164 ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */
165 {
166 void **p;
167 int arg_count;
168
169 p = zend_vm_stack_top(TSRMLS_C) - 1;
170 arg_count = (int)(zend_uintptr_t) *p;
171
172 if (param_count>arg_count) {
173 return FAILURE;
174 }
175
176 while (param_count-->0) {
177 zval **param = (zval **) p-(arg_count--);
178 zval_add_ref(param);
179 add_next_index_zval(argument_array, *param);
180 }
181
182 return SUCCESS;
183 }
184 /* }}} */
185
zend_wrong_param_count(TSRMLS_D)186 ZEND_API void zend_wrong_param_count(TSRMLS_D) /* {{{ */
187 {
188 char *space;
189 char *class_name = get_active_class_name(&space TSRMLS_CC);
190
191 zend_error(E_WARNING, "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name(TSRMLS_C));
192 }
193 /* }}} */
194
195 /* Argument parsing API -- andrei */
zend_get_type_by_const(int type)196 ZEND_API char *zend_get_type_by_const(int type) /* {{{ */
197 {
198 switch(type) {
199 case IS_BOOL:
200 return "boolean";
201 case IS_LONG:
202 return "integer";
203 case IS_DOUBLE:
204 return "double";
205 case IS_STRING:
206 return "string";
207 case IS_OBJECT:
208 return "object";
209 case IS_RESOURCE:
210 return "resource";
211 case IS_NULL:
212 return "null";
213 case IS_ARRAY:
214 return "array";
215 default:
216 return "unknown";
217 }
218 }
219 /* }}} */
220
zend_zval_type_name(const zval * arg)221 ZEND_API char *zend_zval_type_name(const zval *arg) /* {{{ */
222 {
223 return zend_get_type_by_const(Z_TYPE_P(arg));
224 }
225 /* }}} */
226
zend_get_class_entry(const zval * zobject TSRMLS_DC)227 ZEND_API zend_class_entry *zend_get_class_entry(const zval *zobject TSRMLS_DC) /* {{{ */
228 {
229 if (Z_OBJ_HT_P(zobject)->get_class_entry) {
230 return Z_OBJ_HT_P(zobject)->get_class_entry(zobject TSRMLS_CC);
231 } else {
232 zend_error(E_ERROR, "Class entry requested for an object without PHP class");
233 return NULL;
234 }
235 }
236 /* }}} */
237
238 /* returns 1 if you need to copy result, 0 if it's already a copy */
zend_get_object_classname(const zval * object,char ** class_name,zend_uint * class_name_len TSRMLS_DC)239 ZEND_API int zend_get_object_classname(const zval *object, char **class_name, zend_uint *class_name_len TSRMLS_DC) /* {{{ */
240 {
241 if (Z_OBJ_HT_P(object)->get_class_name == NULL ||
242 Z_OBJ_HT_P(object)->get_class_name(object, class_name, class_name_len, 0 TSRMLS_CC) != SUCCESS) {
243 zend_class_entry *ce = Z_OBJCE_P(object);
244
245 *class_name = ce->name;
246 *class_name_len = ce->name_length;
247 return 1;
248 }
249 return 0;
250 }
251 /* }}} */
252
parse_arg_object_to_string(zval ** arg TSRMLS_DC)253 static int parse_arg_object_to_string(zval **arg TSRMLS_DC) /* {{{ */
254 {
255 if (Z_OBJ_HANDLER_PP(arg, cast_object)) {
256 zval *obj;
257 MAKE_STD_ZVAL(obj);
258 if (Z_OBJ_HANDLER_P(*arg, cast_object)(*arg, obj, IS_STRING TSRMLS_CC) == SUCCESS) {
259 zval_ptr_dtor(arg);
260 *arg = obj;
261 return SUCCESS;
262 }
263 efree(obj);
264 }
265 /* Standard PHP objects */
266 if (Z_OBJ_HT_PP(arg) == &std_object_handlers || !Z_OBJ_HANDLER_PP(arg, cast_object)) {
267 SEPARATE_ZVAL_IF_NOT_REF(arg);
268 if (zend_std_cast_object_tostring(*arg, *arg, IS_STRING TSRMLS_CC) == SUCCESS) {
269 return SUCCESS;
270 }
271 }
272 if (!Z_OBJ_HANDLER_PP(arg, cast_object) && Z_OBJ_HANDLER_PP(arg, get)) {
273 int use_copy;
274 zval *z = Z_OBJ_HANDLER_PP(arg, get)(*arg TSRMLS_CC);
275 Z_ADDREF_P(z);
276 if(Z_TYPE_P(z) != IS_OBJECT) {
277 zval_dtor(*arg);
278 Z_TYPE_P(*arg) = IS_NULL;
279 zend_make_printable_zval(z, *arg, &use_copy);
280 if (!use_copy) {
281 ZVAL_ZVAL(*arg, z, 1, 1);
282 }
283 return SUCCESS;
284 }
285 zval_ptr_dtor(&z);
286 }
287 return FAILURE;
288 }
289 /* }}} */
290
zend_parse_arg_impl(int arg_num,zval ** arg,va_list * va,char ** spec,char ** error,int * severity TSRMLS_DC)291 static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **spec, char **error, int *severity TSRMLS_DC) /* {{{ */
292 {
293 char *spec_walk = *spec;
294 char c = *spec_walk++;
295 int return_null = 0;
296
297 /* scan through modifiers */
298 while (1) {
299 if (*spec_walk == '/') {
300 SEPARATE_ZVAL_IF_NOT_REF(arg);
301 } else if (*spec_walk == '!') {
302 if (Z_TYPE_PP(arg) == IS_NULL) {
303 return_null = 1;
304 }
305 } else {
306 break;
307 }
308 spec_walk++;
309 }
310
311 switch (c) {
312 case 'l':
313 case 'L':
314 {
315 long *p = va_arg(*va, long *);
316 switch (Z_TYPE_PP(arg)) {
317 case IS_STRING:
318 {
319 double d;
320 int type;
321
322 if ((type = is_numeric_string(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), p, &d, -1)) == 0) {
323 return "long";
324 } else if (type == IS_DOUBLE) {
325 if (c == 'L') {
326 if (d > LONG_MAX) {
327 *p = LONG_MAX;
328 break;
329 } else if (d < LONG_MIN) {
330 *p = LONG_MIN;
331 break;
332 }
333 }
334
335 *p = zend_dval_to_lval(d);
336 }
337 }
338 break;
339
340 case IS_DOUBLE:
341 if (c == 'L') {
342 if (Z_DVAL_PP(arg) > LONG_MAX) {
343 *p = LONG_MAX;
344 break;
345 } else if (Z_DVAL_PP(arg) < LONG_MIN) {
346 *p = LONG_MIN;
347 break;
348 }
349 }
350 case IS_NULL:
351 case IS_LONG:
352 case IS_BOOL:
353 convert_to_long_ex(arg);
354 *p = Z_LVAL_PP(arg);
355 break;
356
357 case IS_ARRAY:
358 case IS_OBJECT:
359 case IS_RESOURCE:
360 default:
361 return "long";
362 }
363 }
364 break;
365
366 case 'd':
367 {
368 double *p = va_arg(*va, double *);
369 switch (Z_TYPE_PP(arg)) {
370 case IS_STRING:
371 {
372 long l;
373 int type;
374
375 if ((type = is_numeric_string(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), &l, p, -1)) == 0) {
376 return "double";
377 } else if (type == IS_LONG) {
378 *p = (double) l;
379 }
380 }
381 break;
382
383 case IS_NULL:
384 case IS_LONG:
385 case IS_DOUBLE:
386 case IS_BOOL:
387 convert_to_double_ex(arg);
388 *p = Z_DVAL_PP(arg);
389 break;
390
391 case IS_ARRAY:
392 case IS_OBJECT:
393 case IS_RESOURCE:
394 default:
395 return "double";
396 }
397 }
398 break;
399
400 case 's':
401 {
402 char **p = va_arg(*va, char **);
403 int *pl = va_arg(*va, int *);
404 switch (Z_TYPE_PP(arg)) {
405 case IS_NULL:
406 if (return_null) {
407 *p = NULL;
408 *pl = 0;
409 break;
410 }
411 /* break omitted intentionally */
412
413 case IS_STRING:
414 case IS_LONG:
415 case IS_DOUBLE:
416 case IS_BOOL:
417 convert_to_string_ex(arg);
418 if (UNEXPECTED(Z_ISREF_PP(arg) != 0)) {
419 /* it's dangerous to return pointers to string
420 buffer of referenced variable, because it can
421 be clobbered throug magic callbacks */
422 SEPARATE_ZVAL(arg);
423 }
424 *p = Z_STRVAL_PP(arg);
425 *pl = Z_STRLEN_PP(arg);
426 break;
427
428 case IS_OBJECT:
429 case IS_ARRAY:
430 case IS_RESOURCE:
431 default:
432 return "string";
433 }
434 }
435 break;
436
437 case 'b':
438 {
439 zend_bool *p = va_arg(*va, zend_bool *);
440 switch (Z_TYPE_PP(arg)) {
441 case IS_NULL:
442 case IS_STRING:
443 case IS_LONG:
444 case IS_DOUBLE:
445 case IS_BOOL:
446 convert_to_boolean_ex(arg);
447 *p = Z_BVAL_PP(arg);
448 break;
449
450 case IS_ARRAY:
451 case IS_OBJECT:
452 case IS_RESOURCE:
453 default:
454 return "boolean";
455 }
456 }
457 break;
458
459 case 'r':
460 {
461 zval **p = va_arg(*va, zval **);
462 if (return_null) {
463 *p = NULL;
464 break;
465 }
466 if (Z_TYPE_PP(arg) == IS_RESOURCE) {
467 *p = *arg;
468 } else {
469 return "resource";
470 }
471 }
472 break;
473 case 'A':
474 case 'a':
475 {
476 zval **p = va_arg(*va, zval **);
477 if (return_null) {
478 *p = NULL;
479 break;
480 }
481 if (Z_TYPE_PP(arg) == IS_ARRAY || (c == 'A' && Z_TYPE_PP(arg) == IS_OBJECT)) {
482 *p = *arg;
483 } else {
484 return "array";
485 }
486 }
487 break;
488 case 'H':
489 case 'h':
490 {
491 HashTable **p = va_arg(*va, HashTable **);
492 if (return_null) {
493 *p = NULL;
494 break;
495 }
496 if (Z_TYPE_PP(arg) == IS_ARRAY) {
497 *p = Z_ARRVAL_PP(arg);
498 } else if(c == 'H' && Z_TYPE_PP(arg) == IS_OBJECT) {
499 *p = HASH_OF(*arg);
500 if(*p == NULL) {
501 return "array";
502 }
503 } else {
504 return "array";
505 }
506 }
507 break;
508
509 case 'o':
510 {
511 zval **p = va_arg(*va, zval **);
512 if (return_null) {
513 *p = NULL;
514 break;
515 }
516 if (Z_TYPE_PP(arg) == IS_OBJECT) {
517 *p = *arg;
518 } else {
519 return "object";
520 }
521 }
522 break;
523
524 case 'O':
525 {
526 zval **p = va_arg(*va, zval **);
527 zend_class_entry *ce = va_arg(*va, zend_class_entry *);
528
529 if (return_null) {
530 *p = NULL;
531 break;
532 }
533 if (Z_TYPE_PP(arg) == IS_OBJECT &&
534 (!ce || instanceof_function(Z_OBJCE_PP(arg), ce TSRMLS_CC))) {
535 *p = *arg;
536 } else {
537 if (ce) {
538 return ce->name;
539 } else {
540 return "object";
541 }
542 }
543 }
544 break;
545
546 case 'C':
547 {
548 zend_class_entry **lookup, **pce = va_arg(*va, zend_class_entry **);
549 zend_class_entry *ce_base = *pce;
550
551 if (return_null) {
552 *pce = NULL;
553 break;
554 }
555 convert_to_string_ex(arg);
556 if (zend_lookup_class(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), &lookup TSRMLS_CC) == FAILURE) {
557 *pce = NULL;
558 } else {
559 *pce = *lookup;
560 }
561 if (ce_base) {
562 if ((!*pce || !instanceof_function(*pce, ce_base TSRMLS_CC))) {
563 zend_spprintf(error, 0, "to be a class name derived from %s, '%s' given",
564 ce_base->name, Z_STRVAL_PP(arg));
565 *pce = NULL;
566 return "";
567 }
568 }
569 if (!*pce) {
570 zend_spprintf(error, 0, "to be a valid class name, '%s' given",
571 Z_STRVAL_PP(arg));
572 return "";
573 }
574 break;
575
576 }
577 break;
578
579 case 'f':
580 {
581 zend_fcall_info *fci = va_arg(*va, zend_fcall_info *);
582 zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *);
583 char *is_callable_error = NULL;
584
585 if (return_null) {
586 fci->size = 0;
587 fcc->initialized = 0;
588 break;
589 }
590
591 if (zend_fcall_info_init(*arg, 0, fci, fcc, NULL, &is_callable_error TSRMLS_CC) == SUCCESS) {
592 if (is_callable_error) {
593 *severity = E_STRICT;
594 zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error);
595 efree(is_callable_error);
596 *spec = spec_walk;
597 return "";
598 }
599 break;
600 } else {
601 if (is_callable_error) {
602 *severity = E_WARNING;
603 zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error);
604 efree(is_callable_error);
605 return "";
606 } else {
607 return "valid callback";
608 }
609 }
610 }
611
612 case 'z':
613 {
614 zval **p = va_arg(*va, zval **);
615 if (return_null) {
616 *p = NULL;
617 } else {
618 *p = *arg;
619 }
620 }
621 break;
622
623 case 'Z':
624 {
625 zval ***p = va_arg(*va, zval ***);
626 if (return_null) {
627 *p = NULL;
628 } else {
629 *p = arg;
630 }
631 }
632 break;
633
634 default:
635 return "unknown";
636 }
637
638 *spec = spec_walk;
639
640 return NULL;
641 }
642 /* }}} */
643
zend_parse_arg(int arg_num,zval ** arg,va_list * va,char ** spec,int quiet TSRMLS_DC)644 static int zend_parse_arg(int arg_num, zval **arg, va_list *va, char **spec, int quiet TSRMLS_DC) /* {{{ */
645 {
646 char *expected_type = NULL, *error = NULL;
647 int severity = E_WARNING;
648
649 expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, &error, &severity TSRMLS_CC);
650 if (expected_type) {
651 if (!quiet && (*expected_type || error)) {
652 char *space;
653 char *class_name = get_active_class_name(&space TSRMLS_CC);
654
655 if (error) {
656 zend_error(severity, "%s%s%s() expects parameter %d %s",
657 class_name, space, get_active_function_name(TSRMLS_C), arg_num, error);
658 efree(error);
659 } else {
660 zend_error(severity, "%s%s%s() expects parameter %d to be %s, %s given",
661 class_name, space, get_active_function_name(TSRMLS_C), arg_num, expected_type,
662 zend_zval_type_name(*arg));
663 }
664 }
665 if (severity != E_STRICT) {
666 return FAILURE;
667 }
668 }
669
670 return SUCCESS;
671 }
672 /* }}} */
673
zend_parse_va_args(int num_args,char * type_spec,va_list * va,int flags TSRMLS_DC)674 static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int flags TSRMLS_DC) /* {{{ */
675 {
676 char *spec_walk;
677 int c, i;
678 int min_num_args = -1;
679 int max_num_args = 0;
680 int post_varargs = 0;
681 zval **arg;
682 int arg_count = (int)(zend_uintptr_t) *(zend_vm_stack_top(TSRMLS_C) - 1);
683 int quiet = flags & ZEND_PARSE_PARAMS_QUIET;
684 zend_bool have_varargs = 0;
685 zval ****varargs = NULL;
686 int *n_varargs = NULL;
687
688 for (spec_walk = type_spec; *spec_walk; spec_walk++) {
689 c = *spec_walk;
690 switch (c) {
691 case 's':
692 if (max_num_args < arg_count) {
693 arg = (zval **) (zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count - max_num_args));
694 if (Z_TYPE_PP(arg) == IS_OBJECT) {
695 parse_arg_object_to_string(arg TSRMLS_CC);
696 }
697 }
698 /* break missing intentionally */
699 case 'l': case 'd':
700 case 'H': case 'b':
701 case 'r': case 'a':
702 case 'o': case 'O':
703 case 'z': case 'Z':
704 case 'C': case 'h':
705 case 'f': case 'A':
706 max_num_args++;
707 break;
708
709 case '|':
710 min_num_args = max_num_args;
711 break;
712
713 case '/':
714 case '!':
715 /* Pass */
716 break;
717
718 case '*':
719 case '+':
720 if (have_varargs) {
721 if (!quiet) {
722 zend_function *active_function = EG(current_execute_data)->function_state.function;
723 char *class_name = active_function->common.scope ? active_function->common.scope->name : "";
724 zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted",
725 class_name,
726 class_name[0] ? "::" : "",
727 active_function->common.function_name);
728 }
729 return FAILURE;
730 }
731 have_varargs = 1;
732 /* we expect at least one parameter in varargs */
733 if (c == '+') {
734 max_num_args++;
735 }
736 /* mark the beginning of varargs */
737 post_varargs = max_num_args;
738 break;
739
740 default:
741 if (!quiet) {
742 zend_function *active_function = EG(current_execute_data)->function_state.function;
743 char *class_name = active_function->common.scope ? active_function->common.scope->name : "";
744 zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters",
745 class_name,
746 class_name[0] ? "::" : "",
747 active_function->common.function_name);
748 }
749 return FAILURE;
750 }
751 }
752
753 if (min_num_args < 0) {
754 min_num_args = max_num_args;
755 }
756
757 if (have_varargs) {
758 /* calculate how many required args are at the end of the specifier list */
759 post_varargs = max_num_args - post_varargs;
760 max_num_args = -1;
761 }
762
763 if (num_args < min_num_args || (num_args > max_num_args && max_num_args > 0)) {
764 if (!quiet) {
765 zend_function *active_function = EG(current_execute_data)->function_state.function;
766 char *class_name = active_function->common.scope ? active_function->common.scope->name : "";
767 zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given",
768 class_name,
769 class_name[0] ? "::" : "",
770 active_function->common.function_name,
771 min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most",
772 num_args < min_num_args ? min_num_args : max_num_args,
773 (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
774 num_args);
775 }
776 return FAILURE;
777 }
778
779 if (num_args > arg_count) {
780 zend_error(E_WARNING, "%s(): could not obtain parameters for parsing",
781 get_active_function_name(TSRMLS_C));
782 return FAILURE;
783 }
784
785 i = 0;
786 while (num_args-- > 0) {
787 if (*type_spec == '|') {
788 type_spec++;
789 }
790
791 if (*type_spec == '*' || *type_spec == '+') {
792 int num_varargs = num_args + 1 - post_varargs;
793
794 /* eat up the passed in storage even if it won't be filled in with varargs */
795 varargs = va_arg(*va, zval ****);
796 n_varargs = va_arg(*va, int *);
797 type_spec++;
798
799 if (num_varargs > 0) {
800 int iv = 0;
801 zval **p = (zval **) (zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count - i));
802
803 *n_varargs = num_varargs;
804
805 /* allocate space for array and store args */
806 *varargs = safe_emalloc(num_varargs, sizeof(zval **), 0);
807 while (num_varargs-- > 0) {
808 (*varargs)[iv++] = p++;
809 }
810
811 /* adjust how many args we have left and restart loop */
812 num_args = num_args + 1 - iv;
813 i += iv;
814 continue;
815 } else {
816 *varargs = NULL;
817 *n_varargs = 0;
818 }
819 }
820
821 arg = (zval **) (zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count-i));
822
823 if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) {
824 /* clean up varargs array if it was used */
825 if (varargs && *varargs) {
826 efree(*varargs);
827 *varargs = NULL;
828 }
829 return FAILURE;
830 }
831 i++;
832 }
833
834 return SUCCESS;
835 }
836 /* }}} */
837
838 #define RETURN_IF_ZERO_ARGS(num_args, type_spec, quiet) { \
839 int __num_args = (num_args); \
840 \
841 if (0 == (type_spec)[0] && 0 != __num_args && !(quiet)) { \
842 char *__space; \
843 char * __class_name = get_active_class_name(&__space TSRMLS_CC); \
844 zend_error(E_WARNING, "%s%s%s() expects exactly 0 parameters, %d given", \
845 __class_name, __space, \
846 get_active_function_name(TSRMLS_C), __num_args); \
847 return FAILURE; \
848 }\
849 }
850
zend_parse_parameters_ex(int flags,int num_args TSRMLS_DC,char * type_spec,...)851 ZEND_API int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...) /* {{{ */
852 {
853 va_list va;
854 int retval;
855
856 RETURN_IF_ZERO_ARGS(num_args, type_spec, flags & ZEND_PARSE_PARAMS_QUIET);
857
858 va_start(va, type_spec);
859 retval = zend_parse_va_args(num_args, type_spec, &va, flags TSRMLS_CC);
860 va_end(va);
861
862 return retval;
863 }
864 /* }}} */
865
zend_parse_parameters(int num_args TSRMLS_DC,char * type_spec,...)866 ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...) /* {{{ */
867 {
868 va_list va;
869 int retval;
870
871 RETURN_IF_ZERO_ARGS(num_args, type_spec, 0);
872
873 va_start(va, type_spec);
874 retval = zend_parse_va_args(num_args, type_spec, &va, 0 TSRMLS_CC);
875 va_end(va);
876
877 return retval;
878 }
879 /* }}} */
880
zend_parse_method_parameters(int num_args TSRMLS_DC,zval * this_ptr,char * type_spec,...)881 ZEND_API int zend_parse_method_parameters(int num_args TSRMLS_DC, zval *this_ptr, char *type_spec, ...) /* {{{ */
882 {
883 va_list va;
884 int retval;
885 char *p = type_spec;
886 zval **object;
887 zend_class_entry *ce;
888
889 if (!this_ptr) {
890 RETURN_IF_ZERO_ARGS(num_args, p, 0);
891
892 va_start(va, type_spec);
893 retval = zend_parse_va_args(num_args, type_spec, &va, 0 TSRMLS_CC);
894 va_end(va);
895 } else {
896 p++;
897 RETURN_IF_ZERO_ARGS(num_args, p, 0);
898
899 va_start(va, type_spec);
900
901 object = va_arg(va, zval **);
902 ce = va_arg(va, zend_class_entry *);
903 *object = this_ptr;
904
905 if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce TSRMLS_CC)) {
906 zend_error(E_CORE_ERROR, "%s::%s() must be derived from %s::%s",
907 ce->name, get_active_function_name(TSRMLS_C), Z_OBJCE_P(this_ptr)->name, get_active_function_name(TSRMLS_C));
908 }
909
910 retval = zend_parse_va_args(num_args, p, &va, 0 TSRMLS_CC);
911 va_end(va);
912 }
913 return retval;
914 }
915 /* }}} */
916
zend_parse_method_parameters_ex(int flags,int num_args TSRMLS_DC,zval * this_ptr,char * type_spec,...)917 ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args TSRMLS_DC, zval *this_ptr, char *type_spec, ...) /* {{{ */
918 {
919 va_list va;
920 int retval;
921 char *p = type_spec;
922 zval **object;
923 zend_class_entry *ce;
924 int quiet = flags & ZEND_PARSE_PARAMS_QUIET;
925
926 if (!this_ptr) {
927 RETURN_IF_ZERO_ARGS(num_args, p, quiet);
928
929 va_start(va, type_spec);
930 retval = zend_parse_va_args(num_args, type_spec, &va, flags TSRMLS_CC);
931 va_end(va);
932 } else {
933 p++;
934 RETURN_IF_ZERO_ARGS(num_args, p, quiet);
935
936 va_start(va, type_spec);
937
938 object = va_arg(va, zval **);
939 ce = va_arg(va, zend_class_entry *);
940 *object = this_ptr;
941
942 if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce TSRMLS_CC)) {
943 if (!quiet) {
944 zend_error(E_CORE_ERROR, "%s::%s() must be derived from %s::%s",
945 ce->name, get_active_function_name(TSRMLS_C), Z_OBJCE_P(this_ptr)->name, get_active_function_name(TSRMLS_C));
946 }
947 va_end(va);
948 return FAILURE;
949 }
950
951 retval = zend_parse_va_args(num_args, p, &va, flags TSRMLS_CC);
952 va_end(va);
953 }
954 return retval;
955 }
956 /* }}} */
957
958 /* Argument parsing API -- andrei */
_array_init(zval * arg,uint size ZEND_FILE_LINE_DC)959 ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC) /* {{{ */
960 {
961 ALLOC_HASHTABLE_REL(Z_ARRVAL_P(arg));
962
963 _zend_hash_init(Z_ARRVAL_P(arg), size, NULL, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC);
964 Z_TYPE_P(arg) = IS_ARRAY;
965 return SUCCESS;
966 }
967 /* }}} */
968
zend_merge_property(zval ** value TSRMLS_DC,int num_args,va_list args,const zend_hash_key * hash_key)969 static int zend_merge_property(zval **value TSRMLS_DC, int num_args, va_list args, const zend_hash_key *hash_key) /* {{{ */
970 {
971 /* which name should a numeric property have ? */
972 if (hash_key->nKeyLength) {
973 zval *obj = va_arg(args, zval *);
974 zend_object_handlers *obj_ht = va_arg(args, zend_object_handlers *);
975 zval *member;
976
977 MAKE_STD_ZVAL(member);
978 ZVAL_STRINGL(member, hash_key->arKey, hash_key->nKeyLength-1, 1);
979 obj_ht->write_property(obj, member, *value TSRMLS_CC);
980 zval_ptr_dtor(&member);
981 }
982 return ZEND_HASH_APPLY_KEEP;
983 }
984 /* }}} */
985
986 /* This function should be called after the constructor has been called
987 * because it may call __set from the uninitialized object otherwise. */
zend_merge_properties(zval * obj,HashTable * properties,int destroy_ht TSRMLS_DC)988 ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destroy_ht TSRMLS_DC) /* {{{ */
989 {
990 zend_object_handlers *obj_ht = Z_OBJ_HT_P(obj);
991 zend_class_entry *old_scope = EG(scope);
992
993 EG(scope) = Z_OBJCE_P(obj);
994 zend_hash_apply_with_arguments(properties TSRMLS_CC, (apply_func_args_t)zend_merge_property, 2, obj, obj_ht);
995 EG(scope) = old_scope;
996
997 if (destroy_ht) {
998 zend_hash_destroy(properties);
999 FREE_HASHTABLE(properties);
1000 }
1001 }
1002 /* }}} */
1003
zend_update_class_constants(zend_class_entry * class_type TSRMLS_DC)1004 ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
1005 {
1006 if (!class_type->constants_updated || !CE_STATIC_MEMBERS(class_type)) {
1007 zend_class_entry **scope = EG(in_execution)?&EG(scope):&CG(active_class_entry);
1008 zend_class_entry *old_scope = *scope;
1009
1010 *scope = class_type;
1011 zend_hash_apply_with_argument(&class_type->constants_table, (apply_func_arg_t) zval_update_constant, (void*)1 TSRMLS_CC);
1012 zend_hash_apply_with_argument(&class_type->default_properties, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC);
1013
1014 if (!CE_STATIC_MEMBERS(class_type)) {
1015 HashPosition pos;
1016 zval **p;
1017
1018 if (class_type->parent) {
1019 zend_update_class_constants(class_type->parent TSRMLS_CC);
1020 }
1021 #if ZTS
1022 ALLOC_HASHTABLE(CG(static_members)[(zend_intptr_t)(class_type->static_members)]);
1023 #else
1024 ALLOC_HASHTABLE(class_type->static_members);
1025 #endif
1026 zend_hash_init(CE_STATIC_MEMBERS(class_type), zend_hash_num_elements(&class_type->default_static_members), NULL, ZVAL_PTR_DTOR, 0);
1027
1028 zend_hash_internal_pointer_reset_ex(&class_type->default_static_members, &pos);
1029 while (zend_hash_get_current_data_ex(&class_type->default_static_members, (void**)&p, &pos) == SUCCESS) {
1030 char *str_index;
1031 uint str_length;
1032 ulong num_index;
1033 zval **q;
1034
1035 zend_hash_get_current_key_ex(&class_type->default_static_members, &str_index, &str_length, &num_index, 0, &pos);
1036 if (Z_ISREF_PP(p) &&
1037 class_type->parent &&
1038 zend_hash_find(&class_type->parent->default_static_members, str_index, str_length, (void**)&q) == SUCCESS &&
1039 *p == *q &&
1040 zend_hash_find(CE_STATIC_MEMBERS(class_type->parent), str_index, str_length, (void**)&q) == SUCCESS
1041 ) {
1042 Z_ADDREF_PP(q);
1043 Z_SET_ISREF_PP(q);
1044 zend_hash_add(CE_STATIC_MEMBERS(class_type), str_index, str_length, (void**)q, sizeof(zval*), NULL);
1045 } else {
1046 zval *r;
1047
1048 ALLOC_ZVAL(r);
1049 *r = **p;
1050 INIT_PZVAL(r);
1051 zval_copy_ctor(r);
1052 zend_hash_add(CE_STATIC_MEMBERS(class_type), str_index, str_length, (void**)&r, sizeof(zval*), NULL);
1053 }
1054 zend_hash_move_forward_ex(&class_type->default_static_members, &pos);
1055 }
1056 }
1057 zend_hash_apply_with_argument(CE_STATIC_MEMBERS(class_type), (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC);
1058
1059 *scope = old_scope;
1060 class_type->constants_updated = 1;
1061 }
1062 }
1063 /* }}} */
1064
1065 /* This function requires 'properties' to contain all props declared in the
1066 * class and all props being public. If only a subset is given or the class
1067 * has protected members then you need to merge the properties seperately by
1068 * calling zend_merge_properties(). */
_object_and_properties_init(zval * arg,zend_class_entry * class_type,HashTable * properties ZEND_FILE_LINE_DC TSRMLS_DC)1069 ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties ZEND_FILE_LINE_DC TSRMLS_DC) /* {{{ */
1070 {
1071 zval *tmp;
1072 zend_object *object;
1073
1074 if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
1075 char *what = class_type->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "abstract class";
1076 zend_error(E_ERROR, "Cannot instantiate %s %s", what, class_type->name);
1077 }
1078
1079 zend_update_class_constants(class_type TSRMLS_CC);
1080
1081 Z_TYPE_P(arg) = IS_OBJECT;
1082 if (class_type->create_object == NULL) {
1083 Z_OBJVAL_P(arg) = zend_objects_new(&object, class_type TSRMLS_CC);
1084 if (properties) {
1085 object->properties = properties;
1086 } else {
1087 ALLOC_HASHTABLE_REL(object->properties);
1088 zend_hash_init(object->properties, zend_hash_num_elements(&class_type->default_properties), NULL, ZVAL_PTR_DTOR, 0);
1089 zend_hash_copy(object->properties, &class_type->default_properties, zval_copy_property_ctor(class_type), (void *) &tmp, sizeof(zval *));
1090 }
1091 } else {
1092 Z_OBJVAL_P(arg) = class_type->create_object(class_type TSRMLS_CC);
1093 }
1094 return SUCCESS;
1095 }
1096 /* }}} */
1097
_object_init_ex(zval * arg,zend_class_entry * class_type ZEND_FILE_LINE_DC TSRMLS_DC)1098 ZEND_API int _object_init_ex(zval *arg, zend_class_entry *class_type ZEND_FILE_LINE_DC TSRMLS_DC) /* {{{ */
1099 {
1100 return _object_and_properties_init(arg, class_type, 0 ZEND_FILE_LINE_RELAY_CC TSRMLS_CC);
1101 }
1102 /* }}} */
1103
_object_init(zval * arg ZEND_FILE_LINE_DC TSRMLS_DC)1104 ZEND_API int _object_init(zval *arg ZEND_FILE_LINE_DC TSRMLS_DC) /* {{{ */
1105 {
1106 return _object_init_ex(arg, zend_standard_class_def ZEND_FILE_LINE_RELAY_CC TSRMLS_CC);
1107 }
1108 /* }}} */
1109
add_assoc_function(zval * arg,const char * key,void (* function_ptr)(INTERNAL_FUNCTION_PARAMETERS))1110 ZEND_API int add_assoc_function(zval *arg, const char *key, void (*function_ptr)(INTERNAL_FUNCTION_PARAMETERS)) /* {{{ */
1111 {
1112 zend_error(E_WARNING, "add_assoc_function() is no longer supported");
1113 return FAILURE;
1114 }
1115 /* }}} */
1116
add_assoc_long_ex(zval * arg,const char * key,uint key_len,long n)1117 ZEND_API int add_assoc_long_ex(zval *arg, const char *key, uint key_len, long n) /* {{{ */
1118 {
1119 zval *tmp;
1120
1121 MAKE_STD_ZVAL(tmp);
1122 ZVAL_LONG(tmp, n);
1123
1124 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
1125 }
1126 /* }}} */
1127
add_assoc_null_ex(zval * arg,const char * key,uint key_len)1128 ZEND_API int add_assoc_null_ex(zval *arg, const char *key, uint key_len) /* {{{ */
1129 {
1130 zval *tmp;
1131
1132 MAKE_STD_ZVAL(tmp);
1133 ZVAL_NULL(tmp);
1134
1135 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
1136 }
1137 /* }}} */
1138
add_assoc_bool_ex(zval * arg,const char * key,uint key_len,int b)1139 ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, uint key_len, int b) /* {{{ */
1140 {
1141 zval *tmp;
1142
1143 MAKE_STD_ZVAL(tmp);
1144 ZVAL_BOOL(tmp, b);
1145
1146 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
1147 }
1148 /* }}} */
1149
add_assoc_resource_ex(zval * arg,const char * key,uint key_len,int r)1150 ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, uint key_len, int r) /* {{{ */
1151 {
1152 zval *tmp;
1153
1154 MAKE_STD_ZVAL(tmp);
1155 ZVAL_RESOURCE(tmp, r);
1156
1157 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
1158 }
1159 /* }}} */
1160
add_assoc_double_ex(zval * arg,const char * key,uint key_len,double d)1161 ZEND_API int add_assoc_double_ex(zval *arg, const char *key, uint key_len, double d) /* {{{ */
1162 {
1163 zval *tmp;
1164
1165 MAKE_STD_ZVAL(tmp);
1166 ZVAL_DOUBLE(tmp, d);
1167
1168 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
1169 }
1170 /* }}} */
1171
add_assoc_string_ex(zval * arg,const char * key,uint key_len,char * str,int duplicate)1172 ZEND_API int add_assoc_string_ex(zval *arg, const char *key, uint key_len, char *str, int duplicate) /* {{{ */
1173 {
1174 zval *tmp;
1175
1176 MAKE_STD_ZVAL(tmp);
1177 ZVAL_STRING(tmp, str, duplicate);
1178
1179 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
1180 }
1181 /* }}} */
1182
add_assoc_stringl_ex(zval * arg,const char * key,uint key_len,char * str,uint length,int duplicate)1183 ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char *str, uint length, int duplicate) /* {{{ */
1184 {
1185 zval *tmp;
1186
1187 MAKE_STD_ZVAL(tmp);
1188 ZVAL_STRINGL(tmp, str, length, duplicate);
1189
1190 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
1191 }
1192 /* }}} */
1193
add_assoc_zval_ex(zval * arg,const char * key,uint key_len,zval * value)1194 ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, uint key_len, zval *value) /* {{{ */
1195 {
1196 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &value, sizeof(zval *), NULL);
1197 }
1198 /* }}} */
1199
add_index_long(zval * arg,ulong index,long n)1200 ZEND_API int add_index_long(zval *arg, ulong index, long n) /* {{{ */
1201 {
1202 zval *tmp;
1203
1204 MAKE_STD_ZVAL(tmp);
1205 ZVAL_LONG(tmp, n);
1206
1207 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL);
1208 }
1209 /* }}} */
1210
add_index_null(zval * arg,ulong index)1211 ZEND_API int add_index_null(zval *arg, ulong index) /* {{{ */
1212 {
1213 zval *tmp;
1214
1215 MAKE_STD_ZVAL(tmp);
1216 ZVAL_NULL(tmp);
1217
1218 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL);
1219 }
1220 /* }}} */
1221
add_index_bool(zval * arg,ulong index,int b)1222 ZEND_API int add_index_bool(zval *arg, ulong index, int b) /* {{{ */
1223 {
1224 zval *tmp;
1225
1226 MAKE_STD_ZVAL(tmp);
1227 ZVAL_BOOL(tmp, b);
1228
1229 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL);
1230 }
1231 /* }}} */
1232
add_index_resource(zval * arg,ulong index,int r)1233 ZEND_API int add_index_resource(zval *arg, ulong index, int r) /* {{{ */
1234 {
1235 zval *tmp;
1236
1237 MAKE_STD_ZVAL(tmp);
1238 ZVAL_RESOURCE(tmp, r);
1239
1240 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL);
1241 }
1242 /* }}} */
1243
add_index_double(zval * arg,ulong index,double d)1244 ZEND_API int add_index_double(zval *arg, ulong index, double d) /* {{{ */
1245 {
1246 zval *tmp;
1247
1248 MAKE_STD_ZVAL(tmp);
1249 ZVAL_DOUBLE(tmp, d);
1250
1251 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL);
1252 }
1253 /* }}} */
1254
add_index_string(zval * arg,ulong index,const char * str,int duplicate)1255 ZEND_API int add_index_string(zval *arg, ulong index, const char *str, int duplicate) /* {{{ */
1256 {
1257 zval *tmp;
1258
1259 MAKE_STD_ZVAL(tmp);
1260 ZVAL_STRING(tmp, str, duplicate);
1261
1262 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL);
1263 }
1264 /* }}} */
1265
add_index_stringl(zval * arg,ulong index,const char * str,uint length,int duplicate)1266 ZEND_API int add_index_stringl(zval *arg, ulong index, const char *str, uint length, int duplicate) /* {{{ */
1267 {
1268 zval *tmp;
1269
1270 MAKE_STD_ZVAL(tmp);
1271 ZVAL_STRINGL(tmp, str, length, duplicate);
1272
1273 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), NULL);
1274 }
1275 /* }}} */
1276
add_index_zval(zval * arg,ulong index,zval * value)1277 ZEND_API int add_index_zval(zval *arg, ulong index, zval *value) /* {{{ */
1278 {
1279 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &value, sizeof(zval *), NULL);
1280 }
1281 /* }}} */
1282
add_next_index_long(zval * arg,long n)1283 ZEND_API int add_next_index_long(zval *arg, long n) /* {{{ */
1284 {
1285 zval *tmp;
1286
1287 MAKE_STD_ZVAL(tmp);
1288 ZVAL_LONG(tmp, n);
1289
1290 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL);
1291 }
1292 /* }}} */
1293
add_next_index_null(zval * arg)1294 ZEND_API int add_next_index_null(zval *arg) /* {{{ */
1295 {
1296 zval *tmp;
1297
1298 MAKE_STD_ZVAL(tmp);
1299 ZVAL_NULL(tmp);
1300
1301 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL);
1302 }
1303 /* }}} */
1304
add_next_index_bool(zval * arg,int b)1305 ZEND_API int add_next_index_bool(zval *arg, int b) /* {{{ */
1306 {
1307 zval *tmp;
1308
1309 MAKE_STD_ZVAL(tmp);
1310 ZVAL_BOOL(tmp, b);
1311
1312 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL);
1313 }
1314 /* }}} */
1315
add_next_index_resource(zval * arg,int r)1316 ZEND_API int add_next_index_resource(zval *arg, int r) /* {{{ */
1317 {
1318 zval *tmp;
1319
1320 MAKE_STD_ZVAL(tmp);
1321 ZVAL_RESOURCE(tmp, r);
1322
1323 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL);
1324 }
1325 /* }}} */
1326
add_next_index_double(zval * arg,double d)1327 ZEND_API int add_next_index_double(zval *arg, double d) /* {{{ */
1328 {
1329 zval *tmp;
1330
1331 MAKE_STD_ZVAL(tmp);
1332 ZVAL_DOUBLE(tmp, d);
1333
1334 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL);
1335 }
1336 /* }}} */
1337
add_next_index_string(zval * arg,const char * str,int duplicate)1338 ZEND_API int add_next_index_string(zval *arg, const char *str, int duplicate) /* {{{ */
1339 {
1340 zval *tmp;
1341
1342 MAKE_STD_ZVAL(tmp);
1343 ZVAL_STRING(tmp, str, duplicate);
1344
1345 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL);
1346 }
1347 /* }}} */
1348
add_next_index_stringl(zval * arg,const char * str,uint length,int duplicate)1349 ZEND_API int add_next_index_stringl(zval *arg, const char *str, uint length, int duplicate) /* {{{ */
1350 {
1351 zval *tmp;
1352
1353 MAKE_STD_ZVAL(tmp);
1354 ZVAL_STRINGL(tmp, str, length, duplicate);
1355
1356 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL);
1357 }
1358 /* }}} */
1359
add_next_index_zval(zval * arg,zval * value)1360 ZEND_API int add_next_index_zval(zval *arg, zval *value) /* {{{ */
1361 {
1362 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &value, sizeof(zval *), NULL);
1363 }
1364 /* }}} */
1365
add_get_assoc_string_ex(zval * arg,const char * key,uint key_len,const char * str,void ** dest,int duplicate)1366 ZEND_API int add_get_assoc_string_ex(zval *arg, const char *key, uint key_len, const char *str, void **dest, int duplicate) /* {{{ */
1367 {
1368 zval *tmp;
1369
1370 MAKE_STD_ZVAL(tmp);
1371 ZVAL_STRING(tmp, str, duplicate);
1372
1373 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), dest);
1374 }
1375 /* }}} */
1376
add_get_assoc_stringl_ex(zval * arg,const char * key,uint key_len,const char * str,uint length,void ** dest,int duplicate)1377 ZEND_API int add_get_assoc_stringl_ex(zval *arg, const char *key, uint key_len, const char *str, uint length, void **dest, int duplicate) /* {{{ */
1378 {
1379 zval *tmp;
1380
1381 MAKE_STD_ZVAL(tmp);
1382 ZVAL_STRINGL(tmp, str, length, duplicate);
1383
1384 return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), dest);
1385 }
1386 /* }}} */
1387
add_get_index_long(zval * arg,ulong index,long l,void ** dest)1388 ZEND_API int add_get_index_long(zval *arg, ulong index, long l, void **dest) /* {{{ */
1389 {
1390 zval *tmp;
1391
1392 MAKE_STD_ZVAL(tmp);
1393 ZVAL_LONG(tmp, l);
1394
1395 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), dest);
1396 }
1397 /* }}} */
1398
add_get_index_double(zval * arg,ulong index,double d,void ** dest)1399 ZEND_API int add_get_index_double(zval *arg, ulong index, double d, void **dest) /* {{{ */
1400 {
1401 zval *tmp;
1402
1403 MAKE_STD_ZVAL(tmp);
1404 ZVAL_DOUBLE(tmp, d);
1405
1406 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), dest);
1407 }
1408 /* }}} */
1409
add_get_index_string(zval * arg,ulong index,const char * str,void ** dest,int duplicate)1410 ZEND_API int add_get_index_string(zval *arg, ulong index, const char *str, void **dest, int duplicate) /* {{{ */
1411 {
1412 zval *tmp;
1413
1414 MAKE_STD_ZVAL(tmp);
1415 ZVAL_STRING(tmp, str, duplicate);
1416
1417 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), dest);
1418 }
1419 /* }}} */
1420
add_get_index_stringl(zval * arg,ulong index,const char * str,uint length,void ** dest,int duplicate)1421 ZEND_API int add_get_index_stringl(zval *arg, ulong index, const char *str, uint length, void **dest, int duplicate) /* {{{ */
1422 {
1423 zval *tmp;
1424
1425 MAKE_STD_ZVAL(tmp);
1426 ZVAL_STRINGL(tmp, str, length, duplicate);
1427
1428 return zend_hash_index_update(Z_ARRVAL_P(arg), index, (void *) &tmp, sizeof(zval *), dest);
1429 }
1430 /* }}} */
1431
add_property_long_ex(zval * arg,const char * key,uint key_len,long n TSRMLS_DC)1432 ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long n TSRMLS_DC) /* {{{ */
1433 {
1434 zval *tmp;
1435 zval *z_key;
1436
1437 MAKE_STD_ZVAL(tmp);
1438 ZVAL_LONG(tmp, n);
1439
1440 MAKE_STD_ZVAL(z_key);
1441 ZVAL_STRINGL(z_key, key, key_len-1, 1);
1442
1443 Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC);
1444 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1445 zval_ptr_dtor(&z_key);
1446 return SUCCESS;
1447 }
1448 /* }}} */
1449
add_property_bool_ex(zval * arg,const char * key,uint key_len,int b TSRMLS_DC)1450 ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, int b TSRMLS_DC) /* {{{ */
1451 {
1452 zval *tmp;
1453 zval *z_key;
1454
1455 MAKE_STD_ZVAL(tmp);
1456 ZVAL_BOOL(tmp, b);
1457
1458 MAKE_STD_ZVAL(z_key);
1459 ZVAL_STRINGL(z_key, key, key_len-1, 1);
1460
1461 Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC);
1462 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1463 zval_ptr_dtor(&z_key);
1464 return SUCCESS;
1465 }
1466 /* }}} */
1467
add_property_null_ex(zval * arg,const char * key,uint key_len TSRMLS_DC)1468 ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRMLS_DC) /* {{{ */
1469 {
1470 zval *tmp;
1471 zval *z_key;
1472
1473 MAKE_STD_ZVAL(tmp);
1474 ZVAL_NULL(tmp);
1475
1476 MAKE_STD_ZVAL(z_key);
1477 ZVAL_STRINGL(z_key, key, key_len-1, 1);
1478
1479 Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC);
1480 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1481 zval_ptr_dtor(&z_key);
1482 return SUCCESS;
1483 }
1484 /* }}} */
1485
add_property_resource_ex(zval * arg,const char * key,uint key_len,long n TSRMLS_DC)1486 ZEND_API int add_property_resource_ex(zval *arg, const char *key, uint key_len, long n TSRMLS_DC) /* {{{ */
1487 {
1488 zval *tmp;
1489 zval *z_key;
1490
1491 MAKE_STD_ZVAL(tmp);
1492 ZVAL_RESOURCE(tmp, n);
1493
1494 MAKE_STD_ZVAL(z_key);
1495 ZVAL_STRINGL(z_key, key, key_len-1, 1);
1496
1497 Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC);
1498 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1499 zval_ptr_dtor(&z_key);
1500 return SUCCESS;
1501 }
1502 /* }}} */
1503
add_property_double_ex(zval * arg,const char * key,uint key_len,double d TSRMLS_DC)1504 ZEND_API int add_property_double_ex(zval *arg, const char *key, uint key_len, double d TSRMLS_DC) /* {{{ */
1505 {
1506 zval *tmp;
1507 zval *z_key;
1508
1509 MAKE_STD_ZVAL(tmp);
1510 ZVAL_DOUBLE(tmp, d);
1511
1512 MAKE_STD_ZVAL(z_key);
1513 ZVAL_STRINGL(z_key, key, key_len-1, 1);
1514
1515 Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC);
1516 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1517 zval_ptr_dtor(&z_key);
1518 return SUCCESS;
1519 }
1520 /* }}} */
1521
add_property_string_ex(zval * arg,const char * key,uint key_len,char * str,int duplicate TSRMLS_DC)1522 ZEND_API int add_property_string_ex(zval *arg, const char *key, uint key_len, char *str, int duplicate TSRMLS_DC) /* {{{ */
1523 {
1524 zval *tmp;
1525 zval *z_key;
1526
1527 MAKE_STD_ZVAL(tmp);
1528 ZVAL_STRING(tmp, str, duplicate);
1529
1530 MAKE_STD_ZVAL(z_key);
1531 ZVAL_STRINGL(z_key, key, key_len-1, 1);
1532
1533 Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC);
1534 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1535 zval_ptr_dtor(&z_key);
1536 return SUCCESS;
1537 }
1538 /* }}} */
1539
add_property_stringl_ex(zval * arg,const char * key,uint key_len,char * str,uint length,int duplicate TSRMLS_DC)1540 ZEND_API int add_property_stringl_ex(zval *arg, const char *key, uint key_len, char *str, uint length, int duplicate TSRMLS_DC) /* {{{ */
1541 {
1542 zval *tmp;
1543 zval *z_key;
1544
1545 MAKE_STD_ZVAL(tmp);
1546 ZVAL_STRINGL(tmp, str, length, duplicate);
1547
1548 MAKE_STD_ZVAL(z_key);
1549 ZVAL_STRINGL(z_key, key, key_len-1, 1);
1550
1551 Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC);
1552 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1553 zval_ptr_dtor(&z_key);
1554 return SUCCESS;
1555 }
1556 /* }}} */
1557
add_property_zval_ex(zval * arg,const char * key,uint key_len,zval * value TSRMLS_DC)1558 ZEND_API int add_property_zval_ex(zval *arg, const char *key, uint key_len, zval *value TSRMLS_DC) /* {{{ */
1559 {
1560 zval *z_key;
1561
1562 MAKE_STD_ZVAL(z_key);
1563 ZVAL_STRINGL(z_key, key, key_len-1, 1);
1564
1565 Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, value TSRMLS_CC);
1566 zval_ptr_dtor(&z_key);
1567 return SUCCESS;
1568 }
1569 /* }}} */
1570
zend_startup_module_ex(zend_module_entry * module TSRMLS_DC)1571 ZEND_API int zend_startup_module_ex(zend_module_entry *module TSRMLS_DC) /* {{{ */
1572 {
1573 int name_len;
1574 char *lcname;
1575
1576 if (module->module_started) {
1577 return SUCCESS;
1578 }
1579 module->module_started = 1;
1580
1581 /* Check module dependencies */
1582 if (module->deps) {
1583 const zend_module_dep *dep = module->deps;
1584
1585 while (dep->name) {
1586 if (dep->type == MODULE_DEP_REQUIRED) {
1587 zend_module_entry *req_mod;
1588
1589 name_len = strlen(dep->name);
1590 lcname = zend_str_tolower_dup(dep->name, name_len);
1591
1592 if (zend_hash_find(&module_registry, lcname, name_len+1, (void**)&req_mod) == FAILURE || !req_mod->module_started) {
1593 efree(lcname);
1594 /* TODO: Check version relationship */
1595 zend_error(E_CORE_WARNING, "Cannot load module '%s' because required module '%s' is not loaded", module->name, dep->name);
1596 module->module_started = 0;
1597 return FAILURE;
1598 }
1599 efree(lcname);
1600 }
1601 ++dep;
1602 }
1603 }
1604
1605 /* Initialize module globals */
1606 if (module->globals_size) {
1607 #ifdef ZTS
1608 ts_allocate_id(module->globals_id_ptr, module->globals_size, (ts_allocate_ctor) module->globals_ctor, (ts_allocate_dtor) module->globals_dtor);
1609 #else
1610 if (module->globals_ctor) {
1611 module->globals_ctor(module->globals_ptr TSRMLS_CC);
1612 }
1613 #endif
1614 }
1615 if (module->module_startup_func) {
1616 EG(current_module) = module;
1617 if (module->module_startup_func(module->type, module->module_number TSRMLS_CC)==FAILURE) {
1618 zend_error(E_CORE_ERROR,"Unable to start %s module", module->name);
1619 EG(current_module) = NULL;
1620 return FAILURE;
1621 }
1622 EG(current_module) = NULL;
1623 }
1624 return SUCCESS;
1625 }
1626 /* }}} */
1627
zend_sort_modules(void * base,size_t count,size_t siz,compare_func_t compare TSRMLS_DC)1628 static void zend_sort_modules(void *base, size_t count, size_t siz, compare_func_t compare TSRMLS_DC) /* {{{ */
1629 {
1630 Bucket **b1 = base;
1631 Bucket **b2;
1632 Bucket **end = b1 + count;
1633 Bucket *tmp;
1634 zend_module_entry *m, *r;
1635
1636 while (b1 < end) {
1637 try_again:
1638 m = (zend_module_entry*)(*b1)->pData;
1639 if (!m->module_started && m->deps) {
1640 const zend_module_dep *dep = m->deps;
1641 while (dep->name) {
1642 if (dep->type == MODULE_DEP_REQUIRED || dep->type == MODULE_DEP_OPTIONAL) {
1643 b2 = b1 + 1;
1644 while (b2 < end) {
1645 r = (zend_module_entry*)(*b2)->pData;
1646 if (strcasecmp(dep->name, r->name) == 0) {
1647 tmp = *b1;
1648 *b1 = *b2;
1649 *b2 = tmp;
1650 goto try_again;
1651 }
1652 b2++;
1653 }
1654 }
1655 dep++;
1656 }
1657 }
1658 b1++;
1659 }
1660 }
1661 /* }}} */
1662
zend_startup_modules(TSRMLS_D)1663 ZEND_API int zend_startup_modules(TSRMLS_D) /* {{{ */
1664 {
1665 zend_hash_sort(&module_registry, zend_sort_modules, NULL, 0 TSRMLS_CC);
1666 zend_hash_apply(&module_registry, (apply_func_t)zend_startup_module_ex TSRMLS_CC);
1667 return SUCCESS;
1668 }
1669 /* }}} */
1670
zend_register_module_ex(zend_module_entry * module TSRMLS_DC)1671 ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module TSRMLS_DC) /* {{{ */
1672 {
1673 int name_len;
1674 char *lcname;
1675 zend_module_entry *module_ptr;
1676
1677 if (!module) {
1678 return NULL;
1679 }
1680
1681 #if 0
1682 zend_printf("%s: Registering module %d\n", module->name, module->module_number);
1683 #endif
1684
1685 /* Check module dependencies */
1686 if (module->deps) {
1687 const zend_module_dep *dep = module->deps;
1688
1689 while (dep->name) {
1690 if (dep->type == MODULE_DEP_CONFLICTS) {
1691 name_len = strlen(dep->name);
1692 lcname = zend_str_tolower_dup(dep->name, name_len);
1693
1694 if (zend_hash_exists(&module_registry, lcname, name_len+1)) {
1695 efree(lcname);
1696 /* TODO: Check version relationship */
1697 zend_error(E_CORE_WARNING, "Cannot load module '%s' because conflicting module '%s' is already loaded", module->name, dep->name);
1698 return NULL;
1699 }
1700 efree(lcname);
1701 }
1702 ++dep;
1703 }
1704 }
1705
1706 name_len = strlen(module->name);
1707 lcname = zend_str_tolower_dup(module->name, name_len);
1708
1709 if (zend_hash_add(&module_registry, lcname, name_len+1, (void *)module, sizeof(zend_module_entry), (void**)&module_ptr)==FAILURE) {
1710 zend_error(E_CORE_WARNING, "Module '%s' already loaded", module->name);
1711 efree(lcname);
1712 return NULL;
1713 }
1714 efree(lcname);
1715 module = module_ptr;
1716 EG(current_module) = module;
1717
1718 if (module->functions && zend_register_functions(NULL, module->functions, NULL, module->type TSRMLS_CC)==FAILURE) {
1719 EG(current_module) = NULL;
1720 zend_error(E_CORE_WARNING,"%s: Unable to register functions, unable to load", module->name);
1721 return NULL;
1722 }
1723
1724 EG(current_module) = NULL;
1725 return module;
1726 }
1727 /* }}} */
1728
zend_register_internal_module(zend_module_entry * module TSRMLS_DC)1729 ZEND_API zend_module_entry* zend_register_internal_module(zend_module_entry *module TSRMLS_DC) /* {{{ */
1730 {
1731 module->module_number = zend_next_free_module();
1732 module->type = MODULE_PERSISTENT;
1733 return zend_register_module_ex(module TSRMLS_CC);
1734 }
1735 /* }}} */
1736
zend_check_magic_method_implementation(const zend_class_entry * ce,const zend_function * fptr,int error_type TSRMLS_DC)1737 ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, int error_type TSRMLS_DC) /* {{{ */
1738 {
1739 char lcname[16];
1740 int name_len;
1741
1742 /* we don't care if the function name is longer, in fact lowercasing only
1743 * the beginning of the name speeds up the check process */
1744 name_len = strlen(fptr->common.function_name);
1745 zend_str_tolower_copy(lcname, fptr->common.function_name, MIN(name_len, sizeof(lcname)-1));
1746 lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */
1747
1748 if (name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) && fptr->common.num_args != 0) {
1749 zend_error(error_type, "Destructor %s::%s() cannot take arguments", ce->name, ZEND_DESTRUCTOR_FUNC_NAME);
1750 } else if (name_len == sizeof(ZEND_CLONE_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) && fptr->common.num_args != 0) {
1751 zend_error(error_type, "Method %s::%s() cannot accept any arguments", ce->name, ZEND_CLONE_FUNC_NAME);
1752 } else if (name_len == sizeof(ZEND_GET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME))) {
1753 if (fptr->common.num_args != 1) {
1754 zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name, ZEND_GET_FUNC_NAME);
1755 } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) {
1756 zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name, ZEND_GET_FUNC_NAME);
1757 }
1758 } else if (name_len == sizeof(ZEND_SET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME))) {
1759 if (fptr->common.num_args != 2) {
1760 zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name, ZEND_SET_FUNC_NAME);
1761 } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
1762 zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name, ZEND_SET_FUNC_NAME);
1763 }
1764 } else if (name_len == sizeof(ZEND_UNSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME))) {
1765 if (fptr->common.num_args != 1) {
1766 zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name, ZEND_UNSET_FUNC_NAME);
1767 } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) {
1768 zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name, ZEND_UNSET_FUNC_NAME);
1769 }
1770 } else if (name_len == sizeof(ZEND_ISSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME))) {
1771 if (fptr->common.num_args != 1) {
1772 zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name, ZEND_ISSET_FUNC_NAME);
1773 } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) {
1774 zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name, ZEND_ISSET_FUNC_NAME);
1775 }
1776 } else if (name_len == sizeof(ZEND_CALL_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME))) {
1777 if (fptr->common.num_args != 2) {
1778 zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name, ZEND_CALL_FUNC_NAME);
1779 } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
1780 zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name, ZEND_CALL_FUNC_NAME);
1781 }
1782 } else if (name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME) - 1 &&
1783 !memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1)
1784 ) {
1785 if (fptr->common.num_args != 2) {
1786 zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name, ZEND_CALLSTATIC_FUNC_NAME);
1787 } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
1788 zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name, ZEND_CALLSTATIC_FUNC_NAME);
1789 }
1790 } else if (name_len == sizeof(ZEND_TOSTRING_FUNC_NAME) - 1 &&
1791 !memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && fptr->common.num_args != 0
1792 ) {
1793 zend_error(error_type, "Method %s::%s() cannot take arguments", ce->name, ZEND_TOSTRING_FUNC_NAME);
1794 }
1795 }
1796 /* }}} */
1797
1798 /* registers all functions in *library_functions in the function hash */
zend_register_functions(zend_class_entry * scope,const zend_function_entry * functions,HashTable * function_table,int type TSRMLS_DC)1799 ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC) /* {{{ */
1800 {
1801 const zend_function_entry *ptr = functions;
1802 zend_function function, *reg_function;
1803 zend_internal_function *internal_function = (zend_internal_function *)&function;
1804 int count=0, unload=0;
1805 HashTable *target_function_table = function_table;
1806 int error_type;
1807 zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL;
1808 char *lowercase_name;
1809 int fname_len;
1810 char *lc_class_name = NULL;
1811 int class_name_len = 0;
1812
1813 if (type==MODULE_PERSISTENT) {
1814 error_type = E_CORE_WARNING;
1815 } else {
1816 error_type = E_WARNING;
1817 }
1818
1819 if (!target_function_table) {
1820 target_function_table = CG(function_table);
1821 }
1822 internal_function->type = ZEND_INTERNAL_FUNCTION;
1823 internal_function->module = EG(current_module);
1824
1825 if (scope) {
1826 class_name_len = strlen(scope->name);
1827 if ((lc_class_name = zend_memrchr(scope->name, '\\', class_name_len))) {
1828 ++lc_class_name;
1829 class_name_len -= (lc_class_name - scope->name);
1830 lc_class_name = zend_str_tolower_dup(lc_class_name, class_name_len);
1831 } else {
1832 lc_class_name = zend_str_tolower_dup(scope->name, class_name_len);
1833 }
1834 }
1835
1836 while (ptr->fname) {
1837 internal_function->handler = ptr->handler;
1838 internal_function->function_name = (char*)ptr->fname;
1839 internal_function->scope = scope;
1840 internal_function->prototype = NULL;
1841 if (ptr->arg_info) {
1842 internal_function->arg_info = (zend_arg_info*)ptr->arg_info+1;
1843 internal_function->num_args = ptr->num_args;
1844 /* Currently you cannot denote that the function can accept less arguments than num_args */
1845 if (ptr->arg_info[0].required_num_args == -1) {
1846 internal_function->required_num_args = ptr->num_args;
1847 } else {
1848 internal_function->required_num_args = ptr->arg_info[0].required_num_args;
1849 }
1850 internal_function->pass_rest_by_reference = ptr->arg_info[0].pass_by_reference;
1851 internal_function->return_reference = ptr->arg_info[0].return_reference;
1852 } else {
1853 internal_function->arg_info = NULL;
1854 internal_function->num_args = 0;
1855 internal_function->required_num_args = 0;
1856 internal_function->pass_rest_by_reference = 0;
1857 internal_function->return_reference = 0;
1858 }
1859 if (ptr->flags) {
1860 if (!(ptr->flags & ZEND_ACC_PPP_MASK)) {
1861 if (ptr->flags != ZEND_ACC_DEPRECATED || scope) {
1862 zend_error(error_type, "Invalid access level for %s%s%s() - access must be exactly one of public, protected or private", scope ? scope->name : "", scope ? "::" : "", ptr->fname);
1863 }
1864 internal_function->fn_flags = ZEND_ACC_PUBLIC | ptr->flags;
1865 } else {
1866 internal_function->fn_flags = ptr->flags;
1867 }
1868 } else {
1869 internal_function->fn_flags = ZEND_ACC_PUBLIC;
1870 }
1871 if (ptr->flags & ZEND_ACC_ABSTRACT) {
1872 if (scope) {
1873 /* This is a class that must be abstract itself. Here we set the check info. */
1874 scope->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1875 if (!(scope->ce_flags & ZEND_ACC_INTERFACE)) {
1876 /* Since the class is not an interface it needs to be declared as a abstract class. */
1877 /* Since here we are handling internal functions only we can add the keyword flag. */
1878 /* This time we set the flag for the keyword 'abstract'. */
1879 scope->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
1880 }
1881 }
1882 if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) {
1883 zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? scope->name : "", scope ? "::" : "", ptr->fname);
1884 }
1885 } else {
1886 if (scope && (scope->ce_flags & ZEND_ACC_INTERFACE)) {
1887 efree(lc_class_name);
1888 zend_error(error_type, "Interface %s cannot contain non abstract method %s()", scope->name, ptr->fname);
1889 return FAILURE;
1890 }
1891 if (!internal_function->handler) {
1892 if (scope) {
1893 efree(lc_class_name);
1894 }
1895 zend_error(error_type, "Method %s%s%s() cannot be a NULL function", scope ? scope->name : "", scope ? "::" : "", ptr->fname);
1896 zend_unregister_functions(functions, count, target_function_table TSRMLS_CC);
1897 return FAILURE;
1898 }
1899 }
1900 fname_len = strlen(ptr->fname);
1901 lowercase_name = zend_str_tolower_dup(ptr->fname, fname_len);
1902 if (zend_hash_add(target_function_table, lowercase_name, fname_len+1, &function, sizeof(zend_function), (void**)®_function) == FAILURE) {
1903 unload=1;
1904 efree(lowercase_name);
1905 break;
1906 }
1907 if (scope) {
1908 /* Look for ctor, dtor, clone
1909 * If it's an old-style constructor, store it only if we don't have
1910 * a constructor already.
1911 */
1912 if ((fname_len == class_name_len) && !memcmp(lowercase_name, lc_class_name, class_name_len+1) && !ctor) {
1913 ctor = reg_function;
1914 } else if ((fname_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME))) {
1915 ctor = reg_function;
1916 } else if ((fname_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME))) {
1917 dtor = reg_function;
1918 if (internal_function->num_args) {
1919 zend_error(error_type, "Destructor %s::%s() cannot take arguments", scope->name, ptr->fname);
1920 }
1921 } else if ((fname_len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME))) {
1922 clone = reg_function;
1923 } else if ((fname_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME))) {
1924 __call = reg_function;
1925 } else if ((fname_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME))) {
1926 __callstatic = reg_function;
1927 } else if ((fname_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME))) {
1928 __tostring = reg_function;
1929 } else if ((fname_len == sizeof(ZEND_GET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME))) {
1930 __get = reg_function;
1931 } else if ((fname_len == sizeof(ZEND_SET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME))) {
1932 __set = reg_function;
1933 } else if ((fname_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME))) {
1934 __unset = reg_function;
1935 } else if ((fname_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME))) {
1936 __isset = reg_function;
1937 } else {
1938 reg_function = NULL;
1939 }
1940 if (reg_function) {
1941 zend_check_magic_method_implementation(scope, reg_function, error_type TSRMLS_CC);
1942 }
1943 }
1944 ptr++;
1945 count++;
1946 efree(lowercase_name);
1947 }
1948 if (unload) { /* before unloading, display all remaining bad function in the module */
1949 if (scope) {
1950 efree(lc_class_name);
1951 }
1952 while (ptr->fname) {
1953 fname_len = strlen(ptr->fname);
1954 lowercase_name = zend_str_tolower_dup(ptr->fname, fname_len);
1955 if (zend_hash_exists(target_function_table, lowercase_name, fname_len+1)) {
1956 zend_error(error_type, "Function registration failed - duplicate name - %s%s%s", scope ? scope->name : "", scope ? "::" : "", ptr->fname);
1957 }
1958 efree(lowercase_name);
1959 ptr++;
1960 }
1961 zend_unregister_functions(functions, count, target_function_table TSRMLS_CC);
1962 return FAILURE;
1963 }
1964 if (scope) {
1965 scope->constructor = ctor;
1966 scope->destructor = dtor;
1967 scope->clone = clone;
1968 scope->__call = __call;
1969 scope->__callstatic = __callstatic;
1970 scope->__tostring = __tostring;
1971 scope->__get = __get;
1972 scope->__set = __set;
1973 scope->__unset = __unset;
1974 scope->__isset = __isset;
1975 if (ctor) {
1976 ctor->common.fn_flags |= ZEND_ACC_CTOR;
1977 if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
1978 zend_error(error_type, "Constructor %s::%s() cannot be static", scope->name, ctor->common.function_name);
1979 }
1980 ctor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
1981 }
1982 if (dtor) {
1983 dtor->common.fn_flags |= ZEND_ACC_DTOR;
1984 if (dtor->common.fn_flags & ZEND_ACC_STATIC) {
1985 zend_error(error_type, "Destructor %s::%s() cannot be static", scope->name, dtor->common.function_name);
1986 }
1987 dtor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
1988 }
1989 if (clone) {
1990 clone->common.fn_flags |= ZEND_ACC_CLONE;
1991 if (clone->common.fn_flags & ZEND_ACC_STATIC) {
1992 zend_error(error_type, "Constructor %s::%s() cannot be static", scope->name, clone->common.function_name);
1993 }
1994 clone->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
1995 }
1996 if (__call) {
1997 if (__call->common.fn_flags & ZEND_ACC_STATIC) {
1998 zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __call->common.function_name);
1999 }
2000 __call->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2001 }
2002 if (__callstatic) {
2003 if (!(__callstatic->common.fn_flags & ZEND_ACC_STATIC)) {
2004 zend_error(error_type, "Method %s::%s() must be static", scope->name, __callstatic->common.function_name);
2005 }
2006 __callstatic->common.fn_flags |= ZEND_ACC_STATIC;
2007 }
2008 if (__tostring) {
2009 if (__tostring->common.fn_flags & ZEND_ACC_STATIC) {
2010 zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __tostring->common.function_name);
2011 }
2012 __tostring->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2013 }
2014 if (__get) {
2015 if (__get->common.fn_flags & ZEND_ACC_STATIC) {
2016 zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __get->common.function_name);
2017 }
2018 __get->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2019 }
2020 if (__set) {
2021 if (__set->common.fn_flags & ZEND_ACC_STATIC) {
2022 zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __set->common.function_name);
2023 }
2024 __set->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2025 }
2026 if (__unset) {
2027 if (__unset->common.fn_flags & ZEND_ACC_STATIC) {
2028 zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __unset->common.function_name);
2029 }
2030 __unset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2031 }
2032 if (__isset) {
2033 if (__isset->common.fn_flags & ZEND_ACC_STATIC) {
2034 zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __isset->common.function_name);
2035 }
2036 __isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2037 }
2038 efree(lc_class_name);
2039 }
2040 return SUCCESS;
2041 }
2042 /* }}} */
2043
2044 /* count=-1 means erase all functions, otherwise,
2045 * erase the first count functions
2046 */
zend_unregister_functions(const zend_function_entry * functions,int count,HashTable * function_table TSRMLS_DC)2047 ZEND_API void zend_unregister_functions(const zend_function_entry *functions, int count, HashTable *function_table TSRMLS_DC) /* {{{ */
2048 {
2049 const zend_function_entry *ptr = functions;
2050 int i=0;
2051 HashTable *target_function_table = function_table;
2052
2053 if (!target_function_table) {
2054 target_function_table = CG(function_table);
2055 }
2056 while (ptr->fname) {
2057 if (count!=-1 && i>=count) {
2058 break;
2059 }
2060 #if 0
2061 zend_printf("Unregistering %s()\n", ptr->fname);
2062 #endif
2063 zend_hash_del(target_function_table, ptr->fname, strlen(ptr->fname)+1);
2064 ptr++;
2065 i++;
2066 }
2067 }
2068 /* }}} */
2069
zend_startup_module(zend_module_entry * module)2070 ZEND_API int zend_startup_module(zend_module_entry *module) /* {{{ */
2071 {
2072 TSRMLS_FETCH();
2073
2074 if ((module = zend_register_internal_module(module TSRMLS_CC)) != NULL && zend_startup_module_ex(module TSRMLS_CC) == SUCCESS) {
2075 return SUCCESS;
2076 }
2077 return FAILURE;
2078 }
2079 /* }}} */
2080
zend_get_module_started(const char * module_name)2081 ZEND_API int zend_get_module_started(const char *module_name) /* {{{ */
2082 {
2083 zend_module_entry *module;
2084
2085 return (zend_hash_find(&module_registry, module_name, strlen(module_name)+1, (void**)&module) == SUCCESS && module->module_started) ? SUCCESS : FAILURE;
2086 }
2087 /* }}} */
2088
clean_module_class(const zend_class_entry ** ce,int * module_number TSRMLS_DC)2089 static int clean_module_class(const zend_class_entry **ce, int *module_number TSRMLS_DC) /* {{{ */
2090 {
2091 if ((*ce)->type == ZEND_INTERNAL_CLASS && (*ce)->module->module_number == *module_number) {
2092 return ZEND_HASH_APPLY_REMOVE;
2093 } else {
2094 return ZEND_HASH_APPLY_KEEP;
2095 }
2096 }
2097 /* }}} */
2098
clean_module_classes(int module_number TSRMLS_DC)2099 static void clean_module_classes(int module_number TSRMLS_DC) /* {{{ */
2100 {
2101 zend_hash_apply_with_argument(EG(class_table), (apply_func_arg_t) clean_module_class, (void *) &module_number TSRMLS_CC);
2102 }
2103 /* }}} */
2104
module_destructor(zend_module_entry * module)2105 void module_destructor(zend_module_entry *module) /* {{{ */
2106 {
2107 TSRMLS_FETCH();
2108
2109 if (module->type == MODULE_TEMPORARY) {
2110 zend_clean_module_rsrc_dtors(module->module_number TSRMLS_CC);
2111 clean_module_constants(module->module_number TSRMLS_CC);
2112 clean_module_classes(module->module_number TSRMLS_CC);
2113 }
2114
2115 if (module->module_started && module->module_shutdown_func) {
2116 #if 0
2117 zend_printf("%s: Module shutdown\n", module->name);
2118 #endif
2119 module->module_shutdown_func(module->type, module->module_number TSRMLS_CC);
2120 }
2121
2122 /* Deinitilaise module globals */
2123 if (module->globals_size) {
2124 #ifdef ZTS
2125 if (*module->globals_id_ptr) {
2126 ts_free_id(*module->globals_id_ptr);
2127 }
2128 #else
2129 if (module->globals_dtor) {
2130 module->globals_dtor(module->globals_ptr TSRMLS_CC);
2131 }
2132 #endif
2133 }
2134
2135 module->module_started=0;
2136 if (module->functions) {
2137 zend_unregister_functions(module->functions, -1, NULL TSRMLS_CC);
2138 }
2139
2140 #if HAVE_LIBDL
2141 #if !(defined(NETWARE) && defined(APACHE_1_BUILD))
2142 if (module->handle && !getenv("ZEND_DONT_UNLOAD_MODULES")) {
2143 DL_UNLOAD(module->handle);
2144 }
2145 #endif
2146 #endif
2147 }
2148 /* }}} */
2149
2150 /* call request startup for all modules */
module_registry_request_startup(zend_module_entry * module TSRMLS_DC)2151 int module_registry_request_startup(zend_module_entry *module TSRMLS_DC) /* {{{ */
2152 {
2153 if (module->request_startup_func) {
2154 #if 0
2155 zend_printf("%s: Request startup\n", module->name);
2156 #endif
2157 if (module->request_startup_func(module->type, module->module_number TSRMLS_CC)==FAILURE) {
2158 zend_error(E_WARNING, "request_startup() for %s module failed", module->name);
2159 exit(1);
2160 }
2161 }
2162 return 0;
2163 }
2164 /* }}} */
2165
2166 /* call request shutdown for all modules */
module_registry_cleanup(zend_module_entry * module TSRMLS_DC)2167 int module_registry_cleanup(zend_module_entry *module TSRMLS_DC) /* {{{ */
2168 {
2169 if (module->request_shutdown_func) {
2170 #if 0
2171 zend_printf("%s: Request shutdown\n", module->name);
2172 #endif
2173 module->request_shutdown_func(module->type, module->module_number TSRMLS_CC);
2174 }
2175 return 0;
2176 }
2177 /* }}} */
2178
module_registry_unload_temp(const zend_module_entry * module TSRMLS_DC)2179 int module_registry_unload_temp(const zend_module_entry *module TSRMLS_DC) /* {{{ */
2180 {
2181 return (module->type == MODULE_TEMPORARY) ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_STOP;
2182 }
2183 /* }}} */
2184
2185 /* return the next free module number */
zend_next_free_module(void)2186 int zend_next_free_module(void) /* {{{ */
2187 {
2188 return zend_hash_num_elements(&module_registry) + 1;
2189 }
2190 /* }}} */
2191
do_register_internal_class(zend_class_entry * orig_class_entry,zend_uint ce_flags TSRMLS_DC)2192 static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, zend_uint ce_flags TSRMLS_DC) /* {{{ */
2193 {
2194 zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
2195 char *lowercase_name = malloc(orig_class_entry->name_length + 1);
2196 *class_entry = *orig_class_entry;
2197
2198 class_entry->type = ZEND_INTERNAL_CLASS;
2199 zend_initialize_class_data(class_entry, 0 TSRMLS_CC);
2200 class_entry->ce_flags = ce_flags;
2201 class_entry->module = EG(current_module);
2202
2203 if (class_entry->builtin_functions) {
2204 zend_register_functions(class_entry, class_entry->builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
2205 }
2206
2207 zend_str_tolower_copy(lowercase_name, orig_class_entry->name, class_entry->name_length);
2208 zend_hash_update(CG(class_table), lowercase_name, class_entry->name_length+1, &class_entry, sizeof(zend_class_entry *), NULL);
2209 free(lowercase_name);
2210 return class_entry;
2211 }
2212 /* }}} */
2213
2214 /* If parent_ce is not NULL then it inherits from parent_ce
2215 * If parent_ce is NULL and parent_name isn't then it looks for the parent and inherits from it
2216 * If both parent_ce and parent_name are NULL it does a regular class registration
2217 * If parent_name is specified but not found NULL is returned
2218 */
zend_register_internal_class_ex(zend_class_entry * class_entry,zend_class_entry * parent_ce,char * parent_name TSRMLS_DC)2219 ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce, char *parent_name TSRMLS_DC) /* {{{ */
2220 {
2221 zend_class_entry *register_class;
2222
2223 if (!parent_ce && parent_name) {
2224 zend_class_entry **pce;
2225 if (zend_hash_find(CG(class_table), parent_name, strlen(parent_name)+1, (void **) &pce)==FAILURE) {
2226 return NULL;
2227 } else {
2228 parent_ce = *pce;
2229 }
2230 }
2231
2232 register_class = zend_register_internal_class(class_entry TSRMLS_CC);
2233
2234 if (parent_ce) {
2235 zend_do_inheritance(register_class, parent_ce TSRMLS_CC);
2236 }
2237 return register_class;
2238 }
2239 /* }}} */
2240
zend_class_implements(zend_class_entry * class_entry TSRMLS_DC,int num_interfaces,...)2241 ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int num_interfaces, ...) /* {{{ */
2242 {
2243 zend_class_entry *interface_entry;
2244 va_list interface_list;
2245 va_start(interface_list, num_interfaces);
2246
2247 while (num_interfaces--) {
2248 interface_entry = va_arg(interface_list, zend_class_entry *);
2249 zend_do_implement_interface(class_entry, interface_entry TSRMLS_CC);
2250 }
2251
2252 va_end(interface_list);
2253 }
2254 /* }}} */
2255
2256 /* A class that contains at least one abstract method automatically becomes an abstract class.
2257 */
zend_register_internal_class(zend_class_entry * orig_class_entry TSRMLS_DC)2258 ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_class_entry TSRMLS_DC) /* {{{ */
2259 {
2260 return do_register_internal_class(orig_class_entry, 0 TSRMLS_CC);
2261 }
2262 /* }}} */
2263
zend_register_internal_interface(zend_class_entry * orig_class_entry TSRMLS_DC)2264 ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry TSRMLS_DC) /* {{{ */
2265 {
2266 return do_register_internal_class(orig_class_entry, ZEND_ACC_INTERFACE TSRMLS_CC);
2267 }
2268 /* }}} */
2269
zend_register_class_alias_ex(const char * name,int name_len,zend_class_entry * ce TSRMLS_DC)2270 ZEND_API int zend_register_class_alias_ex(const char *name, int name_len, zend_class_entry *ce TSRMLS_DC) /* {{{ */
2271 {
2272 char *lcname = zend_str_tolower_dup(name, name_len);
2273 int ret;
2274
2275 ret = zend_hash_add(CG(class_table), lcname, name_len+1, &ce, sizeof(zend_class_entry *), NULL);
2276 efree(lcname);
2277 if (ret == SUCCESS) {
2278 ce->refcount++;
2279 }
2280 return ret;
2281 }
2282 /* }}} */
2283
zend_set_hash_symbol(zval * symbol,const char * name,int name_length,zend_bool is_ref,int num_symbol_tables,...)2284 ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...) /* {{{ */
2285 {
2286 HashTable *symbol_table;
2287 va_list symbol_table_list;
2288
2289 if (num_symbol_tables <= 0) return FAILURE;
2290
2291 Z_SET_ISREF_TO_P(symbol, is_ref);
2292
2293 va_start(symbol_table_list, num_symbol_tables);
2294 while (num_symbol_tables-- > 0) {
2295 symbol_table = va_arg(symbol_table_list, HashTable *);
2296 zend_hash_update(symbol_table, name, name_length + 1, &symbol, sizeof(zval *), NULL);
2297 zval_add_ref(&symbol);
2298 }
2299 va_end(symbol_table_list);
2300 return SUCCESS;
2301 }
2302 /* }}} */
2303
2304 /* Disabled functions support */
2305
2306 /* {{{ proto void display_disabled_function(void)
2307 Dummy function which displays an error when a disabled function is called. */
ZEND_FUNCTION(display_disabled_function)2308 ZEND_API ZEND_FUNCTION(display_disabled_function)
2309 {
2310 zend_error(E_WARNING, "%s() has been disabled for security reasons", get_active_function_name(TSRMLS_C));
2311 }
2312 /* }}} */
2313
2314 static zend_function_entry disabled_function[] = {
2315 ZEND_FE(display_disabled_function, NULL)
2316 ZEND_FE_END
2317 };
2318
zend_disable_function(char * function_name,uint function_name_length TSRMLS_DC)2319 ZEND_API int zend_disable_function(char *function_name, uint function_name_length TSRMLS_DC) /* {{{ */
2320 {
2321 if (zend_hash_del(CG(function_table), function_name, function_name_length+1)==FAILURE) {
2322 return FAILURE;
2323 }
2324 disabled_function[0].fname = function_name;
2325 return zend_register_functions(NULL, disabled_function, CG(function_table), MODULE_PERSISTENT TSRMLS_CC);
2326 }
2327 /* }}} */
2328
display_disabled_class(zend_class_entry * class_type TSRMLS_DC)2329 static zend_object_value display_disabled_class(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
2330 {
2331 zend_object_value retval;
2332 zend_object *intern;
2333 retval = zend_objects_new(&intern, class_type TSRMLS_CC);
2334 ALLOC_HASHTABLE(intern->properties);
2335 zend_hash_init(intern->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
2336 zend_error(E_WARNING, "%s() has been disabled for security reasons", class_type->name);
2337 return retval;
2338 }
2339 /* }}} */
2340
2341 static const zend_function_entry disabled_class_new[] = {
2342 ZEND_FE_END
2343 };
2344
zend_disable_class(char * class_name,uint class_name_length TSRMLS_DC)2345 ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_DC) /* {{{ */
2346 {
2347 zend_class_entry **disabled_class;
2348
2349 zend_str_tolower(class_name, class_name_length);
2350 if (zend_hash_find(CG(class_table), class_name, class_name_length+1, (void **)&disabled_class)==FAILURE) {
2351 return FAILURE;
2352 }
2353 INIT_CLASS_ENTRY_INIT_METHODS((**disabled_class), disabled_class_new, NULL, NULL, NULL, NULL, NULL);
2354 (*disabled_class)->create_object = display_disabled_class;
2355 zend_hash_clean(&((*disabled_class)->function_table));
2356 return SUCCESS;
2357 }
2358 /* }}} */
2359
zend_is_callable_check_class(const char * name,int name_len,zend_fcall_info_cache * fcc,int * strict_class,char ** error TSRMLS_DC)2360 static int zend_is_callable_check_class(const char *name, int name_len, zend_fcall_info_cache *fcc, int *strict_class, char **error TSRMLS_DC) /* {{{ */
2361 {
2362 int ret = 0;
2363 zend_class_entry **pce;
2364 char *lcname = zend_str_tolower_dup(name, name_len);
2365
2366 *strict_class = 0;
2367 if (name_len == sizeof("self") - 1 &&
2368 !memcmp(lcname, "self", sizeof("self") - 1)) {
2369 if (!EG(scope)) {
2370 if (error) *error = estrdup("cannot access self:: when no class scope is active");
2371 } else {
2372 fcc->called_scope = EG(called_scope);
2373 fcc->calling_scope = EG(scope);
2374 if (!fcc->object_ptr) {
2375 fcc->object_ptr = EG(This);
2376 }
2377 ret = 1;
2378 }
2379 } else if (name_len == sizeof("parent") - 1 &&
2380 !memcmp(lcname, "parent", sizeof("parent") - 1)) {
2381 if (!EG(scope)) {
2382 if (error) *error = estrdup("cannot access parent:: when no class scope is active");
2383 } else if (!EG(scope)->parent) {
2384 if (error) *error = estrdup("cannot access parent:: when current class scope has no parent");
2385 } else {
2386 fcc->called_scope = EG(called_scope);
2387 fcc->calling_scope = EG(scope)->parent;
2388 if (!fcc->object_ptr) {
2389 fcc->object_ptr = EG(This);
2390 }
2391 *strict_class = 1;
2392 ret = 1;
2393 }
2394 } else if (name_len == sizeof("static") - 1 &&
2395 !memcmp(lcname, "static", sizeof("static") - 1)) {
2396 if (!EG(called_scope)) {
2397 if (error) *error = estrdup("cannot access static:: when no class scope is active");
2398 } else {
2399 fcc->called_scope = EG(called_scope);
2400 fcc->calling_scope = EG(called_scope);
2401 if (!fcc->object_ptr) {
2402 fcc->object_ptr = EG(This);
2403 }
2404 *strict_class = 1;
2405 ret = 1;
2406 }
2407 } else if (zend_lookup_class_ex(name, name_len, 1, &pce TSRMLS_CC) == SUCCESS) {
2408 zend_class_entry *scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL;
2409
2410 fcc->calling_scope = *pce;
2411 if (scope && !fcc->object_ptr && EG(This) &&
2412 instanceof_function(Z_OBJCE_P(EG(This)), scope TSRMLS_CC) &&
2413 instanceof_function(scope, fcc->calling_scope TSRMLS_CC)) {
2414 fcc->object_ptr = EG(This);
2415 fcc->called_scope = Z_OBJCE_P(fcc->object_ptr);
2416 } else {
2417 fcc->called_scope = fcc->object_ptr ? Z_OBJCE_P(fcc->object_ptr) : fcc->calling_scope;
2418 }
2419 *strict_class = 1;
2420 ret = 1;
2421 } else {
2422 if (error) zend_spprintf(error, 0, "class '%.*s' not found", name_len, name);
2423 }
2424 efree(lcname);
2425 return ret;
2426 }
2427 /* }}} */
2428
zend_is_callable_check_func(int check_flags,zval * callable,zend_fcall_info_cache * fcc,int strict_class,char ** error TSRMLS_DC)2429 static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, int strict_class, char **error TSRMLS_DC) /* {{{ */
2430 {
2431 zend_class_entry *ce_org = fcc->calling_scope;
2432 int retval = 0;
2433 char *mname, *lmname, *colon;
2434 int clen, mlen;
2435 zend_class_entry *last_scope;
2436 HashTable *ftable;
2437 int call_via_handler = 0;
2438
2439 if (error) {
2440 *error = NULL;
2441 }
2442
2443 fcc->calling_scope = NULL;
2444 fcc->function_handler = NULL;
2445
2446 if (!ce_org) {
2447 /* Skip leading \ */
2448 if (Z_STRVAL_P(callable)[0] == '\\') {
2449 mlen = Z_STRLEN_P(callable) - 1;
2450 lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + 1, mlen);
2451 } else {
2452 mlen = Z_STRLEN_P(callable);
2453 lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen);
2454 }
2455 /* Check if function with given name exists.
2456 * This may be a compound name that includes namespace name */
2457 if (zend_hash_find(EG(function_table), lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) {
2458 efree(lmname);
2459 return 1;
2460 }
2461 efree(lmname);
2462 }
2463
2464 /* Split name into class/namespace and method/function names */
2465 if ((colon = zend_memrchr(Z_STRVAL_P(callable), ':', Z_STRLEN_P(callable))) != NULL &&
2466 colon > Z_STRVAL_P(callable) &&
2467 *(colon-1) == ':'
2468 ) {
2469 colon--;
2470 clen = colon - Z_STRVAL_P(callable);
2471 mlen = Z_STRLEN_P(callable) - clen - 2;
2472
2473 if (colon == Z_STRVAL_P(callable)) {
2474 if (error) zend_spprintf(error, 0, "invalid function name");
2475 return 0;
2476 }
2477
2478 /* This is a compound name.
2479 * Try to fetch class and then find static method. */
2480 last_scope = EG(scope);
2481 if (ce_org) {
2482 EG(scope) = ce_org;
2483 }
2484
2485 if (!zend_is_callable_check_class(Z_STRVAL_P(callable), clen, fcc, &strict_class, error TSRMLS_CC)) {
2486 EG(scope) = last_scope;
2487 return 0;
2488 }
2489 EG(scope) = last_scope;
2490
2491 ftable = &fcc->calling_scope->function_table;
2492 if (ce_org && !instanceof_function(ce_org, fcc->calling_scope TSRMLS_CC)) {
2493 if (error) zend_spprintf(error, 0, "class '%s' is not a subclass of '%s'", ce_org->name, fcc->calling_scope->name);
2494 return 0;
2495 }
2496 mname = Z_STRVAL_P(callable) + clen + 2;
2497 } else if (ce_org) {
2498 /* Try to fetch find static method of given class. */
2499 mlen = Z_STRLEN_P(callable);
2500 mname = Z_STRVAL_P(callable);
2501 ftable = &ce_org->function_table;
2502 fcc->calling_scope = ce_org;
2503 } else {
2504 /* We already checked for plain function before. */
2505 if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) {
2506 zend_spprintf(error, 0, "function '%s' not found or invalid function name", Z_STRVAL_P(callable));
2507 }
2508 return 0;
2509 }
2510
2511 lmname = zend_str_tolower_dup(mname, mlen);
2512 if (strict_class &&
2513 fcc->calling_scope &&
2514 mlen == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 &&
2515 !memcmp(lmname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME))) {
2516 fcc->function_handler = fcc->calling_scope->constructor;
2517 if (fcc->function_handler) {
2518 retval = 1;
2519 }
2520 } else if (zend_hash_find(ftable, lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) {
2521 retval = 1;
2522 if ((fcc->function_handler->op_array.fn_flags & ZEND_ACC_CHANGED) &&
2523 !strict_class && EG(scope) &&
2524 instanceof_function(fcc->function_handler->common.scope, EG(scope) TSRMLS_CC)) {
2525 zend_function *priv_fbc;
2526
2527 if (zend_hash_find(&EG(scope)->function_table, lmname, mlen+1, (void **) &priv_fbc)==SUCCESS
2528 && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE
2529 && priv_fbc->common.scope == EG(scope)) {
2530 fcc->function_handler = priv_fbc;
2531 }
2532 }
2533 if ((check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0 &&
2534 (fcc->calling_scope &&
2535 (fcc->calling_scope->__call ||
2536 fcc->calling_scope->__callstatic))) {
2537 if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) {
2538 if (!zend_check_private(fcc->function_handler, fcc->object_ptr ? Z_OBJCE_P(fcc->object_ptr) : EG(scope), lmname, mlen TSRMLS_CC)) {
2539 retval = 0;
2540 fcc->function_handler = NULL;
2541 goto get_function_via_handler;
2542 }
2543 } else if (fcc->function_handler->common.fn_flags & ZEND_ACC_PROTECTED) {
2544 if (!zend_check_protected(fcc->function_handler->common.scope, EG(scope))) {
2545 retval = 0;
2546 fcc->function_handler = NULL;
2547 goto get_function_via_handler;
2548 }
2549 }
2550 }
2551 } else {
2552 get_function_via_handler:
2553 if (fcc->object_ptr && fcc->calling_scope == ce_org) {
2554 if (strict_class && ce_org->__call) {
2555 fcc->function_handler = emalloc(sizeof(zend_internal_function));
2556 fcc->function_handler->internal_function.type = ZEND_INTERNAL_FUNCTION;
2557 fcc->function_handler->internal_function.module = ce_org->module;
2558 fcc->function_handler->internal_function.handler = zend_std_call_user_call;
2559 fcc->function_handler->internal_function.arg_info = NULL;
2560 fcc->function_handler->internal_function.num_args = 0;
2561 fcc->function_handler->internal_function.scope = ce_org;
2562 fcc->function_handler->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
2563 fcc->function_handler->internal_function.function_name = estrndup(mname, mlen);
2564 fcc->function_handler->internal_function.pass_rest_by_reference = 0;
2565 fcc->function_handler->internal_function.return_reference = ZEND_RETURN_VALUE;
2566 call_via_handler = 1;
2567 retval = 1;
2568 } else if (Z_OBJ_HT_P(fcc->object_ptr)->get_method) {
2569 fcc->function_handler = Z_OBJ_HT_P(fcc->object_ptr)->get_method(&fcc->object_ptr, mname, mlen TSRMLS_CC);
2570 if (fcc->function_handler) {
2571 if (strict_class &&
2572 (!fcc->function_handler->common.scope ||
2573 !instanceof_function(ce_org, fcc->function_handler->common.scope TSRMLS_CC))) {
2574 if ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) {
2575 if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
2576 efree(fcc->function_handler->common.function_name);
2577 }
2578 efree(fcc->function_handler);
2579 }
2580 } else {
2581 retval = 1;
2582 call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
2583 }
2584 }
2585 }
2586 } else if (fcc->calling_scope) {
2587 if (fcc->calling_scope->get_static_method) {
2588 fcc->function_handler = fcc->calling_scope->get_static_method(fcc->calling_scope, mname, mlen TSRMLS_CC);
2589 } else {
2590 fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, mname, mlen TSRMLS_CC);
2591 }
2592 if (fcc->function_handler) {
2593 retval = 1;
2594 call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
2595 if (call_via_handler && !fcc->object_ptr && EG(This) &&
2596 Z_OBJ_HT_P(EG(This))->get_class_entry &&
2597 instanceof_function(Z_OBJCE_P(EG(This)), fcc->calling_scope TSRMLS_CC)) {
2598 fcc->object_ptr = EG(This);
2599 }
2600 }
2601 }
2602 }
2603
2604 if (retval) {
2605 if (fcc->calling_scope && !call_via_handler) {
2606 if (!fcc->object_ptr && (fcc->function_handler->common.fn_flags & ZEND_ACC_ABSTRACT)) {
2607 if (error) {
2608 zend_spprintf(error, 0, "cannot call abstract method %s::%s()", fcc->calling_scope->name, fcc->function_handler->common.function_name);
2609 retval = 0;
2610 } else {
2611 zend_error(E_ERROR, "Cannot call abstract method %s::%s()", fcc->calling_scope->name, fcc->function_handler->common.function_name);
2612 }
2613 } else if (!fcc->object_ptr && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
2614 int severity;
2615 char *verb;
2616 if (fcc->function_handler->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
2617 severity = E_STRICT;
2618 verb = "should not";
2619 } else {
2620 /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
2621 severity = E_ERROR;
2622 verb = "cannot";
2623 }
2624 if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) {
2625 retval = 0;
2626 }
2627 if (EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), fcc->calling_scope TSRMLS_CC)) {
2628 fcc->object_ptr = EG(This);
2629 if (error) {
2630 zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", fcc->calling_scope->name, fcc->function_handler->common.function_name, verb, Z_OBJCE_P(EG(This))->name);
2631 if (severity == E_ERROR) {
2632 retval = 0;
2633 }
2634 } else if (retval) {
2635 zend_error(severity, "Non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", fcc->calling_scope->name, fcc->function_handler->common.function_name, verb, Z_OBJCE_P(EG(This))->name);
2636 }
2637 } else {
2638 if (error) {
2639 zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically", fcc->calling_scope->name, fcc->function_handler->common.function_name, verb);
2640 if (severity == E_ERROR) {
2641 retval = 0;
2642 }
2643 } else if (retval) {
2644 zend_error(severity, "Non-static method %s::%s() %s be called statically", fcc->calling_scope->name, fcc->function_handler->common.function_name, verb);
2645 }
2646 }
2647 }
2648 if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
2649 if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) {
2650 if (!zend_check_private(fcc->function_handler, fcc->object_ptr ? Z_OBJCE_P(fcc->object_ptr) : EG(scope), lmname, mlen TSRMLS_CC)) {
2651 if (error) {
2652 if (*error) {
2653 efree(*error);
2654 }
2655 zend_spprintf(error, 0, "cannot access private method %s::%s()", fcc->calling_scope->name, fcc->function_handler->common.function_name);
2656 }
2657 retval = 0;
2658 }
2659 } else if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PROTECTED)) {
2660 if (!zend_check_protected(fcc->function_handler->common.scope, EG(scope))) {
2661 if (error) {
2662 if (*error) {
2663 efree(*error);
2664 }
2665 zend_spprintf(error, 0, "cannot access protected method %s::%s()", fcc->calling_scope->name, fcc->function_handler->common.function_name);
2666 }
2667 retval = 0;
2668 }
2669 }
2670 }
2671 }
2672 } else if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) {
2673 if (fcc->calling_scope) {
2674 if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", fcc->calling_scope->name, mname);
2675 } else {
2676 if (error) zend_spprintf(error, 0, "function '%s' does not exist", mname);
2677 }
2678 }
2679 efree(lmname);
2680
2681 if (fcc->object_ptr) {
2682 fcc->called_scope = Z_OBJCE_P(fcc->object_ptr);
2683 }
2684 if (retval) {
2685 fcc->initialized = 1;
2686 }
2687 return retval;
2688 }
2689 /* }}} */
2690
zend_is_callable_ex(zval * callable,zval * object_ptr,uint check_flags,char ** callable_name,int * callable_name_len,zend_fcall_info_cache * fcc,char ** error TSRMLS_DC)2691 ZEND_API zend_bool zend_is_callable_ex(zval *callable, zval *object_ptr, uint check_flags, char **callable_name, int *callable_name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
2692 {
2693 zend_bool ret;
2694 int callable_name_len_local;
2695 zend_fcall_info_cache fcc_local;
2696
2697 if (callable_name) {
2698 *callable_name = NULL;
2699 }
2700 if (callable_name_len == NULL) {
2701 callable_name_len = &callable_name_len_local;
2702 }
2703 if (fcc == NULL) {
2704 fcc = &fcc_local;
2705 }
2706 if (error) {
2707 *error = NULL;
2708 }
2709
2710 fcc->initialized = 0;
2711 fcc->calling_scope = NULL;
2712 fcc->called_scope = NULL;
2713 fcc->function_handler = NULL;
2714 fcc->calling_scope = NULL;
2715 fcc->object_ptr = NULL;
2716
2717 if (object_ptr && Z_TYPE_P(object_ptr) != IS_OBJECT) {
2718 object_ptr = NULL;
2719 }
2720 if (object_ptr &&
2721 (!EG(objects_store).object_buckets ||
2722 !EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(object_ptr)].valid)) {
2723 return 0;
2724 }
2725
2726 switch (Z_TYPE_P(callable)) {
2727 case IS_STRING:
2728 if (object_ptr) {
2729 fcc->object_ptr = object_ptr;
2730 fcc->calling_scope = Z_OBJCE_P(object_ptr);
2731 if (callable_name) {
2732 char *ptr;
2733
2734 *callable_name_len = fcc->calling_scope->name_length + Z_STRLEN_P(callable) + sizeof("::") - 1;
2735 ptr = *callable_name = emalloc(*callable_name_len + 1);
2736 memcpy(ptr, fcc->calling_scope->name, fcc->calling_scope->name_length);
2737 ptr += fcc->calling_scope->name_length;
2738 memcpy(ptr, "::", sizeof("::") - 1);
2739 ptr += sizeof("::") - 1;
2740 memcpy(ptr, Z_STRVAL_P(callable), Z_STRLEN_P(callable) + 1);
2741 }
2742 } else if (callable_name) {
2743 *callable_name = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable));
2744 *callable_name_len = Z_STRLEN_P(callable);
2745 }
2746 if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
2747 fcc->called_scope = fcc->calling_scope;
2748 return 1;
2749 }
2750
2751 ret = zend_is_callable_check_func(check_flags, callable, fcc, 0, error TSRMLS_CC);
2752 if (fcc == &fcc_local &&
2753 fcc->function_handler &&
2754 ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
2755 (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
2756 fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
2757 fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
2758 if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
2759 efree(fcc->function_handler->common.function_name);
2760 }
2761 efree(fcc->function_handler);
2762 }
2763 return ret;
2764
2765 case IS_ARRAY:
2766 {
2767 zval **method = NULL;
2768 zval **obj = NULL;
2769 int strict_class = 0;
2770
2771 if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
2772 zend_hash_index_find(Z_ARRVAL_P(callable), 0, (void **) &obj);
2773 zend_hash_index_find(Z_ARRVAL_P(callable), 1, (void **) &method);
2774 }
2775 if (obj && method &&
2776 (Z_TYPE_PP(obj) == IS_OBJECT ||
2777 Z_TYPE_PP(obj) == IS_STRING) &&
2778 Z_TYPE_PP(method) == IS_STRING) {
2779
2780 if (Z_TYPE_PP(obj) == IS_STRING) {
2781 if (callable_name) {
2782 char *ptr;
2783
2784 *callable_name_len = Z_STRLEN_PP(obj) + Z_STRLEN_PP(method) + sizeof("::") - 1;
2785 ptr = *callable_name = emalloc(*callable_name_len + 1);
2786 memcpy(ptr, Z_STRVAL_PP(obj), Z_STRLEN_PP(obj));
2787 ptr += Z_STRLEN_PP(obj);
2788 memcpy(ptr, "::", sizeof("::") - 1);
2789 ptr += sizeof("::") - 1;
2790 memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1);
2791 }
2792
2793 if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
2794 return 1;
2795 }
2796
2797 if (!zend_is_callable_check_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), fcc, &strict_class, error TSRMLS_CC)) {
2798 return 0;
2799 }
2800
2801 } else {
2802 if (!EG(objects_store).object_buckets ||
2803 !EG(objects_store).object_buckets[Z_OBJ_HANDLE_PP(obj)].valid) {
2804 return 0;
2805 }
2806
2807 fcc->calling_scope = Z_OBJCE_PP(obj); /* TBFixed: what if it's overloaded? */
2808
2809 fcc->object_ptr = *obj;
2810
2811 if (callable_name) {
2812 char *ptr;
2813
2814 *callable_name_len = fcc->calling_scope->name_length + Z_STRLEN_PP(method) + sizeof("::") - 1;
2815 ptr = *callable_name = emalloc(*callable_name_len + 1);
2816 memcpy(ptr, fcc->calling_scope->name, fcc->calling_scope->name_length);
2817 ptr += fcc->calling_scope->name_length;
2818 memcpy(ptr, "::", sizeof("::") - 1);
2819 ptr += sizeof("::") - 1;
2820 memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1);
2821 }
2822
2823 if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
2824 fcc->called_scope = fcc->calling_scope;
2825 return 1;
2826 }
2827 }
2828
2829 ret = zend_is_callable_check_func(check_flags, *method, fcc, strict_class, error TSRMLS_CC);
2830 if (fcc == &fcc_local &&
2831 fcc->function_handler &&
2832 ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
2833 (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
2834 fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
2835 fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
2836 if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
2837 efree(fcc->function_handler->common.function_name);
2838 }
2839 efree(fcc->function_handler);
2840 }
2841 return ret;
2842
2843 } else {
2844 if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
2845 if (!obj || (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT)) {
2846 if (error) zend_spprintf(error, 0, "first array member is not a valid class name or object");
2847 } else {
2848 if (error) zend_spprintf(error, 0, "second array member is not a valid method");
2849 }
2850 } else {
2851 if (error) zend_spprintf(error, 0, "array must have exactly two members");
2852 }
2853 if (callable_name) {
2854 *callable_name = estrndup("Array", sizeof("Array")-1);
2855 *callable_name_len = sizeof("Array") - 1;
2856 }
2857 }
2858 }
2859 return 0;
2860
2861 case IS_OBJECT:
2862 if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &fcc->calling_scope, &fcc->function_handler, &fcc->object_ptr TSRMLS_CC) == SUCCESS) {
2863 fcc->called_scope = fcc->calling_scope;
2864 if (callable_name) {
2865 zend_class_entry *ce = Z_OBJCE_P(callable); /* TBFixed: what if it's overloaded? */
2866
2867 *callable_name_len = ce->name_length + sizeof("::__invoke") - 1;
2868 *callable_name = emalloc(*callable_name_len + 1);
2869 memcpy(*callable_name, ce->name, ce->name_length);
2870 memcpy((*callable_name) + ce->name_length, "::__invoke", sizeof("::__invoke"));
2871 }
2872 return 1;
2873 }
2874 /* break missing intentionally */
2875
2876 default:
2877 if (callable_name) {
2878 zval expr_copy;
2879 int use_copy;
2880
2881 zend_make_printable_zval(callable, &expr_copy, &use_copy);
2882 *callable_name = estrndup(Z_STRVAL(expr_copy), Z_STRLEN(expr_copy));
2883 *callable_name_len = Z_STRLEN(expr_copy);
2884 zval_dtor(&expr_copy);
2885 }
2886 if (error) zend_spprintf(error, 0, "no array or string given");
2887 return 0;
2888 }
2889 }
2890 /* }}} */
2891
zend_is_callable(zval * callable,uint check_flags,char ** callable_name TSRMLS_DC)2892 ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name TSRMLS_DC) /* {{{ */
2893 {
2894 return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL, NULL TSRMLS_CC);
2895 }
2896 /* }}} */
2897
zend_make_callable(zval * callable,char ** callable_name TSRMLS_DC)2898 ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRMLS_DC) /* {{{ */
2899 {
2900 zend_fcall_info_cache fcc;
2901
2902 if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_STRICT, callable_name, NULL, &fcc, NULL TSRMLS_CC)) {
2903 if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) {
2904 zval_dtor(callable);
2905 array_init(callable);
2906 add_next_index_string(callable, fcc.calling_scope->name, 1);
2907 add_next_index_string(callable, fcc.function_handler->common.function_name, 1);
2908 }
2909 if (fcc.function_handler &&
2910 ((fcc.function_handler->type == ZEND_INTERNAL_FUNCTION &&
2911 (fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
2912 fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
2913 fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
2914 if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) {
2915 efree(fcc.function_handler->common.function_name);
2916 }
2917 efree(fcc.function_handler);
2918 }
2919 return 1;
2920 }
2921 return 0;
2922 }
2923 /* }}} */
2924
zend_fcall_info_init(zval * callable,uint check_flags,zend_fcall_info * fci,zend_fcall_info_cache * fcc,char ** callable_name,char ** error TSRMLS_DC)2925 ZEND_API int zend_fcall_info_init(zval *callable, uint check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, char **callable_name, char **error TSRMLS_DC) /* {{{ */
2926 {
2927 if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, fcc, error TSRMLS_CC)) {
2928 return FAILURE;
2929 }
2930
2931 fci->size = sizeof(*fci);
2932 fci->function_table = fcc->calling_scope ? &fcc->calling_scope->function_table : EG(function_table);
2933 fci->object_ptr = fcc->object_ptr;
2934 fci->function_name = callable;
2935 fci->retval_ptr_ptr = NULL;
2936 fci->param_count = 0;
2937 fci->params = NULL;
2938 fci->no_separation = 1;
2939 fci->symbol_table = NULL;
2940
2941 return SUCCESS;
2942 }
2943 /* }}} */
2944
zend_fcall_info_args_clear(zend_fcall_info * fci,int free_mem)2945 ZEND_API void zend_fcall_info_args_clear(zend_fcall_info *fci, int free_mem) /* {{{ */
2946 {
2947 if (fci->params) {
2948 if (free_mem) {
2949 efree(fci->params);
2950 fci->params = NULL;
2951 }
2952 }
2953 fci->param_count = 0;
2954 }
2955 /* }}} */
2956
zend_fcall_info_args_save(zend_fcall_info * fci,int * param_count,zval **** params)2957 ZEND_API void zend_fcall_info_args_save(zend_fcall_info *fci, int *param_count, zval ****params) /* {{{ */
2958 {
2959 *param_count = fci->param_count;
2960 *params = fci->params;
2961 fci->param_count = 0;
2962 fci->params = NULL;
2963 }
2964 /* }}} */
2965
zend_fcall_info_args_restore(zend_fcall_info * fci,int param_count,zval *** params)2966 ZEND_API void zend_fcall_info_args_restore(zend_fcall_info *fci, int param_count, zval ***params) /* {{{ */
2967 {
2968 zend_fcall_info_args_clear(fci, 1);
2969 fci->param_count = param_count;
2970 fci->params = params;
2971 }
2972 /* }}} */
2973
zend_fcall_info_args(zend_fcall_info * fci,zval * args TSRMLS_DC)2974 ZEND_API int zend_fcall_info_args(zend_fcall_info *fci, zval *args TSRMLS_DC) /* {{{ */
2975 {
2976 HashPosition pos;
2977 zval **arg, ***params;
2978
2979 zend_fcall_info_args_clear(fci, !args);
2980
2981 if (!args) {
2982 return SUCCESS;
2983 }
2984
2985 if (Z_TYPE_P(args) != IS_ARRAY) {
2986 return FAILURE;
2987 }
2988
2989 fci->param_count = zend_hash_num_elements(Z_ARRVAL_P(args));
2990 fci->params = params = (zval ***) erealloc(fci->params, fci->param_count * sizeof(zval **));
2991
2992 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos);
2993 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void *) &arg, &pos) == SUCCESS) {
2994 *params++ = arg;
2995 zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos);
2996 }
2997
2998 return SUCCESS;
2999 }
3000 /* }}} */
3001
zend_fcall_info_argp(zend_fcall_info * fci TSRMLS_DC,int argc,zval *** argv)3002 ZEND_API int zend_fcall_info_argp(zend_fcall_info *fci TSRMLS_DC, int argc, zval ***argv) /* {{{ */
3003 {
3004 int i;
3005
3006 if (argc < 0) {
3007 return FAILURE;
3008 }
3009
3010 zend_fcall_info_args_clear(fci, !argc);
3011
3012 if (argc) {
3013 fci->param_count = argc;
3014 fci->params = (zval ***) erealloc(fci->params, fci->param_count * sizeof(zval **));
3015
3016 for (i = 0; i < argc; ++i) {
3017 fci->params[i] = argv[i];
3018 }
3019 }
3020
3021 return SUCCESS;
3022 }
3023 /* }}} */
3024
zend_fcall_info_argv(zend_fcall_info * fci TSRMLS_DC,int argc,va_list * argv)3025 ZEND_API int zend_fcall_info_argv(zend_fcall_info *fci TSRMLS_DC, int argc, va_list *argv) /* {{{ */
3026 {
3027 int i;
3028 zval **arg;
3029
3030 if (argc < 0) {
3031 return FAILURE;
3032 }
3033
3034 zend_fcall_info_args_clear(fci, !argc);
3035
3036 if (argc) {
3037 fci->param_count = argc;
3038 fci->params = (zval ***) erealloc(fci->params, fci->param_count * sizeof(zval **));
3039
3040 for (i = 0; i < argc; ++i) {
3041 arg = va_arg(*argv, zval **);
3042 fci->params[i] = arg;
3043 }
3044 }
3045
3046 return SUCCESS;
3047 }
3048 /* }}} */
3049
zend_fcall_info_argn(zend_fcall_info * fci TSRMLS_DC,int argc,...)3050 ZEND_API int zend_fcall_info_argn(zend_fcall_info *fci TSRMLS_DC, int argc, ...) /* {{{ */
3051 {
3052 int ret;
3053 va_list argv;
3054
3055 va_start(argv, argc);
3056 ret = zend_fcall_info_argv(fci TSRMLS_CC, argc, &argv);
3057 va_end(argv);
3058
3059 return ret;
3060 }
3061 /* }}} */
3062
zend_fcall_info_call(zend_fcall_info * fci,zend_fcall_info_cache * fcc,zval ** retval_ptr_ptr,zval * args TSRMLS_DC)3063 ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval **retval_ptr_ptr, zval *args TSRMLS_DC) /* {{{ */
3064 {
3065 zval *retval, ***org_params = NULL;
3066 int result, org_count = 0;
3067
3068 fci->retval_ptr_ptr = retval_ptr_ptr ? retval_ptr_ptr : &retval;
3069 if (args) {
3070 zend_fcall_info_args_save(fci, &org_count, &org_params);
3071 zend_fcall_info_args(fci, args TSRMLS_CC);
3072 }
3073 result = zend_call_function(fci, fcc TSRMLS_CC);
3074
3075 if (!retval_ptr_ptr && retval) {
3076 zval_ptr_dtor(&retval);
3077 }
3078 if (args) {
3079 zend_fcall_info_args_restore(fci, org_count, org_params);
3080 }
3081 return result;
3082 }
3083 /* }}} */
3084
zend_get_module_version(const char * module_name)3085 ZEND_API const char *zend_get_module_version(const char *module_name) /* {{{ */
3086 {
3087 char *lname;
3088 int name_len = strlen(module_name);
3089 zend_module_entry *module;
3090
3091 lname = zend_str_tolower_dup(module_name, name_len);
3092 if (zend_hash_find(&module_registry, lname, name_len + 1, (void**)&module) == FAILURE) {
3093 efree(lname);
3094 return NULL;
3095 }
3096 efree(lname);
3097 return module->version;
3098 }
3099 /* }}} */
3100
zend_declare_property_ex(zend_class_entry * ce,const char * name,int name_length,zval * property,int access_type,char * doc_comment,int doc_comment_len TSRMLS_DC)3101 ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len TSRMLS_DC) /* {{{ */
3102 {
3103 zend_property_info property_info;
3104 HashTable *target_symbol_table;
3105
3106 if (!(access_type & ZEND_ACC_PPP_MASK)) {
3107 access_type |= ZEND_ACC_PUBLIC;
3108 }
3109 if (access_type & ZEND_ACC_STATIC) {
3110 target_symbol_table = &ce->default_static_members;
3111 } else {
3112 target_symbol_table = &ce->default_properties;
3113 }
3114 if (ce->type & ZEND_INTERNAL_CLASS) {
3115 switch(Z_TYPE_P(property)) {
3116 case IS_ARRAY:
3117 case IS_CONSTANT_ARRAY:
3118 case IS_OBJECT:
3119 case IS_RESOURCE:
3120 zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources");
3121 break;
3122 default:
3123 break;
3124 }
3125 }
3126 switch (access_type & ZEND_ACC_PPP_MASK) {
3127 case ZEND_ACC_PRIVATE: {
3128 char *priv_name;
3129 int priv_name_length;
3130
3131 zend_mangle_property_name(&priv_name, &priv_name_length, ce->name, ce->name_length, name, name_length, ce->type & ZEND_INTERNAL_CLASS);
3132 zend_hash_update(target_symbol_table, priv_name, priv_name_length+1, &property, sizeof(zval *), NULL);
3133 property_info.name = priv_name;
3134 property_info.name_length = priv_name_length;
3135 }
3136 break;
3137 case ZEND_ACC_PROTECTED: {
3138 char *prot_name;
3139 int prot_name_length;
3140
3141 zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, name, name_length, ce->type & ZEND_INTERNAL_CLASS);
3142 zend_hash_update(target_symbol_table, prot_name, prot_name_length+1, &property, sizeof(zval *), NULL);
3143 property_info.name = prot_name;
3144 property_info.name_length = prot_name_length;
3145 }
3146 break;
3147 case ZEND_ACC_PUBLIC:
3148 if (ce->parent) {
3149 char *prot_name;
3150 int prot_name_length;
3151
3152 zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, name, name_length, ce->type & ZEND_INTERNAL_CLASS);
3153 zend_hash_del(target_symbol_table, prot_name, prot_name_length+1);
3154 pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS);
3155 }
3156 zend_hash_update(target_symbol_table, name, name_length+1, &property, sizeof(zval *), NULL);
3157 property_info.name = ce->type & ZEND_INTERNAL_CLASS ? zend_strndup(name, name_length) : estrndup(name, name_length);
3158 property_info.name_length = name_length;
3159 break;
3160 }
3161 property_info.flags = access_type;
3162 property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1);
3163
3164 property_info.doc_comment = doc_comment;
3165 property_info.doc_comment_len = doc_comment_len;
3166
3167 property_info.ce = ce;
3168
3169 zend_hash_update(&ce->properties_info, name, name_length + 1, &property_info, sizeof(zend_property_info), NULL);
3170
3171 return SUCCESS;
3172 }
3173 /* }}} */
3174
zend_declare_property(zend_class_entry * ce,char * name,int name_length,zval * property,int access_type TSRMLS_DC)3175 ZEND_API int zend_declare_property(zend_class_entry *ce, char *name, int name_length, zval *property, int access_type TSRMLS_DC) /* {{{ */
3176 {
3177 return zend_declare_property_ex(ce, name, name_length, property, access_type, NULL, 0 TSRMLS_CC);
3178 }
3179 /* }}} */
3180
zend_declare_property_null(zend_class_entry * ce,char * name,int name_length,int access_type TSRMLS_DC)3181 ZEND_API int zend_declare_property_null(zend_class_entry *ce, char *name, int name_length, int access_type TSRMLS_DC) /* {{{ */
3182 {
3183 zval *property;
3184
3185 if (ce->type & ZEND_INTERNAL_CLASS) {
3186 ALLOC_PERMANENT_ZVAL(property);
3187 } else {
3188 ALLOC_ZVAL(property);
3189 }
3190 INIT_ZVAL(*property);
3191 return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC);
3192 }
3193 /* }}} */
3194
zend_declare_property_bool(zend_class_entry * ce,char * name,int name_length,long value,int access_type TSRMLS_DC)3195 ZEND_API int zend_declare_property_bool(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC) /* {{{ */
3196 {
3197 zval *property;
3198
3199 if (ce->type & ZEND_INTERNAL_CLASS) {
3200 ALLOC_PERMANENT_ZVAL(property);
3201 } else {
3202 ALLOC_ZVAL(property);
3203 }
3204 INIT_PZVAL(property);
3205 ZVAL_BOOL(property, value);
3206 return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC);
3207 }
3208 /* }}} */
3209
zend_declare_property_long(zend_class_entry * ce,char * name,int name_length,long value,int access_type TSRMLS_DC)3210 ZEND_API int zend_declare_property_long(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC) /* {{{ */
3211 {
3212 zval *property;
3213
3214 if (ce->type & ZEND_INTERNAL_CLASS) {
3215 ALLOC_PERMANENT_ZVAL(property);
3216 } else {
3217 ALLOC_ZVAL(property);
3218 }
3219 INIT_PZVAL(property);
3220 ZVAL_LONG(property, value);
3221 return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC);
3222 }
3223 /* }}} */
3224
zend_declare_property_double(zend_class_entry * ce,char * name,int name_length,double value,int access_type TSRMLS_DC)3225 ZEND_API int zend_declare_property_double(zend_class_entry *ce, char *name, int name_length, double value, int access_type TSRMLS_DC) /* {{{ */
3226 {
3227 zval *property;
3228
3229 if (ce->type & ZEND_INTERNAL_CLASS) {
3230 ALLOC_PERMANENT_ZVAL(property);
3231 } else {
3232 ALLOC_ZVAL(property);
3233 }
3234 INIT_PZVAL(property);
3235 ZVAL_DOUBLE(property, value);
3236 return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC);
3237 }
3238 /* }}} */
3239
zend_declare_property_string(zend_class_entry * ce,char * name,int name_length,char * value,int access_type TSRMLS_DC)3240 ZEND_API int zend_declare_property_string(zend_class_entry *ce, char *name, int name_length, char *value, int access_type TSRMLS_DC) /* {{{ */
3241 {
3242 zval *property;
3243 int len = strlen(value);
3244
3245 if (ce->type & ZEND_INTERNAL_CLASS) {
3246 ALLOC_PERMANENT_ZVAL(property);
3247 ZVAL_STRINGL(property, zend_strndup(value, len), len, 0);
3248 } else {
3249 ALLOC_ZVAL(property);
3250 ZVAL_STRINGL(property, value, len, 1);
3251 }
3252 INIT_PZVAL(property);
3253 return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC);
3254 }
3255 /* }}} */
3256
zend_declare_property_stringl(zend_class_entry * ce,char * name,int name_length,char * value,int value_len,int access_type TSRMLS_DC)3257 ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, char *name, int name_length, char *value, int value_len, int access_type TSRMLS_DC) /* {{{ */
3258 {
3259 zval *property;
3260
3261 if (ce->type & ZEND_INTERNAL_CLASS) {
3262 ALLOC_PERMANENT_ZVAL(property);
3263 ZVAL_STRINGL(property, zend_strndup(value, value_len), value_len, 0);
3264 } else {
3265 ALLOC_ZVAL(property);
3266 ZVAL_STRINGL(property, value, value_len, 1);
3267 }
3268 INIT_PZVAL(property);
3269 return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC);
3270 }
3271 /* }}} */
3272
zend_declare_class_constant(zend_class_entry * ce,const char * name,size_t name_length,zval * value TSRMLS_DC)3273 ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value TSRMLS_DC) /* {{{ */
3274 {
3275 return zend_hash_update(&ce->constants_table, name, name_length+1, &value, sizeof(zval *), NULL);
3276 }
3277 /* }}} */
3278
zend_declare_class_constant_null(zend_class_entry * ce,const char * name,size_t name_length TSRMLS_DC)3279 ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length TSRMLS_DC) /* {{{ */
3280 {
3281 zval *constant;
3282
3283 if (ce->type & ZEND_INTERNAL_CLASS) {
3284 ALLOC_PERMANENT_ZVAL(constant);
3285 } else {
3286 ALLOC_ZVAL(constant);
3287 }
3288 ZVAL_NULL(constant);
3289 INIT_PZVAL(constant);
3290 return zend_declare_class_constant(ce, name, name_length, constant TSRMLS_CC);
3291 }
3292 /* }}} */
3293
zend_declare_class_constant_long(zend_class_entry * ce,const char * name,size_t name_length,long value TSRMLS_DC)3294 ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, long value TSRMLS_DC) /* {{{ */
3295 {
3296 zval *constant;
3297
3298 if (ce->type & ZEND_INTERNAL_CLASS) {
3299 ALLOC_PERMANENT_ZVAL(constant);
3300 } else {
3301 ALLOC_ZVAL(constant);
3302 }
3303 ZVAL_LONG(constant, value);
3304 INIT_PZVAL(constant);
3305 return zend_declare_class_constant(ce, name, name_length, constant TSRMLS_CC);
3306 }
3307 /* }}} */
3308
zend_declare_class_constant_bool(zend_class_entry * ce,const char * name,size_t name_length,zend_bool value TSRMLS_DC)3309 ZEND_API int zend_declare_class_constant_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_bool value TSRMLS_DC) /* {{{ */
3310 {
3311 zval *constant;
3312
3313 if (ce->type & ZEND_INTERNAL_CLASS) {
3314 ALLOC_PERMANENT_ZVAL(constant);
3315 } else {
3316 ALLOC_ZVAL(constant);
3317 }
3318 ZVAL_BOOL(constant, value);
3319 INIT_PZVAL(constant);
3320 return zend_declare_class_constant(ce, name, name_length, constant TSRMLS_CC);
3321 }
3322 /* }}} */
3323
zend_declare_class_constant_double(zend_class_entry * ce,const char * name,size_t name_length,double value TSRMLS_DC)3324 ZEND_API int zend_declare_class_constant_double(zend_class_entry *ce, const char *name, size_t name_length, double value TSRMLS_DC) /* {{{ */
3325 {
3326 zval *constant;
3327
3328 if (ce->type & ZEND_INTERNAL_CLASS) {
3329 ALLOC_PERMANENT_ZVAL(constant);
3330 } else {
3331 ALLOC_ZVAL(constant);
3332 }
3333 ZVAL_DOUBLE(constant, value);
3334 INIT_PZVAL(constant);
3335 return zend_declare_class_constant(ce, name, name_length, constant TSRMLS_CC);
3336 }
3337 /* }}} */
3338
zend_declare_class_constant_stringl(zend_class_entry * ce,const char * name,size_t name_length,const char * value,size_t value_length TSRMLS_DC)3339 ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length TSRMLS_DC) /* {{{ */
3340 {
3341 zval *constant;
3342
3343 if (ce->type & ZEND_INTERNAL_CLASS) {
3344 ALLOC_PERMANENT_ZVAL(constant);
3345 ZVAL_STRINGL(constant, zend_strndup(value, value_length), value_length, 0);
3346 } else {
3347 ALLOC_ZVAL(constant);
3348 ZVAL_STRINGL(constant, value, value_length, 1);
3349 }
3350 INIT_PZVAL(constant);
3351 return zend_declare_class_constant(ce, name, name_length, constant TSRMLS_CC);
3352 }
3353 /* }}} */
3354
zend_declare_class_constant_string(zend_class_entry * ce,const char * name,size_t name_length,const char * value TSRMLS_DC)3355 ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value TSRMLS_DC) /* {{{ */
3356 {
3357 return zend_declare_class_constant_stringl(ce, name, name_length, value, strlen(value) TSRMLS_CC);
3358 }
3359 /* }}} */
3360
zend_update_property(zend_class_entry * scope,zval * object,char * name,int name_length,zval * value TSRMLS_DC)3361 ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, char *name, int name_length, zval *value TSRMLS_DC) /* {{{ */
3362 {
3363 zval *property;
3364 zend_class_entry *old_scope = EG(scope);
3365
3366 EG(scope) = scope;
3367
3368 if (!Z_OBJ_HT_P(object)->write_property) {
3369 char *class_name;
3370 zend_uint class_name_len;
3371
3372 zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC);
3373
3374 zend_error(E_CORE_ERROR, "Property %s of class %s cannot be updated", name, class_name);
3375 }
3376 MAKE_STD_ZVAL(property);
3377 ZVAL_STRINGL(property, name, name_length, 1);
3378 Z_OBJ_HT_P(object)->write_property(object, property, value TSRMLS_CC);
3379 zval_ptr_dtor(&property);
3380
3381 EG(scope) = old_scope;
3382 }
3383 /* }}} */
3384
zend_update_property_null(zend_class_entry * scope,zval * object,char * name,int name_length TSRMLS_DC)3385 ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, char *name, int name_length TSRMLS_DC) /* {{{ */
3386 {
3387 zval *tmp;
3388
3389 ALLOC_ZVAL(tmp);
3390 Z_UNSET_ISREF_P(tmp);
3391 Z_SET_REFCOUNT_P(tmp, 0);
3392 ZVAL_NULL(tmp);
3393 zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC);
3394 }
3395 /* }}} */
3396
zend_update_property_bool(zend_class_entry * scope,zval * object,char * name,int name_length,long value TSRMLS_DC)3397 ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, char *name, int name_length, long value TSRMLS_DC) /* {{{ */
3398 {
3399 zval *tmp;
3400
3401 ALLOC_ZVAL(tmp);
3402 Z_UNSET_ISREF_P(tmp);
3403 Z_SET_REFCOUNT_P(tmp, 0);
3404 ZVAL_BOOL(tmp, value);
3405 zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC);
3406 }
3407 /* }}} */
3408
zend_update_property_long(zend_class_entry * scope,zval * object,char * name,int name_length,long value TSRMLS_DC)3409 ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, char *name, int name_length, long value TSRMLS_DC) /* {{{ */
3410 {
3411 zval *tmp;
3412
3413 ALLOC_ZVAL(tmp);
3414 Z_UNSET_ISREF_P(tmp);
3415 Z_SET_REFCOUNT_P(tmp, 0);
3416 ZVAL_LONG(tmp, value);
3417 zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC);
3418 }
3419 /* }}} */
3420
zend_update_property_double(zend_class_entry * scope,zval * object,char * name,int name_length,double value TSRMLS_DC)3421 ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, char *name, int name_length, double value TSRMLS_DC) /* {{{ */
3422 {
3423 zval *tmp;
3424
3425 ALLOC_ZVAL(tmp);
3426 Z_UNSET_ISREF_P(tmp);
3427 Z_SET_REFCOUNT_P(tmp, 0);
3428 ZVAL_DOUBLE(tmp, value);
3429 zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC);
3430 }
3431 /* }}} */
3432
zend_update_property_string(zend_class_entry * scope,zval * object,char * name,int name_length,const char * value TSRMLS_DC)3433 ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, char *name, int name_length, const char *value TSRMLS_DC) /* {{{ */
3434 {
3435 zval *tmp;
3436
3437 ALLOC_ZVAL(tmp);
3438 Z_UNSET_ISREF_P(tmp);
3439 Z_SET_REFCOUNT_P(tmp, 0);
3440 ZVAL_STRING(tmp, value, 1);
3441 zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC);
3442 }
3443 /* }}} */
3444
zend_update_property_stringl(zend_class_entry * scope,zval * object,char * name,int name_length,const char * value,int value_len TSRMLS_DC)3445 ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, char *name, int name_length, const char *value, int value_len TSRMLS_DC) /* {{{ */
3446 {
3447 zval *tmp;
3448
3449 ALLOC_ZVAL(tmp);
3450 Z_UNSET_ISREF_P(tmp);
3451 Z_SET_REFCOUNT_P(tmp, 0);
3452 ZVAL_STRINGL(tmp, value, value_len, 1);
3453 zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC);
3454 }
3455 /* }}} */
3456
zend_update_static_property(zend_class_entry * scope,char * name,int name_length,zval * value TSRMLS_DC)3457 ZEND_API int zend_update_static_property(zend_class_entry *scope, char *name, int name_length, zval *value TSRMLS_DC) /* {{{ */
3458 {
3459 zval **property;
3460 zend_class_entry *old_scope = EG(scope);
3461
3462 EG(scope) = scope;
3463 property = zend_std_get_static_property(scope, name, name_length, 0 TSRMLS_CC);
3464 EG(scope) = old_scope;
3465 if (!property) {
3466 return FAILURE;
3467 } else {
3468 if (*property != value) {
3469 if (PZVAL_IS_REF(*property)) {
3470 zval_dtor(*property);
3471 Z_TYPE_PP(property) = Z_TYPE_P(value);
3472 (*property)->value = value->value;
3473 if (Z_REFCOUNT_P(value) > 0) {
3474 zval_copy_ctor(*property);
3475 } else {
3476 efree(value);
3477 }
3478 } else {
3479 zval *garbage = *property;
3480
3481 Z_ADDREF_P(value);
3482 if (PZVAL_IS_REF(value)) {
3483 SEPARATE_ZVAL(&value);
3484 }
3485 *property = value;
3486 zval_ptr_dtor(&garbage);
3487 }
3488 }
3489 return SUCCESS;
3490 }
3491 }
3492 /* }}} */
3493
zend_update_static_property_null(zend_class_entry * scope,char * name,int name_length TSRMLS_DC)3494 ZEND_API int zend_update_static_property_null(zend_class_entry *scope, char *name, int name_length TSRMLS_DC) /* {{{ */
3495 {
3496 zval *tmp;
3497
3498 ALLOC_ZVAL(tmp);
3499 Z_UNSET_ISREF_P(tmp);
3500 Z_SET_REFCOUNT_P(tmp, 0);
3501 ZVAL_NULL(tmp);
3502 return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC);
3503 }
3504 /* }}} */
3505
zend_update_static_property_bool(zend_class_entry * scope,char * name,int name_length,long value TSRMLS_DC)3506 ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, char *name, int name_length, long value TSRMLS_DC) /* {{{ */
3507 {
3508 zval *tmp;
3509
3510 ALLOC_ZVAL(tmp);
3511 Z_UNSET_ISREF_P(tmp);
3512 Z_SET_REFCOUNT_P(tmp, 0);
3513 ZVAL_BOOL(tmp, value);
3514 return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC);
3515 }
3516 /* }}} */
3517
zend_update_static_property_long(zend_class_entry * scope,char * name,int name_length,long value TSRMLS_DC)3518 ZEND_API int zend_update_static_property_long(zend_class_entry *scope, char *name, int name_length, long value TSRMLS_DC) /* {{{ */
3519 {
3520 zval *tmp;
3521
3522 ALLOC_ZVAL(tmp);
3523 Z_UNSET_ISREF_P(tmp);
3524 Z_SET_REFCOUNT_P(tmp, 0);
3525 ZVAL_LONG(tmp, value);
3526 return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC);
3527 }
3528 /* }}} */
3529
zend_update_static_property_double(zend_class_entry * scope,char * name,int name_length,double value TSRMLS_DC)3530 ZEND_API int zend_update_static_property_double(zend_class_entry *scope, char *name, int name_length, double value TSRMLS_DC) /* {{{ */
3531 {
3532 zval *tmp;
3533
3534 ALLOC_ZVAL(tmp);
3535 Z_UNSET_ISREF_P(tmp);
3536 Z_SET_REFCOUNT_P(tmp, 0);
3537 ZVAL_DOUBLE(tmp, value);
3538 return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC);
3539 }
3540 /* }}} */
3541
zend_update_static_property_string(zend_class_entry * scope,char * name,int name_length,const char * value TSRMLS_DC)3542 ZEND_API int zend_update_static_property_string(zend_class_entry *scope, char *name, int name_length, const char *value TSRMLS_DC) /* {{{ */
3543 {
3544 zval *tmp;
3545
3546 ALLOC_ZVAL(tmp);
3547 Z_UNSET_ISREF_P(tmp);
3548 Z_SET_REFCOUNT_P(tmp, 0);
3549 ZVAL_STRING(tmp, value, 1);
3550 return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC);
3551 }
3552 /* }}} */
3553
zend_update_static_property_stringl(zend_class_entry * scope,char * name,int name_length,const char * value,int value_len TSRMLS_DC)3554 ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, char *name, int name_length, const char *value, int value_len TSRMLS_DC) /* {{{ */
3555 {
3556 zval *tmp;
3557
3558 ALLOC_ZVAL(tmp);
3559 Z_UNSET_ISREF_P(tmp);
3560 Z_SET_REFCOUNT_P(tmp, 0);
3561 ZVAL_STRINGL(tmp, value, value_len, 1);
3562 return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC);
3563 }
3564 /* }}} */
3565
zend_read_property(zend_class_entry * scope,zval * object,char * name,int name_length,zend_bool silent TSRMLS_DC)3566 ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, char *name, int name_length, zend_bool silent TSRMLS_DC) /* {{{ */
3567 {
3568 zval *property, *value;
3569 zend_class_entry *old_scope = EG(scope);
3570
3571 EG(scope) = scope;
3572
3573 if (!Z_OBJ_HT_P(object)->read_property) {
3574 char *class_name;
3575 zend_uint class_name_len;
3576
3577 zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC);
3578 zend_error(E_CORE_ERROR, "Property %s of class %s cannot be read", name, class_name);
3579 }
3580
3581 MAKE_STD_ZVAL(property);
3582 ZVAL_STRINGL(property, name, name_length, 1);
3583 value = Z_OBJ_HT_P(object)->read_property(object, property, silent?BP_VAR_IS:BP_VAR_R TSRMLS_CC);
3584 zval_ptr_dtor(&property);
3585
3586 EG(scope) = old_scope;
3587 return value;
3588 }
3589 /* }}} */
3590
zend_read_static_property(zend_class_entry * scope,char * name,int name_length,zend_bool silent TSRMLS_DC)3591 ZEND_API zval *zend_read_static_property(zend_class_entry *scope, char *name, int name_length, zend_bool silent TSRMLS_DC) /* {{{ */
3592 {
3593 zval **property;
3594 zend_class_entry *old_scope = EG(scope);
3595
3596 EG(scope) = scope;
3597 property = zend_std_get_static_property(scope, name, name_length, silent TSRMLS_CC);
3598 EG(scope) = old_scope;
3599
3600 return property?*property:NULL;
3601 }
3602 /* }}} */
3603
zend_save_error_handling(zend_error_handling * current TSRMLS_DC)3604 ZEND_API void zend_save_error_handling(zend_error_handling *current TSRMLS_DC) /* {{{ */
3605 {
3606 current->handling = EG(error_handling);
3607 current->exception = EG(exception_class);
3608 current->user_handler = EG(user_error_handler);
3609 if (current->user_handler) {
3610 Z_ADDREF_P(current->user_handler);
3611 }
3612 }
3613 /* }}} */
3614
zend_replace_error_handling(zend_error_handling_t error_handling,zend_class_entry * exception_class,zend_error_handling * current TSRMLS_DC)3615 ZEND_API void zend_replace_error_handling(zend_error_handling_t error_handling, zend_class_entry *exception_class, zend_error_handling *current TSRMLS_DC) /* {{{ */
3616 {
3617 if (current) {
3618 zend_save_error_handling(current TSRMLS_CC);
3619 if (error_handling != EH_NORMAL && EG(user_error_handler)) {
3620 zval_ptr_dtor(&EG(user_error_handler));
3621 EG(user_error_handler) = NULL;
3622 }
3623 }
3624 EG(error_handling) = error_handling;
3625 EG(exception_class) = error_handling == EH_THROW ? exception_class : NULL;
3626 }
3627 /* }}} */
3628
zend_restore_error_handling(zend_error_handling * saved TSRMLS_DC)3629 ZEND_API void zend_restore_error_handling(zend_error_handling *saved TSRMLS_DC) /* {{{ */
3630 {
3631 EG(error_handling) = saved->handling;
3632 EG(exception_class) = saved->handling == EH_THROW ? saved->exception : NULL;
3633 if (saved->user_handler && saved->user_handler != EG(user_error_handler)) {
3634 if (EG(user_error_handler)) {
3635 zval_ptr_dtor(&EG(user_error_handler));
3636 }
3637 EG(user_error_handler) = saved->user_handler;
3638 } else if (saved->user_handler) {
3639 zval_ptr_dtor(&saved->user_handler);
3640 }
3641 saved->user_handler = NULL;
3642 }
3643 /* }}} */
3644
3645 /*
3646 * Local variables:
3647 * tab-width: 4
3648 * c-basic-offset: 4
3649 * indent-tabs-mode: t
3650 * End:
3651 */
3652