微信小程序支付(PHP后端)

1.申请开通小程序支付,我们正式开通的微信支付是在微信公众平台上,我们需要绑定之前的微信商户平台即可,这一点不过多强调

2.小程序支付开发步骤

(1)、统一下单

大家看到微信的统一下单接口密密麻麻的一大堆参数,千万不要害怕,有问题解决就是了。

<?php
//微信支付向外暴露的支付接口
public function pay()
{
    $result = $this->weChatPay();
    return $result;
}

//请求微信统一下单接口
private function weChatPay()
{
    $param = array(
        'appid' => $this->APPID,//小程序id
        'mch_id'=> $this->MCHID,//商户id
        'spbill_create_ip'=>$_SERVER['REMOTE_ADDR'],//终端ip
        'notify_url'=>$this->APPURL, //回调通知地址
        'nonce_str'=> $this->createNoncestr(),//随机字符串
        'out_trade_no'=>$this->outTradeNo,//商户订单编号
        'total_fee'=>floatval($this->totalFee), //总金额
        'openid'=>$this->openid,//用户openid
        'trade_type'=>$this->TRADETYPE,//交易类型
        'body' =>$this->BODY, //商品信息    
        );
    //通过签名算法计算得出的签名值,详见签名生成算法
    $param['sign'] = $this->getSign($param);
    //将数组内容转为xml格式,向微信发出请求
    $xmlData = $this->arrayToXml($param);
    $xml_result = $this->postXmlCurl($xmlData,'https://api.mch.weixin.qq.com/pay/unifiedorder',60);
    $result = $this->xmlToArray($xml_result);
    return $result;
    // var_dump($result);
    /*
         * array(9) {
          ["return_code"]=>
          string(7) "SUCCESS"
          ["return_msg"]=>
          string(2) "OK"
          ["appid"]=>
          string(18) "wx2d4fefcfe1a39c9b"
          ["mch_id"]=>
          string(10) "1420537902"
          ["nonce_str"]=>
          string(16) "JASf0yXVuPknKm2J"
          ["sign"]=>
          string(32) "BE3CF30459D01660BB9AB2DE0AD023CE"
          ["result_code"]=>
          string(7) "SUCCESS"
          ["prepay_id"]=>
          string(36) "wx29154208585459f31c6875691178935371"
          ["trade_type"]=>
          string(5) "JSAPI"
        }
}

/*
* 对要发送到微信统一下单接口的数据进行签名
*/
protected function getSign($Obj){
    foreach ($Obj as $k => $v){
        $param[$k] = $v;
    }
    //签名步骤一:按字典序排序参数
    ksort($param);
    $String = $this->formatBizQueryParaMap($param, false);
    //签名步骤二:在string后加入KEY
    $String = $String."&key=".$this->KEY;
    //签名步骤三:MD5加密
    $String = md5($String);
    //签名步骤四:所有字符转为大写
    $result_ = strtoupper($String);
    return $result_;
}
/*
 *排序并格式化参数方法,签名时需要使用
 */
protected function formatBizQueryParaMap($paraMap, $urlencode)
{
    $buff = "";
    ksort($paraMap);
    foreach ($paraMap as $k => $v)
    {
        if($urlencode)
        {
            $v = urlencode($v);
        }
        //$buff .= strtolower($k) . "=" . $v . "&";
        $buff .= $k . "=" . $v . "&";
    }
    $reqPar = "";
    if (strlen($buff) > 0)
    {
        $reqPar = substr($buff, 0, strlen($buff)-1);
    }
    return $reqPar;
}

/*
 * 生成随机字符串方法
 */
protected function createNoncestr($length = 32 ){
    $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    $str ="";
    for ( $i = 0; $i < $length; $i++ ) {
        $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
    }
    return $str;
}
//数组转字符串方法
protected function arrayToXml($arr){
    $xml = "<xml>";
    foreach ($arr as $key=>$val)
    {
        if (is_numeric($val)){
            $xml.="<".$key.">".$val."</".$key.">";
        }else{
            $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
        }
    }
    $xml.="</xml>";
    return $xml;
}

//将xml字符串转换为数组
protected static function xmlToArray($xml){
    $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    return $array_data;
}

//发送xml请求方法
private static function postXmlCurl($xml, $url, $second = 30)
{
    $ch = curl_init();
    //设置超时
    curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验
    //设置header
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    //要求结果为字符串且输出到屏幕上
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    //post提交方式
    curl_setopt($ch, CURLOPT_POST, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
    curl_setopt($ch, CURLOPT_TIMEOUT, 40);
    set_time_limit(0);
    //运行curl
    $data = curl_exec($ch);
    //返回结果
    if ($data) {
        curl_close($ch);
        return $data;
    } else {
        $error = curl_errno($ch);
        curl_close($ch);
        throw new WxPayException("curl出错,错误码:$error");
    }
}

(2)、处理微信的notify_url 通知地址

微信会把刚才生成的支付订单返回来,给我们做校验

异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。

/* 微信官方提醒:
* 商户系统对于支付结果通知的内容一定要做【签名验证】,
* 并校验返回的【订单金额是否与商户侧的订单金额】一致,
* 防止数据泄漏导致出现“假通知”,造成资金损失。
*/
$post = post_data();    //接受POST数据XML个数

function post_data(){
    $receipt = $_REQUEST;
    if($receipt==null){
        $receipt = file_get_contents("php://input");
        if($receipt == null){
            $receipt = $GLOBALS['HTTP_RAW_POST_DATA'];
        }
    }
    return $receipt;
}
//调用后台验证
WeiXinPay::payNotifyUrlCallback($post);
 /*
     * 微信支付结果回调;
     * */
    public static function PayCallBack($result){
        //查找对应的功能模块,返回信息内容
        /*
         * <xml>
              <appid><![CDATA[wx24123c4370ec43b]]></appid>
              <attach><![CDATA[测试测试]]></attach>
              <bank_type><![CDATA[CFT]]></bank_type>
              <fee_type><![CDATA[CNY]]></fee_type>
              <is_subscribe><![CDATA[Y]]></is_subscribe>
              <mch_id><![CDATA[10000100]]></mch_id>
              <nonce_str><![CDATA[5d2b634f23F23da20af46e531c]]></nonce_str>
              <openid><![CDATA[oUpF8uMEb4q23FEWG4Q23R268TekukE]]></openid>
              <out_trade_no><![CDATA[140123153]]></out_trade_no>
              <result_code><![CDATA[SUCCESS]]></result_code>
              <sign><![CDATA[B552EDFW23G423G5DD0D78AB241]]></sign>
              <sub_mch_id><![CDATA[10000100]]></sub_mch_id>
              <time_end><![CDATA[20140903131540]]></time_end>
              <total_fee>1</total_fee>
                <coupon_fee><![CDATA[10]]></coupon_fee>
                <coupon_count><![CDATA[1]]></coupon_count>
                <coupon_type><![CDATA[CASH]]></coupon_type>
                <coupon_id><![CDATA[10000]]></coupon_id>
                <coupon_fee><![CDATA[100]]></coupon_fee>
              <trade_type><![CDATA[JSAPI]]></trade_type>
              <transaction_id><![CDATA[1004400740212312353532168]]></transaction_id>
         </xml>
        */
        if($result == null){
            return;
        }
        if($result['result_code'] =='SUCCESS'){
        //支付成功
      //开始取出数据库订单数据进行校验
      //校验成功向微信发出请求成功
      WeiXinPay::return_success(); }
}
/*
* 给微信发送确认订单金额和签名正确,SUCCESS信息 -xzz0521
*/
public static function return_success(){
$return['return_code'] = 'SUCCESS';
$return['return_msg'] = 'OK';
$xml_post = '<xml>
<return_code>'.$return['return_code'].'</return_code>
<return_msg>'.$return['return_msg'].'</return_msg>
</xml>';
echo $xml_post;exit;
}
 

  使用本代码,建议使用单个方法拼接,最终来组成逻辑代码

参考其他案例

posted @ 2018-11-01 15:38  牛奔  阅读(4367)  评论(2编辑  收藏  举报