32 lines
1.0 KiB
PHP
32 lines
1.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace MeshVault\Catalog;
|
|
|
|
use InvalidArgumentException;
|
|
|
|
/** Lexical identity only; filesystem authorization remains PathSafety's responsibility. */
|
|
final class ManagedPath
|
|
{
|
|
public static function validate(string $path): string
|
|
{
|
|
if (
|
|
$path === '' || str_starts_with($path, '/') || str_contains($path, '\\')
|
|
|| str_contains($path, "\0") || preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*:/', $path)
|
|
) {
|
|
throw new InvalidArgumentException('Managed path must be a canonical relative path.');
|
|
}
|
|
foreach (explode('/', $path) as $segment) {
|
|
if (
|
|
$segment === '' || $segment === '.' || $segment === '..'
|
|
|| (PHP_OS_FAMILY === 'Windows'
|
|
&& (str_contains($segment, ':') || rtrim($segment, '. ') !== $segment))
|
|
) {
|
|
throw new InvalidArgumentException('Managed path contains a noncanonical segment.');
|
|
}
|
|
}
|
|
return $path;
|
|
}
|
|
}
|