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 网上商城促销设计实例代码
Feb 17 PHP
深入PHP内存相关的功能特性详解
Jun 08 PHP
php轻松实现中英文混排字符串截取
May 28 PHP
ThinkPHP中自定义错误页面和提示页面实例
Nov 22 PHP
php制作动态随机验证码
Feb 12 PHP
php实现短信发送代码
Jul 05 PHP
PHP 使用 Imagick 裁切/生成缩略图/添加水印自动检测和处理 GIF
Feb 19 PHP
php使用ffmpeg获取视频信息并截图的实现方法
May 03 PHP
深入讲解PHP的对象注入(Object Injection)
Mar 01 PHP
PHP实现重载的常用方法实例详解
Oct 18 PHP
实例分析PHP将字符串转换成数字的方法
Jan 27 PHP
基于Laravel-admin 后台的自定义页面用法详解
Sep 30 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
手把手教你使用DedeCms V3的在线采集图文教程
2007/04/03 PHP
php实现的zip文件内容比较类
2014/09/24 PHP
Yii2框架中一些折磨人的坑
2019/12/15 PHP
IE与FF下javascript获取网页及窗口大小的区别详解
2014/01/14 Javascript
JavaScript将当前时间转换成UTC标准时间的方法
2015/04/06 Javascript
angular.bind使用心得
2015/10/26 Javascript
用JavaScript动态建立或增加CSS样式表的实现方法
2016/05/20 Javascript
js数组的五种迭代方法及两种归并方法(推荐)
2016/06/14 Javascript
浅谈jquery的html方法里包含特殊字符的处理
2016/11/30 Javascript
详解为Angular.js内置$http服务添加拦截器的方法
2016/12/20 Javascript
Bootstrap Scrollspy源码学习
2017/03/02 Javascript
微信小程序将字符串生成二维码图片的操作方法
2018/07/17 Javascript
微信小程序实现带参数的分享功能(两种方法)
2019/05/17 Javascript
微信小程序中weui用法解析
2019/10/21 Javascript
three.js着色器材质的内置变量示例详解
2020/08/16 Javascript
如何使用jQuery操作Cookies方法解析
2020/09/08 jQuery
Python实现大文件排序的方法
2015/07/10 Python
python计算圆周率pi的方法
2015/07/11 Python
微信跳一跳小游戏python脚本
2018/01/05 Python
python列表的增删改查实例代码
2018/01/30 Python
python中format()函数的简单使用教程
2018/03/14 Python
python爬虫之快速对js内容进行破解
2019/07/09 Python
python自动化测试之异常及日志操作实例分析
2019/11/09 Python
使用celery和Django处理异步任务的流程分析
2020/02/19 Python
python实现俄罗斯方块小游戏
2020/04/24 Python
Python绘图之二维图与三维图详解
2020/08/04 Python
python如何实时获取tcpdump输出
2020/09/16 Python
cosme官方海外旗舰店:日本最大化妆品和美容产品的综合口碑网站
2017/01/18 全球购物
全球虚拟主机商:HostGator
2017/02/06 全球购物
英国优质家居用品网上品牌:URBANARA
2018/06/01 全球购物
环境工程与管理大学毕业生求职信
2013/10/02 职场文书
运动会广播稿100字
2014/01/11 职场文书
合作意向书模板
2014/03/31 职场文书
法学专业毕业生自荐信
2014/06/11 职场文书
环保志愿者活动方案
2014/08/14 职场文书
Python列表删除重复元素与图像相似度判断及删除实例代码
2021/05/07 Python