微信支付及退款代码类封装

4 篇文章 0 订阅
2 篇文章 0 订阅

微信支付类

class WeiXinPay
{
    //----- [基本信息设置]  -----
    //微信公众号身份的唯一标识
    protected $APPID = 'wx056xxxxxxxxa02';//填写您的appid。微信公众平台里的
    protected $APPSECRET = '4c11xxxxx5451f6508a7c';
    //受理商ID,身份标识
    protected $MCHID = 155xxx1 ;//商户id
    //商户支付密钥Key
    protected $KEY = 'ASASDF542xxxxxWE45123ZX4C78F789';
    //回调通知接口
    protected $APPURL = 'https://wbstp.xxx.cn/xcxhome/payNotify';
    //交易类型
    protected $TRADETYPE = 'JSAPI';
    //商品类型信息
    protected $BODY = 'wx/book' ;
    //微信支付类的构造函数
    function __construct($openid, $outTradeNo, $totalFee)
    {
        $this->openid = $openid; //用户唯一标识
        $this->outTradeNo = $outTradeNo; //商户订单号
        $this->totalFee = $totalFee; //总价
    }
    //微信支付类向外暴露的支付接口
    public function pay()
    {
        $result = $this->weixinapp();
        return $result;
    }

    //对微信统下单接返回的支付相关 数据进行处理
    private function weixinapp()
    {
        $unifiedorder = $this ->unifiedorder();
        $parameters = array(
            'appId' =>$this ->APPID, //小程序ID
            'timeStamp'=> '' .time().'', //时间戳
            'nonceStr' =>$this->createNoncestr(), //随机串
            'package' => 'prepay_id=' . $unifiedorder['prepay_id'],//数据包
            'signType' => 'MD5'//签名方式
        );
        $parameters['paySign']=$this->getSign($parameters);
        unset($parameters['appId']);
        return $parameters;
    }

    //请求微信统下单接口
    private function unifiedorder()
    {
        $parameters = array(
            'appid' => $this->APPID,//小程序id
            'mch_id' => $this->MCHID,//商户id
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],//终端ip
            'notify_url' =>$this->APPURL, //通知地址
            'nonce_str'=> $this->createNoncestr(),//随机字符串
            'out_trade_no' =>$this->outTradeNo,//商户订单编号
            'total_fee' =>floatval($this->totalFee), //总金额
            'openid' =>$this->openid,//用户openid
            'trade_type' =>$this->TRADETYPE,//交易类型
            'body' =>$this->BODY, //商品信息
        );
        $parameters['sign'] = $this->getSign($parameters);
        $xmlData = $this ->arrayToXml($parameters);
        $xml_result = $this->postXmlCurl($xmlData, 'https://api.mch.weixin.qq.com/pay/unifiedorder',60);
        $result = $this->xmlToArray($xml_result);
        //var_dump($result);
        return $result;
    }

    //数组转xml字符串方法
    protected function arrayToXml($arr)
    {
        $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;
    }

    //xml转数组
    protected function xmlToArray($xml)
    {
        $array_data = json_decode(json_encode(simplexml_load_string($xml,'SimpleXmlElement',LIBXML_NOCDATA)),true);
        return $array_data;
    }

    //发送xm1请求方法
    private static function postXmlCurl($xml, $url, $second = 30)
    {
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        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);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
        curl_setopt($ch, CURLOPT_TIMEOUT, 40);
        set_time_limit(0);
        //运行curl
        $data = curl_exec($ch);
        //var_dump($data);
        //返回结果
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_error($ch);
            curl_close($ch);
            throw new Exception("curl出错错误码$error",500);
        }
    }

    //对要发送到微信统一下单接口的数据进行签名
    protected function getSign($obj)
    {
        foreach ($obj as $k => $v){
            $Parameters[$k] = $v;
        }
        //签名步骤一:按字典字排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //签名步骤二:在string后加入KEY
        $String = $String. "&key=" .$this->KEY;
        //签名步骤三: MD5加密
        $String = md5($String);
        //签名步骤四:所有字符转为大写
        $result_ = strtoupper($String);
        return $result_;
    }

    //排序并格式化参数方法,签名时需要使用
    protected function formatBizQueryParaMap($paraMap, $urlencode)
    {
        $buff = "";
        ksort($paraMap );
        foreach ($paraMap as $k => $v){
            if ($urlencode ){
                $v = urlencode($v);
            }
            $buff .= $k . "=" .$v . "&";
        }
        $reqPar = '';
        if (strlen($buff) > 0){
            $reqPar = substr($buff, 0, strlen($buff)-1);
        }
        return $reqPar;
    }
    protected function createNoncestr($length = 32){
        $str = '';
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol) - 1;
        for ($i = 0; $i < $length; $i++) {
            $str .= $strPol[rand(0, $max)];
        }
        return $str;
    }
}

微信退款类

use think\facade\Log;

class WeiXinRefund extends WeiXinPay
{
    protected $sslCertPath = __DIR__. '/cert/apiclient_cert.pem';//正书路径
    protected $sslKeyPath =  __DIR__.'/cert/apiclient_key.pem';//证书路径

    function __construct($openid, $transactionId, $totalFee, $outRefundNo, $refundFee)
    {
        //初始化退款类需要的变量
        $this->openid = $openid;
        $this->transactionId = $transactionId;
        $this->totalFee = $totalFee;
        $this->outRefundNo = $outRefundNo;
        $this->refundFee = $refundFee;
    }

    public function refund()
    {
        //对外暴露的退款接口
        $result = $this->wxRefundApi();
        return $result;
    }
    private function wxRefundApi()
    {
        //通过微信api进行退款流程
        $param = array(
            'appid' => $this->APPID,
            'mch_id' => $this->MCHID,
            'nonce_str' => $this->createNoncestr(),
            'out_refund_no' => $this->outRefundNo,
            'transaction_id' => $this->transactionId,
            'total_fee' => $this->totalFee,
            'refund_fee' => $this->refundFee,
        );
        $param['sign'] = $this->getsign($param);
        $xmlData = $this->arrayToXml($param);
        $xmlResult = $this->postXmlSSLCurl($xmlData, 'https://api.mch.weixin.qq.com/secapi/pay/refund');
        $result = $this->xmlToArray($xmlResult);
        return $result;
    }
    //需要使用证书的请求
    private function postXmlSSLCurl($xml, $url, $second=30)
    {
        $ch = curl_init();
        //超时时间
        curl_setopt ($ch, CURLOPT_TIMEOUT, $second);
        //这里设置代理,如果有的话
        //curl setopt(Sch,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->sslCertPath);
        //默认格式为PEM,可以注释
        curl_setopt($ch, CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch, CURLOPT_SSLKEY, $this->sslKeyPath);
        //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_error($ch);
            Log::write( 'curl出错,错误内容:'.$error) ;
            curl_close($ch);
            return false;
        }

    }

}

亲测运行可用,代码有待改进,有什么不足之处大佬们可以给点意见

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值