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 相关文章推荐
在mysql数据库原有字段后增加新内容
Nov 26 PHP
PHP中实现汉字转区位码应用源码实例解析
Jun 14 PHP
php中导出数据到excel时数字变为科学计数的解决方法
Feb 03 PHP
深入PHP magic quotes的详解
Jun 17 PHP
php实现ip白名单黑名单功能
Mar 12 PHP
基于PHP实现通过照片获取ip地址
Apr 26 PHP
php添加数据到xml文件的简单例子
Sep 08 PHP
php批量删除操作代码分享
Feb 26 PHP
PHP使用preg_split和explode分割textarea存放内容的方法分析
Jul 03 PHP
PHP封装的XML简单操作类完整实例
Nov 13 PHP
PHP检测接口Traversable用法详解
Dec 29 PHP
php解压缩zip和rar压缩包文件的方法
Jul 10 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判断用户是否已经登录(跳转到不同页面或者执行不同动作)
2016/09/22 PHP
php7 错误处理机制修改实例分析
2020/05/25 PHP
几个比较实用的JavaScript 测试及效验工具
2010/04/18 Javascript
基于jQuery的history历史记录插件
2010/12/11 Javascript
从jquery的过滤器.filter()方法想到的
2013/09/29 Javascript
jQuery中live()方法用法实例
2015/01/19 Javascript
JavaScript学习笔记之Function对象
2015/01/22 Javascript
Chrome浏览器的alert弹窗禁止再次弹出后恢复的方法
2016/12/30 Javascript
JS实现禁止高频率连续点击的方法【基于ES6语法】
2017/04/25 Javascript
node.js 中间件express-session使用详解
2017/05/20 Javascript
解决bootstrap下拉菜单点击立即隐藏bug的方法
2017/06/13 Javascript
ReactNative Image组件使用详解
2017/08/07 Javascript
vue-router定义元信息meta操作
2020/12/07 Vue.js
python自动安装pip
2014/04/24 Python
Python中使用urllib2模块编写爬虫的简单上手示例
2016/01/20 Python
对pandas的dataframe绘图并保存的实现方法
2017/08/05 Python
python实现人民币大写转换
2018/06/20 Python
Python小进度条显示代码
2019/03/05 Python
python代码编写计算器小程序
2020/03/30 Python
python文档字符串(函数使用说明)使用详解
2019/07/30 Python
Python通过正则库爬取淘宝商品信息代码实例
2020/03/02 Python
python list等分并从等分的子集中随机选取一个数
2020/11/16 Python
python实现登录与注册系统
2020/11/30 Python
H5混合开发app如何升级的方法
2018/01/10 HTML / CSS
置业顾问岗位职责
2014/03/02 职场文书
小学“向国旗敬礼”网上签名寄语活动总结
2014/09/27 职场文书
2015年乡镇安全生产工作总结
2015/05/19 职场文书
毕业实习证明范本
2015/06/16 职场文书
结婚司仪主持词
2015/06/29 职场文书
2015年高三年级组工作总结
2015/07/21 职场文书
2015年城管执法工作总结
2015/07/23 职场文书
开业庆典嘉宾致辞
2015/08/01 职场文书
幼儿园开学家长寄语(2016秋季)
2015/12/03 职场文书
创业计划书之餐饮馄饨店
2019/07/18 职场文书
使用logback实现按自己的需求打印日志到自定义的文件里
2021/08/30 Java/Android
MySQL中TIMESTAMP类型返回日期时间数据中带有T的解决
2022/12/24 MySQL