Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:17332 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 97395 invoked by uid 1010); 20 Jul 2005 04:05:34 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 97380 invoked from network); 20 Jul 2005 04:05:34 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 20 Jul 2005 04:05:34 -0000 X-Host-Fingerprint: 65.2.108.10 adsl-2-108-10.mia.bellsouth.net Received: from ([65.2.108.10:17001] helo=localhost.localdomain) by pb1.pair.com (ecelerity 2.0 beta r(6227M)) with SMTP id 52/31-61486-E8DCDD24 for ; Wed, 20 Jul 2005 00:05:34 -0400 Message-ID: <52.31.61486.E8DCDD24@pb1.pair.com> To: internals@lists.php.net Date: Wed, 20 Jul 2005 00:05:30 -0400 Lines: 1394 User-Agent: KNode/0.8.1 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart2276357.JxREzF3cBR" Content-Transfer-Encoding: 7Bit X-Posted-By: 65.2.108.10 Subject: [PATCH] Namespace Patch, Alpha 3 From: jrhernandez05@gmail.com (Jessie Hernandez) --nextPart2276357.JxREzF3cBR Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8Bit Private class support has been completed in the attached patch! Again, to reiterate from my last post, the attached patch is a CVS patch, as some requested me to do. I could not add the test files to the patch because "cvs add" failed with a "cvs add requires write access to the repository" error (any way to fix this?). Also, import statements now include the class files, using a new .ini variable, "class_path". Files under the directories in the class_path have the namespace names as directories and the class names named exactly as the file that declares it (like Java), e.g. my_ns:class1 is declared in $class_path/my_ns/class1.php. Again, the only missing feature I know of is "namespace imports". I've been thinking about it, and I think the best approach is actually very simple. Right now, when an undefined class is found, the __autoload function is called from zend_lookup_class to attempt to declare the class at that point. What I propose is to modify zend_lookup_class to do an additional lookup, either before/after the __autoload function, for namespace imported classes. Here's an example: At compile-time, the "my_namespace1" and "my_namespace2" strings are saved in a runtime hashtable. At runtime, zend_lookup_class will be called on "class1", as usual. Before/after __autoload, this hashtable will be traversed for the file "class1.php". So in the above example, an attempt to include "$class_path/my_namespace1/class1.php" will be done. If that fails, then my_namespace2 is tried, and so forth. If one of these attempts succeed, then the import alias is also added to the import hashtable for the currently-executed file, as if the user had added "import my_namespace1:class1" to the script. (BTW, is there a way to construct an opcode at runtime and execute it immediately? If not, I'll have to duplicate the code I have for ZEND_IMPORT_CLASS in another function). I think this approach is the easiest and most sensible for namespace import support. It is no more than a specialized "__autoload". If there are no objections, I'll start working on it next week. As always, comments/suggestions are most appreciated. Regards, Jessie Hernandez --nextPart2276357.JxREzF3cBR Content-Type: text/x-diff; name="ns_0719.patch" Content-Transfer-Encoding: 8Bit Content-Disposition: attachment; filename="ns_0719.patch" ? tests.tar.gz ? tests/classes/namespace ? tests/classes/namespace_001.phpt ? tests/classes/namespace_002.phpt ? tests/classes/namespace_003.phpt ? tests/classes/namespace_004.phpt Index: Zend/zend.c =================================================================== RCS file: /repository/ZendEngine2/zend.c,v retrieving revision 1.306 diff -u -r1.306 zend.c --- Zend/zend.c 27 Jun 2005 22:04:41 -0000 1.306 +++ Zend/zend.c 20 Jul 2005 03:40:41 -0000 @@ -34,10 +34,12 @@ # define GLOBAL_CLASS_TABLE global_class_table # define GLOBAL_CONSTANTS_TABLE global_constants_table # define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table +# define GLOBAL_IMPORT_CLASS_TABLE global_import_class_table #else # define GLOBAL_FUNCTION_TABLE CG(function_table) # define GLOBAL_CLASS_TABLE CG(class_table) # define GLOBAL_AUTO_GLOBALS_TABLE CG(auto_globals) +# define GLOBAL_IMPORT_CLASS_TABLE CG(import_class_table) #endif #if defined(ZEND_WIN32) && ZEND_DEBUG @@ -50,6 +52,7 @@ ZEND_API zend_write_func_t zend_write; ZEND_API FILE *(*zend_fopen)(const char *filename, char **opened_path); ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); +ZEND_API int (*zend_stream_open_class_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); ZEND_API void (*zend_block_interruptions)(void); ZEND_API void (*zend_unblock_interruptions)(void); ZEND_API void (*zend_ticks_function)(int ticks); @@ -88,6 +91,7 @@ HashTable *global_class_table; HashTable *global_constants_table; HashTable *global_auto_globals_table; +HashTable *global_import_class_table; #endif ZEND_API zend_utility_values zend_uv; @@ -430,6 +434,7 @@ { zend_function tmp_func; zend_class_entry *tmp_class; + HashTable tmp_hash; compiler_globals->compiled_filename = NULL; @@ -443,6 +448,17 @@ zend_set_default_compile_time_values(TSRMLS_C); + /* initialize namespace variables */ + compiler_globals->namespace_prefix = NULL; + compiler_globals->namespace_prefix_lc = NULL; + compiler_globals->namespace_prefix_len = 0; + + /* initialize the import table */ + compiler_globals->import_class_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->current_import_table = NULL; + zend_hash_init_ex(compiler_globals->import_class_table, 10, NULL, (dtor_func_t) zend_hash_destroy, 1, 0); + zend_hash_copy(compiler_globals->import_class_table, global_import_class_table, NULL, &tmp_hash, sizeof(tmp_hash)); + CG(interactive) = 0; compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable)); @@ -465,6 +481,10 @@ zend_hash_destroy(compiler_globals->auto_globals); free(compiler_globals->auto_globals); } + if (compiler_globals->import_class_table != GLOBAL_IMPORT_CLASS_TABLE) { + zend_hash_destroy(compiler_globals->import_class_table); + free(compiler_globals->import_class_table); + } } @@ -565,6 +585,7 @@ zend_fopen = zend_fopen_wrapper; } zend_stream_open_function = utility_functions->stream_open_function; + zend_stream_open_class_function = utility_functions->stream_open_class_function; zend_message_dispatcher_p = utility_functions->message_handler; zend_block_interruptions = utility_functions->block_interruptions; zend_unblock_interruptions = utility_functions->unblock_interruptions; @@ -588,11 +609,13 @@ GLOBAL_FUNCTION_TABLE = (HashTable *) malloc(sizeof(HashTable)); GLOBAL_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable)); GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_IMPORT_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable)); #ifdef ZTS GLOBAL_CONSTANTS_TABLE = (HashTable *) malloc(sizeof(HashTable)); #endif zend_hash_init_ex(GLOBAL_FUNCTION_TABLE, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); zend_hash_init_ex(GLOBAL_CLASS_TABLE, 10, NULL, ZEND_CLASS_DTOR, 1, 0); + zend_hash_init_ex(GLOBAL_IMPORT_CLASS_TABLE, 10, NULL, (dtor_func_t) zend_hash_destroy, 1, 0); zend_hash_init_ex(&module_registry, 50, NULL, ZEND_MODULE_DTOR, 1, 0); zend_init_rsrc_list_dtors(); @@ -618,10 +641,13 @@ compiler_globals->in_compilation = 0; compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->import_class_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->current_import_table = NULL; *compiler_globals->function_table = *GLOBAL_FUNCTION_TABLE; *compiler_globals->class_table = *GLOBAL_CLASS_TABLE; compiler_globals->auto_globals = GLOBAL_AUTO_GLOBALS_TABLE; + *compiler_globals->import_class_table = *GLOBAL_IMPORT_CLASS_TABLE; zend_hash_destroy(executor_globals->zend_constants); *executor_globals->zend_constants = *GLOBAL_CONSTANTS_TABLE; @@ -676,9 +702,11 @@ *GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table; *GLOBAL_CLASS_TABLE = *compiler_globals->class_table; *GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants; + *GLOBAL_IMPORT_CLASS_TABLE = *compiler_globals->import_class_table; zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); free(compiler_globals->function_table); free(compiler_globals->class_table); + free(compiler_globals->import_class_table); compiler_globals_ctor(compiler_globals, tsrm_ls); free(EG(zend_constants)); executor_globals_ctor(executor_globals, tsrm_ls); @@ -699,6 +727,7 @@ zend_hash_destroy(GLOBAL_FUNCTION_TABLE); zend_hash_destroy(GLOBAL_CLASS_TABLE); + zend_hash_destroy(GLOBAL_IMPORT_CLASS_TABLE); zend_hash_destroy(GLOBAL_AUTO_GLOBALS_TABLE); free(GLOBAL_AUTO_GLOBALS_TABLE); @@ -709,6 +738,7 @@ zend_shutdown_constants(TSRMLS_C); free(GLOBAL_FUNCTION_TABLE); free(GLOBAL_CLASS_TABLE); + free(GLOBAL_IMPORT_CLASS_TABLE); #ifdef ZTS zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); zend_hash_destroy(GLOBAL_CONSTANTS_TABLE); @@ -716,6 +746,7 @@ GLOBAL_FUNCTION_TABLE = NULL; GLOBAL_CLASS_TABLE = NULL; GLOBAL_AUTO_GLOBALS_TABLE = NULL; + GLOBAL_IMPORT_CLASS_TABLE = NULL; #endif zend_destroy_rsrc_list_dtors(); } Index: Zend/zend.h =================================================================== RCS file: /repository/ZendEngine2/zend.h,v retrieving revision 1.292 diff -u -r1.292 zend.h --- Zend/zend.h 14 Jul 2005 14:01:02 -0000 1.292 +++ Zend/zend.h 20 Jul 2005 03:40:41 -0000 @@ -384,6 +384,7 @@ int (*stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); int (*vspprintf_function)(char **pbuf, size_t max_len, const char *format, va_list ap); char *(*getenv_function)(char *name, size_t name_len TSRMLS_DC); + int (*stream_open_class_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); } zend_utility_functions; @@ -519,6 +520,7 @@ extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); extern void (*zend_on_timeout)(int seconds TSRMLS_DC); extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); +extern ZEND_API int (*zend_stream_open_class_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); extern int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); extern ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC); @@ -556,6 +558,7 @@ #define ZMSG_MEMORY_LEAK_REPEATED 5L #define ZMSG_LOG_SCRIPT_NAME 6L #define ZMSG_MEMORY_LEAKS_GRAND_TOTAL 7L +#define ZMSG_FAILED_IMPORT_CLASS 8L #define ZVAL_ADDREF(pz) (++(pz)->refcount) Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.644 diff -u -r1.644 zend_compile.c --- Zend/zend_compile.c 17 Jul 2005 19:17:10 -0000 1.644 +++ Zend/zend_compile.c 20 Jul 2005 03:40:43 -0000 @@ -185,8 +185,18 @@ ZEND_API char *zend_set_compiled_filename(char *new_compiled_filename TSRMLS_DC) { char **pp, *p; + HashTable file_imports; int length = strlen(new_compiled_filename); + /* make sure the import class hashtable for this file exists */ + if (!zend_hash_exists(CG(import_class_table), new_compiled_filename, length+1)) { + zend_hash_init(&file_imports, 10, NULL, ZVAL_DESTRUCTOR, 1); + zend_hash_add(CG(import_class_table), new_compiled_filename, length + 1, &file_imports, sizeof(file_imports), NULL); + } + + /* get the import class hashtable for this file */ + zend_hash_find(CG(import_class_table), new_compiled_filename, length + 1, (void **)&CG(current_import_table)); + if (zend_hash_find(&CG(filenames_table), new_compiled_filename, length+1, (void **) &pp) == SUCCESS) { CG(compiled_filename) = *pp; return *pp; @@ -1389,6 +1399,7 @@ zval_dtor(&class_name->u.constant); break; default: + zend_resolve_class_name_node(class_name TSRMLS_CC); opline->op2 = *class_name; break; } @@ -2626,6 +2637,11 @@ zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val); } + /* fully prefix the class name */ + efree(lcname); + zend_prefix_class_name_node(class_name TSRMLS_CC); + lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len); + new_class_entry->type = ZEND_USER_CLASS; new_class_entry->name = class_name->u.constant.value.str.val; new_class_entry->name_length = class_name->u.constant.value.str.len; @@ -2680,8 +2696,231 @@ CG(doc_comment) = NULL; CG(doc_comment_len) = 0; } -} - + +} + +/***************************** + * BEGIN NAMESPACE FUNCTIONS * + *****************************/ + +void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC) +{ + /* allocate space for the namespace prefix */ + CG(namespace_prefix) = emalloc(ns_name->u.constant.value.str.len + 2); + + /* get the namespace prefix */ + strncpy(CG(namespace_prefix), ns_name->u.constant.value.str.val, ns_name->u.constant.value.str.len + 1); + strcat(CG(namespace_prefix), ":"); + + /* get the lowercased namespace prefix */ + CG(namespace_prefix_lc) = zend_str_tolower_dup(CG(namespace_prefix), ns_name->u.constant.value.str.len + 1); + + /* save the prefix length */ + CG(namespace_prefix_len) = ns_name->u.constant.value.str.len + 1; +} + +void zend_do_end_namespace(znode *ns_token TSRMLS_DC) +{ + /* free the string memory */ + efree(CG(namespace_prefix)); + efree(CG(namespace_prefix_lc)); + CG(namespace_prefix_len) = 0; + + /* set the prefixes to null */ + CG(namespace_prefix) = NULL; + CG(namespace_prefix_lc) = NULL; +} + +void zend_do_verify_private_class(TSRMLS_D) +{ + if (CG(namespace_prefix) == NULL) { + zend_error(E_COMPILE_ERROR, "Cannot declare a private class in the global namespace"); + } +} + +void zend_generate_import_include_node(char *class_name, int class_name_len, znode *include_file_node) +{ + char *include_file = NULL; + int include_file_len = class_name_len + sizeof(".php") - 1; + char *include_file_ptr = NULL; + + /* allocate enough space for the include file string */ + include_file = emalloc(include_file_len + 1); + include_file_ptr = include_file; + + /* copy the class name to the include file string, replacing colons with + slashes */ + for (; *class_name != '\0'; ++class_name, ++include_file_ptr) + { + if (*class_name != ':') { + *include_file_ptr = *class_name; + } else { + *include_file_ptr = '/'; + } + } + + /* add the .php extension */ + strcpy(include_file_ptr, ".php"); + + /* create the include file node */ + memset(include_file_node, 0, sizeof(znode)); + include_file_node->op_type = IS_CONST; + include_file_node->u.constant.type = IS_STRING; + include_file_node->u.constant.value.str.val = include_file; + include_file_node->u.constant.value.str.len = include_file_len; +} + +void zend_do_import(znode *result, znode *class_name, znode *alias_name TSRMLS_DC) +{ + char *alias_name_lc = NULL; + zend_uint alias_name_len = 0; + zval alias_val; + /* 'colon_pos' is the position of the last colon in the full class name */ + char *colon_pos = strrchr(class_name->u.constant.value.str.val, ':'); + znode include_file_node; + /* 'last_pos' is the position of the null terminator in the full class name */ + char *last_pos = class_name->u.constant.value.str.val + class_name->u.constant.value.str.len; + + if (colon_pos == NULL) { + zend_error(E_COMPILE_ERROR, "Cannot import non-namespace class: %s!", class_name->u.constant.value.str.val); + return; + } + + if (alias_name == NULL) { + /* advance to the first character of the class name */ + ++colon_pos; + + /* get the lowercased class name as the alias */ + alias_name_len = last_pos - colon_pos; + alias_name_lc = zend_str_tolower_dup(colon_pos, alias_name_len); + } else /* alias_name != NULL */ { + alias_name_lc = zend_str_tolower_dup(alias_name->u.constant.value.str.val, alias_name->u.constant.value.str.len); + alias_name_len = alias_name->u.constant.value.str.len; + } + + /* make sure this import alias is not the same as a class name */ + if (zend_hash_exists(CG(class_table), alias_name_lc, alias_name_len + 1)) { + zend_error(E_COMPILE_ERROR, "Could not import %s as %s: a class exists with the name %s", class_name->u.constant.value.str.val, alias_name_lc, alias_name_lc); + return; + } + + /* make sure this import alias has not been used before */ + if (zend_hash_exists(CG(current_import_table), alias_name_lc, alias_name_len + 1)) { + zend_error(E_COMPILE_ERROR, "An import was already done with the %s alias", alias_name_lc); + return; + } + + /* initialize the full class name zval */ + INIT_ZVAL(alias_val); + alias_val.value.str.val = estrdup(class_name->u.constant.value.str.val); + alias_val.value.str.len = class_name->u.constant.value.str.len; + + /* add the alias */ + if (zend_hash_add(CG(current_import_table), alias_name_lc, alias_name_len + 1, &alias_val, sizeof(alias_val), NULL) == FAILURE) { + zend_error(E_COMPILE_ERROR, "Could not import %s as %s!", class_name->u.constant.value.str.val, alias_name_lc); + return; + } + + efree(alias_name_lc); + + /* generate the include file opcode */ + zend_generate_import_include_node(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len, &include_file_node); + zend_do_include_or_eval(ZEND_IMPORT_CLASS, result, &include_file_node TSRMLS_CC); +} + +void zend_do_namespace_import(znode *ns_name TSRMLS_DC) +{ +#ifdef JESSIE_0 + char *class_path = estrdup(PG(class_path)); + php_stream *dir = NULL; + char *ns_path = estrndup(ns_name->u.constant.value.str.val, ns_name->u.constant.value.str.len); + char *ns_path_ptr = ns_path; + char *path_begin = class_path; + char *path_end = NULL; + char trypath[MAXPATHLEN]; + + /* replace all colons with slashes in the namespace name */ + while ((ns_path_ptr = strchr(ns_path_ptr, ':')) != NULL) { + *ns_path_ptr++ = '/'; + } + + while (path_begin && *path_begin) { + /* find the end of the next path */ + path_end = strchr(path_begin, DEFAULT_DIR_SEPARATOR); + + if (path_end != NULL) { + *path_end++ = '\0'; + } + + /* get the absolute path to try next */ + snprintf(trypath, MAXPATHLEN, "%s/%s", path_begin, ns_path); + + /* attempt to open this directory */ + dir = php_class_files_wrapper.wops->dir_opener(&php_class_files_wrapper, trypath, "rb", 0, NULL, NULL STREAMS_CC TSRMLS_CC); + + if (dir != NULL) { + php_stream_dirent class_file; + + while (php_stream_readdir(dir, &class_file TSRMLS_CC) != NULL) { + printf("namespace file: %s\n", class_file.d_name); + } + + php_stream_closedir(dir); + break; + } + + path_begin = path_end; + } + + efree(class_path); + efree(ns_path); +#endif +} + +void zend_prefix_class_name_node(znode *class_name TSRMLS_DC) +{ + zend_uint new_length = 0; + char *org_class_name = NULL; + + if (CG(namespace_prefix) != NULL) { + new_length = CG(namespace_prefix_len) + class_name->u.constant.value.str.len; + org_class_name = estrdup(class_name->u.constant.value.str.val); + + STR_REALLOC(class_name->u.constant.value.str.val, new_length + 1); + + /* get the full class name */ + strncpy(class_name->u.constant.value.str.val, CG(namespace_prefix), CG(namespace_prefix_len) + 1); + strcat(class_name->u.constant.value.str.val, org_class_name); + + /* get the new string length */ + class_name->u.constant.value.str.len = new_length; + + efree(org_class_name); + } +} + +void zend_resolve_class_name_node(znode *class_name TSRMLS_DC) +{ + zval* mapped_class_name = NULL; + char *org_class_name = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len); + zend_uint org_class_name_len = class_name->u.constant.value.str.len; + + /* check to see if this class name is actually an import alias */ + if (zend_hash_find(CG(current_import_table), org_class_name, org_class_name_len + 1, (void **)&mapped_class_name) == SUCCESS) { + /* free the class name string */ + STR_FREE(class_name->u.constant.value.str.val); + + /* set the class node to contain the full class name */ + class_name->u.constant.value.str.val = estrdup(mapped_class_name->value.str.val); + class_name->u.constant.value.str.len = mapped_class_name->value.str.len; + } + + efree(org_class_name); +} + +/*************************** + * END NAMESPACE FUNCTIONS * + ***************************/ static void do_verify_abstract_class(TSRMLS_D) { Index: Zend/zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.315 diff -u -r1.315 zend_compile.h --- Zend/zend_compile.h 7 Jul 2005 16:07:09 -0000 1.315 +++ Zend/zend_compile.h 20 Jul 2005 03:40:43 -0000 @@ -387,6 +387,7 @@ void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC); int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier); +void zend_do_verify_private_class(TSRMLS_D); void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC); void zend_do_end_function_declaration(znode *function_token TSRMLS_DC); void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, znode *varname, zend_bool pass_by_reference TSRMLS_DC); @@ -438,6 +439,14 @@ void zend_do_declare_implicit_property(TSRMLS_D); void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC); +void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC); +void zend_do_end_namespace(znode *ns_token TSRMLS_DC); +void zend_do_import(znode *result, znode *class_name, znode *alias_name TSRMLS_DC); +void zend_do_namespace_import(znode *ns_name TSRMLS_DC); +void zend_do_unimport_all(TSRMLS_D); +void zend_prefix_class_name_node(znode *class_name TSRMLS_DC); +void zend_resolve_class_name_node(znode *class_name TSRMLS_DC); + void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC); @@ -621,6 +630,7 @@ #define ZEND_INCLUDE_ONCE (1<<2) #define ZEND_REQUIRE (1<<3) #define ZEND_REQUIRE_ONCE (1<<4) +#define ZEND_IMPORT_CLASS (1<<5) #define ZEND_ISSET (1<<0) #define ZEND_ISEMPTY (1<<1) Index: Zend/zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.327 diff -u -r1.327 zend_execute_API.c --- Zend/zend_execute_API.c 12 Jul 2005 06:52:59 -0000 1.327 +++ Zend/zend_execute_API.c 20 Jul 2005 03:40:43 -0000 @@ -135,6 +135,7 @@ EG(function_table) = CG(function_table); EG(class_table) = CG(class_table); + EG(import_class_table) = CG(import_class_table); EG(in_execution) = 0; EG(in_autoload) = NULL; @@ -906,6 +907,102 @@ } +char* zend_get_class_namespace(const zend_class_entry *ce) +{ + int namespace_length = 0; + char *result = NULL; + char *tmp = strrchr(ce->name, ':'); + + if (tmp != NULL) { + namespace_length = tmp - ce->name; + + /* get the namespace name, which is everything before the last colon */ + result = estrndup(ce->name, namespace_length); + zend_str_tolower(ce->name, namespace_length); + } + + return result; +} + + +void zend_resolve_class_name_string(char **lc_name, int *lc_name_len TSRMLS_DC) +{ + HashTable *current_import_table = NULL; + char *executed_filename = zend_get_executed_filename(TSRMLS_C); + int executed_filename_len = strlen(executed_filename); + zval* mapped_class_name = NULL; + + if (zend_hash_find(EG(import_class_table), executed_filename, executed_filename_len + 1, (void **)¤t_import_table) == SUCCESS) { + /* check to see if this class name is actually an import alias */ + if (zend_hash_find(current_import_table, *lc_name, *lc_name_len + 1, (void **)&mapped_class_name) == SUCCESS) { + /* free the class name string */ + free_alloca(*lc_name); + + /* set the class node to contain the full class name */ + *lc_name = do_alloca(mapped_class_name->value.str.len + 1); + zend_str_tolower_copy(*lc_name, mapped_class_name->value.str.val, mapped_class_name->value.str.len); + *lc_name_len = mapped_class_name->value.str.len; + } + } +} + + +int zend_verify_can_use_class(zend_class_entry *ce TSRMLS_DC) +{ + int result = SUCCESS; + + /* exit immediately if this is not a private class */ + if ((ce->ce_flags & ZEND_ACC_PRIVATE) == 0) { + return SUCCESS; + } + + /* check if we are in compilation mode */ + if (zend_is_compiling(TSRMLS_C)) { + char *class_namespace = zend_get_class_namespace(ce); + char *current_namespace = NULL; + + if (CG(namespace_prefix) != NULL) { + /* copy the namespace prefix minus the last character, which is a colon */ + current_namespace = estrndup(CG(namespace_prefix), CG(namespace_prefix_len) - 1); + } + + /* check if the namespaces match */ + if (class_namespace != NULL + && (current_namespace == NULL + || strcmp(class_namespace, current_namespace) != 0)) { + /* the namespaces don't match, so don't allow use of this class */ + result = FAILURE; + } + + efree(class_namespace); + efree(current_namespace); + } else /* zend_is_executing */ { + char *class_directory = estrdup(ce->filename); + char *class_directory_end = strrchr(class_directory, '/'); + char *executed_filename = zend_get_executed_filename(TSRMLS_C); + + if (class_directory_end != NULL) { + *class_directory_end = '\0'; + + if (strstr(executed_filename, class_directory) != executed_filename) { + /* the files are in different directories, so don't allow + use of this class */ + result = FAILURE; + } + } else { + result = FAILURE; + } + } + + /* generate the error message, if needed */ + if (result == FAILURE) { + zend_error(E_ERROR, "Cannot use class '%s' outside of its namespace, as it is private", ce->name); + } + + return result; +} + + ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) { zval **args[1]; @@ -914,6 +1011,7 @@ zval *retval_ptr; int retval; char *lc_name; + int lc_name_length = name_length; zval *exception; char dummy = 1; zend_fcall_info fcall_info; @@ -926,9 +1024,11 @@ lc_name = do_alloca(name_length + 1); zend_str_tolower_copy(lc_name, name, name_length); - if (zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce) == SUCCESS) { + zend_resolve_class_name_string(&lc_name, &lc_name_length TSRMLS_CC); + + if (zend_hash_find(EG(class_table), lc_name, lc_name_length+1, (void **) ce) == SUCCESS) { free_alloca(lc_name); - return SUCCESS; + return zend_verify_can_use_class(**ce TSRMLS_CC); } /* The compiler is not-reentrant. Make sure we __autoload() only during run-time @@ -944,7 +1044,7 @@ zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0); } - if (zend_hash_add(EG(in_autoload), lc_name, name_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { + if (zend_hash_add(EG(in_autoload), lc_name, lc_name_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { free_alloca(lc_name); return FAILURE; } @@ -979,7 +1079,7 @@ zval_ptr_dtor(&class_name_ptr); - zend_hash_del(EG(in_autoload), lc_name, name_length+1); + zend_hash_del(EG(in_autoload), lc_name, lc_name_length+1); if (retval == FAILURE) { EG(exception) = exception; @@ -997,8 +1097,13 @@ zval_ptr_dtor(&retval_ptr); } - retval = zend_hash_find(EG(class_table), lc_name, name_length + 1, (void **) ce); + retval = zend_hash_find(EG(class_table), lc_name, lc_name_length + 1, (void **) ce); free_alloca(lc_name); + + if (retval == SUCCESS) { + retval = zend_verify_can_use_class(**ce TSRMLS_CC); + } + return retval; } Index: Zend/zend_globals.h =================================================================== RCS file: /repository/ZendEngine2/zend_globals.h,v retrieving revision 1.140 diff -u -r1.140 zend_globals.h --- Zend/zend_globals.h 3 Nov 2004 23:13:32 -0000 1.140 +++ Zend/zend_globals.h 20 Jul 2005 03:40:43 -0000 @@ -143,6 +143,14 @@ zend_encoding_converter encoding_converter; zend_encoding_oddlen encoding_oddlen; #endif /* ZEND_MULTIBYTE */ + + /* namespace variables */ + char *namespace_prefix; + char *namespace_prefix_lc; + zend_uint namespace_prefix_len; + + HashTable *import_class_table; + HashTable *current_import_table; }; @@ -232,6 +240,8 @@ zend_property_info std_property_info; + HashTable *import_class_table; /* import class table */ + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; Index: Zend/zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.159 diff -u -r1.159 zend_language_parser.y --- Zend/zend_language_parser.y 4 Jul 2005 13:24:44 -0000 1.159 +++ Zend/zend_language_parser.y 20 Jul 2005 03:40:44 -0000 @@ -145,7 +145,9 @@ %token T_DOLLAR_OPEN_CURLY_BRACES %token T_CURLY_OPEN %token T_PAAMAYIM_NEKUDOTAYIM - +%token T_IMPORT +%token T_NAMESPACE_NAME +%token T_NAMESPACE %% /* Rules */ start: @@ -162,6 +164,7 @@ statement | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } | class_declaration_statement { zend_do_early_binding(TSRMLS_C); } + | namespace_declaration_statement | T_HALT_COMPILER '(' ')' ';' { REGISTER_MAIN_LONG_CONSTANT("__COMPILER_HALT_OFFSET__", zend_get_scanned_file_offset(TSRMLS_C), CONST_CS); YYACCEPT; } ; @@ -305,6 +308,22 @@ T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = 0; } | T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } | T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_FINAL_CLASS; } + | T_PRIVATE T_CLASS { $$.u.opline_num = CG(zend_lineno); zend_do_verify_private_class(TSRMLS_C); $$.u.EA.type = ZEND_ACC_PRIVATE; } + | T_PRIVATE T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); zend_do_verify_private_class(TSRMLS_C); $$.u.EA.type = ZEND_ACC_PRIVATE | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } + | T_PRIVATE T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); zend_do_verify_private_class(TSRMLS_C); $$.u.EA.type = ZEND_ACC_PRIVATE | ZEND_ACC_FINAL_CLASS; } +; + +namespace_declaration_statement: + T_NAMESPACE namespace_name '{' { zend_do_begin_namespace(&$1, &$2 TSRMLS_CC); } namespace_statement_list '}' { zend_do_end_namespace(&$1 TSRMLS_CC); } +; + +namespace_statement_list: + namespace_statement_list namespace_statement + | /* empty */ +; + +namespace_statement: + class_declaration_statement { zend_do_early_binding(TSRMLS_C); } ; extends_from: @@ -439,6 +458,7 @@ optional_class_type: /* empty */ { $$.op_type = IS_UNUSED; } | T_STRING { $$ = $1; } + | T_NAMESPACE_NAME { $$ = $1; } | T_ARRAY { $$.op_type = IS_CONST; $$.u.constant.type=IS_NULL;} ; @@ -639,10 +659,12 @@ fully_qualified_class_name: T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | T_NAMESPACE_NAME { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; class_name_reference: T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | T_NAMESPACE_NAME { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } | dynamic_class_name_reference { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; @@ -654,6 +676,10 @@ | base_variable { $$ = $1; } ; +namespace_name: + T_NAMESPACE_NAME { $$ = $1; } + | T_STRING { $$ = $1; } +; dynamic_class_name_variable_properties: dynamic_class_name_variable_properties dynamic_class_name_variable_property @@ -910,6 +936,10 @@ | T_EVAL '(' expr ')' { zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); } | T_REQUIRE expr { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); } | T_REQUIRE_ONCE expr { zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); } + | T_IMPORT T_NAMESPACE_NAME { zend_do_import(&$$, &$2, NULL TSRMLS_CC); } + | T_IMPORT T_NAMESPACE_NAME T_AS T_STRING { zend_do_import(&$$, &$2, &$4 TSRMLS_CC); } + | T_IMPORT T_NAMESPACE T_NAMESPACE_NAME { zend_do_namespace_import(&$3 TSRMLS_CC); } + | T_IMPORT T_NAMESPACE T_STRING { zend_do_namespace_import(&$3 TSRMLS_CC); } ; isset_variables: Index: Zend/zend_language_scanner.l =================================================================== RCS file: /repository/ZendEngine2/zend_language_scanner.l,v retrieving revision 1.129 diff -u -r1.129 zend_language_scanner.l --- Zend/zend_language_scanner.l 16 Jun 2005 13:31:21 -0000 1.129 +++ Zend/zend_language_scanner.l 20 Jul 2005 03:40:44 -0000 @@ -790,6 +790,7 @@ ESCAPED_AND_WHITESPACE [\n\t\r #'.:;,()|^&+-/*=%!~<>?@]+ ANY_CHAR (.|[\n]) NEWLINE ("\r"|"\n"|"\r\n") +NAMESPACE_NAME ({LABEL}":")*{LABEL} %option noyylineno %option noyywrap @@ -923,6 +924,14 @@ return T_CLASS; } +"namespace" { + return T_NAMESPACE; +} + +"import" { + return T_IMPORT; +} + "interface" { return T_INTERFACE; } @@ -1433,6 +1442,13 @@ return T_STRING; } +{NAMESPACE_NAME} { + zendlval->value.str.val = (char *)estrndup(yytext, yyleng); + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + return T_NAMESPACE_NAME; +} + {LABEL} { zend_copy_value(zendlval, yytext, yyleng); zendlval->type = IS_STRING; Index: Zend/zend_stream.c =================================================================== RCS file: /repository/ZendEngine2/zend_stream.c,v retrieving revision 1.12 diff -u -r1.12 zend_stream.c --- Zend/zend_stream.c 7 Jul 2005 15:43:50 -0000 1.12 +++ Zend/zend_stream.c 20 Jul 2005 03:40:44 -0000 @@ -55,6 +55,11 @@ return (handle->handle.fp) ? SUCCESS : FAILURE; } +ZEND_API int zend_stream_open_class(const char *filename, zend_file_handle *handle TSRMLS_DC) +{ + return zend_stream_open_class_function(filename, handle TSRMLS_CC); +} + ZEND_API int zend_stream_fixup(zend_file_handle *file_handle TSRMLS_DC) { switch (file_handle->type) { Index: Zend/zend_stream.h =================================================================== RCS file: /repository/ZendEngine2/zend_stream.h,v retrieving revision 1.7 diff -u -r1.7 zend_stream.h --- Zend/zend_stream.h 4 Jun 2005 16:16:19 -0000 1.7 +++ Zend/zend_stream.h 20 Jul 2005 03:40:44 -0000 @@ -51,6 +51,7 @@ BEGIN_EXTERN_C() ZEND_API int zend_stream_open(const char *filename, zend_file_handle *handle TSRMLS_DC); +ZEND_API int zend_stream_open_class(const char *filename, zend_file_handle *handle TSRMLS_DC); ZEND_API int zend_stream_ferror(zend_file_handle *file_handle TSRMLS_DC); ZEND_API int zend_stream_getc(zend_file_handle *file_handle TSRMLS_DC); ZEND_API size_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t len TSRMLS_DC); Index: Zend/zend_vm_def.h =================================================================== RCS file: /repository/ZendEngine2/zend_vm_def.h,v retrieving revision 1.53 diff -u -r1.53 zend_vm_def.h --- Zend/zend_vm_def.h 11 Jul 2005 18:44:36 -0000 1.53 +++ Zend/zend_vm_def.h 20 Jul 2005 03:40:45 -0000 @@ -2672,11 +2672,19 @@ switch (opline->op2.u.constant.value.lval) { case ZEND_INCLUDE_ONCE: + case ZEND_IMPORT_CLASS: case ZEND_REQUIRE_ONCE: { int dummy = 1; zend_file_handle file_handle; + int successful = 0; - if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) { + if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) { + successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } else { + successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } + + if (SUCCESS == successful) { if (!file_handle.opened_path) { file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); @@ -2692,8 +2700,10 @@ } else { if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val); - } else { + } else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val); + } else { + zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val); } } break; Index: Zend/zend_vm_execute.h =================================================================== RCS file: /repository/ZendEngine2/zend_vm_execute.h,v retrieving revision 1.56 diff -u -r1.56 zend_vm_execute.h --- Zend/zend_vm_execute.h 11 Jul 2005 18:44:37 -0000 1.56 +++ Zend/zend_vm_execute.h 20 Jul 2005 03:40:49 -0000 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_vm_execute.h,v 1.56 2005/07/11 18:44:37 iliaa Exp $ */ +/* $Id: zend_vm_gen.php,v 1.11 2005/06/24 12:33:53 dmitry Exp $ */ ULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL}; @@ -1848,11 +1848,19 @@ switch (opline->op2.u.constant.value.lval) { case ZEND_INCLUDE_ONCE: + case ZEND_IMPORT_CLASS: case ZEND_REQUIRE_ONCE: { int dummy = 1; zend_file_handle file_handle; + int successful = 0; - if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) { + if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) { + successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } else { + successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } + + if (SUCCESS == successful) { if (!file_handle.opened_path) { file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); @@ -1868,8 +1876,10 @@ } else { if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val); - } else { + } else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val); + } else { + zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val); } } break; @@ -4264,11 +4274,19 @@ switch (opline->op2.u.constant.value.lval) { case ZEND_INCLUDE_ONCE: + case ZEND_IMPORT_CLASS: case ZEND_REQUIRE_ONCE: { int dummy = 1; zend_file_handle file_handle; + int successful = 0; - if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) { + if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) { + successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } else { + successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } + + if (SUCCESS == successful) { if (!file_handle.opened_path) { file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); @@ -4284,8 +4302,10 @@ } else { if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val); - } else { + } else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val); + } else { + zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val); } } break; @@ -7283,11 +7303,19 @@ switch (opline->op2.u.constant.value.lval) { case ZEND_INCLUDE_ONCE: + case ZEND_IMPORT_CLASS: case ZEND_REQUIRE_ONCE: { int dummy = 1; zend_file_handle file_handle; + int successful = 0; - if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) { + if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) { + successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } else { + successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } + + if (SUCCESS == successful) { if (!file_handle.opened_path) { file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); @@ -7303,8 +7331,10 @@ } else { if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val); - } else { + } else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val); + } else { + zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val); } } break; @@ -19322,11 +19352,19 @@ switch (opline->op2.u.constant.value.lval) { case ZEND_INCLUDE_ONCE: + case ZEND_IMPORT_CLASS: case ZEND_REQUIRE_ONCE: { int dummy = 1; zend_file_handle file_handle; + int successful = 0; - if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) { + if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) { + successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } else { + successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC); + } + + if (SUCCESS == successful) { if (!file_handle.opened_path) { file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); @@ -19342,8 +19380,10 @@ } else { if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val); - } else { + } else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val); + } else { + zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val); } } break; Index: Zend/zend_vm_opcodes.h =================================================================== RCS file: /repository/ZendEngine2/zend_vm_opcodes.h,v retrieving revision 1.38 diff -u -r1.38 zend_vm_opcodes.h --- Zend/zend_vm_opcodes.h 4 Jul 2005 13:24:46 -0000 1.38 +++ Zend/zend_vm_opcodes.h 20 Jul 2005 03:40:49 -0000 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_vm_opcodes.h,v 1.38 2005/07/04 13:24:46 dmitry Exp $ */ +/* $Id: zend_vm_gen.php,v 1.11 2005/06/24 12:33:53 dmitry Exp $ */ #define ZEND_NOP 0 #define ZEND_ADD 1 Index: main/main.c =================================================================== RCS file: /repository/php-src/main/main.c,v retrieving revision 1.636 diff -u -r1.636 main.c --- main/main.c 12 Jul 2005 16:53:29 -0000 1.636 +++ main/main.c 20 Jul 2005 03:40:52 -0000 @@ -292,6 +292,7 @@ STD_PHP_INI_ENTRY("error_log", NULL, PHP_INI_ALL, OnUpdateString, error_log, php_core_globals, core_globals) STD_PHP_INI_ENTRY("extension_dir", PHP_EXTENSION_DIR, PHP_INI_SYSTEM, OnUpdateStringUnempty, extension_dir, php_core_globals, core_globals) STD_PHP_INI_ENTRY("include_path", PHP_INCLUDE_PATH, PHP_INI_ALL, OnUpdateStringUnempty, include_path, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("class_path", PHP_INCLUDE_PATH, PHP_INI_ALL, OnUpdateStringUnempty, class_path, php_core_globals, core_globals) PHP_INI_ENTRY("max_execution_time", "30", PHP_INI_ALL, OnUpdateTimeout) STD_PHP_INI_ENTRY("open_basedir", NULL, PHP_INI_SYSTEM, OnUpdateString, open_basedir, php_core_globals, core_globals) STD_PHP_INI_ENTRY("safe_mode_exec_dir", PHP_SAFE_MODE_EXEC_DIR, PHP_INI_SYSTEM, OnUpdateString, safe_mode_exec_dir, php_core_globals, core_globals) @@ -868,6 +869,27 @@ return FAILURE; } +static int php_stream_open_for_zend_class(const char *filename, zend_file_handle *handle TSRMLS_DC) +{ + php_stream *stream = php_stream_open_wrapper_class((char *)filename, "rb", ENFORCE_SAFE_MODE|USE_PATH|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE, &handle->opened_path); + + if (stream) { + handle->type = ZEND_HANDLE_STREAM; + handle->filename = (char*)filename; + handle->free_filename = 0; + handle->handle.stream.handle = stream; + handle->handle.stream.reader = (zend_stream_reader_t)_php_stream_read; + handle->handle.stream.closer = stream_closer_for_zend; + handle->handle.stream.fteller = stream_fteller_for_zend; + handle->handle.stream.interactive = 0; + /* suppress warning if this stream is not explicitly closed */ + php_stream_auto_cleanup(stream); + + return SUCCESS; + } + return FAILURE; +} + /* {{{ php_get_configuration_directive_for_zend */ @@ -897,6 +919,9 @@ case ZMSG_FAILED_REQUIRE_FOPEN: php_error_docref("function.require" TSRMLS_CC, E_COMPILE_ERROR, "Failed opening required '%s' (include_path='%s')", php_strip_url_passwd((char *) data), STR_PRINT(PG(include_path))); break; + case ZMSG_FAILED_IMPORT_CLASS: + php_error_docref("function.import" TSRMLS_CC, E_COMPILE_ERROR, "Failed opening required '%s' (class_path='%s')", php_strip_url_passwd((char *) data), STR_PRINT(PG(class_path))); + break; case ZMSG_FAILED_HIGHLIGHT_FOPEN: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed opening '%s' for highlighting", php_strip_url_passwd((char *) data)); break; @@ -1368,6 +1393,7 @@ zuf.ticks_function = php_run_ticks; zuf.on_timeout = php_on_timeout; zuf.stream_open_function = php_stream_open_for_zend; + zuf.stream_open_class_function = php_stream_open_for_zend_class; zuf.vspprintf_function = vspprintf; zuf.getenv_function = sapi_getenv; zend_startup(&zuf, NULL, 1); Index: main/php_globals.h =================================================================== RCS file: /repository/php-src/main/php_globals.h,v retrieving revision 1.97 diff -u -r1.97 php_globals.h --- main/php_globals.h 16 Mar 2004 19:49:19 -0000 1.97 +++ main/php_globals.h 20 Jul 2005 03:40:52 -0000 @@ -89,6 +89,7 @@ char *doc_root; char *user_dir; char *include_path; + char *class_path; char *open_basedir; char *extension_dir; Index: main/php_streams.h =================================================================== RCS file: /repository/php-src/main/php_streams.h,v retrieving revision 1.102 diff -u -r1.102 php_streams.h --- main/php_streams.h 16 May 2005 08:37:10 -0000 1.102 +++ main/php_streams.h 20 Jul 2005 03:40:52 -0000 @@ -511,11 +511,13 @@ PHPAPI int php_register_url_stream_wrapper_volatile(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC); PHPAPI int php_unregister_url_stream_wrapper_volatile(char *protocol TSRMLS_DC); PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); +PHPAPI php_stream *_php_stream_open_wrapper_class(char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, char **path_for_open, int options TSRMLS_DC); PHPAPI char *php_stream_locate_eol(php_stream *stream, char *buf, size_t buf_len TSRMLS_DC); #define php_stream_open_wrapper(path, mode, options, opened) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_CC TSRMLS_CC) #define php_stream_open_wrapper_ex(path, mode, options, opened, context) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_CC TSRMLS_CC) +#define php_stream_open_wrapper_class(path, mode, options, opened) _php_stream_open_wrapper_class((path), (mode), (options), (opened), NULL STREAMS_CC TSRMLS_CC) #define php_stream_get_from_zval(stream, zstream, mode, options, opened, context) \ if (Z_TYPE_PP((zstream)) == IS_RESOURCE) { \ Index: main/streams/plain_wrapper.c =================================================================== RCS file: /repository/php-src/main/streams/plain_wrapper.c,v retrieving revision 1.48 diff -u -r1.48 plain_wrapper.c --- main/streams/plain_wrapper.c 24 Jun 2005 02:04:19 -0000 1.48 +++ main/streams/plain_wrapper.c 20 Jul 2005 03:40:53 -0000 @@ -917,11 +917,11 @@ /* }}} */ -static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode, - int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) +static php_stream *php_plain_files_stream_opener_ex(php_stream_wrapper *wrapper, char *path, char *mode, + int options, char **opened_path, char *include_path, php_stream_context *context STREAMS_DC TSRMLS_DC) { - if ((options & USE_PATH) && PG(include_path) != NULL) { - return php_stream_fopen_with_path_rel(path, mode, PG(include_path), opened_path, options); + if ((options & USE_PATH) && include_path != NULL) { + return php_stream_fopen_with_path_rel(path, mode, include_path, opened_path, options); } if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) { @@ -934,6 +934,18 @@ return php_stream_fopen_rel(path, mode, opened_path, options); } +static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode, + int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) +{ + return php_plain_files_stream_opener_ex(wrapper, path, mode, options, opened_path, PG(include_path), context STREAMS_CC TSRMLS_CC); +} + +static php_stream *php_class_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode, + int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) +{ + return php_plain_files_stream_opener_ex(wrapper, path, mode, options, opened_path, PG(class_path), context STREAMS_CC TSRMLS_CC); +} + static int php_plain_files_url_stater(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) { @@ -1162,6 +1174,25 @@ 0 }; +static php_stream_wrapper_ops php_class_files_wrapper_ops = { + php_class_files_stream_opener, + NULL, + NULL, + php_plain_files_url_stater, + php_plain_files_dir_opener, + "classfile", + NULL, + NULL, + NULL, + NULL +}; + +php_stream_wrapper php_class_files_wrapper = { + &php_class_files_wrapper_ops, + NULL, + 0 +}; + /* {{{ php_stream_fopen_with_path */ PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path, int options STREAMS_DC TSRMLS_DC) { Index: main/streams/streams.c =================================================================== RCS file: /repository/php-src/main/streams/streams.c,v retrieving revision 1.81 diff -u -r1.81 streams.c --- main/streams/streams.c 1 Jun 2005 15:11:44 -0000 1.81 +++ main/streams/streams.c 20 Jul 2005 03:40:53 -0000 @@ -40,6 +40,8 @@ static int le_pstream = FAILURE; /* true global */ static int le_stream_filter = FAILURE; /* true global */ +extern php_stream_wrapper php_class_files_wrapper; + PHPAPI int php_file_le_stream(void) { return le_stream; @@ -1739,13 +1741,11 @@ } /* }}} */ -/* {{{ php_stream_open_wrapper_ex */ -PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options, - char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) +/* {{{ php_stream_open_wrapper_ex_ww */ +PHPAPI php_stream *_php_stream_open_wrapper_ex_ww(char *path, char *mode, int options, + char **opened_path, php_stream_wrapper *wrapper, char *path_to_open, php_stream_context *context STREAMS_DC TSRMLS_DC) { php_stream *stream = NULL; - php_stream_wrapper *wrapper = NULL; - char *path_to_open; int persistent = options & STREAM_OPEN_PERSISTENT; char *copy_of_path = NULL; @@ -1758,9 +1758,6 @@ return NULL; } - path_to_open = path; - - wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC); if (options & STREAM_USE_URL && (!wrapper || !wrapper->is_url)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "This function may only be used against URLs."); return NULL; @@ -1842,6 +1839,27 @@ } /* }}} */ +/* {{{ php_stream_open_wrapper_ex */ +PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options, + char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) +{ + char *path_to_open = path; + php_stream_wrapper *wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC); + + if (!path || !*path) { + return NULL; + } + + return _php_stream_open_wrapper_ex_ww(path, mode, options, opened_path, wrapper, path_to_open, context STREAMS_CC TSRMLS_CC); +} +/* }}} */ + +PHPAPI php_stream *_php_stream_open_wrapper_class(char *path, char *mode, int options, + char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) +{ + return _php_stream_open_wrapper_ex_ww(path, mode, options, opened_path, &php_class_files_wrapper, path, context STREAMS_CC TSRMLS_CC); +} + /* {{{ context API */ PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context) { --nextPart2276357.JxREzF3cBR Content-Type: application/x-gzip; name="tests.tar.gz" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="tests.tar.gz" H4sICK7H3UIAA3Rlc3RzLnRhcgDtmX1r20gQh/2v9SkGn8H2ESXaXVkCp0nhUqcUSilJOArtIVR5 U2/RG9pVekfJd+++SIod2+dCGvVNPxxk7c5oZWmfmdmNoFzwoygOOaf8KA0TyvMwooHjoMN8mYve N5Aj5XmuPvr3jrpv6vaQgz3Pww5xnJ6DfPm9B863GHyfSi7CAqD3kXLO6G67ff3Vb2mOP4ls+2p+ eWXb1qv61c/gkiV5TOEsS3IWU/uKJRReJHlWCMu2z1+8nEvzJ0/l7LBYygJOxRhGegYFeSiWowNY sELNpDEEgTIPApjAIYzuptcIJseWxfQ1IeUz7Y2O77dgCLk8CcyJ9Bhel3EMJ5DST3duY3mtm7AI FmWSj0Gb2KcJTZAeZBjGTF7F+Gx10AYbHrgZphp+mxfWbli73fU1LrPZMPkvkBNMsEjZPD2VD3D+ 5vX8TD1xlooxmqwe8MTiomDphzFyJzAQS8ZBfswFBtZjvH+xk3/cGv8u8mr+MfaQ5t8nHf9taBv/ F2UqJPP2BeVZfEMXLcFvDc03CUwh4TNXRaNj2Y4qGFcs7uEYoU3AsvcfaSTGzRCTPxBI1OCzBfB2 oHgf/HNyKk8qBG8fhbAfW7v5J+3x7zkN/z7Bhv8u/7eibfy/LthNKGQBYGbFo3JPGu7JGvdEc0/W uCfbuCf3uL+YP5+/kfd6HoowBloUWTGDszBNMwElp6YEgFEz/giyUnC2oJBdAxOy3qjv90BVH0yo DJybJ3L45y8XIXbz77bGP/Gmmn+fEN93df73Hb/jvw1t5b98H8uC9RmVs54ujupw8FfI6ePGgiBa snihIwJZrdirDoW+7LFPJY6p+DuMS9o0RWEcX+o6ebxRBxCrKsGVEV1YvxzED9AO/o/SqlHvAjxw jH38I9fw702nHkKk52DHJ9OO/zZkMG7eu2TRUuWxkcmVZh40jXfdtXITL4Z6BX0CspSve25lTS1Z /N4/stNO7eMft8A/dnGz/4eIb/jHHf9t6Gv5x1/Hv9o1w8e7LKo0vLIpJsv99V2uURc8WtU+/qvS 60FRYO/6XzLf1P++yv8YYafjvw1VZfzmonx/SKimBtB/BU0XdeP/xInrMo0Ey1JYrd83rDb9atFo mcFQxQu97U4OYPAuHWxGm1vL6vebwVZXBrL9s/zrm1udzUzMOZematXQ79/+dsFnL/9t5H/c/P8P u8jR+R936/9WtDX/96v9rjXaLY3OSq5XS3QVKZrGKqc35K3SVZOnGR6srcc1w4q9/u8CXadOnTp1 6tSp03fUF+rBGJUAKAAA --nextPart2276357.JxREzF3cBR--