用到的PHP文件系统函数
bool move_uploaded_file ( string destination ) 将上传的文件移动到新位置
bool file_exists ( string $filename ) 检查文件或目录是否存在。
[resource fopen ( string mode [, bool context ]] )](http://php.net/manual/zh/function.fopen.php) 打开文件或者 URL
int filesize ( string $filename ) 取得文件大小
string fread ( resource length ) 读取文件(可安全用于二进制文件)
int fwrite ( resource string [, int $length ] )写入文件(可安全用于二进制文件)
bool fclose ( resource $handle ) 关闭一个已打开的文件指针
[bool unlink ( string context ] )](http://php.net/manual/zh/function.unlink.php) 删除文件
[string md5_file ( string raw_output = FALSE ] )](http://php.net/manual/zh/function.md5-file.php) 计算指定文件的 MD5 散列值
upload.html
<form method="post" enctype="multipart/form-data" class="form-horizontal" action="">
<tableclass="table table-hover">
<tr>
<tdclass="right">
<strong>上传App</strong>
</td>
<tdclass="left">
<div id="progress">
<div id="finish" style="width: 0%;" progress="0"></div>
</div>
<span id="new_file">
<input type="file" value="" name="gz_app_b_android" onchange="onchangeUpload(this,'finish','new_file')" class="input" size="50" id="file">
</span>
<input type="hidden" value="" name="gz_app_c_android" id="gz_app_c_android">
<p class="help-block"></p>
</td>
</tr>
</table>
</form>
<script type="text/javascript" src="__PUBLIC__/Js/upload.js"></script>
<script type="text/javascript" src="__PUBLIC__/Js/spark-md5.js"></script>
upload.js
function onchangeUpload(obj,progress_id,self_id)
{
var blob= obj.files[0];
browserMD5File(blob, function (err, md5) {
//console.log(md5); // 97027eb624f85892c69c4bcec8ab0f11
var time= Math.floor((new Date().valueOf())/ 1000);
var bytesPerPiece= 1024 * 1024 * 2; // 文件切片大小定义.
var totalPieces;
var x= 4, y= 0;
var rand= '';
for (var i= 0; i< 5; i++) {
rand+= parseInt(Math.random()* (x- y+ 1)+ y);
}
var start= 0;
var end;
var index= 1;
var filesize= blob.size;
var filename= time+ rand+ '.apk';
var that= obj;
//计算文件切片总数
totalPieces= Math.ceil(filesize/ bytesPerPiece);
var progress;
var progressObj= document.getElementById(progress_id);
//重新上传则清空进度条
progress= '0%';
progressObj.style.width= progress;
var upload_status= true;
while(start< filesize)
{
end= start+ bytesPerPiece;
if (end> filesize) {
end= filesize;
}
var chunk= blob.slice(start, end);//切割文件
// 兼容firefox
/*if(blob.mozSlice){
var chunk = blob.mozSlice(startByte,endByte);
}*/
//传参
var formData= new FormData();
formData.append("file", chunk, filename+ index);
formData.append("file_name", filename);
formData.append("total_pieces", totalPieces);
formData.append("now_pieces", index);
formData.append("md5", md5);
$.ajax({
url: './asyncUploadAjax',
type: 'POST',
cache: false,
data: formData,
processData: false,
contentType: false,
async: true // true:异步,false:同步
}).done(function (res) {
if (JSON.parse(res).code== 1) {
progress= Math.min(100, ((JSON.parse(res).n+1)/ totalPieces)* 100)+ '%';
progressObj.style.width= progress;
}else if (JSON.parse(res).code== 2) {
//判断是否有上传失败的节点
if(upload_status== true)
{
progress= '100%';
progressObj.style.width= progress;
document.getElementById(that.name).value= JSON.parse(res).file_path;
//清空file 防止将文件大小计算到表单里
document.getElementById(self_id).innerHTML= '<input type="file" value="" name="'+that.name+'" onchange="onchangeUpload(this,\''+progress_id+'\', \''+self_id+'\')" class="input" size="50" id="file">';
alert(blob.name+ ' 上传完成');
}else{
alert(blob.name+ JSON.parse(res).msg);
}
}else {
upload_status= false;
}
}).fail(function (res) {
upload_status= false;
});
start= end;
index++;
}
})
}
upload.php
/*
* 异步上传
* */
public function asyncUploadAjax()
{
$data['code'] = 1;
$data['msg'] = 'waiting for all';
$data['file_path'] = '';
$form_data = $_POST;
$file = $_FILES;
$new_file_path = $_SERVER['SINASRV_DATA_DIR'].'/'. $_FILES['file']['name'];
if (move_uploaded_file($file['file']['tmp_name'], $new_file_path)) {
//判断是否上传完成
$status = self::checkUploadAccomplish($form_data['file_name'], $form_data['total_pieces']);
if($status['status'])
{
//合并切片文件
$file_path = self::mergeSlices($form_data['file_name'], $form_data['total_pieces']);
//验证文件安全
if(md5_file($file_path) == $form_data['md5'])
{
$data['code'] = 2;
$data['msg'] = 'upload success';
$data['file_path'] = $file_path;
}else{
$data['code'] = 0;
$data['msg'] = '文件不安全,请重新上传';
}
}else{
$data['n'] = $status['n'];
}
} else {
$data['code'] = 0;
$data['msg'] = 'upload fail';
}
echo json_encode($data);
}
/*
* 判断文件是否上传完成
* */
public function checkUploadAccomplish($file_name='', $total_pieces)
{
$file_name = substr($file_name, 0, 15);
$n = 0;
$status = true;
for($i=1; $i<=$total_pieces; $i++)
{
if(!file_exists($_SERVER['SINASRV_DATA_DIR'].'/'. $file_name.'.apk'.$i))
{
$status = false;
}else{
$n++;
}
}
return ['n'=>$n, 'status'=>$status];
}
/*
* 合并切片文件
* */
public function mergeSlices($file_name='', $total_pieces)
{
$file_name = substr($file_name, 0, 15);
$new_file_name = $_SERVER['SINASRV_DATA_DIR'].'/'.$file_name.'.apk';
$fp = fopen($new_file_name,"wb");
for($i=1; $i<=$total_pieces; $i++)
{
$tmp_name = $_SERVER['SINASRV_DATA_DIR'].'/'. $file_name.'.apk'.$i;
//只读方式打开文件 指针指向文件头
$handle = fopen($tmp_name,"rb");
//切片文件写入新文件
fwrite($fp,fread($handle,filesize($tmp_name)));
//关闭切片文件
fclose($handle);
unset($handle);
//删除切片
unlink($tmp_name);
}
fclose($fp);
return $new_file_name;
}