1.证书位置
2.退款文件
3.退款代码
<?php
/*
* 咔咔
* 2018.6.21 微信退款
*/
class Refund
{
const REFUND = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
const KEY = 'h5l4P8S3u5n1H5Y4D7E5l9e6J4Y7S8h3';
const CODEURL = 'https://open.weixin.qq.com/connect/oauth2/authorize?';
const OPENIDURL = 'https://api.weixin.qq.com/sns/oauth2/access_token?';
const APPID = 'wxf8a78496174320e9';
const SECRET = '6806ae46548d5a27e0939f12139e7a42';
const MCHID = '1502276551';
const UNURL = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
private $params;
public function __construct($data) {
//组装数据
$this->params = [
'appid' => self::APPID, //APPID
'mch_id' => self::MCHID, //商户号
'nonce_str'=> md5(time()), //随机串
'sign' => 'md5', //签名方式
'transaction_id'=> $data['transaction_id'],//微信支付订单号 与商户订单号二选一
//'out_trade_no'=> '', //商户订单号 和微信支付订单号二选一
'out_refund_no' => $data['out_refund_no'],//退单号
'total_fee' => $data['total_fee'], //订单金额
'refund_fee' => $data['refund_fee'] //退款金额
];
}
//发送退款请求
public function orderRefund(){
//生成签名
$signParams = $this->setSign($this->params);
//将数据转换为xml
$xmlData = $this->ArrToXml($signParams);
//发送请求
return $this->postStr(self::REFUND, $xmlData);
}
//post 字符串到接口
public function postStr($url,$postfields){
$ch = curl_init();
$params[CURLOPT_URL] = $url; //请求url地址
$params[CURLOPT_HEADER] = false; //是否返回响应头信息
$params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
$params[CURLOPT_FOLLOWLOCATION] = true; //是否重定向
$params[CURLOPT_POST] = true;
$params[CURLOPT_SSL_VERIFYPEER] = false;//禁用证书校验
$params[CURLOPT_SSL_VERIFYHOST] = false;
//以下是证书相关代码
$params[CURLOPT_SSLCERTTYPE] = 'PEM';
$params[CURLOPT_SSLCERT] = './cert/apiclient_cert.pem';
$params[CURLOPT_SSLKEYTYPE] = 'PEM';
$params[CURLOPT_SSLKEY] = './cert/apiclient_key.pem';
$params[CURLOPT_POSTFIELDS] = $postfields;
curl_setopt_array($ch, $params); //传入curl参数
$content = curl_exec($ch); //执行
curl_close($ch); //关闭连接
return $content;
}
//生成签名
public function getSign($arr){
//去除空值
$arr = array_filter($arr);
if(isset($arr['sign'])){
unset($arr['sign']);
}
//按照键名字典排序
ksort($arr);
//生成url格式的字符串
$str = $this->arrToUrl($arr) . '&key=' . self::KEY;
return strtoupper(md5($str));
}
//获取带签名的数组
public function setSign($arr){
$arr['sign'] = $this->getSign($arr);;
return $arr;
}
public function arrToUrl($arr){
return urldecode(http_build_query($arr));
}
//验证签名
public function chekSign($arr){
$sign = $this->getSign($arr);
if($sign == $arr['sign']){
return true;
}else{
return false;
}
}
//数组转xml
public function ArrToXml($arr)
{
if(!is_array($arr) || count($arr) == 0) return '';
$xml = "<xml>";
foreach ($arr as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
public function XmlToArr($xml)
{
if($xml == '') return '';
libxml_disable_entity_loader(true);
$arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $arr;
}
}
// 获取订单号
$orderdata = D('foodorder')->where([
'id'=>$_SESSION['orderid']
])->find();
// 传值
$data = [
'transaction_id' => $orderdata['wx_number'], //微信交易号
'out_refund_no' => $orderdata['wx_number'], //退款单号
'total_fee' => $orderdata['cash_fee'], //原订单金额
'refund_fee' => $orderdata['cash_fee'] //退款金额
];
// 实例化退款类
$obj = new Refund($data);
// 调用退款方法
$res = $obj->orderRefund();
// 退款微信返回数据
$refunddata = $obj->XmlToArr($res);
if($refunddata['return_code'] == 'SUCCESS'){
$data['wx_refundorder'] = $orderdata['wx_number'];
$data['user_id'] = $orderdata['userid'];
$data['refund_fee'] = $orderdata['cash_fee'];
$data['refund_time'] = time();
$refundorder = D('refundorder')->add($data);
if(!$refundorder){
$log_name= "./Public/Pay/refund_url.log";//log文件路径
file_put_contents($log_name,"【退款成功 , 数据库添加失败通知", FILE_APPEND);
}
}else{
$log_name= "./Public/Pay/refund_url.log";//log文件路径
file_put_contents($log_name,"【退款失败", FILE_APPEND);
}
4.控制器文件
5.控制器代码
// 退款
public function refundmoney() {
$order_id = I('orderid');
session('orderid',$order_id);
vendor('WxPayPubHelper.refund');
// 查询订单表
$orderdata = D('foodorder')->where([
'id'=>$order_id
])->find();
// 查询退款后的数据库
$refunddata = D('refundorder')->where([
'wx_refundorder'=>$orderdata['wx_number']
])->find();
// 判断是否存在
if($orderdata){
// 修改退款的refund状态
$orderedit = D('foodorder')->where([
'id'=>session('orderid')
])->setInc('refund');
// 清除订单id
session('orderid',null);
__success('退款成功',U('/addon/WeiuidDeit/web/foodorderindex'));
}else{
__error('退款失败');
}
}