php docking APP micro-channel pay

Please combination of the following official documents 

Development preparation:

After the merchant WeChat open platform for application development and application, WeChat open platform will generate a unique identity of APPID APP. Because of the need to ensure payment security, business applications need to bind application package name and signature in an open platform, set to launch later paid properly. The interface is provided in [section] open platform in [Manager / applications to modify / edit] development information which, as shown in FIG.

 

How to apply signatures and application package name to write, if you are using apicloud development, front-end will know, specifically refer to the official documentation; Now we can begin to develop a

Payment process: 1. The first call unified under a single API to generate prepaid orders

                 2. Obtain the signatures again after parameter prepay_id

                 3. Transfer to APP, initiated payment

                 4. Pay success, asynchronous callbacks

Specific look at the code

WechatAppPay I created a third-party class

Wxpay is processing payments

<?php
namespace Wxpay;
 
use app\common\lib\helper\ConfigHelper;
use app\common\lib\helper\Helper;
use think\Request;
 
class WechatAppPay
{
 
    private $appid = '';
    private $partnerId = '';
    private $key = '';
    private $notify_url = '';
    const URL='https://api.mch.weixin.qq.com/pay/unifiedorder';
    function __construct()
    {
        $this->appid = ConfigHelper::getConfig('Wxpay_config')['appid'];
        $this->partnerId = ConfigHelper::getConfig('Wxpay_config')['mch_id'];
        $this->notify_url = ConfigHelper::getConfig('Wxpay_config')['notify_url'];
        $this->key = ConfigHelper::getConfig('Wxpay_config')['key'];
    }
    //生成订单
    public function wechat_pay($body, $out_trade_no, $total_fee){
        $data["appid"] = $this->appid;
        $data["mch_id"] = $this->partnerId;
        $data["nonce_str"] = $this->getRandChar(32);
        $data["body"] = $body;
        $data["notify_url"] = $this->notify_url;
        $data["out_trade_no"] = $out_trade_no;
        $data["spbill_create_ip"] = $this->get_client_ip();
        $data["total_fee"] = $total_fee;
        $data["trade_type"] = "APP";
        $time_expire = date('YmdHis',time()+1200);  //失效时间20分钟
        $data["time_expire"] = $time_expire;
 
        $sign = $this->getSign($data);
        $data["sign"] = $sign;
        //配置xml最终得到最终发送的数据
        $formData=$this->data_to_xml($data);
        $response = $this->postXmlCurl($formData,self::URL);
        //将微信返回的结果xml转成数组
        $params = (array)simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);
        if($params['return_code'] != 'SUCCESS'){
            return Helper::ajaxFail($params);
        }else{
            $timestamp = time();
            //接收微信返回的数据,传给APP!
            $arr =array(
                'prepayid' =>$params['prepay_id'],
                'appid' => $this->appid,
                'partnerid' => $this->partnerId,
                'package' => 'Sign=WXPay',
                'noncestr' => $data["nonce_str"],
                'timestamp' => strval($timestamp),
            );
            //第二次生成签名
            $s = $this->getSign($arr);
            $arr['sign'] = $s;
            return Helper::ajaxSuccess($arr);
        }
    }
    //进行签名
    function getSign($Obj)
    {
        foreach ($Obj as $k => $v)
        {
            $arr[strtolower($k)] = $v;
        }
        ksort($arr);
        $string = $this->ToUrlParams($arr);
        $string = $string. "&key=".$this->key;
        $string = md5($string);
        $paySign = strtoupper($string);
        return $paySign;
    }
 
    public function https_request($url, $post_data = '', $timeout = 5){//curl
        $ch = curl_init();
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_POST, 1);
        if($post_data != ''){
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        }
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_HEADER, false);
        $file_contents = curl_exec($ch);
        curl_close($ch);
        return $file_contents;
    }
 
    public function data_to_xml( $params ){
        if(!is_array($params)|| count($params) <= 0)
        {
            return false;
        }
        $xml = "<xml>";
        foreach ($params as $key=>$val){
            // if (is_numeric($val)){
            $xml.="<".$key.">".$val."</".$key.">";
            // }else{
            //     $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            // }
        }
        $xml.="</xml>";
        return $xml;
    }
    //获取指定长度的随机字符串
    private function getRandChar($length){
        $str = null;
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol)-1;
 
        for($i=0;$i<$length;$i++){
            $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
        }
 
        return $str;
    }
 
    public function ToUrlParams($arr)
    {
        $buff = "";
        foreach ($arr as $k => $v)
        {
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }
 
    //获取当前服务器的IP
    function get_client_ip()
    {
        if ($_SERVER['REMOTE_ADDR']) {
            $cip = $_SERVER['REMOTE_ADDR'];
        } elseif (getenv("REMOTE_ADDR")) {
            $cip = getenv("REMOTE_ADDR");
        } elseif (getenv("HTTP_CLIENT_IP")) {
            $cip = getenv("HTTP_CLIENT_IP");
        } else {
            $cip = "unknown";
        }
        return $cip;
    }
    //将数组转成uri字符串
    function formatBizQueryParaMap($paraMap, $urlencode)
    {
        $buff = "";
        $reqPar='';
        ksort($paraMap);
        foreach ($paraMap as $k => $v)
        {
            if($urlencode)
            {
                $v = urlencode($v);
            }
            $buff .= strtolower($k) . "=" . $v . "&";
        }
        if (strlen($buff) > 0)
        {
            $reqPar = substr($buff, 0, strlen($buff)-1);
        }
        return $reqPar;
    }
    //数组转xml
    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;
    }
    //post https请求,CURLOPT_POSTFIELDS xml格式
    function postXmlCurl($xml,$url,$second=30)
    {
        //初始化curl
        $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
        $data = curl_exec($ch);
        //返回结果
        if($data)
        {
            curl_close($ch);
            return $data;
        }
        else
        {
            $error = curl_errno($ch);
            curl_close($ch);
            return false;
        }
    }
 
    //xml转成数组
    public function xmlstr_to_array($xmlstr) {
        $doc = new \DOMDocument();
        $doc->loadXML($xmlstr);
        return $this->domnode_to_array($doc->documentElement);
    }
    public function domnode_to_array($node) {
        $output = array();
        switch ($node->nodeType) {
            case XML_CDATA_SECTION_NODE:
            case XML_TEXT_NODE:
                $output = trim($node->textContent);
                break;
            case XML_ELEMENT_NODE:
                for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) {
                    $child = $node->childNodes->item($i);
                    $v = $this->domnode_to_array($child);
                    if(isset($child->tagName)) {
                        $t = $child->tagName;
                        if(!isset($output[$t])) {
                            $output[$t] = array();
                        }
                        $output[$t][] = $v;
                    }
                    elseif($v) {
                        $output = (string) $v;
                    }
                }
                if(is_array($output)) {
                    if($node->attributes->length) {
                        $a = array();
                        foreach($node->attributes as $attrName => $attrNode) {
                            $a[$attrName] = (string) $attrNode->value;
                        }
                        $output['@attributes'] = $a;
                    }
                    foreach ($output as $t => $v) {
                        if(is_array($v) && count($v)==1 && $t!='@attributes') {
                            $output[$t] = $v[0];
                        }
                    }
                }
                break;
        }
        return $output;
    }
    //微信支付成功以后的回调
    public function notify()
    {
        $content = Request::instance()->getContent();
        file_put_contents('test.txt',$content);
        $result = json_decode(json_encode(simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        //效验签名
        $sign = $this->getSign($result);
        if ($sign == $result['sign']) {
            return $result;
        } else {
            return false;
        }
 
    }
 
 
 
 
}

 

 

<?php
namespace app\app_frontend\controller;
 
use Wxpay\WechatAppPay;
 
 
/**
 * @desc 微信支付接口
 */
 
class Wxpay extends Common {
 
    public function pay(){
        $body = '测试';
        $out_trade_no = "wx".rand(1, 20).date('YmdHis',time());  //订单号
        $total_fee = 0.01 * 100;
        $WeChat = new WechatAppPay();
        $res = $WeChat->wechat_pay($body, $out_trade_no, $total_fee);
        return $res;
    }
 
}

 

/**
     * @return \think\response\Json
     * @desc 微信异步通知
     */
    public function WxPayBack(){
        $WeChat = new WechatAppPay();
        $res = $WeChat->notify();
        if($res){ //签名验证通过后期处理
            if($res['result_code'] == 'SUCCESS'){
                //交易支付成功
                $data = array(
                    'out_trade_no' => $res['out_trade_no'],
                    'trade_no' => $res['transaction_id'],
                    'total_amount' => $res['total_fee'] / 100,
                    'gmt_payment' => date( 'Y-m-d H:i:s',strtotime($res['time_end']) ),
                );
                ChargeRecordModel::getInstance()->dataUpdate($data);  //订单处理
                $info = array(
                    'return_code' => 'SUCCESS',
                    'return_msg' => 'OK'
                );
                $formData=$this->arrayToXml($info);
                return $formData;
            }
        }
 
    }

配置参数:

//微信支付相关配置
        'Wxpay_config' => array (
            'appid' => '',  //应用id
            'mch_id' => '',  //商户id
            'key' => '',  //商户秘钥
            'notify_url' => ''  //支付回调地址
        ),

Guess you like

Origin www.cnblogs.com/ashuaideboke/p/12132987.html