开发中遇到的几个问题:
1:js传送文件的数据,无法传送的问题,最后采用了实例化h5的接口,FormData,利用这个构建form表单,进行表单的传送数据,文件
2:遇到了传的问题中,传了一半不传了,是因为设置了timeout的值有点小
3:在用,file_put_contents ,filesize,这两个函数的时候路径没有写对,导致了判断失误的问题
4:FILE_APPEND表示向同一个文件中追加的意思
5:ajax 中timeout的单位为毫秒
file_put_contents($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'.$arr['fileName'],file_get_contents($files['tmp_name']),FILE_APPEND)
// 计算文件大小 size = file.size > 1024 ? file.size / 1024 > 1024 ? file.size / (1024 * 1024) > 1024 ? (file.size / (1024 * 1024 * 1024)).toFixed(2) + 'GB' : (file.size / (1024 * 1024)).toFixed(2) + 'MB' : (file.size / 1024).toFixed(2) + 'KB' : (file.size).toFixed(2) + 'B';
//页面代码
<input type="file" name="slice" id="slice" >
<a href="javascript:void(0);" οnclick="sendForm()">Js File Upload!</a>
<div id="output"><!-- 信息存放地 --> </div>
//JS代码
<script type="text/javascript">
$("#slice").change(function(event) {
var file = $("#slice")[0].files[0];
PostFile(file,0);
});
//执行分片上传
function PostFile(file,i){
var name = file.name, //文件名
size = file.size, //总大小shardSize = 2 * 1024 * 1024,
shardSize = 2 * 1024 * 1024, //以2MB为一个分片,每个分片的大小
shardCount = Math.ceil(size / shardSize); //总片数
if(i >= shardCount){
return;
}
//console.log(size,i+1,shardSize); //文件总大小,第一次,分片大小//
var start = i * shardSize;
var end = start + shardSize;
var packet = file.slice(start, end); //将文件进行切片
/* 构建form表单进行提交 */
var form = new FormData();
form.append("data", packet); //slice方法用于切出文件的一部分
form.append("lastModified", file.lastModified); //最后的额修改时间
form.append("name", name);
form.append("totalsize", size);
form.append("total", shardCount); //总片数
form.append("index", i + 1); //当前是第几片
$.ajax({
url: "__CONTROLLER__/upload",
type: "POST",
data: form,
//timeout:"10000",
async: true, //异步
dataType:"json",
processData: false, //很重要,告诉jquery不要对form进行处理
contentType: false, //很重要,指定为false才能形成正确的Content-Type
success: function (msg) {
console.log(msg);
/* 表示上一块文件上传成功,继续下一次 */
if (msg.status == 201) {
form = '';
i++;
PostFile(file, i);
} else if (msg.status == 502) {
form = '';
/* 失败后,每2秒继续传一次分片文件 */
setInterval(function () { PostFile(file, i) }, 2000);
} else if (msg.status == 200) {
console.log("上传成功");
} else if (msg.status == 500) {
console.log('第'+msg.i+'次,上传文件有误!');
} else {
console.log('未知错误');
}
}
})
}
</script>
//服务器端代码
if($_POST){
$files = $_FILES['data'];
$arr['i'] = $_POST['index'];
$arr['shardCount'] = $_POST['total'];
$arr['totalsize'] = $_POST['totalsize'];
$arr['fileName'] = $_POST['name'];
if($files['error'] > 0){
$arr['status'] = 500;
exit(json_encode($arr));
}
if($files['error'] == 0){
/* 检测第一次上传的时候已经有同文件时,删除原来的文件 */
if ($arr['i'] == 1 && is_file('/Public/Upload/'. $arr['fileName']) && filesize($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']) == $arr['totalsize']) {
unlink($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']);
}
// 否则继续追加文件数据
if (!file_put_contents($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'.$arr['fileName'],file_get_contents($files['tmp_name']),FILE_APPEND)) {
$arr['status'] = 501;
exit(json_encode($arr));
}
// 在上传的最后片段时,检测文件是否完整(大小是否一致)
if ($arr['i'] == $arr['shardCount']) {
if(filesize($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']) == $arr['totalsize']){
$arr['status'] = 200;
}else{
$arr['status'] = 501;
}
exit(json_encode($arr));
}
$arr['status'] = 201;
exit(json_encode($arr));
}else{
$arr['status'] = 502;
exit(json_encode($arr));
}
}else{
$this->display();
}
附件1:upload.html,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JS分片上传-极速上传</title>
</head>
<body>
<input type="file" name="slice" id="slice" >
<a href="javascript:void(0);" οnclick="sendForm()">Js File Upload!</a>
<div id="output"><!-- 信息存放地 --> </div>
<br/>
</body>
<script src="__PUBLIC__/js/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
$("#slice").change(function(event) {
var file = $("#slice")[0].files[0];
PostFile(file,0);
});
//执行分片上传
function PostFile(file,i){
var name = file.name, //文件名
size = file.size, //总大小shardSize = 2 * 1024 * 1024,
shardSize = 2 * 1024 * 1024, //以2MB为一个分片,每个分片的大小
shardCount = Math.ceil(size / shardSize); //总片数
if(i >= shardCount){
return;
}
//console.log(size,i+1,shardSize); //文件总大小,第一次,分片大小//
var start = i * shardSize;
var end = start + shardSize;
var packet = file.slice(start, end); //将文件进行切片
/* 构建form表单进行提交 */
var form = new FormData();
form.append("data", packet); //slice方法用于切出文件的一部分
form.append("lastModified", file.lastModified); //最后的额修改时间
form.append("name", name);
form.append("totalsize", size);
form.append("total", shardCount); //总片数
form.append("index", i + 1); //当前是第几片
$.ajax({
url: "__CONTROLLER__/upload",
type: "POST",
data: form,
//timeout:"10000", //超时10秒
async: true, //异步
dataType:"json",
processData: false, //很重要,告诉jquery不要对form进行处理
contentType: false, //很重要,指定为false才能形成正确的Content-Type
success: function (msg) {
console.log(msg);
/* 表示上一块文件上传成功,继续下一次 */
if (msg.status == 201) {
form = '';
i++;
PostFile(file, i);
} else if (msg.status == 502) {
form = '';
/* 失败后,每2秒继续传一次分片文件 */
setInterval(function () { PostFile(file, i) }, 2000);
} else if (msg.status == 200) {
console.log("上传成功");
} else if (msg.status == 500) {
console.log('第'+msg.i+'次,上传文件有误!');
} else {
console.log('未知错误');
}
}
})
}
</script>
</html>
附件2:SliceUploadController.class.php
<?php
namespace Home\Controller;
use Think\Controller;
class SliceUploadController extends Controller {
/*
* JS预览
* @author 阿旺
* */
public function index(){
$this->display();
}
/*
* 分片上传demo
* @author 阿旺
* */
public function upload(){
if($_POST){
$files = $_FILES['data'];
$arr['i'] = $_POST['index'];
$arr['shardCount'] = $_POST['total'];
$arr['totalsize'] = $_POST['totalsize'];
$arr['fileName'] = $_POST['name'];
if($files['error'] > 0){
$arr['status'] = 500;
exit(json_encode($arr));
}
if($files['error'] == 0){
/* 检测第一次上传的时候已经有同文件时,删除原来的文件 */
if ($arr['i'] == 1 && is_file('/Public/Upload/'. $arr['fileName']) && filesize($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']) == $arr['totalsize']) {
unlink($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']);
}
// 否则继续追加文件数据
if (!file_put_contents($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'.$arr['fileName'],file_get_contents($files['tmp_name']),FILE_APPEND)) {
$arr['status'] = 501;
exit(json_encode($arr));
}
// 在上传的最后片段时,检测文件是否完整(大小是否一致)
if ($arr['i'] == $arr['shardCount']) {
$arr['status'] = 200;
exit(json_encode($arr));
}
$arr['status'] = 201;
exit(json_encode($arr));
}else{
$arr['status'] = 502;
exit(json_encode($arr));
}
}else{
//echo "1";die;
$this->display();
}
}
/*
* JS断点上传
* @author 阿旺
* */
public function breakpoint($file_path = '') {
if ($_POST) {
$speed = 1024;//此参数为下载最大速度
$pos = strrpos($file_path, "/");
$file_name = substr($file_path, $pos + 1);
$file_size = filesize($file_path);
$ranges = $this->getRange($file_size);
$fh = fopen($file_path, "rb");
header('Cache-control: public');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $file_name);
if ($ranges != null) {
header('HTTP/1.1 206 Partial Content');
header('Accept-Ranges: bytes');
header(sprintf('Content-Length: %u', $ranges['end'] - $ranges['start']));
header(sprintf('Content-Range: bytes %s-%s/%s', $ranges['start'], $ranges['end'], $file_size));
fseek($fh, sprintf('%u', $ranges['start']));
} else {
header("HTTP/1.1 200 OK");
header(sprintf('Content-Length:%s', $file_size));
}
while(!feof($fh)) {
fread($fh, round($speed*1024, 0));
ob_flush();
//sleep(1);
}
} else {
$this->display();
}
}
/**
* 获取header range信息
* @param int $file_size 文件大小
* @return Array
* */
private function getRange($file_size){
if(isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])){
$range = $_SERVER['HTTP_RANGE'];
$range = preg_replace('/[\s|,].*/', '', $range);
$range = explode('-', substr($range, 6));
if(count($range)<2){
$range[1] = $file_size;
}
$range = array_combine(array('start','end'), $range);
if(empty($range['start'])){
$range['start'] = 0;
}
if(empty($range['end'])){
$range['end'] = $file_size;
}
return $range;
}
return null;
}
}