]> granicus.if.org Git - php/commitdiff
Optimized require_once() and include_once() by eliminationg open() syscall on second...
authorDmitry Stogov <dmitry@php.net>
Wed, 5 Mar 2008 13:34:12 +0000 (13:34 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 5 Mar 2008 13:34:12 +0000 (13:34 +0000)
NEWS
Zend/zend.c
Zend/zend.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
main/fopen_wrappers.c
main/fopen_wrappers.h
main/main.c

diff --git a/NEWS b/NEWS
index 8c2fcdb33dd212ebfee3d1fda3ecb3c38c756326..bde3d9dcd6e963662e894351273bf215d6180491 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -87,6 +87,8 @@ PHP                                                                        NEWS
     (Dmitry, Pierre)
   . Changed exception handling. Now each op_array doesn't contain
     ZEND_HANDLE_EXCEPTION opcode in the end. (Dmitry)
+  . Optimized require_once() and include_once() by eliminating fopen(3) on
+    second usage. (Dmitry)
 - Improved php.ini handling: (Jani)
   . Added ".htaccess" style user-defined php.ini files support for CGI/FastCGI
   . Added support for special [PATH=/opt/httpd/www.example.com/] and
index 9f9f4965723298386b331834976bee04c18ca12f..95e8ad5f55c6da98fefe1f9cc35da9f46c4d9c2d 100644 (file)
@@ -57,6 +57,7 @@ ZEND_API void (*zend_ticks_function)(int ticks);
 ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);
 int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap);
 ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC);
+ZEND_API char *(*zend_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
 
 void (*zend_on_timeout)(int seconds TSRMLS_DC);
 
@@ -622,6 +623,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i
        zend_on_timeout = utility_functions->on_timeout;
        zend_vspprintf = utility_functions->vspprintf_function;
        zend_getenv = utility_functions->getenv_function;
+       zend_resolve_path = utility_functions->resolve_path_function;
 
        zend_compile_file = compile_file;
        zend_compile_string = compile_string;
index 9e44a79adaa7907f24070ff4f64a1d6855b436d2..765b8af3b91177badd8345ba78304485018d51bf 100644 (file)
@@ -463,6 +463,7 @@ typedef struct _zend_utility_functions {
        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);
+       char *(*resolve_path_function)(const char *filename, int filename_len TSRMLS_DC);
 } zend_utility_functions;
 
 typedef struct _zend_utility_values {
@@ -590,6 +591,7 @@ 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 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);
+extern ZEND_API char *(*zend_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
 
 ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
 
index 9f03d7e35d49f9cd216d3d319044bd4ff9016e93..7202dee6a594394d2c71cff41b7b66de80626b79 100644 (file)
@@ -3054,26 +3054,21 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY)
                case ZEND_INCLUDE_ONCE:
                case ZEND_REQUIRE_ONCE: {
                                zend_file_handle file_handle;
+                               char *resolved_path;
 
-                               if (IS_ABSOLUTE_PATH(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename))) {
-                                       cwd_state state;
-
-                                       state.cwd_length = 0;
-                                       state.cwd = malloc(1);
-                                       state.cwd[0] = 0;
-
-                                       failure_retval = (!virtual_file_ex(&state, Z_STRVAL_P(inc_filename), NULL, 1) &&
-                                               zend_hash_exists(&EG(included_files), state.cwd, state.cwd_length+1));
-
-                                       free(state.cwd);
+                               resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename) TSRMLS_CC);
+                               if (resolved_path) {
+                                       failure_retval = zend_hash_exists(&EG(included_files), resolved_path, strlen(resolved_path)+1);
+                               } else {
+                                       resolved_path = Z_STRVAL_P(inc_filename);
                                }
 
                                if (failure_retval) {
-                                       /* do nothing */
-                               } else if (SUCCESS == zend_stream_open(Z_STRVAL_P(inc_filename), &file_handle TSRMLS_CC)) {
+                                       /* do nothing, file already included */
+                               } else if (SUCCESS == zend_stream_open(resolved_path, &file_handle TSRMLS_CC)) {
 
                                        if (!file_handle.opened_path) {
-                                               file_handle.opened_path = estrndup(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename));
+                                               file_handle.opened_path = estrdup(resolved_path);
                                        }
 
                                        if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1)==SUCCESS) {
@@ -3090,6 +3085,9 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY)
                                                zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename));
                                        }
                                }
+                               if (resolved_path != Z_STRVAL_P(inc_filename)) {
+                                       efree(resolved_path);
+                               }
                        }
                        break;
                case ZEND_INCLUDE:
index 0acfdab2b6c04ffe97f9b41cccf89d286a84dd8c..bc864c858309e6d3d9e3f76bbf123bda0c8b4afa 100644 (file)
@@ -1663,26 +1663,21 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                case ZEND_INCLUDE_ONCE:
                case ZEND_REQUIRE_ONCE: {
                                zend_file_handle file_handle;
+                               char *resolved_path;
 
-                               if (IS_ABSOLUTE_PATH(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename))) {
-                                       cwd_state state;
-
-                                       state.cwd_length = 0;
-                                       state.cwd = malloc(1);
-                                       state.cwd[0] = 0;
-
-                                       failure_retval = (!virtual_file_ex(&state, Z_STRVAL_P(inc_filename), NULL, 1) &&
-                                               zend_hash_exists(&EG(included_files), state.cwd, state.cwd_length+1));
-
-                                       free(state.cwd);
+                               resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename) TSRMLS_CC);
+                               if (resolved_path) {
+                                       failure_retval = zend_hash_exists(&EG(included_files), resolved_path, strlen(resolved_path)+1);
+                               } else {
+                                       resolved_path = Z_STRVAL_P(inc_filename);
                                }
 
                                if (failure_retval) {
-                                       /* do nothing */
-                               } else if (SUCCESS == zend_stream_open(Z_STRVAL_P(inc_filename), &file_handle TSRMLS_CC)) {
+                                       /* do nothing, file already included */
+                               } else if (SUCCESS == zend_stream_open(resolved_path, &file_handle TSRMLS_CC)) {
 
                                        if (!file_handle.opened_path) {
-                                               file_handle.opened_path = estrndup(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename));
+                                               file_handle.opened_path = estrdup(resolved_path);
                                        }
 
                                        if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1)==SUCCESS) {
@@ -1699,6 +1694,9 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                                                zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename));
                                        }
                                }
+                               if (resolved_path != Z_STRVAL_P(inc_filename)) {
+                                       efree(resolved_path);
+                               }
                        }
                        break;
                case ZEND_INCLUDE:
@@ -4850,26 +4848,21 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                case ZEND_INCLUDE_ONCE:
                case ZEND_REQUIRE_ONCE: {
                                zend_file_handle file_handle;
+                               char *resolved_path;
 
-                               if (IS_ABSOLUTE_PATH(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename))) {
-                                       cwd_state state;
-
-                                       state.cwd_length = 0;
-                                       state.cwd = malloc(1);
-                                       state.cwd[0] = 0;
-
-                                       failure_retval = (!virtual_file_ex(&state, Z_STRVAL_P(inc_filename), NULL, 1) &&
-                                               zend_hash_exists(&EG(included_files), state.cwd, state.cwd_length+1));
-
-                                       free(state.cwd);
+                               resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename) TSRMLS_CC);
+                               if (resolved_path) {
+                                       failure_retval = zend_hash_exists(&EG(included_files), resolved_path, strlen(resolved_path)+1);
+                               } else {
+                                       resolved_path = Z_STRVAL_P(inc_filename);
                                }
 
                                if (failure_retval) {
-                                       /* do nothing */
-                               } else if (SUCCESS == zend_stream_open(Z_STRVAL_P(inc_filename), &file_handle TSRMLS_CC)) {
+                                       /* do nothing, file already included */
+                               } else if (SUCCESS == zend_stream_open(resolved_path, &file_handle TSRMLS_CC)) {
 
                                        if (!file_handle.opened_path) {
-                                               file_handle.opened_path = estrndup(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename));
+                                               file_handle.opened_path = estrdup(resolved_path);
                                        }
 
                                        if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1)==SUCCESS) {
@@ -4886,6 +4879,9 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                                                zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename));
                                        }
                                }
+                               if (resolved_path != Z_STRVAL_P(inc_filename)) {
+                                       efree(resolved_path);
+                               }
                        }
                        break;
                case ZEND_INCLUDE:
@@ -8068,26 +8064,21 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                case ZEND_INCLUDE_ONCE:
                case ZEND_REQUIRE_ONCE: {
                                zend_file_handle file_handle;
+                               char *resolved_path;
 
-                               if (IS_ABSOLUTE_PATH(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename))) {
-                                       cwd_state state;
-
-                                       state.cwd_length = 0;
-                                       state.cwd = malloc(1);
-                                       state.cwd[0] = 0;
-
-                                       failure_retval = (!virtual_file_ex(&state, Z_STRVAL_P(inc_filename), NULL, 1) &&
-                                               zend_hash_exists(&EG(included_files), state.cwd, state.cwd_length+1));
-
-                                       free(state.cwd);
+                               resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename) TSRMLS_CC);
+                               if (resolved_path) {
+                                       failure_retval = zend_hash_exists(&EG(included_files), resolved_path, strlen(resolved_path)+1);
+                               } else {
+                                       resolved_path = Z_STRVAL_P(inc_filename);
                                }
 
                                if (failure_retval) {
-                                       /* do nothing */
-                               } else if (SUCCESS == zend_stream_open(Z_STRVAL_P(inc_filename), &file_handle TSRMLS_CC)) {
+                                       /* do nothing, file already included */
+                               } else if (SUCCESS == zend_stream_open(resolved_path, &file_handle TSRMLS_CC)) {
 
                                        if (!file_handle.opened_path) {
-                                               file_handle.opened_path = estrndup(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename));
+                                               file_handle.opened_path = estrdup(resolved_path);
                                        }
 
                                        if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1)==SUCCESS) {
@@ -8104,6 +8095,9 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                                                zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename));
                                        }
                                }
+                               if (resolved_path != Z_STRVAL_P(inc_filename)) {
+                                       efree(resolved_path);
+                               }
                        }
                        break;
                case ZEND_INCLUDE:
@@ -21750,26 +21744,21 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                case ZEND_INCLUDE_ONCE:
                case ZEND_REQUIRE_ONCE: {
                                zend_file_handle file_handle;
+                               char *resolved_path;
 
-                               if (IS_ABSOLUTE_PATH(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename))) {
-                                       cwd_state state;
-
-                                       state.cwd_length = 0;
-                                       state.cwd = malloc(1);
-                                       state.cwd[0] = 0;
-
-                                       failure_retval = (!virtual_file_ex(&state, Z_STRVAL_P(inc_filename), NULL, 1) &&
-                                               zend_hash_exists(&EG(included_files), state.cwd, state.cwd_length+1));
-
-                                       free(state.cwd);
+                               resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename) TSRMLS_CC);
+                               if (resolved_path) {
+                                       failure_retval = zend_hash_exists(&EG(included_files), resolved_path, strlen(resolved_path)+1);
+                               } else {
+                                       resolved_path = Z_STRVAL_P(inc_filename);
                                }
 
                                if (failure_retval) {
-                                       /* do nothing */
-                               } else if (SUCCESS == zend_stream_open(Z_STRVAL_P(inc_filename), &file_handle TSRMLS_CC)) {
+                                       /* do nothing, file already included */
+                               } else if (SUCCESS == zend_stream_open(resolved_path, &file_handle TSRMLS_CC)) {
 
                                        if (!file_handle.opened_path) {
-                                               file_handle.opened_path = estrndup(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename));
+                                               file_handle.opened_path = estrdup(resolved_path);
                                        }
 
                                        if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1)==SUCCESS) {
@@ -21786,6 +21775,9 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                                                zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename));
                                        }
                                }
+                               if (resolved_path != Z_STRVAL_P(inc_filename)) {
+                                       efree(resolved_path);
+                               }
                        }
                        break;
                case ZEND_INCLUDE:
index 736da15b0d0da9e1c2211742ab32edf81dfe1cd8..3fa92b121f17a123c0105f4ac182d4671057df34 100644 (file)
@@ -439,6 +439,80 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC)
 }
 /* }}} */
 
+/* {{{ php_resolve_path
+ * Returns the realpath for given filename according to include path
+ */
+PHPAPI char *php_resolve_path(const char *filename, int filename_length, const char *path TSRMLS_DC)
+{
+       char resolved_path[MAXPATHLEN];
+       char trypath[MAXPATHLEN];
+       char *ptr, *end;
+
+       if (!filename) {
+               return NULL;
+       }
+
+       if (*filename == '.' ||
+           IS_ABSOLUTE_PATH(filename, filename_length) ||
+           !path ||
+           !*path) {
+               if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
+                       return estrdup(resolved_path);
+               } else {
+                       return NULL;
+               }
+       }
+
+       ptr = path;
+       while (ptr && *ptr) {
+               end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
+               if (end) {
+                       if ((end-ptr) + 1 + filename_length + 1 >= MAXPATHLEN) {
+                               ptr = end + 1;
+                               continue;
+                       }
+                       memcpy(trypath, ptr, end-ptr);
+                       trypath[end-ptr] = '/';
+                       memcpy(trypath+(end-ptr)+1, filename, filename_length+1);
+                       ptr = end+1;
+               } else {
+                       int len = strlen(ptr);
+
+                       if (len + 1 + filename_length + 1 >= MAXPATHLEN) {
+                               break;
+                       }
+                       memcpy(trypath, ptr, len);
+                       trypath[len] = '/';
+                       memcpy(trypath+len+1, filename, filename_length+1);
+                       ptr = NULL;
+               }
+               if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
+                       return estrdup(resolved_path);
+               }
+       } /* end provided path */
+
+       /* check in calling scripts' current working directory as a fall back case
+        */
+       if (zend_is_executing(TSRMLS_C)) {
+               char *exec_fname = zend_get_executed_filename(TSRMLS_C);
+               int exec_fname_length = strlen(exec_fname);
+
+               while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
+               if (exec_fname && exec_fname[0] != '[' &&
+                   exec_fname_length > 0 &&
+                   exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN) {
+                       memcpy(trypath, exec_fname, exec_fname_length + 1);
+                       memcpy(trypath+exec_fname_length + 1, filename, filename_length+1);
+                       if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
+                               return estrdup(resolved_path);
+                       }
+               }
+       }
+
+       return NULL;
+}
+/* }}} */
+
 /* {{{ php_fopen_with_path
  * Tries to open a file with a PATH-style list of directories.
  * If the filename starts with "." or "/", the path is ignored.
index c442d76708ad7a50c471f4e7ae3f728b96213143..2afd24183b9590ee7c1664effcc2565129d8a3b2 100644 (file)
@@ -33,6 +33,8 @@ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path
 
 PHPAPI int php_check_safe_mode_include_dir(const char *path TSRMLS_DC);
 
+PHPAPI char *php_resolve_path(const char *filename, int filename_len, const char *path TSRMLS_DC);
+
 PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const char *path, char **opened_path TSRMLS_DC);
 
 PHPAPI char *php_strip_url_passwd(char *path);
index 60e488d0d32ff2f2cd9c1e5afaa8f30a5a1f1172..2cf47034ff4dce2f6702cc413ba7a54683ccfd78 100644 (file)
@@ -1098,6 +1098,12 @@ PHPAPI int php_stream_open_for_zend_ex(const char *filename, zend_file_handle *h
 }
 /* }}} */
 
+static char *php_resolve_path_for_zend(const char *filename, int filename_len TSRMLS_DC) /* {{{ */
+{
+       return php_resolve_path(filename, filename_len, PG(include_path) TSRMLS_CC);
+}
+/* }}} */
+
 /* {{{ php_get_configuration_directive_for_zend
  */
 static int php_get_configuration_directive_for_zend(char *name, uint name_length, zval *contents)
@@ -1697,6 +1703,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
        zuf.stream_open_function = php_stream_open_for_zend;
        zuf.vspprintf_function = vspprintf;
        zuf.getenv_function = sapi_getenv;
+       zuf.resolve_path_function = php_resolve_path_for_zend;
        zend_startup(&zuf, NULL, 1);
 
 #ifdef ZTS