File uploads are 1 of the vital pieces in nigh web projects, and Laravel has awesome functionality for that, but information is pretty fragmented, especially for specific cases. I decided to assemble it all under one big articles, discussing the almost painful tasks related to file uploads. Enjoy!

Here are the topics we volition discuss in the article:

  1. Simple "local" file upload
  2. File validation process
  3. Uploading to external disks: Amazon S3 case
  4. AJAX upload and multiple files at once
  5. Image manipulation: crop, resize etc.

1. Local file upload

Let'south starting time from the basics – how does Laravel bargain with it past default? It'due south pretty easy.

So, we accept a uncomplicated form:

<form activeness="{{ route('books.store') }}" method="Postal service" enctype="multipart/form-data">     {{ csrf_field() }}     Book title:     <br />     <input type="text" name="championship" />     <br /><br />     Logo:     <br />     <input type="file" name="logo" />     <br /><br />     <input type="submit" value=" Save " /> </grade>        

And this is a simple code to upload that logo.

public role store(Request $asking) {     $request->logo->store('logos'); }        

After this sentence, file is actually stored in the folder storage/app/logos:

You tin specify the folder where the file should exist uploaded – encounter parameter 'logos'.

As you can come across, Laravel generated a random filename, merely yous can easily override it – use function storeAs():

$request->logo->storeAs('logos', 'i.png');        

Or, you can continue the original filename:

$request->logo->storeAs('logos', $request->logo->getClientOriginalName());        

Storage folder: files are not public?

We saw that, past default, Laravel stores the file in /storage/app folder. Why?

It's actually done with a good program – to hide uploaded files from users past default, to avoid illegal access or scraping.

Also, you may ask how to evidence the file and then, if /storage folder is not attainable in the browser? It's non public, correct?

If you lot do want those files to be public, you need to change two things:

ane. Config deejay modify. Modify config/filesystems.php parameter 'default' – from 'local' to 'public': then the files will be stored in storage/app/public (nosotros volition talk about filesystems settings afterward);

two. Symlink. Put a symlink from /public/storage to /storage/app/public folder, with ane Artisan control:

php artisan storage:link

Here'south an excerpt from the official Laravel docs on this:

By default, the public disk uses the local commuter and stores these files in storage/app/public. To brand them accessible from the web, you lot should create a symbolic link from public/storage to storage/app/public.

Now, we tin can admission the file from our example:

Another way, of course, is to bank check access in your Laravel code and then return the file as downloaded stream.

// This volition come from database in reality $filename = 'onvuqaJkKWx6ShRSserOR8p5HAE4RE3yJPCeAdrO.png';  if (!auth()->check()) {     return abort(404); } return response()->download(storage_path('app/public/logos/' . $filename));        

In this example, bodily users won't even know the actual filename until download, then you're in control over the access to that file.

Finally, if yous want to delete the file, you should use Storage facade for information technology:

use Illuminate\Back up\Facades\Storage;  $filename = 'onvuqaJkKWx6ShRSserOR8p5HAE4RE3yJPCeAdrO.png'; Storage::delete('logos/' . $filename);        

This is pretty much all the data we become from the official Laravel documentation about file upload. Simply in reality, information technology'due south simply the showtime. 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 instance, if you want to check for successfully uploaded file you may check this.

grade StoreBookRequest extends FormRequest {     public function rules()     {         return [             'logo' => 'required|file',         ];     } }        

This rule file ways: The field under validation must be a successfully uploaded file.

Here are more rules related to files:

image:
The file nether validation must be an prototype (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.

Fifty-fifty though y'all only need to specify the extensions, this rule actually validates against the MIME type of the file by reading the file'due south contents and guessing its MIME blazon.

A total listing of MIME types and their respective extensions may be institute at the following location: https://svn.apache.org/repos/asf/httpd/httpd/torso/docs/conf/mime.types


mimetypes:text/plain,…:
The file nether validation must match one of the given MIME types.

'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'

To determine the MIME type of the uploaded file, the file'southward contents will be read and the framework will endeavour to guess the MIME type, which may be different from the client provided MIME type.


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 dominion'southward parameters:

'avatar' => 'dimensions:min_width=100,min_height=200'

Available constraints are: min_width, max_width, min_height, max_height, width, height, ratio.

A ratio constraint should be represented every bit width divided past summit. This can exist specified either past a statement like 3/2 or a bladder like ane.5:

'avatar' => 'dimensions:ratio=iii/2'

You tin check other validation rules for Laravel here.

Detect. Important note about size validation – don't forget to check your php.ini settings. By default, you tin upload files simply up to 2mb.

upload_max_filesize = 2M

Also, cheque maximum Postal service request size:

post_max_size = 8M

But be conscientious with putting bigger numbers hither, it can exist used in wrong means by some people. To upload much bigger files, yous can apply chunks, we volition discuss it separately after.


iii. Uploading to external disks: Amazon S3

Disks and Drivers.

And then far, in this commodity we touched on the basic file upload to the same code repository – into the /storage folder. Merely quite frequently it makes sense to store files separately, peculiarly if they are bigger and could take up server disk infinite.

Let's come across two new concepts of Filesystem: drivers and disks.

Driver is a type of storage.
Laravel supports these drivers out of the box:

  • local: default one we used so far
  • ‎s3: represents popular Amazon S3, requires boosted parcel league/flysystem-aws-s3-v3
  • ‎rackspace: represents Rackspace Cloud storage, requires boosted package league/flysystem-rackspace
  • ftp: yous demand to setup host/username/countersign to brand it work

Ok, these are drivers.

Now, there'south some other term called disk – it represents the actual folder/saucepan name inside your chosen driver.

And yep, it ways that one driver can have multiple disks – for case, y'all want to utilize one S3 bucket for images, and some other one for documents.

Let's look at a default config/filesystems.php settings:

'default' => env('FILESYSTEM_DRIVER', 'local'),  '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'),         'undercover' => env('AWS_SECRET_ACCESS_KEY'),         'region' => env('AWS_DEFAULT_REGION'),         'bucket' => env('AWS_BUCKET'),     ],  ],        

Yous 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 deejay that volition be used every bit the primary one
  • Please put your parameters in .env files, to be able to accept different settings for testing and live servers. We've written about .env files here.

So, if yous desire to use S3 equally primary driver, you lot need to install league/flysystem-aws-s3-v3 package and change the .env file:

FILESYSTEM_DRIVER=s3

And then also yous can specify the disk straight in the code of file upload.

$request->logo->shop('logos', 's3');        

If nosotros practise that and put in our AWS details, here'due south how our file will be placed in S3 Console.

Now, by default our files volition get public URLs, like this:
https://s3-european union-w-1.amazonaws.com/laraveldaily-videos-examination/logos/OIIB2jilZkhn7wUI6Mol14pgiCtmtxdLUyoZmVKh.png

Is that a security breach? Well, yes and no.

1 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 tin can access the file if you lot know the name. Here'due south the official comment from Trello'southward help page:

The URLs for the attachments are cryptographically unguessable, pregnant that no ane is going to exist able to estimate your zipper URL. However, if you share the URL for a Trello zipper, anyone with the URL will be able to come across the attachment.

If you lot need extra security, we recommend using Google Bulldoze for attachments. You can attach files from Google Bulldoze directly to Trello and specify fine-grained access to the file via the Google Bulldoze interface.

In other words, y'all can add boosted layers to your file storage for security, Trello is simply 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

Nosotros've touched briefly on larger file uploads, that it makes sense to shop them outside the code, on something like Amazon S3. But there's another consequence – uploading process, which leaves user waiting for quite a while. We need to handle it gracefully.

If you just Postal service a big file via default form, browser will only bear witness loading signs and you lot won't get notified almost any progress until it'south done.

Nosotros can modify that using AJAX upload and certain library – as an instance, I volition take BlueImp JQuery library.

I've recently shot a demo-video for file uploads to Amazon S3:

Also, code on GitHub: https://github.com/LaravelDaily/Laravel-AmazonS3-Video

Another tutorial I've written is this: Laravel AJAX File Upload with BlueImp JQuery Library

So I won't echo those tutorials here, please read them in full detail, simply I will simply re-cap the primary things:

  • You use JavaScript library to upload files – catch consequence on click of upload push button
  • Every JavaScript library would still demand dorsum-stop URL to perform upload – y'all can code it yourself, or use some Laravel parcel for upload like Spatie Larvel MediaLibrary
  • Information technology is uploading files in chunks so should piece of work for larger files, too

five. Bonus. Epitome manipulation: resize/ingather/thumbs

Ok, one more final topic. Nosotros often upload images and there should be ways to manipulate them earlier/after storing. For example, we demand to make several thumbnails with different sizes – one for the detailed view, one for the listing view, and final one every bit a pocket-size icon.

There's a great package for that, recommended by Laravel customs and beyond: Intervention Prototype

This package is not actually for Laravel specifically, it works in general PHP, besides.

How to install information technology in Laravel:

composer require intervention/paradigm

The official documentation as well mentions config/app.php changes, but information technology'south not needed anymore since Laravel five.5.
You can use it correct afterward the composer command.

Now, what can nosotros practise with this packet? Basically, annihilation you demand with images.

Here's the about simple example:

utilize Intervention\Prototype\Facades\Paradigm;  public function alphabetize() {     $img = Image::make(storage_path('app/logos/ane.png'))->resize(300, 200);      return $img->response('jpg'); }        

It will take the file from storage (where nosotros uploaded it), resize and show it in the browser.

You tin can likewise save it in different folder for thumbnails:

Image::make(storage_path('app/logos/1.png'))->resize(300, 200)->save('1-thumb.png');        

Hither are only a few of the methods that you can use for image manipulation:

So, just get artistic, read their official documentation and movement on to examples like this:

$prototype->fit(250, 250, office ($constraint) {     $constraint->aspectRatio(); });        

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, merely enter the details for the field:

See yous soon in other tutorials for Laravel!