微信支付之退款(PHP版本)

这段日子在写微信支付退款的时候,发现很多问题,当然主要问题还是发生在异步回调的路上。

申请退款

总的来说呢,申请退款是挺简单的。

但是还是有几个重点的。比如说SSL证书的POST请求,再比如说商家用户的KEY

这几个点可以在百度中找到答案。

我接下来就直接上申请退款的代码好了

代码实现之类文件

1.Xwechat.php ```php class Xwechat{ protected static function getConfig(){ $config = \think\facade\Config::get('tool.wechat.wechat_app'); if (!isset($config) || !isset($config['appid']) || !isset($config['appsecret']) || empty($config['appid']) || empty($config['appsecret'])){ outErr(31,'wechat app config is missing'); }
    return $config;

}

public static function refund($orderSn,$refundOrderSn,$total_fee,$refund_fee,$transaction_id){ $time = date('Y-m-d H:i:s',$time);

    $config = self::getConfig();

    $wechatConfig = \think\facade\Config::get('tool.wechat.wechat_pay');

    $unifiedData = [
        'appid' => $config['appid'],
        'mch_id' => $wechatConfig['mchid'],
        'nonce_str' => md5($time),

// 'body' => $body, 'out_trade_no' => $orderSn, 'out_refund_no' => $refundOrderSn, 'refund_fee' => $refund_fee * 100, 'total_fee' => $total_fee * 100, 'transaction_id' => $transaction_id, 'notify_url' => $wechatConfig['refund_notify'] ]; $unifiedData['sign'] = self::wechatPayCreateSign($unifiedData,$wechatConfig);

    $xmlData = Xstring::arrayToXml($unifiedData);

    $postData = HttpRequest::postRefundWechatPaySSLData($xmlData,'https://api.mch.weixin.qq.com/secapi/pay/refund');

    $res = Xstring::xmlToArray($postData);

    if ($res['return_code'] == 'FAIL'){
        if (!empty($content['err_code_des'])) {
            outErr(1,$content['err_code_des']);
        }else{
            outErr(1,$content['return_msg']);
        }
    }

    return $res;

}

public static function wechatPayCreateSign($arr,$config){ ksort($arr);

    $string="";
    $i=1;
    foreach($arr as $key=>$val){
        if($i == 1){
            $string .= $key."=".$val;
        }else{
            $string .= "&".$key."=".$val;
        }

        $i++;
    }

    $signtemp = $string."&key=".$config['key'];
    $sign = MD5($signtemp);
    $sign = strtoupper($sign);

    return $sign;

} }

2.Xstring.php
```php
class Xstring{
  public static function xmlToArray($data){
        libxml_disable_entity_loader(true);

        $data = json_decode(json_encode(simplexml_load_string($data,'SimpleXMLElement',LIBXML_NOCDATA)),true);

        return $data;
    }

    public static function arrayToXml($arr){
        $xml = "";

        foreach ($arr as $key=>$val){
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."";
            }else{
                $xml.="<".$key.">";
            }
        }
        $xml.="";

        return $xml;
    }
}

3.HttpRequest.php

class HttpRequest{
  public static function postRefundWechatPaySSLData($xml,$url,$second = 30){
        $path = dirname(__DIR__).'/file/wechatRefundPaySSL/';

        if (is_array($xml)) {
            $xml = http_build_query($xml);
        }
        $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, $xml);
        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,$path.'apiclient_cert.pem');//证书路径
        //默认格式为PEM,可以注释
        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLKEY,$path.'apiclient_key.pem');//证书路径

        $data = curl_exec($ch);

        curl_close($ch);
        return $data;
    }
}

代码实现之实现

1.Refund.php ```php class Refund{ Xwechat::refund('商家订单号','商家退款单号','订单总价','退款金额','transaction_id'); } ```

退款回调

回调这里有个很严重的问题,那就是php>7.0的开发者注意,解密函数mcrypt_decrypt()不可用,要用openssl_decrypt()

代码实现

1.Notify.php ```php class Notify{ public function refund(){ //先获取微信服务器过来的XML信息 //最主要是解密 $wechatConfig = \think\facade\Config::get('tool.wechat.wechat_pay'); $datas = Xstring::xmlToArray(self::refundDecrypt($data['req_info'],md5($wechatConfig['key'])));
  if ('SUCCESS' == $datas['refund_status']){
            RefundAction::_updateStateById('success',[
                'refundSn' => $datas['out_refund_no']
            ]);

            $result = $datas;
        }else{
            $result = false;
        }
    }else{
        $result = false;
    }

    if ($result){
        $str='';
    }else{
        $str='';
    }
    echo $str;

}

 //php>7.0
 public static function refundDecrypt($str,$key){
    $str = openssl_decrypt($str , 'aes-256-ecb',$key, OPENSSL_ZERO_PADDING);
    $pad = ord($str[($len = strlen($str)) - 1]);
    $len = strlen($str);
    $pad = ord($str[$len - 1]);
    return substr($str, 0, strlen($str) - $pad);
} 

 //php<=7.0
public static function refundDecrypt($str,$key){
    $str = base64_decode($str);
    $str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB);
    $block = mcrypt_get_block_size('rijndael_128', 'ecb');
    $pad = ord($str[($len = strlen($str)) - 1]);
    $len = strlen($str);
    $pad = ord($str[$len - 1]);
    return substr($str, 0, strlen($str) - $pad);
}

}


本文为ctexthuang原创文章,转载请注明来自[ctexthuang_blog][1] 


  [1]: https://ctexthuang.com
tag(s): Wechat
show comments · back · home
Edit with Markdown
召唤看板娘