php 55 lines · 8 steps

Validating file uploads safely in PHP

A layered set of checks that rejects malformed, oversized, or spoofed uploads before trusting a file.

Explained by highlit
1<?php
2 
3class ImageUploadService
4{
5 private const MAX_BYTES = 5 * 1024 * 1024;
6 
7 private const ALLOWED = [
8 'image/jpeg' => 'jpg',
9 'image/png' => 'png',
10 'image/webp' => 'webp',
11 ];
12 
13 public function __construct(private string $storageDir) {}
14 
15 public function store(array $file): string
16 {
17 if (!isset($file['error']) || is_array($file['error'])) {
18 throw new InvalidArgumentException('Malformed upload payload.');
19 }
20 
21 if ($file['error'] !== UPLOAD_ERR_OK) {
22 throw new RuntimeException('Upload failed with code ' . $file['error']);
23 }
24 
25 if ($file['size'] > self::MAX_BYTES) {
26 throw new RuntimeException('File exceeds the 5MB limit.');
27 }
28 
29 if (!is_uploaded_file($file['tmp_name'])) {
30 throw new RuntimeException('Suspicious upload, not an HTTP upload.');
31 }
32 
33 $finfo = new finfo(FILEINFO_MIME_TYPE);
34 $mime = $finfo->file($file['tmp_name']);
35 
36 if (!isset(self::ALLOWED[$mime])) {
37 throw new RuntimeException('Unsupported image type: ' . $mime);
38 }
39 
40 if (@getimagesize($file['tmp_name']) === false) {
41 throw new RuntimeException('File is not a valid image.');
42 }
43 
44 $name = bin2hex(random_bytes(16)) . '.' . self::ALLOWED[$mime];
45 $target = rtrim($this->storageDir, '/') . '/' . $name;
46 
47 if (!move_uploaded_file($file['tmp_name'], $target)) {
48 throw new RuntimeException('Could not persist the uploaded file.');
49 }
50 
51 chmod($target, 0644);
52 
53 return $name;
54 }
55}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Never trust the client-supplied MIME type; detect content type from the file's actual bytes.
  2. 2Layer cheap structural checks before expensive ones so bad input fails fast.
  3. 3Generate random server-side filenames to avoid path traversal and collisions from user input.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Validating file uploads safely in PHP — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code