php微信普通商户退款

关于退款有几点说明

1,退款需要证书 apiclient_cert.pem和apiclient_key.pem证书

2,数据库需要保存相关微信返回的参数 trade_no 例如是:4200000122201806222222222222

3,另外就是appid和mch_id一整套。

下面是相关退款的方法和执行流程

 直接调用  wxRefund() 方法即可,根据返回的退款信息进行下一步操作。

   public function wxRefund()
    {
        $userpayinfo = Db::table('支付工具记录表')->find();

     //查询订单表trad_num,主要是用这个字段到支付记录表换取$tradLog记录
        $trad_num = Db::table('订单表')->value('trad_num');

        $tradLog = Db::table('交易记录表')->where(['itemid'=>$itemid,'trad_num'=>$trad_num])->field('transaction_id,total_fee')->find();
        $trade_no = $tradLog['transaction_id'];
        $total_fee = $tradLog['total_fee'];

        //支付信息
        $appid = $userpayinfo['appid'];
        $mch_id = $userpayinfo['mchid'];

        $nonce_str = $this->getNonceStr();
        $op_user_id = $userpayinfo['mchid'];

     //随机生成的退款单号
        $out_refund_no = date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT),$transaction_id = $trade_no;
        $refund_fee = $refund_money*100;
        $total_fee = $total_fee*100;
        $key = $userpayinfo['partnerkey'];
        $apiclient_cert = $userpayinfo['certpath'];
        $apiclient_key = $userpayinfo['publicpath'];
        $ref= strtoupper(md5("appid=".$appid."&mch_id=".$mch_id."&nonce_str=".$nonce_str."&op_user_id=".$op_user_id."&out_refund_no=".$out_refund_no."&refund_fee=".$refund_fee."&total_fee=".$total_fee."&transaction_id=".$transaction_id."&key=".$key));//sign加密MD5
        $refund=array(
            'appid'=>$appid,//应用ID,固定
            'mch_id'=>$mch_id,//商户号,固定
            'nonce_str'=>$nonce_str,//随机字符串
            'op_user_id'=>$op_user_id,//操作员
            'out_refund_no'=>$out_refund_no,//商户内部唯一退款单号
            'transaction_id'=>$transaction_id,//微信订单号 微信生成的订单号,在支付通知中有返回
            'refund_fee'=>$refund_fee,//退款金额
            'total_fee'=>$total_fee,//总金额
            'sign'=>$ref//签名
        );
     //微信退款地址,post请求
        $url="https://api.mch.weixin.qq.com/secapi/pay/refund";//微信退款地址,post请求
        $xml=$this->arrayToXml($refund);
        $ch=curl_init();
        curl_setopt($ch,CURLOPT_URL,$url);
        // curl_setopt($ch,CURLOPT_HEADER,1);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,1);//证书检查
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem');
        curl_setopt($ch,CURLOPT_SSLCERT,getcwd().$apiclient_cert);
        // curl_setopt($ch,CURLOPT_SSLCERT,'/data/wwwroot/项目名/public/upload/certificate/1498007396990/apiclient_cert.pem');
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem');
        curl_setopt($ch,CURLOPT_SSLKEY,getcwd().$apiclient_key);
        // curl_setopt($ch,CURLOPT_SSLKEY,'/data/wwwroot/项目名/public/upload/certificate/1498007396990/apiclient_key.pem');
        curl_setopt($ch,CURLOPT_POST,1);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
        $data=curl_exec($ch);
        curl_close($ch);
        $return = $this->xmlToArray($data);
        return $return;
    }

 退款方法中需要调用的其他函数

    //生成随机字符串
    public function getNonceStr($length = 16)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {
            $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
        }
        return $str;
    }

    //数组转为xml格式
    public function arrayToXml($arr)
    {
        $xml = "<xml>";
        foreach ($arr as $key=>$val){
            if(is_array($val)){
                $xml.="<".$key.">".arrayToXml($val)."</".$key.">";
            }else{
                $xml.="<".$key.">".$val."</".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml ;
    }

    //xml格式转化为数组
    public function xmlToArray($xml)
    {
        libxml_disable_entity_loader(true);
        $xmlstring = simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOCDATA);
        $val = json_decode(json_encode($xmlstring),true);
        return $val;
    }

希望大家能用的上,谢谢大家的观看!

posted @ 2018-06-16 17:37  瑛雄  阅读(381)  评论(0编辑  收藏  举报