diff --git a/ext/standard/tests/streams/gh17067.phpt b/ext/standard/tests/streams/gh17067.phpt new file mode 100644 index 0000000000000..f3ea6a682a5ef --- /dev/null +++ b/ext/standard/tests/streams/gh17067.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-17067 (glob:// wrapper doesn't cater to CWD for ZTS builds) +--FILE-- + +--CLEAN-- + +--EXPECT-- +array(1) { + [0]=> + string(3) "foo" +} diff --git a/main/streams/glob_wrapper.c b/main/streams/glob_wrapper.c index 66f2e8e0dfc70..8772850f784f3 100644 --- a/main/streams/glob_wrapper.c +++ b/main/streams/glob_wrapper.c @@ -225,10 +225,32 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha *opened_path = zend_string_init(path, strlen(path), 0); } } + const char *pattern = path; +#ifdef ZTS + char cwd[MAXPATHLEN]; + char work_pattern[MAXPATHLEN]; + char *result; + size_t cwd_skip = 0; + if (!IS_ABSOLUTE_PATH(path, strlen(path))) { + result = VCWD_GETCWD(cwd, MAXPATHLEN); + if (!result) { + cwd[0] = '\0'; + } +# ifdef PHP_WIN32 + if (IS_SLASH(*path)) { + cwd[2] = '\0'; + } +# endif + cwd_skip = strlen(cwd)+1; + + snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, path); + pattern = work_pattern; + } +#endif pglob = ecalloc(1, sizeof(*pglob)); - if (0 != (ret = glob(path, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) { + if (0 != (ret = glob(pattern, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) { #ifdef GLOB_NOMATCH if (GLOB_NOMATCH != ret) #endif @@ -238,6 +260,21 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha } } +#ifdef ZTS + if (cwd_skip > 0) { + /* strip prepended CWD */ + for (i = 0; i < pglob->glob.gl_pathc; i++) { + char *p = pglob->glob.gl_pathv[i]; + char *q = p + cwd_skip; + char *e = p + strlen(pglob->glob.gl_pathv[i]) - 1; + while (q <= e) { + *p++ = *q++; + } + *p = '\0'; + } + } +#endif + /* if open_basedir in use, check and filter restricted paths */ if ((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) { pglob->open_basedir_used = true;