PHP:微信小程序调用【统一下单】【微信支付】【支付回调】API;XML转Array,Array转XML方法(通用)

时间:2024-02-24 11:22:50

1、微信公众号、微信小程序开发过程中,第三方服务器与微信服务器数据交互,需要进行数据转换,必须用到这两个函数:

分别是xml_to_array、array_to_xml ;

    /**
     * 输出xml字符(数组转换成xml)
     * @param $params 参数名称
     * return string 返回组装的xml
     **/
    public function array_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;
    }
    /**
     * 将xml转为array
     * @param string $xml
     * return array
     */
    public function xml_to_array($xml){
        if(!$xml){
            return false;
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $data = json_decode(json_encode(simplexml_load_string($xml, \'SimpleXMLElement\', LIBXML_NOCDATA)), true);
        return $data;
    }

2、拼接参数,将数组转换成键值对形式的字符串:key=value&k=v

    /**
     * 将参数拼接为url: key=value&key=value
     * @param $params
     * @return string
     */
    public function ToUrlParams( $params ){
        $string = \'\';
        if( !empty($params) ){
            $array = array();
            foreach( $params as $key => $value ){
                $array[] = $key.\'=\'.$value;
            }
            $string = implode("&",$array);
        }
        return $string;
    }

3、微信小程序生成签名,makeSign($params,$KEY),第一个参数是微信官方文档需要的参数;第二个参数是 申请微信支付获得的KEY

    /**
     * 生成签名, $KEY就是支付key
     * @return 签名
     */
    public function MakeSign( $params,$KEY){
        //签名步骤一:按字典序排序数组参数
        ksort($params);
        $string = $this->ToUrlParams($params);  //参数进行拼接key=value&k=v
        //签名步骤二:在string后加入KEY
        $string = $string . "&key=".$KEY;
        //签名步骤三:MD5加密
        $string = md5($string);
        //签名步骤四:所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

4、微信小程序的签名,总共需要三次;期中前两次是必须的,最后一次尽量加上

  4.1 第一次是【统一下单】,将所有需要的信息进行生成签名,包括:

$post[\'appid\'] = $appid;
$post[\'body\'] = $body;
$post[\'mch_id\'] = $mch_id;
$post[\'nonce_str\'] = $nonce_str;//随机字符串
$post[\'notify_url\'] = $notify_url;
$post[\'openid\'] = $openid;
$post[\'out_trade_no\'] = $out_trade_no;
$post[\'spbill_create_ip\'] = $spbill_create_ip;//服务器终端的ip
$post[\'total_fee\'] = intval($total_fee); //总金额 最低为一分钱 必须是整数
$post[\'trade_type\'] = $trade_type;
$sign = $this->MakeSign($post,$KEY); //签名

..等等信息;

 4.2 第二次是根据【统一下单】获得的"PREPAY_ID",和申请支付获得的KEY,进行makeSign签名,返回给前端(如JS、APP等)进行调用wx.requestPayment({...})微信支付,包括:

$tmp[\'appId\'] = $appid;
$tmp[\'nonceStr\'] = $nonce_str;
$tmp[\'package\'] = \'prepay_id=\'.$array[\'PREPAY_ID\'];
$tmp[\'signType\'] = \'MD5\';
$tmp[\'timeStamp\'] = "$time";

//上面是签名所需数据,下面是返回数据

$data[\'timeStamp\'] = "$time";

$data[\'nonceStr\'] = $nonce_str;

$data[\'signType\'] = \'MD5\';

$data[\'paySign\'] = $this->MakeSign($tmp,$KEY);

$data[\'package\'] = \'prepay_id=\'.$array[\'PREPAY_ID\'];

($array是【统一下单】返回的数据,经过了xml_to_array处理)

  4.3 第三次是微信将支付结果通知给商户,商户需要进行处理通知结果。(通俗点:就是微信告诉你,用户支付成功,你要给微信回一句话:我知道了。)

这个时候也需要makeSing签名,具体代码如下:

/* 微信支付完成,回调地址url方法  xiao_notify_url() */
    public function xiao_notify_url(){
        $KEY = \'你申请微信支付的KEY\';
        $post = post_data();    //接受POST数据
        $post_data = $this->xml_to_array($post);   //微信支付成功,返回回调地址url的数据:XML转数组Array
        $postSign = $post_data[\'sign\'];
        unset($post_data[\'sign\']);    //这里很重要哦,一定要将返回的sign剔除掉
        
        /* 微信官方提醒:
         *  商户系统对于支付结果通知的内容一定要做【签名验证】,
         *  并校验返回的【订单金额是否与商户侧的订单金额】一致,
         *  防止数据泄漏导致出现“假通知”,造成资金损失。
        */
        ksort($post_data);// 对数据进行排序
        //正常情况微信是不会返回支付的key的,为保万一我们判断一下  --xzz 0622
        if($post_data[\'key\']){
            $str = $this->ToUrlParams($post_data);//对数组数据拼接成key=value字符串
        }else{
            $str = $this->ToUrlParams($post_data).\'&key=\'.$KEY; //这里也一定要加上key,不然签名就错了
        }
        $user_sign = strtoupper(md5($str));   //再次生成签名,与$postSign比较
        
        $where[\'crsNo\'] = $post_data[\'out_trade_no\'];
        $order_msg = M(\'home_order\',\'xxf_witkey_\')->where($where)->find();
        /*
         *  分别判断返回状态码、返回签名sign、返回订单总金额,三者同时为真,订单交易成功,状态修改为‘ok’
        */
        if($post_data[\'return_code\']==\'SUCCESS\'&&$postSign==$user_sign&&$order_msg[\'order_amount\']*100==$post_data[\'total_fee\']){
            /*
            * 首先判断,订单是否已经更新为ok,因为微信会总共发送8次回调确认
            * 其次,订单已经为ok的,直接返回SUCCESS
            * 最后,订单没有为ok的,更新状态为ok,返回SUCCESS
            */
            if($order_msg[\'order_status\']==\'ok\'){
                $this->return_success();
            }else{
                $updata[\'order_status\'] = \'ok\';
                if(M(\'home_order\',\'xxf_witkey_\')->where($where)->save($updata)){
                    $this->return_success();
                }
            }
        }else{
            echo \'微信支付失败\';
        }
    }
    
    /*
     * 给微信发送确认订单金额和签名正确,SUCCESS信息 -xzz0521
     */
    private 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;
    }

 5、再次提醒一下,这个代码是给微信小程序用的,其他的别照搬哦。