【HTML部分】

<div id="container">
<a id="selectfiles" href="javascript:void(0);" class='btn'  onclick="document.getElementById('c-files').click();">选择文件</a>
<input id="c-files"  class="form-control" name="file" type="file"  style="display: none">
&nbsp;&nbsp;&nbsp;&nbsp;
<a id="postfiles" href="javascript:void(0);" class='btn'>开始上传</a>
<p id="filetypeTips" class="goods_sx">支持上传文件格式:PDF,PSD,AI,CDR</p>
<p class="goods_sx">当前选择:<span id="file_info"></span></p>
<p class="goods_sx">上传文件:<span id="server_info"></span></p>
</div>
<div  class="step_line"><div id="step_line"></div></div>

【Javascript部分】

<script>
var selectfiles_button =document.getElementById("c-files");
var postfiles_button =document.getElementById("postfiles");
var file_info_button =document.getElementById("file_info");
var step_line_button =document.getElementById('step_line');
var server_info_button =document.getElementById('server_info');
//上传文件侦测侦测
selectfiles_button.addEventListener("change",(e)=>{
    //console.log(e.target.files[0]);
    step_line_button.innerHTML ='';
    file_info_button.innerHTML ='';
    var reader = new FileReader(); 
    var file =e.target.files[0];
    //reader.readAsDataURL(e.target.files[0]); 
    reader.readAsDataURL(file); 
    reader.onloadstart= function(){  
      console.log(reader.result); 
      //selectfiles_button.setAttribute("value",reader.result);
      file_info_button.innerHTML= file.name;
    } 
})

//上传POST
postfiles_button.addEventListener("click", function(){
        
           // 文件对象
            var file = selectfiles_button.files[0];
            // 分块的大小 默认4M
            var block = 1024 * 1024 * 10;
            // 文件大小
            var fileSize = file.size;
            // 总的分块数
            var totalCount = Math.ceil(fileSize / block);
            var start = 0,
                end = 0;
            // 原文件名
            var fileName = file.name;
            // 生成随机的前缀
            var prfix = Math.random();
        //返回服务器文件地址
        var server_url ='1';
        var init_b =0;
            for(var num = 0; num <totalCount; num++) {
            //块数据
                start = num * block;
                end = start + block;
                blockFile = file.slice(start, end);
                // 组装 FormData() 对象
                var formData = new FormData();
                formData.append('file', blockFile);
                formData.append('num', num);
                formData.append('fileName', fileName);
                formData.append('prfix', prfix);
                formData.append('totalCount', totalCount);
        //AJAX请求
        var xhr =new XMLHttpRequest(num);
        //采用同步的方式
        xhr.open('post','user.php?act=blob',false);
        //获取进度条对象
        var jdt=document.querySelector('#step_line');
               //返回状态
        xhr.onload = function(dd) {
        //console.log('ff_'+num);
        //console.log(jdt);
            if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                          //console.log(this.response);
                            //刷新进度条
                        var curr =num+1;
                        var total =totalCount;
                        var  percent = Math.ceil((curr/total)*100);
                        var len =  percent * 300 /100;
                        jdt.innerHTML=percent+'%';
                        jdt.setAttribute("style","width:"+len+"px;background:green;border-radius: 10px;");
                        //赋值
                        var result =JSON.parse(this.response);
                        //console.log(result);
                        if(result.code==1){
                            if(typeof(result.url)=='undefined'||result.url==''||result.url==null){
                            server_info_button.innerHTML='';
                            }else{
                            server_info_button.innerHTML=result.url;
                            }
                        }else{
                          //失败要回滚 删除临时缓存
                        
                        }
                    } else {
                       console.error(xhr.statusText);
                    }
            }
        };
        //设置请求超时的时间
        //xhr.timeout = 3000;
        init_b =1;
        //发送请求
        xhr.send(formData);
        }    

});
</script>

【PHP后端】

/**分块上传**/
function action_blob(){
       //设置json格式
        header('content-type:application/json;charset=utf-8');
        // 接收 post 和FILES参数
        $data = $_POST;
        $file = $_FILES;
        if(!$file['file']){
          exit(json_encode(['code'=>0,'msg'=>'文件不存在']));
        }
        //创建目录
        $dir=ROOT_PATH .'data/block/'; //块临时目录
        $save_dir=ROOT_PATH .'data/printfile/'; //最终目录
        if(!is_dir($dir)){
        mkdir($dir,0777);
        }
        if(!is_dir($save_dir)){
        mkdir($save_dir,0777);
        }
        // 分块文件位置
        $block_path =$dir. $data['prfix']. '_';
        //临时保存分块
        $save_key =$dir.$data['prfix'].'_' . $data['num'];
        move_uploaded_file($file['file']['tmp_name'],$save_key );
        $done = 0;
        $file_url='';
        // 判断文件是否上传完成
        if ($data['num'] == ($data['totalCount'] - 1)) {
                $ext = pathinfo($data['fileName'], PATHINFO_EXTENSION);
                $newFileName = $data['prfix'] . '.' . $ext;
                // 合并文件 注意file_put_contents 添加FILE_APPEND 避免替换数据
                for($i = 0; $i < $data['totalCount']; $i++) {
                 file_put_contents($save_dir. $newFileName, file_get_contents($block_path.$i),FILE_APPEND);
                }
                // 合并完成后删除分块文件
                for($i = 0; $i < $data['totalCount']; $i++) {
                unlink($dir. $data['prfix'] . '_' . $i);
                }
                $done = 1;
                $file_url=$save_dir.$newFileName;
                //上传完成后返回
              exit(json_encode(['code'=>1,'msg'=>'文件上传成功','url'=>$file_url]));
        }
      //返回状态
      exit(json_encode(['code'=>1,'msg'=>'分块上传成功']));
}

 
class aes{

    const KEY="Eheyin2017042424";

    const IV ="damiyinEheyin888";

    /**

     * pkcs7补码

     * @param string $string  明文

     * @param int $blocksize Blocksize , 以 byte 为单位

     * @return String

     */ 

    private function addPkcs7Padding($string, $blocksize = 32) {

        $len = strlen($string); //取得字符串长度

        $pad = $blocksize - ($len % $blocksize); //取得补码的长度

        $string .= str_repeat(chr($pad), $pad); //用ASCII码为补码长度的字符, 补足最后一段

        return $string;

    }



    /**

     * 加密然后base64转码

     * 

     * @param String 明文

     * @param 加密的初始向量(IV的长度必须和Blocksize一样, 且加密和解密一定要用相同的IV)

     * @param $key 密钥

     */

    function aes256cbcEncrypt($str, $iv, $key ) {   

        return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $this->addPkcs7Padding($str) , MCRYPT_MODE_CBC, $iv));

    }



    /**

     * 除去pkcs7 padding

     * 

     * @param String 解密后的结果

     * 

     * @return String

     */

    private function stripPkcs7Padding($string){

        $slast = ord(substr($string, -1));

        $slastc = chr($slast);

        $pcheck = substr($string, -$slast);



        if(preg_match("/$slastc{".$slast."}/", $string)){

            $string = substr($string, 0, strlen($string)-$slast);

            return $string;

        } else {

            return false;

        }

    }

    /**

     * 解密

     * 

     * @param String $encryptedText 二进制的密文 

     * @param String $iv 加密时候的IV

     * @param String $key 密钥

     * @return String

     */

    function aes256cbcDecrypt($encryptedText, $iv, $key) {

        $encryptedText =base64_decode($encryptedText);

        return $this->stripPkcs7Padding(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encryptedText, MCRYPT_MODE_CBC, $iv));

    }



    function aes128cbcDecrypt($encryptedText, $iv=self::IV, $key=self::KEY) {

        $encryptedText =base64_decode($encryptedText);

        return $this->stripPkcs7Padding(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encryptedText, MCRYPT_MODE_CBC, $iv));

    }



    function hexToStr($hex)//十六进制转字符串

    {   

        $string=""; 

        for($i=0;$i<strlen($hex)-1;$i+=2)

        $string.=chr(hexdec($hex[$i].$hex[$i+1]));

        return  $string;

    }

    function strToHex($string)//字符串转十六进制

    { 

        $hex="";

        $tmp="";

        for($i=0;$i<strlen($string);$i++)

        {

            $tmp = dechex(ord($string[$i]));

            $hex.= strlen($tmp) == 1 ? "0".$tmp : $tmp;

        }

        $hex=strtoupper($hex);

        return $hex;

    }

    function aes128cbcHexDecrypt($encryptedText, $iv=self::IV, $key=self::KEY) {

        $str = $this->hexToStr($encryptedText);

        return $this->stripPkcs7Padding(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_CBC, $iv));

    }



    function aes128cbcEncrypt($str, $iv=self::IV, $key=self::KEY ) {    // $this->addPkcs7Padding($str,16)

        $base = (mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,$this->addPkcs7Padding($str,16) , MCRYPT_MODE_CBC, $iv));

        return $this->strToHex($base);

    }

}

- 阅读剩余部分 -

二.启动redis服务

redis-server.exe redis.conf

实例:
比如小鱼我这里的安装目录:

C:\phpstudy_pro\Extensions\redis3.0.504\

键盘win+R运行输入cmd进入CMD窗口
1.输入命令:

cd C:\phpstudy_pro\Extensions\redis3.0.504\

进入redis的安装路径:
2.启动redis服务

redis-server.exe redis.conf

三、连接redis服务

键盘win+R运行输入cmd进入CMD窗口
1.输入命令:

cd C:\phpstudy_pro\Extensions\redis3.0.504\

进入redis的安装路径:
2.输入命令:

 redis-cli -h 127.0.0.1 -p 6379 -a "xfFzA9ifDz86NHutd5"

返回以下代表连接成功:

127.0.0.1:6379>

四、关闭redis服务
A、通过redis-cli友好关闭redis服务
命令如下:

redis-cli -h 127.0.0.1 -p 6379 -a "xfFzA9ifDz86NHutd5" shutdown

-p 端口
-a 密码 没有密码则取消-a选项

获取异步通知数据

$weixin = file_get_contents('php://input');

解析数据 xml转数组

$obj = simplexml_load_string($weixin,"SimpleXMLElement", LIBXML_NOCDATA);
$data = json_decode(json_encode($obj),true);

notify返回的数据

A、支付成功的异步通知

Array (
[appid] => appid
[bank_type] => CCB_DEBIT
[cash_fee] => 1
[fee_type] => CNY
[is_subscribe] => N
[mch_id] => mch_id
[nonce_str] => 5f48558fa41a7
[openid] => o6Yya08PrSfOFS8DsCmBJ_RoURwc
[out_trade_no] => 20200828085335873434
[result_code] => SUCCESS
[return_code] => SUCCESS
[sign] => 2A23DE00DD138E553288F3DBCC49E912
[time_end] => 20200828085403
[total_fee] => 1
[trade_type] => NATIVE
[transaction_id] => 4200000721202008289823097889
)

查询订单的支付状态

A、扫描未支付

Array (
[return_code] => SUCCESS
[return_msg] => OK
[appid] => appid
[mch_id] => mch_id
[device_info] =>
[nonce_str] => GR8mjKXt8tuNsu81
[sign] => 4E348373A478E752400F3593E27C9DAB
[result_code] => SUCCESS
[total_fee] => 1
[out_trade_no] => 20200828150554884809
[trade_state] => NOTPAY
[trade_state_desc] => 订单未支付
)

B、扫描支付成功的

Array (
[return_code] => SUCCESS
[return_msg] => OK
[appid] => appid
[mch_id] => mch_id
[nonce_str] => t4pCO8Nvmr7uqOx0
[sign] => 3876BA2223A99B066787F1D9A551028E
[result_code] => SUCCESS
[openid] => o6Yya076u3kY9ExdgIpi-SDXZOsc
[is_subscribe] => N
[trade_type] => NATIVE
[bank_type] => OTHERS
[total_fee] => 1
[fee_type] => CNY
[transaction_id] => 4200000719202008288009765782
[out_trade_no] => 20200828093538226231
[attach] =>
[time_end] => 20200828095549
[trade_state] => SUCCESS
[cash_fee] => 1
[trade_state_desc] => 支付成功
[cash_fee_type] => CNY
)

 //回调校验
public  function  notify(){
        //微信来的通知
        $weixin = file_get_contents('php://input');
        //$weixin ="<xml><appid><![CDATA[APPID]]></appid>\n<bank_type><![CDATA[OTHERS]]></bank_type>\n<cash_fee><![CDATA[1]]></cash_fee>\n<fee_type><![CDATA[CNY]]></fee_type>\n<is_subscribe><![CDATA[N]]></is_subscribe>\n<mch_id><![CDATA[MCHID]]></mch_id>\n<nonce_str><![CDATA[5f485f6a36efc]]></nonce_str>\n<openid><![CDATA[o6Yya076u3kY9ExdgIpi-SDXZOsc]]></openid>\n<out_trade_no><![CDATA[20200828093538226231]]></out_trade_no>\n<result_code><![CDATA[SUCCESS]]></result_code>\n<return_code><![CDATA[SUCCESS]]></return_code>\n<sign><![CDATA[1808F30039789D9B7A47E84C390AF304]]></sign>\n<time_end><![CDATA[20200828095549]]></time_end>\n<total_fee>1</total_fee>\n<trade_type><![CDATA[NATIVE]]></trade_type>\n<transaction_id><![CDATA[4200000719202008288009765782]]></transaction_id>\n</xml>";
       //解析微信传来的参数
       $obj = simplexml_load_string($weixin,"SimpleXMLElement", LIBXML_NOCDATA);
       $data = json_decode(json_encode($obj),true);
       //我收到通知了
       $paydata=array();
       if($data['return_code']=='SUCCESS'){
              //我检查我的库有没有
              $out_trade_no=$data['out_trade_no'];
              $pay_count=D('pay_lists')->where(array('order_id'=>$out_trade_no))->find();
              //原来我有此订单 
              if(count($pay_count)>0){
                    //我还要查询下订单 校验是否一致
                    $sign_check=$this->app->order->queryByOutTradeNumber($out_trade_no);
                    if($sign_check['result_code']=='SUCCESS'&&$data['result_code']=='SUCCESS'){
                        //金额校对结果
                        $amount =$pay_count['amount']*100; //订单的单位是元 而微信这里是分
                        if($data['total_fee']=$sign_check['total_fee']=$amount){
                          //三方校对都合法了 是时候改变业务数据的支付状态了
                          $paydata['pay_status'] = 1;
                          $paydata['pay_time'] = time();
                          $paydata['remark']=$sign_check['trade_state_desc'];
                        }else{  
                          $paydata['pay_status'] = 2;
                          $paydata['remark']='支付失败:金额不一致';
                        }
                    }else{
                           $paydata['pay_status'] = 2;
                           $paydata['remark']='支付失败:返回失败状态';
                    }
                    //处理完业务告诉微信
                    $result=D('pay_lists')->where(array('order_id'=>$out_trade_no))->save($paydata);
                    if($result){
                       return true;
                    }else{
                       return false;
                    }
             }else{
               //没有这个订单了 不再发消息来了
               return true;
             }
       }else{
         return false; //没接收到 下次继续通知我
       }
}

使用thinkphp3.2做图片流数据返回的时候要特别注意别用json,json的返回有长度限制,会将(data:image/png;base64,...)里面的data rn换行,从而导致图片无法解析。
错误做法:
$this->Ajaxreturn($img,'json')
正确做法:
$this->Ajaxreturn($img)