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