О web-разработке
и даже немного больше...

Как загрузить большой файл в Laravel?

Иногда для загрузки больших файлов стандартной формы HTML становится недостаточно, по той причине, что на стороне веб-сервера имеются ограничения по размеру загружаемого файла. Иногда разработчики (особенно начинающие) приходят к тому что просто меняют лимиты загрузки файлов на сервер в большую сторону, но не всё так просто. Увеличение лимита загружаемых файлов тянут за собой другие проблемы, которые вы создаёте для вашего веб-сервера. Об этом много информации на просторах интернета.

Мы же поговорим о другом способе загрузки файлов, более правильном и безопасным. В этих случаях остаётся один и скорее единственный правильный способ – это разбиение файла на части.
Так как передача файла происходит с клиентской части, то логично предположить, что разбивать и передавать частями нужно на клиентской стороне. Для этих целей мы можем воспользоваться готовым решением под названием resumable.js. Данный плагин поможет реализовать отправку на сервер файла с вашей формы частями.

Вы можете установить resumable.js с GIT, либо подключить его напрямую через CDN.
https://cdn.jsdelivr.net/npm/resumablejs@1.1.0/resumable.min.js

Следующим шагом является подготовка HTML формы для выбора файла. Для примера мы сделаем такую разметку:

<div class="container pt-4">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header text-center">
                    <h5>Загрузка файла</h5>
                </div>

                <div class="card-body">
                    <div id="upload-container" class="text-center">
                        <button id="browseFile" class="btn btn-primary">Выбрать файл</button>
                    </div>
                    <div  style="display: none" class="progress mt-3" style="height: 25px">
                        <div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" style="width: 75%; height: 100%">75%</div>
                    </div>
                </div>

                <div class="card-footer p-4" style="display: none">
                    <video id="videoPreview" src="" controls style="width: 100%; height: auto"></video>
                </div>
            </div>
        </div>
    </div>
</div>

Разметка сделана для демонстрации примера, разумеется, вы её будете адаптировать под свой проект. Теперь что касается обработчика на JavaScript, инициализация плагина производится так же для демонстрации. Полный набор параметров и триггеров вы можете посмотреть в описании в Git репозитории проекта.

<script type="text/javascript">
    let browseFile = $('#browseFile');
    let resumable = new Resumable({
        target: '{{ route('files.upload.large') }}',
        query:{_token:'{{ csrf_token() }}'}, // CSRF token
        fileType: ['mp4'],
        chunkSize: 10*1024*1024, // default is 1*1024*1024, this should be less than your maximum limit in php.ini
        headers: {
            'Accept' : 'application/json'
        },
        testChunks: false,
        throttleProgressCallbacks: 1,
    });

    resumable.assignBrowse(browseFile[0]);

    resumable.on('fileAdded', function (file) { // trigger when file picked
        showProgress();
        resumable.upload() // to actually start uploading.
    });

    resumable.on('fileProgress', function (file) { // trigger when file progress update
        updateProgress(Math.floor(file.progress() * 100));
    });

    resumable.on('fileSuccess', function (file, response) { // trigger when file upload complete
        response = JSON.parse(response)
        $('#videoPreview').attr('src', response.path);
        $('.card-footer').show();
    });

    resumable.on('fileError', function (file, response) { // trigger when there is any error
        alert('file uploading error.')
    });


    let progress = $('.progress');
    function showProgress() {
        progress.find('.progress-bar').css('width', '0%');
        progress.find('.progress-bar').html('0%');
        progress.find('.progress-bar').removeClass('bg-success');
        progress.show();
    }

    function updateProgress(value) {
        progress.find('.progress-bar').css('width', `${value}%`)
        progress.find('.progress-bar').html(`${value}%`)
    }

    function hideProgress() {
        progress.hide();
    }
</script>

Теперь что касается серверной части, то там нужно реализовать обработку передачи файлов частями. Для этих целей в Laravel так же есть пакет под названием laravel-chunk-upload который вы можете установить его себе с Git-репозитория.

Установка laravel-chunk-upload в ваш проект через composer

composer require pion/laravel-chunk-upload

Если возникают проблемы с установкой пакета в Laravel можно поступить другим путём.

  • Копируем в файл composer.json нужный пакет
  • Запускаем composer в папке с проектом: composer update и пакет скачивается. (* для некоторых случаев в папке проекта выполяется через команду php ../composer.phar update)
  • При необходимости копируем в конфиг app.php aliase и providers.

Далее пишем обработчик формы для загрузки файла в контроллере.

<?php

public function uploadLargeFiles(Request $request) {
    $receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request));

    if (!$receiver->isUploaded()) {
        // file not uploaded
    }

    $fileReceived = $receiver->receive(); // receive file
    if ($fileReceived->isFinished()) { // file uploading is complete / all chunks are uploaded
        $file = $fileReceived->getFile(); // get file
        $extension = $file->getClientOriginalExtension();
        $fileName = str_replace('.'.$extension, '', $file->getClientOriginalName()); //file name without extenstion
        $fileName .= '_' . md5(time()) . '.' . $extension; // a unique file name

        $disk = Storage::disk(config('filesystems.default'));
        $path = $disk->putFileAs('videos', $file, $fileName);

        // delete chunked file
        unlink($file->getPathname());
        return [
            'path' => asset('storage/' . $path),
            'filename' => $fileName
        ];
    }

    // otherwise return percentage information
    $handler = $fileReceived->handler();
    return [
        'done' => $handler->getPercentageDone(),
        'status' => true
    ];
}

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

Опубликован: 06.05.2025 г.

См. также:

Как посмотреть версию Laravel?
Ограничение параметров в маршрутах Laravel
Необязательные параметры маршрутов в Laravel
Как выбрать записи за определённый период (День, Месяц, Год) в Laravel?
Использование метода leftJoin() для выборки из нескольких таблиц в Laravel
Как просмотреть SQL запрос в Eloquent Laravel?
Как объявить переменную в шаблоне Laravel Blade?
Проверка на пустоту коллекций Eloquent в Laravel

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *