Using Image Intervention in Laravel to Resize Uploads

One of the requirements of my Laravel project is allowing users to upload a photo and post it. I didn’t want to set a low upload size because I know most of the users are going to be using their phone camera and those files can be very large. My solution was to allow large upload sizes but then resize the image before saving the file.

First we need to install Image Intervention in our project:


composer require intervention/image

In config/app.php we need to add this under providers:


'Intervention\Image\ImageServiceProvider',

and this under aliases:

 'Image' => 'Intervention\Image\Facades\Image', 

At the top of the Controller we need to declare it:

use Intervention\Image\ImageManagerStatic as Image;

Now that it’s all installed and ready to use we can look at the code for saving our image. This is how we would normally save an image:

if($request->file('uploadedFile')) {
       $image = $request->file('uploadedFile');
       $fileNameWithExt = $image->getClientOriginalName();
       $fileName = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
       $extension = $image->getClientOriginalExtension();
       $fileNameToStore = $fileName."_".time().'.'.$extension;
       $image->storeAs('public/uploaded_images', $fileNameToStore);
}

With Image Intervention it looks like this:

if($request->hasFile('post_image')) {
    $image = $request->file('post_image');
    $fileNameWithExt = $image->getClientOriginalName();
    $fileName = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
    $extension = $image->getClientOriginalExtension();
    $fileNameToStore = $fileName."_".time().'.'.$extension;
    $path = public_path('storage/uploaded_images/' . $fileNameToStore);
    Image::make($image->getRealPath())
        ->resize(800, 500, function ($constraint) {
            $constraint->aspectRatio();
            $constraint->upsize();
        })
        ->save($path);
    }

Note the path. I had to try a few different ways of specifying where it was going to be saved, this is what works for Laravel.

The resize() function documentation is here:
http://image.intervention.io/api/resize
I used a callback function for two constraints: aspectRatio(), which resizes the image but keeps the original aspect ratio, and upsize(), which prevents the image from being upsized to the given size if the original is smaller.

Now the uploaded images are resized so they aren’t taking up a ton of storage space, they fit perfectly in the space I need them to, and the ratio isn’t distorted. If the uploaded image is smaller than the available space then they will display at their original size.

Laravel on Vultr with Ubuntu/Nginx

Finally! Time to push my Laravel project to a live server. I knew this was going to be quite a process so I was pushing it off until I had time to dedicate to it.

Setting up Ubuntu, Nginx, Laravel on a Vultr Server

I am not going to write up an entire explanation because mostly I followed this very well written guide here:
https://devmarketer.io/learn/deploy-laravel-5-app-lemp-stack-ubuntu-nginx/

Updating to PHP 7.2

Unfortunately I realized I needed PHP 7.2 for my app and the server had 7.0. (In hindsight I probably should have chosen Ubuntu 18.) I found this guide for updating the PHP version:
https://ayesh.me/Ubuntu-PHP-7.2

sudo apt install php7.2 php7.2-common php7.2-cli php7.2-fpm

I had to update some additional PHP modules as well:

sudo apt install 7.2-zip php7.2-mbstring php7.2-mysql php7.2-gd

To update the Nginx config to point to the 7.2 socket you need to edit the default file and change one line:

sudo nano /etc/nginx/sites-available/default

/run/php/php7.2-fpm.sock

When it was all set I followed the instructions for removing the PHP 7.0 version but something went awry and deleted more than it should. I had to re-install some things but finally it was all running properly!

Domain Name Server

Pointing my domain name to my new server was easy with Vultr:
https://serverpilot.io/docs/how-to-configure-dns-on-vultr

File Permissions

And then here’s when the fun started. I ran into file permissions errors. At first glance on google there are obvious steps to take, which solved some – but not all – of my errors. It was really frustrating because it worked perfectly fine in local development but was failing on file upload in production.

Here’s what I learned.

First, make sure to set the storage link on the production server:

php artisan storage:link

Second, don’t ever set a folder permission to 777 like half of the google results say to. It should be set to 775:

sudo chmod -R 775 /var/www/laravel/storage

Unfortunately I still had one file upload section that wasn’t working – but the others were! After reading many ideas and trying various things what finally worked for me was changing the ownership of the folders to www-data, which is the user that fps uses:

sudo chown -R www-data:www-data /var/www/laravel/storage

After all of that I discovered that some of my code had a bug in it – of course – but was otherwise working! Next time I will write about using Image Intervention for saving the images.