PHP tp5 微信支付

在php中实现微信支付,我们需要准备设置以下东西:

1、appid(微信开放平台上的应用id)

2、mch_id(微信申请成功之后邮件中的商户id)

3、notify_url(支付成功后的回调地址)

4、api_key(在微信商户平台上自己设定的api密钥 32位)

5、apiclient_cert.pem 和 apiclient_key.pem 证书

接下来直接上代码(可复制粘贴,修改以上的参数及可使用):

<?php
namespace app\api\controller;
use think\Db;

class Wxpay{

    /*
    微信支付配置参数
    */
    private $config = array(
        'appid' => "你的微信开放平台上的应用id",    /*微信开放平台上的应用id*/
        'mch_id' => "你的微信申请成功之后邮件中的商户id",   /*微信申请成功之后邮件中的商户id*/
        'api_key' => "你的在微信商户平台上自己设定的api密钥",    /*在微信商户平台上自己设定的api密钥 32位*/
        'notify_url' => '回调地址',
  
    );
 
    //微信支付下单
    public function wxpay($body,$orderid, $out_trade_no, $total_fee, $type){
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $data["appid"]            = $this->config["appid"];
        $data["body"]             = '艺商城-'.$body;
        $data["mch_id"]           = $this->config['mch_id'];
        $data["nonce_str"]        = $this->createNoncestr();
        $data["notify_url"]       = $this->config["notify_url"];
        $data['trade_type']       = 'APP';
        $data["total_fee"]        = "1";//"$total_fee"
        $data["out_trade_no"]     = $out_trade_no;
        $data["spbill_create_ip"] = $this->get_client_ip();
        $sign                     = $this->getSign($data);
        $data["sign"]             = $sign;

        $xml      = $this->arrayToXml($data);
        $response = $this->postXmlCurl($xml, $url);
        $response = $this->xmlToArray($response);
        $response = $this->two_sign($response, $data["nonce_str"]);
        //返回数据
        echo json_encode(['status'=>1,'indo'=>'success','orderid'=>$orderid,'data'=>$response]);
    }

    //微信支付回调地址--商品支付
    public function wxNotifyUrl(){
        $type = 3;
        $this->payCommom($type);
    }

  
    /**
     * [payCommom 充值公共方法]
     * @param  [type] $type []
     * @return [type]       [description]
     */
    public function payCommom($type){
        $xml_data = file_get_contents('php://input');
        $re = $this->wx_verification($xml_data);
        $flow_sn = $re['transaction_id'];//获取流水号
        if($re['code'] == 1){
            $data  = $this->xmlToArray($xml_data);
                // 启动事务
                Db::startTrans();
                try{

                  #你的订单业务逻辑....

                    // 提交事务
                    Db::commit(); 
                } catch (\Exception $e) {
                    // 回滚事务
                    Db::rollback();
                }
            }
        }
        echo "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    }

    /**
     * 微信支付退款
     * $pay_sn      支付单号
     * $total_fee   订单金额
     * $refund_fee  退款金额
     */
    public function wxrefundOrder($pay_sn, $total_fee, $refund_fee)
    {
        $url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
 
        $data["appid"]            = $this->config["appid"];
        $data["mch_id"]           = $this->config['mch_id'];
        $data["nonce_str"]        = $this->createNoncestr();
        $data['out_trade_no']     = $pay_sn;
        $data['out_refund_no']    = $pay_sn;
        $data["total_fee"]        = intval($total_fee * 100);
        $data["refund_fee"]       = intval($refund_fee * 100);
        $sign                     = $this->getSign($data);
        $data["sign"]             = $sign;

        $xml      = $this->arrayToXml($data);
        $response = $this->postXmlCurl($xml, $url);
        $response = $this->xmlToArray($response);  
        if ($response['return_code'] == 'SUCCESS' && $response['refund_id']) {
            return ['code'=>1,'refund_id'    => $response['refund_id']];
        }else{
            return ['code'=>0,'err_code_des' => $response['err_code_des']];
        }
    }

    /**
     * [order_record 订单记录]
     * @return [type] [description]
     */
    public function order_record($orderid, $unionid, $title, $price, $user_money){
        $record['orderid'] = $orderid; 
        $record['unionid'] = $unionid; 
        $record['title'] = $title; 
        $record['price'] = $price;
        $record['money'] = $user_money;
        $record['addtime'] = time();
        Db::name('order_record')->insert($record);
    }

    //微信支付二次签名
    public function two_sign( $response = NULL, $nonce_str){
        if( $response != NULL && $response['return_code'] != 'SUCCESS'){
            return [];
        }else{
            //接收微信返回的数据,传给APP!
            $arr =array(
                'appid'     => $this->config["appid"],
                'partnerid' => $this->config['mch_id'],
                'prepayid'  => $response['prepay_id'],
                'package'   => 'Sign=WXPay',
                'noncestr'  => $nonce_str,
                'timestamp' => time(),
            );
            //第二次生成签名
            $sign = $this->getSign($arr);
            $arr['sign'] = $sign;
            return $arr;
        }
    }
    //微信支付签名
    public function getSign($Obj){
        foreach ($Obj as $k => $v){
            $Parameters[$k] = $v;
        }
        //签名步骤一:按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        // echo '【string1】:'.$String.'</br>';
        //签名步骤二:在string后加入KEY
        $String = $String."&key=".$this->config['api_key'];
        // echo "【string2】".$String."</br>";
        //签名步骤三:MD5加密
        $String = md5($String);
        // echo "【string3】 ".$String."</br>";
        //签名步骤四:所有字符转为大写
        $result_ = strtoupper($String);
        // echo "【result】 ".$result_."</br>";
        return $result_;
    }
 
 
    /**
    *  作用:产生随机字符串,不长于32位
    */
    public function createNoncestr( $length = 32 ){
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; 
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  { 
            $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1); 
        } 
        return $str;
    }
    
    /*
    获取当前服务器的IP
    */
    public function get_client_ip(){
        if ($_SERVER['REMOTE_ADDR']) {
            $cip = $_SERVER['REMOTE_ADDR'];
        } elseif (getenv("REMOTE_ADDR")) {
            $cip = getenv("REMOTE_ADDR");
        } elseif (getenv("HTTP_CLIENT_IP")) {
            $cip = getenv("HTTP_CLIENT_IP");
        } else {
            $cip = "unknown";
        }
        return $cip;
    }
 
    //数组转xml
    public 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转为array
    */
    public function xmlToArray($xml){  
        //将XML转为array       
        $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);   
        return $array_data;
    }
 
 
    /**
    *  作用:以post方式提交xml到对应的接口url
    */
    public function postXmlCurl($xml,$url,$second=30){  
        //初始化curl       
        $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,2);
        //设置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);

        //默认格式为PEM,可以注释
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
        //退款证书
        curl_setopt($ch,CURLOPT_SSLCERT,PUBLIC_PATH.'/wx/apiclient_cert.pem');
        //默认格式为PEM,可以注释
        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        //退款证书
        curl_setopt($ch,CURLOPT_SSLKEY,PUBLIC_PATH.'/wx/apiclient_key.pem');

        //运行curl
        $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;
        }
    }
 
    /**
    *  作用:格式化参数,签名过程需要使用
    */
    public 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;
    }
        
    //微信支付回调验证
    public function wx_verification($xml_data){
        $data = $this->xmlToArray($xml_data);
        $sign = $data['sign'];
        unset($data['sign']);
        if($sign == $this->getSign($data)){
            if ($data['result_code'] == 'SUCCESS') {
                $arr=['code'=>1];
            }else{
                $arr=['code'=>0,'msg'=>$data['return_msg']];
            }
        }else{
            $arr=['code'=>0,'msg'=>'签名验证失败']; 
        }
        return $arr;
    }
}

 

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值