]> granicus.if.org Git - php/commitdiff
Added ability to use stream wrappers in include_path
authorDmitry Stogov <dmitry@php.net>
Thu, 27 Mar 2008 10:33:52 +0000 (10:33 +0000)
committerDmitry Stogov <dmitry@php.net>
Thu, 27 Mar 2008 10:33:52 +0000 (10:33 +0000)
ext/standard/tests/file/include_streams.phpt [new file with mode: 0644]
main/fopen_wrappers.c
main/php_streams.h
main/streams/plain_wrapper.c
main/streams/streams.c

diff --git a/ext/standard/tests/file/include_streams.phpt b/ext/standard/tests/file/include_streams.phpt
new file mode 100644 (file)
index 0000000..4c7d4bb
--- /dev/null
@@ -0,0 +1,130 @@
+--TEST--
+Stream wrappers in include_path
+--FILE--
+<?php
+$data1 = $data2 = $data3 = $data4 = $data5 = $data6 = <<<'EOD'
+<?php echo __FILE__ . "\n";?>
+
+EOD;
+
+class mystream 
+{
+       public $path;
+       public $mode;
+       public $options;
+
+       public $position;
+       public $varname;
+
+       function url_stat($path, $flags) {
+               return array();
+       }
+       
+       function stream_stat() {
+               return array();
+       }
+
+       function stream_open($path, $mode, $options, &$opened_path)
+       {
+               $this->path = $path;
+               $this->mode = $mode;
+               $this->options = $options;
+
+               $split = parse_url($path);
+               if ($split["host"] !== "GLOBALS" || 
+                   empty($split["path"]) ||
+                   empty($GLOBALS[substr($split["path"],1)])) {
+                   return false;
+               }
+               $this->varname = substr($split["path"],1);
+
+               if (strchr($mode, 'a'))
+                       $this->position = strlen($GLOBALS[$this->varname]);
+               else
+                       $this->position = 0;
+               
+               return true;
+       }
+
+       function stream_read($count)
+       {
+               $ret = substr($GLOBALS[$this->varname], $this->position, $count);
+               $this->position += strlen($ret);
+               return $ret;
+       }
+
+       function stream_tell()
+       {
+               return $this->position;
+       }
+
+       function stream_eof()
+       {
+               return $this->position >= strlen($GLOBALS[$this->varname]);
+       }
+
+       function stream_seek($offset, $whence)
+       {
+               switch($whence) {
+                       case SEEK_SET:
+                               if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) {
+                                       $this->position = $offset;
+                                       return true;
+                               } else {
+                                       return false;
+                               }
+                               break;
+                       case SEEK_CUR:
+                               if ($offset >= 0) {
+                                       $this->position += $offset;
+                                       return true;
+                               } else {
+                                       return false;
+                               }
+                               break;
+                       case SEEK_END:
+                               if (strlen($GLOBALS[$this->varname]) + $offset >= 0) {
+                                       $this->position = strlen($GLOBALS[$this->varname]) + $offset;
+                                       return true;
+                               } else {
+                                       return false;
+                               }
+                               break;
+                       default:
+                               return false;
+               }
+       }
+
+}
+
+if (!stream_wrapper_register("test", "mystream")) {
+       die("test wrapper registration failed");
+}
+
+echo file_get_contents("test://GLOBALS/data1");
+include("test://GLOBALS/data1");
+include_once("test://GLOBALS/data2");
+include_once("test://GLOBALS/data2");
+$include_path = get_include_path();
+set_include_path($include_path . PATH_SEPARATOR . "test://GLOBALS");
+echo file_get_contents("data3", true);
+include("data3");
+include_once("data4");
+include_once("data4");
+set_include_path("test://GLOBALS"  . PATH_SEPARATOR .  $include_path);
+echo file_get_contents("data5", true);
+include("data5");
+include_once("data6");
+include_once("data6");
+?>
+--EXPECTF--
+<?php echo __FILE__ . "\n";?>
+test://GLOBALS/data1
+test://GLOBALS/data2
+<?php echo __FILE__ . "\n";?>
+test://GLOBALS/data3
+test://GLOBALS/data4
+<?php echo __FILE__ . "\n";?>
+test://GLOBALS/data5
+test://GLOBALS/data6
+
index 5f55105ac627390308edf7d062752306314657fc..2efba4d85fc19386dbef6c8c955fff3f85ee8080 100644 (file)
@@ -455,14 +455,22 @@ PHPAPI char *php_resolve_path(const char *filename, int filename_length, const c
        char resolved_path[MAXPATHLEN];
        char trypath[MAXPATHLEN];
        const char *ptr, *end, *p;
+       char *actual_path;
+       php_stream_wrapper *wrapper;
 
        if (!filename) {
                return NULL;
        }
 
-       /* Don't resolve paths which contain protocol */
+       /* Don't resolve paths which contain protocol (except of file://) */
        for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
        if ((*p == ':') && (p - filename > 1) && (p[1] == '/') && (p[2] == '/')) {
+               wrapper = php_stream_locate_url_wrapper(filename, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+               if (wrapper == &php_plain_files_wrapper) {
+                       if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
+                               return estrdup(resolved_path);
+                       }
+               }
                return NULL;
        }
 
@@ -481,7 +489,18 @@ PHPAPI char *php_resolve_path(const char *filename, int filename_length, const c
 
        ptr = path;
        while (ptr && *ptr) {
-               end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
+               /* Check for stream wrapper */
+               int is_stream_wrapper = 0;
+
+               for (p = ptr; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+               if ((*p == ':') && (p - ptr > 1) && (p[1] == '/') && (p[2] == '/')) {
+                       /* .:// or ..:// is not a stream wrapper */
+                       if (p[-1] != '.' || p[-2] != '.' || p - 2 != ptr) {
+                               p += 3;
+                               is_stream_wrapper = 1;
+                       }
+               }
+               end = strchr(p, DEFAULT_DIR_SEPARATOR);
                if (end) {
                        if ((end-ptr) + 1 + filename_length + 1 >= MAXPATHLEN) {
                                ptr = end + 1;
@@ -502,7 +521,23 @@ PHPAPI char *php_resolve_path(const char *filename, int filename_length, const c
                        memcpy(trypath+len+1, filename, filename_length+1);
                        ptr = NULL;
                }
-               if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
+               actual_path = trypath;
+               if (is_stream_wrapper) {
+                       wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+                       if (!wrapper) {
+                               continue;
+                       } else if (wrapper != &php_plain_files_wrapper) {
+                               if (wrapper->wops->url_stat) {
+                                       php_stream_statbuf ssb;
+
+                                       if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
+                                               return estrdup(trypath);
+                                       }
+                               }
+                               continue;
+                       }
+               }
+               if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
                        return estrdup(resolved_path);
                }
        } /* end provided path */
@@ -519,7 +554,27 @@ PHPAPI char *php_resolve_path(const char *filename, int filename_length, const c
                    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)) {
+                       actual_path = trypath;
+
+                       /* Check for stream wrapper */
+                       for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+                       if ((*p == ':') && (p - trypath > 1) && (p[1] == '/') && (p[2] == '/')) {
+                               wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+                               if (!wrapper) {
+                                       return NULL;
+                               } else if (wrapper != &php_plain_files_wrapper) {
+                                       if (wrapper->wops->url_stat) {
+                                               php_stream_statbuf ssb;
+
+                                               if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
+                                                       return estrdup(trypath);
+                                               }
+                                       }
+                                       return NULL;
+                               }
+                       }
+
+                       if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
                                return estrdup(resolved_path);
                        }
                }
index e7e0dec0cc687f4cafa5e1209ef921e29cfaa78b..44606f26b9a44cd2de0c5967962fcf2fbe0f910d 100755 (executable)
@@ -622,6 +622,9 @@ END_EXTERN_C()
 /* don't check allow_url_fopen and allow_url_include */
 #define STREAM_DISABLE_URL_PROTECTION   0x00002000
 
+/* assume the path passed in exists and is fully expanded, avoiding syscalls */
+#define STREAM_ASSUME_REALPATH          0x00004000
+
 /* Antique - no longer has meaning */
 #define IGNORE_URL_WIN 0
 
index 52a9df388bae62c3cb73b86ac79c0ed54dccc647..f92a8939b0c8f87eefacc5040f474effe18844b0 100644 (file)
@@ -889,9 +889,13 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, cha
                }
                return NULL;
        }
-       
-       if ((realpath = expand_filepath(filename, NULL TSRMLS_CC)) == NULL) {
-               return NULL;
+
+       if (options & STREAM_ASSUME_REALPATH) {
+               realpath = estrdup(filename);
+       } else {
+               if ((realpath = expand_filepath(filename, NULL TSRMLS_CC)) == NULL) {
+                       return NULL;
+               }
        }
 
        if (persistent) {
index 7282dcaa2494d947e57ebae03ce2b6b15bcdaaa4..19f3fcd457448c019f59f44d058c923d385fdcab 100755 (executable)
@@ -2356,6 +2356,7 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int optio
        php_stream_wrapper *wrapper = NULL;
        char *path_to_open;
        int persistent = options & STREAM_OPEN_PERSISTENT;
+       char *resolved_path = NULL;
        char *copy_of_path = NULL;
        char implicit_mode[16];
        int modelen = strlen(mode);
@@ -2368,11 +2369,24 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int optio
                return NULL;
        }
 
+       if (options & USE_PATH) {
+               resolved_path = php_resolve_path(path, strlen(path), PG(include_path) TSRMLS_CC);
+               if (resolved_path) {
+                       path = resolved_path;
+                       /* we've found this file, don't re-check include_path or run realpath */
+                       options |= STREAM_ASSUME_REALPATH;
+                       options &= ~USE_PATH;
+               }
+       }
+
        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");
+               if (resolved_path) {
+                       efree(resolved_path);
+               }
                return NULL;
        }
 
@@ -2412,6 +2426,10 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int optio
        }
 
        if (stream) {
+               if (opened_path && !*opened_path && resolved_path) {
+                       *opened_path = resolved_path;
+                       resolved_path = NULL;
+               }
                if (stream->orig_path) {
                        pefree(stream->orig_path, persistent);
                }
@@ -2430,12 +2448,18 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int optio
                                        (options & STREAM_WILL_CAST)
                                                ? PHP_STREAM_PREFER_STDIO : PHP_STREAM_NO_PREFERENCE)) {
                        case PHP_STREAM_UNCHANGED:
+                               if (resolved_path) {
+                                       efree(resolved_path);
+                               }
                                return stream;
                        case PHP_STREAM_RELEASED:
                                if (newstream->orig_path) {
                                        pefree(newstream->orig_path, persistent);
                                }
                                newstream->orig_path = pestrdup(path, persistent);
+                               if (resolved_path) {
+                                       efree(resolved_path);
+                               }
                                return newstream;
                        default:
                                php_stream_close(stream);
@@ -2478,6 +2502,9 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int optio
        }
 #endif
 
+       if (resolved_path) {
+               efree(resolved_path);
+       }
        return stream;
 }
 /* }}} */