This package was developed using ServBay as the local development environment.
- Local development tool:
ServBay - Website: www.servbay.com
- Tested on:
Mac M4 - Built on:
Mac M4
This guide covers package-level configuration, validation, and security-sensitive upload behavior.
Because this package is published on Packagist, its composer.json does not declare a fixed version. When using a local path repository with a stable constraint such as ^1.0, add a Composer path version override in the consuming app:
{
"repositories": [
{
"type": "path",
"url": "/Users/ghostcompiler/Desktop/GhostCompiler/laravel-upload",
"options": {
"versions": {
"ghostcompiler/laravel-uploads": "1.0.2"
}
}
}
],
"require": {
"ghostcompiler/laravel-uploads": "^1.0"
}
}When using a local path repository, run this in the consuming app:
composer update ghostcompiler/laravel-uploads
php artisan optimize:clear- Add a Composer path repository in the Laravel app.
- Require
ghostcompiler/laravel-uploads. - Run:
composer update ghostcompiler/laravel-uploads
php artisan package:discover
php artisan install:laravel-uploads
php artisan migrateWhen you make changes in this package repo and want your Laravel app to use them:
composer update ghostcompiler/laravel-uploads
php artisan package:discoverIf you changed helper autoloading or package metadata, this is also useful:
composer dump-autoloadIf you changed the published config or migration stubs:
php artisan install:laravel-uploadsOverwrite existing published files without prompts:
php artisan install:laravel-uploads --forceInside the package repo:
git pullMake your changes, then:
git add .
git commit -m "Update Laravel Uploads"
git pushInside the Laravel app using the local path repository:
composer update ghostcompiler/laravel-uploads
php artisan package:discoverThis package includes a PHPUnit + Testbench scaffold.
Inside the package repo:
composer installcomposer test- cached URL reuse until expiry
- cache invalidation when uploads are deleted
- cache-disabled fallback behavior
- resize dimension calculation
- aspect-ratio preservation
- no upscaling behavior
- expired link cleanup command
- dry-run cleanup reporting
Use a real Laravel test project and verify:
- upload works with
Uploads::upload(...) - upload works with
GhostCompiler()->upload(...) - custom folder uploads work
- excluded file validation blocks dangerous extensions
- explicit excluded-extension upload override works only when requested
- model serialization returns URL fields correctly
- cached URL reuse prevents repeated link generation on refresh
- preview URL opens supported file types
- SVG files download instead of opening inline by default
?download=1forces download- AVIF conversion works when supported
- WEBP fallback works when AVIF is unavailable
- resize limits preserve the original aspect ratio
- oversized image dimensions are rejected before optimization
- cleanup command removes only expired links
Uploads::upload($file)stores files in the configuredbase_pathUploads::upload('demo/image', $file)stores files insidebase_path/demo/imageGhostCompiler()->upload($file)uses the same Laravel Uploads service directly- upload paths must stay relative and cannot contain traversal segments
- generated URLs are tracked in the database
- generated URLs are cached by upload ID and expiry when
cache.enabledistrue - generated URL cache registries expire automatically and are used only to clear cached URLs when an upload is deleted
- image optimization only applies to supported images
- AVIF is tried first
- WEBP is used as the main fallback format
- resizing keeps the original aspect ratio
- GD is used first and
Imagickis used as a fallback encoder when available
Package validation is controlled by config/laravel-uploads.php.
'validation' => [
'max_size' => 10 * 1024 * 1024,
'allowed_mime_types' => [],
'allowed_extensions' => [],
'excluded_mime_types' => [
'application/x-httpd-php',
'application/x-php',
'text/x-php',
],
'excluded_extensions' => [
'cgi',
'phar',
'php',
'php3',
'php4',
'php5',
'phtml',
'pl',
'py',
'rb',
'sh',
],
'never_allowed_extensions' => [
'phar',
'php',
'php3',
'php4',
'php5',
'phtml',
],
],Empty allowed_mime_types and allowed_extensions lists mean all non-excluded files are accepted.
Excluded files stay blocked by default. If your application has already performed its own authorization and validation, you can allow one or more excluded extensions for one upload call.
use GhostCompiler\LaravelUploads\Facades\Uploads;
$upload = Uploads::upload($request->file('script'), 'sh');Allow multiple excluded extensions for one upload call:
$upload = Uploads::upload($request->file('script'), ['sh', 'rb']);The same extension-specific override works with custom paths:
$upload = Uploads::upload('trusted/path', $request->file('script'), 'sh');Only the specified extension is allowed. For example, passing 'sh' does not allow rb, phar, or any other excluded extension.
Critical extensions listed in validation.never_allowed_extensions, such as php, phar, and phtml, cannot be bypassed with per-upload overrides.
Use uploadMany() when handling a request field containing multiple uploaded files.
use GhostCompiler\LaravelUploads\Facades\Uploads;
$uploads = Uploads::uploadMany($request->file('documents'), 'documents');The third argument accepts the same extension override rules:
$uploads = Uploads::uploadMany($request->file('scripts'), 'trusted/scripts', ['sh', 'rb']);Image optimization can reject oversized source images before GD or Imagick processes them.
'image_optimization' => [
'enabled' => false,
'strict' => false,
'quality' => 75,
'convert_to_avif' => true,
'max_width' => null,
'max_height' => null,
'max_input_width' => 8000,
'max_input_height' => 8000,
'max_input_pixels' => 12000000,
'max_output_pixels' => 4000000,
],Set a max input dimension or pixel value to protect the PHP process from oversized image payloads.
Set strict to true when an image upload should fail instead of storing the original file after AVIF/WEBP conversion fails.
Upload paths must be relative disk paths. The package rejects:
- absolute paths
- Windows drive paths
..traversal segments- empty path segments
- control characters
This applies to upload paths, read paths, and delete paths.
SVG is not included in the default preview_mime_types list because inline SVG can execute script in the application origin. The package controller also blocks inline SVG preview even if image/svg+xml is added to the preview list, so SVG files download by default.
'preview_mime_types' => [
'image/avif',
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
'application/pdf',
'text/plain',
],The private file route defaults to no route middleware:
'route' => [
'middleware' => [],
],This avoids host app web, auth, Inertia, tenant dashboard, or MFA middleware redirecting image/file requests before the package controller can stream the file. Add middleware only when it is safe for direct file requests.
- Keep
validation.max_sizestrict for the application. - Use conservative image pixel limits when optimization is enabled.
- Enable
image_optimization.strictwhen storing original images after conversion failure is not acceptable. - Use Laravel throttling, queue worker limits, web server upload limits, or a WAF for high-volume upload endpoints.
- Schedule
php artisan ghost:laravel-uploads-cleanto remove expired private URL tokens. - Set
expose => falsefor upload fields that should not be returned in API responses. - Use
Uploads::resolvePublicUrlsUsing(...)orurls.public_resolverfor multi-tenant public upload URLs.