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
PHP 出现乱码和Sessions验证问题的解决方法!
Dec 06 PHP
php一句话cmdshell新型 (非一句话木马)
Apr 18 PHP
PHP中register_globals参数为OFF和ON的区别(register_globals 使用详解)
Feb 05 PHP
PHP 使用header函数设置HTTP头的示例解析 表头
Jun 17 PHP
深入file_get_contents函数抓取内容失败的原因分析
Jun 25 PHP
php curl 获取https请求的2种方法
Apr 27 PHP
PHP date函数常用时间处理方法
May 11 PHP
php微信开发之百度天气预报
Nov 18 PHP
PHP实现生成模糊图片的方法示例
Dec 21 PHP
PHP生成推广海报的方法分享
Apr 22 PHP
yii框架结合charjs实现统计30天数据的方法
Apr 04 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 多行多列显示
2009/08/15 PHP
php使用pack处理二进制文件的方法
2014/07/03 PHP
php的GD库imagettftext函数解决中文乱码问题
2015/01/24 PHP
基于Codeigniter框架实现的student信息系统站点动态发布功能详解
2017/03/23 PHP
PHP curl 或 file_get_contents 获取需要授权页面的方法
2017/05/05 PHP
基于Jquery的简单&amp;简陋Tabs插件代码
2010/02/09 Javascript
DIV+CSS+JS不间断横向滚动实现代码
2013/03/19 Javascript
原生js封装二级城市下拉列表的实现代码
2016/06/16 Javascript
微信小程序后台解密用户数据实例详解
2017/06/28 Javascript
JS函数节流和函数防抖问题分析
2017/12/18 Javascript
详解Vue-cli webpack移动端自动化构建rem问题
2018/04/07 Javascript
vue组件表单数据回显验证及提交的实例代码
2018/08/30 Javascript
详解微信小程序实现跑马灯效果(附完整代码)
2019/04/29 Javascript
vue使用混入定义全局变量、函数、筛选器的实例代码
2019/07/29 Javascript
使用vuex存储用户信息到localStorage的实例
2019/11/11 Javascript
js实现纯前端压缩图片
2020/11/16 Javascript
在Python中使用判断语句和循环的教程
2015/04/25 Python
python之PyMongo使用总结
2017/05/26 Python
Python使用plotly绘制数据图表的方法
2017/07/18 Python
pygame实现五子棋游戏
2019/10/29 Python
以SQLite和PySqlite为例来学习Python DB API
2020/02/05 Python
css3学习系列之移动属性详解
2017/07/04 HTML / CSS
html5+svg学习指南之SVG基础知识
2014/12/17 HTML / CSS
优秀毕业生事迹材料
2014/02/12 职场文书
高中军训感言600字
2014/03/11 职场文书
幼儿园大班开学寄语
2014/08/02 职场文书
写给医生的感谢信
2015/01/22 职场文书
补充协议书
2015/01/28 职场文书
化妆品促销活动总结
2015/05/07 职场文书
电影雨中的树观后感
2015/06/15 职场文书
2016教师校本培训心得体会
2016/01/08 职场文书
2019各种承诺书范文
2019/06/24 职场文书
关于JavaScript回调函数的深入理解
2021/06/27 Javascript
html5调用摄像头实例代码
2021/06/28 HTML / CSS
python 判断文件或文件夹是否存在
2022/03/18 Python
PostgreSQL 插入INSERT、删除DELETE、更新UPDATE、事务transaction
2022/04/12 PostgreSQL