返回 导航

其他

hangge.com

JS - 文件上传组件WebUploader使用详解2(MD5秒传、判断是否已经上传过)

作者:hangge | 2019-01-14 08:10
    文件秒传的实现原理其实就是在文件上传前,把内容读取出来,算出 md5 值,然后通过 ajax 与服务端进行验证, 然后根据结果选择继续上传还是跳过上传。
    由于这个验证行为是异步的,所以这里我们要借助 WebUploader 提供的 hookWebUploader.Uploader.register)来实现。即在上传前的 hanlder 里面返回一个 promise 对象,这样 WebUploader 就会等待此过程,监听此 promise 的完成事件,自动继续。

1,效果图

(1)当我们选择文件后,会自动计算该文件的 md5 值(如果文件太大,需要等待一会儿,同时会有计算进度显示)

(2)当第一次上次时,效果同以前一样,正常上传。

(3)如果服务器已存在该文件,点击上传时,客户端这边会立刻弹出提示,且任务变成已完成(不再上传)

2,样例代码

(1)客户端代码(index.html
高亮部分代码为在前文基础上新增的部分,即 MD5 验证的相关代码。
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <!--引入CSS-->
    <link rel="stylesheet" type="text/css" href="webuploader/webuploader.css">
    <!--引入JS-->
    <script type="text/javascript" src="js/jquery-1.11.1.js"></script>
    <script type="text/javascript" src="webuploader/webuploader.js"></script>
    <script type="text/javascript">
      $(function() {
        //开始上传按钮
        var $btn = $('#ctlBtn');
        //文件信息显示区域
        var $list = $('#thelist');
        //当前状态
        var state = 'pending';
        //待上传文件的md5值(key为file id)
        var md5 = {};

        // WebUploader提供的钩子(hook),在文件上传前先判断服务是否已存在这个文件
        WebUploader.Uploader.register({
          'before-send-file': 'beforeSendFile' //整个文件上传前
        }, {
          beforeSendFile: function( file ) {
            var that = this;
            var deferred = WebUploader.Deferred();
            //上传前请求服务端,判断文件是否已经上传过
            $.post("http://www.hangge.com/checkFileExist.php", { md5: md5[file.id] },
            function(data){
              if (data == '1') {
                //跳过如果存在则跳过
                that.owner.skipFile( file );
                alert("文件已存在,无需上传!");
              }
              // 继续后面行为
              deferred.resolve();
            });
            return deferred.promise();
          }
        });

        //初始化Web Uploader
        var uploader = WebUploader.create({
            // swf文件路径
            swf: 'webuploader/Uploader.swf',
            // 文件接收服务端。
            server: 'http://www.hangge.com/upload.php',
            // 选择文件的按钮。可选。
            // 内部根据当前运行是创建,可能是input元素,也可能是flash.
            pick: '#picker'
        });

        // 当有文件被添加进队列的时候(选择文件后调用)
        uploader.on( 'fileQueued', function( file ) {
          $list.append( '<div id="' + file.id + '" class="item">' +
              '<h4 class="info">' + file.name + '</h4>' +
              '<p class="md5"></p>' +
              '<p class="state"></p>' +
          '</div>' );
          //获取文件MD5值
          md5[file.id] = '';
          uploader.md5File( file )// 及时显示进度
            .progress(function(percentage) {
              $( '#'+file.id ).find('.md5').text('读取文件:'+parseInt(percentage*100)+"%");
            })
            // 完成
            .then(function(val) {
              md5[file.id] = val;
              $( '#'+file.id ).find('.md5').text('md5值:' + val);
              $( '#'+file.id ).find('.state').text('等待上传...');
            });
        });

        // 文件上传过程中创建进度条实时显示。
        uploader.on( 'uploadProgress', function( file, percentage ) {
            var $li = $( '#'+file.id );
            $li.find('p.state').text('上传中(' + parseInt(percentage * 100) + '%)');
        });

        // 文件上传成功后会调用
        uploader.on( 'uploadSuccess', function( file ) {
            $( '#'+file.id ).find('p.state').text('已上传');
        });

        // 文件上传失败后会调用
        uploader.on( 'uploadError', function( file ) {
            $( '#'+file.id ).find('p.state').text('上传出错');
        });

        // 文件上传完毕后会调用(不管成功还是失败)
        uploader.on( 'uploadComplete', function( file ) {
            $( '#'+file.id ).find('.progress').fadeOut();
        });

        // all事件(所有的事件触发都会响应到)
        uploader.on( 'all', function( type ) {
            if ( type === 'startUpload' ) {
                state = 'uploading';
            } else if ( type === 'stopUpload' ) {
                state = 'paused';
            } else if ( type === 'uploadFinished' ) {
                state = 'done';
            }

            if ( state === 'uploading' ) {
                $btn.text('暂停上传');
            } else {
                $btn.text('开始上传');
            }
        });

        // 开始上传按钮点击事件响应
        $btn.on( 'click', function() {
            if ( state === 'uploading' ) {
                uploader.stop();
            } else {
                // 不存在则上传文件
                uploader.upload();
            }
        });
      });
    </script>
    <style>
      #picker {
        display: inline-block;
      }
      #ctlBtn {
        position: relative;
        display: inline-block;
        cursor: pointer;
        background: #EFEFEF;
        padding: 10px 15px;
        color: #2E2E2E;
        text-align: center;
        border-radius: 3px;
        overflow: hidden;
      }
      #ctlBtn:hover {
        background: #DDDDDD;
      }
    </style>
  </head>
  <body>
    <div id="uploader" class="wu-example">
        <div class="btns">
            <div id="picker">选择文件</div>
            <div id="ctlBtn" class="webuploader-upload">开始上传</div>
        </div>
        <!--用来存放文件信息-->
        <div id="thelist" class="uploader-list"></div>
    </div>
  </body>
</html>


(2)服务端验证代码(checkFileExist.php
其内部逻辑是遍历文件夹下所有文件,计算出 md5 值,并与提交的 md5 做比较。如果有相同的话则表示存在。
<?php 
  //获取需要验证的md5值
  $md5 = $_POST["md5"];
  //验证结果
  $exist = 0;
  //切换目录
  chdir($_SERVER["DOCUMENT_ROOT"]."/uploadFiles/");
  //遍历该目录下的所有文件
  foreach(glob('*.*') as $filename) {
    //计算每个文件的md5值并判读
    if (strcmp($md5, md5_file($filename)) == 0){
      $exist = 1;
      break;
    }
  }
  echo $exist
?>

(3)服务端文件上传代码(upload.php
这个与前文相比没有变化,具体见:JS - 文件上传组件WebUploader使用详解1(带进度的文件上传)
评论

全部评论(0)

回到顶部