composer require pion/laravel-chunk-upload
Нет доступа к глобальному composer?
php -r "readfile('https://getcomposer.org/installer');" | php
на сервер загрузится файл composer.phar, после этого можем установить необходимую библиотеку используя composer.phar командойphp composer.phar require pion/laravel-chunk-upload
Route::get('/files-library', [App\Http\Controllers\FilesLibraryController::class, 'filesLibrary'])->name('files-library');
Route::post('files-library/upload', [App\Http\Controllers\UploaderController::class, 'upload'])->name('file-upload');
По пути /files-library - будет доступна страница для загрузки файлов, а files-library/upload - служит для самой загрузки // /app/Http/Controllers/FilesLibraryController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class FilesLibraryController extends Controller
{
public function filesLibrary(Request $request) {
return view('/files.library');
}
}
// /app/Http/Controllers/UploaderController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Pion\Laravel\ChunkUpload\Exceptions\UploadFailedException;
use Storage;
use Illuminate\Http\UploadedFile;
use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException;
use Pion\Laravel\ChunkUpload\Handler\AbstractHandler;
use Pion\Laravel\ChunkUpload\Handler\HandlerFactory;
use Pion\Laravel\ChunkUpload\Receiver\FileReceiver;
use App\Models\Tasks;
class UploaderController extends Controller
{
public $uploadPath = '/storage/app/public/uploads/';
/**
* @param Request $request
*
* @return JsonResponse
*
* @throws UploadMissingFileException
* @throws UploadFailedException
*/
public function upload(Request $request)
{
$receiver = new FileReceiver("file", $request, HandlerFactory::classFromRequest($request));
if ($receiver->isUploaded() === false) {
throw new UploadMissingFileException();
}
$save = $receiver->receive();
// если загрузка всего файла завершена
if ($save->isFinished()) {
return $this->saveFile($save->getFile(), $request);
}
// отправляем текущий прогресс о загрузке
/** @var AbstractHandler $handler */
$handler = $save->handler();
return response()->json([
"done" => $handler->getPercentageDone(),
'status' => true
]);
}
/**
* @param UploadedFile $file
*
* @return JsonResponse
*/
protected function saveFile(UploadedFile $file, Request $request)
{
$fileName = $file->getClientOriginalName();
$file->move($_SERVER['DOCUMENT_ROOT'] . $this->uploadPath, $fileName);
$filePath = $this->uploadPath . $fileName;
return response()->json([
'path' => $filePath,
'name' => $fileName
]);
}
}
Теперь создадим новый шаблон /resources/views/files.library.blade.php@extends('layouts.app')
@section('content')
<div class="file-upload-container">
<input type="file" name="file" id="file">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="action-buttons" style="display: none">
<a href="#" data-action="upload" style="display: none" class="progress-resume-link">Продолжить</a>
<a href="#" data-action="pause" style="display: none" class="progress-pause-link">Пауза</a>
<a href="#" data-action="cancel" class="progress-cancel-link">Отмена</a>
</div>
<ul class="resumable-list"></ul>
</div>
@endsection
@push('javascript')
<script src="{{ asset('js/resumable.js') }}"></script>
<script src="{{ asset('js/script.js') }}"></script>
@endpush
Нам осталось добавить основной js файл /public/js/script.js $(document).ready(function () {
var r = new Resumable({
target: '/file-library/upload',
chunkSize: 1 * 1024 * 1024, // 1MB
simultaneousUploads: 3,
testChunks: false,
throttleProgressCallbacks: 1,
query: {_token: $('input[name=_token]').val()}
});
$(document).on('click', '[data-action]', function (e) {
e.preventDefault();
let action = $(this).attr('data-action');
if (action == 'upload') {
r.upload();
} else if (action == 'pause') {
r.pause();
} else if (action == 'cancel') {
r.cancel();
}
})
var fileElement = document.getElementById('file');
r.assignBrowse(fileElement);
r.on('fileAdded', function (file) {
$('.action-buttons').show();
$('.progress-resume-link').hide();
$('.progress-pause-link').show();
$('.resumable-list').append('<li class="resumable-file-' + file.uniqueIdentifier + '">Загрузка <span class="resumable-file-name"></span> <span class="resumable-file-progress"></span>');
$('.resumable-file-' + file.uniqueIdentifier + ' .resumable-file-name').html(file.fileName);
r.upload();
});
r.on('pause', function () {
$('.progress-resume-link').show();
$('.progress-pause-link').hide();
});
r.on('complete', function () {
$('.action-buttons').hide();
$('.resumable-file-' + file.uniqueIdentifier + ' .resumable-file-progress').text('загружено');
});
r.on('fileSuccess', function (file, message) {
$('.resumable-file-' + file.uniqueIdentifier + ' .resumable-file-progress').html('(загружен)');
);
r.on('fileError', function (file, message) {
$('.resumable-file-' + file.uniqueIdentifier + ' .resumable-file-progress').html('(Ошибка: ' + message + ')');
});
r.on('fileProgress', function (file) {
$('.resumable-file-' + file.uniqueIdentifier + ' .resumable-file-progress').html(Math.floor(file.progress() * 100) + '%');
$('.progress-bar').css({width: Math.floor(r.progress() * 100) + '%'});
});
r.on('cancel', function () {
$('.resumable-file-progress').html('отменено');
});
r.on('uploadStart', function () {
$('.progress-resume-link').hide();
$('.progress-pause-link').show();
});
})
Теперь у нас готов базовый функционал загрузки больших файлов с возможностью приостановить или отменить загрузку. public $uploadPath = '/storage/app/public/uploads/';
Нажимая кнопку «Оставить заявку», Вы даёте согласие на обработку Персональных данных.