bitandblack/pathinfo
Tiny PHP utility offering a consistent, OO wrapper around path information. Parse file paths into dirname, basename, extension, filename, and more, with simple getters and helpers for working with filesystem paths across environments.
Installation
composer require bitandblack/pathinfo
No additional configuration is required for basic usage.
First Use Case: Parsing Paths Replace procedural path parsing with an object-oriented approach:
use BitAndBlack\PathInfo\PathInfo;
$path = '/uploads/2023/10/avatar.jpg';
$pathInfo = new PathInfo($path);
// Extract components
$filename = $pathInfo->getFilename(); // 'avatar.jpg'
$extension = $pathInfo->getExtension(); // 'jpg'
$dirname = $pathInfo->getDirname(); // '/uploads/2023/10'
Where to Look First
getPath(), getBasename(), getFilename(), getExtension(), getDirname(), and normalize()./file)./.hiddenfile)./dir/)./dir%20name/file).Service Layer Integration
Inject PathInfo into services handling file operations:
class FileUploadService {
public function __construct(private PathInfo $pathInfo) {}
public function processUpload($filePath) {
$normalized = $this->pathInfo->normalize($filePath);
// Use normalized path for storage
}
}
Laravel-specific: Use dependency injection via the container:
$this->app->bind(PathInfo::class, function () {
return new PathInfo();
});
Request Validation Validate file paths in Laravel request pipelines:
use Illuminate\Http\Request;
use BitAndBlack\PathInfo\PathInfo;
public function store(Request $request) {
$path = $request->input('file_path');
$pathInfo = new PathInfo($path);
if (!$pathInfo->hasExtension()) {
return back()->withError('Invalid file path');
}
// Proceed with logic
}
Artisan Commands Parse paths in CLI tools:
use Illuminate\Console\Command;
use BitAndBlack\PathInfo\PathInfo;
class CleanupCommand extends Command {
protected $signature = 'files:cleanup {path}';
public function handle() {
$pathInfo = new PathInfo($this->argument('path'));
$files = Storage::files($pathInfo->getPath());
// Process files
}
}
Path Normalization Ensure consistent path formats for storage/comparison:
$path1 = '/user//profile';
$path2 = '/user/profile/';
$normalized1 = (new PathInfo($path1))->normalize(); // '/user/profile'
$normalized2 = (new PathInfo($path2))->normalize(); // '/user/profile'
if ($normalized1 === $normalized2) {
// Paths are equivalent
}
Laravel Storage Integration
Combine with Laravel’s Storage facade for unified path handling:
$pathInfo = new PathInfo($request->file('avatar')->path());
$diskPath = $pathInfo->getDirname() . '/processed_' . $pathInfo->getFilename();
Storage::put($diskPath, $processedImage);
Domain-Specific Extensions
Extend PathInfo for custom rules (e.g., tenant-aware paths):
class TenantPathInfo extends PathInfo {
public function getTenantPath($tenantId) {
return $this->normalize("/tenants/{$tenantId}{$this->getPath()}");
}
}
Testing
Mock PathInfo in unit tests:
$mockPathInfo = Mockery::mock(PathInfo::class);
$mockPathInfo->shouldReceive('getFilename')->andReturn('test.jpg');
$this->app->instance(PathInfo::class, $mockPathInfo);
Namespace Collisions
PathInfo class may conflict with Laravel’s Path facade.use BitAndBlack\PathInfo\PathInfo as CustomPathInfo;
Windows Path Handling
C:\Users\file.txt).str_replace() or use DIRECTORY_SEPARATOR.URL-Encoded Paths
/dir%20name/file may not decode automatically.urldecode() before instantiating:
$pathInfo = new PathInfo(urldecode($encodedPath));
Empty Paths
$pathInfo = empty($path) ? new PathInfo('/') : new PathInfo($path);
Extension Detection
.env) or files without extensions may return unexpected results.if ($pathInfo->getExtension() === '' && !$pathInfo->isDotFile()) {
// Handle no-extension case
}
Log Path Components Inspect parsed paths during development:
$pathInfo = new PathInfo($path);
\Log::debug('Path components', [
'path' => $pathInfo->getPath(),
'dirname' => $pathInfo->getDirname(),
'filename' => $pathInfo->getFilename(),
'extension' => $pathInfo->getExtension(),
]);
Compare with Native Functions
Verify behavior against PHP’s pathinfo():
$native = pathinfo($path);
$custom = [
'dirname' => $pathInfo->getDirname(),
'basename' => $pathInfo->getBasename(),
'extension' => $pathInfo->getExtension(),
'filename' => $pathInfo->getFilename(),
];
No Built-in Config The package has no configuration file. All behavior is determined at runtime via method calls.
Immutable Design
The PathInfo object is immutable. To modify a path, create a new instance:
$newPath = (new PathInfo($originalPath))->setExtension('jpg');
Custom Path Rules Override methods to enforce business logic:
class SecurePathInfo extends PathInfo {
public function getFilename() {
$filename = parent::getFilename();
return preg_replace('/[^a-z0-9_\-]/i', '_', $filename);
}
}
Event Hooks Extend the class to trigger events (e.g., on path normalization):
class EventPathInfo extends PathInfo {
public function normalize() {
$path = parent::normalize();
event(new PathNormalized($path));
return $path;
}
}
Laravel Service Provider
Bind a custom PathInfo implementation in AppServiceProvider:
public function register() {
$this->app->bind(PathInfo::class, function () {
return new TenantPathInfo();
});
}
Avoid Redundant Instantiation
Reuse PathInfo objects where possible:
$pathInfo = new PathInfo($basePath);
foreach ($files as $file) {
$filePathInfo = new PathInfo($pathInfo->getPath() . '/' . $file);
// Process
}
Benchmark Complex Paths For deeply nested paths, test performance against native PHP functions:
$start = microtime(true);
$pathInfo = new PathInfo($deepPath);
$time = microtime(true) - $start;
How can I help you explore Laravel packages today?