You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

941 lines
30 KiB

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