js代碼
<html lang="cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>分塊上傳</title>
<style>
#progressBlo {
width: 300px;
height: 20px;
background-color: #f7f7f7;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 4px;
background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);
}
#progress {
background-color: #149bdf;
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-size: 40px 40px;
height: 100%;
}
form {
margin-top: 50px;
}
</style>
</head>
<body>
<div id="progressBlo">
<div id="progress" style="width: 0%;" progress="0"></div>
</div>
<form action="upload.php">
<input type="file" name="file" id="file">
<div id="msg">等待開始</div>
<input type="button" value="停止" id="stopBtn">
</form>
<script>
var fileElem = document.getElementById("file");
var progressObj = document.getElementById('progress');
var msgElem = document.getElementById("msg");
var stopBtn = document.getElementById('stopBtn');
var upload = null;
fileElem.onchange = function () {
if (this.files.length > 0) {
upload = new Upload(this.files[0]);
upload.start();
this.value = null;
}
}
stopBtn.onclick = function () {
upload.stop();
}
function Upload(file)
{
var file = file;
var status = 0;
const BLOCK_SIZE = 1024 * 256; // 256k
var blockIdx = 1;
var blockTotal = Math.ceil(file.size / BLOCK_SIZE);
var blobStart = 0;
var blobEnd = blobStart + BLOCK_SIZE;
// 開始上傳
this.start = function () {
msgElem.innerText = "正在上傳:" + file.name;
status = 1;
sendFile(cutFile());
}
// 停止文件上傳
this.stop = function() {
if (status != 1) {
msgElem.innerText = "已停止";
return;
}
msgElem.innerText = "正在停止";
status = -1;
}
// 切割文件
function cutFile() {
var fileBlob = file.slice(blobStart, blobEnd);
blobStart = blobEnd;
blobEnd = blobStart + BLOCK_SIZE;
return fileBlob;
};
// 發送文件
function sendFile(blob) {
var formData = new FormData();
formData.append('file', blob);
formData.append('blockIdx', blockIdx);
formData.append('blockTotal', blockTotal);
formData.append('fileName', file.name);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'upload.php', true);
xhr.onreadystatechange = function () {
// 請求已完成
if (xhr.readyState == 4) {
blockIdx += 1;
// 是否停止
if (status != 1) {
msgElem.innerText = "已停止";
return false;
}
// 繼續上傳下一塊
if (blobStart < file.size) {
progressObj.style.width = Math.min(100, (blockIdx / blockTotal) * 100) + '%';
sendFile(cutFile());
} else {
progressObj.style.width = '100%';
msgElem.innerText = "上傳完成";
status = 2;
}
}
}
xhr.send(formData);
}
}
</script>
</body>
</html>
後端PHP
<?php
class Upload
{
private $saveDir = './uploads/down'; //上傳目錄
private $tmpFile; // PHP文件臨時目錄
private $fileName; // 文件名
private $blockIdx; // 第幾個文件塊
private $blockTotal; // 文件塊總數
public function __construct($tmpPath, $fileName, $blobNum, $totalBlobNum)
{
$this->tmpFile = $tmpPath;
$this->fileName = $fileName;
$this->blockIdx = $blobNum;
$this->blockTotal = $totalBlobNum;
// 文件夾
if (file_exists($this->saveDir) == false) {
mkdir($this->saveDir, 0666, true);
}
$this->moveFile();
$this->fileMerge();
}
// 判斷是否是最後一塊,如果是則進行文件合成並且刪除文件塊
private function fileMerge()
{
if ($this->blockIdx == $this->blockTotal) {
$blob = '';
for ($i = 1; $i <= $this->blockTotal; $i++) {
$blob .= file_get_contents($this->saveDir . '/' . $this->fileName . '__' . $i);
}
file_put_contents($this->saveDir . '/' . $this->fileName, $blob);
$this->deleteFileBlob();
}
}
// 刪除文件塊
private function deleteFileBlob()
{
for ($i = 1; $i <= $this->blockTotal; $i++) {
@unlink($this->saveDir . '/' . $this->fileName . '__' . $i);
}
}
// 移動文件
private function moveFile()
{
$this->touchDir();
$filename = $this->saveDir . '/' . $this->fileName . '__' . $this->blockIdx;
move_uploaded_file($this->tmpFile, $filename);
}
// API返回數據
public function apiReturn()
{
if ($this->blockIdx == $this->blockTotal) {
if (file_exists($this->saveDir . '/' . $this->fileName)) {
$data['code'] = 2;
$data['file_path'] = 'http://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['DOCUMENT_URI']) . str_replace('.', '', $this->saveDir) . '/' . $this->fileName;
}
} else {
if (file_exists($this->saveDir . '/' . $this->fileName . '__' . $this->blockIdx)) {
$data['code'] = 1;
$data['file_path'] = '';
}
}
header('Content-type: application/json');
echo json_encode($data);
}
// 建立上傳文件夾
private function touchDir()
{
if (!file_exists($this->saveDir)) {
return mkdir($this->saveDir);
}
}
}
//實例化並獲取系統變量傳參
$upload = new Upload($_FILES['file']['tmp_name'], $_POST['fileName'], $_POST['blockIdx'], $_POST['blockTotal']);
//調用方法,返回結果
$upload->apiReturn();