I'm using Laravel 5.6 to let users upload their profile photo. On production, I've got some cases that returned error
Unable to init from given binary data.
Got like 5 errors from the last 2,000 users uploads (0.25%). Pretty low, but these users are important users that I want to keep.
I use Dropzone as a frontend, and send only image data to Controller via Ajax Post.
Here is the Controller:
public function savePhotos(Request $request) {
if(!$_FILES["file"]["error"]){
$file = $request->file('file');
$ext = $file->getClientOriginalExtension();
$filename = Auth::user()->id . '.' . $ext;
$filePathAndName = 'uploaded/'.$filename;
Storage::disk('original_images')->put($filePathAndName, file_get_contents($file -> getRealPath()));
//generate thumbnail
try{
$img = Image::make(Storage::disk('original_images')->get($filePathAndName));
$img->orientate()->fit(200, 240);
$newImg=Image::canvas(200, 240, '#ffffff')->encode('jpg',75); //create a blank image 200x240 px with white background
$newImg->insert($img, 'center'); //paste resized img to new blank image
Storage::disk('thumb_images')->put($filePathAndName, (string) $newImg->encode());
} catch (ErrorException $e) {}
}
}
The error happened at line with Image::make()
, even it's in the try catch block. I've checked all uploaded files and there are 2 cases of error here.
Some entry level Android phones upload 0 bytes image.
iPhones (iOS13/Safari) upload images that I can download them from server, and view on my Windows machine. But Laravel somehow couldn't process them, and return said error.
For those images uploaded from iPhone, I can't share them since it's the facial of the uploaders. Can't break privacy law. Instead, I could share exifs. Both are .JPEG.
Upload from iPhone #1:
Camera: Apple iPhone 8
Lens: iPhone 8 back camera 3.99mm f/1.8 Shot at 4 mm
Exposure: Auto exposure, Program AE, 1/5 sec, f/1.8, ISO 100
Flash: Off, Did not fire
File: 1,181 × 1,475 JPEG (1.7 megapixels) 504,666 bytes (493 kilobytes)
Color Encoding: WARNING: Embedded color profile: “(unrecognized embedded color profile 'Display P3')”
JFIF Version 1.01
Resolution 72 pixels/None
File Type JPEG
File Type Extension jpg
MIME Type image/jpeg
Exif Byte Order Big-endian (Motorola, MM)
Encoding Process Baseline DCT, Huffman coding
Bits Per Sample 8
Color Components 3
File Size 493 kB
Image Size 1,181 × 1,475
Y Cb Cr Sub Sampling YCbCr4:2:0 (2 2)
Upload from iPhone #2, surprisingly the image was taken by Canon 5D:
Camera: Canon EOS 5D Mark II
Lens: 85 mm
Exposure: Manual, 1/125 sec, f/9, ISO 100
Flash: none
File: 1,800 × 2,400 JPEG (4.3 megapixels) 589,171 bytes (575 kilobytes)
Color Encoding: WARNING: Embedded color profile: “(unrecognized embedded color profile 'Display P3')”
XMP Toolkit Adobe XMP Core 5.6-c140 79.160451, 2017/05/06-01:08:21
Creator Tool Adobe Photoshop CS6 (Windows)
Photographic Sensitivity 100
Exif Image Size 1,800 × 2,400
Make Canon
Camera Model Name Canon EOS 5D Mark II
Software Adobe Photoshop CS6 (Windows)
Exposure Time 1/125
F Number 9.00
Exposure Program Manual
ISO 100
Shutter Speed Value 1/125
Aperture Value 9.00
Exposure Compensation 0
Metering Mode Multi-segment
Flash No Flash
Focal Length 85.0 mm
JFIF Version 1.01
Resolution 72 pixels/None
File Type JPEG
File Type Extension jpg
MIME Type image/jpeg
Exif Byte Order Big-endian (Motorola, MM)
Encoding Process Baseline DCT, Huffman coding
Bits Per Sample 8
Color Components 3
File Size 575 kB
Image Size 1,800 × 2,400
Y Cb Cr Sub Sampling YCbCr4:2:0 (2 2)
PHP.ini
upload_max_filesize = 10M
Could be a problem of concurrent uploads, because you use the same file name for all the files. If user uploads two images at the same time one gets corrupted, it can not be opened by the other request. I suggest you to do cropping before uploading it to Storage::disk('original_images')
.
Concurrent upload can happen easily just by double clicking a form submit button, so this is a common error.