1 /*
2 +----------------------------------------------------------------------+
3 | Yet Another Framework |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Xinchen Hui <laruence@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include "php.h"
22 #include "Zend/zend_interfaces.h" /* for zend_class_serialize_deny */
23 #include "ext/standard/php_string.h" /* php_trim */
24
25 #include "php_yaf.h"
26 #include "yaf_application.h"
27 #include "yaf_namespace.h"
28 #include "yaf_request.h"
29 #include "yaf_loader.h"
30 #include "yaf_exception.h"
31
32 #define YAF_LOADER_CONTROLLER "Controller"
33 #define YAF_LOADER_MODEL "Model"
34 #define YAF_LOADER_PLUGIN "Plugin"
35 #define YAF_LOADER_RESERVERD "Yaf_"
36
37 #define YAF_CLASS_NAME_NORMAL 0
38 #define YAF_CLASS_NAME_MODEL 1
39 #define YAF_CLASS_NAME_PLUGIN 2
40 #define YAF_CLASS_NAME_CONTROLLER 3
41
42 zend_class_entry *yaf_loader_ce;
43 static zend_object_handlers yaf_loader_obj_handlers;
44
45 /** {{{ ARG_INFO
46 */
47 ZEND_BEGIN_ARG_INFO_EX(yaf_loader_void_arginfo, 0, 0, 0)
ZEND_END_ARG_INFO()48 ZEND_END_ARG_INFO()
49
50 ZEND_BEGIN_ARG_INFO_EX(yaf_loader_getinstance_arginfo, 0, 0, 0)
51 ZEND_ARG_INFO(0, local_library_path)
52 ZEND_ARG_INFO(0, global_library_path)
53 ZEND_END_ARG_INFO()
54
55 ZEND_BEGIN_ARG_INFO_EX(yaf_loader_autoloader_arginfo, 0, 0, 1)
56 ZEND_ARG_INFO(0, class_name)
57 ZEND_END_ARG_INFO()
58
59 ZEND_BEGIN_ARG_INFO_EX(yaf_loader_regnamespace_arginfo, 0, 0, 1)
60 ZEND_ARG_INFO(0, namespace)
61 ZEND_ARG_INFO(0, path)
62 ZEND_END_ARG_INFO()
63
64 ZEND_BEGIN_ARG_INFO_EX(yaf_loader_islocalname_arginfo, 0, 0, 1)
65 ZEND_ARG_INFO(0, class_name)
66 ZEND_END_ARG_INFO()
67
68 ZEND_BEGIN_ARG_INFO_EX(yaf_loader_import_arginfo, 0, 0, 1)
69 ZEND_ARG_INFO(0, file)
70 ZEND_END_ARG_INFO()
71
72 ZEND_BEGIN_ARG_INFO_EX(yaf_loader_setlib_arginfo, 0, 0, 1)
73 ZEND_ARG_INFO(0, library_path)
74 ZEND_ARG_INFO(0, is_global)
75 ZEND_END_ARG_INFO()
76
77 ZEND_BEGIN_ARG_INFO_EX(yaf_loader_getlib_arginfo, 0, 0, 0)
78 ZEND_ARG_INFO(0, is_global)
79 ZEND_END_ARG_INFO()
80 /* }}} */
81
82 static void yaf_loader_obj_free(zend_object *object) /* {{{ */ {
83 yaf_loader_object *loader = (yaf_loader_object*)object;
84
85 if (loader->library) {
86 zend_string_release(loader->library);
87 }
88 if (loader->glibrary) {
89 zend_string_release(loader->glibrary);
90 }
91 if (GC_DELREF(YAF_LOADER_NAMESPACES(loader)) == 0) {
92 GC_REMOVE_FROM_BUFFER(YAF_LOADER_NAMESPACES(loader));
93 zend_array_destroy(YAF_LOADER_NAMESPACES(loader));
94 }
95 if (loader->properties) {
96 if (GC_DELREF(loader->properties) == 0) {
97 GC_REMOVE_FROM_BUFFER(loader->properties);
98 zend_array_destroy(loader->properties);
99 }
100 }
101
102 zend_object_std_dtor(object);
103 }
104 /* }}} */
105
yaf_loader_register(yaf_loader_t * loader)106 int yaf_loader_register(yaf_loader_t *loader) /* {{{ */ {
107 zval autoload, function, method, ret;
108
109 array_init(&autoload);
110
111 ZVAL_STRING(&method, YAF_AUTOLOAD_FUNC_NAME);
112 Z_ADDREF_P(loader);
113 zend_hash_next_index_insert(Z_ARRVAL(autoload), loader);
114 zend_hash_next_index_insert(Z_ARRVAL(autoload), &method);
115
116 ZVAL_STRING(&function, YAF_SPL_AUTOLOAD_REGISTER_NAME);
117
118 do {
119 zend_fcall_info fci = {
120 sizeof(fci),
121 #if PHP_VERSION_ID < 70100
122 EG(function_table),
123 #endif
124 function,
125 #if PHP_VERSION_ID < 70100
126 NULL,
127 #endif
128 &ret,
129 &autoload,
130 NULL,
131 1,
132 #if PHP_VERSION_ID < 80000
133 1
134 #else
135 NULL
136 #endif
137 };
138
139 if (zend_call_function(&fci, NULL) == FAILURE) {
140 zval_ptr_dtor(&function);
141 zval_ptr_dtor(&autoload);
142 php_error_docref(NULL,
143 E_WARNING,
144 "Unable to register autoload function %s",
145 YAF_AUTOLOAD_FUNC_NAME);
146 return 0;
147 }
148 zval_ptr_dtor(&function);
149 zval_ptr_dtor(&autoload);
150 } while (0);
151 return 1;
152 }
153 /* }}} */
154
yaf_loader_set_global_library_path(yaf_loader_object * loader,zend_string * global_library)155 void yaf_loader_set_global_library_path(yaf_loader_object *loader, zend_string *global_library) /* {{{ */ {
156 if (EXPECTED(loader->glibrary)) {
157 zend_string_release(loader->glibrary);
158 }
159 loader->glibrary = zend_string_copy(global_library);
160 }
161 /* }}} */
162
yaf_loader_get_namespaces(yaf_loader_object * loader)163 static zend_array *yaf_loader_get_namespaces(yaf_loader_object *loader) /* {{{ */ {
164 zval *val, rv;
165 HashTable *ht;
166 zend_string *name;
167
168 ALLOC_HASHTABLE(ht);
169 zend_hash_init(ht, zend_hash_num_elements(YAF_LOADER_NAMESPACES(loader)), NULL, ZVAL_PTR_DTOR, 0);
170
171 ZEND_HASH_FOREACH_STR_KEY_VAL(YAF_LOADER_NAMESPACES(loader), name, val) {
172 ZEND_ASSERT(name);
173 if (Z_TYPE_P(val) == IS_NULL) {
174 ZVAL_STR_COPY(&rv, name);
175 zend_hash_next_index_insert(ht, &rv);
176 } else {
177 zend_hash_update(ht, name, val);
178 Z_TRY_ADDREF_P(val);
179 }
180 } ZEND_HASH_FOREACH_END();
181
182 return ht;
183 }
184 /* }}} */
185
yaf_loader_get_properties(yaf_object * obj)186 static HashTable *yaf_loader_get_properties(yaf_object *obj) /* {{{ */ {
187 zval rv;
188 HashTable *ht;
189 #if PHP_VERSION_ID < 80000
190 yaf_loader_object *loader = Z_YAFLOADEROBJ_P(obj);
191 #else
192 yaf_loader_object *loader = (yaf_loader_object*)(obj);
193 #endif
194
195 if (!loader->properties) {
196 ALLOC_HASHTABLE(loader->properties);
197 zend_hash_init(loader->properties, 4, NULL, ZVAL_PTR_DTOR, 0);
198 YAF_ALLOW_VIOLATION(loader->properties);;
199 }
200
201 ht = loader->properties;
202
203 ZVAL_STR_COPY(&rv, loader->library);
204 zend_hash_str_update(ht, "library:protected", sizeof("library:protected") - 1, &rv);
205 if (loader->glibrary) {
206 ZVAL_STR_COPY(&rv, loader->glibrary);
207 } else {
208 ZVAL_NULL(&rv);
209 }
210 zend_hash_str_update(ht, "global_library:protected", sizeof("global_library:protected") - 1, &rv);
211
212 ZVAL_ARR(&rv, yaf_loader_get_namespaces(loader));
213 zend_hash_str_update(ht, "namespace:protected", sizeof("namespace:protected") - 1, &rv);
214
215 ZVAL_BOOL(&rv, yaf_loader_use_spl_autoload(loader));
216 zend_hash_str_update(ht, "use_spl_autoload:protected", sizeof("use_spl_autoload:protected") - 1, &rv);
217
218 ZVAL_BOOL(&rv, yaf_loader_is_lowcase_path(loader));
219 zend_hash_str_update(ht, "lowercase_path:protected", sizeof("lowercase_path:protected") - 1, &rv);
220
221 ZVAL_BOOL(&rv, yaf_loader_is_name_suffix(loader));
222 zend_hash_str_update(ht, "is_name_suffix:protected", sizeof("is_name_suffix:protected") - 1, &rv);
223
224 ZVAL_BOOL(&rv, yaf_loader_has_name_separator(loader));
225 zend_hash_str_update(ht, "has_name_seperator:protected", sizeof("has_name_seperator:protected") - 1, &rv);
226
227 return ht;
228 }
229 /* }}} */
230
yaf_loader_reset(yaf_loader_object * loader)231 void yaf_loader_reset(yaf_loader_object *loader) /* {{{ */ {
232 /* for back-compatibility of change of YAF_G after loader in initialized only */
233 YAF_LOADER_FLAGS(loader) = (zend_uchar)YAF_FLAGS();
234 }
235 /* }}} */
236
yaf_loader_instance(zend_string * library_path)237 yaf_loader_t *yaf_loader_instance(zend_string *library_path) /* {{{ */ {
238 yaf_loader_object *loader;
239 yaf_loader_t *instance = &YAF_G(loader);
240
241 if (EXPECTED(IS_OBJECT == Z_TYPE_P(instance))) {
242 return instance;
243 }
244
245 loader = emalloc(sizeof(yaf_loader_object));
246 zend_object_std_init(&loader->std, yaf_loader_ce);
247 loader->std.handlers = &yaf_loader_obj_handlers;
248
249 /* yaf_loader_reset(loader); */
250 YAF_LOADER_FLAGS(loader) = (zend_uchar)YAF_FLAGS();
251 if (library_path) {
252 loader->library = zend_string_copy(library_path);
253 } else {
254 loader->library = ZSTR_EMPTY_ALLOC();
255 }
256
257 if (*YAF_G(global_library)) {
258 loader->glibrary = zend_string_init(YAF_G(global_library), strlen(YAF_G(global_library)), 0);
259 } else {
260 loader->glibrary = NULL;
261 }
262
263 ZVAL_OBJ(&YAF_G(loader), &loader->std);
264 if (UNEXPECTED(!yaf_loader_register(&YAF_G(loader)))) {
265 php_error_docref(NULL, E_WARNING, "Failed to register autoload function");
266 }
267
268 ALLOC_HASHTABLE(YAF_LOADER_NAMESPACES(loader));
269 zend_hash_init(YAF_LOADER_NAMESPACES(loader), 8, NULL, ZVAL_PTR_DTOR, 0);
270 YAF_ALLOW_VIOLATION(YAF_LOADER_NAMESPACES(loader));
271
272 loader->properties = NULL;
273
274 return &YAF_G(loader);
275 }
276 /* }}} */
277
yaf_loader_register_namespace(yaf_loader_object * loader,zend_string * class_name,zend_string * path)278 int yaf_loader_register_namespace(yaf_loader_object *loader, zend_string *class_name, zend_string *path) /* {{{ */ {
279 zval *entry, rv;
280 HashTable *target;
281 char *delim;
282 char *name = ZSTR_VAL(class_name);
283 uint32_t len = ZSTR_LEN(class_name);
284
285 ZVAL_NULL(&rv);
286 target = YAF_LOADER_NAMESPACES(loader);
287
288 if (*name == '\\') {
289 name++;
290 len--;
291 }
292 if (((delim = memchr(name, '\\', len)) || (delim = memchr(name, '_', len)))) {
293 do {
294 loop:
295 if ((entry = zend_hash_str_find(target, name, delim - name)) == NULL) {
296 entry = zend_hash_str_update(target, name, delim - name, &rv);
297 array_init(entry);
298 } else if (UNEXPECTED(Z_TYPE_P(entry) != IS_ARRAY)) {
299 zval_ptr_dtor(entry);
300 array_init(entry);
301 }
302 len -= delim - name + 1;
303 name = delim + 1;
304 target = Z_ARRVAL_P(entry);
305 if (((delim = memchr(name, '\\', len)) || (delim = memchr(name, '_', len)))) {
306 goto loop;
307 } else {
308 entry = zend_hash_str_update(target, name, len, &rv);
309 }
310 } while (0);
311 } else {
312 entry = zend_hash_str_update(YAF_LOADER_NAMESPACES(loader), name, len, &rv);
313 }
314
315 if (path) {
316 ZVAL_STR_COPY(entry, path);
317 }
318
319 return 1;
320 }
321 /* }}} */
322
yaf_loader_register_namespace_multi(yaf_loader_object * loader,zval * namespaces)323 int yaf_loader_register_namespace_multi(yaf_loader_object *loader, zval *namespaces) /* {{{ */ {
324 zval *pzval;
325 HashTable *ht;
326 zend_string *key;
327
328 ht = Z_ARRVAL_P(namespaces);
329 ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, pzval) {
330 if (key == NULL) {
331 if (IS_STRING == Z_TYPE_P(pzval)) {
332 yaf_loader_register_namespace(loader, Z_STR_P(pzval), NULL);
333 }
334 } else {
335 if (IS_STRING == Z_TYPE_P(pzval)) {
336 yaf_loader_register_namespace(loader, key, Z_STR_P(pzval));
337 } else {
338 yaf_loader_register_namespace(loader, key, NULL);
339 }
340 }
341 } ZEND_HASH_FOREACH_END();
342
343 return 1;
344 }
345 /* }}} */
346
yaf_loader_sanitize_path(char * name,uint32_t len)347 static void yaf_loader_sanitize_path(char *name, uint32_t len) /* {{{ */ {
348 yaf_replace_chr(name, len, '_', DEFAULT_SLASH);
349 }
350 /* }}} */
351
yaf_loader_sanitize_name(char * name,uint32_t len,char * buf)352 static void yaf_loader_sanitize_name(char *name, uint32_t len, char *buf) /* {{{ */ {
353 memcpy(buf, name, len);
354 /* replace all '\' to '_' */
355 yaf_replace_chr(buf, len, '\\', '_');
356 }
357 /* }}} */
358
yaf_loader_resolve_namespace(yaf_loader_object * loader,const char * class_name,uint32_t * name_len)359 static zend_string *yaf_loader_resolve_namespace(yaf_loader_object *loader, const char *class_name, uint32_t *name_len) /* {{{ */ {
360 zval *name;
361 const char *delim;
362 uint32_t len = *name_len;
363 HashTable *target = YAF_LOADER_NAMESPACES(loader);
364
365 if ((delim = memchr(class_name, '_', len))) {
366 do {
367 if ((name = zend_hash_str_find(target, class_name, delim - class_name))) {
368 if (Z_TYPE_P(name) == IS_ARRAY) {
369 target = Z_ARRVAL_P(name);
370 len -= delim - class_name + 1;
371 class_name = delim + 1;
372 } else if (Z_TYPE_P(name) == IS_STRING) {
373 *name_len = (len - (delim - class_name + 1));
374 return Z_STR_P(name);
375 } else {
376 return (zend_string*)-1; /* use library path */
377 }
378 } else {
379 return NULL;
380 }
381 } while ((delim = memchr(class_name, '_', len)));
382 } else if ((name = zend_hash_str_find(target, class_name, len))) {
383 return Z_TYPE_P(name) == IS_STRING? Z_STR_P(name) : (zend_string*)-1;
384 }
385 return NULL;
386 }
387 /* }}} */
388
yaf_loader_identify_category(yaf_loader_object * loader,zend_string * class_name)389 static int yaf_loader_identify_category(yaf_loader_object *loader, zend_string *class_name) /* {{{ */ {
390 char *name = ZSTR_VAL(class_name);
391 size_t len = ZSTR_LEN(class_name);
392 char *suspense_name;
393 int suspense_len;
394 int suspense_type = YAF_CLASS_NAME_NORMAL;
395
396 if (EXPECTED(yaf_loader_is_name_suffix(loader))) {
397 switch (name[len - 1]) {
398 case 'l':
399 suspense_name = YAF_LOADER_MODEL;
400 suspense_len = sizeof(YAF_LOADER_MODEL) - 1;
401 suspense_type = YAF_CLASS_NAME_MODEL;
402 break;
403 case 'n':
404 suspense_name = YAF_LOADER_PLUGIN;
405 suspense_len = sizeof(YAF_LOADER_PLUGIN) - 1;
406 suspense_type = YAF_CLASS_NAME_PLUGIN;
407 break;
408 case 'r':
409 suspense_name = YAF_LOADER_CONTROLLER;
410 suspense_len = sizeof(YAF_LOADER_CONTROLLER) - 1;
411 suspense_type = YAF_CLASS_NAME_CONTROLLER;
412 break;
413 default:
414 return YAF_CLASS_NAME_NORMAL;
415 }
416 if (len <= suspense_len || !yaf_slip_equal(name + len - suspense_len, suspense_name, suspense_len - 1)) {
417 return YAF_CLASS_NAME_NORMAL;
418 }
419 if (UNEXPECTED(yaf_loader_has_name_separator(loader))) {
420 name += (len - suspense_len);
421 if (len > YAF_G(name_separator_len) &&
422 memcmp(name - YAF_G(name_separator_len), YAF_G(name_separator), YAF_G(name_separator_len)) == 0) {
423 return suspense_type;
424 }
425 return YAF_CLASS_NAME_NORMAL;
426 }
427 return suspense_type;
428 } else {
429 switch (*name) {
430 case 'M':
431 suspense_name = YAF_LOADER_MODEL;
432 suspense_len = sizeof(YAF_LOADER_MODEL) - 1;
433 suspense_type = YAF_CLASS_NAME_MODEL;
434 break;
435 case 'P':
436 suspense_name = YAF_LOADER_PLUGIN;
437 suspense_len = sizeof(YAF_LOADER_PLUGIN) - 1;
438 suspense_type = YAF_CLASS_NAME_PLUGIN;
439 break;
440 case 'C':
441 suspense_name = YAF_LOADER_CONTROLLER;
442 suspense_len = sizeof(YAF_LOADER_CONTROLLER) - 1;
443 suspense_type = YAF_CLASS_NAME_CONTROLLER;
444 break;
445 default:
446 return YAF_CLASS_NAME_NORMAL;
447 }
448 if (len <= suspense_len || !yaf_slip_equal(name + 1, suspense_name + 1, suspense_len - 1)) {
449 return YAF_CLASS_NAME_NORMAL;
450 }
451 if (UNEXPECTED(yaf_loader_has_name_separator(loader))) {
452 name += suspense_len;
453 if (len > YAF_G(name_separator_len) &&
454 memcmp(name, YAF_G(name_separator), YAF_G(name_separator_len)) == 0) {
455 return suspense_type;
456 }
457 return YAF_CLASS_NAME_NORMAL;
458 }
459 return suspense_type;
460 }
461 }
462 /* }}} */
463
yaf_loader_import(const char * path,uint32_t len)464 ZEND_HOT int yaf_loader_import(const char *path, uint32_t len) /* {{{ */ {
465 zend_file_handle file_handle;
466 zend_op_array *op_array;
467 zend_stat_t sb;
468
469 if (UNEXPECTED(VCWD_STAT(path, &sb) == -1)) {
470 return 0;
471 }
472
473 #if PHP_VERSION_ID < 70400
474 file_handle.filename = path;
475 file_handle.type = ZEND_HANDLE_FILENAME;
476 file_handle.free_filename = 0;
477 file_handle.opened_path = NULL;
478 file_handle.handle.fp = NULL;
479 #else
480 /* setup file-handle */
481 zend_stream_init_filename(&file_handle, path);
482 #endif
483
484 if (EXPECTED((op_array = zend_compile_file(&file_handle, ZEND_INCLUDE)))) {
485 zval result;
486 if (EXPECTED(file_handle.handle.stream.handle)) {
487 if (UNEXPECTED(!file_handle.opened_path)) {
488 file_handle.opened_path = zend_string_init(path, len, 0);
489 }
490 zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path);
491 }
492
493 ZVAL_UNDEF(&result);
494 zend_execute(op_array, &result);
495 destroy_op_array(op_array);
496 efree_size(op_array, sizeof(zend_op_array));
497 zval_ptr_dtor(&result);
498 zend_destroy_file_handle(&file_handle);
499
500 return 1;
501 }
502
503 zend_destroy_file_handle(&file_handle);
504 return 0;
505 }
506 /* }}} */
507
yaf_loader_load_internal(yaf_loader_object * loader,char * filename,size_t fname_len,char * directory,uint32_t directory_len)508 ZEND_HOT int yaf_loader_load_internal(yaf_loader_object *loader, char *filename, size_t fname_len, char *directory, uint32_t directory_len) /* {{{ */ {
509 char *ext;
510 uint32_t ext_len;
511 yaf_application_object *app = yaf_application_instance();
512
513 if (UNEXPECTED(app->ext)) {
514 ext = ZSTR_VAL(app->ext);
515 ext_len = ZSTR_LEN(app->ext);
516 } else {
517 ext = YAF_DEFAULT_EXT;
518 ext_len = sizeof(YAF_DEFAULT_EXT) - 1;
519 }
520
521 if (UNEXPECTED((directory_len + fname_len + ext_len + 3) > MAXPATHLEN)) {
522 directory[directory_len] = '\0';
523 return 0;
524 }
525
526 directory[directory_len] = DEFAULT_SLASH;
527 memcpy(directory + directory_len + 1, filename, fname_len);
528 filename = directory + directory_len + 1;
529 if (UNEXPECTED(yaf_loader_is_lowcase_path(loader))) {
530 zend_str_tolower(filename, fname_len);
531 }
532 yaf_loader_sanitize_path(filename, fname_len);
533 directory[directory_len + 1 + fname_len] = '.';
534 memcpy(directory + directory_len + 1 + fname_len + 1, ext, ext_len);
535 /* aussume all the path is not end in slash */
536 directory[directory_len + 1 + fname_len + 1 + ext_len] = '\0';
537 directory_len = directory_len + 1 + fname_len + 1 + ext_len;
538
539 return yaf_loader_import(directory, directory_len);
540 }
541 /* }}} */
542
yaf_loader_load_user(yaf_loader_object * loader,char * buf,uint32_t len)543 ZEND_HOT static int yaf_loader_load_user(yaf_loader_object *loader, char *buf, uint32_t len) /* {{{ */ {
544 zend_string *library_dir;
545 const char *ext;
546 char *name = buf;
547 uint32_t ext_len;
548 uint32_t origin_len = len;
549 yaf_application_object *app = yaf_application_instance();
550
551 if ((library_dir = yaf_loader_resolve_namespace(loader, buf, &len))) {
552 if (library_dir == ((zend_string*)-1)) {
553 library_dir = loader->library;
554 } else {
555 name += (origin_len - len);
556 }
557 } else {
558 if (!loader->glibrary) {
559 library_dir = loader->library;
560 } else {
561 library_dir = loader->glibrary;
562 }
563 }
564
565 if (UNEXPECTED(yaf_loader_is_lowcase_path(loader))) {
566 zend_str_tolower(name, len);
567 }
568 yaf_loader_sanitize_path(name, len);
569
570 if (EXPECTED(app) && UNEXPECTED(app->ext)) {
571 ext = ZSTR_VAL(app->ext);
572 ext_len = ZSTR_LEN(app->ext);
573 } else {
574 ext = YAF_DEFAULT_EXT;
575 ext_len = sizeof(YAF_DEFAULT_EXT) - 1;
576 }
577
578 ZEND_ASSERT(library_dir);
579 if (UNEXPECTED(ZSTR_LEN(library_dir) + len + ext_len + 2 > MAXPATHLEN)) {
580 return 0;
581 }
582
583 memmove(buf + ZSTR_LEN(library_dir) + 1, name, len);
584 memcpy(buf, ZSTR_VAL(library_dir), ZSTR_LEN(library_dir));
585 buf[ZSTR_LEN(library_dir)] = DEFAULT_SLASH;
586 buf[ZSTR_LEN(library_dir) + 1 + len] = '.';
587 memcpy(buf + ZSTR_LEN(library_dir) + 1 + len + 1, ext, ext_len);
588 buf[ZSTR_LEN(library_dir) + 1 + len + 1 + ext_len] = '\0';
589 len = ZSTR_LEN(library_dir) + 1 + len + 1 + ext_len;
590
591 return yaf_loader_import(buf, len);
592 }
593 /* }}} */
594
yaf_loader_load_mvc(yaf_loader_object * loader,char * buf,uint32_t len,int type)595 static zend_never_inline int yaf_loader_load_mvc(yaf_loader_object *loader, char *buf, uint32_t len, int type) /* {{{ */ {
596 char *name;
597 const char *folder, *ext;
598 uint32_t folder_len, ext_len;
599 zend_string *library_dir;
600 yaf_application_object *app = yaf_application_instance();
601
602 if (UNEXPECTED(app == NULL)) {
603 php_error_docref(NULL, E_WARNING, "Couldn't load a MVC class unless an %s is initialized", ZSTR_VAL(yaf_application_ce->name));
604 *buf = '\0';
605 return 0;
606 }
607
608 switch (type) {
609 case YAF_CLASS_NAME_MODEL:
610 folder = YAF_MODEL_DIRECTORY_NAME;
611 folder_len = sizeof(YAF_MODEL_DIRECTORY_NAME) - 1;
612 break;
613 case YAF_CLASS_NAME_PLUGIN:
614 folder = YAF_PLUGIN_DIRECTORY_NAME;
615 folder_len = sizeof(YAF_PLUGIN_DIRECTORY_NAME) - 1;
616 break;
617 case YAF_CLASS_NAME_CONTROLLER:
618 folder = YAF_CONTROLLER_DIRECTORY_NAME;
619 folder_len = sizeof(YAF_CONTROLLER_DIRECTORY_NAME) - 1;
620 break;
621 default:
622 ZEND_ASSERT(0);
623 break;
624 }
625
626 len -= (folder_len - 1); /* models -> model etc*/
627 if (EXPECTED(yaf_loader_is_name_suffix(loader))) {
628 name = buf;
629 if (UNEXPECTED(yaf_loader_has_name_separator(loader))) {
630 len -= YAF_G(name_separator_len);
631 }
632 } else {
633 name = buf + folder_len - 1;
634 if (UNEXPECTED(yaf_loader_has_name_separator(loader))) {
635 name += YAF_G(name_separator_len);
636 len -= YAF_G(name_separator_len);
637 }
638 }
639 if (UNEXPECTED(yaf_loader_is_lowcase_path(loader))) {
640 zend_str_tolower(name, len);
641 }
642 yaf_loader_sanitize_path(name, len);
643
644 if (UNEXPECTED(app->ext)) {
645 ext = ZSTR_VAL(app->ext);
646 ext_len = ZSTR_LEN(app->ext);
647 } else {
648 ext = YAF_DEFAULT_EXT;
649 ext_len = sizeof(YAF_DEFAULT_EXT) - 1;
650 }
651
652 if (UNEXPECTED(ZSTR_LEN(app->directory) + 1 + folder_len + 1 + len + 1 + ext_len > MAXPATHLEN)) {
653 php_error_docref(NULL, E_WARNING, "Path too long '%s'", ZSTR_VAL(app->directory));
654 *buf = '\0';
655 return 0;
656 }
657
658 library_dir = app->directory;
659 memmove(buf + ZSTR_LEN(library_dir) + 1 + folder_len + 1, name, len);
660 memcpy(buf, ZSTR_VAL(library_dir), ZSTR_LEN(library_dir));
661 buf[ZSTR_LEN(library_dir)] = DEFAULT_SLASH;
662 memcpy(buf + ZSTR_LEN(library_dir) + 1, folder, folder_len);
663 buf[ZSTR_LEN(library_dir) + 1 + folder_len] = DEFAULT_SLASH;
664 buf[ZSTR_LEN(library_dir) + 1 + folder_len + 1 + len] = '.';
665 memcpy(buf + ZSTR_LEN(library_dir) + 1 + folder_len + 1 + len + 1, ext, ext_len);
666 buf[ZSTR_LEN(library_dir) + 1 + folder_len + 1 + len + 1 + ext_len] = '\0';
667
668 return yaf_loader_import(buf, len);
669 }
670 /* }}} */
671
672 /** {{{ proto public Yaf_Loader::autoload($class_name)
673 */
PHP_METHOD(yaf_loader,autoload)674 PHP_METHOD(yaf_loader, autoload) {
675 char directory[MAXPATHLEN];
676 uint32_t class_type, status;
677 zend_string *class_name;
678 zend_string *unqualified = NULL;
679 yaf_loader_object *loader = Z_YAFLOADEROBJ_P(getThis());
680
681 ZEND_PARSE_PARAMETERS_START(1, 1)
682 Z_PARAM_STR(class_name)
683 ZEND_PARSE_PARAMETERS_END();
684
685 if (UNEXPECTED(ZSTR_LEN(class_name) == 0 || ZSTR_LEN(class_name) > MAXPATHLEN)) {
686 RETURN_FALSE;
687 }
688
689 /*
690 if (UNEXPECTED(ZSTR_LEN(class_name) >= sizeof(YAF_LOADER_RESERVERD) - 1 &&
691 yaf_slip_equal(ZSTR_VAL(class_name), YAF_LOADER_RESERVERD, sizeof(YAF_LOADER_RESERVERD) - 1))) {
692 php_error_docref(NULL, E_WARNING, "You should not use '%s' as class name prefix", YAF_LOADER_RESERVERD);
693 }
694 */
695 if (ZSTR_VAL(class_name)[0] == '\\') {
696 unqualified = zend_string_init(ZSTR_VAL(class_name) + 1, ZSTR_LEN(class_name) - 1, 0);
697 class_name = unqualified;
698 }
699 yaf_loader_sanitize_name(ZSTR_VAL(class_name), ZSTR_LEN(class_name), directory);
700 if ((class_type = yaf_loader_identify_category(loader, class_name)) == YAF_CLASS_NAME_NORMAL) {
701 status = yaf_loader_load_user(loader, directory, ZSTR_LEN(class_name));
702 } else {
703 status = yaf_loader_load_mvc(loader, directory, ZSTR_LEN(class_name), class_type);
704 }
705
706 if (unqualified) {
707 zend_string_release(unqualified);
708 }
709 if (EXPECTED(!yaf_loader_use_spl_autoload(loader))) {
710 if (EXPECTED(status)) {
711 zend_string *lc_name = zend_string_tolower(class_name);
712 if (UNEXPECTED(!zend_hash_exists(EG(class_table), lc_name))) {
713 php_error_docref(NULL, E_WARNING, "Could not find class %s in %s", ZSTR_VAL(class_name), directory);
714 }
715 zend_string_release(lc_name);
716 } else if (*directory) {
717 php_error_docref(NULL, E_WARNING, "Failed opening script %s: %s", directory, strerror(errno));
718 }
719 RETURN_TRUE;
720 }
721 RETURN_BOOL(status);
722 }
723 /* }}} */
724
725 /** {{{ proto public static Yaf_Loader::import($file)
726 */
PHP_METHOD(yaf_loader,import)727 PHP_METHOD(yaf_loader, import) {
728 zend_string *file;
729 int need_free = 0;
730
731 ZEND_PARSE_PARAMETERS_START(1, 1)
732 Z_PARAM_STR(file)
733 ZEND_PARSE_PARAMETERS_END();
734
735 if (ZSTR_LEN(file) == 0) {
736 RETURN_FALSE;
737 } else {
738 int retval;
739
740 if (!IS_ABSOLUTE_PATH(ZSTR_VAL(file), ZSTR_LEN(file))) {
741 if (UNEXPECTED(Z_TYPE(YAF_G(loader)) != IS_OBJECT)) {
742 php_error_docref(NULL, E_WARNING, "%s need to be initialize first", ZSTR_VAL(yaf_loader_ce->name));
743 RETURN_FALSE;
744 } else {
745 yaf_loader_object *loader = Z_YAFLOADEROBJ(YAF_G(loader));
746 zend_string *library = loader->library;
747 file = strpprintf(0, "%s%c%s", ZSTR_VAL(library), DEFAULT_SLASH, ZSTR_VAL(file));
748 need_free = 1;
749 }
750 }
751
752 retval = zend_hash_exists(&EG(included_files), file);
753 if (retval) {
754 if (need_free) {
755 zend_string_release(file);
756 }
757 RETURN_TRUE;
758 }
759
760 retval = yaf_loader_import(ZSTR_VAL(file), ZSTR_LEN(file));
761 if (need_free) {
762 zend_string_release(file);
763 }
764
765 RETURN_BOOL(retval);
766 }
767 }
768 /* }}} */
769
770 /** {{{ proto public Yaf_Loader::registerLocalNamespace(mixed $namespace, string $path = NULL)
771 */
PHP_METHOD(yaf_loader,registerLocalNamespace)772 PHP_METHOD(yaf_loader, registerLocalNamespace) {
773 zval *namespaces;
774 zend_string *path = NULL;
775
776 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|S", &namespaces, &path) == FAILURE) {
777 return;
778 }
779
780 if (IS_STRING == Z_TYPE_P(namespaces)) {
781 if (yaf_loader_register_namespace(Z_YAFLOADEROBJ_P(getThis()), Z_STR_P(namespaces), path)) {
782 RETURN_ZVAL(getThis(), 1, 0);
783 }
784 } else if (IS_ARRAY == Z_TYPE_P(namespaces)) {
785 if (yaf_loader_register_namespace_multi(Z_YAFLOADEROBJ_P(getThis()), namespaces)) {
786 RETURN_ZVAL(getThis(), 1, 0);
787 }
788 } else {
789 php_error_docref(NULL, E_WARNING, "Invalid parameters provided, must be a string, or an array");
790 }
791
792 RETURN_FALSE;
793 }
794 /* }}} */
795
796 /** {{{ proto public Yaf_Loader::getLocalNamespace(void)
797 */
PHP_METHOD(yaf_loader,getLocalNamespace)798 PHP_METHOD(yaf_loader, getLocalNamespace) {
799 yaf_loader_object *loader = Z_YAFLOADEROBJ_P(getThis());
800
801 if (zend_parse_parameters_none() == FAILURE) {
802 return;
803 }
804
805 ZVAL_ARR(return_value, yaf_loader_get_namespaces(loader));
806 }
807 /* }}} */
808
809 /** {{{ proto public Yaf_Loader::clearLocalNamespace(void)
810 */
PHP_METHOD(yaf_loader,clearLocalNamespace)811 PHP_METHOD(yaf_loader, clearLocalNamespace) {
812 yaf_loader_object *loader = Z_YAFLOADEROBJ_P(getThis());
813
814 if (zend_parse_parameters_none() == FAILURE) {
815 return;
816 }
817
818 zend_hash_clean(YAF_LOADER_NAMESPACES(loader));
819
820 RETURN_TRUE;
821 }
822 /* }}} */
823
824 /** {{{ proto public Yaf_Loader::isLocalName(string $class_name)
825 */
PHP_METHOD(yaf_loader,isLocalName)826 PHP_METHOD(yaf_loader, isLocalName) {
827 zend_string *name;
828 int result;
829 char *sanitized_name;
830 uint32_t sanitized_len;
831 yaf_loader_object *loader = Z_YAFLOADEROBJ_P(getThis());
832 ALLOCA_FLAG(use_heap);
833
834 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
835 return;
836 }
837
838 if (ZSTR_VAL(name)[0] == '\\') {
839 sanitized_len = ZSTR_LEN(name) - 1;
840 sanitized_name = do_alloca(sanitized_len, use_heap);
841 yaf_loader_sanitize_name(ZSTR_VAL(name) + 1, sanitized_len, sanitized_name);
842 } else {
843 sanitized_len = ZSTR_LEN(name);
844 sanitized_name = do_alloca(sanitized_len, use_heap);
845 yaf_loader_sanitize_name(ZSTR_VAL(name), sanitized_len, sanitized_name);
846 }
847 result = YAF_LOADER_NAMESPACES(loader) && yaf_loader_resolve_namespace(loader, sanitized_name, &sanitized_len);
848 free_alloca(sanitized_name, use_heap);
849
850 RETURN_BOOL(result);
851 }
852 /* }}} */
853
854 /** {{{ proto public Yaf_Loader::getNamespacePath(string $class_name)
855 */
PHP_METHOD(yaf_loader,getNamespacePath)856 PHP_METHOD(yaf_loader, getNamespacePath) {
857 zend_string *name;
858 zend_string *path;
859 char *sanitized_name;
860 uint32_t sanitized_len;
861 yaf_loader_object *loader = Z_YAFLOADEROBJ_P(getThis());
862 ALLOCA_FLAG(use_heap);
863
864 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
865 return;
866 }
867
868 if (ZSTR_VAL(name)[0] == '\\') {
869 sanitized_len = ZSTR_LEN(name) - 1;
870 sanitized_name = do_alloca(sanitized_len, use_heap);
871 yaf_loader_sanitize_name(ZSTR_VAL(name) + 1, sanitized_len, sanitized_name);
872 } else {
873 sanitized_len = ZSTR_LEN(name);
874 sanitized_name = do_alloca(sanitized_len, use_heap);
875 yaf_loader_sanitize_name(ZSTR_VAL(name), sanitized_len, sanitized_name);
876 }
877 if ((path = yaf_loader_resolve_namespace(loader, sanitized_name, &sanitized_len))) {
878 if (path == ((zend_string*)-1)) {
879 RETVAL_STR_COPY(loader->library);
880 } else {
881 RETVAL_STR_COPY(path);
882 }
883 } else {
884 if (loader->glibrary) {
885 RETVAL_STR_COPY(loader->glibrary);
886 } else {
887 RETVAL_STR_COPY(loader->library);
888 }
889 }
890 free_alloca(sanitized_name, use_heap);
891
892 return;
893 }
894 /* }}} */
895
896 /** {{{ proto public Yaf_Loader::setLibraryPath(string $path, $global = FALSE)
897 */
PHP_METHOD(yaf_loader,setLibraryPath)898 PHP_METHOD(yaf_loader, setLibraryPath) {
899 zend_string *library;
900 zend_bool global = 0;
901 yaf_loader_object *loader = Z_YAFLOADEROBJ_P(getThis());
902
903 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|b", &library, &global) == FAILURE) {
904 return;
905 }
906
907 if (!global) {
908 yaf_loader_set_library_path(loader, library);
909 } else {
910 yaf_loader_set_global_library_path(loader, library);
911 }
912
913 RETURN_ZVAL(getThis(), 1, 0);
914 }
915 /* }}} */
916
917 /** {{{ proto public Yaf_Loader::getLibraryPath($global = FALSE)
918 */
PHP_METHOD(yaf_loader,getLibraryPath)919 PHP_METHOD(yaf_loader, getLibraryPath) {
920 zend_bool global = 0;
921 yaf_loader_object *loader = Z_YAFLOADEROBJ_P(getThis());
922
923 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &global) == FAILURE) {
924 return;
925 }
926
927 if (!global) {
928 RETURN_STR_COPY(loader->library);
929 } else if (loader->glibrary) {
930 RETURN_STR_COPY(loader->glibrary);
931 } else {
932 RETURN_EMPTY_STRING();
933 }
934 }
935 /* }}} */
936
937 /** {{{ proto public Yaf_Loader::getInstance($library = NULL, $global_library = NULL)
938 */
PHP_METHOD(yaf_loader,getInstance)939 PHP_METHOD(yaf_loader, getInstance) {
940 zend_string *library = NULL;
941 zend_string *global = NULL;
942 yaf_loader_t *loader;
943
944 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!S!", &library, &global) == FAILURE) {
945 return;
946 }
947
948 if ((loader = yaf_loader_instance(NULL))) {
949 if (library) {
950 yaf_loader_set_library_path(Z_YAFLOADEROBJ_P(loader), library);
951 }
952 if (global) {
953 yaf_loader_set_global_library_path(Z_YAFLOADEROBJ_P(loader), global);
954 }
955 /* for back-compatible with changing of YAF_G(lowcase_path) ini_set */
956 yaf_loader_reset(Z_YAFLOADEROBJ_P(loader));
957 RETURN_ZVAL(loader, 1, 0);
958 }
959
960 RETURN_FALSE;
961 }
962 /* }}} */
963
964 /** {{{ proto private Yaf_Loader::__construct(void)
965 */
PHP_METHOD(yaf_loader,__construct)966 PHP_METHOD(yaf_loader, __construct) {
967 }
968 /* }}} */
969
970 /** {{{ yaf_loader_methods
971 */
972 zend_function_entry yaf_loader_methods[] = {
973 PHP_ME(yaf_loader, __construct, yaf_loader_void_arginfo, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR)
974 PHP_ME(yaf_loader, autoload, yaf_loader_autoloader_arginfo, ZEND_ACC_PUBLIC)
975 PHP_ME(yaf_loader, getInstance, yaf_loader_getinstance_arginfo, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
976 PHP_ME(yaf_loader, registerLocalNamespace, yaf_loader_regnamespace_arginfo, ZEND_ACC_PUBLIC)
977 PHP_ME(yaf_loader, getLocalNamespace, yaf_loader_void_arginfo, ZEND_ACC_PUBLIC)
978 PHP_ME(yaf_loader, clearLocalNamespace, yaf_loader_void_arginfo, ZEND_ACC_PUBLIC)
979 PHP_ME(yaf_loader, isLocalName, yaf_loader_islocalname_arginfo, ZEND_ACC_PUBLIC)
980 PHP_ME(yaf_loader, getNamespacePath, yaf_loader_islocalname_arginfo, ZEND_ACC_PUBLIC)
981 PHP_ME(yaf_loader, import, yaf_loader_import_arginfo, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
982 PHP_ME(yaf_loader, setLibraryPath, yaf_loader_setlib_arginfo, ZEND_ACC_PUBLIC)
983 PHP_ME(yaf_loader, getLibraryPath, yaf_loader_getlib_arginfo, ZEND_ACC_PUBLIC)
984 PHP_MALIAS(yaf_loader, registerNamespace, registerLocalNamespace, yaf_loader_regnamespace_arginfo, ZEND_ACC_PUBLIC)
985 PHP_MALIAS(yaf_loader, getNamespaces, getLocalNamespace, yaf_loader_void_arginfo, ZEND_ACC_PUBLIC)
986 {NULL, NULL, NULL}
987 };
988 /* }}} */
989
990 /** {{{ YAF_STARTUP_FUNCTION
991 */
YAF_STARTUP_FUNCTION(loader)992 YAF_STARTUP_FUNCTION(loader) {
993 zend_class_entry ce;
994
995 YAF_INIT_CLASS_ENTRY(ce, "Yaf_Loader", "Yaf\\Loader", yaf_loader_methods);
996 yaf_loader_ce = zend_register_internal_class_ex(&ce, NULL);
997 yaf_loader_ce->ce_flags |= ZEND_ACC_FINAL;
998 yaf_loader_ce->serialize = zend_class_serialize_deny;
999 yaf_loader_ce->unserialize = zend_class_unserialize_deny;
1000
1001 memcpy(&yaf_loader_obj_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1002 yaf_loader_obj_handlers.clone_obj = NULL;
1003 yaf_loader_obj_handlers.get_gc = yaf_fake_get_gc;
1004 yaf_loader_obj_handlers.free_obj = yaf_loader_obj_free;
1005 yaf_loader_obj_handlers.get_properties = yaf_loader_get_properties;
1006
1007 return SUCCESS;
1008 }
1009 /* }}} */
1010
1011 /*
1012 * Local variables:
1013 * tab-width: 4
1014 * c-basic-offset: 4
1015 * End:
1016 * vim600: noet sw=4 ts=4 fdm=marker
1017 * vim<600: noet sw=4 ts=4
1018 */
1019