top

php 微信支付回调校验的两种做法(校验了签名)

支付的时候设置了异步回调地址
微信回调返回的数据是xml

 

<xml><appid><![CDATA[wx6a94d840sssssss]]></appid>
<attach><![CDATA[test]]></attach>
<bank_type><![CDATA[OTHERS]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[Y]]></is_subscribe>
<mch_id><![CDATA[1602876300]]></mch_id>
<nonce_str><![CDATA[5dh7wiradptg55udp7w9rmlrur8madrv]]></nonce_str>
<openid><![CDATA[oo44a5uldojwVmL27KS4R0APR_gw]]></openid>
<out_trade_no><![CDATA[sdkphp20210305164812]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<sign><![CDATA[BD851430C2493F16A49B70A5B5D26DE4F2906B1CB3B5B969193DB9671DAE4AAF]]></sign>
<time_end><![CDATA[20210305164816]]></time_end>
<total_fee>1</total_fee>
<trade_type><![CDATA[JSAPI]]></trade_type>
<transaction_id><![CDATA[4200000892202103057215065043]]></transaction_id>
</xml>

直接用post或者get是获取不到微信返回的数据,需要使用 file_get_contents("php://input");

实现代码

/**
* @return string
*/
public function notify(): string
{
$xmlstr = file_get_contents("php://input");
if(empty($xmlstr)) return '非法访问';
$xmlObj = simplexml_load_string($xmlstr, 'SimpleXMLElement', LIBXML_NOCDATA);
$data = json_decode(json_encode($xmlObj),true);
if ($this->checkSign($data)) {
//校验通过,可以再增加对微信官方订单查询,判断订单真实性
return 'success';
}
return 'fail';
}
/**校验签名
* @param array $arr
* @return bool
*/
private function checkSign(array $arr): bool
{
$sign = $arr['sign'];
unset($arr['sign']);
$key='1234';//微信商户平台支付设置的key
ksort($arr);//根据key升序排序
$str=http_build_query($arr);//数组字典排序拼接字符串
$stringSignTemp = $str.'&key='.$key;//拼接上key
$signValue = md5($stringSignTemp);//md5处理
$signValue = strtoupper($signValue);//转大写
return $signValue == $sign;
}
/** * @return string */ public function notify(): string { $xmlstr = file_get_contents("php://input"); if(empty($xmlstr)) return '非法访问'; $xmlObj = simplexml_load_string($xmlstr, 'SimpleXMLElement', LIBXML_NOCDATA); $data = json_decode(json_encode($xmlObj),true); if ($this->checkSign($data)) { //校验通过,可以再增加对微信官方订单查询,判断订单真实性 return 'success'; } return 'fail'; } /**校验签名 * @param array $arr * @return bool */ private function checkSign(array $arr): bool { $sign = $arr['sign']; unset($arr['sign']); $key='1234';//微信商户平台支付设置的key ksort($arr);//根据key升序排序 $str=http_build_query($arr);//数组字典排序拼接字符串 $stringSignTemp = $str.'&key='.$key;//拼接上key $signValue = md5($stringSignTemp);//md5处理 $signValue = strtoupper($signValue);//转大写 return $signValue == $sign; }
    /**
     * @return string
     */
    public function notify(): string
    {
        $xmlstr = file_get_contents("php://input");
        if(empty($xmlstr)) return '非法访问';
        $xmlObj = simplexml_load_string($xmlstr, 'SimpleXMLElement', LIBXML_NOCDATA);
        $data = json_decode(json_encode($xmlObj),true);
        if ($this->checkSign($data)) {
        //校验通过,可以再增加对微信官方订单查询,判断订单真实性
            return 'success';
        }
        return 'fail';
    }
    /**校验签名
     * @param array $arr
     * @return bool
     */
    private function checkSign(array $arr): bool
    {
        $sign = $arr['sign'];
        unset($arr['sign']);
        $key='1234';//微信商户平台支付设置的key
        ksort($arr);//根据key升序排序
        $str=http_build_query($arr);//数组字典排序拼接字符串
        $stringSignTemp = $str.'&key='.$key;//拼接上key
        $signValue = md5($stringSignTemp);//md5处理
        $signValue = strtoupper($signValue);//转大写
        return $signValue == $sign;

    }

也可以这样,直接使用官方SDK

require_once "../lib/WxPay.Api.php";
require_once '../lib/WxPay.Notify.php';
require_once "WxPay.Config.php";
require_once 'log.php';
//初始化日志
$logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log');
$log = Log::Init($logHandler, 15);
class PayNotifyCallBack extends WxPayNotify
{
//查询订单
public function Queryorder($transaction_id)
{
$input = new WxPayOrderQuery();
$input->SetTransaction_id($transaction_id);
$config = new WxPayConfig();
$result = WxPayApi::orderQuery($config, $input);
Log::DEBUG("query:" . json_encode($result));
if(array_key_exists("return_code", $result)
&& array_key_exists("result_code", $result)
&& $result["return_code"] == "SUCCESS"
&& $result["result_code"] == "SUCCESS")
{
return true;
}
return false;
}
/**
*
* 回包前的回调方法
* 业务可以继承该方法,打印日志方便定位
* @param string $xmlData 返回的xml参数
*
**/
public function LogAfterProcess($xmlData)
{
Log::DEBUG("call back, return xml:" . $xmlData);
return;
}
//重写回调处理函数
/**
* @param WxPayNotifyResults $data 回调解释出的参数
* @param WxPayConfigInterface $config
* @param string $msg 如果回调处理失败,可以将错误信息输出到该方法
* @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调
*/
public function NotifyProcess($objData, $config, &$msg)
{
var_dump($objData);
$data = $objData->GetValues();
//TODO 1、进行参数校验
if(!array_key_exists("return_code", $data)
||(array_key_exists("return_code", $data) && $data['return_code'] != "SUCCESS")) {
//TODO失败,不是支付成功的通知
//如果有需要可以做失败时候的一些清理处理,并且做一些监控
$msg = "异常异常";
return false;
}
if(!array_key_exists("transaction_id", $data)){
$msg = "输入参数不正确";
return false;
}
//TODO 2、进行签名验证
try {
$checkResult = $objData->CheckSign($config);
if($checkResult == false){
//签名错误
Log::ERROR("签名错误...");
return false;
}
} catch(Exception $e) {
Log::ERROR(json_encode($e));
}
//TODO 3、处理业务逻辑
Log::DEBUG("call back:" . json_encode($data));
$notfiyOutput = array();
//查询订单,判断订单真实性
if(!$this->Queryorder($data["transaction_id"])){
$msg = "订单查询失败";
return false;
}
return true;
}
}
$config = new WxPayConfig();
Log::DEBUG("begin notify");
$notify = new PayNotifyCallBack();
$notify->Handle($config, false);
require_once "../lib/WxPay.Api.php"; require_once '../lib/WxPay.Notify.php'; require_once "WxPay.Config.php"; require_once 'log.php'; //初始化日志 $logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log'); $log = Log::Init($logHandler, 15); class PayNotifyCallBack extends WxPayNotify { //查询订单 public function Queryorder($transaction_id) { $input = new WxPayOrderQuery(); $input->SetTransaction_id($transaction_id); $config = new WxPayConfig(); $result = WxPayApi::orderQuery($config, $input); Log::DEBUG("query:" . json_encode($result)); if(array_key_exists("return_code", $result) && array_key_exists("result_code", $result) && $result["return_code"] == "SUCCESS" && $result["result_code"] == "SUCCESS") { return true; } return false; } /** * * 回包前的回调方法 * 业务可以继承该方法,打印日志方便定位 * @param string $xmlData 返回的xml参数 * **/ public function LogAfterProcess($xmlData) { Log::DEBUG("call back, return xml:" . $xmlData); return; } //重写回调处理函数 /** * @param WxPayNotifyResults $data 回调解释出的参数 * @param WxPayConfigInterface $config * @param string $msg 如果回调处理失败,可以将错误信息输出到该方法 * @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调 */ public function NotifyProcess($objData, $config, &$msg) { var_dump($objData); $data = $objData->GetValues(); //TODO 1、进行参数校验 if(!array_key_exists("return_code", $data) ||(array_key_exists("return_code", $data) && $data['return_code'] != "SUCCESS")) { //TODO失败,不是支付成功的通知 //如果有需要可以做失败时候的一些清理处理,并且做一些监控 $msg = "异常异常"; return false; } if(!array_key_exists("transaction_id", $data)){ $msg = "输入参数不正确"; return false; } //TODO 2、进行签名验证 try { $checkResult = $objData->CheckSign($config); if($checkResult == false){ //签名错误 Log::ERROR("签名错误..."); return false; } } catch(Exception $e) { Log::ERROR(json_encode($e)); } //TODO 3、处理业务逻辑 Log::DEBUG("call back:" . json_encode($data)); $notfiyOutput = array(); //查询订单,判断订单真实性 if(!$this->Queryorder($data["transaction_id"])){ $msg = "订单查询失败"; return false; } return true; } } $config = new WxPayConfig(); Log::DEBUG("begin notify"); $notify = new PayNotifyCallBack(); $notify->Handle($config, false);
require_once "../lib/WxPay.Api.php";
require_once '../lib/WxPay.Notify.php';
require_once "WxPay.Config.php";
require_once 'log.php';

//初始化日志
$logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log');
$log = Log::Init($logHandler, 15);

class PayNotifyCallBack extends WxPayNotify
{
    //查询订单
    public function Queryorder($transaction_id)
    {
        $input = new WxPayOrderQuery();
        $input->SetTransaction_id($transaction_id);

        $config = new WxPayConfig();
        $result = WxPayApi::orderQuery($config, $input);
        Log::DEBUG("query:" . json_encode($result));
        if(array_key_exists("return_code", $result)
            && array_key_exists("result_code", $result)
            && $result["return_code"] == "SUCCESS"
            && $result["result_code"] == "SUCCESS")
        {
            return true;
        }
        return false;
    }

    /**
    *
    * 回包前的回调方法
    * 业务可以继承该方法,打印日志方便定位
    * @param string $xmlData 返回的xml参数
    *
    **/
    public function LogAfterProcess($xmlData)
    {
        Log::DEBUG("call back, return xml:" . $xmlData);
        return;
    }
    
    //重写回调处理函数
    /**
     * @param WxPayNotifyResults $data 回调解释出的参数
     * @param WxPayConfigInterface $config
     * @param string $msg 如果回调处理失败,可以将错误信息输出到该方法
     * @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调
     */
    public function NotifyProcess($objData, $config, &$msg)
    {
        var_dump($objData);
        $data = $objData->GetValues();
        //TODO 1、进行参数校验
        if(!array_key_exists("return_code", $data) 
            ||(array_key_exists("return_code", $data) && $data['return_code'] != "SUCCESS")) {
            //TODO失败,不是支付成功的通知
            //如果有需要可以做失败时候的一些清理处理,并且做一些监控
            $msg = "异常异常";
            return false;
        }
        if(!array_key_exists("transaction_id", $data)){
            $msg = "输入参数不正确";
            return false;
        }

        //TODO 2、进行签名验证
        try {
            $checkResult = $objData->CheckSign($config);
            if($checkResult == false){
                //签名错误
                Log::ERROR("签名错误...");
                return false;
            }
        } catch(Exception $e) {
            Log::ERROR(json_encode($e));
        }

        //TODO 3、处理业务逻辑
        Log::DEBUG("call back:" . json_encode($data));
        $notfiyOutput = array();
        
        
        //查询订单,判断订单真实性
        if(!$this->Queryorder($data["transaction_id"])){
            $msg = "订单查询失败";
            return false;
        }
        return true;
    }
}
$config = new WxPayConfig();
Log::DEBUG("begin notify");
$notify = new PayNotifyCallBack();
$notify->Handle($config, false);

回调返回的数据($data中参考):

[appid] => wx0debacb93cb90fe5

[bank_type] => CFT

[cash_fee] => 1

[fee_type] => CNY

[is_subscribe] => N

[mch_id] => 1238270202

[nonce_str] => 44wugpcoqff9guhpp30e60rok50eb0td

[openid] => ozUTy0PeBNzlPx2cTIjq40T6kUVA

[out_trade_no] => 2017091311090393

[result_code] => SUCCESS

[return_code] => SUCCESS

[sign] => 9C1F65C03B475017864261ADCD2D750D

[time_end] => 20170913110908

[total_fee] => 1

[trade_type] => JSAPI

[transaction_id] => 4000542001201709131822508410

备注:第一种挺方便的,楼主使用的是第一种

回调注意事项:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=23_8&index=6

THE END
icon
0
icon
打赏
icon
分享
icon
二维码
icon
海报