tp5微信退款及回调

退款要注意的地方
1、证书的路径–证书在商户平台下载并放在public里面引用即可
2、退款回调地址-在商户平台设置,不带参数
3、金额都要x100变元为分
4、商户退款单号out_refund_no–自定义-相当于支付时订单号
5、微信单号transaction_id–在支付回调时需要返回存储的参数,见另一篇小程序支付回调方法
6、商户订单号out_trade_no和微信单号transaction_id任选其一,我只用了transaction_id没有报错

 //退款
    //@param    order_id订单号
    public function refund()
    {
    
    
        $token=input('post.token');
        $res=checkToken($token);
        if($res ==90001){
    
    
            $order_id=input('post.order_id');
            $info=Db::name('order')->where('order_id',$order_id)->find();
            if ($info['expire_time']< time()){
    
    
                $data['code']=5;
                $data['msg']='订单已过期';
                $data['date']=null;
                return json($data);
            }
            $result=Db::name('refund')->where('order_id',$order_id)->find();
            if ($result){
    
    
                $data['code']=4;
                $data['msg']='您已申请退款,请勿重复申请';
                $data['date']=null;
                return json($data);
            }
            $res1=$this->refundOrder($order_id,$info);
            if ($res1){
    
    
                $appid=config('base.web_appid');
                $mch_id=config('base.wev_mch_id');
                $key=config('base.web_appsecret');
                $apiKey=config('base.web_apiKey');
                $wxPay = new WxpayService($mch_id,$appid,$key,$apiKey);
                $order_no=$order_id;//退款的订单号
                $total_fee=intval($info['amount']*100);;//订单金额
                $refund_fee=intval($res1['amount']*100);//退款的金额
                $transaction_id=$info['transaction_id'];
                $notify_url='https://域名/xxx/xx/xx/refundNotify';
                $result= $wxPay->wx_refund($appid,$mch_id,$order_no,$notify_url,$total_fee,$refund_fee,$transaction_id,$apiKey);
                if ($result){
    
    
                    $data['code']=1;
                    $data['msg']='退款申请成功';
                    $data['date']=$order_no;
                    return json($data);
                }else{
    
    
                    $data['code']=0;
                    $data['msg']='退款申请失败';
                    $data['date']=null;
                    return json($data);
                }

            }else{
    
    
                $data['code']=0;
                $data['msg']='退款申请失败';
                $data['date']=null;
                return json($data);
            }

        }else if($res == 90002){
    
    
            $data['code']=2;
            $data['msg']='token验证出错';
            $data['date']=null;
        }else if($res == 90003){
    
    
            $data['code']=3;
            $data['msg']='token超时,请重新登录';
            $data['date']=null;
        }

        return json($data);
    }

    //退款回调
    public function refundNotify(){
    
    
        $data = file_get_contents('php://input');
        if (empty($data)){
    
    
            $data=$GLOBALS['HTTP_RAW_POST_DATA'];;
        }
        $arr = $this -> xmlToArray($data);
       //判断返回状态
        if($arr['return_code'] == 'SUCCESS'){
    
    
            $req_info = $arr['req_info'];
            $rep=$this->decipheringReqInfo($req_info);
            if($rep["refund_status"] == "SUCCESS") {
    
    
                //修改订单状态
                $res = Db::name('order')->where('order_id', $rep['out_trade_no'])->update(['status' => 9]);
                $res1 = Db::name('refund')->where('order_id', $rep['out_trade_no'])->update(['status' => 2,'update_time'=>$rep['success_time']]);
                return '<xml> <return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
            }
        }
        return '<xml> <return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
    }

    //解密退款成功时,微信回调返回的信息
    public static function decipheringReqInfo($str){
    
    
        //微信商户key
        $key = config('base.web_apiKey');
        $str = base64_decode($str);
        $xml = openssl_decrypt($str,'aes-256-ecb',md5($key),OPENSSL_RAW_DATA);
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }

    //将xml格式转换成数组
    public  function xmlToArray($xml) {
    
    
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $val = json_decode(json_encode($xmlstring), true);
        return $val;
    }
<?php
namespace WxpayService;

class WxpayService
{
    
    
	// 退款地址
    private $refund_url   = 'https://api.mch.weixin.qq.com/secapi/pay/refund';							
    // 证书文件放在与入口文件同级的目录下
    private $SSLCERT_PATH = './apiclient_cert.pem';							// api证书路径
    private $SSLKEY_PATH  = './apiclient_key.pem';							// 密钥证书路径
    protected $mchid;
    protected $appid;
    protected $appKey;
    protected $apiKey;
    public $data = null;
    public function __construct($mchid, $appid, $appKey,$key)
    {
    
    
        $this->mchid = $mchid; //https://pay.weixin.qq.com 产品中心-开发配置-商户号
        $this->appid = $appid; //微信支付申请对应的公众号的APPID
        $this->appKey = $appKey; //微信支付申请对应的公众号的APP Key
        $this->apiKey = $key;   //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
    }
   
    /**
     * 微信退款
     * [wx_refund description]
     * @Author   念天地之悠悠
     * @DateTime 2019-03-11
     * @param    [type]     $appid          [description] APPID
     * @param    [type]     $mch_id         [description] 商户号
     * @param    [type]     $order_no       [description] 商户退款单号
     * @param    [type]     $notify_url     [description] 异步通知地址
     * @param    [type]     $total_fee      [description] 订单金额
     * @param    [type]     $refund_fee     [description] 退款金额 单位分
     * @param    [type]     $transaction_id [description] 微信单号
     * @param    [type]     $wx_key 		[description] 申请支付后设置的key
     * @return   [type]                     [description]
     */
    public function wx_refund($appid,$mch_id,$order_no,$notify_url,$total_fee,$refund_fee,$transaction_id,$wx_key){
    
    
        $post_data = [];
        $nonce_str = $this->nonce_str();
        $post_data['appid']			 = $appid;					// APPID
        $post_data['mch_id']		 = $mch_id;					// 商户号
        $post_data['nonce_str']		 = $nonce_str;				// 随机码
        $post_data['out_refund_no']  = $order_no;				// 商户退款单号
        $post_data['refund_fee'] 	 = (int)$refund_fee;		// 退款金额
        $post_data['total_fee'] 	 = (int)$total_fee;			// 订单金额
        $post_data['transaction_id'] = $transaction_id;			// 微信单号
        $sign = $this->sign($post_data,$wx_key);				// 签名
        $post_xml = '<xml>
		   <appid>'.$appid.'</appid>
		   <mch_id>'.$mch_id.'</mch_id>
		   <nonce_str>'.$nonce_str.'</nonce_str>
		   <out_refund_no>'.$order_no.'</out_refund_no>
		   <refund_fee>'.$refund_fee.'</refund_fee>
		   <total_fee>'.$total_fee.'</total_fee>
		   <transaction_id>'.$transaction_id.'</transaction_id>
		   <sign>'.$sign.'</sign>
		</xml>';
        $xml = $this->postXmlSSLCurl($this->refund_url,$post_xml);
        // 将xml转数组
        $arr 	 = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        if ($arr === false) {
    
    
            die('parse xml error');
        }
        if ($arr->return_code != 'SUCCESS') {
    
    
            die($arr->return_msg);
        }
        if ($arr->result_code != 'SUCCESS') {
    
    
            die($arr->err_code);
        }

        return true;
    }

    private function nonce_str(){
    
    
        $result = '';
        $str 	= 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
        for ($i = 0; $i < 32; $i++) {
    
    
            $result .= $str[rand(0,48)];
        }
        return $result;
    }

    /**
     * 签名
     * [sign description]
     * @Author   念天地之悠悠
     * @DateTime 2019-03-11
     * @param    [type]     $data   [description] 数据集
     * @param    [type]     $wx_key [description] 微信支付key
     * @return   [type]             [description]
     */
    private function sign($data,$wx_key = ''){
    
    
        $stringA = '';
        foreach ($data as $key => $value) {
    
    
            if (!$value) continue;
            if ($stringA) $stringA .= '&'.$key."=".$value;
            else $stringA = $key."=".$value;
        }
        if ($wx_key == '') {
    
    
            $stringSignTemp = $stringA;
        }else{
    
    
            $stringSignTemp = $stringA.'&key='.$wx_key;
        }
        return strtoupper(md5($stringSignTemp));
    }

    /**
     * 需要证书的curl请求
     * [postXmlSSLCurl description]
     * @Author   念天地之悠悠
     * @DateTime 2019-03-12
     * @param    [type]     $url    [description] 访问地址
     * @param    [type]     $xml    [description] mxl数据体
     * @param    integer    $second [description] 超时时间
     * @return   [type]             [description]
     */
    public function postXmlSSLCurl($url,$xml,$second=30){
    
    
        $ch = curl_init();
        //超时时间
        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
        //这里设置代理,如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
        //设置header
        curl_setopt($ch,CURLOPT_HEADER,FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
        //设置证书
        //使用证书:cert 与 key 分别属于两个.pem文件
        //默认格式为PEM,可以注释
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLCERT, $this->SSLCERT_PATH);
        //默认格式为PEM,可以注释
        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLKEY, $this->SSLKEY_PATH);
        //post提交方式
        curl_setopt($ch,CURLOPT_POST, true);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
        $data = curl_exec($ch);
        //返回结果
        if($data){
    
    
            curl_close($ch);
            return $data;
        } else {
    
    
            $error = curl_errno($ch);
            echo "curl出错,错误码:$error"."<br>";
            curl_close($ch);
            return false;
        }
    }
}


猜你喜欢

转载自blog.csdn.net/zax_96/article/details/107033887
今日推荐