Last updated: August 29, 2026.
Phone cameras may store pixels in one direction and the intended display orientation in EXIF. Normalize the pixels once so every later derivative is correct.
Normalize common orientations
<?php
$image = imagecreatefromjpeg(__DIR__ . '/upload.jpg');
if ($image === false) throw new RuntimeException('Invalid JPEG.');
$exif = function_exists('exif_read_data') ? @exif_read_data(__DIR__ . '/upload.jpg') : false;
$orientation = (int) ($exif['Orientation'] ?? 1);
$degrees = [3 => 180, 6 => -90, 8 => 90][$orientation] ?? 0;
if ($degrees !== 0) { $rotated = imagerotate($image, $degrees, 0); imagedestroy($image); $image = $rotated; }
imagejpeg($image, __DIR__ . '/normalized.jpg', 88);
imagedestroy($image);Handle the full input set
- Add mirrored orientations 2, 4, 5, and 7 if required.
- Save a normalized derivative for later processing.
- Retain the original when metadata is important.
- Test portrait and landscape phone photos.
Normalize before generating derivatives
Read the orientation from the original JPEG, transform the pixels, and then create thumbnails or alternate formats from the normalized image. Saving a derivative avoids requiring every display path to understand EXIF.
Test all orientations produced by the devices your users actually upload, including mirrored front-camera images. Confirm width and height after rotation and decide whether other metadata should be retained or removed.
- Handle mirrored orientations when needed.
- Keep the original for recovery.
- Apply upload size limits before decoding.
Keep resource limits explicit and make failure cleanup part of the example. Log enough context to diagnose the operation without recording passwords, private message bodies, or uploaded file contents.
Continue with WebP thumbnails, AVIF conversion, and image preview.
Practical implementation check
Put the operation in a small function or service with explicit inputs and a clear failure result. Test invalid input, missing extensions, permission failures, and concurrent requests. Production logs should identify the operation and record ID without storing secrets or private content. Clean up partially created files or queue records when any later step fails.
Reference: PHP exif_read_data reference.