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超级全局变量
Jan 26 PHP
PHP对MongoDB[NoSQL]数据库的操作
Mar 01 PHP
php float不四舍五入截取浮点型字符串方法总结
Oct 28 PHP
ZF框架实现发送邮件的方法
Dec 03 PHP
Zend Framework创建自己的动作助手详解
Mar 05 PHP
PHP如何实现跨域
May 30 PHP
PHP调试及性能分析工具Xdebug详解
Feb 09 PHP
PHP调用Mailgun发送邮件的方法
May 04 PHP
Yii2.0实现生成二维码功能实例
Oct 24 PHP
在laravel中实现ORM模型使用第二个数据库设置
Oct 24 PHP
laravel框架中间件简单使用方法示例
Jan 25 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
php5 pdo新改动加载注意事项
2008/09/11 PHP
ThinkPHP行为扩展Behavior应用实例详解
2014/07/22 PHP
PHP命名空间(namespace)的动态访问及使用技巧
2014/08/18 PHP
PHP工程师VIM配置分享
2015/12/15 PHP
php cookie 详解使用实例
2016/11/03 PHP
php操作redis数据库常见方法实例总结
2020/02/20 PHP
JQuery 初体验(建议学习jquery)
2009/04/25 Javascript
JS中FRAME的操作问题实例分析
2014/10/21 Javascript
node.js使用require()函数加载模块
2014/11/26 Javascript
JQuery显示、隐藏div的几种方法简明总结
2015/04/16 Javascript
谈一谈jQuery核心架构设计
2016/03/28 Javascript
bootstrap 模态框(modal)实现水平垂直居中显示
2017/01/23 Javascript
JS ES6多行字符串与连接字符串的表示方法
2017/04/26 Javascript
javascript简单写的判断电话号码实例
2017/05/24 Javascript
Vue-router路由判断页面未登录跳转到登录页面的实例
2017/10/26 Javascript
JS实现的JSON数组去重算法示例
2018/04/11 Javascript
axios 封装上传文件的请求方法
2018/09/26 Javascript
小程序获取当前位置加搜索附近热门小区及商区的方法
2019/04/08 Javascript
浅谈Vue CLI 3结合Lerna进行UI框架设计
2019/04/14 Javascript
vue中通过使用$attrs实现组件之间的数据传递功能
2019/09/01 Javascript
node crawler如何添加promise支持
2020/02/01 Javascript
[07:57]DOTA2热力大趴狂欢夜 广州站活动回顾
2013/11/27 DOTA
使用70行Python代码实现一个递归下降解析器的教程
2015/04/17 Python
Python入门之modf()方法的使用
2015/05/15 Python
python常用数据重复项处理方法
2019/11/22 Python
python数据分析工具之 matplotlib详解
2020/04/09 Python
解决Jupyter Notebook开始菜单栏Anaconda下消失的问题
2020/04/13 Python
Python3爬虫关于识别检验滑动验证码的实例
2020/07/30 Python
使用Python通过oBIX协议访问Niagara数据的示例
2020/12/04 Python
基于CSS3制作立体效果导航菜单
2016/01/12 HTML / CSS
世界上最好的帽子:Tilley
2016/11/27 全球购物
单位提档介绍信
2014/01/17 职场文书
行政助理的岗位职责
2014/02/18 职场文书
广告学专业自荐信范文
2014/02/24 职场文书
信用卡工资证明格式
2014/09/13 职场文书
使用Nginx+Tomcat实现负载均衡的全过程
2022/05/30 Servers