diff --git a/src/Orbit/Module/Statics.php b/src/Orbit/Module/Statics.php index a5e8772..4307c74 100644 --- a/src/Orbit/Module/Statics.php +++ b/src/Orbit/Module/Statics.php @@ -28,8 +28,8 @@ class Statics extends Module $resource_path = rtrim($real_root_dir, "/") . $request->path; // Check if within the server root - // Realpath will translate any '..' in the path - $realpath = realpath($resource_path); + // getAbsolutePath will translate any '..' in the path + $realpath = self::getAbsolutePath($resource_path); if ($realpath && strpos($realpath, $real_root_dir) !== 0) { $response->setStatus(Response::STATUS_PERMANENT_FAILURE); $response->setMeta("Invalid location"); @@ -165,4 +165,33 @@ class Statics extends Module { return (bool)(fileperms($file) & self::WORLD_READABLE); } + + /** + * Get an absolute path for a filename + * + * Translates .. and . to the real locations. The reason I am not using + * realpath() to do it is it resolves symlinks + * + * @param string $path + * @return string + */ + public static function getAbsolutePath($path): string + { + $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); + $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); + $absolutes = []; + + foreach ($parts as $part) { + if ('.' == $part) { + continue; + } + if ('..' == $part) { + array_pop($absolutes); + } else { + $absolutes[] = $part; + } + } + + return "/" . implode(DIRECTORY_SEPARATOR, $absolutes); + } }