webmozart/path-util
Lightweight PHP utility for safe, cross-platform path handling. Normalize, join, resolve and compare filesystem paths, with helpers for absolute/relative paths and canonicalization. Useful for file operations and libraries needing consistent path logic.
Installation
composer require webmozart/path-util
Add to composer.json if not using autoloading:
"autoload": {
"psr-4": {
"App\\": "app/",
"Webmozart\\PathUtil\\": "vendor/webmozart/path-util/src/"
}
}
Run composer dump-autoload.
First Use Case Normalize a path in a Laravel controller or service:
use Webmozart\PathUtil\PathUtil;
$path = PathUtil::normalize('/var//www//example.com/../');
// Returns: '/var/www/example.com'
Key Classes to Know
PathUtil: Core utility for path manipulation.PathUtil::normalize(): Resolves ., .., and duplicate slashes.PathUtil::canonicalize(): Resolves symlinks (if supported by the OS).PathUtil::isAbsolute(): Checks if a path is absolute.PathUtil::join(): Safely joins paths (avoids DIRECTORY_SEPARATOR issues).use Webmozart\PathUtil\PathUtil;
use Illuminate\Http\Request;
public function handleUpload(Request $request) {
$filePath = $request->file('file')->getRealPath();
$normalizedPath = PathUtil::normalize($filePath);
// Store or process $normalizedPath
}
Ensure paths work on Linux/Windows in Laravel config:
use Webmozart\PathUtil\PathUtil;
$configPath = PathUtil::join(
storage_path('config'),
'custom_' . PathUtil::normalize('some/../path')
);
use Webmozart\PathUtil\PathUtil;
public function validatePath($path) {
$normalized = PathUtil::normalize($path);
return PathUtil::isAbsolute($normalized) &&
str_starts_with($normalized, storage_path());
}
Build paths dynamically in Laravel views or Blade:
@php
$dynamicPath = PathUtil::join(
public_path('uploads'),
PathUtil::normalize('user_' . auth()->id() . '/file.txt')
);
@endphp
Resolve symlinks in Laravel's filesystem (e.g., for shared storage):
use Webmozart\PathUtil\PathUtil;
$realPath = PathUtil::canonicalize('/path/with/symlinks');
if (!str_starts_with($realPath, storage_path())) {
abort(403, 'Path outside allowed directory');
}
Laravel Service Provider
Bind PathUtil as a singleton for dependency injection:
public function register() {
$this->app->singleton('pathUtil', function () {
return new \Webmozart\PathUtil\PathUtil();
});
}
Custom Helper
Add to app/Helpers/path.php:
if (!function_exists('normalize_path')) {
function normalize_path($path) {
return \Webmozart\PathUtil\PathUtil::normalize($path);
}
}
Filesystem Events
Use in filesystem events (e.g., creating, deleting) to sanitize paths:
use Webmozart\PathUtil\PathUtil;
Storage::extend('custom', function ($app) {
return new CustomFilesystem(
$app['files'],
PathUtil::normalize(storage_path('custom'))
);
});
Testing Path Logic
Mock PathUtil in PHPUnit:
$this->partialMock(PathUtil::class, ['normalize'])
->shouldReceive('normalize')
->with('/test/../path')
->andReturn('/test/path');
Symlink Resolution Limitations
canonicalize() may fail on Windows or restricted systems.normalize() for most cases; handle symlinks manually if needed.Case Sensitivity
if (PathUtil::normalize('/Path/To/File') === PathUtil::normalize('/path/to/file')) {
// Compare logic
}
Trailing Slashes
normalize() removes trailing slashes, but join() adds them.rtrim() if you need to preserve trailing slashes:
$path = rtrim(PathUtil::normalize('/path/'), '/');
Windows-Specific Issues
\) may cause issues in URLs or logs.$safePath = str_replace('\\', '/', PathUtil::normalize($path));
Performance
canonicalize() in loops (it’s slower due to symlink resolution).Log Normalized Paths
\Log::debug('Normalized path:', ['path' => PathUtil::normalize($rawPath)]);
Compare Paths Visually
dd([
'Original' => $rawPath,
'Normalized' => PathUtil::normalize($rawPath),
'Canonical' => PathUtil::canonicalize($rawPath),
]);
Check for Hidden Characters
Use trim() or preg_replace() to clean paths before normalization:
$cleanPath = trim($path, "\0..\x1F");
$normalized = PathUtil::normalize($cleanPath);
Custom Path Validator
Extend PathUtil for Laravel validation rules:
use Webmozart\PathUtil\PathUtil;
Validator::extend('valid_path', function ($attribute, $value, $parameters) {
$normalized = PathUtil::normalize($value);
return PathUtil::isAbsolute($normalized) &&
str_starts_with($normalized, $parameters[0] ?? storage_path());
});
Path Utility Trait Create a reusable trait for models or services:
trait PathUtilTrait {
protected function normalizePath($path) {
return PathUtil::normalize($path);
}
protected function isStoragePath($path) {
return str_starts_with(
PathUtil::normalize($path),
storage_path()
);
}
}
Override PathUtil Methods For testing or custom logic, extend the class:
class CustomPathUtil extends \Webmozart\PathUtil\PathUtil {
public function normalize($path) {
$normalized = parent::normalize($path);
return str_replace('\\', '/', $normalized);
}
}
Integration with Laravel Filesystem Create a custom filesystem adapter:
use Webmozart\PathUtil\PathUtil;
use Illuminate\Filesystem\Filesystem;
class SanitizedFilesystem extends Filesystem {
public function __construct() {
parent::__construct();
$this->basePath = PathUtil::normalize(storage_path());
}
}
DIRECTORY_SEPARATOR Handling
DIRECTORY_SEPARATOR internally, so paths work cross-platform./ or \ in your code.Relative Paths
normalize() converts relative paths to absolute if combined with getcwd().join() for relative paths:
$relative = PathUtil::join('subdir', 'file.txt');
$absolute = PathUtil::join(__DIR__, $relative);
URL vs. Filesystem Paths
urlencode() or Str::slug() for URLs:
$urlSafe = urlencode(PathUtil::normalize('/path with spaces/file.txt'));
How can I help you explore Laravel packages today?