<?php /* * 咔咔 * 微信号 fangkangfk * author:2018.6.20 * 一个文件实现微信退款 */ 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 = '商户号id'; const SECRET = '秘钥'; const MCHID = '商户微信号'; 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(); $datas['wxrefund_number'] = $orderdata['wx_number']; $orderdata = D('foodorder')->where([ 'wx_number'=>$orderdata['wx_number'] ])->save($datas); if(!$orderdata){ $log_name= "./Public/Pay/refund_url.log";//log文件路径 file_put_contents($log_name,"【退款成功 , 订单数据库添加失败通知", FILE_APPEND); } $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); }