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往windows中添加用户
Dec 06 PHP
PHP中使用gettext来支持多语言的方法
May 02 PHP
PHP下利用shell后台运行PHP脚本,并获取该脚本的Process ID的代码
Sep 19 PHP
PHP关联链接常用代码
Nov 05 PHP
深入phpMyAdmin的安装与配置的详细步骤
May 07 PHP
Codeigniter出现错误提示Error with CACHE directory的解决方案
Jun 12 PHP
php采集自中央气象台范围覆盖全国的天气预报代码实例
Jan 04 PHP
php+MySql实现登录系统与输出浏览者信息功能
Jul 01 PHP
CI框架数据库查询缓存优化的方法
Nov 21 PHP
PHP控制反转(IOC)和依赖注入(DI)
Mar 13 PHP
php解决约瑟夫环算法实例分析
Sep 30 PHP
gearman管理工具GearmanManager的安装与php使用方法示例
Feb 27 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
深入eAccelerator与memcached的区别详解
2013/06/06 PHP
自动更新作用
2006/10/08 Javascript
JavaScript 页面坐标相关知识整理
2010/01/09 Javascript
JavaScript Event学习第十一章 按键的检测
2010/02/10 Javascript
jQuery实现form表单元素序列化为json对象的方法
2015/12/09 Javascript
Angular2 环境配置详细介绍
2016/09/21 Javascript
原生js编写焦点图效果
2016/12/08 Javascript
快速解决vue-cli不能初始化webpack模板的问题
2018/03/20 Javascript
简单说说angular.json文件的使用
2018/10/29 Javascript
解决JQuery的ajax函数执行失败alert函数弹框一闪而过问题
2019/04/10 jQuery
Vue实战教程之仿肯德基宅急送App
2019/07/19 Javascript
vue日历/日程提醒/html5本地缓存功能
2019/09/02 Javascript
ES6 Object.assign()的用法及其使用
2020/01/18 Javascript
node.js中path路径模块的使用方法实例分析
2020/02/13 Javascript
微信小程序中使用 async/await的方法实例分析
2020/05/06 Javascript
js实现轮播图效果 纯js实现图片自动切换
2020/08/09 Javascript
[46:55]LGD vs Liquid 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/19 DOTA
Python ORM框架SQLAlchemy学习笔记之安装和简单查询实例
2014/06/10 Python
Python远程桌面协议RDPY安装使用介绍
2015/04/15 Python
PyMongo安装使用笔记
2015/04/27 Python
pyqt5自定义信号实例解析
2018/01/31 Python
学生信息管理系统python版
2018/10/17 Python
Python3解释器知识点总结
2019/02/19 Python
pytorch 使用加载训练好的模型做inference
2020/02/20 Python
CSS3为背景图设置遮罩并解决遮罩样式继承问题
2020/06/22 HTML / CSS
美国生日蛋糕店:Bake Me A Wish!
2017/02/08 全球购物
乌克兰时尚鞋子和衣服购物网站:Born2be
2018/05/24 全球购物
美国领先的宠物用品和宠物食品零售商:Petco
2020/10/28 全球购物
玩具公司的创业计划书
2013/12/31 职场文书
商场消防演习方案
2014/02/12 职场文书
留守儿童工作方案
2014/06/02 职场文书
优秀大学生自荐信
2014/06/09 职场文书
如果用一句诗总结你的上半年,你会用哪句呢?
2019/07/16 职场文书
中秋节作文(五年级)之关于月亮
2019/09/11 职场文书
go xorm框架的使用
2021/05/22 Golang
彩虹社八名人气艺人全新周边限时推出,性转女装男装一次拥有!
2022/04/01 日漫