1 : /*
2 : +----------------------------------------------------------------------+
3 : | Zend Engine |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1998-2009 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 : +----------------------------------------------------------------------+
18 : */
19 :
20 : /* $Id: zend_builtin_functions.c 282907 2009-06-28 01:16:36Z felipe $ */
21 :
22 : #include "zend.h"
23 : #include "zend_API.h"
24 : #include "zend_builtin_functions.h"
25 : #include "zend_constants.h"
26 : #include "zend_ini.h"
27 : #include "zend_exceptions.h"
28 : #include "zend_extensions.h"
29 :
30 : #undef ZEND_TEST_EXCEPTIONS
31 :
32 : static ZEND_FUNCTION(zend_version);
33 : static ZEND_FUNCTION(func_num_args);
34 : static ZEND_FUNCTION(func_get_arg);
35 : static ZEND_FUNCTION(func_get_args);
36 : static ZEND_FUNCTION(strlen);
37 : static ZEND_FUNCTION(strcmp);
38 : static ZEND_FUNCTION(strncmp);
39 : static ZEND_FUNCTION(strcasecmp);
40 : static ZEND_FUNCTION(strncasecmp);
41 : static ZEND_FUNCTION(each);
42 : static ZEND_FUNCTION(error_reporting);
43 : static ZEND_FUNCTION(define);
44 : static ZEND_FUNCTION(defined);
45 : static ZEND_FUNCTION(get_class);
46 : static ZEND_FUNCTION(get_parent_class);
47 : static ZEND_FUNCTION(method_exists);
48 : static ZEND_FUNCTION(property_exists);
49 : static ZEND_FUNCTION(class_exists);
50 : static ZEND_FUNCTION(interface_exists);
51 : static ZEND_FUNCTION(function_exists);
52 : #if ZEND_DEBUG
53 : static ZEND_FUNCTION(leak);
54 : #ifdef ZEND_TEST_EXCEPTIONS
55 : static ZEND_FUNCTION(crash);
56 : #endif
57 : #endif
58 : static ZEND_FUNCTION(get_included_files);
59 : static ZEND_FUNCTION(is_subclass_of);
60 : static ZEND_FUNCTION(is_a);
61 : static ZEND_FUNCTION(get_class_vars);
62 : static ZEND_FUNCTION(get_object_vars);
63 : static ZEND_FUNCTION(get_class_methods);
64 : static ZEND_FUNCTION(trigger_error);
65 : static ZEND_FUNCTION(set_error_handler);
66 : static ZEND_FUNCTION(restore_error_handler);
67 : static ZEND_FUNCTION(set_exception_handler);
68 : static ZEND_FUNCTION(restore_exception_handler);
69 : static ZEND_FUNCTION(get_declared_classes);
70 : static ZEND_FUNCTION(get_declared_interfaces);
71 : static ZEND_FUNCTION(get_defined_functions);
72 : static ZEND_FUNCTION(get_defined_vars);
73 : static ZEND_FUNCTION(create_function);
74 : static ZEND_FUNCTION(get_resource_type);
75 : static ZEND_FUNCTION(get_loaded_extensions);
76 : static ZEND_FUNCTION(extension_loaded);
77 : static ZEND_FUNCTION(get_extension_funcs);
78 : static ZEND_FUNCTION(get_defined_constants);
79 : static ZEND_FUNCTION(debug_backtrace);
80 : static ZEND_FUNCTION(debug_print_backtrace);
81 : #if ZEND_DEBUG
82 : static ZEND_FUNCTION(zend_test_func);
83 : #ifdef ZTS
84 : static ZEND_FUNCTION(zend_thread_id);
85 : #endif
86 : #endif
87 :
88 : #include "zend_arg_defs.c"
89 :
90 :
91 : static zend_function_entry builtin_functions[] = {
92 : ZEND_FE(zend_version, NULL)
93 : ZEND_FE(func_num_args, NULL)
94 : ZEND_FE(func_get_arg, NULL)
95 : ZEND_FE(func_get_args, NULL)
96 : ZEND_FE(strlen, NULL)
97 : ZEND_FE(strcmp, NULL)
98 : ZEND_FE(strncmp, NULL)
99 : ZEND_FE(strcasecmp, NULL)
100 : ZEND_FE(strncasecmp, NULL)
101 : ZEND_FE(each, first_arg_force_ref)
102 : ZEND_FE(error_reporting, NULL)
103 : ZEND_FE(define, NULL)
104 : ZEND_FE(defined, NULL)
105 : ZEND_FE(get_class, NULL)
106 : ZEND_FE(get_parent_class, NULL)
107 : ZEND_FE(method_exists, NULL)
108 : ZEND_FE(property_exists, NULL)
109 : ZEND_FE(class_exists, NULL)
110 : ZEND_FE(interface_exists, NULL)
111 : ZEND_FE(function_exists, NULL)
112 : #if ZEND_DEBUG
113 : ZEND_FE(leak, NULL)
114 : #ifdef ZEND_TEST_EXCEPTIONS
115 : ZEND_FE(crash, NULL)
116 : #endif
117 : #endif
118 : ZEND_FE(get_included_files, NULL)
119 : ZEND_FALIAS(get_required_files, get_included_files, NULL)
120 : ZEND_FE(is_subclass_of, NULL)
121 : ZEND_FE(is_a, NULL)
122 : ZEND_FE(get_class_vars, NULL)
123 : ZEND_FE(get_object_vars, NULL)
124 : ZEND_FE(get_class_methods, NULL)
125 : ZEND_FE(trigger_error, NULL)
126 : ZEND_FALIAS(user_error, trigger_error, NULL)
127 : ZEND_FE(set_error_handler, NULL)
128 : ZEND_FE(restore_error_handler, NULL)
129 : ZEND_FE(set_exception_handler, NULL)
130 : ZEND_FE(restore_exception_handler, NULL)
131 : ZEND_FE(get_declared_classes, NULL)
132 : ZEND_FE(get_declared_interfaces, NULL)
133 : ZEND_FE(get_defined_functions, NULL)
134 : ZEND_FE(get_defined_vars, NULL)
135 : ZEND_FE(create_function, NULL)
136 : ZEND_FE(get_resource_type, NULL)
137 : ZEND_FE(get_loaded_extensions, NULL)
138 : ZEND_FE(extension_loaded, NULL)
139 : ZEND_FE(get_extension_funcs, NULL)
140 : ZEND_FE(get_defined_constants, NULL)
141 : ZEND_FE(debug_backtrace, NULL)
142 : ZEND_FE(debug_print_backtrace, NULL)
143 : #if ZEND_DEBUG
144 : ZEND_FE(zend_test_func, NULL)
145 : #ifdef ZTS
146 : ZEND_FE(zend_thread_id, NULL)
147 : #endif
148 : #endif
149 : { NULL, NULL, NULL }
150 : };
151 :
152 :
153 : int zend_startup_builtin_functions(TSRMLS_D)
154 13565 : {
155 13565 : return zend_register_functions(NULL, builtin_functions, NULL, MODULE_PERSISTENT TSRMLS_CC);
156 : }
157 :
158 :
159 : /* {{{ proto string zend_version(void)
160 : Get the version of the Zend Engine */
161 : ZEND_FUNCTION(zend_version)
162 136 : {
163 136 : RETURN_STRINGL(ZEND_VERSION, sizeof(ZEND_VERSION)-1, 1);
164 : }
165 : /* }}} */
166 :
167 :
168 : /* {{{ proto int func_num_args(void)
169 : Get the number of arguments that were passed to the function */
170 : ZEND_FUNCTION(func_num_args)
171 16 : {
172 : void **p;
173 : int arg_count;
174 :
175 16 : p = EG(argument_stack).top_element-1-1;
176 16 : arg_count = (int)(zend_uintptr_t) *p; /* this is the amount of arguments passed to func_num_args(); */
177 16 : p -= 1+arg_count;
178 16 : if (*p) {
179 0 : zend_error(E_ERROR, "func_num_args(): Can't be used as a function parameter");
180 : }
181 16 : --p;
182 16 : if (p>=EG(argument_stack).elements) {
183 14 : RETURN_LONG((long)(zend_uintptr_t) *p);
184 : } else {
185 2 : zend_error(E_WARNING, "func_num_args(): Called from the global scope - no function context");
186 2 : RETURN_LONG(-1);
187 : }
188 : }
189 : /* }}} */
190 :
191 :
192 : /* {{{ proto mixed func_get_arg(int arg_num)
193 : Get the $arg_num'th argument that was passed to the function */
194 : ZEND_FUNCTION(func_get_arg)
195 41 : {
196 : void **p;
197 : int arg_count;
198 : zval **z_requested_offset;
199 : zval *arg;
200 : long requested_offset;
201 :
202 41 : if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &z_requested_offset)==FAILURE) {
203 4 : RETURN_FALSE;
204 : }
205 37 : convert_to_long_ex(z_requested_offset);
206 37 : requested_offset = Z_LVAL_PP(z_requested_offset);
207 :
208 37 : if (requested_offset < 0) {
209 4 : zend_error(E_WARNING, "func_get_arg(): The argument number should be >= 0");
210 4 : RETURN_FALSE;
211 : }
212 :
213 33 : p = EG(argument_stack).top_element-1-1;
214 33 : arg_count = (int)(zend_uintptr_t) *p; /* this is the amount of arguments passed to func_get_arg(); */
215 33 : p -= 1+arg_count;
216 33 : if (*p) {
217 0 : zend_error(E_ERROR, "func_get_arg(): Can't be used as a function parameter");
218 : }
219 33 : --p;
220 33 : if (p<EG(argument_stack).elements) {
221 3 : zend_error(E_WARNING, "func_get_arg(): Called from the global scope - no function context");
222 3 : RETURN_FALSE;
223 : }
224 30 : arg_count = (int)(zend_uintptr_t) *p;
225 :
226 30 : if (requested_offset>=arg_count) {
227 16 : zend_error(E_WARNING, "func_get_arg(): Argument %ld not passed to function", requested_offset);
228 16 : RETURN_FALSE;
229 : }
230 :
231 14 : arg = *(p-(arg_count-requested_offset));
232 14 : *return_value = *arg;
233 14 : zval_copy_ctor(return_value);
234 14 : INIT_PZVAL(return_value);
235 : }
236 : /* }}} */
237 :
238 :
239 : /* {{{ proto array func_get_args()
240 : Get an array of the arguments that were passed to the function */
241 : ZEND_FUNCTION(func_get_args)
242 59 : {
243 : void **p;
244 : int arg_count;
245 : int i;
246 :
247 59 : p = EG(argument_stack).top_element-1-1;
248 59 : arg_count = (int)(zend_uintptr_t) *p; /* this is the amount of arguments passed to func_get_args(); */
249 59 : p -= 1+arg_count;
250 59 : if (*p) {
251 0 : zend_error(E_ERROR, "func_get_args(): Can't be used as a function parameter");
252 : }
253 59 : --p;
254 :
255 59 : if (p<EG(argument_stack).elements) {
256 2 : zend_error(E_WARNING, "func_get_args(): Called from the global scope - no function context");
257 2 : RETURN_FALSE;
258 : }
259 57 : arg_count = (int)(zend_uintptr_t) *p;
260 :
261 :
262 57 : array_init(return_value);
263 117 : for (i=0; i<arg_count; i++) {
264 : zval *element;
265 :
266 60 : ALLOC_ZVAL(element);
267 60 : *element = **((zval **) (p-(arg_count-i)));
268 60 : zval_copy_ctor(element);
269 60 : INIT_PZVAL(element);
270 60 : zend_hash_next_index_insert(return_value->value.ht, &element, sizeof(zval *), NULL);
271 : }
272 : }
273 : /* }}} */
274 :
275 :
276 : /* {{{ proto int strlen(string str)
277 : Get string length */
278 : ZEND_FUNCTION(strlen)
279 636313 : {
280 : zval **str;
281 :
282 636313 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
283 5 : ZEND_WRONG_PARAM_COUNT();
284 : }
285 636308 : convert_to_string_ex(str);
286 636308 : RETVAL_LONG(Z_STRLEN_PP(str));
287 : }
288 : /* }}} */
289 :
290 :
291 : /* {{{ proto int strcmp(string str1, string str2)
292 : Binary safe string comparison */
293 : ZEND_FUNCTION(strcmp)
294 852147 : {
295 : zval **s1, **s2;
296 :
297 852147 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
298 4 : ZEND_WRONG_PARAM_COUNT();
299 : }
300 852143 : convert_to_string_ex(s1);
301 852143 : convert_to_string_ex(s2);
302 852143 : RETURN_LONG(zend_binary_zval_strcmp(*s1, *s2));
303 : }
304 : /* }}} */
305 :
306 :
307 : /* {{{ proto int strncmp(string str1, string str2, int len)
308 : Binary safe string comparison */
309 : ZEND_FUNCTION(strncmp)
310 9789 : {
311 : zval **s1, **s2, **s3;
312 :
313 9789 : if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &s1, &s2, &s3) == FAILURE) {
314 5 : ZEND_WRONG_PARAM_COUNT();
315 : }
316 9784 : convert_to_string_ex(s1);
317 9784 : convert_to_string_ex(s2);
318 9784 : convert_to_long_ex(s3);
319 :
320 9784 : if (Z_LVAL_PP(s3) < 0) {
321 3 : zend_error(E_WARNING, "Length must be greater than or equal to 0");
322 3 : RETURN_FALSE;
323 : }
324 :
325 9781 : RETURN_LONG(zend_binary_zval_strncmp(*s1, *s2, *s3));
326 : }
327 : /* }}} */
328 :
329 :
330 : /* {{{ proto int strcasecmp(string str1, string str2)
331 : Binary safe case-insensitive string comparison */
332 : ZEND_FUNCTION(strcasecmp)
333 1035 : {
334 : zval **s1, **s2;
335 :
336 1035 : if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
337 5 : ZEND_WRONG_PARAM_COUNT();
338 : }
339 1030 : convert_to_string_ex(s1);
340 1030 : convert_to_string_ex(s2);
341 1030 : RETURN_LONG(zend_binary_zval_strcasecmp(*s1, *s2));
342 : }
343 : /* }}} */
344 :
345 :
346 : /* {{{ proto int strncasecmp(string str1, string str2, int len)
347 : Binary safe string comparison */
348 : ZEND_FUNCTION(strncasecmp)
349 13767 : {
350 : zval **s1, **s2, **s3;
351 :
352 13767 : if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &s1, &s2, &s3) == FAILURE) {
353 5 : ZEND_WRONG_PARAM_COUNT();
354 : }
355 13762 : convert_to_string_ex(s1);
356 13762 : convert_to_string_ex(s2);
357 13762 : convert_to_long_ex(s3);
358 :
359 13762 : if (Z_LVAL_PP(s3) < 0) {
360 3 : zend_error(E_WARNING, "Length must be greater than or equal to 0");
361 3 : RETURN_FALSE;
362 : }
363 :
364 13759 : RETURN_LONG(zend_binary_zval_strncasecmp(*s1, *s2, *s3));
365 : }
366 : /* }}} */
367 :
368 :
369 : /* {{{ proto array each(array arr)
370 : Return the currently pointed key..value pair in the passed array, and advance the pointer to the next element */
371 : ZEND_FUNCTION(each)
372 219 : {
373 : zval **array, *entry, **entry_ptr, *tmp;
374 : char *string_key;
375 : uint string_key_len;
376 : ulong num_key;
377 : zval **inserted_pointer;
378 : HashTable *target_hash;
379 :
380 219 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
381 5 : ZEND_WRONG_PARAM_COUNT();
382 : }
383 :
384 214 : target_hash = HASH_OF(*array);
385 214 : if (!target_hash) {
386 28 : zend_error(E_WARNING,"Variable passed to each() is not an array or object");
387 28 : return;
388 : }
389 186 : if (zend_hash_get_current_data(target_hash, (void **) &entry_ptr)==FAILURE) {
390 37 : RETURN_FALSE;
391 : }
392 149 : array_init(return_value);
393 149 : entry = *entry_ptr;
394 :
395 : /* add value elements */
396 149 : if (entry->is_ref) {
397 3 : ALLOC_ZVAL(tmp);
398 3 : *tmp = *entry;
399 3 : zval_copy_ctor(tmp);
400 3 : tmp->is_ref=0;
401 3 : tmp->refcount=0;
402 3 : entry=tmp;
403 : }
404 149 : zend_hash_index_update(return_value->value.ht, 1, &entry, sizeof(zval *), NULL);
405 149 : entry->refcount++;
406 149 : zend_hash_update(return_value->value.ht, "value", sizeof("value"), &entry, sizeof(zval *), NULL);
407 149 : entry->refcount++;
408 :
409 : /* add the key elements */
410 149 : switch (zend_hash_get_current_key_ex(target_hash, &string_key, &string_key_len, &num_key, 1, NULL)) {
411 : case HASH_KEY_IS_STRING:
412 35 : add_get_index_stringl(return_value, 0, string_key, string_key_len-1, (void **) &inserted_pointer, 0);
413 35 : break;
414 : case HASH_KEY_IS_LONG:
415 114 : add_get_index_long(return_value, 0, num_key, (void **) &inserted_pointer);
416 : break;
417 : }
418 149 : zend_hash_update(return_value->value.ht, "key", sizeof("key"), inserted_pointer, sizeof(zval *), NULL);
419 149 : (*inserted_pointer)->refcount++;
420 149 : zend_hash_move_forward(target_hash);
421 : }
422 : /* }}} */
423 :
424 :
425 : /* {{{ proto int error_reporting(int new_error_level=null)
426 : Return the current error_reporting level, and if an argument was passed - change to the new level */
427 : ZEND_FUNCTION(error_reporting)
428 1775 : {
429 : zval **arg;
430 : int old_error_reporting;
431 :
432 1775 : old_error_reporting = EG(error_reporting);
433 1775 : switch (ZEND_NUM_ARGS()) {
434 : case 0:
435 1568 : break;
436 : case 1:
437 207 : if (zend_get_parameters_ex(1, &arg) == FAILURE) {
438 0 : RETURN_FALSE;
439 : }
440 207 : convert_to_string_ex(arg);
441 207 : zend_alter_ini_entry("error_reporting", sizeof("error_reporting"), Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
442 207 : break;
443 : default:
444 0 : ZEND_WRONG_PARAM_COUNT();
445 : break;
446 : }
447 :
448 1775 : RETVAL_LONG(old_error_reporting);
449 : }
450 : /* }}} */
451 :
452 :
453 : /* {{{ proto bool define(string constant_name, mixed value, boolean case_sensitive=true)
454 : Define a new constant */
455 : ZEND_FUNCTION(define)
456 245 : {
457 : char *name;
458 : int name_len;
459 : zval *val;
460 245 : zval *val_free = NULL;
461 245 : zend_bool non_cs = 0;
462 245 : int case_sensitive = CONST_CS;
463 : zend_constant c;
464 : char *p;
465 :
466 245 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {
467 4 : return;
468 : }
469 :
470 241 : if(non_cs) {
471 124 : case_sensitive = 0;
472 : }
473 :
474 : /* class constant, check if there is name and make sure class is valid & exists */
475 241 : if ((p = zend_memnstr(name, "::", sizeof("::") - 1, name + name_len))) {
476 : char *class_name;
477 : int found;
478 : zend_class_entry **ce;
479 : ALLOCA_FLAG(use_heap)
480 :
481 1 : if (p == (name + name_len - sizeof("::") + 1)) {
482 1 : zend_error(E_WARNING, "Class constant must have a name");
483 1 : RETURN_FALSE;
484 0 : } else if (p == name) {
485 0 : zend_error(E_WARNING, "Missing class name");
486 0 : RETURN_FALSE;
487 : }
488 :
489 0 : class_name = do_alloca_with_limit((p - name + 1), use_heap);
490 0 : zend_str_tolower_copy(class_name, name, (p - name));
491 :
492 0 : found = zend_hash_find(EG(class_table), class_name, p - name + 1, (void **) &ce);
493 :
494 0 : if (found != SUCCESS) {
495 0 : zend_error(E_WARNING, "Class '%s' does not exist", class_name);
496 0 : free_alloca_with_limit(class_name, use_heap);
497 0 : RETURN_FALSE;
498 : }
499 0 : free_alloca_with_limit(class_name, use_heap);
500 : }
501 :
502 240 : repeat:
503 240 : switch (Z_TYPE_P(val)) {
504 : case IS_LONG:
505 : case IS_DOUBLE:
506 : case IS_STRING:
507 : case IS_BOOL:
508 : case IS_RESOURCE:
509 : case IS_NULL:
510 236 : break;
511 : case IS_OBJECT:
512 3 : if (!val_free) {
513 3 : if (Z_OBJ_HT_P(val)->get) {
514 0 : val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);
515 0 : goto repeat;
516 3 : } else if (Z_OBJ_HT_P(val)->cast_object) {
517 3 : ALLOC_INIT_ZVAL(val_free);
518 3 : if (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS) {
519 1 : val = val_free;
520 1 : break;
521 : }
522 : }
523 : }
524 : /* no break */
525 : default:
526 3 : zend_error(E_WARNING,"Constants may only evaluate to scalar values");
527 3 : if (val_free) {
528 2 : zval_ptr_dtor(&val_free);
529 : }
530 3 : RETURN_FALSE;
531 : }
532 :
533 237 : c.value = *val;
534 237 : zval_copy_ctor(&c.value);
535 237 : if (val_free) {
536 1 : zval_ptr_dtor(&val_free);
537 : }
538 237 : c.flags = case_sensitive; /* non persistent */
539 237 : c.name = zend_strndup(name, name_len);
540 237 : c.name_len = name_len+1;
541 237 : c.module_number = PHP_USER_CONSTANT;
542 237 : if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {
543 233 : RETURN_TRUE;
544 : } else {
545 4 : RETURN_FALSE;
546 : }
547 : }
548 : /* }}} */
549 :
550 :
551 : /* {{{ proto bool defined(string constant_name)
552 : Check whether a constant exists */
553 : ZEND_FUNCTION(defined)
554 81 : {
555 : zval **var;
556 : zval c;
557 :
558 81 : if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &var)==FAILURE) {
559 0 : ZEND_WRONG_PARAM_COUNT();
560 : }
561 :
562 81 : convert_to_string_ex(var);
563 81 : if (zend_get_constant(Z_STRVAL_PP(var), Z_STRLEN_PP(var), &c TSRMLS_CC)) {
564 74 : zval_dtor(&c);
565 74 : RETURN_TRUE;
566 : } else {
567 7 : RETURN_FALSE;
568 : }
569 : }
570 : /* }}} */
571 :
572 :
573 : /* {{{ proto string get_class([object object])
574 : Retrieves the class name */
575 : ZEND_FUNCTION(get_class)
576 294 : {
577 : zval **arg;
578 294 : char *name = "";
579 294 : zend_uint name_len = 0;
580 : int dup;
581 :
582 294 : if (!ZEND_NUM_ARGS()) {
583 5 : if (EG(scope)) {
584 4 : RETURN_STRINGL(EG(scope)->name, EG(scope)->name_length, 1);
585 : } else {
586 1 : zend_error(E_WARNING, "get_class() called without object from outside a class");
587 1 : RETURN_FALSE;
588 : }
589 : }
590 289 : if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &arg)==FAILURE) {
591 1 : ZEND_WRONG_PARAM_COUNT();
592 : }
593 288 : if (Z_TYPE_PP(arg) != IS_OBJECT) {
594 27 : RETURN_FALSE;
595 : }
596 :
597 261 : dup = zend_get_object_classname(*arg, &name, &name_len TSRMLS_CC);
598 :
599 261 : RETURN_STRINGL(name, name_len, dup);
600 : }
601 : /* }}} */
602 :
603 :
604 : /* {{{ proto string get_parent_class([mixed object])
605 : Retrieves the parent class name for object or class or current scope. */
606 : ZEND_FUNCTION(get_parent_class)
607 47 : {
608 : zval **arg;
609 47 : zend_class_entry *ce = NULL;
610 : char *name;
611 : zend_uint name_length;
612 :
613 47 : if (!ZEND_NUM_ARGS()) {
614 3 : ce = EG(scope);
615 3 : if (ce && ce->parent) {
616 1 : RETURN_STRINGL(ce->parent->name, ce->parent->name_length, 1);
617 : } else {
618 2 : RETURN_FALSE;
619 : }
620 : }
621 44 : if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &arg)==FAILURE) {
622 1 : ZEND_WRONG_PARAM_COUNT();
623 : }
624 :
625 43 : if (Z_TYPE_PP(arg) == IS_OBJECT) {
626 7 : if (Z_OBJ_HT_PP(arg)->get_class_name
627 : && Z_OBJ_HT_PP(arg)->get_class_name(*arg, &name, &name_length, 1 TSRMLS_CC) == SUCCESS) {
628 3 : RETURN_STRINGL(name, name_length, 0);
629 : } else {
630 4 : ce = zend_get_class_entry(*arg TSRMLS_CC);
631 : }
632 36 : } else if (Z_TYPE_PP(arg) == IS_STRING) {
633 : zend_class_entry **pce;
634 :
635 12 : if (zend_lookup_class(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), &pce TSRMLS_CC) == SUCCESS) {
636 5 : ce = *pce;
637 : }
638 : }
639 :
640 40 : if (ce && ce->parent) {
641 2 : RETURN_STRINGL(ce->parent->name, ce->parent->name_length, 1);
642 : } else {
643 38 : RETURN_FALSE;
644 : }
645 : }
646 : /* }}} */
647 :
648 :
649 : static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
650 144 : {
651 : zval **obj, **class_name;
652 : zend_class_entry *instance_ce;
653 : zend_class_entry **ce;
654 : zend_bool retval;
655 :
656 144 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &obj, &class_name)==FAILURE) {
657 4 : ZEND_WRONG_PARAM_COUNT();
658 : }
659 :
660 142 : if (only_subclass && Z_TYPE_PP(obj) == IS_STRING) {
661 : zend_class_entry **the_ce;
662 10 : if (zend_lookup_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), &the_ce TSRMLS_CC) == FAILURE) {
663 8 : zend_error(E_WARNING, "Unknown class passed as parameter");
664 8 : RETURN_FALSE;
665 : }
666 2 : instance_ce = *the_ce;
667 130 : } else if (Z_TYPE_PP(obj) != IS_OBJECT) {
668 70 : RETURN_FALSE;
669 : } else {
670 60 : instance_ce = NULL;
671 : }
672 :
673 : /* TBI!! new object handlers */
674 62 : if (Z_TYPE_PP(obj) == IS_OBJECT && !HAS_CLASS_ENTRY(**obj)) {
675 0 : RETURN_FALSE;
676 : }
677 :
678 62 : convert_to_string_ex(class_name);
679 :
680 62 : if (zend_lookup_class_ex(Z_STRVAL_PP(class_name), Z_STRLEN_PP(class_name), 0, &ce TSRMLS_CC) == FAILURE) {
681 53 : retval = 0;
682 : } else {
683 9 : if (only_subclass) {
684 5 : if (!instance_ce) {
685 4 : instance_ce = Z_OBJCE_PP(obj)->parent;
686 : } else {
687 1 : instance_ce = instance_ce->parent;
688 : }
689 : } else {
690 4 : instance_ce = Z_OBJCE_PP(obj);
691 : }
692 :
693 9 : if (!instance_ce) {
694 1 : RETURN_FALSE;
695 : }
696 :
697 8 : if (instanceof_function(instance_ce, *ce TSRMLS_CC)) {
698 6 : retval = 1;
699 : } else {
700 2 : retval = 0;
701 : }
702 : }
703 :
704 61 : RETURN_BOOL(retval);
705 : }
706 :
707 :
708 : /* {{{ proto bool is_subclass_of(object object, string class_name)
709 : Returns true if the object has this class as one of its parents */
710 : ZEND_FUNCTION(is_subclass_of)
711 86 : {
712 86 : is_a_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
713 86 : }
714 : /* }}} */
715 :
716 :
717 : /* {{{ proto bool is_a(object object, string class_name)
718 : Returns true if the object is of this class or has this class as one of its parents */
719 : ZEND_FUNCTION(is_a)
720 58 : {
721 58 : zend_error(E_STRICT, "is_a(): Deprecated. Please use the instanceof operator");
722 58 : is_a_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
723 58 : }
724 : /* }}} */
725 :
726 :
727 : /* {{{ add_class_vars */
728 : static void add_class_vars(zend_class_entry *ce, HashTable *properties, zval *return_value TSRMLS_DC)
729 64 : {
730 64 : if (zend_hash_num_elements(properties) > 0) {
731 : HashPosition pos;
732 : zval **prop;
733 :
734 45 : zend_hash_internal_pointer_reset_ex(properties, &pos);
735 214 : while (zend_hash_get_current_data_ex(properties, (void **) &prop, &pos) == SUCCESS) {
736 : char *key, *class_name, *prop_name;
737 : uint key_len;
738 : ulong num_index;
739 124 : int prop_name_len = 0;
740 : zval *prop_copy;
741 : zend_property_info *property_info;
742 : zval zprop_name;
743 :
744 124 : zend_hash_get_current_key_ex(properties, &key, &key_len, &num_index, 0, &pos);
745 124 : zend_hash_move_forward_ex(properties, &pos);
746 :
747 124 : zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name);
748 124 : prop_name_len = strlen(prop_name);
749 :
750 124 : ZVAL_STRINGL(&zprop_name, prop_name, prop_name_len, 0);
751 124 : property_info = zend_get_property_info(ce, &zprop_name, 1 TSRMLS_CC);
752 :
753 124 : if (!property_info || property_info == &EG(std_property_info)) {
754 : continue;
755 : }
756 :
757 : /* copy: enforce read only access */
758 78 : ALLOC_ZVAL(prop_copy);
759 78 : *prop_copy = **prop;
760 78 : zval_copy_ctor(prop_copy);
761 78 : INIT_PZVAL(prop_copy);
762 :
763 : /* this is necessary to make it able to work with default array
764 : * properties, returned to user */
765 78 : if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || Z_TYPE_P(prop_copy) == IS_CONSTANT) {
766 0 : zval_update_constant(&prop_copy, 0 TSRMLS_CC);
767 : }
768 :
769 78 : add_assoc_zval(return_value, prop_name, prop_copy);
770 : }
771 : }
772 64 : }
773 : /* }}} */
774 :
775 :
776 : /* {{{ proto array get_class_vars(string class_name)
777 : Returns an array of default properties of the class. */
778 : ZEND_FUNCTION(get_class_vars)
779 59 : {
780 : char *class_name;
781 : int class_name_len;
782 : zend_class_entry **pce;
783 :
784 59 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &class_name, &class_name_len) == FAILURE) {
785 7 : return;
786 : }
787 :
788 52 : if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC) == FAILURE) {
789 20 : RETURN_FALSE;
790 : } else {
791 32 : array_init(return_value);
792 32 : zend_update_class_constants(*pce TSRMLS_CC);
793 32 : add_class_vars(*pce, &(*pce)->default_properties, return_value TSRMLS_CC);
794 32 : add_class_vars(*pce, CE_STATIC_MEMBERS(*pce), return_value TSRMLS_CC);
795 : }
796 : }
797 : /* }}} */
798 :
799 :
800 : /* {{{ proto array get_object_vars(object obj)
801 : Returns an array of object properties */
802 : ZEND_FUNCTION(get_object_vars)
803 61 : {
804 : zval **obj;
805 : zval **value;
806 : HashTable *properties;
807 : HashPosition pos;
808 : char *key, *prop_name, *class_name;
809 : uint key_len;
810 : ulong num_index;
811 : zend_object *zobj;
812 :
813 61 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &obj) == FAILURE) {
814 2 : ZEND_WRONG_PARAM_COUNT();
815 : }
816 :
817 59 : if (Z_TYPE_PP(obj) != IS_OBJECT) {
818 26 : RETURN_FALSE;
819 : }
820 33 : if (Z_OBJ_HT_PP(obj)->get_properties == NULL) {
821 0 : RETURN_FALSE;
822 : }
823 :
824 33 : properties = Z_OBJ_HT_PP(obj)->get_properties(*obj TSRMLS_CC);
825 :
826 33 : if (properties == NULL) {
827 0 : RETURN_FALSE;
828 : }
829 :
830 33 : zobj = zend_objects_get_address(*obj TSRMLS_CC);
831 :
832 33 : array_init(return_value);
833 :
834 33 : zend_hash_internal_pointer_reset_ex(properties, &pos);
835 :
836 189 : while (zend_hash_get_current_data_ex(properties, (void **) &value, &pos) == SUCCESS) {
837 123 : if (zend_hash_get_current_key_ex(properties, &key, &key_len, &num_index, 0, &pos) == HASH_KEY_IS_STRING) {
838 120 : if (zend_check_property_access(zobj, key, key_len-1 TSRMLS_CC) == SUCCESS) {
839 92 : zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name);
840 : /* Not separating references */
841 92 : (*value)->refcount++;
842 92 : add_assoc_zval_ex(return_value, prop_name, strlen(prop_name)+1, *value);
843 : }
844 : }
845 123 : zend_hash_move_forward_ex(properties, &pos);
846 : }
847 : }
848 : /* }}} */
849 :
850 :
851 : /* {{{ proto array get_class_methods(mixed class)
852 : Returns an array of method names for class or class instance. */
853 : ZEND_FUNCTION(get_class_methods)
854 65 : {
855 : zval **class;
856 : zval *method_name;
857 65 : zend_class_entry *ce = NULL, **pce;
858 : HashPosition pos;
859 : zend_function *mptr;
860 :
861 65 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &class)==FAILURE) {
862 2 : ZEND_WRONG_PARAM_COUNT();
863 : }
864 :
865 63 : if (Z_TYPE_PP(class) == IS_OBJECT) {
866 : /* TBI!! new object handlers */
867 5 : if (!HAS_CLASS_ENTRY(**class)) {
868 0 : RETURN_FALSE;
869 : }
870 5 : ce = Z_OBJCE_PP(class);
871 58 : } else if (Z_TYPE_PP(class) == IS_STRING) {
872 36 : if (zend_lookup_class(Z_STRVAL_PP(class), Z_STRLEN_PP(class), &pce TSRMLS_CC) == SUCCESS) {
873 31 : ce = *pce;
874 : }
875 : }
876 :
877 63 : if (!ce) {
878 27 : RETURN_NULL();
879 : }
880 :
881 36 : array_init(return_value);
882 36 : zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
883 :
884 217 : while (zend_hash_get_current_data_ex(&ce->function_table, (void **) &mptr, &pos) == SUCCESS) {
885 145 : if ((mptr->common.fn_flags & ZEND_ACC_PUBLIC)
886 : || (EG(scope) &&
887 : (((mptr->common.fn_flags & ZEND_ACC_PROTECTED) &&
888 : zend_check_protected(mptr->common.scope, EG(scope)))
889 : || ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) &&
890 : EG(scope) == mptr->common.scope)))) {
891 : char *key;
892 : uint key_len;
893 : ulong num_index;
894 107 : uint len = strlen(mptr->common.function_name);
895 :
896 : /* Do not display old-style inherited constructors */
897 107 : if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 ||
898 : mptr->common.scope == ce ||
899 : zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING ||
900 : zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0) {
901 :
902 106 : MAKE_STD_ZVAL(method_name);
903 106 : ZVAL_STRINGL(method_name, mptr->common.function_name, len, 1);
904 106 : zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL);
905 : }
906 : }
907 145 : zend_hash_move_forward_ex(&ce->function_table, &pos);
908 : }
909 : }
910 : /* }}} */
911 :
912 :
913 : /* {{{ proto bool method_exists(object object, string method)
914 : Checks if the class method exists */
915 : ZEND_FUNCTION(method_exists)
916 125 : {
917 : zval **klass, **method_name;
918 : char *lcname;
919 : zend_class_entry * ce, **pce;
920 :
921 125 : if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &klass, &method_name)==FAILURE) {
922 2 : ZEND_WRONG_PARAM_COUNT();
923 : }
924 123 : if (Z_TYPE_PP(klass) == IS_OBJECT) {
925 71 : ce = Z_OBJCE_PP(klass);
926 52 : } else if (Z_TYPE_PP(klass) == IS_STRING) {
927 30 : if (zend_lookup_class(Z_STRVAL_PP(klass), Z_STRLEN_PP(klass), &pce TSRMLS_CC) == FAILURE) {
928 5 : RETURN_FALSE;
929 : }
930 25 : ce = *pce;
931 : } else {
932 22 : RETURN_FALSE;
933 : }
934 :
935 96 : convert_to_string_ex(method_name);
936 96 : lcname = zend_str_tolower_dup(Z_STRVAL_PP(method_name), Z_STRLEN_PP(method_name));
937 96 : if (zend_hash_exists(&ce->function_table, lcname, Z_STRLEN_PP(method_name)+1)) {
938 59 : efree(lcname);
939 59 : RETURN_TRUE;
940 : } else {
941 37 : union _zend_function *func = NULL;
942 37 : efree(lcname);
943 :
944 37 : if (Z_TYPE_PP(klass) == IS_OBJECT
945 : && Z_OBJ_HT_PP(klass)->get_method != NULL
946 : && (func = Z_OBJ_HT_PP(klass)->get_method(klass, Z_STRVAL_PP(method_name), Z_STRLEN_PP(method_name) TSRMLS_CC)) != NULL
947 : ) {
948 2 : if (func->type == ZEND_INTERNAL_FUNCTION
949 : && ((zend_internal_function*)func)->handler == zend_std_call_user_call
950 : ) {
951 2 : efree(((zend_internal_function*)func)->function_name);
952 2 : efree(func);
953 2 : RETURN_FALSE;
954 : }
955 0 : RETURN_TRUE;
956 : }
957 : }
958 35 : RETURN_FALSE;
959 : }
960 : /* }}} */
961 :
962 : /* {{{ proto bool property_exists(mixed object_or_class, string property_name)
963 : Checks if the object or class has a property */
964 : ZEND_FUNCTION(property_exists)
965 98 : {
966 : zval **object, **property;
967 : zend_class_entry *ce, **pce;
968 : zend_property_info *property_info;
969 : char *prop_name, *class_name;
970 :
971 98 : if (ZEND_NUM_ARGS()!= 2 || zend_get_parameters_ex(2, &object, &property)==FAILURE) {
972 4 : ZEND_WRONG_PARAM_COUNT();
973 : }
974 94 : convert_to_string_ex(property);
975 94 : if (!Z_STRLEN_PP(property)) {
976 6 : RETURN_FALSE;
977 : }
978 :
979 88 : switch((*object)->type) {
980 : case IS_STRING:
981 54 : if (!Z_STRLEN_PP(object)) {
982 1 : RETURN_FALSE;
983 : }
984 53 : if (zend_lookup_class(Z_STRVAL_PP(object), Z_STRLEN_PP(object), &pce TSRMLS_CC) == SUCCESS) {
985 52 : ce = *pce;
986 : } else {
987 1 : RETURN_FALSE;
988 : }
989 52 : if (!ce) {
990 0 : RETURN_NULL();
991 : }
992 52 : if (!(property_info = zend_get_property_info(ce, *property, 1 TSRMLS_CC)) || property_info == &EG(std_property_info)) {
993 27 : RETURN_FALSE;
994 : }
995 25 : if (property_info->flags & ZEND_ACC_PUBLIC) {
996 14 : RETURN_TRUE;
997 : }
998 11 : zend_unmangle_property_name(property_info->name, property_info->name_length, &class_name, &prop_name);
999 11 : if (!strncmp(class_name, "*", 1)) {
1000 7 : if (instanceof_function(EG(scope), ce TSRMLS_CC) ||
1001 : (EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC))) {
1002 6 : RETURN_TRUE;
1003 : }
1004 1 : RETURN_FALSE;
1005 : }
1006 4 : if (zend_lookup_class(Z_STRVAL_PP(object), Z_STRLEN_PP(object), &pce TSRMLS_CC) == SUCCESS) {
1007 4 : ce = *pce;
1008 : } else {
1009 0 : RETURN_FALSE; /* shouldn't happen */
1010 : }
1011 4 : RETURN_BOOL(EG(scope) == ce);
1012 :
1013 : case IS_OBJECT:
1014 28 : if (Z_OBJ_HANDLER_PP(object, has_property) && Z_OBJ_HANDLER_PP(object, has_property)(*object, *property, 2 TSRMLS_CC)) {
1015 13 : RETURN_TRUE;
1016 : }
1017 15 : RETURN_FALSE;
1018 :
1019 : default:
1020 6 : zend_error(E_WARNING, "First parameter must either be an object or the name of an existing class");
1021 6 : RETURN_NULL();
1022 : }
1023 : }
1024 : /* }}} */
1025 :
1026 :
1027 : /* {{{ proto bool class_exists(string classname [, bool autoload])
1028 : Checks if the class exists */
1029 : ZEND_FUNCTION(class_exists)
1030 264 : {
1031 : char *class_name, *lc_name;
1032 : zend_class_entry **ce;
1033 : int class_name_len;
1034 : int found;
1035 264 : zend_bool autoload = 1;
1036 : ALLOCA_FLAG(use_heap)
1037 :
1038 264 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &class_name, &class_name_len, &autoload) == FAILURE) {
1039 16 : return;
1040 : }
1041 :
1042 248 : if (!autoload) {
1043 51 : lc_name = do_alloca_with_limit(class_name_len + 1, use_heap);
1044 51 : zend_str_tolower_copy(lc_name, class_name, class_name_len);
1045 :
1046 51 : found = zend_hash_find(EG(class_table), lc_name, class_name_len+1, (void **) &ce);
1047 51 : free_alloca_with_limit(lc_name, use_heap);
1048 51 : RETURN_BOOL(found == SUCCESS && !((*ce)->ce_flags & ZEND_ACC_INTERFACE));
1049 : }
1050 :
1051 197 : if (zend_lookup_class(class_name, class_name_len, &ce TSRMLS_CC) == SUCCESS) {
1052 132 : RETURN_BOOL(((*ce)->ce_flags & ZEND_ACC_INTERFACE) == 0);
1053 : } else {
1054 65 : RETURN_FALSE;
1055 : }
1056 : }
1057 : /* }}} */
1058 :
1059 : /* {{{ proto bool interface_exists(string classname [, bool autoload])
1060 : Checks if the class exists */
1061 : ZEND_FUNCTION(interface_exists)
1062 93 : {
1063 : char *iface_name, *lc_name;
1064 : zend_class_entry **ce;
1065 : int iface_name_len;
1066 : int found;
1067 93 : zend_bool autoload = 1;
1068 : ALLOCA_FLAG(use_heap)
1069 :
1070 93 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &iface_name, &iface_name_len, &autoload) == FAILURE) {
1071 15 : return;
1072 : }
1073 :
1074 78 : if (!autoload) {
1075 17 : lc_name = do_alloca_with_limit(iface_name_len + 1, use_heap);
1076 17 : zend_str_tolower_copy(lc_name, iface_name, iface_name_len);
1077 :
1078 17 : found = zend_hash_find(EG(class_table), lc_name, iface_name_len+1, (void **) &ce);
1079 17 : free_alloca_with_limit(lc_name, use_heap);
1080 17 : RETURN_BOOL(found == SUCCESS && (*ce)->ce_flags & ZEND_ACC_INTERFACE);
1081 : }
1082 :
1083 61 : if (zend_lookup_class(iface_name, iface_name_len, &ce TSRMLS_CC) == SUCCESS) {
1084 25 : RETURN_BOOL(((*ce)->ce_flags & ZEND_ACC_INTERFACE) > 0);
1085 : } else {
1086 36 : RETURN_FALSE;
1087 : }
1088 : }
1089 : /* }}} */
1090 :
1091 :
1092 : /* {{{ proto bool function_exists(string function_name)
1093 : Checks if the function exists */
1094 : ZEND_FUNCTION(function_exists)
1095 1580 : {
1096 : zval **function_name;
1097 : zend_function *func;
1098 : char *lcname;
1099 : zend_bool retval;
1100 :
1101 1580 : if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &function_name)==FAILURE) {
1102 2 : ZEND_WRONG_PARAM_COUNT();
1103 : }
1104 1578 : convert_to_string_ex(function_name);
1105 1578 : lcname = zend_str_tolower_dup(Z_STRVAL_PP(function_name), Z_STRLEN_PP(function_name));
1106 :
1107 1578 : retval = (zend_hash_find(EG(function_table), lcname, Z_STRLEN_PP(function_name)+1, (void **)&func) == SUCCESS);
1108 :
1109 1578 : efree(lcname);
1110 :
1111 : /*
1112 : * A bit of a hack, but not a bad one: we see if the handler of the function
1113 : * is actually one that displays "function is disabled" message.
1114 : */
1115 1578 : if (retval && func->type == ZEND_INTERNAL_FUNCTION &&
1116 : func->internal_function.handler == zif_display_disabled_function) {
1117 0 : retval = 0;
1118 : }
1119 :
1120 1578 : RETURN_BOOL(retval);
1121 : }
1122 : /* }}} */
1123 :
1124 : #if ZEND_DEBUG
1125 : /* {{{ proto void leak(int num_bytes=3)
1126 : Cause an intentional memory leak, for testing/debugging purposes */
1127 : ZEND_FUNCTION(leak)
1128 : {
1129 : int leakbytes=3;
1130 : zval **leak;
1131 :
1132 : if (ZEND_NUM_ARGS()>=1) {
1133 : if (zend_get_parameters_ex(1, &leak)==SUCCESS) {
1134 : convert_to_long_ex(leak);
1135 : leakbytes = Z_LVAL_PP(leak);
1136 : }
1137 : }
1138 :
1139 : emalloc(leakbytes);
1140 : }
1141 : /* }}} */
1142 :
1143 :
1144 : #ifdef ZEND_TEST_EXCEPTIONS
1145 : ZEND_FUNCTION(crash)
1146 : {
1147 : char *nowhere=NULL;
1148 :
1149 : memcpy(nowhere, "something", sizeof("something"));
1150 : }
1151 : #endif
1152 :
1153 : #endif /* ZEND_DEBUG */
1154 :
1155 : /* {{{ proto array get_included_files(void)
1156 : Returns an array with the file names that were include_once()'d */
1157 : ZEND_FUNCTION(get_included_files)
1158 11 : {
1159 : char *entry;
1160 11 : if (ZEND_NUM_ARGS() != 0) {
1161 3 : ZEND_WRONG_PARAM_COUNT();
1162 : }
1163 :
1164 8 : array_init(return_value);
1165 8 : zend_hash_internal_pointer_reset(&EG(included_files));
1166 31 : while (zend_hash_get_current_key(&EG(included_files), &entry, NULL, 1) == HASH_KEY_IS_STRING) {
1167 15 : add_next_index_string(return_value, entry, 0);
1168 15 : zend_hash_move_forward(&EG(included_files));
1169 : }
1170 : }
1171 : /* }}} */
1172 :
1173 :
1174 : /* {{{ proto void trigger_error(string messsage [, int error_type])
1175 : Generates a user-level error/warning/notice message */
1176 : ZEND_FUNCTION(trigger_error)
1177 10 : {
1178 10 : int error_type = E_USER_NOTICE;
1179 : zval **z_error_type, **z_error_message;
1180 :
1181 10 : switch (ZEND_NUM_ARGS()) {
1182 : case 1:
1183 3 : if (zend_get_parameters_ex(1, &z_error_message)==FAILURE) {
1184 0 : ZEND_WRONG_PARAM_COUNT();
1185 : }
1186 3 : break;
1187 : case 2:
1188 6 : if (zend_get_parameters_ex(2, &z_error_message, &z_error_type)==FAILURE) {
1189 0 : ZEND_WRONG_PARAM_COUNT();
1190 : }
1191 6 : convert_to_long_ex(z_error_type);
1192 6 : error_type = Z_LVAL_PP(z_error_type);
1193 6 : switch (error_type) {
1194 : case E_USER_ERROR:
1195 : case E_USER_WARNING:
1196 : case E_USER_NOTICE:
1197 : break;
1198 : default:
1199 2 : zend_error(E_WARNING, "Invalid error type specified");
1200 2 : RETURN_FALSE;
1201 : break;
1202 : }
1203 4 : break;
1204 : default:
1205 1 : ZEND_WRONG_PARAM_COUNT();
1206 : }
1207 7 : convert_to_string_ex(z_error_message);
1208 7 : zend_error(error_type, "%s", Z_STRVAL_PP(z_error_message));
1209 6 : RETURN_TRUE;
1210 : }
1211 : /* }}} */
1212 :
1213 :
1214 : /* {{{ proto string set_error_handler(string error_handler [, int error_types])
1215 : Sets a user-defined error handler function. Returns the previously defined error handler, or false on error */
1216 : ZEND_FUNCTION(set_error_handler)
1217 214 : {
1218 : zval *error_handler;
1219 214 : zend_bool had_orig_error_handler=0;
1220 214 : char *error_handler_name = NULL;
1221 214 : long error_type = E_ALL | E_STRICT;
1222 :
1223 214 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &error_handler, &error_type) == FAILURE) {
1224 0 : return;
1225 : }
1226 :
1227 214 : if (!zend_is_callable(error_handler, 0, &error_handler_name)) {
1228 0 : zend_error(E_WARNING, "%s() expects the argument (%s) to be a valid callback",
1229 : get_active_function_name(TSRMLS_C), error_handler_name?error_handler_name:"unknown");
1230 0 : efree(error_handler_name);
1231 0 : return;
1232 : }
1233 214 : efree(error_handler_name);
1234 :
1235 214 : if (EG(user_error_handler)) {
1236 0 : had_orig_error_handler = 1;
1237 0 : *return_value = *EG(user_error_handler);
1238 0 : zval_copy_ctor(return_value);
1239 0 : INIT_PZVAL(return_value);
1240 0 : zend_stack_push(&EG(user_error_handlers_error_reporting), &EG(user_error_handler_error_reporting), sizeof(EG(user_error_handler_error_reporting)));
1241 0 : zend_ptr_stack_push(&EG(user_error_handlers), EG(user_error_handler));
1242 : }
1243 214 : ALLOC_ZVAL(EG(user_error_handler));
1244 :
1245 214 : if (!zend_is_true(error_handler)) { /* unset user-defined handler */
1246 0 : FREE_ZVAL(EG(user_error_handler));
1247 0 : EG(user_error_handler) = NULL;
1248 0 : RETURN_TRUE;
1249 : }
1250 :
1251 214 : EG(user_error_handler_error_reporting) = (int)error_type;
1252 214 : *EG(user_error_handler) = *error_handler;
1253 214 : zval_copy_ctor(EG(user_error_handler));
1254 214 : INIT_PZVAL(EG(user_error_handler));
1255 :
1256 214 : if (!had_orig_error_handler) {
1257 214 : RETURN_NULL();
1258 : }
1259 : }
1260 : /* }}} */
1261 :
1262 :
1263 : /* {{{ proto void restore_error_handler(void)
1264 : Restores the previously defined error handler function */
1265 : ZEND_FUNCTION(restore_error_handler)
1266 1 : {
1267 1 : if (EG(user_error_handler)) {
1268 1 : zval *zeh = EG(user_error_handler);
1269 :
1270 1 : EG(user_error_handler) = NULL;
1271 1 : zval_ptr_dtor(&zeh);
1272 : }
1273 :
1274 1 : if (zend_ptr_stack_num_elements(&EG(user_error_handlers))==0) {
1275 1 : EG(user_error_handler) = NULL;
1276 : } else {
1277 0 : EG(user_error_handler_error_reporting) = zend_stack_int_top(&EG(user_error_handlers_error_reporting));
1278 0 : zend_stack_del_top(&EG(user_error_handlers_error_reporting));
1279 0 : EG(user_error_handler) = zend_ptr_stack_pop(&EG(user_error_handlers));
1280 : }
1281 1 : RETURN_TRUE;
1282 : }
1283 : /* }}} */
1284 :
1285 :
1286 : /* {{{ proto string set_exception_handler(callable exception_handler)
1287 : Sets a user-defined exception handler function. Returns the previously defined exception handler, or false on error */
1288 : ZEND_FUNCTION(set_exception_handler)
1289 14 : {
1290 : zval **exception_handler;
1291 14 : char *exception_handler_name = NULL;
1292 14 : zend_bool had_orig_exception_handler=0;
1293 :
1294 14 : if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &exception_handler)==FAILURE) {
1295 2 : ZEND_WRONG_PARAM_COUNT();
1296 : }
1297 :
1298 12 : if (Z_TYPE_PP(exception_handler) != IS_NULL) { /* NULL == unset */
1299 12 : if (!zend_is_callable(*exception_handler, 0, &exception_handler_name)) {
1300 2 : zend_error(E_WARNING, "%s() expects the argument (%s) to be a valid callback",
1301 : get_active_function_name(TSRMLS_C), exception_handler_name?exception_handler_name:"unknown");
1302 2 : efree(exception_handler_name);
1303 2 : return;
1304 : }
1305 10 : efree(exception_handler_name);
1306 : }
1307 :
1308 10 : if (EG(user_exception_handler)) {
1309 2 : had_orig_exception_handler = 1;
1310 2 : *return_value = *EG(user_exception_handler);
1311 2 : zval_copy_ctor(return_value);
1312 2 : zend_ptr_stack_push(&EG(user_exception_handlers), EG(user_exception_handler));
1313 : }
1314 10 : ALLOC_ZVAL(EG(user_exception_handler));
1315 :
1316 10 : if (Z_TYPE_PP(exception_handler) == IS_NULL) { /* unset user-defined handler */
1317 0 : FREE_ZVAL(EG(user_exception_handler));
1318 0 : EG(user_exception_handler) = NULL;
1319 0 : RETURN_TRUE;
1320 : }
1321 :
1322 10 : *EG(user_exception_handler) = **exception_handler;
1323 10 : zval_copy_ctor(EG(user_exception_handler));
1324 :
1325 10 : if (!had_orig_exception_handler) {
1326 8 : RETURN_NULL();
1327 : }
1328 : }
1329 : /* }}} */
1330 :
1331 :
1332 : /* {{{ proto void restore_exception_handler(void)
1333 : Restores the previously defined exception handler function */
1334 : ZEND_FUNCTION(restore_exception_handler)
1335 1 : {
1336 1 : if (EG(user_exception_handler)) {
1337 1 : zval_ptr_dtor(&EG(user_exception_handler));
1338 : }
1339 1 : if (zend_ptr_stack_num_elements(&EG(user_exception_handlers))==0) {
1340 0 : EG(user_exception_handler) = NULL;
1341 : } else {
1342 1 : EG(user_exception_handler) = zend_ptr_stack_pop(&EG(user_exception_handlers));
1343 : }
1344 1 : RETURN_TRUE;
1345 : }
1346 : /* }}} */
1347 :
1348 :
1349 : static int copy_class_or_interface_name(zend_class_entry **pce, int num_args, va_list args, zend_hash_key *hash_key)
1350 1942 : {
1351 1942 : zval *array = va_arg(args, zval *);
1352 1942 : zend_uint mask = va_arg(args, zend_uint);
1353 1942 : zend_uint comply = va_arg(args, zend_uint);
1354 1942 : zend_uint comply_mask = (comply)? mask:0;
1355 1942 : zend_class_entry *ce = *pce;
1356 :
1357 1942 : if ((hash_key->nKeyLength==0 || hash_key->arKey[0]!=0)
1358 : && (comply_mask == (ce->ce_flags & mask))) {
1359 919 : add_next_index_stringl(array, ce->name, ce->name_length, 1);
1360 : }
1361 1942 : return ZEND_HASH_APPLY_KEEP;
1362 : }
1363 :
1364 :
1365 : /* {{{ proto array get_declared_classes()
1366 : Returns an array of all declared classes. */
1367 : ZEND_FUNCTION(get_declared_classes)
1368 8 : {
1369 8 : zend_uint mask = ZEND_ACC_INTERFACE;
1370 8 : zend_uint comply = 0;
1371 :
1372 8 : if (ZEND_NUM_ARGS() != 0) {
1373 1 : ZEND_WRONG_PARAM_COUNT();
1374 : }
1375 :
1376 7 : array_init(return_value);
1377 7 : zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t) copy_class_or_interface_name, 3, return_value, mask, comply);
1378 : }
1379 : /* }}} */
1380 :
1381 : /* {{{ proto array get_declared_interfaces()
1382 : Returns an array of all declared interfaces. */
1383 : ZEND_FUNCTION(get_declared_interfaces)
1384 10 : {
1385 10 : zend_uint mask = ZEND_ACC_INTERFACE;
1386 10 : zend_uint comply = 1;
1387 :
1388 10 : if (ZEND_NUM_ARGS() != 0) {
1389 2 : ZEND_WRONG_PARAM_COUNT();
1390 : }
1391 :
1392 8 : array_init(return_value);
1393 8 : zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t) copy_class_or_interface_name, 3, return_value, mask, comply);
1394 : }
1395 : /* }}} */
1396 :
1397 :
1398 : static int copy_function_name(zend_function *func, int num_args, va_list args, zend_hash_key *hash_key)
1399 8285 : {
1400 8285 : zval *internal_ar = va_arg(args, zval *),
1401 8285 : *user_ar = va_arg(args, zval *);
1402 :
1403 8285 : if (hash_key->nKeyLength == 0 || hash_key->arKey[0] == 0) {
1404 0 : return 0;
1405 : }
1406 :
1407 8285 : if (func->type == ZEND_INTERNAL_FUNCTION) {
1408 8276 : add_next_index_stringl(internal_ar, hash_key->arKey, hash_key->nKeyLength-1, 1);
1409 9 : } else if (func->type == ZEND_USER_FUNCTION) {
1410 9 : add_next_index_stringl(user_ar, hash_key->arKey, hash_key->nKeyLength-1, 1);
1411 : }
1412 :
1413 8285 : return 0;
1414 : }
1415 :
1416 :
1417 : /* {{{ proto array get_defined_functions(void)
1418 : Returns an array of all defined functions */
1419 : ZEND_FUNCTION(get_defined_functions)
1420 6 : {
1421 : zval *internal;
1422 : zval *user;
1423 :
1424 6 : if (ZEND_NUM_ARGS() != 0) {
1425 2 : ZEND_WRONG_PARAM_COUNT();
1426 : }
1427 :
1428 4 : MAKE_STD_ZVAL(internal);
1429 4 : MAKE_STD_ZVAL(user);
1430 :
1431 4 : array_init(internal);
1432 4 : array_init(user);
1433 4 : array_init(return_value);
1434 :
1435 4 : zend_hash_apply_with_arguments(EG(function_table), (apply_func_args_t) copy_function_name, 2, internal, user);
1436 :
1437 4 : if (zend_hash_add(Z_ARRVAL_P(return_value), "internal", sizeof("internal"), (void **)&internal, sizeof(zval *), NULL) == FAILURE) {
1438 0 : zval_ptr_dtor(&internal);
1439 0 : zval_ptr_dtor(&user);
1440 0 : zval_dtor(return_value);
1441 0 : zend_error(E_WARNING, "Cannot add internal functions to return value from get_defined_functions()");
1442 0 : RETURN_FALSE;
1443 : }
1444 :
1445 4 : if (zend_hash_add(Z_ARRVAL_P(return_value), "user", sizeof("user"), (void **)&user, sizeof(zval *), NULL) == FAILURE) {
1446 0 : zval_ptr_dtor(&user);
1447 0 : zval_dtor(return_value);
1448 0 : zend_error(E_WARNING, "Cannot add user functions to return value from get_defined_functions()");
1449 0 : RETURN_FALSE;
1450 : }
1451 : }
1452 : /* }}} */
1453 :
1454 :
1455 : /* {{{ proto array get_defined_vars(void)
1456 : Returns an associative array of names and values of all currently defined variable names (variables in the current scope) */
1457 : ZEND_FUNCTION(get_defined_vars)
1458 17 : {
1459 : zval *tmp;
1460 :
1461 17 : array_init(return_value);
1462 :
1463 17 : zend_hash_copy(Z_ARRVAL_P(return_value), EG(active_symbol_table),
1464 : (copy_ctor_func_t)zval_add_ref, &tmp, sizeof(zval *));
1465 17 : }
1466 : /* }}} */
1467 :
1468 :
1469 : #define LAMBDA_TEMP_FUNCNAME "__lambda_func"
1470 : /* {{{ proto string create_function(string args, string code)
1471 : Creates an anonymous function, and returns its name (funny, eh?) */
1472 : ZEND_FUNCTION(create_function)
1473 42 : {
1474 : char *eval_code, *function_name;
1475 : int eval_code_length, function_name_length;
1476 : zval **z_function_args, **z_function_code;
1477 : int retval;
1478 : char *eval_name;
1479 :
1480 42 : if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &z_function_args, &z_function_code)==FAILURE) {
1481 0 : ZEND_WRONG_PARAM_COUNT();
1482 : }
1483 :
1484 42 : convert_to_string_ex(z_function_args);
1485 42 : convert_to_string_ex(z_function_code);
1486 :
1487 42 : eval_code_length = sizeof("function " LAMBDA_TEMP_FUNCNAME)
1488 : +Z_STRLEN_PP(z_function_args)
1489 : +2 /* for the args parentheses */
1490 : +2 /* for the curly braces */
1491 : +Z_STRLEN_PP(z_function_code);
1492 :
1493 42 : zend_spprintf(&eval_code, 0, "function " LAMBDA_TEMP_FUNCNAME "(%s){%s}", Z_STRVAL_PP(z_function_args), Z_STRVAL_PP(z_function_code));
1494 :
1495 42 : eval_name = zend_make_compiled_string_description("runtime-created function" TSRMLS_CC);
1496 42 : retval = zend_eval_string(eval_code, NULL, eval_name TSRMLS_CC);
1497 42 : efree(eval_code);
1498 42 : efree(eval_name);
1499 :
1500 42 : if (retval==SUCCESS) {
1501 : zend_function new_function, *func;
1502 :
1503 40 : if (zend_hash_find(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), (void **) &func)==FAILURE) {
1504 0 : zend_error(E_ERROR, "Unexpected inconsistency in create_function()");
1505 0 : RETURN_FALSE;
1506 : }
1507 40 : new_function = *func;
1508 40 : function_add_ref(&new_function);
1509 :
1510 40 : function_name = (char *) emalloc(sizeof("0lambda_")+MAX_LENGTH_OF_LONG);
1511 :
1512 : do {
1513 40 : sprintf(function_name, "%clambda_%d", 0, ++EG(lambda_count));
1514 40 : function_name_length = strlen(function_name+1)+1;
1515 40 : } while (zend_hash_add(EG(function_table), function_name, function_name_length+1, &new_function, sizeof(zend_function), NULL)==FAILURE);
1516 40 : zend_hash_del(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME));
1517 40 : RETURN_STRINGL(function_name, function_name_length, 0);
1518 : } else {
1519 2 : zend_hash_del(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME));
1520 2 : RETURN_FALSE;
1521 : }
1522 : }
1523 : /* }}} */
1524 :
1525 :
1526 : #if ZEND_DEBUG
1527 : ZEND_FUNCTION(zend_test_func)
1528 : {
1529 : zval *arg1, *arg2;
1530 :
1531 : zend_get_parameters(ht, 2, &arg1, &arg2);
1532 : }
1533 :
1534 :
1535 : #ifdef ZTS
1536 : ZEND_FUNCTION(zend_thread_id)
1537 : {
1538 : RETURN_LONG(tsrm_thread_id());
1539 : }
1540 : #endif
1541 : #endif
1542 :
1543 : /* {{{ proto string get_resource_type(resource res)
1544 : Get the resource type name for a given resource */
1545 : ZEND_FUNCTION(get_resource_type)
1546 74 : {
1547 : char *resource_type;
1548 : zval **z_resource_type;
1549 :
1550 74 : if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &z_resource_type)==FAILURE) {
1551 3 : ZEND_WRONG_PARAM_COUNT();
1552 : }
1553 :
1554 71 : if (Z_TYPE_PP(z_resource_type) != IS_RESOURCE) {
1555 8 : zend_error(E_WARNING, "Supplied argument is not a valid resource handle");
1556 8 : RETURN_FALSE;
1557 : }
1558 :
1559 63 : resource_type = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(z_resource_type) TSRMLS_CC);
1560 63 : if (resource_type) {
1561 38 : RETURN_STRING(resource_type, 1);
1562 : } else {
1563 25 : RETURN_STRING("Unknown", 1);
1564 : }
1565 : }
1566 : /* }}} */
1567 :
1568 :
1569 : static int add_extension_info(zend_module_entry *module, void *arg TSRMLS_DC)
1570 240 : {
1571 240 : zval *name_array = (zval *)arg;
1572 240 : add_next_index_string(name_array, module->name, 1);
1573 240 : return 0;
1574 : }
1575 :
1576 : static int add_zendext_info(zend_extension *ext, void *arg TSRMLS_DC)
1577 0 : {
1578 0 : zval *name_array = (zval *)arg;
1579 0 : add_next_index_string(name_array, ext->name, 1);
1580 0 : return 0;
1581 : }
1582 :
1583 : static int add_constant_info(zend_constant *constant, void *arg TSRMLS_DC)
1584 15451 : {
1585 15451 : zval *name_array = (zval *)arg;
1586 : zval *const_val;
1587 :
1588 15451 : MAKE_STD_ZVAL(const_val);
1589 15451 : *const_val = constant->value;
1590 15451 : zval_copy_ctor(const_val);
1591 15451 : INIT_PZVAL(const_val);
1592 15451 : add_assoc_zval_ex(name_array, constant->name, constant->name_len, const_val);
1593 15451 : return 0;
1594 : }
1595 :
1596 :
1597 : /* {{{ proto array get_loaded_extensions([bool zend_extensions]) U
1598 : Return an array containing names of loaded extensions */
1599 : ZEND_FUNCTION(get_loaded_extensions)
1600 8 : {
1601 8 : zend_bool zendext = 0;
1602 :
1603 8 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &zendext) == FAILURE) {
1604 2 : return;
1605 : }
1606 :
1607 6 : array_init(return_value);
1608 :
1609 6 : if (zendext) {
1610 2 : zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) add_zendext_info, return_value TSRMLS_CC);
1611 : } else {
1612 4 : zend_hash_apply_with_argument(&module_registry, (apply_func_arg_t) add_extension_info, return_value TSRMLS_CC);
1613 : }
1614 : }
1615 : /* }}} */
1616 :
1617 :
1618 : /* {{{ proto array get_defined_constants([mixed categorize])
1619 : Return an array containing the names and values of all defined constants */
1620 : ZEND_FUNCTION(get_defined_constants)
1621 12 : {
1622 12 : zend_bool categorize = 0;
1623 :
1624 12 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &categorize) == FAILURE) {
1625 2 : return;
1626 : }
1627 :
1628 10 : array_init(return_value);
1629 :
1630 10 : if (categorize) {
1631 : HashPosition pos;
1632 : zend_constant *val;
1633 : int module_number;
1634 : zval **modules;
1635 : char **module_names;
1636 : zend_module_entry *module;
1637 2 : int i = 1;
1638 :
1639 2 : modules = ecalloc(zend_hash_num_elements(&module_registry) + 2, sizeof(zval *));
1640 2 : module_names = emalloc((zend_hash_num_elements(&module_registry) + 2) * sizeof(char *));
1641 :
1642 2 : module_names[0] = "internal";
1643 2 : zend_hash_internal_pointer_reset_ex(&module_registry, &pos);
1644 124 : while (zend_hash_get_current_data_ex(&module_registry, (void *) &module, &pos) != FAILURE) {
1645 120 : module_names[module->module_number] = module->name;
1646 120 : i++;
1647 120 : zend_hash_move_forward_ex(&module_registry, &pos);
1648 : }
1649 2 : module_names[i] = "user";
1650 :
1651 2 : zend_hash_internal_pointer_reset_ex(EG(zend_constants), &pos);
1652 3867 : while (zend_hash_get_current_data_ex(EG(zend_constants), (void **) &val, &pos) != FAILURE) {
1653 : zval *const_val;
1654 :
1655 3863 : if (val->module_number == PHP_USER_CONSTANT) {
1656 1 : module_number = i;
1657 3862 : } else if (val->module_number > i || val->module_number < 0) {
1658 : /* should not happen */
1659 : goto bad_module_id;
1660 : } else {
1661 3862 : module_number = val->module_number;
1662 : }
1663 :
1664 3863 : if (!modules[module_number]) {
1665 77 : MAKE_STD_ZVAL(modules[module_number]);
1666 77 : array_init(modules[module_number]);
1667 77 : add_assoc_zval(return_value, module_names[module_number], modules[module_number]);
1668 : }
1669 :
1670 3863 : MAKE_STD_ZVAL(const_val);
1671 3863 : *const_val = val->value;
1672 3863 : zval_copy_ctor(const_val);
1673 3863 : INIT_PZVAL(const_val);
1674 :
1675 3863 : add_assoc_zval_ex(modules[module_number], val->name, val->name_len, const_val);
1676 3863 : bad_module_id:
1677 3863 : zend_hash_move_forward_ex(EG(zend_constants), &pos);
1678 : }
1679 2 : efree(module_names);
1680 2 : efree(modules);
1681 : } else {
1682 8 : zend_hash_apply_with_argument(EG(zend_constants), (apply_func_arg_t) add_constant_info, return_value TSRMLS_CC);
1683 : }
1684 : }
1685 : /* }}} */
1686 :
1687 :
1688 : static zval *debug_backtrace_get_args(void ***curpos TSRMLS_DC)
1689 2003 : {
1690 2003 : void **p = *curpos - 2;
1691 : zval *arg_array, **arg;
1692 2003 : int arg_count = (int)(zend_uintptr_t) *p;
1693 :
1694 2003 : *curpos -= (arg_count+2);
1695 :
1696 2003 : MAKE_STD_ZVAL(arg_array);
1697 2003 : array_init(arg_array);
1698 2003 : p -= arg_count;
1699 :
1700 8164 : while (--arg_count >= 0) {
1701 4158 : arg = (zval **) p++;
1702 4158 : if (*arg) {
1703 4155 : if (Z_TYPE_PP(arg) != IS_OBJECT) {
1704 3832 : SEPARATE_ZVAL_TO_MAKE_IS_REF(arg);
1705 : }
1706 4155 : (*arg)->refcount++;
1707 4155 : add_next_index_zval(arg_array, *arg);
1708 : } else {
1709 3 : add_next_index_null(arg_array);
1710 : }
1711 : }
1712 :
1713 : /* skip args from incomplete frames */
1714 4068 : while ((((*curpos)-1) > EG(argument_stack).elements) && *((*curpos)-1)) {
1715 62 : (*curpos)--;
1716 : }
1717 :
1718 2003 : return arg_array;
1719 : }
1720 :
1721 : void debug_print_backtrace_args(zval *arg_array TSRMLS_DC)
1722 14 : {
1723 : zval **tmp;
1724 : HashPosition iterator;
1725 14 : int i = 0;
1726 :
1727 14 : zend_hash_internal_pointer_reset_ex(arg_array->value.ht, &iterator);
1728 45 : while (zend_hash_get_current_data_ex(arg_array->value.ht, (void **) &tmp, &iterator) == SUCCESS) {
1729 17 : if (i++) {
1730 12 : ZEND_PUTS(", ");
1731 : }
1732 17 : zend_print_flat_zval_r(*tmp TSRMLS_CC);
1733 17 : zend_hash_move_forward_ex(arg_array->value.ht, &iterator);
1734 : }
1735 14 : }
1736 :
1737 : /* {{{ proto void debug_print_backtrace(void) */
1738 : ZEND_FUNCTION(debug_print_backtrace)
1739 7 : {
1740 : zend_execute_data *ptr, *skip;
1741 : int lineno;
1742 : char *function_name;
1743 : char *filename;
1744 7 : char *class_name = NULL;
1745 : char *call_type;
1746 7 : char *include_filename = NULL;
1747 7 : zval *arg_array = NULL;
1748 7 : void **cur_arg_pos = EG(argument_stack).top_element;
1749 7 : void **args = cur_arg_pos;
1750 7 : int arg_stack_consistent = 0;
1751 7 : int frames_on_stack = 0;
1752 7 : int indent = 0;
1753 :
1754 7 : if (ZEND_NUM_ARGS()) {
1755 0 : ZEND_WRONG_PARAM_COUNT();
1756 : }
1757 :
1758 28 : while (--args > EG(argument_stack).elements) {
1759 21 : if (*args--) {
1760 0 : break;
1761 : }
1762 21 : args -= *(ulong*)args;
1763 21 : frames_on_stack++;
1764 :
1765 : /* skip args from incomplete frames */
1766 42 : while (((args-1) > EG(argument_stack).elements) && *(args-1)) {
1767 0 : args--;
1768 : }
1769 :
1770 21 : if ((args-1) == EG(argument_stack).elements) {
1771 7 : arg_stack_consistent = 1;
1772 7 : break;
1773 : }
1774 : }
1775 :
1776 7 : ptr = EG(current_execute_data);
1777 :
1778 : /* skip debug_backtrace() */
1779 7 : ptr = ptr->prev_execute_data;
1780 7 : cur_arg_pos -= 2;
1781 7 : frames_on_stack--;
1782 :
1783 7 : if (arg_stack_consistent) {
1784 : /* skip args from incomplete frames */
1785 14 : while (((cur_arg_pos-1) > EG(argument_stack).elements) && *(cur_arg_pos-1)) {
1786 0 : cur_arg_pos--;
1787 : }
1788 : }
1789 :
1790 31 : while (ptr) {
1791 17 : char *free_class_name = NULL;
1792 :
1793 17 : class_name = call_type = NULL;
1794 17 : arg_array = NULL;
1795 :
1796 17 : skip = ptr;
1797 : /* skip internal handler */
1798 17 : if (!skip->op_array &&
1799 : skip->prev_execute_data &&
1800 : skip->prev_execute_data->opline &&
1801 : skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL &&
1802 : skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME &&
1803 : skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
1804 1 : skip = skip->prev_execute_data;
1805 : }
1806 :
1807 17 : if (skip->op_array) {
1808 15 : filename = skip->op_array->filename;
1809 15 : lineno = skip->opline->lineno;
1810 : } else {
1811 2 : filename = NULL;
1812 2 : lineno = 0;
1813 : }
1814 :
1815 17 : function_name = ptr->function_state.function->common.function_name;
1816 :
1817 17 : if (function_name) {
1818 14 : if (ptr->object) {
1819 4 : if (ptr->function_state.function->common.scope) {
1820 4 : class_name = ptr->function_state.function->common.scope->name;
1821 : } else {
1822 : zend_uint class_name_len;
1823 : int dup;
1824 :
1825 0 : dup = zend_get_object_classname(ptr->object, &class_name, &class_name_len TSRMLS_CC);
1826 0 : if(!dup) {
1827 0 : free_class_name = class_name;
1828 : }
1829 : }
1830 :
1831 4 : call_type = "->";
1832 10 : } else if (ptr->function_state.function->common.scope) {
1833 4 : class_name = ptr->function_state.function->common.scope->name;
1834 4 : call_type = "::";
1835 : } else {
1836 6 : class_name = NULL;
1837 6 : call_type = NULL;
1838 : }
1839 14 : if ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL))) {
1840 14 : if (arg_stack_consistent && (frames_on_stack > 0)) {
1841 14 : arg_array = debug_backtrace_get_args(&cur_arg_pos TSRMLS_CC);
1842 14 : frames_on_stack--;
1843 : }
1844 : }
1845 : } else {
1846 : /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
1847 3 : zend_bool build_filename_arg = 1;
1848 :
1849 3 : if (!ptr->opline || ptr->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
1850 : /* can happen when calling eval from a custom sapi */
1851 0 : function_name = "unknown";
1852 0 : build_filename_arg = 0;
1853 : } else
1854 3 : switch (Z_LVAL(ptr->opline->op2.u.constant)) {
1855 : case ZEND_EVAL:
1856 1 : function_name = "eval";
1857 1 : build_filename_arg = 0;
1858 1 : break;
1859 : case ZEND_INCLUDE:
1860 2 : function_name = "include";
1861 2 : break;
1862 : case ZEND_REQUIRE:
1863 0 : function_name = "require";
1864 0 : break;
1865 : case ZEND_INCLUDE_ONCE:
1866 0 : function_name = "include_once";
1867 0 : break;
1868 : case ZEND_REQUIRE_ONCE:
1869 0 : function_name = "require_once";
1870 0 : break;
1871 : default:
1872 : /* this can actually happen if you use debug_backtrace() in your error_handler and
1873 : * you're in the top-scope */
1874 0 : function_name = "unknown";
1875 0 : build_filename_arg = 0;
1876 : break;
1877 : }
1878 :
1879 3 : if (build_filename_arg && include_filename) {
1880 0 : MAKE_STD_ZVAL(arg_array);
1881 0 : array_init(arg_array);
1882 0 : add_next_index_string(arg_array, include_filename, 1);
1883 : }
1884 3 : call_type = NULL;
1885 : }
1886 17 : zend_printf("#%-2d ", indent);
1887 17 : if (class_name) {
1888 8 : ZEND_PUTS(class_name);
1889 8 : ZEND_PUTS(call_type);
1890 : }
1891 17 : zend_printf("%s(", function_name?function_name:"main");
1892 17 : if (arg_array) {
1893 14 : debug_print_backtrace_args(arg_array TSRMLS_CC);
1894 14 : zval_ptr_dtor(&arg_array);
1895 : }
1896 17 : if (filename) {
1897 15 : zend_printf(") called at [%s:%d]\n", filename, lineno);
1898 : } else {
1899 2 : zend_execute_data *prev = skip->prev_execute_data;
1900 :
1901 4 : while (prev) {
1902 2 : if (prev->function_state.function &&
1903 : prev->function_state.function->common.type != ZEND_USER_FUNCTION) {
1904 0 : prev = NULL;
1905 0 : break;
1906 : }
1907 2 : if (prev->op_array) {
1908 2 : zend_printf(") called at [%s:%d]\n", prev->op_array->filename, prev->opline->lineno);
1909 2 : break;
1910 : }
1911 0 : prev = prev->prev_execute_data;
1912 : }
1913 2 : if (!prev) {
1914 0 : ZEND_PUTS(")\n");
1915 : }
1916 : }
1917 17 : include_filename = filename;
1918 17 : ptr = skip->prev_execute_data;
1919 17 : ++indent;
1920 17 : if (free_class_name) {
1921 0 : efree(free_class_name);
1922 : }
1923 : }
1924 : }
1925 :
1926 : /* }}} */
1927 :
1928 : ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int provide_object TSRMLS_DC)
1929 1030 : {
1930 : zend_execute_data *ptr, *skip;
1931 : int lineno;
1932 : char *function_name;
1933 : char *filename;
1934 : char *class_name;
1935 1030 : char *include_filename = NULL;
1936 : zval *stack_frame;
1937 1030 : void **cur_arg_pos = EG(argument_stack).top_element;
1938 1030 : void **args = cur_arg_pos;
1939 1030 : int arg_stack_consistent = 0;
1940 1030 : int frames_on_stack = 0;
1941 :
1942 3050 : while (--args > EG(argument_stack).elements) {
1943 1999 : if (*args--) {
1944 0 : break;
1945 : }
1946 1999 : args -= *(ulong*)args;
1947 1999 : frames_on_stack++;
1948 :
1949 : /* skip args from incomplete frames */
1950 4061 : while (((args-1) > EG(argument_stack).elements) && *(args-1)) {
1951 63 : args--;
1952 : }
1953 :
1954 1999 : if ((args-1) == EG(argument_stack).elements) {
1955 1009 : arg_stack_consistent = 1;
1956 1009 : break;
1957 : }
1958 : }
1959 :
1960 1030 : ptr = EG(current_execute_data);
1961 :
1962 : /* skip "new Exception()" */
1963 1030 : if (ptr && (skip_last == 0) && ptr->opline && (ptr->opline->opcode == ZEND_NEW)) {
1964 232 : ptr = ptr->prev_execute_data;
1965 : }
1966 :
1967 : /* skip debug_backtrace() */
1968 1030 : if (skip_last-- && ptr) {
1969 9 : int arg_count = *((ulong*)(cur_arg_pos - 2));
1970 9 : cur_arg_pos -= (arg_count + 2);
1971 9 : frames_on_stack--;
1972 9 : ptr = ptr->prev_execute_data;
1973 :
1974 9 : if (arg_stack_consistent) {
1975 : /* skip args from incomplete frames */
1976 19 : while (((cur_arg_pos-1) > EG(argument_stack).elements) && *(cur_arg_pos-1)) {
1977 1 : cur_arg_pos--;
1978 : }
1979 : }
1980 : }
1981 :
1982 1030 : array_init(return_value);
1983 :
1984 4148 : while (ptr) {
1985 2088 : MAKE_STD_ZVAL(stack_frame);
1986 2088 : array_init(stack_frame);
1987 :
1988 2088 : skip = ptr;
1989 : /* skip internal handler */
1990 2088 : if (!skip->op_array &&
1991 : skip->prev_execute_data &&
1992 : skip->prev_execute_data->opline &&
1993 : skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL &&
1994 : skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME &&
1995 : skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
1996 37 : skip = skip->prev_execute_data;
1997 : }
1998 :
1999 2088 : if (skip->op_array) {
2000 1345 : filename = skip->op_array->filename;
2001 1345 : lineno = skip->opline->lineno;
2002 1345 : add_assoc_string_ex(stack_frame, "file", sizeof("file"), filename, 1);
2003 1345 : add_assoc_long_ex(stack_frame, "line", sizeof("line"), lineno);
2004 :
2005 : /* try to fetch args only if an FCALL was just made - elsewise we're in the middle of a function
2006 : * and debug_baktrace() might have been called by the error_handler. in this case we don't
2007 : * want to pop anything of the argument-stack */
2008 : } else {
2009 743 : zend_execute_data *prev = skip->prev_execute_data;
2010 :
2011 1486 : while (prev) {
2012 737 : if (prev->function_state.function &&
2013 : prev->function_state.function->common.type != ZEND_USER_FUNCTION) {
2014 731 : break;
2015 : }
2016 6 : if (prev->op_array) {
2017 6 : add_assoc_string_ex(stack_frame, "file", sizeof("file"), prev->op_array->filename, 1);
2018 6 : add_assoc_long_ex(stack_frame, "line", sizeof("line"), prev->opline->lineno);
2019 6 : break;
2020 : }
2021 0 : prev = prev->prev_execute_data;
2022 : }
2023 743 : filename = NULL;
2024 : }
2025 :
2026 2088 : function_name = ptr->function_state.function->common.function_name;
2027 :
2028 2088 : if (function_name) {
2029 2001 : add_assoc_string_ex(stack_frame, "function", sizeof("function"), function_name, 1);
2030 :
2031 3606 : if (ptr->object && Z_TYPE_P(ptr->object) == IS_OBJECT) {
2032 1605 : if (ptr->function_state.function->common.scope) {
2033 1605 : add_assoc_string_ex(stack_frame, "class", sizeof("class"), ptr->function_state.function->common.scope->name, 1);
2034 : } else {
2035 : zend_uint class_name_len;
2036 : int dup;
2037 :
2038 0 : dup = zend_get_object_classname(ptr->object, &class_name, &class_name_len TSRMLS_CC);
2039 0 : add_assoc_string_ex(stack_frame, "class", sizeof("class"), class_name, dup);
2040 :
2041 : }
2042 1605 : if (provide_object) {
2043 5 : add_assoc_zval_ex(stack_frame, "object", sizeof("object"), ptr->object);
2044 5 : ptr->object->refcount++;
2045 : }
2046 :
2047 1605 : add_assoc_string_ex(stack_frame, "type", sizeof("type"), "->", 1);
2048 396 : } else if (ptr->function_state.function->common.scope) {
2049 78 : add_assoc_string_ex(stack_frame, "class", sizeof("class"), ptr->function_state.function->common.scope->name, 1);
2050 78 : add_assoc_string_ex(stack_frame, "type", sizeof("type"), "::", 1);
2051 : }
2052 :
2053 2001 : if ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL))) {
2054 1995 : if (arg_stack_consistent && (frames_on_stack > 0)) {
2055 1989 : add_assoc_zval_ex(stack_frame, "args", sizeof("args"), debug_backtrace_get_args(&cur_arg_pos TSRMLS_CC));
2056 1989 : frames_on_stack--;
2057 : }
2058 : }
2059 : } else {
2060 : /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
2061 87 : zend_bool build_filename_arg = 1;
2062 :
2063 91 : if (!ptr->opline || ptr->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
2064 : /* can happen when calling eval from a custom sapi */
2065 4 : function_name = "unknown";
2066 4 : build_filename_arg = 0;
2067 : } else
2068 83 : switch (ptr->opline->op2.u.constant.value.lval) {
2069 : case ZEND_EVAL:
2070 2 : function_name = "eval";
2071 2 : build_filename_arg = 0;
2072 2 : break;
2073 : case ZEND_INCLUDE:
2074 81 : function_name = "include";
2075 81 : break;
2076 : case ZEND_REQUIRE:
2077 0 : function_name = "require";
2078 0 : break;
2079 : case ZEND_INCLUDE_ONCE:
2080 0 : function_name = "include_once";
2081 0 : break;
2082 : case ZEND_REQUIRE_ONCE:
2083 0 : function_name = "require_once";
2084 0 : break;
2085 : default:
2086 : /* this can actually happen if you use debug_backtrace() in your error_handler and
2087 : * you're in the top-scope */
2088 0 : function_name = "unknown";
2089 0 : build_filename_arg = 0;
2090 : break;
2091 : }
2092 :
2093 87 : if (build_filename_arg && include_filename) {
2094 : zval *arg_array;
2095 :
2096 80 : MAKE_STD_ZVAL(arg_array);
2097 80 : array_init(arg_array);
2098 :
2099 : /* include_filename always points to the last filename of the last last called-fuction.
2100 : if we have called include in the frame above - this is the file we have included.
2101 : */
2102 :
2103 80 : add_next_index_string(arg_array, include_filename, 1);
2104 80 : add_assoc_zval_ex(stack_frame, "args", sizeof("args"), arg_array);
2105 : }
2106 :
2107 87 : add_assoc_string_ex(stack_frame, "function", sizeof("function"), function_name, 1);
2108 : }
2109 :
2110 2088 : add_next_index_zval(return_value, stack_frame);
2111 :
2112 2088 : include_filename = filename;
2113 :
2114 2088 : ptr = skip->prev_execute_data;
2115 : }
2116 1030 : }
2117 : /* }}} */
2118 :
2119 :
2120 : /* {{{ proto array debug_backtrace([bool provide_object])
2121 : Return backtrace as array */
2122 : ZEND_FUNCTION(debug_backtrace)
2123 8 : {
2124 8 : zend_bool provide_object = 1;
2125 :
2126 8 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &provide_object) == FAILURE) {
2127 0 : return;
2128 : }
2129 :
2130 8 : zend_fetch_debug_backtrace(return_value, 1, provide_object TSRMLS_CC);
2131 : }
2132 : /* }}} */
2133 :
2134 : /* {{{ proto bool extension_loaded(string extension_name)
2135 : Returns true if the named extension is loaded */
2136 : ZEND_FUNCTION(extension_loaded)
2137 3901 : {
2138 : zval **extension_name;
2139 : char *lcname;
2140 :
2141 3901 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &extension_name)) {
2142 0 : ZEND_WRONG_PARAM_COUNT();
2143 : }
2144 :
2145 3901 : convert_to_string_ex(extension_name);
2146 3901 : lcname = zend_str_tolower_dup(Z_STRVAL_PP(extension_name), Z_STRLEN_PP(extension_name));
2147 3901 : if (zend_hash_exists(&module_registry, lcname, Z_STRLEN_PP(extension_name)+1)) {
2148 3897 : RETVAL_TRUE;
2149 : } else {
2150 4 : RETVAL_FALSE;
2151 : }
2152 3901 : efree(lcname);
2153 : }
2154 : /* }}} */
2155 :
2156 :
2157 : /* {{{ proto array get_extension_funcs(string extension_name)
2158 : Returns an array with the names of functions belonging to the named extension */
2159 : ZEND_FUNCTION(get_extension_funcs)
2160 32 : {
2161 : zval **extension_name;
2162 : zend_module_entry *module;
2163 : zend_function_entry *func;
2164 :
2165 32 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &extension_name)) {
2166 3 : ZEND_WRONG_PARAM_COUNT();
2167 : }
2168 :
2169 29 : convert_to_string_ex(extension_name);
2170 29 : if (strncasecmp(Z_STRVAL_PP(extension_name), "zend", sizeof("zend"))) {
2171 27 : char *lcname = zend_str_tolower_dup(Z_STRVAL_PP(extension_name), Z_STRLEN_PP(extension_name));
2172 27 : if (zend_hash_find(&module_registry, lcname,
2173 : Z_STRLEN_PP(extension_name)+1, (void**)&module) == FAILURE) {
2174 24 : efree(lcname);
2175 24 : RETURN_FALSE;
2176 : }
2177 3 : efree(lcname);
2178 :
2179 3 : if (!(func = module->functions)) {
2180 0 : RETURN_FALSE;
2181 : }
2182 : } else {
2183 2 : func = builtin_functions;
2184 : }
2185 :
2186 5 : array_init(return_value);
2187 :
2188 1642 : while (func->fname) {
2189 1632 : add_next_index_string(return_value, func->fname, 1);
2190 1632 : func++;
2191 : }
2192 : }
2193 : /* }}} */
2194 :
2195 : /*
2196 : * Local variables:
2197 : * tab-width: 4
2198 : * c-basic-offset: 4
2199 : * indent-tabs-mode: t
2200 : * End:
2201 : */
|