ThinkPHP5整合微信支付

首先在extend目录新建一个文件夹建立如下脚本:

ThinkPHP5整合微信支付_第1张图片

WxPayApi.php 脚本如下:
GetNotifyUrl();
            $appid =$config->GetAppId();
            $mch_id = $config->GetMerchantId();
            $onoce_str = $this->createNoncestr();
            $data["appid"] = $appid;
            $data["body"] = $body;
            $data["mch_id"] = $mch_id;
            $data["nonce_str"] = $onoce_str;
            $data["notify_url"] = $notify_url;
            $data["out_trade_no"] = "whkjtjy".date("YmdHis");
            $data["spbill_create_ip"] = $this->get_client_ip();
            $data["total_fee"] = $total_fee;
            $data["trade_type"] = "JSAPI";
            $data["openid"] = $openId;
            $sign = $this->getSign($data);
            // halt($data);
            $data["sign"] = $sign;
            $xml = $this->arrayToXml($data);
            $response = $this->postXmlCurl($xml, $url);
            //将微信返回的结果xml转成数组
            $response = $this->xmlToArray($response);
            $response['package']="prepay_id=".$response['prepay_id'];
            $jsapi=array();
            $timeStamp = time();
            $jsapi['appId']=($response["appid"]);
            $jsapi['timeStamp']=("$timeStamp");
            $jsapi['nonceStr']=($this->createNoncestr());
            $jsapi['package']=("prepay_id=" . $response['prepay_id']);
            $jsapi['signType']=("MD5");
            $jsapi['paySign']=($this->getSign($jsapi));
            $parameters = json_encode($jsapi);
            return $parameters;
        }

        /**
         *
         * 统一下单 小程序
         * $openId 用户openid  必填
         * $body 商品信息 必填
         * $total_fee 商品金额 必填
         */
        public function wxappunifiedOrder($openId,$body,$total_fee)
        {
            $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";

            $config = new WxPayConfig();
            $appid =$config->GetWxAppId();
            $mch_id = $config->GetMerchantId();
            $notify_url = $config->GetWxAppNotifyUrl();

            $onoce_str = $this->createNoncestr();
            $data["appid"] = $appid;
            $data["body"] = $body;
            $data["mch_id"] = $mch_id;
            $data["nonce_str"] = $onoce_str;
            $data["notify_url"] = $notify_url;
            $data["out_trade_no"] = "whkjtjy".date("YmdHis");
            $data["spbill_create_ip"] = $this->get_client_ip();
            $data["total_fee"] = $total_fee;
            $data["trade_type"] = "JSAPI";
            $data["openid"] = $openId;
            $sign = $this->getSign($data);
            // halt($data);
            $data["sign"] = $sign;
            $xml = $this->arrayToXml($data);
            $response = $this->postXmlCurl($xml, $url);
            //将微信返回的结果xml转成数组
            $response = $this->xmlToArray($response);
            $response['package']="prepay_id=".$response['prepay_id'];
            $jsapi=array();
            $timeStamp = time();
            $jsapi['appId']=($response["appid"]);
            $jsapi['timeStamp']=("$timeStamp");
            $jsapi['nonceStr']=($this->createNoncestr());
            $jsapi['package']=("prepay_id=" . $response['prepay_id']);
            $jsapi['signType']=("MD5");
            $jsapi['paySign']=($this->getSign($jsapi));
            $parameters = json_encode($jsapi);
            return $parameters;
        }

        /**
         *  作用:产生随机字符串,不长于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;
        }

        /**
         * 生成签名
         */
        public function getSign($Obj)
        {
            $config = new WxPayConfig();
            $key = $config->GetKey();

            foreach ($Obj as $k => $v){
                $Parameters[$k] = $v;
            }
            //签名步骤一:按字典序排序参数
            ksort($Parameters);
            $String = $this->formatBizQueryParaMap($Parameters, false);
            //echo '【string1】'.$String.'
'; //签名步骤二:在string后加入KEY $String = $String."&key=".$key; //echo "【string2】".$String."
"; //签名步骤三:MD5加密 $String = md5($String); //echo "【string3】 ".$String."
"; //签名步骤四:所有字符转为大写 $result_ = strtoupper($String); //echo "【result】 ".$result_."
"; return $result_; } /** * 数组转xml * */ public function arrayToXml($arr){ $xml = ""; foreach ($arr as $key=>$val){ if (is_numeric($val)){ $xml.="<".$key.">".$val.""; }else{ $xml.="<".$key.">"; } } $xml.=""; return $xml; } /** * 作用:以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,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 $data = curl_exec($ch); //返回结果 if($data){ curl_close($ch); return $data; }else{ $error = curl_errno($ch); echo "curl出错,错误码:$error"."
"; curl_close($ch); return false; } } /* * 获取当前服务器的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; } /** * 作用:格式化参数,签名过程需要使用 */ 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; } /** * 作用:将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; } /** * 记录支付信息log */ public static function wxpay_log($basename=null,$msg=null) { $msg = '['.date("Y-m-d H:i:s").']'.'文件名:'.$basename.'[Log]:'.$msg; // 日志文件名:日期.txt $path = ROOT_PATH.DS.'public'. DS .'logs'. DS .date("Ymd").'.txt'; file_put_contents($path, $msg.PHP_EOL,FILE_APPEND); } }
WxPayConfig.php 如下
 
  
WxPayConfigInterface.php脚本如下:
 
  
WxPayJsApi.php 脚本如下:
_CreateOauthUrlForCode($baseUrl);
            Header("Location: $url");
            exit();
        } else {
            //获取code码,以获取openid
            $code = $_GET['code'];
            $openid = $this->getOpenidFromMp($code);
            return $openid;
        }
    }

    /**
     *
     * 获取jsapi支付的参数
     * @param array $UnifiedOrderResult 统一支付接口返回的数据
     * @throws WxPayException
     *
     * @return json数据,可直接填入js函数作为参数
     */
    public function GetJsApiParameters($UnifiedOrderResult)
    {
        if(!array_key_exists("appid", $UnifiedOrderResult)
            || !array_key_exists("prepay_id", $UnifiedOrderResult)
            || $UnifiedOrderResult['prepay_id'] == "")
        {
            throw new WxPayException("参数错误");
        }

        $jsapi = new WxPayJsApiPay();
        $jsapi->SetAppid($UnifiedOrderResult["appid"]);
        $timeStamp = time();
        $jsapi->SetTimeStamp("$timeStamp");
        $jsapi->SetNonceStr(WxPayApi::getNonceStr());
        $jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']);

        $config = new WxPayConfig();
        $jsapi->SetPaySign($jsapi->MakeSign($config));
        $parameters = json_encode($jsapi->GetValues());
        return $parameters;
    }

    /**
     *
     * 通过code从工作平台获取openid机器access_token
     * @param string $code 微信跳转回来带上的code
     *
     * @return openid
     */
    public function GetOpenidFromMp($code)
    {
        $url = $this->__CreateOauthUrlForOpenid($code);

        //初始化curl
        $ch = curl_init();
        $curlVersion = curl_version();
        $config = new WxPayConfig();
        $ua = "WXPaySDK/3.0.9 (".PHP_OS.") PHP/".PHP_VERSION." CURL/".$curlVersion['version']." "
            .$config->GetMerchantId();

        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
        curl_setopt($ch, CURLOPT_USERAGENT, $ua);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

        $proxyHost = "0.0.0.0";
        $proxyPort = 0;
        $config->GetProxy($proxyHost, $proxyPort);
        if($proxyHost != "0.0.0.0" && $proxyPort != 0){
            curl_setopt($ch,CURLOPT_PROXY, $proxyHost);
            curl_setopt($ch,CURLOPT_PROXYPORT, $proxyPort);
        }
        //运行curl,结果以jason形式返回
        $res = curl_exec($ch);
        curl_close($ch);
        //取出openid
        $data = json_decode($res,true);
        $this->data = $data;
        $openid = $data['openid'];
        return $openid;
    }

    /**
     *
     * 拼接签名字符串
     * @param array $urlObj
     *
     * @return 返回已经拼接好的字符串
     */
    private function ToUrlParams($urlObj)
    {
        $buff = "";
        foreach ($urlObj as $k => $v)
        {
            if($k != "sign"){
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     *
     * 获取地址js参数
     *
     * @return 获取共享收货地址js函数需要的参数,json格式可以直接做参数使用
     */
    public function GetEditAddressParameters()
    {
        $config = new WxPayConfig();
        $getData = $this->data;
        $data = array();
        $data["appid"] = $config->GetAppId();
        $data["url"] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
        $time = time();
        $data["timestamp"] = "$time";
        $data["noncestr"] = WxPayApi::getNonceStr();
        $data["accesstoken"] = $getData["access_token"];
        ksort($data);
        $params = $this->ToUrlParams($data);
        $addrSign = sha1($params);

        $afterData = array(
            "addrSign" => $addrSign,
            "signType" => "sha1",
            "scope" => "jsapi_address",
            "appId" => $config->GetAppId(),
            "timeStamp" => $data["timestamp"],
            "nonceStr" => $data["noncestr"]
        );
        $parameters = json_encode($afterData);
        return $parameters;
    }

    /**
     *
     * 构造获取code的url连接
     * @param string $redirectUrl 微信服务器回跳的url,需要url编码
     *
     * @return 返回构造好的url
     */
    private function _CreateOauthUrlForCode($redirectUrl)
    {
        $config = new WxPayConfig();
        $urlObj["appid"] = $config->GetAppId();
        $urlObj["redirect_uri"] = "$redirectUrl";
        $urlObj["response_type"] = "code";
        $urlObj["scope"] = "snsapi_base";
        $urlObj["state"] = "STATE"."#wechat_redirect";
        $bizString = $this->ToUrlParams($urlObj);
        return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
    }

    /**
     *
     * 构造获取open和access_toke的url地址
     * @param string $code,微信跳转带回的code
     *
     * @return 请求的url
     */
    private function __CreateOauthUrlForOpenid($code)
    {
        $config = new WxPayConfig();
        $urlObj["appid"] = $config->GetAppId();
        $urlObj["secret"] = $config->GetAppSecret();
        $urlObj["code"] = $code;
        $urlObj["grant_type"] = "authorization_code";
        $bizString = $this->ToUrlParams($urlObj);
        return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
    }
}

OK到处所有准备工作都做完了 接下来如何调用:

公众号支付
public function index()
{
    //获取openid
    $tools = new WxPayJsApi();
    $openId = $tools->GetOpenid();

    //统一下单
    $wxpay = new WxPayApi();
    $res = $wxpay->unifiedOrder($openId,"好帅的李佳","1");

    //显示支付网页
    $this->assign("res",$res);
    return $this->fetch('wechatpay');
}

小程序支付

public function wxapppay($openId,$body,$fee)
{
    //post
    $wp = new WxPayApi();
    $result = $wp->wxappunifiedOrder($openId,$body,$fee);
    return $result;
}

支付回调

public function notify(){

    $testxml  = file_get_contents("php://input");

    $jsonxml = json_encode(simplexml_load_string($testxml, 'SimpleXMLElement', LIBXML_NOCDATA));

    $result = json_decode($jsonxml, true);//转成数组,
    if($result){
        //如果成功返回了
        $out_trade_no = $result['out_trade_no'];
        if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
            //执行业务逻辑
            //记录支付信息在数据库--此步骤暂时略。。。。
            WxPayApi::wxpay_log('【小程序】支付订单号:'.$out_trade_no,$jsonxml);
        }
        exit('');
    }
}

完成!

 

 

 

你可能感兴趣的:(PHP)