大文件切片上传

作者:Shine 发布于:2017-08-16 14:52:51 浏览:1036次 分类:PHP

利用slice(start,end)方法对文件进行区域式的一个切割,每一个小部分一小部分的传过去 后台接收 并且存储 继续和停止的判断就是最简单的页面变量来实现的定义全局的

<?php
    use yii\helpers\Url;
    $this->registerJsFile('/my-layer/layer.js',['depends' => [\yii\web\JqueryAsset::className()]]);
?>

<div class="progress">
    <div class="progress-bar progress-bar-info progress-bar-striped active" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0" id="progress">
    </div>
    <span id="progress-num">0%</span>
</div>

<input type="file" class="form-control" id="file">
<h2 id="pre"></h2>
<button type="button" id="bg_to" class="btn btn-default">上传</button>
<button type="button" id="sendStop" class="btn btn-default">停止</button>
<button type="button" id="sendStart" class="btn btn-default">继续</button>

<?php
$uploadUrl = Url::to(['tool/upload']);
$mergeUrl = Url::to(['tool/merge-files']);
$js = <<<JS
    const BYTES_PER_CHUNK = 1024 * 102.4; // 每个文件切片大小定为0.1MB .
    var slices;
    var totalSlices;
    var start = 0;
    var end = BYTES_PER_CHUNK;
    var index = 0;
    var stop = 0;
    var uploadUrl = '$uploadUrl';
    var mergeUrl = '$mergeUrl';

    function init(){
        slices = 0;
        totalSlices = 0;
        start = 0;
        end = 0;
        index = 0;
        stop = 0;
        document.getElementById("progress").style.width = "0";
        document.getElementById("progress").setAttribute('aria-valuenow', 0);
        document.getElementById("progress-num").innerHTML = "0%";
    }

    $("#bg_to").click(function(){
        var file=$("#file");
        if($.trim(file.val())==""){
            layer.msg("请选择文件");
            return false;
        }
        sendRequest()
    });

    $('#sendStop').click(function(){
        if(start==0){
            layer.msg("未检测到文件上传");
            return false
        }
        stop = 1
    });

    $('#sendStart').click(function(){
        if(start==0){
            layer.msg("未检测到文件上传");
            return false
        }
        stop = 0;
        sendRequest();
    })

    //发送请求
    sendRequest =  function () {
        var blob = document.getElementById('file').files[0];
        // 计算文件切片总数
        slices = Math.ceil(blob.size / BYTES_PER_CHUNK);
        totalSlices= slices;
        if(stop == 1){
            layer.msg("停止上传");
            return false
        }
        if(start < blob.size) {
            if(end > blob.size) {
                end = blob.size;
            }
            uploadFile(blob, index, start, end);
            start = end;
            end = start + BYTES_PER_CHUNK;
            index++;
        }
    }
    //上传文件
    uploadFile =   function (blob, index, start, end) {
        var xhr;
        var fd;
        var chunk;
        xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if(xhr.readyState == 4) {
                if(xhr.responseText) {
                    layer.msg(xhr.responseText);
                }
                if(slices>1){
                    slices--;
                }
                var percent=100*index/slices;
                if(percent>100){
                    percent=100;
                }else if(percent==0&&slices==1){
                    percent=100;
                }
                document.getElementById("progress").style.width = percent+"%";
                document.getElementById("progress").setAttribute('aria-valuenow', percent);
                document.getElementById("progress-num").innerHTML = parseInt(percent)+"%";
                // 如果所有文件切片都成功发送,发送文件合并请求。
                if(percent == 100) {
                    mergeFile(blob);
                    start = 0;
                    layer.msg('文件上传完毕');
                    setTimeout(function(){init();}, 1000);
                }else{
                    if(stop!=1){
                        sendRequest();
                    }
                }
            }
        };

        xhr.upload.onprogress = function(event){
            var pre = (100 * event.loaded / event.total);
            console.log(pre);
            //document.getElementById("progress").style.width = (index / totalSlices) + pre +"%";
            //document.getElementById("progress").setAttribute('aria-valuenow', (index / totalSlices) + pre );
            //document.getElementById("progress-num").innerHTML = parseInt((index / totalSlices) + pre )+"%";
        }

        chunk = blob.slice(start,end);//切割文件
        //构造form数据
        fd = new FormData();
        fd.append("file", chunk);
        fd.append("name", blob.name);
        fd.append("index", index);
        xhr.open("POST", uploadUrl, true);
        //设置二进制文边界件头
        xhr.setRequestHeader("X_Requested_With", location.href.split("/")[3].replace(/[^a-z]+/g, "$"));
        xhr.send(fd);
    };

    mergeFile = function (blob) {
        var xhr;
        var fd;
        xhr = new XMLHttpRequest();
        fd = new FormData();
        fd.append("name", blob.name);
        fd.append("index", totalSlices);
        xhr.open("POST", mergeUrl, true);
        xhr.setRequestHeader("X_Requested_With", location.href.split("/")[3].replace(/[^a-z]+/g, "$"));
        xhr.send(fd);
    }
JS;
$this->registerJs($js);
?>

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/8/16
 * Time: 10:27
 */

namespace frontend\controllers;

use Yii;
use yii\web\Controller;
use yii\web\NotFoundHttpException;

/**
 * ToolController implements the CRUD actions for User model.
 */
class ToolController extends Controller
{
    public $enableCsrfValidation = false;

    public function actionSliceFileUpload(){
        return $this->render('slice-file-upload');
    }

    public function actionUpload(){
        $fileName = Yii::$app->request->post('name');
        $index    = Yii::$app->request->post('index');

        $target   = "./slice-file/" .iconv("utf-8","gbk", $fileName) . '-' . $index;
        move_uploaded_file($_FILES['file']['tmp_name'], $target);
        usleep(200);
    }

    public function actionMergeFiles(){
        $fileName = Yii::$app->request->post('name');
        $total = Yii::$app->request->post('index');

        $target = "./slice-file/" . iconv("utf-8", "gbk", $fileName);
        $dst = fopen($target, 'wb');

        for($i = 0; $i < $total; $i++) {
            $slice = $target . '-' . $i;
            $src   = fopen($slice, 'rb');
            stream_copy_to_stream($src, $dst);
            fclose($src);
            unlink($slice);
        }
        fclose($dst);
    }
}

预览地址:www.jumoshen.cn/tool/slice-file-upload.html

标签: 大文件上传
声明:文章内容由作者原创或整理,转载请标明出处!
暂留位置!--请勿随意修改