Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
longjinwen committed Dec 6, 2018
1 parent 8f31615 commit 78ac9a5
Show file tree
Hide file tree
Showing 19 changed files with 1,877 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"presets": [
"env"
]
}
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.js linguist-language=JavaScript
*.html linguist-language=JavaScript
*.php linguist-language=PHP
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
.idea
!dist/php/upload/.*


30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,28 @@
# simple-upload-slice-file
一款前端简单的分片上传文件小项目,支持进度计算,队列提交,MD5校验
# Simple upload slice file

#### 项目介绍

一款前端简单的分片上传文件小项目,不依赖jQuery,解决大文件上传过久,网络不稳定导致前功尽弃的问题。支持如下:
- 设置切片大小
- 错误重传
- 进度计算
- 队列提交
- 各种回调
- MD5校验
- IE10及其他主流浏览器(因使用原生FormData对象)


#### 开发构建

1. (c)npm install
2. npm run dev | build


#### 使用

1. dist目录下提供了前端提交和php演示文件。具体查看demo





130 changes: 130 additions & 0 deletions dist/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div>
<input type="file" class="file1" name="" id="file1">
<input type="file" class="file2" name="" id="file2">
<input type="file" class="file3" name="" id="file3">
<button onclick="upload()">发送</button>
</div>

<script src="index.js"></script>
<!--<script src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js"></script>-->
<script>
function upload() {

new SimpleUploadSliceFile({
url: 'http://127.0.0.1:11005/php/upload.php',
// 队列延迟发送,可用于调试,默认0(ms)
delay: 0,
// 切片大小(M),建议不要太小,默认10
chunkSile: 10,
// 一块切片连续上传失败数即终止该文件上传,默认10
sliceTryFreq: 3,
// 是否全部上传完毕发送MD5校验,默认false
isSendCheckMd5: true,
// 开启校验MD5之后,会在最后队列末尾发送一个请求,参数如下
/*
分别在请求头和请求体中携带‘upload-check-md5’,值类型为json
[
{
"upload-file-id":"SGf0ziqCvO31WpGzwQVJ1542616176023",
"md5":"17fffaa02b0b30be96db75fd58f8d21d",
"suffix":"mp4"
},
...
]
* */

callBack: {
// 上传进度回调
progress: function (res) {
// console.log(res);
for (var key in res) {
console.log('字段:' + key + '进度:' + parseInt(res[key].loadedTotalSize
/ res[key].totalSize * 100));
}
},
// 一个文件上传成功回调
singleSuccess: function (res) {
console.log('一个文件上传成功');
console.log(res);
},
// 全部上传成功回调
allSuccess: function (res) {
console.log('全部上传完成');
console.log(res);
},
// 某个文件由于某个切片上传连续失败回调
tryFreqError: function (err) {
console.log('某个文件由于某个切片上传连续失败回调');
console.log(err);
},
// 获取文件MD5,如果未开启MD5校验,该回调则不执行
getFileMd5: function (res) {
console.log('md5值');
console.log(res);
},
// 后端校验MD5结果,如果未开启MD5校验,该回调则不执行
checkMd5Result: function (res) {
console.log('MD5校验结果');
console.log(res);
}
}
}).appendHeader({ // 添加请求头参数
time: '123456789',
time2: '123456789'
}).appendData({ // 添加请求体参数
username: 'longjinwen',
age: 1
}).appendFile({ // 添加文件 支持格式如下

// music: $('#file1'), // jq对象,取第0个
// music: document.getElementById('file1'), // 原生dom对象,在获取FileList对象时,取第0个
// music: document.getElementById('file1').files, // 原生FileList对象 ,取第0个
// music: document.getElementById('file1').files[0], // 原生File对象

music: document.getElementById('file1').files[0],

music2: document.getElementById('file2').files[0],
music3: document.getElementById('file3').files[0],
}).send();


}
/**
* 1、完整演示内容如上
*
* 2、在提交中前端会自动添加以下请求头,用户标识前端目前发送文件的状态
* upload-file-id -> 该文件的唯一标识
* upload-total-size -> 该文件总大小
* upload-total-slice -> 该文件总共被切成了几块
* upload-now-order -> 当前所传输的第几块切片
* upload-size-range -> 正在提交的当前切片在文件里的大小所在区间
*
* 3、在提交文件的过程中,后端需返回 status code 如下
* 206 -> 表示该文件还没提交完成,后端根据响应头发的信息进行判断是否是最后一次提交
* 200 -> 表示一个文件提交完成
* 非以上 -> 一个切片如果上传超过指定次数,会终止该文件的提交,下一个文件的切片将不会终止
*
* 4、如果开启了MD5校验,那么在全部提交完成之后,会再发一个请求将md5值提交给后端,
* 在请求头和请求体中均会带 upload-file-md5 一个参数,如demo所示
*
*
*
*
*
*
*
* */


</script>


</body>
</html>
2 changes: 2 additions & 0 deletions dist/index.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/index.js.map

Large diffs are not rendered by default.

117 changes: 117 additions & 0 deletions dist/php/upload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
header('Content-type: text/json');


if (!function_exists('getallheaders')) {
function getallheaders()
{
$headers = [];
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ',
'-',
ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))
)] = $value;
}
}
return $headers;
}
}
$header = getallheaders();

// 这里写死前端三个字段

if (isset($_FILES['music']) || isset($_FILES['music2']) || isset($_FILES['music3'])) {
if (isset($_FILES['music'])) {
$field = 'music';
}
if (isset($_FILES['music2'])) {
$field = 'music2';
}
if (isset($_FILES['music3'])) {
$field = 'music3';
}

$uploaded_tmp = $_FILES[$field]['tmp_name'];

// 创建该切片储存文件夹
$path = "./upload/" . $header['upload-file-id'];
if (!file_exists($path)) {
mkdir($path);
}

$filename = $_FILES[$field]['name'];

$suffix = substr($filename, strrpos($filename, "."));

// 新的文件名称
$file = $path . "/" .
$header['upload-now-order'] . '-' . $header['upload-size-range']
. $suffix;
if (move_uploaded_file($uploaded_tmp, $file) && true) {

// 可以选择每次进行文件追加或者全部完成之后进行合并

if ($header['upload-total-slice'] === $header['upload-now-order']) {
// 最后一块切片上传完成
header('HTTP/1.1 200 ok');
$files = scandir($path);
// 合并文件
foreach ($files as $item) {
if (!in_array($item, ['.', '..'])) {
file_put_contents(
$path . '/' . $header['upload-file-id'] . $suffix,
file_get_contents($path . '/' . $item),
FILE_APPEND
);

unlink($path . '/' . $item);
}
}
exit(json_encode([
'msg' => '' . $header['upload-now-order'] . '块上传成功' . '-全部上传完成',
'header' => $header
]));

} else {

header('HTTP/1.1 206 next');
exit(json_encode([
'msg' => '' . $header['upload-now-order'] . '块上传成功',
'header' => $header
]));

}
} else {
// 返回非 200 206 前端会重新上传
header('HTTP/1.1 510 error');
echo json_encode([
'msg' => '' . $header['upload-now-order'] . '块上传失败',
'header' => $header
]);
}
} else if (isset($header['upload-file-md5'])) {
// 在这里进行MD5校验

$md5Data = json_decode($_POST['upload-file-md5'], true);

foreach ($md5Data as &$item) {
$path = "./upload/" . $item['upload-file-id'] . '/' . $item['upload-file-id'] . '.' . $item['suffix'];
$phpMd5 = md5_file($path);
if ($phpMd5 === $item['md5']) {

$item['status'] = 1;
} else {

$item['status'] = 0;
}
$item['phpMd5'] = $phpMd5;

}
echo json_encode([
'res' => $md5Data,
'header' => $header
]);
}
Empty file added dist/php/upload/.gitignore
Empty file.
21 changes: 21 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "simple-upload-slice-file",
"version": "1.0.1",
"description": "一款前端简单的分片上传文件小项目,支持进度计算,队列提交,MD5校验",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack -w",
"build": "webpack -p"
},
"author": "[email protected]",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"webpack": "^4.19.0",
"webpack-cli": "^3.1.2"
}
}
Loading

0 comments on commit 78ac9a5

Please sign in to comment.