众所周知php无法上传大文件,即使是修改了php.ini文件,最有效的方法就是将文件分片上传再合并
废话不多说,直接上代码
index.html文件
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传</title>
</head>
<script>
function upload() {
var file = $("#upload_file")[0].files[0]// 获取文件对象
if (file == undefined) {
layer.msg("请先选择文件");
return false;
}
var loading = layer.load(1, { shade: false }); // 加载的风格
var name = file.name; // 文件名
var size = file.size; // 文件总大小
var succeed = 0; // 请求成功次数
var shardSize = 1024 * 1024 * 10; // 这里是分片的文件大小,不要设置太大不然可能OOM
var shardCount = Math.ceil(size / shardSize); // 计算总片数(向上取整)
for (var i = 0; i < shardCount; i++) {
var start = i * shardSize;
var end = Math.min(size, start + shardSize);
var form = new FormData();
form.append("upload_name", name); //文件名称
form.append("numbers", shardCount); // 总片数
form.append("number", i + 1); // 当前片
form.append("data", file.slice(start, end));
$.ajax({
url: "upload.php?action=upload",
type: "POST",
data: form,
async: true, // 异步
processData: false,
contentType: false,
success: function (data) {
console.log(data);
var returnData = $.parseJSON(data);
if (returnData.error == 200) {
++succeed;
if (succeed == shardCount) {
$.ajax({
url: "upload.php?action=merge",
type: "POST",
data: { 'numbers': shardCount, 'upload_name': name },
success: function (data) {
var returnData = $.parseJSON(data);
if (returnData.error == 200) {
layer.closeAll();
layer.msg("上传成功");
} else {
layer.closeAll();
layer.msg("其他错误");
}
},
});
}
} else {
layer.open({ content: "上传失败", time: 2 });
}
},
});
}
}
</script>
<body>
<p>
<input type="file" name="" id="upload_file">
</p>
<p>
<button onclick="upload()">上传文件</button>
</p>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://www.layuicdn.com/layui/layui.js"></script>
</html>
upload.php文件
<?php
class upload{
private $path='tmp/'; //临时文件存放目录
function uploadFile(){
if(empty($_POST['upload_name'])||empty($_POST['number'])){
die(json_encode(array('error'=>202, 'message'=>'No parameters!')));
}
$name=$_POST['upload_name'];
$nowShardNumber=$_POST['number'];
$fileName = $this->path .$name .$nowShardNumber.".tmp";
$result = move_uploaded_file($_FILES['data']['tmp_name'], $fileName);
if ($result) {
echo json_encode(array('error'=>200, 'message'=>'Upload ok'));
} else {
echo json_encode(array('error'=>201, 'message'=>'Upload error'));
}
}
function merge()
{
if(empty($_POST['upload_name'])||empty($_POST['numbers'])){
die(json_encode(array('error'=>202, 'message'=>'No parameters!')));
}
$fileName = $_POST['upload_name'];//文件名
$allShardNumber = $_POST['numbers'];//文件总片数
if(file_exists($fileName)){
unlink($fileName); //删除已经存在的完整文件
}
for($i=1; $i<=$allShardNumber;$i++) {
$shardFile=$this->path.$fileName.$i.'.tmp';
if(file_exists($shardFile)){
file_put_contents($this->path.$fileName,file_get_contents($shardFile), FILE_APPEND); //file_put_contents默认的是重写文件加上FILE_APPEND为追加写入
@unlink($shardFile); //删除临时文件
}else{
break;
}
}
echo json_encode(array('error'=>200, 'message'=>'Merge successful!'));
}
}
if(isset($_GET['action'])){
$obj = new upload();
if($_GET['action']==='upload'){
$obj->uploadFile();
}else{
$obj->merge();
}
}else{
echo json_encode(array('error'=>-1, 'message'=>'Error!'));
}
上传一个2.5GB的文件耗时80秒,但是没有完全达到80秒
都看到这了点个赞呗