PS:本篇文章主要是对PHP实现小程序退款以及退款回调数据解密的流程做大概解释,代码请各位按照自身需求进行修改
小程序js代码:
refundOrder(){
var refund = this
wx.request({
url: 'http://127.0.0.1:2910/wxPayV2/refundOrder/refundOrderAction.php', //此处写你的PHP文件地址
method:'POST',
header:{
'content-type':'application/x-www-form-urlencoded'
},
data:{
'out_trade_no':'商户订单号',
'refund_fee':'1' //退款金额,单位为分
},
success(res){
console.log(res)
}
})
},
PHP微信v2退款类文件
refundOrder.php
<?php
require_once dirname(__FILE__,3).'/config/appConfig.php';
require_once dirname(__FILE__,2).'/createOrder/createOrder.php';
class refundOrder
{
/**
* 获取相关基本配置
*/
public function __construct(){
$this -> APIv2 = APIv2;
$this -> appid = appid;
$this -> mch_id = mch_id;
}
/**
* 生成32位随机字符串
* @return false|string
*/
public function nonce_str(){
$getData = new createOrder;
return $getData -> nonce_str();
}
/**
* 生成商户退款单号
* @return string
*/
public function out_refund_no(): string
{
$getData = new createOrder;
$data = $getData -> out_trade_no();
return 'T'.$data;
}
/**
* 返回参与签名的数据主体
* @param $nonce_str :32位随机字符串
* @param $transaction_id :微信支付订单号
* @param $out_refund_no :商户退款单号
* @param $total_fee :订单总金额
* @param $refund_fee :退款金额
* @return array
*/
public function signBody($nonce_str,$transaction_id,$out_refund_no,$total_fee,$refund_fee): array
{
$data = array(
'appid' => $this -> appid,
'mch_id' => $this -> mch_id,
'nonce_str' => $nonce_str,
'sign_type' => 'MD5',
'transaction_id' => $transaction_id,
'out_refund_no' => $out_refund_no,
'total_fee' => $total_fee,
'refund_fee' => $refund_fee,
);
ksort($data);
return $data;
}
/**
* 将参与签名的数据转换字符串并连接APIv2
* @param $data :参与签名的数据主体(array)
* @return string
*/
public function disposeSignBody($data): string
{
$signBody = '';
foreach ($data as $key => $val){
$signBody .= "$key=$val&";
}
$signBody .= "key=$this->APIv2";
return $signBody;
}
/**
* 返回签名值
* @param $signBody :经过处理后的待签名数据
* @return string
*/
public function sign($signBody): string
{
return strtoupper(MD5($signBody));
}
/**
* 生成访问微信退款接口的参数主体
* @param $sign :签名值
* @param $signBody :参与签名的数据主体
* @return string
*/
public function requestBody($sign,$signBody): string
{
$signArray = array(
'sign' => $sign
);
$requestArray = array_merge($signArray,$signBody);
$requestBody = '<xml>';
foreach($requestArray as $key => $val){
$requestBody .= "<$key>".$val."</$key>";
}
$requestBody .= '</xml>';
return $requestBody;
}
/**
* 使用curl对微信退款接口进行访问
* @param $url :微信退款接口url地址
* @param $data :访问接口所传输的数据主体
* @return bool|string
*/
public function curlRequest($url,$data){
$action = curl_init();
curl_setopt($action, CURLOPT_URL,$url);
curl_setopt($action, CURLOPT_HEADER,0);
curl_setopt($action, CURLOPT_POST,1);
curl_setopt($action, CURLOPT_POSTFIELDS,$data);
curl_setopt($action, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($action, CURLOPT_SSLCERTTYPE,'pem');
curl_setopt($action, CURLOPT_SSLCERT,dirname(__FILE__,3).'/cert/apiclient_cert.pem');
curl_setopt($action, CURLOPT_SSLKEYTYPE,'pem');
curl_setopt($action, CURLOPT_SSLKEY,dirname(__FILE__,3).'/cert/apiclient_key.pem');
curl_setopt($action, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($action, CURLOPT_RETURNTRANSFER,1);
curl_setopt($action, CURLOPT_CONNECTTIMEOUT,60);
$result = curl_exec($action);
curl_close($action);
return $result;
}
/**
* 对微信返回的数据进行验签 (微信回传的数据中包含空数据,在对数据进行处理时空数据被转化成数组,目前难以解决,暂时废弃验签操作)
* @param $data :已经被转化为数组的微信返回数据
* @return bool
*/
public function verifySign($data): bool
{
$sign = $data['sign'];
unset($data['sign']);
ksort($data);
$signBody = '';
foreach ($data as $key => $val){
$signBody .= "$key=$val&";
}
$signBody .= "key=$this->APIv2";
$verifySign = strtoupper(MD5($signBody));
if($verifySign == $sign){
return true;
}else{
return false;
}
}
}
PHP退款代码
refundOrderAction.php
<?php
require_once dirname(__FILE__).'/refundOrder.php';
require_once dirname(__FILE__,3).'/database/connect.php';
$out_trade_no = $_POST['out_trade_no']; //接收小程序端发送的商户订单号
$refund_fee = $_POST['refund_fee']; //接收小程序端发送的退款金额
$buildData = new refundOrder;
$getInDatabase = new Connect;
$selectRefund = 'select * from order_basic_information where out_trade_no = "'.$out_trade_no.'";'; //在数据库中根据商户订单号进行查询
$databaseResult = $getInDatabase -> querySql($selectRefund);
$resultData = mysqli_fetch_assoc($databaseResult);
$status = $resultData['status']; //从数据库中获取订单状态
if($status == 1){ //判断订单状态:1.待支付不能退款
die('该订单未支付不能进行退款操作');
}
if($status == 7){ //判断订单状态:7.已退款不能退款
die('该订单已经退款,不能再次进行退款');
}
$transaction_id = $resultData['transaction_id']; //从数据库中获得微信支付单号
$total_fee = $resultData['total_fee']; //从数据库中获得订单总金额
$out_refund_no = $resultData['out_refund_no']; //从数据库获取商户退款单号
if(!isset($out_refund_no)){ //判断商户退款单号是否为空
$out_refund_no = $buildData -> out_refund_no(); //生成商户退款单号
}
$nonce_str = $buildData -> nonce_str(); //获取32位随机字符串
$signBody = $buildData -> signBody($nonce_str,$transaction_id,$out_refund_no,$total_fee,$refund_fee); //获取参与签名的数据主体
$disposeSignBody = $buildData -> disposeSignBody($signBody);//对参与签名的数据主体转换为字符串格式
$sign = $buildData -> sign($disposeSignBody); //获取签名值
$requestData = $buildData -> requestBody($sign,$signBody); //获取请求接口的主体数据
file_put_contents('./requestAndResultData.xml',$requestData."\n\r",FILE_APPEND); //将请求接口的主体数据存入相关的文件中
$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund'; //微信退款接口url地址
$wxResult = $buildData -> curlRequest($url,$requestData); //使用curl对微信退款接口进行访问并获得返回数据
if(!isset($wxResult)){
die('未接收到微信的返回数据');
}
file_put_contents('./requestAndResultData.xml',$wxResult."\n\r",FILE_APPEND); //将访问微信接口返回的数据存入相关文件中
$disposeWxData = simplexml_load_string($wxResult,null,LIBXML_NOCDATA); //对微信返回的数据进行解析
$json_data = json_encode($disposeWxData); //将数据转换为json格式
$array_data = json_decode($json_data,true); //将json格式数据转换为数组格式
$refund_id = $array_data['refund_id']; //从微信返回的数据中获取微信退款单号
//将相关数据存入数据库中
$updateSql = 'update order_basic_information set status = 7,refund_id = "'.$refund_id.'",refund_fee = "'.$refund_fee.'",out_refund_no = "'.$out_refund_no.'",refund_time = "'.date('Y-m-d H:i:s').'" where out_trade_no = "'.$out_trade_no.'";';
$getInDatabase -> querySql($updateSql);
curl返回的数据如下:
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[appid]]></appid>
<mch_id><![CDATA[商户号]]></mch_id>
<nonce_str><![CDATA[HF1WsvV3kQxqr26R]]></nonce_str>
<sign><![CDATA[签名]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<transaction_id><![CDATA[微信支付单号]]></transaction_id>
<out_trade_no><![CDATA[商户订单号]]></out_trade_no>
<out_refund_no><![CDATA[商户退款单号]]></out_refund_no>
<refund_id><![CDATA[微信退款单号]]></refund_id>
<refund_channel><![CDATA[]]></refund_channel>
<refund_fee>1</refund_fee>
<coupon_refund_fee>0</coupon_refund_fee>
<total_fee>1</total_fee>
<cash_fee>1</cash_fee>
<coupon_refund_count>0</coupon_refund_count>
<cash_refund_fee>1</cash_refund_fee>
</xml>
PS:由于隐私原因,商法的部分数据我已经隐去,不影响各位观看数据结构
以下是对退款回调数据的处理
PHP类代码
refundCallBack.php
<?php
require_once dirname(__FILE__,4).'/config/appConfig.php';
class refundCallBack
{
/**
* 将xml格式数据转换为数组
* @param $data :需要转换成为数组的xml格式数据
* @return mixed
*/
public function xmlToArray($data){
$disposeData = simplexml_load_string($data,null,LIBXML_NOCDATA);
$json_data = json_encode($disposeData);
return json_decode($json_data,true);
}
/**
* 对微信返回的加密回调数据进行解密并将其由xml格式转换为数组格式
* @param $req_info :微信会掉返回的加密数据
* @return false|string
*/
public function decrypt($req_info){
$APIv2 = APIv2;
$disposeAPI = strtolower(MD5($APIv2));
$disposeReq = base64_decode($req_info);
$decrypt = openssl_decrypt($disposeReq,'AES-256-ECB',$disposeAPI,OPENSSL_RAW_DATA);
file_put_contents('./returnData.xml',$decrypt."\n\r",FILE_APPEND);
return $decrypt;
}
}
PHP调用方法的代码
refundCallBackAction.php
<?php
require_once dirname(__FILE__).'/refundCallBack.php';
require_once dirname(__FILE__,4).'/database/connect.php';
$returnData = file_get_contents('php://input'); //接收微信的退款回调数据
$content = $returnData;
file_put_contents('./returnData.xml',$content."\n\r",FILE_APPEND);
$getData = new refundCallBack;
$disposeContent = $getData -> xmlToArray($content); //将微信回调的xml数据转换为数组数据
$req_info = $disposeContent['req_info']; //从数组中获取微信的加密数据
$getDecryptData = $getData -> decrypt($req_info); //对加密数据进行解密
$decryptData = $getData -> xmlToArray($getDecryptData); //将解密的数据由xml数据转化为数据格式
$refund_id = $decryptData['refund_id']; //从数组中获取微信退款单号
$out_refund_no = $decryptData['out_refund_no']; //从数组中获取商户退款单号
$refund_fee = $decryptData['refund_fee']; //从数组中获取退款金额
$out_trade_no = $decryptData['out_trade_no']; //从数组中获取商户订单号
$refund_time = $decryptData['success_time']; //从数组中获取退款完成时间
$refund_state = $decryptData['refund_state']; //从数组中获取退款状态
$getInDatabase = new Connect;
$selectSql = 'select * from order_basic_information where out_trade_no = "'.$out_trade_no.'";'; //从数据库中根据商户订单号获取相关数据
$resultInDatabase = $getInDatabase -> querySql($selectSql);
$dataInDatabase = mysqli_fetch_assoc($resultInDatabase);
$status = $dataInDatabase['status']; //从数据库返回的数组中获取当前订单状态
if($status == 7){ //判断当前订单是否已经完成退款且已经修改相关数据
die('订单已经退款,状态已经修改,无需继续修改');
}
if($refund_state != 'SUCCESS'){ //判断微信返回数据的订单状态
die('解密数据订单状态错误,请排查后重试');
}
//将微信返回的解密数据存入数据库中
$updateSql = 'update order_basic_information set status = 7,out_refund_no = "'.$out_refund_no.'",refund_id = "'.$refund_id.'",refund_time = "'.$refund_time.'",refund_fee = "'.$refund_fee.'" where out_trade_no = "'.$out_trade_no.'";';
$databaseResult = $getInDatabase -> querySql($updateSql);
if($databaseResult == 1){ //判断插入数据结果,向微信返回信息
$getReturnWxData = file_get_contents('./returnWxData.xml');
echo $getReturnWxData;
}
微信回调数据的展示
<xml>
<return_code>SUCCESS</return_code>
<appid><![CDATA[appid]]></appid>
<mch_id><![CDATA[商户号]]></mch_id>
<nonce_str><![CDATA[28cf5d99e569ef56178d8e49ed3213ec]]></nonce_str>
<req_info><!微信加密后的数据</req_info>
</xml>
<root>
<cash_refund_fee><![CDATA[1]]></cash_refund_fee>
<out_refund_no><![CDATA[商户退款单号]]></out_refund_no>
<out_trade_no><![CDATA[商户订单号]]></out_trade_no>
<refund_account><![CDATA[REFUND_SOURCE_RECHARGE_FUNDS]]></refund_account>
<refund_fee><![CDATA[1]]></refund_fee>
<refund_id><![CDATA[微信退款单号]]></refund_id>
<refund_recv_accout><![CDATA[支付用户零钱]]></refund_recv_accout>
<refund_request_source><![CDATA[API]]></refund_request_source>
<refund_status><![CDATA[SUCCESS]]></refund_status>
<settlement_refund_fee><![CDATA[1]]></settlement_refund_fee>
<settlement_total_fee><![CDATA[1]]></settlement_total_fee>
<success_time><![CDATA[2022-08-12 14:24:12]]></success_time>
<total_fee><![CDATA[1]]></total_fee>
<transaction_id><![CDATA[微信支付单号]]></transaction_id>
</root>
PS:由于隐私原因,上方部分数据已经隐去,但不影响关看数据结构
下面附上返回给微信通知的数据
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>
注意使用这个代码返回给微信后,微信将停止发送回调数据,所以在完成自己的逻辑之后再将此xml数据返回给微信
本文由CSDN用户: 缱绻淡蓝海 原创,代码具有时效性,作者会不定期对往期文章进行更新