Use $request->file('field') for one and $request->files('field') for a multiple picker — the second always returns a list, whether one file arrived or forty.
The rules, all learned the hard way:
- Sniff the type from the file's own bytes. The filename and the Content-Type are both supplied by whoever is uploading.
- Re-encode images rather than storing what arrived. A file that parses as a JPEG can carry anything in the parts a decoder skips.
- Never accept SVG without a sanitiser. It is a document that can carry script, served from your own origin.
- Check pixel dimensions before decoding. A 30,000 × 30,000 PNG is a few hundred kilobytes and needs gigabytes to decode.
- Store under
content/, outside the document root, and serve through a controller.
🚨 Add your path to tools/deploy/nginx-paths-served-by-php.conf. Uploads served through PHP still have addresses ending in .png, and a typical nginx rule serves those from disk without reaching the application. It works perfectly locally and 404s in production.
Str::slug(), Html::toText() and the CoverStore / AvatarStore / ImageStore classes are worth reading before writing your own.