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 相关文章推荐
第十三节--对象串行化
Nov 16 PHP
实用函数4
Nov 08 PHP
php中的一些数组排序方法分享
Jul 20 PHP
PHP中空字符串介绍0、null、empty和false之间的关系
Sep 25 PHP
用PHP实现浏览器点击下载TXT文档的方法详解
Jun 02 PHP
Windows下安装PHP单元测试环境PHPUnit图文教程
Oct 24 PHP
Linux系统中设置多版本PHP共存配合Nginx服务器使用
Dec 21 PHP
一波PHP中cURL库的常见用法代码示例
May 06 PHP
详解Laravel视图间共享数据与视图Composer
Aug 04 PHP
PHP实现的数独求解问题示例
Apr 18 PHP
Docker 安装 PHP并与Nginx的部署实例讲解
Feb 27 PHP
php引用传递
Apr 01 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
神族 PROTOSS 概述
2020/03/14 星际争霸
使用PHP导出Redis数据到另一个Redis中的代码
2014/03/12 PHP
通过源码解析Laravel的依赖注入
2018/01/22 PHP
ThinkPHP5 框架引入 Go AOP,PHP AOP编程项目详解
2020/05/12 PHP
jquery 指南/入门基础
2007/11/30 Javascript
[Web]防止用户复制页面内容和另存页面的方法
2009/02/06 Javascript
禁止你的左键复制实用技巧
2013/01/04 Javascript
nodejs实现bigpipe异步加载页面方案
2016/01/26 NodeJs
深入浅析javascript中的作用域(推荐)
2016/07/19 Javascript
JS组件系列之使用HTML标签的data属性初始化JS组件
2016/09/14 Javascript
获取url中用&amp;隔开的参数实例(分享)
2017/05/28 Javascript
webstorm添加vue.js支持的方法教程
2017/07/05 Javascript
深入理解vue.js中$watch的oldvalue与newValue
2017/08/07 Javascript
angularjs使用gulp-uglify压缩后执行报错的解决方法
2018/03/07 Javascript
vue.js内置组件之keep-alive组件使用
2018/07/10 Javascript
Puppeteer环境搭建的详细步骤
2018/09/21 Javascript
详解Vue webapp项目通过HBulider打包原生APP(vue+webpack+HBulider)
2019/02/02 Javascript
详解基于vue-cli3快速发布一个fullpage组件
2019/03/08 Javascript
微信小程序如何自定义table组件
2019/06/29 Javascript
JS实现表单中点击小眼睛显示隐藏密码框中的密码
2020/04/13 Javascript
python多线程抓取天涯帖子内容示例
2014/04/03 Python
python从sqlite读取并显示数据的方法
2015/05/08 Python
python 默认参数问题的陷阱
2016/02/29 Python
python检查URL是否正常访问的小技巧
2017/02/25 Python
django自带的server 让外网主机访问方法
2018/05/14 Python
基于python实现聊天室程序
2018/07/27 Python
Django 中自定义 Admin 样式与功能的实现方法
2019/07/04 Python
Python目录和文件处理总结详解
2019/09/02 Python
Python开发企业微信机器人每天定时发消息实例
2020/03/17 Python
使用sklearn对多分类的每个类别进行指标评价操作
2020/06/11 Python
Python 如何操作 SQLite 数据库
2020/08/17 Python
python向xls写入数据(包括合并,边框,对齐,列宽)
2021/02/02 Python
CSS3动画特效在活动页中的应用
2020/01/21 HTML / CSS
大学军训感言1500字
2014/03/09 职场文书
就业推荐表自我鉴定
2014/03/21 职场文书
python函数的两种嵌套方法使用
2022/04/02 Python