热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

php微信退款返回签名错误,PHP微信支付开发(2)退款

一、概述本系列博客将讨论基于微信支付的项目开发中,涉及到的下单与支付、退款、以及订单查询的后端代码实现。在本系列博客中,将以代码片段作为示例࿰

一、概述

本系列博客将讨论基于微信支付的项目开发中,涉及到的下单与支付、退款、以及订单查询的后端代码实现。在本系列博客中,将以代码片段作为示例,来讨论ThinkPHP 后端接口实现的过程。

在本系列的接口示例中,返回的状态码标识如下:

0: 业务成功

-1: 业务失败

开发环境如果:

ThinkPHP 6 或者 ThinkPHP 5 / 5.1

PHP 7 运行环境

本文是第二篇,我们讨论退款。

二、退款申请

订单支付成功之后即可退款,退款的金额可以小于或者等于订单的下单金额。请求参数相对下单接口略有变化,如下代码:

$order = Order::where('id',request()->params('id'))->find();

$order['out_refund_no'] = date('YmdHis').mt_rand(1000, 9999);

$params = [

'appid' => config('wx.app_id'),

'mch_id' => config('wx.mch_id'),

'nonce_str' => md5(time()),

'sign_type' => 'MD5',

'transaction_id' => $order['transaction_id'],

'out_trade_no' => $order['out_trade_no'],

'out_refund_no' => $order['out_refund_no'],

'total_fee' => $order['fee'] * 100,

'refund_fee' => $order['fee'] * 100,

'refund_desc' => $params['refund_desc'],

'notify_url' => 'https://test.com/orders/callback_refund',//通知地址

];

构造xml

//创建xml

$xml = '';

$xml .= '';

//遍历参数

$stringA = '';

//根据键名对参数进行字典排序

ksort($params);

foreach ($params as $key => $value) {

$stringA .= $key . '=' . $value . '&';

$xml .= '' . $value . '' . $key . '>';

}

$signTmp = $stringA . 'key=' . config('wx.mch_key');//与商户API秘钥进行拼接

$sign = strtoupper(md5($signTmp));//签名后的32位字符

//将签名添加到请求参数中

$xml .= '' . $sign . '';

$xml .= '';

退款申请需要安全证书(在微信商户号里申请),我们重新定义在common.php一个用于请求的方法

function order_refund_request($url, $data = null)

{

$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);

if (!empty($data)) {

curl_setopt($curl, CURLOPT_POST, 1);

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

}

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

//证书设置

curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');

curl_setopt($curl, CURLOPT_SSLCERT, dirname(__FILE__) . '/cert/apiclient_cert.pem');//客户端cert路径

curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');

curl_setopt($curl, CURLOPT_SSLKEY, dirname(__FILE__) . '/cert/apiclient_key.pem');//客户端key路径

$output = curl_exec($curl);

curl_close($curl);

return $output;

}

这里要注意证书的路径,一定要匹配。接着发送退款请求

$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';

$res_xml = order_refund_request($url, $xml);

trace('微信中台申请退款,返回信息');

trace($res_xml);

$simpleXMLElement = simplexml_load_string($res_xml, 'SimpleXMLElement', LIBXML_NOCDATA);

//将SimpleXMLElement转为数组

$jsonStr = json_encode($simpleXMLElement);

$jsonArray = json_decode($jsonStr, true);

if (isset($jsonArray['return_code']) && $jsonArray['return_code'] == 'SUCCESS') {

// 退款申请成功,更新订单状态

$order['status'] = 2;

return json(['code'=>0,'msg'=>'成功']);

} else {

//响应失败

return json(['code'=>-1,'msg'=>'响应失败']);

}

三、退款回调

退款回调返回的数据是加密的,回调地址是退款申请中的通知地址。我们需要先解密返回数据,再根据返回数据去更新订单状态。首先在当前类里定义解密方法

private function refundDecrypt($str, $key)

{

$key = md5($key);

$str = base64_decode($str);

return openssl_decrypt($str, 'aes-256-ecb', $key, OPENSSL_RAW_DATA);

}

接下来,获取参数并解密

$xml = file_get_contents('php://input');

if (!$xml) {

exit(0);

}

$simpleXMLElement = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);

//将SimpleXMLElement转为数组

$jsonStr = json_encode($simpleXMLElement);

$jsonArray = json_decode($jsonStr, true);

// 中台返回数据解密

if (!isset($jsonArray['req_info'])) {

exit(0);

}

$decryptStr = $this->refundDecrypt($jsonArray['req_info'],

//将xml解析为array

$simpleXMLElement = simplexml_load_string($decryptStr, 'SimpleXMLElement', LIBXML_NOCDATA);

//将SimpleXMLElement对象转为数组

$jsonStr = json_encode($simpleXMLElement);

// 解析字段

$jsonResArr = json_decode($jsonStr, true);

// 验证参数

if (!(isset($jsonResArr['out_refund_no']) && isset($jsonResArr['refund_status']) && (strval($jsonResArr['refund_status']) === 'SUCCESS'))) {

exit(0);//参数错误,终止程序

}

// 通过退款订单号查询订单

$order = Order::where('out_refund_no',$jsonResArr['out_refund_no'])->find();

if (!$order) {

exit(0);//查询不到相应订单,终止程序

}

// 更新订单状态

if ($order['status'] !== 3) {

// 更新订单状态

trace('微信退款回调,正在更新订单状态');

$order['status'] = 3;

$order['transaction_id'] = $jsonResArr['transaction_id'];

$order['refund_fee'] = round($jsonResArr['refund_fee'] / 100, 2);

$order['refund_time'] = time();

$saveOrder = $order->save();

}

// 给微信返回数据

$xml = '';

$xml .= '' . '' . '';

$xml .= '' . '' . '';

$xml .= '';

return response($xml, 200, [], 'xml');



推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 有没有一种方法可以在不继承UIAlertController的子类或不涉及UIAlertActions的情况下 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • 20211101CleverTap参与度和分析工具功能平台学习/实践
    1.应用场景主要用于学习CleverTap的使用,该平台主要用于客户保留与参与平台.为客户提供价值.这里接触到的原因,是目前公司用到该平台的服务~2.学习操作 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
author-avatar
找唐娃娃_622
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有