/* {{{ php_resolve_path * Returns the realpath for given filename according to include path */ PHPAPI zend_string *php_resolve_path(const char *filename, int filename_length, const char *path) { char resolved_path[MAXPATHLEN]; char trypath[MAXPATHLEN]; const char *ptr, *end, *p; const char *actual_path; php_stream_wrapper *wrapper; zend_string *exec_filename; if (!filename || CHECK_NULL_PATH(filename, filename_length)) { return NULL; } /* 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); if (wrapper == &php_plain_files_wrapper) { if (tsrm_realpath(actual_path, resolved_path)) { return zend_string_init(resolved_path, strlen(resolved_path), 0); } } return NULL; } if ((*filename == '.' && (IS_SLASH(filename[1]) || ((filename[1] == '.') && IS_SLASH(filename[2])))) || IS_ABSOLUTE_PATH(filename, filename_length) || !path || !*path) { if (tsrm_realpath(filename, resolved_path)) { return zend_string_init(resolved_path, strlen(resolved_path), 0); } else { return NULL; } } ptr = path; while (ptr && *ptr) { /* 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; continue; } memcpy(trypath, ptr, end-ptr); trypath[end-ptr] = '/'; memcpy(trypath+(end-ptr)+1, filename, filename_length+1); ptr = end+1; } else { int len = (int)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; } actual_path = trypath; if (is_stream_wrapper) { wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE); 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)) { return zend_string_init(trypath, strlen(trypath), 0); } } continue; } } if (tsrm_realpath(actual_path, resolved_path)) { return zend_string_init(resolved_path, strlen(resolved_path), 0); } } /* end provided path */ /* check in calling scripts' current working directory as a fall back case */ if (zend_is_executing() && (exec_filename = zend_get_executed_filename_ex()) != NULL) { const char *exec_fname = exec_filename->val; size_t exec_fname_length = exec_filename->len; while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])); if (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); 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); 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)) { return zend_string_init(trypath, strlen(trypath), 0); } } return NULL; } } if (tsrm_realpath(actual_path, resolved_path)) { return zend_string_init(resolved_path, strlen(resolved_path), 0); } } } 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. */ PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const char *path, zend_string **opened_path) { char *pathbuf, *ptr, *end; char trypath[MAXPATHLEN]; FILE *fp; int filename_length; zend_string *exec_filename; if (opened_path) { *opened_path = NULL; } if (!filename) { return NULL; } filename_length = (int)strlen(filename); #ifndef PHP_WIN32 (void) filename_length; #endif /* Relative path open */ if ((*filename == '.') /* Absolute path open */ || IS_ABSOLUTE_PATH(filename, filename_length) || (!path || (path && !*path)) ) { return php_fopen_and_set_opened_path(filename, mode, opened_path); } /* check in provided path */ /* append the calling scripts' current working directory * as a fall back case */ if (zend_is_executing() && (exec_filename = zend_get_executed_filename_ex()) != NULL) { const char *exec_fname = exec_filename->val; size_t exec_fname_length = exec_filename->len; while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])); if ((exec_fname && exec_fname[0] == '[') || exec_fname_length <= 0) { /* [no active file] or no path */ pathbuf = estrdup(path); } else { size_t path_length = strlen(path); pathbuf = (char *) emalloc(exec_fname_length + path_length + 1 + 1); memcpy(pathbuf, path, path_length); pathbuf[path_length] = DEFAULT_DIR_SEPARATOR; memcpy(pathbuf + path_length + 1, exec_fname, exec_fname_length); pathbuf[path_length + exec_fname_length + 1] = '\0'; } } else { pathbuf = estrdup(path); } ptr = pathbuf; while (ptr && *ptr) { end = strchr(ptr, DEFAULT_DIR_SEPARATOR); if (end != NULL) { *end = '\0'; end++; } if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) { php_error_docref(NULL, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN); } fp = php_fopen_and_set_opened_path(trypath, mode, opened_path); if (fp) { efree(pathbuf); return fp; } ptr = end; } /* end provided path */ efree(pathbuf); return NULL; }
/* {{{ php_resolve_path * Returns the realpath for given filename according to include path */ PHPAPI zend_string *php_resolve_path(const char *filename, int filename_length, const char *path) { char resolved_path[MAXPATHLEN]; char trypath[MAXPATHLEN]; const char *ptr, *end, *p; const char *actual_path; php_stream_wrapper *wrapper; zend_string *exec_filename; if (!filename || CHECK_NULL_PATH(filename, filename_length)) { return NULL; } /* 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); if (wrapper == &php_plain_files_wrapper) { if (tsrm_realpath(actual_path, resolved_path)) { return zend_string_init(resolved_path, strlen(resolved_path), 0); } } return NULL; } if ((*filename == '.' && (IS_SLASH(filename[1]) || ((filename[1] == '.') && IS_SLASH(filename[2])))) || IS_ABSOLUTE_PATH(filename, filename_length) || #if PHP_WIN32 /* This should count as an absolute local path as well, however IS_ABSOLUTE_PATH doesn't care about this path form till now. It might be a big thing to extend, thus just a local handling for now. */ filename_length >=2 && IS_SLASH(filename[0]) && !IS_SLASH(filename[1]) || #endif !path || !*path) { if (tsrm_realpath(filename, resolved_path)) { return zend_string_init(resolved_path, strlen(resolved_path), 0); } else { return NULL; } } ptr = path; while (ptr && *ptr) { /* 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 (filename_length > (MAXPATHLEN - 2) || (end-ptr) > MAXPATHLEN || (end-ptr) + 1 + (size_t)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 { size_t len = strlen(ptr); if (filename_length > (MAXPATHLEN - 2) || len > MAXPATHLEN || len + 1 + (size_t)filename_length + 1 >= MAXPATHLEN) { break; } memcpy(trypath, ptr, len); trypath[len] = '/'; memcpy(trypath+len+1, filename, filename_length+1); ptr = NULL; } actual_path = trypath; if (is_stream_wrapper) { wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE); 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)) { return zend_string_init(trypath, strlen(trypath), 0); } } continue; } } if (tsrm_realpath(actual_path, resolved_path)) { return zend_string_init(resolved_path, strlen(resolved_path), 0); } } /* end provided path */ /* check in calling scripts' current working directory as a fall back case */ if (zend_is_executing() && (exec_filename = zend_get_executed_filename_ex()) != NULL) { const char *exec_fname = ZSTR_VAL(exec_filename); size_t exec_fname_length = ZSTR_LEN(exec_filename); while ((--exec_fname_length < SIZE_MAX) && !IS_SLASH(exec_fname[exec_fname_length])); if (exec_fname_length > 0 && filename_length < (MAXPATHLEN - 2) && 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); 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); 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)) { return zend_string_init(trypath, strlen(trypath), 0); } } return NULL; } } if (tsrm_realpath(actual_path, resolved_path)) { return zend_string_init(resolved_path, strlen(resolved_path), 0); } } } return NULL; }