PHP实现微信根据订单退款

由 emer 发布
<?php
header('Content-type:text/html; Charset=utf-8');
if(!$_GET['id']){
    error(['非法访问'],"操作错误");
}
$order = get_by_id("orders",$_GET['id']);

if(!$order){
    error(['订单不存在'],"操作错误");
}

$_config = require('config.php');
$mchid = $_config['mchid']; //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
$appid = $_config['appid']; //微信支付申请对应的公众号的APPID
$apiKey = $_config['apikey']; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
$orderNo = $order['order_no']; //商户订单号(商户订单号与微信订单号二选一,至少填一个)
$wxOrderNo = ''; //微信订单号(商户订单号与微信订单号二选一,至少填一个)
$totalFee = number_format($order['total_price']/100,2); //订单金额,单位:元
$refundFee = number_format($order['total_price']/100,2); //退款金额,单位:元
$refundNo = date("YmdHis").rand(100000,999999); //退款订单号(可随机生成)
$wxPay = new WxpayService($mchid,$appid,$apiKey);

$result = $wxPay->doRefund($totalFee, $refundFee, $refundNo, $wxOrderNo,$orderNo);

if($result===true){
    header("location:result.php");exit;
}

echo 'refund fail';

class WxpayService
{   
    protected $mchid;

    protected $appid;

    protected $apiKey;

    public $data = null;

    public function __construct($mchid, $appid, $key)   
    {

        $this->mchid = $mchid; //https://pay.weixin.qq.com 产品中心-开发配置-商户号

        $this->appid = $appid; //微信支付申请对应的公众号的APPID

        $this->apiKey = $key; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥     
    }   
    /** 
    * 退款    
    * @param float $totalFee 订单金额 单位元   
    * @param float $refundFee 退款金额 单位元  
    * @param string $refundNo 退款单号  
    * @param string $wxOrderNo 微信订单号    
    * @param string $orderNo 商户订单号  
    * @return string
    */  
    public function doRefund($totalFee, $refundFee, $refundNo, $wxOrderNo='',$orderNo='')   
    {

        $config = array(                
                'mch_id' => $this->mchid,

                'appid' => $this->appid,

                'key' => $this->apiKey,             
        );

        $unified = array(               
                'appid' => $config['appid'],

                'mch_id' => $config['mch_id'],

                'nonce_str' => self::createNonceStr(),

                'total_fee' => intval($totalFee * 100), //订单金额 单位 转为分

                'refund_fee' => intval($refundFee * 100), //退款金额 单位 转为分

                'sign_type' => 'MD5', //签名类型 支持HMAC-SHA256和MD5,默认为MD5

                'transaction_id'=>$wxOrderNo, //微信订单号

                'out_trade_no'=>$orderNo, //商户订单号

                'out_refund_no'=>$refundNo, //商户退款单号

                'refund_desc'=>'已退款', //退款原因(选填)                
        );

        $unified['sign'] = self::getSign($unified, $config['key']);

        $responseXml = $this->curlPost('https://api.mch.weixin.qq.com/secapi/pay/refund', self::arrayToXml($unified));

        $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);

        if ($unifiedOrder === false) {          
            die('parse xml error');         
        }

        if ($unifiedOrder->return_code != 'SUCCESS') {          
            die($unifiedOrder->return_msg);         
        }

        if ($unifiedOrder->result_code != 'SUCCESS') {          
            die($unifiedOrder->err_code);           
        }

        return true;

    }

    public static function curlGet($url = '', $options = array())   
    {   
        $ch = curl_init($url);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        curl_setopt($ch, CURLOPT_TIMEOUT, 30);

        if (!empty($options)) {         
            curl_setopt_array($ch, $options);           
        }

        //https请求 不验证证书和host        
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        $data = curl_exec($ch);

        curl_close($ch);

        return $data;       
    }

    public function curlPost($url = '', $postData = '', $options = array()) 
    {       
        if (is_array($postData)) {          
            $postData = http_build_query($postData);            
        }

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        curl_setopt($ch, CURLOPT_POST, 1);

        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);

        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数

        if (!empty($options)) {         
            curl_setopt_array($ch, $options);           
        }

        //https请求 不验证证书和host        
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);        
        //第一种方法,cert 与 key 分别属于两个.pem文件     
        //默认格式为PEM,可以注释 
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); 
        curl_setopt($ch,CURLOPT_SSLCERT,'protected/cert/apiclient_cert.pem');   
        //默认格式为PEM,可以注释

        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');      
        curl_setopt($ch,CURLOPT_SSLKEY,'protected/cert/apiclient_key.pem');

        //第二种方式,两个文件合成一个.pem文件      
        // curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');

        $data = curl_exec($ch);

        curl_close($ch);

        return $data;

    }

    public static function createNonceStr($length = 16) 
    {   
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

        $str = '';

        for ($i = 0; $i < $length; $i++) {          
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);          
        }

        return $str;        
    }

    public static function arrayToXml($arr) 
    {       
        $xml = "<root>";
        foreach ($arr as $key => $val) {
            if (is_array($val)) {
                $xml .= "<" . $key . ">" . $this->arrayToXml($val) . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            }
        }
        $xml .= "</root>";
        return $xml;
    }

    public static function getSign($params, $key)   
    {

        ksort($params, SORT_STRING);

        $unSignParaString = self::formatQueryParaMap($params, false);

        $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));

        return $signStr;        
    }

    protected static function formatQueryParaMap($paraMap, $urlEncode = false)  
    {       
        $buff = "";

        ksort($paraMap);

        foreach ($paraMap as $k => $v) {            
            if (null != $v && "null" != $v) {               
                if ($urlEncode) {                   
                    $v = urlencode($v);                 
                }               
                $buff .= $k . "=" . $v . "&";               
            }           
        }

        $reqPar = '';

        if (strlen($buff) > 0) {            
            $reqPar = substr($buff, 0, strlen($buff) - 1);          
        }

        return $reqPar;     
    }   
}

0条评论

发表评论


验证码