Third party calls wechat payment interface

Time:2021-4-21

Step one: preparation

1. Wechat payment interface can only be called if the developer qualification has been authenticated on wechat open platform, so the first thing is to authenticate. It’s very simple, but wechat will charge 300 yuan for audit

2. Set payment directory

Login wechat payment merchant platform( pay.weixin.qq . com) — > Product Center — > development configuration, set it, and it will take effect within 5 minutes after setting.

This is the official document of wechat

3. Set authorized domain name

In fact, if you have done wechat login before, you don’t need to do it, because it has been set before

The reason why we need to set the authorized domain name is to get the openid. In the unified order interface, it is required to transfer the user‘s openid. Only those who have set the authorized domain name can get the effective openid. (if the user gets the unionid of the open platform when logging in, you can also pay successfully by changing the unionid attribute name to openid when placing an order.)

Step 2: start

1. The first step

The user clicks the payment button to make a request

function bay(pid,uid,money,name){
          $.ajax({
            url:ajaxurl+'/Car/payh5',
            dataType: 'json',
            data:{
                pid:pid , // commodity ID
                uid:uid , // user ID
                money:money , // price
                Name: name, // product name
                 },
            type: 'post',
            success: function (data) {
                 var state=data.state;
                 if(state==0){
                     var RETURN_MSG =data.RETURN_MSG;
                         alert(RETURN_MSG);
                  }else{
                         callpay(data);
                        }
             }
        });
}

2. Step two

According to the front-end parameters, query the user and commodity details, generate payment orders

public function pay()
    {   
        
           //Access to information needed for wechat payment
        /**
        *@ param [sting] $appid [applets appid]
        *@ param [sting] $openid [user openid]
        * @param [sting] $mch_ ID [merchant ID] (ID of wechat merchant platform)
        *@ param [sting] $key [merchant key] (key of wechat merchant platform)
        *@ param [sting] $money [payment amount]
        *@ param [sting] $body [product description]
        * @param [sting] $notify_ URL [callback address] the callback address is written after
        *@ return [sting] $data [response data] 
        */
        $merchpay = new \WeiXinPay($appid,$openid,$mch_id,$key,$money,$body,$notify_status,$o_number);
        $data = $merchpay->Pay();
          $data['appId']=$appid;
        echo $this->ajaxReturn($data);
    }

I’ve omitted the steps of adding orders to my data table here. Don’t forget to use them

After that, the parameters are transformed into XML and the unified interface is called

class WeiXinPay{
    private $appid;
    private $openid;
    private $mch_id;
    private $key;
    private $money;
    private $body;
    private $notify_status;
    private $order_id;
    public function __construct($appid,$openid,$mch_id,$key,$money,$body,$notify_status,$order_id)
    {                            
        $this->appid = $appid;
        $this->openid = $openid;
        $this->mch_id = $mch_id;
        $this->key = $key;
        $this->money = $money;
        $this->body = $body;
        $this->notify_status = $notify_status;
        $this->order_id = $order_id;
    }
    public function Pay()
    {   
 
        $fee = $this - > money; // for example, recharge 0.01
        $appid = $this - > appid; // pay appid
        $body =         $this->body;
        $mch_id =       $this->mch_id;
        $nonce_ str =    $this->nonce_ Str(); // random string
        // $notify_url =   $this->$notify_url;
        if($this->notify_status==1){
            $notify_url ='http://'.$_SERVER['HTTP_HOST'].U('Car/notify');
        }else{
            $notify_url ='http://'.$_SERVER['HTTP_HOST'].U('Car/qnotify');
        }
        
        // p($notify_url);
        $openid =       $this->openid;
        $order_id =     $this->order_id;
        $getServerIP=   $this->getServerIP();
        // $out_ trade_ no = $this->order_ Number ($openid); // merchant order number
        $out_ trade_ no = $order_ ID; // merchant order number
        $spbill_create_ip = $getServerIP;//ip
        $total_ Fee = $fee * 100; // because the minimum recharge amount is 1 and the unit is Fen, if it is 1 yuan, you need * 100 here
        $trade_ Type ='jsapi '; // default transaction type
        //This is in order, because the signature below is in order. Wrong. Wrong
        $post['appid'] = $appid;
        $post['body'] = $body;
        $post['mch_id'] = $mch_id;
        $post['nonce_ str'] = $nonce_ str;// Random string
        $post['notify_url'] = $notify_url;
        $post['openid'] = $openid;
        $post['out_trade_no'] = $out_trade_no;
        $post['spbill_ create_ ip'] = $spbill_ create_ IP; // terminal IP
        $post['total_ fee'] = $total_ Fee; // the minimum total amount is one yuan. It must be an integer
        $post['trade_type'] = $trade_type;
        $sign = $this - > sign ($post); // sign
        $post_xml = '
               '.$appid.'
               '.$body.'
               '.$mch_id.'
               '.$nonce_str.'
               '.$notify_url.'
               '.$openid.'
               '.$out_trade_no.'
               '.$spbill_create_ip.'
               '.$total_fee.'
               '.$trade_type.'
               '.$sign.'
             ';
        //Unified interface prepay_ id
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $xml = $this->http_request($url,$post_xml);
        $array = $this - > XML ($XML); // all in uppercase
        // var_dump($array);exit;
        if($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS'){
            $time = time();
            $TMP = '; // temporary array for signature
            $tmp['appId'] = $appid;
            $tmp['nonceStr'] = $nonce_str;
            $tmp['package'] = 'prepay_id='.$array['PREPAY_ID'];
            $tmp['signType'] = 'MD5';
            $tmp['timeStamp'] = "$time";
 
            $data['state'] = 1;
            $data ['timestamp '] = $time "; // timestamp
            $data['nonceStr'] = $nonce_ Str; // random string
            $data['signType'] = 'MD5';// Signature algorithm, temporarily support MD5
            $data['package'] = 'prepay_ id='.$array['PREPAY_ ID ']; // prepay returned by unified ordering interface_ ID parameter value, submission format, such as: prepay_ id=*
            $data['paySign'] = $this->sign($tmp);// Signature, specific signature scheme, see WeChat official account for help documents;
            $data['out_trade_no'] = $out_trade_no;
        }else{
            $data['state'] = 0;
            $data ['text '] = error;
            $data['RETURN_CODE'] = $array['RETURN_CODE'];
            $data['RETURN_MSG'] = $array['RETURN_MSG'];
        }
        // var_dump($data);exit;
        $data = json_encode($data);
        return json_decode($data,true);
    }

Several methods are called in this pay () method

32-bit random string

private function nonce_str()
    {
        $result = '';
        $str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
        for ($i=0;$i<32;$i++){
            $result .= $str[rand(0,48)];
        }
        return $result;
    }

Sign $data in order

private function sign($data)
    {
        $stringA = '';
        foreach ($data as $key=>$value){
            if(!$value) continue;
            if($stringA) $stringA .= '&'.$key."=".$value;
            else $stringA = $key."=".$value;
        }
        $wx_ Key = $this - > key; // after applying for payment, a merchant account and password are given. After logging in, set the key yourself
        $stringSignTemp = $stringA.'&key='.$wx_key;
        return strtoupper(md5($stringSignTemp));
    }

Get XML

private function xml($xml)
    {
        $p = xml_parser_create();
        xml_parse_into_struct($p, $xml, $vals, $index);
        xml_parser_free($p);
        $data = "";
        foreach ($index as $key=>$value) {
            if($key == 'xml' || $key == 'XML') continue;
            $tag = $vals[$value[0]]['tag'];
            $value = $vals[$value[0]]['value'];
            $data[$tag] = $value;
        }
        return $data;
    }

Curl request

private function http_request($url,$data = null,$headers=array())
    {
        $curl = curl_init();
        if( count($headers) >= 1 ){
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (!empty($data)){
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

After that is the callback method notify (), which is used to receive and process the parameters returned by wechat

//Wechat payment callback
    public function notify()
    {   
        $post =$GLOBALS['HTTP_ RAW_ POST_ DATA'];// Number of accepted Post Data XML
        $post_ Data = $this - > xmltoarray ($post); // wechat payment is successful, return the data of callback address URL: XML to array
        
        $postSign = $post_data['sign'];
        file_put_contents('log1.txt',$postSign);
        unset($post_data['sign']);
        // $post_data=unset($post_data['sign']);
 
        /*Wechat official reminder:
         *The merchant system must do [signature verification] for the content of the payment result notice,
         *And check whether the returned order amount is consistent with the order amount on the merchant side,
         *To prevent data leakage leading to "false notice", resulting in financial losses.
         */
        $str = $this->sign($post_ Data); // splice the array data into a key = value string
        //Judge signature
        file_put_contents('log2.txt',$postSign);
        file_put_contents('log3.txt',$str);
        if($postSign!=$str){
            Echo 'wechat payment failed'; exit;
        }
        $where['o_number'] = $post_data['out_trade_no'];
        $order_status = M('new_order')->where($where)->find();
 
        if($post_data['return_code']=='SUCCESS'&&$postSign){
            /*
            *First, judge whether the order has been updated to OK, because wechat will send a total of 8 callback confirmations
            *Secondly, if the order is OK, return to success directly
            *Finally, if the order is not OK, update the status to OK and return success
            */
            $updata['status'] = '2';
            // $updata['time']=date('Y-m-d H:i:s',time());
            if(M('new_order')->where($where)->save($updata)!=false){
                $new_order=M('new_order')->where($where)->find();
                M('new_order')->where(array('uid'=>$new_order['uid'],'status'=>1))->delete();
                
                $this->return_success();
            }
                   
              echo exit('');
               
        }else{
            Echo 'wechat payment failed';
        }
    }

Notification successful

public function return_success()
        {
            $return['return_code'] = 'SUCCESS';
            $return['return_msg'] = 'OK';
            $xml_post = '
                        '.$return['return_code'].'
                        '.$return['return_msg'].'
                        ';
            echo $xml_post;exit;
        }

It’s basically over here, and then it’s logical processing according to the results returned by wechat

This is the official development document of wechathttps://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4

 

If the payment notice is not received and the payment status cannot be determined, the wechat order query interface can be called to actively query the order status and complete the last step

Order query interface:https://api.mch.weixin.qq.com/pay/orderquery

Required parameters:

appid
   Merchant number
   Random character
   Wechat order number / merchant order number (one out of two)
   autograph

Parameters returned:

Of course, the returned data seems to be too much. In fact, you only need to find what you want to use

For example, as long as you judge whether the payment is successful, you only need to use the trade_ The state parameter is OK

trade_ Explanation represented by the value of state:

Success – payment success

Refund – transfer in refund

Notpay – unpaid

Closed – closed

Revoked – cancelled (payment code payment)

User paying (payment code payment)

Payerror — payment failure (other reasons, such as bank return failure)