上傳大的附件分為兩種情況,
第2種使用分片上傳
優勢:可以突破服務器上傳大小的限制,可以web存儲上傳到哪一塊了,在浏覽器關閉或者刷新的情況下可以斷點續傳;
劣勢:上傳速度慢,在我本地電腦測試,200M的文件,改變配置按照正常方式上傳大約需要12到15秒,但是使用第2種分片上傳,大約需要40多秒,也就是所需時間是正常上傳的3倍,我測試了for循環同時上傳幾個碎片,電腦直接很卡,點擊别的浏覽器或者文件夾之類的全部是沒有響應,所以放棄了使用循環同時上傳多個;
如果上傳大的文件實現進度條是很有必要的,否則用戶看不到進度會等得不耐煩了。
小的文件隻需要2秒左右,是否有進度條沒有關系。
第一種,在可以改變服務器配置的前提下
圖1 帶進度條文件上傳
1、配置php.ini
如果上傳的文件比較大,以上4點都需要修改,特别是第2點,盡可能配置,否則上傳最後會比較慢。
2、iis上傳大小限制,可以在web.config直接修改,加入以下代碼
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
<requestLimits maxAllowedContentLength="1073741824" /> 這裡是限制的大小,默認大小忘記了,我這裡設置的是可以上傳1G進行的測試。
3、nginx上傳大小限制
我開始想把這些加到location / {}裡邊,提示錯誤client_header_timeout不允許放到裡邊,所以全部加到外邊了,也就是server {}裡邊;
注意下第6點,如果不配置,nginx上傳文件會存到緩存,然後再一點一點傳到upload_tmp_dir的目錄下,導緻上傳所需時間是iis的2倍。
4、html代碼
<tr class=''>
<td width="90" align="right" rowspan='2'>超大附件</td>
<td>
<div class='jdfull '><div class='jdperc'></div></div>
<div class='jdtis '>0%</div>
<input type='file' id="down_bfule_tpfile" class='inpMain layui-inpu' name='' size='30'><button type='button' class='layui-btn submitpfile' >上傳</button> </td>
</tr>
<tr class=''>
<td>
<input type='text' class='inpMain' placeholder='不限大小' style='width:calc(100% - 20px);' value='' name='down_bfule' id="down_bfule" ></td>
</tr>
5、css代碼 用來設置進度條
/*進度條*/
.jdfull{width:calc(100%);height:20px;background:#FFF;margin-bottom:10px;border-radius:10px;border:1px solid #DDD;}
.jdperc{height:20px;background:#5FB878;width:0px;border-radius:10px;}
.jdtis{margin-bottom:10px;}
6、js代碼(jquery使用監聽progress實現進度條功能)
$(".submitpfile").click(function() {
var fileext=['rar','ZIP','pdf'];
var formData = new FormData();
formData.append("file", $("#down_bfule_tpfile").get(0).files[0]);
if (!$("#down_bfule_tpfile").get(0).files[0]) {
alert("請選擇要上傳的文件!");
return false
};
//判斷擴展名 是否支持上傳
var patharr = $("#down_bfule_tpfile").get(0).files[0].name.split(".");
//上傳文件擴展名轉小寫,ZIP zip 2個是同一個文件
var ext = patharr[patharr.length - 1].toLowerCase();
if (fileext.indexOf(ext) < 0) {
alert('隻支持' fileext.join(','));
return false;
}
$.ajax({
url: '處理圖片上傳的url',
data: formData,
type: "post",
dataType: "JSON",
contentType: false,
processData: false,
//監聽progress 實現上傳進度條
xhr: function() {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress',
function(e) {
console.log(e);
//百分比取整
var progressRate = parseInt((e.loaded / e.total) * 100);
$('.jdfull .jdperc').css('width', progressRate "%");
$('.jdtis').html(progressRate "%")
});
return xhr
},
/*進度條結束*/
success: function(result) {
if (result.error == "0000") {
console.log(result.msg);
//上傳完成以後文件地址賦值給文本框,用于表單提交
$("#down_bfule").val(result.msg);
} else {
//錯誤信息提示
alert(result.msg);
return false
}
//上傳框初始化
var objFile = document.getElementById("down_bfule_tpfile");
objFile.outerHTML = objFile.outerHTML.replace(/(value=\"). \"/i, '$1"')
}
})
})
7、後端php處理程序
foreach($_FILES as $k=>$v){
$v['name']//文件名稱
$v['size']//文件大小
$v["tmp_name"]//臨時文件名包含了物理路徑E:\temp\文件名
move_uploaded_file($v["tmp_name"],'文件存放路徑(物理路徑 文件名)')
}
第二種,不能改變服務器的配置使用分片上傳
圖2 進度條顯示多少片
html,css不變,隻是改變js,下面是用到的js代碼
代碼1:點擊事件
$(".submitpfile").click(function() {
var fileext=['rar','zip','pdf'];//支持格式
var ranksize=1024*1024;//分片每次上傳的大小 1M
if (!$("#down_bfule_tpfile").get(0).files[0]) {
alert("請選擇要上傳的文件!");
return false
};
var patharr = $("#down_bfule_tpfile").get(0).files[0].name.split(".");
var ext = patharr[patharr.length - 1].toLowerCase();
if (fileext.indexOf(ext) < 0) {
alert('隻支持' fileext.join(','));
return false
}
var size = $("#down_bfule_tpfile").get(0).files[0].size;
var start=true;//是否從第一個開始上傳
var localname=$("#down_bfule_tpfile").get(0).files[0].name;
/*
使用localStorage 文件名作文變量存儲
存儲大小,還有上傳了多少片
文件名存放 判斷大小 如果大小也和上傳的文件相同判斷為同一個文件
如果用戶把文件名改成了上傳過的,不加判斷會造成上傳文件錯誤
window.localStorage.getItem 獲取存儲的數據
window.localStorage.setItem 設置存儲的數據 key value
window.localStorage.removeItem 移除存儲的數據
json.parse 字符串轉成json格式
*/
if(JSON.parse(window.localStorage.getItem(localname))){
var localsize=JSON.parse(window.localStorage.getItem(localname)).localsize;
var ranknum=JSON.parse(window.localStorage.getItem(localname)).ranknum;
if(size==localsize){
//已經上傳過 但是沒有上傳完,中斷了
start=false;
}
}
if(start==true){
//第一片開始上傳
uploadtp(1);
}else{
//存儲的下一片開始上傳
uploadtp(ranknum 1);
}
})
代碼2:uploadtp方法
function uploadtp(m){
var size = $("#down_bfule_tpfile").get(0).files[0].size;
var formData = new FormData();
formData.append("filename", $("#down_bfule_tpfile").get(0).files[0].name);
formData.append("size", size);
//Math.ceil 向上取整 獲得上傳總得片數 例如:1.1 1.9 都會取整為2,和php的分頁一個性質
rankcount=Math.ceil(size/ranksize);
/*
uptemp 用于存放 要上傳大小 上傳完多少片
uptemp['ranknum']=m; 上傳完多少片
uptemp['localsize']=size; 上傳文件總得大小,用于判斷要上傳的是否同一個文件
JSON.stringify 數組轉成json字符串
*/
var uptemp={};
uptemp['ranknum']=m;
uptemp['localsize']=size;
window.localStorage.setItem($("#down_bfule_tpfile").get(0).files[0].name,JSON.stringify(uptemp));
/*存儲完成*/
/*
$("#down_bfule_tpfile").get(0).files[0].slice 對選擇的文件進行切割
(m-1)*ranksize 起始位置
m*ranksize 結束位置
*/
formData.append("photo", $("#down_bfule_tpfile").get(0).files[0].slice((m-1)*ranksize,m*ranksize));
$.ajax({
url: "處理上傳的url",
data: formta,
type: "post",
dataType: "json",
contentType: false,
processData: false,
/*
進度條開始
這是一種豎線方式 監聽progress,監聽每一片的上傳進度
*/
xhr: function() {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress',
function(e) {
console.log(e);
var progressRate = parseInt((e.loaded / e.total) * 100);
$('.jdfull .jdperc').css('width', progressRate "%");
$('.jdtis').html("總共:<span style='color:red'>" rankcount "</span>片,當前:第<span style='color:red'>" m "</span>片" progressRate "%")
});
return xhr
},
/*進度條結束*/
success: function(result) {
if (result.error == "0000") {
$('.jdtis').html("全部上傳完成!");
//上傳完成,清除以前的分片存儲
window.localStorage.removeItem($("#down_bfule_tpfile").get(0).files[0].name);
var objFile = document.getElementById("down_bfule_tpfile");
objFile.outerHTML = objFile.outerHTML.replace(/(value=\"). \"/i, '$1"');
$("#down_bfule").val(result.msg)
} else if(result.error == "0001") {
//0001文件沒有上傳完 需要繼續上傳
uploadtp(m 1);
}else{
//php處理返回的錯誤提示 比如長時間沒有刷新頁面,導緻已經退出登陸了
alert(result.msg);
return false
}
}
/*
第2種 去掉上邊進度條開始 到結束的代碼,使用下面的success 代替上邊的success
根據上傳了多少片除以總數 顯示當前的百分比 var progressRate=parseInt((m / rankcount) * 100);
*/
/*
success: function(result) {
if (result.error == "0000") {
var progressRate=100;
$('.jdfull .jdperc').css('width', progressRate "%");
$('.jdtis').html("全部上傳完成!");
window.localStorage.removeItem($("#down_bfule_tpfile").get(0).files[0].name);
var objFile = document.getElementById("down_bfule_tpfile");
objFile.outerHTML = objFile.outerHTML.replace(/(value=\"). \"/i, '$1"');
$("#down_bfule").val(result.msg)
} else if(result.error == "0001") {
var progressRate=parseInt((m / rankcount) * 100);
$('.jdfull .jdperc').css('width', progressRate "%");
$('.jdtis').html(progressRate "%");
//0001文件沒有上傳完 需要繼續上傳
uploadtp(m 1);
}else{
//php處理返回的錯誤提示 比如長時間沒有刷新頁面,導緻已經退出登陸了
alert(result.msg);
return false
}
}
*/
})
}
php後端處理程序
$filename=input('post.filename');//原始文件名
$size=input('post.size');//原始文件大小
//創建存放的文件夾
foreach($_FILES as $k=>$v){
//$v["tmp_name"]臨時文件 含路徑
$images_dir = '/public/upload/file/'.date("Ymd")."/";
if (!file_exists(ROOT_PATH."".$images_dir)) {
mkdir(ROOT_PATH."".$images_dir,0777);
}
$name = explode(".", $filename); //将上傳前的文件以“.”分開取得文件類型 支持png jpg gif
$imgtype=strtolower($name[count($name)-1]);//類型轉成小寫
$newname=date("YmdHis".rand(10000,99999)).".".$imgtype;//新的文件名
//file_put_contents 追加 注意有FILE_APPEND,不加的話會覆蓋原來的
//file_get_contents讀取内容
file_put_contents(ROOT_PATH.$images_dir.$filename,file_get_contents($v["tmp_name"]),FILE_APPEND);
//判斷大小 是否已經上傳完成
if(filesize(ROOT_PATH.$images_dir.$filename)>=$size){
rename(ROOT_PATH.$images_dir.$filename,ROOT_PATH.$images_dir.$newname);
exit( json_encode(array('error'=>'0000','msg'=>$images_dir.$newname),JSON_UNESCAPED_UNICODE));
}else{
exit( json_encode(array('error'=>'0001'),JSON_UNESCAPED_UNICODE));
}
}
說明:
nginx上傳文件很慢
處理辦法:關閉 fastcgi_request_buffering,如果不關閉,上傳所需時間至少是iis的2倍;
具體操作:編輯nginx.conf,
server {
fastcgi_request_buffering off;
}
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!