2018-08-30php版 WebUploader上传几个G大文件单文件(分片)和 一次性上传多个文件

您现在的位置是: 首页 > PHP技术 > php版 WebUploader上传几个G大文件单文件(分片)和 一次性上传多个文件

637次阅读


最近帮客户做一个文件管理的项目,用到了百度插件 webuploader,感觉非常实用,可分片上传几个G的大文件,何为分片,就是将一个大文件分成几M的小文件,多次上传,还可以一次性上传多个。特别记录这个实用的插件,分享出来学习学习


文档地址:WebUploader API文档


一、前端页面代码


<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="文件上传,图片上传" />
    <meta name="description" content="Helloweba演示平台,演示XHTML、CSS、jquery、PHP案例和示例" />
    <title>演示:功能强大的上传控件 WebUploader</title>
    <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="css/webuploader.css">
    <link rel="stylesheet" type="text/css" href="css/style.css">
    <style>
        .demo{min-width:360px;margin:30px auto;padding:10px 20px}
        .demo h3{line-height:40px; font-weight: bold;}
        .file-item{float: left; position: relative; width: 110px;height: 110px; margin: 0 20px 20px 0; padding: 4px;}
        .file-item .info{overflow: hidden;}
        .uploader-list{width: 100%; overflow: hidden;}
    </style>
</head>
<body>
<div class="container">
    <header>
        <div class="row">
            <div class="col-md-3 col-xs-12"><h1 class="logo"><a href="http://www.helloweba.com" title="返回helloweba首页">helloweba</a></h1></div>
            <div class="col-md-9 text-right"><!--<script src="/js/ad_js/demo_topad.js" type="text/javascript"></script>--></div>
        </div>
    </header>
    <div class="row main">
        <h2 class="top_title"><span class="glyphicon glyphicon-menu-left" aria-hidden="true"></span><a href="http://www.helloweba.com/view-blog-375.html">功能强大的上传控件 WebUploader</a></h2>
        <div class="demo">
            <h3>1、文件上传</h3>
            <div id="uploadfile">
                <!--用来存放文件信息-->
                <div id="thelist" class="uploader-list"></div>
                <div class="form-group form-inline">
                    <div id="picker" style="float:left">选择文件</div> &nbsp;
                    <button id="ctlBtn" class="btn btn-default" style="padding:8px 15px;">开始上传</button>
                </div>
            </div>
        </div>
        <div class="demo">
            <h3>2、图片上传</h3>
            <div id="uploadimg">
                <div id="fileList" class="uploader-list"></div>
                <div id="imgPicker">选择图片</div>
            </div>
        </div>
        <!--<div class="ad_76090"><script src="/js/ad_js/bd_76090.js" type="text/javascript"></script></div><br/>-->
        <div class="demo">
            <h3>3、高级上传</h3>
            <div id="uploader">
                <div class="queueList">
                    <div id="dndArea" class="placeholder">
                        <div id="filePicker"></div>
                        <p>或将照片拖到这里,单次最多可选1000张</p>
                    </div>
                </div>
                <div class="statusBar" style="display:none;">
                    <div class="progress">
                        <span class="text">0%</span>
                        <span class="percentage"></span>
                    </div><div class="info"></div>
                    <div class="btns">
                        <div id="filePicker2"></div><div class="uploadBtn">开始上传</div>
                    </div>
                </div>
            </div>
        </div>

    </div>
    <footer>
        <p>Powered by helloweba.com  允许转载、修改和使用本站的DEMO,但请注明出处:<a href="http://www.helloweba.com">www.helloweba.com</a></p>
    </footer>
</div>

<script src="//cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript" src="./js/webuploader.min.js"></script>
<script type="text/javascript" src="./js/upload.js"></script>
<script>
    $(function(){

        var $list = $('#thelist'),
                $btn = $('#ctlBtn');
        var allMaxSize = 200; //限制大小200M,所有被选文件,超出选择不上

        var uploader = WebUploader.create({
            resize: false, // 不压缩image
            swf: 'js/uploader.swf', // swf文件路径
            server: 'upload.php', // 文件接收服务端。
            chunked: true, //是否要分片处理大文件上传
            chunkSize:2*1024*1024, //分片上传,每片2M,默认是5M
            pick:{
                id: '#picker',
                multiple: false // false 单选,true 多选
            }, // 选择文件的按钮。可选
            fileSizeLimit: allMaxSize*1024*1024, //限制大小200M,所有被选文件,超出选择不上
            //auto: false //选择文件后是否自动上传
            // chunkRetry : 2, //如果某个分片由于网络问题出错,允许自动重传次数
            //runtimeOrder: 'html5,flash',
            // accept: {
            //   title: 'Images',
            //   extensions: 'gif,jpg,jpeg,bmp,png',
            //   mimeTypes: 'image/*'
            // }
        });
        // 当有文件被添加进队列的时候
        uploader.on( 'fileQueued', function( file ) {
            $list.append( '<div id="' + file.id + '" class="item">' +
                    '<h4 class="info">' + file.name + '</h4>' +
                    '<p class="state">等待上传...</p>' +
                    '</div>' );
        });
        // 文件上传过程中创建进度条实时显示。
        uploader.on( 'uploadProgress', function( file, percentage ) {
            var $li = $( '#'+file.id ),
                    $percent = $li.find('.progress .progress-bar');

            // 避免重复创建
            if ( !$percent.length ) {
                $percent = $('<div class="progress progress-striped active">' +
                        '<div class="progress-bar" role="progressbar" style="width: 0%">' +
                        '</div>' +
                        '</div>').appendTo( $li ).find('.progress-bar');
            }

            $li.find('p.state').text('上传中');

            $percent.css( 'width', percentage * 100 + '%' );
        });
        // 文件上传成功
        uploader.on( 'uploadSuccess', function( file, res ) {
            if(res.status==1){
                $( '#'+file.id ).find('p.state').text('已上传');
            }else{
                $( '#'+file.id ).find('p.state').text(res.result.message);
            }
        });

        //  验证大小
        uploader.on("error",function (file){
            if(file == "Q_EXCEED_SIZE_LIMIT"){
                Tools.toast("非共享文件,限制单个文件大小不超过200M");
            }
        });

        // 文件上传失败,显示上传出错
        uploader.on( 'uploadError', function( file ) {
            $( '#'+file.id ).find('p.state').text('上传出错');
        });
        // 完成上传完
        uploader.on( 'uploadComplete', function( file ) {
            $( '#'+file.id ).find('.progress').fadeOut();
        });

        $btn.on('click', function () {

            if ($(this).hasClass('disabled')) {
                return false;
            }
            uploader.upload();
            // if (state === 'ready') {
            //     uploader.upload();
            // } else if (state === 'paused') {
            //     uploader.upload();
            // } else if (state === 'uploading') {
            //     uploader.stop();
            // }
        });

    });

    //上传图片
    // 初始化Web Uploader
    var uploader = WebUploader.create({

        // 选完文件后,是否自动上传。
        auto: true,

        // swf文件路径
        swf: 'js/Uploader.swf',

        // 文件接收服务端。
        server: 'upload.php',

        // 选择文件的按钮。可选。
        // 内部根据当前运行是创建,可能是input元素,也可能是flash.
        pick: '#imgPicker',

        // 只允许选择图片文件。
        accept: {
            title: 'Images',
            extensions: 'gif,jpg,jpeg,bmp,png',
            mimeTypes: 'image/*'
        }
    });

    // 当有文件添加进来的时候
    uploader.on( 'fileQueued', function( file ) {
        var $list = $("#fileList"),
                $li = $(
                        '<div id="' + file.id + '" class="file-item thumbnail">' +
                        '<img>' +
                        '<div class="info">' + file.name + '</div>' +
                        '</div>'
                ),
                $img = $li.find('img');


        // $list为容器jQuery实例
        $list.append( $li );

        // 创建缩略图
        // 如果为非图片文件,可以不用调用此方法。
        // thumbnailWidth x thumbnailHeight 为 100 x 100
        uploader.makeThumb( file, function( error, src ) {
            if ( error ) {
                $img.replaceWith('<span>不能预览</span>');
                return;
            }

            $img.attr( 'src', src );
        }, 100, 100 );
    });
    // 文件上传过程中创建进度条实时显示。
    uploader.on( 'uploadProgress', function( file, percentage ) {
        var $li = $( '#'+file.id ),
                $percent = $li.find('.progress span');

        // 避免重复创建
        if ( !$percent.length ) {
            $percent = $('<p class="progress"><span></span></p>')
                    .appendTo( $li )
                    .find('span');
        }

        $percent.css( 'width', percentage * 100 + '%' );
    });

    // 文件上传成功,给item添加成功class, 用样式标记上传成功。
    uploader.on( 'uploadSuccess', function( file ) {
        $( '#'+file.id ).addClass('upload-state-done');
    });

    // 文件上传失败,显示上传出错。
    uploader.on( 'uploadError', function( file ) {
        var $li = $( '#'+file.id ),
                $error = $li.find('div.error');

        // 避免重复创建
        if ( !$error.length ) {
            $error = $('<div class="error"></div>').appendTo( $li );
        }

        $error.text('上传失败');
    });

    // 完成上传完了,成功或者失败,先删除进度条。
    uploader.on( 'uploadComplete', function( file ) {
        $( '#'+file.id ).find('.progress').remove();
    });

</script>
</body>
</html>


二、PHP上传文件代码


<?php


header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

function show_json($status = 1, $return = NULL) {

    $ret = array('status' => $status, 'result' => array());
    if (!is_array($return)) {
        if ($return) {
            $ret['result']['message'] = $return;
        }
        exit(json_encode($ret));
    } else {
        $ret['result'] = $return;
    }
    exit(json_encode($ret));

}


if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    exit; // finish preflight CORS requests here
}
if ( !empty($_REQUEST['debug']) ) {
    $random = rand(0, intval($_REQUEST['debug']) );
    if ( $random === 0 ) {
        header("HTTP/1.0 500 Internal Server Error");
        exit;
    }
}

@set_time_limit(0);

$targetDir = 'uploads/file_material_tmp';
$uploadDir = 'uploads/file_material/'.date('Ymd');

$cleanupTargetDir = true; // Remove old files
$maxFileAge = 5 * 3600; // Temp file age in seconds
$mode = 0777; // 0777 权限

// Create target dir
if (!file_exists($targetDir)) {
    @mkdir($targetDir, $mode,true);
    @chmod($targetDir, $mode);
}
// Create target dir
if (!file_exists($uploadDir)) {
    @mkdir($uploadDir, $mode, true);
    @chmod($uploadDir, $mode);
}
// Get a file name
if (isset($_REQUEST["name"])) {
    $fileName = $_REQUEST["name"];
} elseif (!empty($_FILES)) {
    $fileName = $_FILES["file"]["name"];
} else {
    $fileName = uniqid("file_");
}
$oldName = $fileName;
$filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
// $uploadPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
// Chunking might be enabled
$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1;
// Remove old temp files
if ($cleanupTargetDir) {
    if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
        show_json(100, 'Failed to open temp directory.');
    }
    while (($file = readdir($dir)) !== false) {
        $tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
        // If temp file is current file proceed to the next
        if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
            continue;
        }
        // Remove temp file if it is older than the max age and is not the current file
        if (preg_match('/\.(part|parttmp)$/', $file) && (@filemtime($tmpfilePath) < time() - $maxFileAge)) {
            @unlink($tmpfilePath);
        }
    }
    closedir($dir);
}

// Open temp file
if (!$out = @fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
    show_json(102, 'Failed to open output stream.');
}
if (!empty($_FILES)) {
    if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
        show_json(103, 'Failed to move uploaded file.');
    }
    // Read binary input stream and append it to temp file
    if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
        show_json(101, 'Failed to open input stream.');
    }
} else {
    if (!$in = @fopen("php://input", "rb")) {
        show_json(101, 'Failed to open input stream.');
    }
}
while ($buff = fread($in, 4096)) {
    fwrite($out, $buff);
}
@fclose($out);
@fclose($in);
rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");
$index = 0;
$done = true;
for( $index = 0; $index < $chunks; $index++ ) {
    if ( !file_exists("{$filePath}_{$index}.part") ) {
        $done = false;
        break;
    }
}

if ( $done ) {
    $pathInfo = pathinfo($fileName);
    $hashStr = substr(md5($pathInfo['basename']),8,16);
    $hashName = time() . $hashStr . '.' .$pathInfo['extension'];
    $uploadPath = $uploadDir . DIRECTORY_SEPARATOR .$hashName;

    if (!$out = @fopen($uploadPath, "wb")) {
        show_json(102, 'Failed to open output stream.');
    }
    if ( flock($out, LOCK_EX) ) {
        for( $index = 0; $index < $chunks; $index++ ) {
            if (!$in = @fopen("{$filePath}_{$index}.part", "rb")) {
                break;
            }
            while ($buff = fread($in, 4096)) {
                fwrite($out, $buff);
            }
            @fclose($in);
            @unlink("{$filePath}_{$index}.part");
        }
        flock($out, LOCK_UN);
    }
    @fclose($out);
    $response = [
        'success'=>true,
        'oldName'=>$oldName,
        'filePaht'=>$uploadPath,
        'fileSuffixes'=>$pathInfo['extension'],
        'hashName' => $hashName
    ];

    // 当status返回1时,为上传成功,其他则失败
    show_json(1, array('message' => '上传成功',  'info' => $response));

}


?>


三、上传时的效果图


php版 WebUploader上传几个G大文件单文件(分片)和 一次性上传多个文件.png


源码下载