Laravel - File Upload in Laravel
Laravel - File Upload in Laravel
Let’s start from the basics – how does Laravel deal with it by default? It’s pretty easy.
You can specify the folder where the file should be uploaded – see parameter ‘logos’.
As you can see, Laravel generated a random filename, but you can easily override it – use function storeAs():
$request->logo->storeAs('logos', '1.png');
Or, you can keep the original filename:
$request->logo->storeAs('logos', $request->logo->getClientOriginalName());
We saw that, by default, Laravel stores the file in /storage/app folder. Why?
It’s actually done with a good plan – to hide uploaded files from users by default, to avoid illegal access or scraping.
Also, you may ask how to show the file then, if /storage folder is not accessible in the browser? It’s not public, right?
If you do want those files to be public, you need to change two things:
1. Config disk change. Change config/filesystems.php parameter ‘default’ – from ‘local’ to ‘public’: then the files will be
stored in storage/app/public (we will talk about filesystems settings later);
2. Symlink. Put a symlink from /public/storage to /storage/app/public folder, with one Artisan command:
By default, the public disk uses the local driver and stores these files in storage/app/public. To make them accessible from
the web, you should create a symbolic link from public/storage to storage/app/public.
Now, we can access the file from our example:
Another way, of course, is to check access in your Laravel code and then return the file as downloaded stream.
if (!auth()->check()) {
return abort(404);
}
return response()->download(storage_path('app/public/logos/' . $filename));
In this example, actual users won’t even know the actual filename until download, so you’re in control over the access to that
file.
Finally, if you want to delete the file, you should use Storage facade for it:
use Illuminate\Support\Facades\Storage;
$filename = 'onvuqaJkKWx6ShRSserOR8p5HAE4RE3yJPCeAdrO.png';
Storage::delete('logos/' . $filename);
This is pretty much all the information we get from the official Laravel documentation about file upload. But in reality, it’s
only the beginning. Let’s dive deeper.
2. File validation
Laravel has quite a lot of validation rules, that can be stored in Request classes, some of them are related to files.
For example, if you want to check for successfully uploaded file you may check this.
image:
The file under validation must be an image (jpeg, png, bmp, gif, or svg)
mimes:jpeg,bmp,png,…:
The file under validation must have a MIME type corresponding to one of the listed extensions.
Even though you only need to specify the extensions, this rule actually validates against the MIME type of the file by reading
the file’s contents and guessing its MIME type.
A full listing of MIME types and their corresponding extensions may be found at the following
location: https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
mimetypes:text/plain,…:
The file under validation must match one of the given MIME types.
size:value
The field under validation must have a size matching the given value. For files, size corresponds to the file size in kilobytes.
dimensions:
The file under validation must be an image meeting the dimension constraints as specified by the rule’s parameters:
A ratio constraint should be represented as width divided by height. This can be specified either by a statement like 3/2 or a
float like 1.5:
Notice. Important note about size validation – don’t forget to check your php.ini settings. By default, you can upload files
only up to 2mb.
upload_max_filesize = 2M
Also, check maximum POST request size:
post_max_size = 8M
But be careful with putting bigger numbers here, it can be used in wrong ways by some people. To upload much bigger files,
you can use chunks, we will discuss it separately later.
3. Uploading to external disks: Amazon S3
So far, in this article we touched on the basic file upload to the same code repository – into the /storage folder. But quite
often it makes sense to store files separately, especially if they are bigger and could take up server disk space.
Now, there’s another term called disk – it represents the actual folder/bucket name within your chosen driver.
And yes, it means that one driver can have multiple disks – for example, you want to use one S3 bucket for images, and
another one for documents.
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
],
],
You can see a few things here:
Same driver called local has two different disks – local and public. Remember we changed between the two, in the
chapter above?
Parameter ‘default’ points to the disk that will be used as the primary one
Please put your parameters in .env files, to be able to have different settings for testing and live servers. We’ve
written about .env files here.
So, if you want to use S3 as primary driver, you need to install league/flysystem-aws-s3-v3 package and change
the .env file:
FILESYSTEM_DRIVER=s3
And then also you can specify the disk directly in the code of file upload.
$request->logo->store('logos', 's3');
If we do that and put in our AWS details, here’s how our file will be placed in S3 Console.
Now, by default our files will get public URLs, like this:
https://s3-eu-west-1.amazonaws.com/laraveldaily-videos-test/logos/OIIB2jilZkhn7wUI6Mol14pgiCtmtxdLUyoZmVKh.png
One of the most popular examples of S3 usage is popular project management system called Trello. If you attach a file to any
card there, it is stored in S3 and is encoded to really long public URL, like this – see browser URL bar:
So you can access the file if you know the name. Here’s the official comment from Trello’s help page:
The URLs for the attachments are cryptographically unguessable, meaning that no one is going to be able to guess your
attachment URL. However, if you share the URL for a Trello attachment, anyone with the URL will be able to see the
attachment.
If you need extra security, we recommend using Google Drive for attachments. You can attach files from Google
Drive directly to Trello and specify fine-grained access to the file via the Google Drive interface.
In other words, you can add additional layers to your file storage for security, Trello is just one example of this.
Ok, we’re done with disks/drivers and Amazon S3 example. Let’s move on to exciting topic of uploading larger files.
4. AJAX upload: Large/multiple files
We’ve touched briefly on larger file uploads, that it makes sense to store them outside the code, on something like Amazon
S3. But there’s another issue – uploading process, which leaves user waiting for quite a while. We need to handle it
gracefully.
If you just POST a big file via default form, browser will only show loading signs and you won’t get notified about any
progress until it’s done.
We can change that using AJAX upload and certain library – as an example, I will take BlueImp JQuery library.
Another tutorial I’ve written is this: Laravel AJAX File Upload with BlueImp JQuery Library
So I won’t repeat those tutorials here, please read them in full detail, but I will just re-cap the main things:
You use JavaScript library to upload files – catch event on click of upload button
Every JavaScript library would still need back-end URL to perform upload – you can code it yourself, or use some
Laravel package for upload like Spatie Larvel MediaLibrary
It is uploading files in chunks so should work for larger files, too
5. Bonus. Image manipulation: resize/crop/thumbs
Ok, one more final topic. We often upload images and there should be ways to manipulate them before/after storing. For
example, we need to make several thumbnails with different sizes – one for the detailed view, one for the list view, and final
one as a small icon.
There’s a great package for that, recommended by Laravel community and beyond: Intervention Image
This package is not actually for Laravel specifically, it works in general PHP, too.
Now, what can we do with this package? Basically, anything you need with images.
use Intervention\Image\Facades\Image;
return $img->response('jpg');
}
It will take the file from storage (where we uploaded it), resize and show it in the browser.
Image::make(storage_path('app/logos/1.png'))->resize(300, 200)->save('1-thumb.png');
Here are only a few of the methods that you can use for image manipulation:
So, just get creative, read their official documentation and move on to examples like this:
So, we’ve covered a lot about file uploading in Laravel. I hope you will have a deeper picture now about how it works.
In our QuickAdminPanel Laravel Generator, we do use all those three packages mentioned above, so you wouldn’t have to
write the code at all, just enter the details for the field:
See you soon in other tutorials for Laravel!