/index/pay.php

<?php

namespace app\index\controller;
use think\Exception;
use app\common\controller\Frontend;

class Pay  extends Frontend{

    protected $noNeedLogin = '*';
    protected $noNeedRight = '*';
    
    protected $apiurl="https://api.dpweixin.com/payment/do.html";
    protected $pid="---";
    protected $hashkey="----";

    public function _initialize()
    {
        parent::_initialize();
        // $this->apiurl=$apiurl;
        // $this->pid=$pid;
        // $this->hashkey=$hashkey;
    }

    //$param=["type"=>"","sn"=>"","price"=>"","title"=>"","notify_url"=>"","return_url"=>""];
    public function pay()
    {
        $param=$this->request->param();

        if(!in_array($param["type"], ["wechat","alipay"])){
            $this->error("type参数错误");
        }

        if(empty($param["price"])){
            $this->error("价格不能为空!");
        }

        if(empty($param["title"])){
            $this->error("订单名称不能为空!");
        }

        if(empty($param["sn"])){
            $this->error("订单号不能为空!");
        }




        $paytxt=["wechat"=>"微信","alipay"=>"支付宝"];

        $data=array(
            'version'   => '1.1',//固定值,api 版本,目前暂时是1.1
            'appid'     => $this->pid, //必须的,APPID
            'trade_order_id'=> $param["sn"], //必须的,网站订单ID,唯一的,匹配[a-zA-Z\d\-_]+
            'total_fee' => $param['price'],//人民币,单位精确到分(测试账户只支持0.1元内付款)
            'title'     => $param['title'], //必须的,订单标题,长度32或以内
            'time'      => time(),//必须的,当前时间戳,根据此字段判断订单请求是否已超时,防止第三方攻击服务器
            'notify_url'=> $param['notify_url'], //必须的,支付成功异步回调接口
            'return_url'=> $param['return_url'], //支付成功返回地址
            'nonce_str' => str_shuffle(time())//必须的,随机字符串,作用:1.避免服务器缓存,2.防止安全密钥被猜测出来
        );
        //微信h5
        if($param['type']=='wechat' && $this->isWebApp()){
            $data['type'] = "WAP";
        }
        //签名
        $data['hash'] = $this->generate_xh_hash($data,$this->hashkey);

        
        try {
            $response     = $this->http_post($this->apiurl, json_encode($data));

            $result = $response?json_decode($response,true):null;
            if(empty($result)){
                throw new Exception($response,500);
            }
            if ($result['errcode'] != 0) {
                throw new Exception($result['errmsg']);
            }
            if ($this->isWebApp()) {
                $pay_url =$result['url'];
                header("Location: $pay_url");
                exit;
            }
            $qrcode=$result['url_qrcode'];
        } catch (\Exception $e) {
            $this->error($e->getMessage());
        }

        
        $this->view->assign("paytxt",$paytxt[$param['type']]);
        $this->view->assign("type",$param['type']);
        $this->view->assign("data",$data);
        $this->view->assign("qrcode",$qrcode);
        $this->view->assign("param",$param);
        return $this->view->fetch();

    }

    public function notifyx()
    {
        $data = $this->request->post();
        $uid = $this->request->param("uid");
        $paytype = $this->request->param("paytype");

        
        foreach ($data as $k=>$v){
            $data[$k] = stripslashes($v);
        }
        if(!isset($data['hash'])||!isset($data['trade_order_id'])){
            trace($data,'参数错误');
            echo 'failed';exit;
        }
        // if($data['plugins']=='wechat'){
        //     $appid              = '201906130470';
        //     $appsecret          = 'd6031f0c7debcc61d486cad77468ae46';   
        // }else{
        //     $appid              = '';
        //     $appsecret          = '';
        // }
        // //APP SECRET
        // $appkey =$appsecret;

        unset($data['paytype']);
        unset($data['sn']);
        unset($data['uid']);
        $hash =$this->generate_xh_hash($data,$this->hashkey);
        if($data['hash']!=$hash){
            //签名验证失败
            trace($data,'签名验证失败:'.$hash);
            echo 'failed';exit;
        }
        //商户订单ID
        $trade_order_id =$data['trade_order_id'];
        if($data['status']=='OD'){
            $this->CreateBaoGao($uid,$data['transaction_id'],$data['total_fee'],$trade_order_id);
            
            /************商户业务处理******************/
            //TODO:此处处理订单业务逻辑,支付平台会多次调用本接口(防止网络异常导致回调失败等情况)
            //     请避免订单被二次更新而导致业务异常!!!
            //     if(订单未处理){
            //         处理订单....
            //      }

            //....
            //...
            /*************商户业务处理 END*****************/
        }else{
            //处理未支付的情况
        }

        //以下是处理成功后输出,当支付平台接收到此消息后,将不再重复回调当前接口
        echo 'success';
        exit;
    }
    
    
    public function query()
    {
        $order_id=$this->request->param("order_id");
        $request=array(
            'appid'     => $this->pid, //必须的,APPID
            'out_trade_order'=> $order_id, //网站订单号(out_trade_order,open_order_id 二选一)
            'time'      => time(),//必须的,当前时间戳,根据此字段判断订单请求是否已超时,防止第三方攻击服务器
            'nonce_str' => str_shuffle(time())//必须的,随机字符串,作用:1.避免服务器缓存,2.防止安全密钥被猜测出来
        );
        $request['hash'] =  $this->generate_xh_hash($request,$this->hashkey);
        $url = 'https://api.dpweixin.com/payment/query.html';
        try {
            $response  = $this->http_post($url, http_build_query($request));
           // dump($response);
            $result       = $response?json_decode($response,true):null;
            if(!$result){
                throw new Exception('Internal server error:'.$response,500);
            }
            if($result['data']['status']=='OD'){
                echo 'complete';
                exit;
            }else{
                echo 'paidding';
                exit;
            }
        } catch (Exception $e) {
           $this->error($e->getMessage());
        }
    }

    protected function CreateBaoGao($user_id,$transaction_id,$payamount,$out_trade_no)
    {
        $site=config("site");
        if(empty(db('baogao')->where("sn",$out_trade_no)->find())){
            db("baogao")->insert([
                "uid"=>$user_id,
                "sn"=>$out_trade_no,
                "title"=>$site["ordername"],
                "syts"=>$this->getQujian($site["syts"]),
                "nqsj"=>$this->getQujian($site["nqsj"]),
                "fsxx"=>$this->getQujian($site["fsxx"]),
                "cghybl"=>$this->getQujian($site["cghybl"]),
                "bscs"=>$this->getQujian($site["bscs"]),
                "bhyzd"=>$this->getQujian($site["bhyzd"]),
                "ckzpdthys"=>$this->getQujian($site["ckzpdthys"]),
                "hybzrs"=>$this->getQujian($site["hybzrs"]),
                "hybznr"=>$this->getQujian($site["hybznr"]),
                "pyqfwcs"=>$this->getQujian($site["pyqfwcs"]),
                "bzcs"=>$this->getQujian($site["bzcs"]),
                "zbs"=>$this->getQujian($site["zbs"]),
                "nzgjc"=>$this->getQujian($site["nzgjc"]),
                "pyqtlsc"=>$this->getQujian($site["pyqtlsc"]),
    
                "amount"=>$site["price"],
                "zfmoney"=>$payamount,
                "zfstatus"=>"ok",
                "zfsn"=>$out_trade_no,
                "zftime"=>time(),
                "createtime"=>time(),
                "status"=>"normal",
            ]);
        }
    }
    protected function getQujian($str){
        $arr1=explode(",",$str);
        $arr2=explode("-",$str);
        if(count($arr1)>1){
            return $arr1[array_rand($arr1)];
        }elseif(count($arr2)==2){
            if(intval(trim($arr2[0]))>0 && intval(trim($arr2[1]))>0){
              return  rand(intval(trim($arr2[0])),intval(trim($arr2[1])));
            }
        }else{
            return $str;
        }
    }

    protected function http_post($url,$data){
        if(!function_exists('curl_init')){
            throw new Exception('php未安装curl组件',500);
        }
        
        $protocol = (! empty ( $_SERVER ['HTTPS'] ) && $_SERVER ['HTTPS'] !== 'off' || $_SERVER ['SERVER_PORT'] == 443) ? "https://" : "http://";
        $siteurl= $protocol.$_SERVER['HTTP_HOST'];
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_REFERER,$siteurl);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        $response = curl_exec($ch);
        $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error=curl_error($ch);
        curl_close($ch);
        if($httpStatusCode!=200){
            throw new Exception("invalid httpstatus:{$httpStatusCode} ,response:$response,detail_error:".$error,$httpStatusCode);
        }
         
        return $response;
    }
    protected function isWebApp(){
        if(!isset($_SERVER['HTTP_USER_AGENT'])){
            return false;
        }
    
        $u=strtolower($_SERVER['HTTP_USER_AGENT']);
        if($u==null||strlen($u)==0){
            return false;
        }
    
        preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/',$u,$res);
    
        if($res&&count($res)>0){
            return true;
        }
    
        if(strlen($u)<4){
            return false;
        }
    
        preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/',substr($u,0,4),$res);
        if($res&&count($res)>0){
            return true;
        }
    
        $ipadchar = "/(ipad|ipad2)/i";
        preg_match($ipadchar,$u,$res);
        return $res&&count($res)>0;
    }
    protected function  generate_xh_hash(array $datas,$hashkey){
        ksort($datas);
        reset($datas);
        $arg  = '';
        foreach ($datas as $key=>$val){
            if($key=='hash'||is_null($val)||$val===''){continue;}
            if($arg){$arg.='&';}
            $arg.="$key=$val";
        }
        return md5($arg.$hashkey);
    }

    protected  function is_wechat_app(){
        return strripos($_SERVER['HTTP_USER_AGENT'],'micromessenger');
    }
}
?>



html

<!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.0, maximum-scale=1.0, user-scalable=no" />
    <meta name="keywords" content="">
    <meta name="description" content="">
    <title>{$paytxt}支付收银台</title>
    <style>
         *{margin:0;padding:0;}
          body{background: #f2f2f4;}
         .clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
        .clearfix { display: inline-block; }
        * html .clearfix { height: 1%; }
        .clearfix { display: block; }
          .xh-title{height:75px;line-height:75px;text-align:center;font-size:30px;font-weight:300;border-bottom:2px solid #eee;background: #fff;}
          .qrbox{max-width: 900px;margin: 0 auto;padding:85px 20px 20px 50px;}

          .qrbox .left{width: 40%;
            float: left;
             display: block;
            margin: 0px auto;}
          .qrbox .left .qrcon{
            border-radius: 10px;
            background: #fff;
            overflow: visible;
            text-align: center;
            padding-top:25px;
            color: #555;
            box-shadow: 0 3px 3px 0 rgba(0, 0, 0, .05);
            vertical-align: top;
            -webkit-transition: all .2s linear;
            transition: all .2s linear;
          }
            .qrbox .left .qrcon .logo{width: 100%;}
            .qrbox .left .qrcon .title{font-size: 16px;margin: 10px auto;width: 100%;}
            .qrbox .left .qrcon .price{font-size: 22px;margin: 0px auto;width: 100%;}
            .qrbox .left .qrcon .bottom{border-radius: 0 0 10px 10px;
            width: 100%;
            background: #32343d;
            color: #f2f2f2;padding:15px 0px;text-align: center;font-size: 14px;}
           .qrbox .sys{width: 60%;float: right;text-align: center;padding-top:20px;font-size: 12px;color: #ccc}
           .qrbox img{max-width: 100%;}
           @media (max-width : 767px){
        .qrbox{padding:20px;}
            .qrbox .left{width: 90%;float: none;}
            .qrbox .sys{display: none;}
           }

           @media (max-width : 320px){

          }
          @media ( min-width: 321px) and ( max-width:375px ){

          }
    </style>
    </head>
    <body>
     <div class="xh-title"><img src="/skin/pay/images/{$type}.png" alt="" style="vertical-align: middle"> {$paytxt}支付收银台</div>
      <div class="qrbox clearfix">
      <div class="left">
         <div class="qrcon">
           <h5><img src="/skin/pay/images/{$type}/logo.png" alt=""></h5>
             <div class="title">{$data['title']}</div>
             <div class="price">{$data['total_fee']} 元</div>
             <div align="center"><div id="wechat_qrcode" style="width: 250px;height: 250px;"><img id='qrcode' src="{$qrcode}"/></div></div>
             <div class="bottom">
                请使用{$paytxt}扫一扫<br/>
                扫描二维码支付
             </div>
         </div>
  </div>
     <div class="sys"><img src="/skin/pay/images/{$type}/{$type}-sys.png" alt=""></div>
  </div>
<script src="/skin/pay/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript">
(function($){
    window.view={
        query:function () {
            $.ajax({
                type: "POST",
              url:"{:url('index/pay/query',['order_id'=>$data['trade_order_id'],'type'=>$type])}",
                timeout:6000,
                cache:false,
                dataType:'text',
                success:function(e){
                    if (e && e.indexOf('complete')!==-1) {
                        window.location.href = "{$data['return_url']}";
                        return;
                    }
                },
                error:function(){
                }
            });
        }
    };
    var timer;
    timer = setInterval(function(){window.view.query();}, 5000);
  setTimeout(function(){
      console.log("任务已停止。");
      clearInterval(timer); // 清除定时器
      $("#qrcode").attr('src','/skin/pay/images/error.png');
  }, 300 * 1000);
  window.view.query();
})(jQuery);
</script>
</body>
</html>


点赞(0)

评论列表 共有 0 条评论

暂无评论
立即
投稿
发表
评论
返回
顶部