mirror of
https://github.com/michalcz10/USB-RAID-Array.git
synced 2026-11-11 07:59:04 +00:00
47 lines
1.7 KiB
PHP
47 lines
1.7 KiB
PHP
<?php
|
|
/** SFTP paths use POSIX separators, regardless of the OS running PHP. */
|
|
function normalizePath(string $path): string {
|
|
$parts = array_filter(explode('/', $path), fn($part) => $part !== '' && $part !== '.');
|
|
$stack = [];
|
|
foreach ($parts as $part) {
|
|
if ($part === '..') {
|
|
array_pop($stack);
|
|
} else {
|
|
$stack[] = $part;
|
|
}
|
|
}
|
|
return '/' . implode('/', $stack);
|
|
}
|
|
|
|
/** Like dirname(), but only '/' is a separator and the root stays '/'. */
|
|
function remoteDirname(string $path): string {
|
|
$path = rtrim($path, '/');
|
|
if ($path === '') return '/';
|
|
$separator = strrpos($path, '/');
|
|
if ($separator === false) return '.';
|
|
$parent = rtrim(substr($path, 0, $separator), '/');
|
|
return $parent === '' ? '/' : $parent;
|
|
}
|
|
|
|
/** Compare directory boundaries, so /data-other is not considered part of /data. */
|
|
function isRemotePathWithin(string $path, string $basePath): bool {
|
|
$path = normalizePath($path);
|
|
$basePath = normalizePath($basePath);
|
|
return $path === $basePath || strpos($path, rtrim($basePath, '/') . '/') === 0;
|
|
}
|
|
|
|
/** Validate a single POSIX filename before joining it to a directory. */
|
|
function isRemoteNameValid(string $name): bool {
|
|
return $name !== '' && $name !== '.' && $name !== '..'
|
|
&& strpos($name, '/') === false && strpos($name, "\0") === false;
|
|
}
|
|
|
|
/** Resolve a request path inside the user's configured workspace. */
|
|
function requireRemotePath(string $path, string $basePath): string {
|
|
if (strpos($path, "\0") !== false || !isRemotePathWithin($path, $basePath)) {
|
|
http_response_code(403);
|
|
exit('Path is outside your workspace.');
|
|
}
|
|
return normalizePath($path);
|
|
}
|