通过PHP处理微信支付回调–处理通知消息和业务逻辑

发布于 2023-06-04  480 次阅读


内容纲要

微信支付在用户完成付款时会将回调数据通知给在服务端下单时传入的回调通知地址,商户服务器在接受到微信的回调通知后,需要正确处理业务逻辑并且按照微信规定返回状态信息,如果微信得到的回应不合法,则会在一段时间后再次通知,因此服务端必须在得到回调通知时判断订单状态来确定是否已经处理订单,并且合法返回结果数据,否则如果微信多次通知结果,服务端对结果处理的业务代码的验证不严谨,会导致多次处理订单造成业务损失。

整个回调通知的逻辑比较简单:

  1. 用户完成支付
  2. 微信处理数据,打包为XML
  3. 将XML数据发送到商户服务端
  4. 商户接收并处理XML数据,进行业务逻辑
  5. 完成业务的处理后,返回成功状态码
  6. 微信判断商户的响应内容是否合法,如果不合法则再次发起通知

(一)、微信通知数据规范

微信通知数据采用XML格式,商户服务器需要对XML数据进行解析并且编写相应代码来处理业务逻辑。

在微信通知的数据包括:

其中包括发起支付的商户信息、支付的商户订单信息、微信支付平台订单信息以及支付状态的相关参数。

在v2版本接口中微信回调通知以xml格式发送到商户服务端。

(二)、商户服务端接收通知消息

服务端需要通过获得输入流来接收微信服务器发送的回调通知,在v2接口中以xml数据的格式返回,回调的通知地址为统一下单时传递的url内容,当用户完成支付后微信会将结果通知到这个url。

首先发起一个支付测试,回调通知地址设定为:

http://msg.1haodh.com/wepay/finish

在对应的方法中写入测试获取通知结果的代码,通过输入流得到字符串,然后存放到根目录的paylogs.txt中:

public function notify(){
        $data=file_get_contents("php://input");
        file_put_contents("logpay.txt",json_encode($data));
    }

发起支付测试:

查看paylogs.txt:

"<xml><appid><![CDATA[wxea657d3cd3c701a5]]><\/appid>\n<bank_type><![CDATA[OTHERS]]><\/bank_type>\n<cash_fee><![CDATA[1]]><\/cash_fee>\n<fee_type><![CDATA[CNY]]><\/fee_type>\n<is_subscribe><![CDATA[Y]]><\/is_subscribe>\n<mch_id><![CDATA[1609608650]]><\/mch_id>\n<nonce_str><![CDATA[67c8rnsab9s1yyubzxj0znt1s34vg3cd]]><\/nonce_str>\n<openid><![CDATA[oZfnW532CIlKZMvh7HlOjF-yD39U]]><\/openid>\n<out_trade_no><![CDATA[2306041856108959732]]><\/out_trade_no>\n<result_code><![CDATA[SUCCESS]]><\/result_code>\n<return_code><![CDATA[SUCCESS]]><\/return_code>\n<sign><![CDATA[E1303E31F3AF182534A63555C64EC5FF]]><\/sign>\n<time_end><![CDATA[20230604185620]]><\/time_end>\n<total_fee>1<\/total_fee>\n<trade_type><![CDATA[JSAPI]]><\/trade_type>\n<transaction_id><![CDATA[4200001812202306041184186536]]><\/transaction_id>\n<\/xml>"

得到json转码后的xml通知字符串,确认支付结果通知没有问题,接下来进行商户订单处理。

(三)、商户订单处理

因为可能存在出乎意料的错误,导致微信多次通知支付结果,所以必须按照规范进行开发,商户处理订单的逻辑应该为:

  • 商户得到微信通知的结果内容
  • 商户获取通知结果内的商户订单号和微信订单号
  • 判断商户订单号和微信订单号以及支付金额等是否一致
  • 判断商户内订单处理状态,若未处理则进行处理订单,若已处理则略过,直接向微信服务器返回成功
  • 若订单未处理则处理订单,并返回成功消息防止微信误判多次通知。

首先获取订单必要信息:

        $data=file_get_contents("php://input");
        $rs=$this->xmlParse($data);
        // 商户订单号
        $out_order=$rs[0]['XML']['OUT_TRADE_NO']['content'];
        // 微信支付订单号
        $order_no=$rs[0]['XML']['TRANSACTION_ID']['content'];
        //支付金额
        $total_fee=((float)$rs[0]['XML']['TOTAL_FEE']['content'])/100;
        // 支付完成时间
        $finish_time=$rs[0]['XML']['TIME_END']['content']

对通知结果进行处理:

            $order_in=Db::table('order')->where("order_sn",$out_order)->select()[0];
            if(!empty($order_in['pay_sn'])){
                return ["return_code"=>"SUCCESS"];
            }else if($order_in['pay_sn']==NULL){
                // 执行未处理订单的业务逻辑。首先判断金额是否正确
                if($order_in['price']<>$total_fee){
                    // 更新订单处理状态
                    DB::table('order')->where('order_sn',$out_order)->update(['pay_sn'=>$order_no,'result'=>'付款金额不一致,联系客服处理']);
                    //返回处理状态
                    return ["return_code"=>"SUCCESS"];
                }else{
                    // 执行验证完成的业务逻辑,进行发货
                }
            }
届ける言葉を今は育ててる
最后更新于 2023-06-04