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