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中的日期处理方法集锦
Jan 02 PHP
php修改时间格式的代码
May 29 PHP
在WAMP环境下搭建ZendDebugger php调试工具的方法
Jul 18 PHP
php中strtotime函数用法详解
Nov 15 PHP
PHP面试常用算法(推荐)
Jul 22 PHP
PHP中的多种加密技术及代码示例解析
Oct 20 PHP
php读取XML的常见方法实例总结
Apr 25 PHP
PHP实现mysqli批量执行多条语句的方法示例
Jul 22 PHP
PHP删除数组中指定值的元素常用方法实例分析【4种方法】
Aug 21 PHP
php 处理png图片白色背景色改为透明色的实例代码
Dec 10 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
Nov 26 PHP
详解no input file specified 三种解决方法
Nov 29 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应用程序来获取Web服务器的状态信息
2006/10/09 PHP
php使用gzip压缩传输js和css文件的方法
2015/07/29 PHP
PHP中list()函数用法实例简析
2016/01/08 PHP
YII2框架中ActiveDataProvider与GridView的配合使用操作示例
2020/03/18 PHP
document.getElementById为空或不是对象的解决方法
2010/01/24 Javascript
JavaScript 空位补零实现代码
2010/02/26 Javascript
javascript 打开页面window.location和window.open的区别
2010/03/17 Javascript
用JQuery调用Session的实现代码
2010/10/29 Javascript
jQuery参数列表集合
2011/04/06 Javascript
js操作label给label赋值及取label的值示例
2013/11/07 Javascript
优化javascript的执行效率一些方法总结
2013/12/25 Javascript
JavaScript获取URL汇总
2015/06/08 Javascript
javascript鼠标跟随运动3种效果(眼球效果,苹果菜单,方向跟随)
2016/10/27 Javascript
nodejs mysql 实现分页的方法
2017/06/06 NodeJs
bootstrapvalidator之API学习教程
2017/06/29 Javascript
python运行时间的几种方法
2016/06/17 Python
Python找出最小的K个数实例代码
2018/01/04 Python
python学生信息管理系统
2018/03/13 Python
python实现批量nii文件转换为png图像
2019/07/18 Python
Tornado实现多进程/多线程的HTTP服务详解
2019/07/25 Python
win10系统下python3安装及pip换源和使用教程
2020/01/06 Python
flask利用flask-wtf验证上传的文件的方法
2020/01/17 Python
使用Python求解带约束的最优化问题详解
2020/02/11 Python
浅谈python量化 双均线策略(金叉死叉)
2020/06/03 Python
python定义类的简单用法
2020/07/24 Python
Python爬虫防封ip的一些技巧
2020/08/06 Python
Python结合百度语音识别实现实时翻译软件的实现
2021/01/18 Python
英国第一蛋白粉品牌:Myprotein
2016/09/14 全球购物
AP澳洲中文网:澳洲正品直邮,包税收件无忧
2019/07/12 全球购物
一套比较完整的软件测试人员面试题
2012/05/13 面试题
初中生物教学反思
2014/01/10 职场文书
社区科普工作方案
2014/06/03 职场文书
海上钢琴师的观后感
2015/06/11 职场文书
薪资证明范本
2015/06/19 职场文书
2015年度考核个人工作总结
2015/10/24 职场文书
2016年共产党员个人承诺书
2016/03/24 职场文书