Загрузка файлов Laravel

Работа с файлами в любом приложении является важной частью любой системы. Laravel предоставляет файловую систему, из которой мы можем взаимодействовать с файлами; загрузки файлов, их хранения или извлечения. В этой статье мы рассмотрим, как загружать и сжимать файлы в Laravel перед их сохранением.

Как загружать файлы в Laravel?

Чтобы загрузить файлы в Laravel, мы можем выполнить следующие шаги:

Шаг 1: Создайте проект Laravel

Мы можем использовать команду Laravel new или composer

laravel new test 

Или

composer create-project laravel/laravel test

Шаг 2. Добавьте аутентификацию

На этом этапе мы можем использовать Laravel breeze для проверки подлинности и выполнения всех других необходимых требований, таких как сброс пароля и логика подтверждения электронной почты.

composer require laravel/breeze

Шаг 3: Добавьте модель и миграцию

Следующим шагом является создание файла миграции, который будет содержать имя файла и папку. Мы можем использовать artisan для создания модели и файла миграции.

php artisan make:model Files -m

Флаг -m создает файл миграции для файловой модели . Мы можем добавить следующую логику к модели

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Files extends Model
{
    use HasFactory;

    protected $fillable = ['path'];
}

Затем мы можем указать столбцы в таблице файлов

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('files', function (Blueprint $table) {
            $table->id();
            $table->string('path');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('files');
    }
};

Шаг 4. Создайте общий Trait загрузки файлов

Trait помогает нам повторно использовать код в нескольких классах. Этот trait будет содержать логику для загрузки файла , переименования файла , сохранения файлов в папках, указанных пользователем , и удаления файлов из хранилища.

Например, в системе электронной коммерции мы можем захотеть разделить изображения на папки; Основные изображения, второстепенные изображения, баннеры и т. д.

Для этого мы будем использовать класс Illuminate\Http\UploadedFile для работы с файлами.

Мы также можем сделать трейт пригодным для использования с любым внешним диском, таким как Amazon S3.

Laravel поддерживает локальное хранилище файлов и Amazon S3 из коробки. Если вы хотите использовать Google Cloud Storage в качестве хранилища, вы можете рассмотреть возможность использования этого пакета.

В любом случае, какой бы сервис хранения вы ни решили использовать, трейт должен иметь возможность обрабатывать его без добавления каких-либо дополнительных реализаций.

Мы можем создать папку App\Traits в папке App, которая будет содержать все наши черты.

<?php

namespace App\Traits;

use Illuminate\Support\Str;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

trait Upload
{
    public function UploadFile(UploadedFile $file, $folder = null, $disk = 'public', $filename = null)
    {
        $FileName = !is_null($filename) ? $filename : Str::random(10);
        return $file->storeAs(
            $folder,
            $FileName . "." . $file->getClientOriginalExtension(),
            $disk
        );
    }

    public function deleteFile($path, $disk = 'public')
    {
        Storage::disk($disk)->delete($path);
    }
}

Чтобы сжать изображения при загрузке, мы можем использовать один из пакетов Spatie.

composer require spatie/laravel-image-optimizer 

Мы можем автоматически сжимать изображения при загрузке, тем самым уменьшая размер их файлов перед загрузкой в ​​хранилище. Чтобы настроить его, нам сначала нужно зарегистрировать его как промежуточное ПО маршрута в файле app/Http/Kernel.php .

// app/Http/Kernel.php   
protected $routeMiddleware = [   
     'optimizeImages' => \Spatie\LaravelImageOptimizer\Middlewares\OptimizeImages::class,   
   ]; 

Позже мы назначим промежуточное ПО маршруту загрузки файлов.

Шаг 5. Обработка загрузки файлов с помощью контроллера

Следующим шагом будет получение файлов через POST-запрос. Для этого мы будем использовать метод store в контроллере загрузки файлов.

Мы также можем проверить проверки, чтобы убедиться, что загруженные файлы имеют правильный тип и являются разрешенными файлами.

Путь к файлу также хранится в таблице файлов. Путь к файлу возвращается из нашего трейта после того, как он переименовал загружаемый файл. Формат пути к файлу будет следующим : Папка/имя файла и расширение, т.е. Products/HIDvPbozwW.png

<?php

namespace App\Http\Controllers;

use App\Models\Files;
use App\Traits\Upload;
use Illuminate\Http\Request;

class FilesController extends Controller
{
    use Upload;

    public function store(Request $request)
    {
        if ($request->hasFile('file')) {
            $path = $this->UploadFile($request->file('file'), 'Products');
            Files::create([
                'path' => $path
            ]);
            return redirect()->route('files.index')->with('success', 'File Uploaded Successfully');
        }
    }
}

Загрузка файла Laravel

Пути к файлам в базе

Шаг 6: Добавьте маршрут

Мы можем добавить маршрут в файл route/web.php . Мы можем использовать промежуточное программное обеспечение, которое мы создали ранее в нашем маршруте.

Route::post('upload-files', [FileController::class,'store'])->middleware('optimizeImages'); 

Шаг 7: Добавьте пользовательский интерфейс загрузки файлов

Мы можем создать файл просмотра и добавить форму загрузки файла

Форма загрузки файла Laravel

Форма загрузки файла

Шаг 8. Добавьте ссылку на хранилище (необязательно)

Файлы, загруженные с использованием общедоступного диска, всегда хранятся в папке storage/app/public . Мы можем использовать команду storage:link для создания символической ссылки на общую папку.

php artisan storage:link 

Шаг 9: Просмотр загруженных файлов

Как только файлы будут загружены в предпочитаемое вами хранилище, вы сможете просмотреть файл. Если вы используете общую папку, вы можете использовать вспомогательную функцию ресурса или вспомогательную функцию public_path , чтобы вернуть путь к файлу. Если вы используете стороннюю систему хранения, такую ​​как s3 или хранилище Google Cloud, вы можете использовать фасад хранилища.

Использование общей папки

asset('storage/'.$file->path)

Использование S3 или GCS

use Illuminate\Support\Facades\Storage;
Storage::disk('s3')->url($file->path)

Затем вы можете добавить путь в качестве источника изображения и отобразить их в своем приложении.

<img src="{{asset('storage/'.$file->path)}}" alt="file name">
//or
<img src="{{$file->path}}" alt="file name">

Загрузка файла Laravel

Показать файлы

Как обновить файлы в Laravel?

По умолчанию нет встроенного способа обновить файлы/изображения с помощью стандартного запроса PUT или PATCH, основанного на этой проблеме . Поэтому нам нужно искать другой способ сделать это. Мы могли бы использовать запрос POST, но затем удалить предыдущий файл, если он существует, а затем загрузить новый файл и обновить путь к файлу в базе данных.

 public function update_file(Request $request) //POST
    {
        //get the file id and retrieve the file record from the database
        $file_id = $request->input('file_id');
        $file = Files::where('id', $file_id)->first();
        //check if the request has a file
        if ($request->hasFile('file')) {
            //check if the existing file is present and delete it from the storage
            if (!is_null($file->path)) {
                $this->deleteFile($file->path);
            }
            //upload the new file
            $path = $this->UploadFile($request->file('file'), 'Products');
        }
        //upadate the file path in the database
        $file->update(['path' => $path]);

        //redirect with the success message
        return redirect()->back()->with('success', 'File Updated Successfully');
    }

Затем мы можем определить маршрут для обновления файла.

Route::post('update-file', [FilesController::class, 'update_file'])->middleware('optimizeImages');

Как загрузить несколько файлов и изображений в Laravel?

Это довольно легко. Мы можем повторно использовать наш трейт и использовать цикл foreach для загрузки и сохранения пути в базе данных.

Сначала мы обновим файловый контроллер, чтобы разрешить несколько файлов.

<?php

namespace App\Http\Controllers;

use App\Models\Files;
use App\Traits\Upload;
use Illuminate\Http\Request;

class FilesController extends Controller
{
    use Upload;

    public function store(Request $request)
    {

        $file_details = [];

        //check if request has files
        if ($request->hasFile('files')) {
          // loop through each file and upload

            foreach ($request->file('files') as $key => $file) {
                //Upload to Storage
                $path = $this->UploadFile($file, 'Products');

                //reformat the file details
                array_push($file_details, [
                    'path' => $path,
                ]);
            }

            //add each file details to database
            foreach ($file_details as $key => $value) {
                Files::create($value);
            }
        }
    }
}

Метод store теперь позволяет загружать несколько файлов.

Как изменить размер файлов в Laravel?

Вы можете изменить размер файлов перед их сохранением с помощью пакета Intervention Image . Этот пакет может помочь вам изменить размер изображений перед их сохранением.

use Intervention\Image\Facades\Image;
Image::make($file->path)->resize(200, 200);

Заключение

Работа с файлами и изображениями может быть сложной задачей в любом приложении, но Laravel позволяет легко работать с несколькими службами хранилища, используя их встроенные API и другие сторонние пакеты.