一、PHP实现大文件上传的办法
1、因为默认会有上传大小限制,所有可以通过修改nginx和PHP的配置,来扩大限制,但是只能治标不治本,换一个环境还需要重新配置,而且很容易因为上传超时而中断
2、通过将大文件进行分片,每一片都是一个小文件,每次上传一部分到服务器,通过多次上传来完成大文件的上传功能,不会出现超时中断的问题
大文件分片上传解决的是大文件上传容易出现超时中断的问题,并不是解决上传速度的问题
该篇文章是我在已有的可以正常运行的laravel项目中新增的几个文件来实现的,如果不想自己做也可以使用laravel的开源扩展包 AetherUpload - 让 Laravel 支持超大文件断点上传
二、具体实现
1、前端代码,通过前端js代码,实现每次只上传指定大小的文件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ajax上传文件进度条显示</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">
</script>
<script type="text/javascript">
function sendfile(){
const LENGTH = 2*1024*1024;
var sta=0;
var end=sta+LENGTH;
var blob=new Blob();
var fd=null;
var xhr=null;
var pic=document.getElementsByTagName('input')[0].files[0];
console.log(pic,1);
var name=pic.name;
var totalsize=pic.size;
var precent=null;
while(sta<totalsize){
blob = pic.slice(sta,end);
fd = new FormData();
fd.append('part',blob);
fd.append('name',name);
xhr=new XMLHttpRequest();
xhr.open('POST','{{route('upload.store')}}',false);
xhr.send(fd);
var response = JSON.parse(xhr.responseText);
if (response.code == '-1'){
alert(response.error);
break;
}
precent=100 * (end/totalsize);
if(precent>100){
precent=100;
}
console.log(Math.round(precent)+'%');
document.getElementById('nei').style.width=precent+'%';
document.getElementById('precent').innerHTML=Math.floor(precent)+'%';
sta = end;
end = end + LENGTH;
}
}
</script>
<style>
#wai{
width:500px;
height:30px;
border:1px solid green;
}
#nei{
width:0px;
height:30px;
background:green;
}
</style>
</head>
<body>
<div id="wai">
<div id="nei"></div>
</div>
<span id="precent"></span><br/>
<input type="file" name="pic" onchange="sendfile();"/>
</body>
</html>
2、后端代码
2.1创建一个UploadContracts契约,用来约定一下接口
<?php
namespace App\Contracts;
use Illuminate\Http\Request;
interface UploadContracts
{
/**
* @param Request $request
* @return mixed
* 接收文件
*/
public function requestFile(Request $request);
/**
* @return mixed
* 文件校验的方法
*/
public function FileCheck();
/**
* @return mixed
* 判断目录是否存在
*/
public function ExistsDir();
/**
* @return mixed
* 上传文件
*/
public function UploadFIle();
}
2.2创建一个UploadSupport,实现这个契约接口
<?php
namespace App\Support;
use App\Contracts\UploadContracts;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class UploadSupport implements UploadContracts
{
protected $file;
protected $fileName;
protected $fileSize;
protected $fileExtension;
protected $image = [
'png','jpeg','jpg','gif'
];
protected $txt = [
'docx','doc'.'txt','csv','pdf'
];
protected $url = 'default';
/**
* @var 本次文件上传地址
*/
protected $pathUrl;
public function requestFile(Request $request)
{
$this->file = $request->file('part');
$this->fileName = $request->input('name');
$this->fileSize = $this->file->getSize();
// $this->fileExtension = $this->file->extension();
$this->fileExtension = substr($this->fileName,strripos($this->fileName,'.') + 1);
return $this;
}
public function FileCheck()
{
if (in_array($this->fileExtension,$this->image)){
$this->url = 'images';
}
if (in_array($this->fileExtension,$this->txt)){
$this->url = 'document';
}
$this->ExistsDir();
$this->pathUrl = Storage::path('public').'/'.$this->url.'/'.$this->fileName;
return $this;
}
public function ExistsDir()
{
if (!is_dir(Storage::path('public').'/'.$this->url)){
mkdir(Storage::path('public').'/'.$this->url);
}
return true;
}
public function UploadFIle()
{
//分片文件第一次上传,创建文件
if (!file_exists($this->pathUrl)){
return move_uploaded_file($this->file->path(),$this->pathUrl);
}
//追加分片文件到之前的文件中
return file_put_contents($this->pathUrl,file_get_contents($this->file->path()),FILE_APPEND);
}
}
3.3在AppServiceProvider服务提供者中注册
3.4创建控制器,配置路由
<?php
namespace App\Http\Controllers\Admin\V1;
use App\Contracts\UploadContracts;
use Illuminate\Http\Request;
class UploadController extends BaseAdminController
{
public function store(Request $request,UploadContracts $uploadContracts)
{
$upload = $uploadContracts->requestFile($request);
$upload->FileCheck();
$upload->UploadFIle();
return response()->json([
'code' => 200,
'info' => '上传成功'
]);
}
}
路由
Route::view(‘upload’,‘upload’);
Route::post(‘UploadFile’,[\App\Http\Controllers\Admin\V1\UploadController::class,‘store’])->name(‘upload.store’)->middleware(‘upload.check’);