{"id":30738586,"url":"https://github.com/hdaklue/larapath","last_synced_at":"2026-05-18T19:36:17.152Z","repository":{"id":311958448,"uuid":"1045772853","full_name":"hdaklue/LaraPath","owner":"hdaklue","description":"A secure, fluent path builder for PHP with sanitization strategies and Laravel integration","archived":false,"fork":false,"pushed_at":"2025-08-27T21:49:54.000Z","size":282,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-08-28T02:27:59.699Z","etag":null,"topics":["composer-package","laravel","path-builder","php","security"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hdaklue.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-27T17:32:30.000Z","updated_at":"2025-08-27T21:49:57.000Z","dependencies_parsed_at":"2025-08-28T02:31:11.312Z","dependency_job_id":"e0fcda4c-158c-437f-a518-66fecc15bf9b","html_url":"https://github.com/hdaklue/LaraPath","commit_stats":null,"previous_names":["hdaklue/larapath"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/hdaklue/LaraPath","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hdaklue%2FLaraPath","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hdaklue%2FLaraPath/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hdaklue%2FLaraPath/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hdaklue%2FLaraPath/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hdaklue","download_url":"https://codeload.github.com/hdaklue/LaraPath/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hdaklue%2FLaraPath/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273517485,"owners_count":25119783,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["composer-package","laravel","path-builder","php","security"],"created_at":"2025-09-03T22:02:04.628Z","updated_at":"2026-05-18T19:36:17.086Z","avatar_url":"https://github.com/hdaklue.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LaraPath\n\n[![Tests](https://github.com/hdaklue/LaraPath/workflows/Tests/badge.svg)](https://github.com/hdaklue/LaraPath/actions)\n[![Latest Stable Version](https://poser.pugx.org/hdaklue/larapath/v/stable)](https://packagist.org/packages/hdaklue/larapath)\n[![License](https://poser.pugx.org/hdaklue/larapath/license)](https://packagist.org/packages/hdaklue/larapath)\n\n![Lara Path](artwork.svg)\nA secure, fluent path builder for PHP with sanitization strategies and Laravel 11-12 integration.\n\n## Features\n\n- 🔒 **Security First**: Built-in protection against directory traversal attacks with comprehensive validation\n- 🎯 **Fluent API**: Clean, readable path building with method chaining\n- 🔧 **Sanitization Strategies**: Multiple strategies for different use cases (hash, slug, snake_case, timestamp)\n- 📁 **Extension Preservation**: Automatic file extension preservation during sanitization\n- 🚀 **Immutable Operations**: Thread-safe path building with no side effects\n- 🏗️ **Strategy Pattern**: Extensible sanitization system with automatic validation\n- 🎨 **Type Safety**: Full type hints and IDE autocompletion\n- 📦 **Laravel Integration**: Optional Laravel Storage facade integration\n- ⚡ **Error Handling**: Comprehensive exception handling with specific error types\n\n## Installation\n\n```bash\ncomposer require hdaklue/larapath\n```\n\n## Quick Start\n\n```php\nuse Hdaklue\\PathBuilder\\PathBuilder;\nuse Hdaklue\\PathBuilder\\Enums\\SanitizationStrategy;\n// Or use the facade in Laravel\nuse LaraPath;\n\n// Basic usage (static)\n$path = PathBuilder::base('uploads')\n    -\u003eadd('images')\n    -\u003eadd('avatar.jpg')\n    -\u003etoString(); // \"uploads/images/avatar.jpg\"\n\n// Laravel facade usage (auto-registered)\n$path = LaraPath::base('uploads')\n    -\u003eadd('images') \n    -\u003eadd('avatar.jpg')\n    -\u003etoString();\n\n// With sanitization strategies\n$path = PathBuilder::base('uploads')\n    -\u003eadd('user-123', SanitizationStrategy::HASHED)\n    -\u003eadd('My File.jpg', SanitizationStrategy::SLUG)\n    -\u003evalidate()\n    -\u003etoString(); // \"uploads/a665a45920422f9d417e4867efdc4fb8/my-file.jpg\"\n```\n\n## Real-World Use Cases\n\nFor detailed examples of how LaraPath solves critical problems in multi-tenant Laravel applications, see [Real World Problems](real-world-problems.md).\n\nThe guide covers 5 essential scenarios:\n- Multi-tenant storage organization with privacy protection\n- Database-friendly storage strategies across multiple disks  \n- File naming conflicts and data loss prevention\n- Cross-platform filename sanitization and migration\n- Team-wide consistency and standardization\n\nPerfect for understanding LaraPath's value in complex Laravel applications.\n\n## Usage Examples\n\n### Sanitization Strategies\n\nLaraPath automatically preserves file extensions during sanitization, ensuring your files maintain their proper types.\n\n```php\n// Hash sensitive data (preserves extensions)\n$path = PathBuilder::base('storage')\n    -\u003eaddFile('user@email.com', SanitizationStrategy::HASHED)\n    -\u003etoString(); // \"storage/d549c81aa88e6e76e1f4c141aaae4c6e.com\"\n\n// Create URL-friendly names (preserves extensions)\n$path = PathBuilder::base('uploads')\n    -\u003eaddFile('My Amazing File!.pdf', SanitizationStrategy::SLUG)\n    -\u003etoString(); // \"uploads/my-amazing-file.pdf\"\n\n// Convert to snake_case (preserves extensions)\n$path = PathBuilder::base('files')\n    -\u003eaddFile('CamelCase Name.docx', SanitizationStrategy::SNAKE)\n    -\u003etoString(); // \"files/camel_case_name.docx\"\n\n// Add timestamps for uniqueness (preserves extensions)\n$path = PathBuilder::base('temp')\n    -\u003eaddFile('session.log', SanitizationStrategy::TIMESTAMP)\n    -\u003etoString(); // \"temp/session_1640995200.log\"\n\n// Directory names (no extensions to preserve)\n$path = PathBuilder::base('uploads')\n    -\u003eadd('User Documents', SanitizationStrategy::SLUG)\n    -\u003etoString(); // \"uploads/user-documents\"\n```\n\n### File Extension Preservation\n\nAll sanitization strategies automatically detect and preserve file extensions:\n\n```php\n// Complex filename with special characters\n$path = PathBuilder::base('documents')\n    -\u003eaddFile('My Complex File Name!@#.pdf', SanitizationStrategy::SLUG)\n    -\u003etoString(); // \"documents/my-complex-file-name.pdf\"\n\n// Multiple dots in filename - preserves only the last extension\n$path = PathBuilder::base('archives')\n    -\u003eaddFile('backup.2023.tar.gz', SanitizationStrategy::SLUG)\n    -\u003etoString(); // \"archives/backup-2023-tar.gz\"\n\n// Files without extensions work normally\n$path = PathBuilder::base('configs')\n    -\u003eaddFile('README', SanitizationStrategy::SLUG)\n    -\u003etoString(); // \"configs/readme\"\n\n// Hidden files (starting with dot)\n$path = PathBuilder::base('configs')\n    -\u003eaddFile('.env.example', SanitizationStrategy::SLUG)\n    -\u003etoString(); // \"configs/env.example\"\n```\n\n### Path Operations\n\n```php\n$builder = PathBuilder::base('files/video.mp4');\n\n// Extract path components\n$extension = $builder-\u003egetExtension(); // \"mp4\"\n$filename = $builder-\u003egetFilename(); // \"video.mp4\"\n$filenameWithoutExt = $builder-\u003egetFilenameWithoutExtension(); // \"video\"\n$directory = $builder-\u003egetDirectoryPath(); // \"files\"\n\n// Modify paths\n$newPath = $builder-\u003ereplaceExtension('webm')-\u003etoString(); // \"files/video.webm\"\n```\n\n### Laravel Integration\n\nLaraPath is automatically registered in Laravel applications with facade support and container binding.\n\n```php\n// Using the facade (recommended for Laravel)\nuse LaraPath;\n\n$exists = LaraPath::base('uploads')\n    -\u003eadd('avatar.jpg')\n    -\u003eexists('public'); // Uses Storage::disk('public')-\u003eexists()\n\n// Using container binding\n$builder = app('larapath');\n$size = $builder-\u003ebase('files')\n    -\u003eadd('document.pdf')\n    -\u003esize(); // Uses Storage::size()\n\n// Using static methods (framework-agnostic)\nuse Hdaklue\\PathBuilder\\PathBuilder;\n\n$url = PathBuilder::base('images')\n    -\u003eadd('logo.png')\n    -\u003eurl('public'); // Uses Storage::disk('public')-\u003eurl()\n\n// Delete file\n$deleted = LaraPath::base('temp')\n    -\u003eadd('cache.tmp')\n    -\u003edelete(); // Uses Storage::delete()\n\n// Get file size in different formats\n$path = LaraPath::base('uploads')-\u003eadd('document.pdf');\n\n$size = $path-\u003esize(); // Raw bytes: 1048576\n$formatted = $path-\u003egetSizeFormatted(); // Human readable: \"1 MB\"\n$sizeInKB = $path-\u003egetSizeInKB(); // Binary KB: 1024.0\n$sizeInMB = $path-\u003egetSizeInMB(); // Binary MB: 1.0\n$sizeInKBDecimal = $path-\u003egetSizeInKBDecimal(); // Decimal KB: 1048.576\n```\n\n### Validation and Security\n\nLaraPath provides comprehensive security and validation features:\n\n```php\n// Automatic path validation\n$path = PathBuilder::base('uploads')\n    -\u003eadd('../../../etc/passwd') // Dangerous path\n    -\u003evalidate() // Throws UnsafePathException\n    -\u003etoString();\n\n// Manual safety check\n$isSafe = PathBuilder::isSafe('uploads/../dangerous/path'); // false\n$isSafe = PathBuilder::isSafe('uploads/safe/file.txt'); // true\n\n// File existence validation\n$path = PathBuilder::base('uploads')\n    -\u003eaddFile('document.pdf')\n    -\u003emustExist('public') // Throws PathNotFoundException if file doesn't exist\n    -\u003etoString();\n\n$path = PathBuilder::base('uploads')\n    -\u003eaddFile('new-file.pdf')\n    -\u003emustNotExist('public') // Throws PathAlreadyExistsException if file exists\n    -\u003etoString();\n```\n\n### Error Handling\n\nLaraPath throws specific exceptions for different error conditions:\n\n```php\nuse Hdaklue\\PathBuilder\\Exceptions\\UnsafePathException;\nuse Hdaklue\\PathBuilder\\Exceptions\\PathNotFoundException;\nuse Hdaklue\\PathBuilder\\Exceptions\\PathAlreadyExistsException;\nuse Hdaklue\\PathBuilder\\Exceptions\\InvalidSanitizationStrategyException;\n\ntry {\n    $path = PathBuilder::base('../dangerous')\n        -\u003eaddFile('file.txt')\n        -\u003evalidate();\n} catch (UnsafePathException $e) {\n    // Handle directory traversal attempt\n    echo \"Unsafe path detected: \" . $e-\u003egetMessage();\n}\n\ntry {\n    $path = PathBuilder::base('uploads')\n        -\u003eaddFile('missing.txt')\n        -\u003emustExist('local');\n} catch (PathNotFoundException $e) {\n    // Handle missing file\n    echo \"File not found: \" . $e-\u003egetMessage();\n}\n\ntry {\n    $path = PathBuilder::base('uploads')\n        -\u003eadd('input', 'InvalidStrategy');\n} catch (InvalidSanitizationStrategyException $e) {\n    // Handle invalid sanitization strategy\n    echo \"Invalid strategy: \" . $e-\u003egetMessage();\n}\n```\n\n### Custom Strategies\n\nCreate custom sanitization strategies by implementing the `SanitizationStrategyContract`:\n\n```php\nuse Hdaklue\\PathBuilder\\Contracts\\SanitizationStrategyContract;\n\nclass UuidStrategy implements SanitizationStrategyContract\n{\n    public static function apply(string $input): string\n    {\n        return \\Str::uuid()-\u003etoString();\n    }\n}\n\n// Use custom strategy\n$path = PathBuilder::base('files')\n    -\u003eadd('temp-file', UuidStrategy::class)\n    -\u003etoString(); // \"files/550e8400-e29b-41d4-a716-446655440000\"\n```\n\n### Strategy Validation\n\nLaraPath automatically validates that custom strategies implement the required contract:\n\n```php\n// ✅ Valid strategy - implements SanitizationStrategyContract\n$path = PathBuilder::base('files')\n    -\u003eadd('input', MyCustomStrategy::class)\n    -\u003etoString();\n\n// ❌ Invalid strategy - throws InvalidSanitizationStrategyException\n$path = PathBuilder::base('files')\n    -\u003eadd('input', 'NonExistentStrategy')\n    -\u003etoString(); // Exception: Strategy class NonExistentStrategy not found\n\n// ❌ Invalid strategy - missing contract implementation\n$path = PathBuilder::base('files')\n    -\u003eadd('input', \\stdClass::class)\n    -\u003etoString(); // Exception: Strategy class stdClass must implement SanitizationStrategyContract interface\n```\n\n## API Reference\n\n### PathBuilder Methods\n\n- `PathBuilder::base(string $path, ?SanitizationStrategy $strategy = null): self`\n- `add(string $name, ?SanitizationStrategy $strategy = null): self`\n- `addFile(string $filename, ?SanitizationStrategy $strategy = null): self`\n- `addTimestampedDir(): self`\n- `addHashedDir(string $input, string $algorithm = 'md5'): self`\n- `replaceExtension(string $newExt): self`\n- `getExtension(): string`\n- `getFilename(): string`\n- `getFilenameWithoutExtension(): string`\n- `getDirectoryPath(): string`\n- `ensureTrailing(): self`\n- `removeTrailing(): self`\n- `validate(): self`\n- `toString(): string`\n\n### Laravel Integration Methods\n\n- `mustExist(string $disk = 'local'): self`\n- `mustNotExist(string $disk = 'local'): self`\n- `exists(string $disk = 'local'): bool`\n- `size(string $disk = 'local'): int`\n- `getSizeFormatted(string $disk = 'local', int $precision = 3): string`\n- `getSizeInKB(string $disk = 'local'): float`\n- `getSizeInMB(string $disk = 'local'): float`\n- `getSizeInGB(string $disk = 'local'): float`\n- `getSizeInKBDecimal(string $disk = 'local'): float`\n- `getSizeInMBDecimal(string $disk = 'local'): float`\n- `getSizeInGBDecimal(string $disk = 'local'): float`\n- `url(string $disk = 'local'): string`\n- `delete(string $disk = 'local'): bool`\n\n### Static Utility Methods\n\n- `PathBuilder::build(array $segments): string`\n- `PathBuilder::join(string ...$segments): string`\n- `PathBuilder::normalize(string $path): string`\n- `PathBuilder::isSafe(string $path): bool`\n- `PathBuilder::buildRelativePath(string $absolutePath, string $basePath): string`\n\n## Available Strategies\n\nAll strategies automatically preserve file extensions when present:\n\n- `SanitizationStrategy::HASHED` - MD5 hash of input (preserves extensions: `user.txt` → `hash.txt`)\n- `SanitizationStrategy::SLUG` - URL-friendly slug (preserves extensions: `My File!.pdf` → `my-file.pdf`)\n- `SanitizationStrategy::SNAKE` - snake_case conversion (preserves extensions: `CamelCase.docx` → `camel_case.docx`)\n- `SanitizationStrategy::TIMESTAMP` - Appends Unix timestamp (preserves extensions: `file.log` → `file_1640995200.log`)\n\n## Requirements\n\n- PHP ^8.2\n- illuminate/support ^11.0|^12.0 (for Laravel integration)\n\n## Testing\n\n```bash\ncomposer test\n```\n\n## License\n\nMIT License. See [LICENSE](LICENSE) for details.\n\n## Contributing\n\nPlease see [CONTRIBUTING.md](CONTRIBUTING.md) for details.\n\n## Security\n\nIf you discover any security related issues, please email hassan@daklue.com instead of using the issue tracker.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhdaklue%2Flarapath","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhdaklue%2Flarapath","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhdaklue%2Flarapath/lists"}