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 相关文章推荐
PHP新手上路(三)
Oct 09 PHP
php面向对象全攻略 (九)访问类型
Sep 30 PHP
PHP与SQL注入攻击防范小技巧
Sep 16 PHP
fgetcvs在linux的问题
Jan 15 PHP
MySQL时间字段究竟使用INT还是DateTime的说明
Feb 27 PHP
php foreach循环中使用引用的问题
Nov 06 PHP
PHP学习笔记之字符串编码的转换和判断
May 22 PHP
php中file_get_content 和curl以及fopen 效率分析
Sep 19 PHP
浅析Yii2缓存的使用
May 10 PHP
php array_keys 返回数组的键名
Oct 25 PHP
php函数mkdir实现递归创建层级目录
Oct 27 PHP
php base64 编码与解码实例代码
Mar 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
基于php常用函数总结(数组,字符串,时间,文件操作)
2013/06/27 PHP
php中的比较运算符详解
2013/10/28 PHP
php进行md5加密简单实例方法
2019/09/19 PHP
PHP中通过getopt解析GNU C风格命令行选项
2019/11/18 PHP
JavaScript 利用Cookie记录用户登录信息
2009/12/08 Javascript
被jQuery折腾得半死,揭秘为何jQuery为何在IE/Firefox下均无法使用
2010/01/22 Javascript
IE8下关于querySelectorAll()的问题
2010/05/13 Javascript
GreyBox技术总结(转)
2010/11/23 Javascript
JQuery 常用方法和事件详细介绍
2013/04/18 Javascript
深入Javascript函数、递归与闭包(执行环境、变量对象与作用域链)使用详解
2013/05/08 Javascript
js实现飞入星星特效代码
2014/10/17 Javascript
JavaScript使用位运算符判断奇数和偶数的方法
2015/06/01 Javascript
JavaScript与HTML的结合方法详解
2015/11/23 Javascript
jQuery实现Tab选项卡切换效果简单演示
2015/11/23 Javascript
js实现滚动条滚动到页面底部继续加载
2015/12/19 Javascript
vue项目中做编辑功能传递数据时遇到问题的解决方法
2016/12/19 Javascript
vue项目实现记住密码到cookie功能示例(附源码)
2018/01/31 Javascript
JavaScript捕捉事件和阻止冒泡事件实例分析
2018/08/03 Javascript
vue 刷新之后 嵌套路由不变 重新渲染页面的方法
2018/09/13 Javascript
在JavaScript中如何访问暂未存在的嵌套对象
2019/06/18 Javascript
[38:40]2018DOTA2亚洲邀请赛 4.6淘汰赛 mineski vs LGD 第一场
2018/04/10 DOTA
Python 格式化打印json数据方法(展开状态)
2020/02/27 Python
Python日志logging模块功能与用法详解
2020/04/09 Python
基于python实现坦克大战游戏
2020/10/27 Python
加利福尼亚州威尼斯的女性奢侈品设计师服装和概念店:Mona Moore
2018/09/13 全球购物
网络专业学生个人的自我评价
2013/12/16 职场文书
装修致歉信
2014/01/15 职场文书
春节联欢晚会主持词
2014/03/24 职场文书
法学自荐信
2014/06/20 职场文书
小学标准化建设汇报材料
2014/08/16 职场文书
个人遵守党的政治纪律情况对照检查材料思想汇报
2014/09/25 职场文书
法律意见书范本
2015/06/04 职场文书
从贫穷到富有,是知识技能和学习力的差别
2019/08/20 职场文书
SpringBoot工程下使用OpenFeign的坑及解决
2021/07/02 Java/Android
MySQL如何解决幻读问题
2021/08/07 MySQL
CentOS7和8下安装Maven3.8.4
2022/04/07 Servers