1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Marcus Boerger <helly@php.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: php_spl.c 286476 2009-07-28 22:25:31Z bjori $ */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 : #include "php_ini.h"
27 : #include "php_main.h"
28 : #include "ext/standard/info.h"
29 : #include "php_spl.h"
30 : #include "spl_functions.h"
31 : #include "spl_engine.h"
32 : #include "spl_array.h"
33 : #include "spl_directory.h"
34 : #include "spl_iterators.h"
35 : #include "spl_sxe.h"
36 : #include "spl_exceptions.h"
37 : #include "spl_observer.h"
38 : #include "zend_exceptions.h"
39 : #include "zend_interfaces.h"
40 : #include "ext/standard/md5.h"
41 :
42 : #ifdef COMPILE_DL_SPL
43 : ZEND_GET_MODULE(spl)
44 : #endif
45 :
46 : ZEND_DECLARE_MODULE_GLOBALS(spl)
47 :
48 : #define SPL_DEFAULT_FILE_EXTENSIONS ".inc,.php"
49 :
50 : /* {{{ spl_functions_none
51 : */
52 : zend_function_entry spl_functions_none[] = {
53 : {NULL, NULL, NULL}
54 : };
55 : /* }}} */
56 :
57 : /* {{{ PHP_GINIT_FUNCTION
58 : */
59 : static PHP_GINIT_FUNCTION(spl)
60 13565 : {
61 13565 : spl_globals->autoload_extensions = NULL;
62 13565 : spl_globals->autoload_extensions_len = 0;
63 13565 : spl_globals->autoload_functions = NULL;
64 13565 : spl_globals->autoload_running = 0;
65 13565 : }
66 : /* }}} */
67 :
68 : static zend_class_entry * spl_find_ce_by_name(char *name, int len, zend_bool autoload TSRMLS_DC)
69 36 : {
70 : zend_class_entry **ce;
71 : int found;
72 :
73 36 : if (!autoload) {
74 : char *lc_name;
75 :
76 12 : lc_name = do_alloca(len + 1);
77 12 : zend_str_tolower_copy(lc_name, name, len);
78 :
79 12 : found = zend_hash_find(EG(class_table), lc_name, len +1, (void **) &ce);
80 : free_alloca(lc_name);
81 : } else {
82 24 : found = zend_lookup_class(name, len, &ce TSRMLS_CC);
83 : }
84 36 : if (found != SUCCESS) {
85 8 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class %s does not exist%s", name, autoload ? " and could not be loaded" : "");
86 8 : return NULL;
87 : }
88 :
89 28 : return *ce;
90 : }
91 :
92 : /* {{{ proto array class_parents(object instance [, boolean autoload = true])
93 : Return an array containing the names of all parent classes */
94 : PHP_FUNCTION(class_parents)
95 8 : {
96 : zval *obj;
97 : zend_class_entry *parent_class, *ce;
98 8 : zend_bool autoload = 1;
99 :
100 8 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &obj, &autoload) == FAILURE) {
101 0 : RETURN_FALSE;
102 : }
103 :
104 8 : if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) {
105 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "object or string expected");
106 0 : RETURN_FALSE;
107 : }
108 :
109 8 : if (Z_TYPE_P(obj) == IS_STRING) {
110 5 : if (NULL == (ce = spl_find_ce_by_name(Z_STRVAL_P(obj), Z_STRLEN_P(obj), autoload TSRMLS_CC))) {
111 2 : RETURN_FALSE;
112 : }
113 : } else {
114 3 : ce = Z_OBJCE_P(obj);
115 : }
116 :
117 6 : array_init(return_value);
118 6 : parent_class = ce->parent;
119 20 : while (parent_class) {
120 8 : spl_add_class_name(return_value, parent_class, 0, 0 TSRMLS_CC);
121 8 : parent_class = parent_class->parent;
122 : }
123 : }
124 : /* }}} */
125 :
126 : /* {{{ proto array class_implements(mixed what [, bool autoload ])
127 : Return all classes and interfaces implemented by SPL */
128 : PHP_FUNCTION(class_implements)
129 70 : {
130 : zval *obj;
131 70 : zend_bool autoload = 1;
132 : zend_class_entry *ce;
133 :
134 70 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &obj, &autoload) == FAILURE) {
135 9 : RETURN_FALSE;
136 : }
137 61 : if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) {
138 22 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "object or string expected");
139 22 : RETURN_FALSE;
140 : }
141 :
142 39 : if (Z_TYPE_P(obj) == IS_STRING) {
143 31 : if (NULL == (ce = spl_find_ce_by_name(Z_STRVAL_P(obj), Z_STRLEN_P(obj), autoload TSRMLS_CC))) {
144 6 : RETURN_FALSE;
145 : }
146 : } else {
147 8 : ce = Z_OBJCE_P(obj);
148 : }
149 :
150 33 : array_init(return_value);
151 33 : spl_add_interfaces(return_value, ce, 1, ZEND_ACC_INTERFACE TSRMLS_CC);
152 : }
153 : /* }}} */
154 :
155 : #define SPL_ADD_CLASS(class_name, z_list, sub, allow, ce_flags) \
156 : spl_add_classes(&spl_ce_ ## class_name, z_list, sub, allow, ce_flags TSRMLS_CC)
157 :
158 : #define SPL_LIST_CLASSES(z_list, sub, allow, ce_flags) \
159 : SPL_ADD_CLASS(AppendIterator, z_list, sub, allow, ce_flags); \
160 : SPL_ADD_CLASS(ArrayIterator, z_list, sub, allow, ce_flags); \
161 : SPL_ADD_CLASS(ArrayObject, z_list, sub, allow, ce_flags); \
162 : SPL_ADD_CLASS(BadFunctionCallException, z_list, sub, allow, ce_flags); \
163 : SPL_ADD_CLASS(BadMethodCallException, z_list, sub, allow, ce_flags); \
164 : SPL_ADD_CLASS(CachingIterator, z_list, sub, allow, ce_flags); \
165 : SPL_ADD_CLASS(Countable, z_list, sub, allow, ce_flags); \
166 : SPL_ADD_CLASS(DirectoryIterator, z_list, sub, allow, ce_flags); \
167 : SPL_ADD_CLASS(DomainException, z_list, sub, allow, ce_flags); \
168 : SPL_ADD_CLASS(EmptyIterator, z_list, sub, allow, ce_flags); \
169 : SPL_ADD_CLASS(FilterIterator, z_list, sub, allow, ce_flags); \
170 : SPL_ADD_CLASS(InfiniteIterator, z_list, sub, allow, ce_flags); \
171 : SPL_ADD_CLASS(InvalidArgumentException, z_list, sub, allow, ce_flags); \
172 : SPL_ADD_CLASS(IteratorIterator, z_list, sub, allow, ce_flags); \
173 : SPL_ADD_CLASS(LengthException, z_list, sub, allow, ce_flags); \
174 : SPL_ADD_CLASS(LimitIterator, z_list, sub, allow, ce_flags); \
175 : SPL_ADD_CLASS(LogicException, z_list, sub, allow, ce_flags); \
176 : SPL_ADD_CLASS(NoRewindIterator, z_list, sub, allow, ce_flags); \
177 : SPL_ADD_CLASS(OuterIterator, z_list, sub, allow, ce_flags); \
178 : SPL_ADD_CLASS(OutOfBoundsException, z_list, sub, allow, ce_flags); \
179 : SPL_ADD_CLASS(OutOfRangeException, z_list, sub, allow, ce_flags); \
180 : SPL_ADD_CLASS(OverflowException, z_list, sub, allow, ce_flags); \
181 : SPL_ADD_CLASS(ParentIterator, z_list, sub, allow, ce_flags); \
182 : SPL_ADD_CLASS(RangeException, z_list, sub, allow, ce_flags); \
183 : SPL_ADD_CLASS(RecursiveArrayIterator, z_list, sub, allow, ce_flags); \
184 : SPL_ADD_CLASS(RecursiveCachingIterator, z_list, sub, allow, ce_flags); \
185 : SPL_ADD_CLASS(RecursiveDirectoryIterator, z_list, sub, allow, ce_flags); \
186 : SPL_ADD_CLASS(RecursiveFilterIterator, z_list, sub, allow, ce_flags); \
187 : SPL_ADD_CLASS(RecursiveIterator, z_list, sub, allow, ce_flags); \
188 : SPL_ADD_CLASS(RecursiveIteratorIterator, z_list, sub, allow, ce_flags); \
189 : SPL_ADD_CLASS(RecursiveRegexIterator, z_list, sub, allow, ce_flags); \
190 : SPL_ADD_CLASS(RegexIterator, z_list, sub, allow, ce_flags); \
191 : SPL_ADD_CLASS(RuntimeException, z_list, sub, allow, ce_flags); \
192 : SPL_ADD_CLASS(SeekableIterator, z_list, sub, allow, ce_flags); \
193 : SPL_ADD_CLASS(SimpleXMLIterator, z_list, sub, allow, ce_flags); \
194 : SPL_ADD_CLASS(SplFileInfo, z_list, sub, allow, ce_flags); \
195 : SPL_ADD_CLASS(SplFileObject, z_list, sub, allow, ce_flags); \
196 : SPL_ADD_CLASS(SplObjectStorage, z_list, sub, allow, ce_flags); \
197 : SPL_ADD_CLASS(SplObserver, z_list, sub, allow, ce_flags); \
198 : SPL_ADD_CLASS(SplSubject, z_list, sub, allow, ce_flags); \
199 : SPL_ADD_CLASS(SplTempFileObject, z_list, sub, allow, ce_flags); \
200 : SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \
201 : SPL_ADD_CLASS(UnexpectedValueException, z_list, sub, allow, ce_flags); \
202 :
203 : /* {{{ proto array spl_classes()
204 : Return an array containing the names of all clsses and interfaces defined in SPL */
205 : PHP_FUNCTION(spl_classes)
206 1 : {
207 1 : array_init(return_value);
208 :
209 1 : SPL_LIST_CLASSES(return_value, 0, 0, 0)
210 1 : }
211 : /* }}} */
212 :
213 : static int spl_autoload(const char *class_name, const char * lc_name, int class_name_len, const char * file_extension TSRMLS_DC) /* {{{ */
214 15 : {
215 : char *class_file;
216 : int class_file_len;
217 15 : int dummy = 1;
218 : zend_file_handle file_handle;
219 : zend_op_array *new_op_array;
220 15 : zval *result = NULL;
221 : int ret;
222 :
223 15 : class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension);
224 :
225 15 : ret = php_stream_open_for_zend_ex(class_file, &file_handle, ENFORCE_SAFE_MODE|USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
226 :
227 15 : if (ret == SUCCESS) {
228 10 : if (!file_handle.opened_path) {
229 0 : file_handle.opened_path = estrndup(class_file, class_file_len);
230 : }
231 10 : if (zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) {
232 5 : new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
233 5 : zend_destroy_file_handle(&file_handle TSRMLS_CC);
234 : } else {
235 5 : new_op_array = NULL;
236 5 : zend_file_handle_dtor(&file_handle);
237 : }
238 10 : if (new_op_array) {
239 5 : EG(return_value_ptr_ptr) = &result;
240 5 : EG(active_op_array) = new_op_array;
241 :
242 5 : zend_execute(new_op_array TSRMLS_CC);
243 :
244 5 : destroy_op_array(new_op_array TSRMLS_CC);
245 5 : efree(new_op_array);
246 5 : if (!EG(exception)) {
247 5 : if (EG(return_value_ptr_ptr)) {
248 5 : zval_ptr_dtor(EG(return_value_ptr_ptr));
249 : }
250 : }
251 :
252 5 : efree(class_file);
253 5 : return zend_hash_exists(EG(class_table), (char*)lc_name, class_name_len+1);
254 : }
255 : }
256 10 : efree(class_file);
257 10 : return 0;
258 : } /* }}} */
259 :
260 : /* {{{ proto void spl_autoload(string class_name [, string file_extensions])
261 : Default implementation for __autoload() */
262 : PHP_FUNCTION(spl_autoload)
263 10 : {
264 10 : char *class_name, *lc_name, *file_exts = SPL_G(autoload_extensions);
265 10 : int class_name_len, file_exts_len = SPL_G(autoload_extensions_len), found = 0;
266 : char *copy, *pos1, *pos2;
267 10 : zval **original_return_value = EG(return_value_ptr_ptr);
268 10 : zend_op **original_opline_ptr = EG(opline_ptr);
269 10 : zend_op_array *original_active_op_array = EG(active_op_array);
270 10 : zend_function_state *original_function_state_ptr = EG(function_state_ptr);
271 :
272 10 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &class_name, &class_name_len, &file_exts, &file_exts_len) == FAILURE) {
273 0 : RETURN_FALSE;
274 : }
275 :
276 10 : if (file_exts == NULL) { /* autoload_extensions is not intialzed, set to defaults */
277 3 : copy = pos1 = estrndup(SPL_DEFAULT_FILE_EXTENSIONS, sizeof(SPL_DEFAULT_FILE_EXTENSIONS)-1);
278 : } else {
279 7 : copy = pos1 = estrndup(file_exts, file_exts_len);
280 : }
281 10 : lc_name = zend_str_tolower_dup(class_name, class_name_len);
282 34 : while(pos1 && *pos1 && !EG(exception)) {
283 15 : EG(return_value_ptr_ptr) = original_return_value;
284 15 : EG(opline_ptr) = original_opline_ptr;
285 15 : EG(active_op_array) = original_active_op_array;
286 15 : EG(function_state_ptr) = original_function_state_ptr;
287 15 : pos2 = strchr(pos1, ',');
288 15 : if (pos2) *pos2 = '\0';
289 15 : if (spl_autoload(class_name, lc_name, class_name_len, pos1 TSRMLS_CC)) {
290 1 : found = 1;
291 1 : break; /* loaded */
292 : }
293 14 : pos1 = pos2 ? pos2 + 1 : NULL;
294 : }
295 10 : efree(lc_name);
296 10 : if (copy) {
297 10 : efree(copy);
298 : }
299 :
300 10 : EG(return_value_ptr_ptr) = original_return_value;
301 10 : EG(opline_ptr) = original_opline_ptr;
302 10 : EG(active_op_array) = original_active_op_array;
303 10 : EG(function_state_ptr) = original_function_state_ptr;
304 :
305 10 : if (!found && !SPL_G(autoload_running)) {
306 : /* For internal errors, we generate E_ERROR, for direct calls an exception is thrown.
307 : * The "scope" is determined by an opcode, if it is ZEND_FETCH_CLASS we know function was called indirectly by
308 : * the Zend engine.
309 : */
310 8 : if (active_opline->opcode != ZEND_FETCH_CLASS) {
311 7 : zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Class %s could not be loaded", class_name);
312 : } else {
313 1 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s could not be loaded", class_name);
314 : }
315 : }
316 : } /* }}} */
317 :
318 : /* {{{ proto string spl_autoload_extensions([string file_extensions])
319 : Register and return default file extensions for spl_autoload */
320 : PHP_FUNCTION(spl_autoload_extensions)
321 4 : {
322 : char *file_exts;
323 : int file_exts_len;
324 :
325 4 : if (ZEND_NUM_ARGS() > 0) {
326 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file_exts, &file_exts_len) == FAILURE) {
327 0 : return;
328 : }
329 :
330 3 : if (SPL_G(autoload_extensions)) {
331 2 : efree(SPL_G(autoload_extensions));
332 : }
333 3 : SPL_G(autoload_extensions) = estrndup(file_exts, file_exts_len);
334 3 : SPL_G(autoload_extensions_len) = file_exts_len;
335 : }
336 :
337 4 : if (SPL_G(autoload_extensions) == NULL) {
338 1 : RETURN_STRINGL(SPL_DEFAULT_FILE_EXTENSIONS, sizeof(SPL_DEFAULT_FILE_EXTENSIONS) - 1, 1);
339 : } else {
340 3 : RETURN_STRINGL(SPL_G(autoload_extensions), SPL_G(autoload_extensions_len), 1);
341 : }
342 : } /* }}} */
343 :
344 : typedef struct {
345 : zend_function *func_ptr;
346 : zval *obj;
347 : zend_class_entry *ce;
348 : } autoload_func_info;
349 :
350 : static void autoload_func_info_dtor(autoload_func_info *alfi)
351 26 : {
352 26 : if (alfi->obj) {
353 7 : zval_ptr_dtor(&alfi->obj);
354 : }
355 26 : }
356 :
357 : /* {{{ proto void spl_autoload_call(string class_name)
358 : Try all registerd autoload function to load the requested class */
359 : PHP_FUNCTION(spl_autoload_call)
360 15 : {
361 15 : zval *class_name, *retval = NULL;
362 : int class_name_len;
363 : char *func_name, *lc_name;
364 : uint func_name_len;
365 : ulong dummy;
366 : HashPosition function_pos;
367 : autoload_func_info *alfi;
368 :
369 15 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &class_name) == FAILURE || Z_TYPE_P(class_name) != IS_STRING) {
370 0 : return;
371 : }
372 :
373 15 : if (SPL_G(autoload_functions)) {
374 15 : int l_autoload_running = SPL_G(autoload_running);
375 15 : SPL_G(autoload_running) = 1;
376 15 : class_name_len = Z_STRLEN_P(class_name);
377 15 : lc_name = zend_str_tolower_dup(Z_STRVAL_P(class_name), class_name_len);
378 15 : zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos);
379 46 : while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS && !EG(exception)) {
380 21 : zend_hash_get_current_key_ex(SPL_G(autoload_functions), &func_name, &func_name_len, &dummy, 0, &function_pos);
381 21 : zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos);
382 21 : zend_call_method(alfi->obj ? &alfi->obj : NULL, alfi->ce, &alfi->func_ptr, func_name, func_name_len, &retval, 1, class_name, NULL TSRMLS_CC);
383 21 : if (retval) {
384 14 : zval_ptr_dtor(&retval);
385 : }
386 21 : if (zend_hash_exists(EG(class_table), lc_name, class_name_len + 1)) {
387 5 : break;
388 : }
389 16 : zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos);
390 : }
391 15 : efree(lc_name);
392 15 : SPL_G(autoload_running) = l_autoload_running;
393 : } else {
394 : /* do not use or overwrite &EG(autoload_func) here */
395 0 : zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload", NULL, class_name);
396 : }
397 : } /* }}} */
398 :
399 : /* {{{ proto bool spl_autoload_register([mixed autoload_function = "spl_autoload" [, throw = true]])
400 : Register given function as __autoload() implementation */
401 : PHP_FUNCTION(spl_autoload_register)
402 46 : {
403 : char *func_name;
404 : int func_name_len;
405 46 : char *lc_name = NULL;
406 46 : zval *zcallable = NULL;
407 46 : zend_bool do_throw = 1;
408 : zend_function *spl_func_ptr;
409 : autoload_func_info alfi;
410 : zval **obj_ptr;
411 :
412 46 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "|zb", &zcallable, &do_throw) == FAILURE) {
413 0 : return;
414 : }
415 :
416 46 : if (ZEND_NUM_ARGS()) {
417 42 : if (Z_TYPE_P(zcallable) == IS_STRING) {
418 22 : if (Z_STRLEN_P(zcallable) == sizeof("spl_autoload_call") - 1) {
419 0 : if (!zend_binary_strcasecmp(Z_STRVAL_P(zcallable), sizeof("spl_autoload_call"), "spl_autoload_call", sizeof("spl_autoload_call"))) {
420 0 : if (do_throw) {
421 0 : zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function spl_autoload_call() cannot be registered");
422 : }
423 0 : RETURN_FALSE;
424 : }
425 : }
426 : }
427 :
428 42 : if (!zend_is_callable_ex(zcallable, IS_CALLABLE_STRICT, &func_name, &func_name_len, &alfi.ce, &alfi.func_ptr, &obj_ptr TSRMLS_CC)) {
429 12 : if (Z_TYPE_P(zcallable) == IS_ARRAY) {
430 7 : if (!obj_ptr && alfi.func_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
431 3 : if (do_throw) {
432 3 : zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array specifies a non static method but no object");
433 : }
434 3 : efree(func_name);
435 3 : RETURN_FALSE;
436 : }
437 4 : else if (do_throw) {
438 4 : zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array does not specify %s %smethod", alfi.func_ptr ? "a callable" : "an existing", !obj_ptr ? "static " : "");
439 : }
440 4 : efree(func_name);
441 4 : RETURN_FALSE;
442 5 : } else if (Z_TYPE_P(zcallable) == IS_STRING) {
443 5 : if (do_throw) {
444 5 : zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function '%s' not %s", func_name, alfi.func_ptr ? "callable" : "found");
445 : }
446 5 : efree(func_name);
447 5 : RETURN_FALSE;
448 : } else {
449 0 : if (do_throw) {
450 0 : zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Illegal value passed");
451 : }
452 0 : efree(func_name);
453 0 : RETURN_FALSE;
454 : }
455 : }
456 :
457 30 : lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1);
458 30 : zend_str_tolower_copy(lc_name, func_name, func_name_len);
459 30 : efree(func_name);
460 :
461 30 : if (SPL_G(autoload_functions) && zend_hash_exists(SPL_G(autoload_functions), (char*)lc_name, func_name_len+1)) {
462 5 : goto skip;
463 : }
464 :
465 32 : if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
466 : /* add object id to the hash to ensure uniqueness, for more reference look at bug #40091 */
467 7 : lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle));
468 7 : memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_PP(obj_ptr), sizeof(zend_object_handle));
469 7 : func_name_len += sizeof(zend_object_handle);
470 7 : lc_name[func_name_len] = '\0';
471 7 : alfi.obj = *obj_ptr;
472 7 : alfi.obj->refcount++;
473 : } else {
474 18 : alfi.obj = NULL;
475 : }
476 :
477 25 : if (!SPL_G(autoload_functions)) {
478 12 : ALLOC_HASHTABLE(SPL_G(autoload_functions));
479 12 : zend_hash_init(SPL_G(autoload_functions), 1, NULL, (dtor_func_t) autoload_func_info_dtor, 0);
480 : }
481 :
482 25 : zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr);
483 :
484 25 : if (EG(autoload_func) == spl_func_ptr) { /* registered already, so we insert that first */
485 : autoload_func_info spl_alfi;
486 :
487 1 : spl_alfi.func_ptr = spl_func_ptr;
488 1 : spl_alfi.obj = NULL;
489 1 : spl_alfi.ce = NULL;
490 1 : zend_hash_add(SPL_G(autoload_functions), "spl_autoload", sizeof("spl_autoload"), &spl_alfi, sizeof(autoload_func_info), NULL);
491 : }
492 :
493 25 : zend_hash_add(SPL_G(autoload_functions), lc_name, func_name_len+1, &alfi.func_ptr, sizeof(autoload_func_info), NULL);
494 30 : skip:
495 30 : efree(lc_name);
496 : }
497 :
498 34 : if (SPL_G(autoload_functions)) {
499 30 : zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &EG(autoload_func));
500 : } else {
501 4 : zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &EG(autoload_func));
502 : }
503 34 : RETURN_TRUE;
504 : } /* }}} */
505 :
506 : /* {{{ proto bool spl_autoload_unregister(mixed autoload_function)
507 : Unregister given function as __autoload() implementation */
508 : PHP_FUNCTION(spl_autoload_unregister)
509 11 : {
510 : char *func_name;
511 : int func_name_len;
512 : zval *zcallable;
513 11 : int success = FAILURE;
514 : zend_function *spl_func_ptr;
515 : zval **obj_ptr;
516 :
517 11 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zcallable) == FAILURE) {
518 0 : return;
519 : }
520 :
521 11 : if (!zend_is_callable_ex(zcallable, IS_CALLABLE_CHECK_SYNTAX_ONLY, &func_name, &func_name_len, NULL, NULL, &obj_ptr TSRMLS_CC)) {
522 0 : if (func_name) {
523 0 : efree(func_name);
524 : }
525 0 : RETURN_FALSE;
526 : }
527 :
528 11 : zend_str_tolower(func_name, func_name_len);
529 :
530 11 : if (SPL_G(autoload_functions)) {
531 10 : if (func_name_len == sizeof("spl_autoload_call")-1 && !strcmp(func_name, "spl_autoload_call")) {
532 : /* remove all */
533 1 : zend_hash_destroy(SPL_G(autoload_functions));
534 1 : FREE_HASHTABLE(SPL_G(autoload_functions));
535 1 : SPL_G(autoload_functions) = NULL;
536 1 : EG(autoload_func) = NULL;
537 1 : success = SUCCESS;
538 : } else {
539 : /* remove specific */
540 8 : success = zend_hash_del(SPL_G(autoload_functions), func_name, func_name_len+1);
541 8 : if (success != SUCCESS && obj_ptr) {
542 1 : func_name = erealloc(func_name, func_name_len + 1 + sizeof(zend_object_handle));
543 1 : memcpy(func_name + func_name_len, &Z_OBJ_HANDLE_PP(obj_ptr), sizeof(zend_object_handle));
544 1 : func_name_len += sizeof(zend_object_handle);
545 1 : func_name[func_name_len] = '\0';
546 1 : success = zend_hash_del(SPL_G(autoload_functions), func_name, func_name_len+1);
547 : }
548 : }
549 2 : } else if (func_name_len == sizeof("spl_autoload")-1 && !strcmp(func_name, "spl_autoload")) {
550 : /* register single spl_autoload() */
551 2 : zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr);
552 :
553 2 : if (EG(autoload_func) == spl_func_ptr) {
554 2 : success = SUCCESS;
555 2 : EG(autoload_func) = NULL;
556 : }
557 : }
558 :
559 11 : efree(func_name);
560 11 : RETURN_BOOL(success == SUCCESS);
561 : } /* }}} */
562 :
563 : /* {{{ proto false|array spl_autoload_functions()
564 : Return all registered __autoload() functionns */
565 : PHP_FUNCTION(spl_autoload_functions)
566 24 : {
567 : zend_function *fptr;
568 : HashPosition function_pos;
569 : autoload_func_info *alfi;
570 :
571 24 : if (!EG(autoload_func)) {
572 4 : if (zend_hash_find(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), (void **) &fptr) == SUCCESS) {
573 0 : array_init(return_value);
574 0 : add_next_index_stringl(return_value, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)-1, 1);
575 0 : return;
576 : }
577 4 : RETURN_FALSE;
578 : }
579 :
580 20 : zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &fptr);
581 :
582 20 : if (EG(autoload_func) == fptr) {
583 18 : array_init(return_value);
584 18 : zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos);
585 51 : while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS) {
586 15 : zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos);
587 15 : if (alfi->func_ptr->common.scope) {
588 : zval *tmp;
589 9 : MAKE_STD_ZVAL(tmp);
590 9 : array_init(tmp);
591 :
592 9 : if (alfi->obj) {
593 4 : alfi->obj->refcount++;
594 4 : add_next_index_zval(tmp, alfi->obj);
595 : } else {
596 5 : add_next_index_string(tmp, alfi->ce->name, 1);
597 : }
598 9 : add_next_index_string(tmp, alfi->func_ptr->common.function_name, 1);
599 9 : add_next_index_zval(return_value, tmp);
600 : } else
601 6 : add_next_index_string(return_value, alfi->func_ptr->common.function_name, 1);
602 :
603 15 : zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos);
604 : }
605 18 : return;
606 : }
607 :
608 2 : array_init(return_value);
609 2 : add_next_index_string(return_value, EG(autoload_func)->common.function_name, 1);
610 : } /* }}} */
611 :
612 : /* {{{ proto string spl_object_hash(object obj)
613 : Return hash id for given object */
614 : PHP_FUNCTION(spl_object_hash)
615 3 : {
616 : zval *obj;
617 : int len;
618 : char *hash;
619 : char md5str[33];
620 : PHP_MD5_CTX context;
621 : unsigned char digest[16];
622 :
623 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
624 2 : return;
625 : }
626 :
627 1 : len = spprintf(&hash, 0, "%p:%d", Z_OBJ_HT_P(obj), Z_OBJ_HANDLE_P(obj));
628 :
629 1 : md5str[0] = '\0';
630 1 : PHP_MD5Init(&context);
631 1 : PHP_MD5Update(&context, (unsigned char*)hash, len);
632 1 : PHP_MD5Final(digest, &context);
633 1 : make_digest(md5str, digest);
634 1 : RETVAL_STRING(md5str, 1);
635 1 : efree(hash);
636 : }
637 :
638 : int spl_build_class_list_string(zval **entry, char **list TSRMLS_DC) /* {{{ */
639 258 : {
640 : char *res;
641 :
642 258 : spprintf(&res, 0, "%s, %s", *list, Z_STRVAL_PP(entry));
643 258 : efree(*list);
644 258 : *list = res;
645 258 : return ZEND_HASH_APPLY_KEEP;
646 : } /* }}} */
647 :
648 : /* {{{ PHP_MINFO(spl)
649 : */
650 : PHP_MINFO_FUNCTION(spl)
651 6 : {
652 : zval list;
653 : char *strg;
654 :
655 6 : php_info_print_table_start();
656 6 : php_info_print_table_header(2, "SPL support", "enabled");
657 :
658 6 : INIT_PZVAL(&list);
659 6 : array_init(&list);
660 6 : SPL_LIST_CLASSES(&list, 0, 1, ZEND_ACC_INTERFACE)
661 6 : strg = estrdup("");
662 6 : zend_hash_apply_with_argument(Z_ARRVAL_P(&list), (apply_func_arg_t)spl_build_class_list_string, &strg TSRMLS_CC);
663 6 : zval_dtor(&list);
664 6 : php_info_print_table_row(2, "Interfaces", strg + 2);
665 6 : efree(strg);
666 :
667 6 : INIT_PZVAL(&list);
668 6 : array_init(&list);
669 6 : SPL_LIST_CLASSES(&list, 0, -1, ZEND_ACC_INTERFACE)
670 6 : strg = estrdup("");
671 6 : zend_hash_apply_with_argument(Z_ARRVAL_P(&list), (apply_func_arg_t)spl_build_class_list_string, &strg TSRMLS_CC);
672 6 : zval_dtor(&list);
673 6 : php_info_print_table_row(2, "Classes", strg + 2);
674 6 : efree(strg);
675 :
676 6 : php_info_print_table_end();
677 6 : }
678 : /* }}} */
679 :
680 : static
681 : ZEND_BEGIN_ARG_INFO_EX(arginfo_iterator_to_array, 0, 0, 1)
682 : ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
683 : ZEND_ARG_INFO(0, use_keys)
684 : ZEND_END_ARG_INFO();
685 :
686 : static
687 : ZEND_BEGIN_ARG_INFO(arginfo_iterator, 0)
688 : ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
689 : ZEND_END_ARG_INFO();
690 :
691 : static
692 : ZEND_BEGIN_ARG_INFO_EX(arginfo_iterator_apply, 0, 0, 2)
693 : ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
694 : ZEND_ARG_INFO(0, function)
695 : ZEND_ARG_ARRAY_INFO(0, args, 1)
696 : ZEND_END_ARG_INFO();
697 :
698 : /* {{{ spl_functions
699 : */
700 : zend_function_entry spl_functions[] = {
701 : PHP_FE(spl_classes, NULL)
702 : PHP_FE(spl_autoload, NULL)
703 : PHP_FE(spl_autoload_extensions, NULL)
704 : PHP_FE(spl_autoload_register, NULL)
705 : PHP_FE(spl_autoload_unregister, NULL)
706 : PHP_FE(spl_autoload_functions, NULL)
707 : PHP_FE(spl_autoload_call, NULL)
708 : PHP_FE(class_parents, NULL)
709 : PHP_FE(class_implements, NULL)
710 : PHP_FE(spl_object_hash, NULL)
711 : #ifdef SPL_ITERATORS_H
712 : PHP_FE(iterator_to_array, arginfo_iterator_to_array)
713 : PHP_FE(iterator_count, arginfo_iterator)
714 : PHP_FE(iterator_apply, arginfo_iterator_apply)
715 : #endif /* SPL_ITERATORS_H */
716 : {NULL, NULL, NULL}
717 : };
718 : /* }}} */
719 :
720 : /* {{{ PHP_MINIT_FUNCTION(spl)
721 : */
722 : PHP_MINIT_FUNCTION(spl)
723 13565 : {
724 13565 : PHP_MINIT(spl_iterators)(INIT_FUNC_ARGS_PASSTHRU);
725 13565 : PHP_MINIT(spl_array)(INIT_FUNC_ARGS_PASSTHRU);
726 13565 : PHP_MINIT(spl_directory)(INIT_FUNC_ARGS_PASSTHRU);
727 13565 : PHP_MINIT(spl_sxe)(INIT_FUNC_ARGS_PASSTHRU);
728 13565 : PHP_MINIT(spl_exceptions)(INIT_FUNC_ARGS_PASSTHRU);
729 13565 : PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU);
730 :
731 13565 : return SUCCESS;
732 : }
733 : /* }}} */
734 :
735 : PHP_RINIT_FUNCTION(spl) /* {{{ */
736 13551 : {
737 13551 : SPL_G(autoload_extensions) = NULL;
738 13551 : SPL_G(autoload_extensions_len) = 0;
739 13551 : SPL_G(autoload_functions) = NULL;
740 13551 : return SUCCESS;
741 : } /* }}} */
742 :
743 : PHP_RSHUTDOWN_FUNCTION(spl) /* {{{ */
744 13584 : {
745 13584 : if (SPL_G(autoload_extensions)) {
746 1 : efree(SPL_G(autoload_extensions));
747 1 : SPL_G(autoload_extensions) = NULL;
748 1 : SPL_G(autoload_extensions_len) = 0;
749 : }
750 13584 : if (SPL_G(autoload_functions)) {
751 11 : zend_hash_destroy(SPL_G(autoload_functions));
752 11 : FREE_HASHTABLE(SPL_G(autoload_functions));
753 11 : SPL_G(autoload_functions) = NULL;
754 : }
755 13584 : return SUCCESS;
756 : } /* }}} */
757 :
758 : #ifdef HAVE_SIMPLEXML
759 : static zend_module_dep spl_deps[] = {
760 : ZEND_MOD_REQUIRED("libxml")
761 : ZEND_MOD_REQUIRED("simplexml")
762 : {NULL, NULL, NULL}
763 : };
764 : #endif
765 :
766 : /* {{{ spl_module_entry
767 : */
768 : zend_module_entry spl_module_entry = {
769 : #ifdef HAVE_SIMPLEXML
770 : STANDARD_MODULE_HEADER_EX, NULL,
771 : spl_deps,
772 : #else
773 : STANDARD_MODULE_HEADER,
774 : #endif
775 : "SPL",
776 : spl_functions,
777 : PHP_MINIT(spl),
778 : NULL,
779 : PHP_RINIT(spl),
780 : PHP_RSHUTDOWN(spl),
781 : PHP_MINFO(spl),
782 : "0.2",
783 : PHP_MODULE_GLOBALS(spl),
784 : PHP_GINIT(spl),
785 : NULL,
786 : NULL,
787 : STANDARD_MODULE_PROPERTIES_EX
788 : };
789 : /* }}} */
790 :
791 : /*
792 : * Local variables:
793 : * tab-width: 4
794 : * c-basic-offset: 4
795 : * End:
796 : * vim600: fdm=marker
797 : * vim: noet sw=4 ts=4
798 : */
|