ThinkPHP 整合微信支付 扫码支付 模式二 图文教程

前面我们介绍了支付的在线支付实例 ThinkPHP实现支付宝接口功能 代码实例

这篇文章主要介绍扫码支付场景二。

目前有两种模式,模式一比模式二稍微复杂点,至于模式一与模式二的具体内容,流程,微信开发文档都有详细介绍,这里就不多说废话,接下来赶紧上教程!

下载SDK类文件

Wxpay Library

并SDK文件/lib下的几个文件放置到/ThinkPHP/Library/Vendor/

修改WxPay.pub.config.php中的配置选项

	//=======【基本信息设置】=====================================
	//微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
	const APPID = '公众号表示ID';
	//受理商ID,身份标识
	const MCHID = '商户ID';
	//商户支付密钥Key。审核通过后,在微信发送的邮件中查看
	const KEY = 'KEY密匙';
	//JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
	const APPSECRET = 'SECRET密匙';
	
	//=======【JSAPI路径设置】===================================
	//获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面
	const JS_API_CALL_URL = 'http://www.laoji.org';
	
	//=======【证书路径设置】=====================================
	//证书路径,注意应该填写绝对路径
	const SSLCERT_PATH =  "__ROOT__\paypem\\apiclient_cert.pem";
	const SSLKEY_PATH =   "__ROOT__\paypem\\apiclient_key.pem";
	
	//=======【异步通知url设置】===================================
	//异步通知url,商户根据实际开发过程设定
	const NOTIFY_URL = 'http://www.laoji.org/wxpay/notify';

	//=======【curl超时设置】===================================
	//本例程通过curl使用HTTP POST方法,此处可修改其超时时间,默认为30秒
	const CURL_TIMEOUT = 30;

新建微信的Controller方法,目录位置为:\Application\Home\Controller\WxpayController.class.php

<?php
/**
 * WxpayController.class.php
 * 微信支付控制器
 * 网站地址:   https://jiloc.com/43212.html
 * Author: 老季 ( admin@laoji.org ) 
 * Date: 2017年4月18日
*/
namespace Home\Controller;

class WxpayController extends HomeController {
    //初始化
    public function _initialize()
    {
        //引入类文件
        vendor('Wxpay.WxPayPubHelper');
    }
    
    private function makeOrder($ary){
        $data = array();
        $data['userid'] = session('user_auth')['uid'];
        if ( !$data['userid'] ){
            $this->error('用户ID错误! -> '.$data['uid'],'/my/publishlist');
        } 
        // 检查船舶信息
        $data['shipinfoid'] = $ary['id'];
        $ShipInfo = M('ShipInfo')->where(array('id'=>$ary['id']))->find();
        if( !$ShipInfo ){
            $this->error('信息ID错误! -> '.$ary['id'],'/my/publishlist');
        }
        // 检查支付价格
        $data['ordercatid'] = $ary['catid'];
        $OrderCat = M('OrderCat')->where(array('id'=>$ary['catid']))->find();
        if( !$OrderCat ){
            $this->error('产品价格错误! -> '.$ary['catid'],'/my/publishlist');
        }
        
        $data['ordid'] = "LJ".$ary['TYPE'].date('YmdHis',time()).rand(11,99);
        $data['ordtime'] = time();
        
        $data['ordtitle'] = $ShipInfo['title'];
        $data['ordbuydays'] = $OrderCat['days'];
        $data['ordfee'] = $data['ordprice'] = $OrderCat['price'];
        $data['status'] = 0;
        
        M('OrderList')->add($data);
        
        return $data['ordid'];
        
    }
    
    //生成二维码
    public function qrcode()
    {
        // 生成订单
        $_POST['TYPE'] = 'W';
        $out_trade_no = $this->makeOrder($_POST);
        $ordtotal_fee = str_replace(".","",$_POST['ordtotal_fee']*100);
        //使用统一支付接口
        $unifiedOrder = new \UnifiedOrder_pub();
        //设置统一支付接口参数
        //设置必填参数
        $unifiedOrder->setParameter("body",$_POST['ordsubject'] );//商品描述
        //自定义订单号,此处仅作举例
        $timeStamp = time();
        $unifiedOrder->setParameter("out_trade_no",$out_trade_no);//商户订单号 
        $unifiedOrder->setParameter("total_fee",$ordtotal_fee);//总金额
        $unifiedOrder->setParameter("notify_url", \WxPayConf_pub::NOTIFY_URL);//通知地址 
        $unifiedOrder->setParameter("trade_type","NATIVE");//交易类型
        //非必填参数,商户可根据实际情况选填
        //$unifiedOrder->setParameter("sub_mch_id","XXXX");//子商户号  
        //$unifiedOrder->setParameter("device_info","XXXX");//设备号 
        //$unifiedOrder->setParameter("attach","XXXX");//附加数据 
        //$unifiedOrder->setParameter("time_start","XXXX");//交易起始时间
        //$unifiedOrder->setParameter("time_expire","XXXX");//交易结束时间 
        //$unifiedOrder->setParameter("goods_tag","");//商品标记 
        //$unifiedOrder->setParameter("openid","19405");//用户标识
        //$unifiedOrder->setParameter("product_id","XXXX");//商品ID
        //获取统一支付接口结果
        $unifiedOrderResult = $unifiedOrder->getResult();
        //var_dump($unifiedOrder);
        //商户根据实际情况设置相应的处理流程
        if ($unifiedOrderResult["return_code"] == "FAIL") 
        {
            //商户自行增加处理流程
            echo "通信出错:".$unifiedOrderResult['return_msg']."<br>";
        }
        elseif($unifiedOrderResult["result_code"] == "FAIL")
        {
            //商户自行增加处理流程
            echo "错误代码:".$unifiedOrderResult['err_code']."<br>";
            echo "错误代码描述:".$unifiedOrderResult['err_code_des']."<br>";
        }
        elseif($unifiedOrderResult["code_url"] != NULL)
        {
            //从统一支付接口获取到code_url
            $code_url = $unifiedOrderResult["code_url"];
            //商户自行增加处理流程
            //......
        }
        $this->assign('title',$_POST['ordsubject']);
        $this->assign('total_fee',$_POST['ordtotal_fee']);
        $this->assign('out_trade_no',$out_trade_no);
        $this->assign('code_url',urlencode($code_url));
        $this->assign('unifiedOrderResult',$unifiedOrderResult);
        
        $this->display();
    }
    
    public function notify()
    {
        //使用通用通知接口
        $notify = new \Notify_pub();
        //存储微信的回调
        $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
        $notify->saveData($xml);
        //var_dump($xml);
        //验证签名,并回应微信。
        //对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,
        //微信会通过一定的策略(如30分钟共8次)定期重新发起通知,
        //尽可能提高通知的成功率,但微信不保证通知最终能成功。
        if($notify->checkSign() == FALSE){
            $notify->setReturnParameter("return_code","FAIL");//返回状态码
            $notify->setReturnParameter("return_msg","签名失败");//返回信息
        }else{
            $notify->setReturnParameter("return_code","SUCCESS");//设置返回码
        }
        $returnXml = $notify->returnXml();
        echo $returnXml;
         
        //==商户根据实际情况设置相应的处理流程,此处仅作举例=======
         
        //以log文件形式记录回调信息
        //         $log_ = new Log_();
        //$log_name= __ROOT__."/Public/notify_url.log";//log文件路径
         
        //$this->log_result($log_name,"【接收到的notify通知】:\n".$xml."\n");
         
        if($notify->checkSign() == TRUE)
        {
            if ($notify->data["return_code"] == "FAIL") {
                //此处应该更新一下订单状态,商户自行增删操作
                log_result($log_name,"【通信出错】:\n".$xml."\n");
                $this->error("通信出错");
            }
            elseif($notify->data["result_code"] == "FAIL"){
                //此处应该更新一下订单状态,商户自行增删操作
                //log_result($log_name,"【业务出错】:\n".$xml."\n");
                $this->error("业务出错");
            }
            elseif( $notify->data['return_code'] == "SUCCESS" && $notify->data['result_code'] == "SUCCESS"){
                $out_trade_no   = $notify->data['out_trade_no'];
                $parameter = array(
                    "out_trade_no"     => $notify->data['out_trade_no'],    //商户订单编号;
                    "transaction_id"         => $notify->data['transaction_id'],  //微信支付订单号	
                    "total_fee"        => $notify->data['total_fee'],       //交易金额;
                    "result_code"     => "SUCCESS",                        //交易状态
                    "time_end"    => $notify->data['time_end'],          //支付完成时间
                    "openid"    => $notify->data['openid'],            //用户标识	
                );
                if (!$this->checkorderstatus($out_trade_no)){
                    $this->orderhandle($parameter);
                }
                return true;
                //$this->success("支付成功!");
            }
            else{
                //此处应该更新一下订单状态,商户自行增删操作
                //log_result($log_name,"【支付成功】:\n".$xml."\n");
                $this->error("UNKNOW ERROR");
                
            }
             
            //商户自行增加处理流程,
            //例如:更新订单状态
            //例如:数据库操作
            //例如:推送支付完成信息
        }
    }
    
    //查询订单
    public function orderQuery()
    {  
        if($this->checkorderstatus( I('post.out_trade_no') )){
            $this->ajaxReturn("SUCCESS");
        };
        $this->ajaxReturn("FAILD");
    }
    
    //在线交易订单支付处理函数
    //函数功能:根据支付接口传回的数据判断该订单是否已经支付成功;
    //返回值:如果订单已经成功支付,返回true,否则返回false;
    private function checkorderstatus($ordid){
        $ordstatus=M('OrderList')->where(array('ordid'=>$ordid))->getField('ordstatus');
        if($ordstatus==1){
            return true;
        }else{
            return false;    
        }
    }

    //处理订单函数
    //更新订单状态,写入订单支付后返回的数据
    private function orderhandle($parameter){
        $ordid=$parameter['out_trade_no'];
        $data['payment_trade_no']      =$parameter['transaction_id'];
        $data['payment_trade_status']  =$parameter['result_code'];
        $data['payment_notify_time']   =$parameter['time_end'];
        $data['payment_buyer_email']   =$parameter['openid'];
        $data['ordstatus']             =1;
        M('OrderList')->where(array('ordid'=>$ordid))->save($data);
        
        $Order = M('OrderList')->where(array('ordid'=>$ordid))->find();
        
        $ship_due_date = M("ShipInfo")->where(array('id'=>$Order['shipinfoid']))->find();
        if( $ship_due_date['due_date'] > time() ){
            $due_date = $ship_due_date['due_date']+($Order['ordbuydays']*86400);
        }else{
            $due_date = strtotime("+".$Order['ordbuydays']." day");
        }
        
        M('ShipInfo')->where(array('id'=>$Order['shipinfoid']))->save(array('due_date'=>$due_date,'status'=>1,'top'=>1));
        return ;
    } 
    
    
    
}

二维码生成页面的html,目录位置\Application\Home\View\default\Wxpay\qrcode.html

<extend name="Base/common"/>


<block name="body">
<div class="center clearfix">
    <div class="bread">
    <a class="link" href="/">首页></a><span class="on">支付页面</span>
	</div>
    <div class="pay_con_zl">
       
        <div class="p_tit_zl">支付页面</div>
      <div class="p_info_zl">
           <p>标题:{$title}</p>
           <p>支付金额:<span style="font-size:24px; font-weight:bold; color:#F00;">¥{$total_fee}元</span>,请使用微信扫描下方二维码完成支付<span style="padding-left:20px; color:#F00;">2小时之内,请尽快扫描支付</span></p>          
           <P><img alt="扫码支付" src="https://cdn.uziwp.com/20170409040501NP4.jpg" style="width:150px;height:150px;"/></P>
        </div>
        
    </div>
</div>
<script language="JavaScript">
function Check(){
    var out_trade_no = "{$out_trade_no}";
    $.post("{:U('wxpay/orderQuery')}", { out_trade_no: out_trade_no},
        function(data){
            if(data == "SUCCESS"){
                window.location = '{:U("my/paystatus",array("ordtype"=>"payed"))}';
            }
    });
}
window.setInterval("Check()",3000); 
</script>
</block>

表单提交以后则跳转到二维码生成页面,提交地址:/wxpay/qrcode ,效果如下图:

微信客户端支付成功以后,该页面会自动跳转到支付成功页面。

回调数据库表建立

我们这里使用的是ThinkPHP实现支付宝接口功能 代码实例 中的order_list 表。

微信平台配置

微信公众平台上的配置了,这里我遇到过问题,如果有在这里遇到问题的同学请留言,比如出现了access_deined或者access_notallowed等问题,这都可能是因为这里配置不对。
请看配置过程截图:

支付授权目录设置为:http://laoji.org/wxpay/


注意

微信支付订单中的totla_fee的单位为分,比如1元,传值为100(分)

评论

《 “ThinkPHP 整合微信支付 扫码支付 模式二 图文教程” 》 有 5 条评论

  1. APPSECRET参数是必须填?

    1. 应该是必填的吧。时间有点久不记得了。

  2. 看截图的SDK应该是旧版本的吧。和我刚下的不一样呢 :confused:

  3. 看截图的sdk 应该是旧版本的吧。 和我下载的不一样

    1. 直接用这个代码应该也能运行,这个是2017.4月份左右写的。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注