From: Dmitry Stogov Date: Thu, 27 Mar 2008 10:33:52 +0000 (+0000) Subject: Added ability to use stream wrappers in include_path X-Git-Tag: RELEASE_2_0_0b1~545 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=977cc7939856c932b386769d10cca8cb0373e52a;p=php Added ability to use stream wrappers in include_path --- diff --git a/ext/standard/tests/file/include_streams.phpt b/ext/standard/tests/file/include_streams.phpt new file mode 100644 index 0000000000..4c7d4bb082 --- /dev/null +++ b/ext/standard/tests/file/include_streams.phpt @@ -0,0 +1,130 @@ +--TEST-- +Stream wrappers in include_path +--FILE-- + + +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-- + +test://GLOBALS/data1 +test://GLOBALS/data2 + +test://GLOBALS/data3 +test://GLOBALS/data4 + +test://GLOBALS/data5 +test://GLOBALS/data6 + diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c index 5f55105ac6..2efba4d85f 100644 --- a/main/fopen_wrappers.c +++ b/main/fopen_wrappers.c @@ -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); } } diff --git a/main/php_streams.h b/main/php_streams.h index e7e0dec0cc..44606f26b9 100755 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -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 diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 52a9df388b..f92a8939b0 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -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) { diff --git a/main/streams/streams.c b/main/streams/streams.c index 7282dcaa24..19f3fcd457 100755 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -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; } /* }}} */