Secure Uploads - v1.0.0
Validation Pipeline
FileValidationService (bound to FileValidatorInterface) runs every uploaded file through MIME sniffing, extension checks, size limits, and trick detection before any storage or scanning happens.
Via validation rule (recommended)
The simplest way — drop the shipped rules into a Form Request:
use ArtisanPackUI\SecureUploads\Rules\SafeFilename;
use ArtisanPackUI\SecureUploads\Rules\SecureFile;
public function rules(): array
{
return [
'attachment' => ['required', 'file', new SecureFile, new SafeFilename],
];
}
SecureFile— runs the full validation pipeline (MIME, extension, size, tricks).SafeFilename— checks just the filename for path traversal, null bytes, double extensions, and other shenanigans. Use independently when you accept raw filename strings (e.g. from API metadata) rather thanUploadedFileinstances.
Via the service directly
use ArtisanPackUI\SecureUploads\Contracts\FileValidatorInterface;
use ArtisanPackUI\SecureUploads\FileUpload\ValidationResult;
$validator = app(FileValidatorInterface::class);
$result = $validator->validate($request->file('attachment'));
if (! $result->isValid()) {
return back()->withErrors(['attachment' => $result->getErrors()]);
}
ValidationResult has isValid(), getErrors(), and a few accessors for the resolved MIME type and sanitized filename.
What the pipeline checks
In order:
- File present and non-empty.
- Size against
maxFileSizeandmaxFileSizePerType. Per-type wins when smaller. - MIME against allow / blocklists. When
validateMimeByContentis on,FileValidationService::detectMimeType()callsfinfoagainst the actual file bytes — the supplied / claimed MIME type is ignored. - Extension against allow / blocklists.
- Double-extension trick (when enabled) —
file.php.jpgstyle. - Null-byte trick (when enabled) —
file.php\x00.jpgstyle. - Filename sanitization — strips path separators, collapses whitespace, normalizes Unicode, truncates to a reasonable length.
- EXIF stripping for JPEG / TIFF / PNG (when enabled).
Each failed check appends to ValidationResult::getErrors(). The pipeline runs every check rather than short-circuiting so the user sees all problems at once.
Per-call overrides
validate() accepts an $options array to override config for a single call:
$validator->validate($request->file('attachment'), [
'maxFileSize' => 50 * 1024 * 1024,
'allowedMimeTypes' => ['application/pdf'],
]);
Useful for endpoints with stricter or looser policies than the application default.
Media library defaults
The shipped withMediaLibraryDefaults() preset configures the validator for typical CMS media library use (broad image + document support, EXIF stripped, double-extension and null-byte checks on):
$validator = app(FileValidatorInterface::class)->withMediaLibraryDefaults();
Useful when wiring the validator into a media library upload endpoint that has different policy from the rest of your app.
Customizing
See Custom validators for extending the validation pipeline with your own checks.