PHP微信支付结果通知与回调策略分析


Posted in PHP onJanuary 10, 2019

本文实例讲述了PHP微信支付结果通知与回调策略。分享给大家供大家参考,具体如下:

支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。

对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒)

注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。

推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。

特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。

$str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
exit($str);
//微信支付回调
public function order_notice(){
    $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
    //将服务器返回的XML数据转化为数组
    $data = $this->FromXml($xml);
    // 保存微信服务器返回的签名sign
    $data_sign = $data['sign'];
    // sign不参与签名算法
    unset($data['sign']);
    //$sign = self::makeSign($data);
    $sign = $this->makeSign($data);
    Clog::setLog($data,'order_notice');
    // 判断签名是否正确 判断支付状态
    if ( ($sign===$data_sign) && ($data['return_code']=='SUCCESS') && ($data['result_code']=='SUCCESS') ) {
      //获取服务器返回的数据
      $order_num = $data['out_trade_no'];     //订单单号
      $openid = $data['openid'];         //付款人openID
      $total_fee = $data['total_fee'];      //付款金额
      $transaction_id = $data['transaction_id']; //微信支付流水号
      $res = $this->order_notice_data_deal($order_num,$openid,$total_fee,$transaction_id);
      if (!$res) {
        $result = -2;
      } else {
        $result = 0;
      }
    }else{
      $result = -1;
    }
    // 返回状态给微信服务器
    if ($result == 0) { // 成功之后不会再回调
      $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
    } elseif ($result == -1){ // 失败后会继续发送几次回调
      $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
    } elseif ($result == -2) { // 失败后会继续发送几次回调
      $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[更改状态失败]]></return_msg></xml>';
    }
    Clog::setLog($result,'order_notice_result');
    exit($str);
}

附上微信支付助手函数

public function ToXml($array){
    if(!is_array($array)|| count($array) <= 0){
      return ;
    }
    $xml = '<xml version="1.0">';
    foreach ($array as $key=>$val){
      if (is_numeric($val)){
        $xml.="<".$key.">".$val."</".$key.">";
      }else{
        $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
      }
    }
    $xml.="</xml>";
    return $xml;
}
public function FromXml($xml){
    if(!$xml){
      // 人工抛出错误
      throw new Exception("xml数据异常!");
    }
    //将XML转为array
    //禁止引用外部xml实体
    libxml_disable_entity_loader(true);
    $this->values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    return $this->values;
}
public function MakeSign($data)
{
    //签名步骤一:按字典序排序参数
    ksort($data);
    $string = $this->ToUrlParams($data);
    //签名步骤二:在string后加入KEY
    $string = $string . "&key=".C('WEIXIN_PAY_KEY');
    //签名步骤三:MD5加密
    $string = md5($string);
    //签名步骤四:所有字符转为大写
    $result = strtoupper($string);
    return $result;
}
public function ToUrlParams($array)
{
    $buff = "";
    foreach ($array as $k => $v)
    {
      if($k != "sign" && $v != "" && !is_array($v)){
        $buff .= $k . "=" . $v . "&";
      }
    }
    $buff = trim($buff, "&");
    return $buff;
}
// createNonceStr
public function createNonceStr($length = 16) {
    $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    $str ="";
    for ( $i = 0; $i < $length; $i++ ) {
      $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
    }
    return $str;
}

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
基于数据库的在线人数,日访问量等统计
Oct 09 PHP
用PHP读取flv文件的播放时间长度
Sep 03 PHP
php循环检测目录是否存在并创建(循环创建目录)
Jan 06 PHP
PHP 日,周,月点击排行统计
Jan 11 PHP
神盾加密解密教程(二)PHP 神盾解密
Jun 08 PHP
PHP基于CURL进行POST数据上传实例
Nov 10 PHP
orm获取关联表里的属性值
Apr 17 PHP
[原创]PHP实现字节数Byte转换为KB、MB、GB、TB的方法
Aug 31 PHP
Yii2框架自定义验证规则操作示例
Feb 08 PHP
Yii2框架控制器、路由、Url生成操作示例
May 27 PHP
PHP实现倒计时功能
Nov 16 PHP
如何使用php生成zip压缩包
Apr 21 PHP
php如何利用pecl安装mongodb扩展详解
Jan 09 #PHP
PHP如何通过表单直接提交大文件详解
Jan 08 #PHP
Laravel 队列使用的实现
Jan 08 #PHP
laravel 框架配置404等异常页面
Jan 07 #PHP
PHP array_shift()用法实例分析
Jan 07 #PHP
PHP parse_ini_file函数的应用与扩展操作示例
Jan 07 #PHP
PHP一个简单的无需刷新爬虫
Jan 05 #PHP
You might like
Mysql的Root密码忘记,查看或修改的解决方法(图文介绍)
2013/06/14 PHP
浅谈PHP正则表达式中修饰符/i, /is, /s, /isU
2014/10/21 PHP
PHP7正式版测试,性能惊艳!
2015/12/08 PHP
详解PHP5.6.30与Apache2.4.x配置
2017/06/02 PHP
ThinkPHP框架整合微信支付之Native 扫码支付模式一图文详解
2019/04/09 PHP
如何实现JS函数的重载
2006/09/22 Javascript
setTimeout 不断吐食CPU的问题分析
2009/04/01 Javascript
JS短路原理的应用示例 精简代码的途径
2013/12/13 Javascript
2014年50个程序员最适用的免费JQuery插件
2014/12/15 Javascript
Node.js开发之访问Redis数据库教程
2015/01/14 Javascript
JavaScript中原型链存在的问题解析
2016/09/25 Javascript
js实现导航栏中英文切换效果
2017/01/16 Javascript
js实现音频控制进度条功能
2017/04/01 Javascript
bootstrap+jQuery 实现下拉菜单中复选框全选和全不选效果
2017/06/12 jQuery
详解小程序用户登录状态检查与更新实例
2019/05/15 Javascript
vue3.0中的双向数据绑定方法及优缺点
2019/08/01 Javascript
原生javascript的ajax请求及后台PHP响应操作示例
2020/02/24 Javascript
微信小程序实现canvas分享朋友圈海报
2020/06/21 Javascript
vue tab滚动到一定高度,固定在顶部,点击tab切换不同的内容操作
2020/07/22 Javascript
Python实现感知器模型、两层神经网络
2017/12/19 Python
Python实现快速傅里叶变换的方法(FFT)
2018/07/21 Python
对python requests的content和text方法的区别详解
2018/10/11 Python
python实现整数的二进制循环移位
2019/03/08 Python
python dumps和loads区别详解
2020/02/04 Python
Python爬取豆瓣数据实现过程解析
2020/10/27 Python
使用HTML5 Canvas绘制圆角矩形及相关的一些应用举例
2016/03/22 HTML / CSS
中国高端家电购物商城:顺电
2018/03/04 全球购物
德国运动营养和健身网上商店:Myprotein.de
2018/07/18 全球购物
SneakerStudio英国:最佳运动鞋商店
2019/05/22 全球购物
C#如何调用Windows程序打开一个文档
2014/12/26 面试题
大学活动邀请函
2014/01/28 职场文书
《草虫的村落》教学反思
2014/02/16 职场文书
《第一朵杏花》教学反思
2014/04/16 职场文书
2015年药房工作总结
2015/04/25 职场文书
Python如何利用正则表达式爬取网页信息及图片
2021/04/17 Python
关于MySQL中explain工具的使用
2023/05/08 MySQL