首页 > php教程 > php手册 > 正文

ThinkPay最新微信支付公众号支付驱动分享

php中文网
发布: 2016-12-01 00:00:17
原创
1649人浏览过

ThinkPay最新微信支付公众号支付驱动分享
下面分享个ThinkPay的微信支付驱动,便于大家使用,如有疑问加QQ群讨论105108204 // +----------------------------------------------------------------------
// | 零云 [ 简单 高效 卓越 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016 http://www.lingyun.net All rights reserved.
// +----------------------------------------------------------------------
// | Author: jry 
// +----------------------------------------------------------------------
namespace Addons\Pay\ThinkPay\Pay\Driver;

/**
 * 微信支付驱动
 */
class Wxpay extends \Addons\Pay\ThinkPay\Pay\Pay
{
    protected $gateway    = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
    protected $orderquery = 'https://api.mch.weixin.qq.com/pay/orderquery';
    protected $config     = array(
        'appid'     => '',
        'appsecret' => '',
        'mchid'     => '',
        'key'       => '',
    );

    public function check()
    {
        if (!$this->config['appid'] || !$this->config['appsecret'] || !$this->config['mchid'] || !$this->config['key']) {
            E("微信支付设置有误!");
        }
        return true;
    }

    public function buildRequestForm($pay_data)
    {
        // APP支付
        if (C('IS_API')) {
            $param = array(
                'appid'            => $this->config['appid'],
                'mch_id'           => $this->config['mchid'],
                'nonce_str'        => $this->getNonceStr(),
                'body'             => $pay_data['body'],
                'out_trade_no'     => $pay_data['out_trade_no'],
                'total_fee'        => $pay_data['money'] * 100,
                'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
                'notify_url'       => $this->config['notify_url'],
                'trade_type'       => 'APP',
            );

            // 签名
            $param['sign'] = $this->MakeSign($param);
            $xml_param     = $this->ToXml($param);
            $result        = $this->FromXml($this->postXmlCurl($xml_param, $this->gateway));
            if ($result['return_code'] === 'SUCCESS') {
                if ($this->CheckSign($result)) {
                    // 统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。
                    // 参与签名的字段名为appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay
                    $prepayparams              = array();
                    $prepayparams['appid']     = $result['appid'];
                    $prepayparams['partnerid'] = $result['mch_id'];
                    $prepayparams['prepayid']  = $result['prepay_id'];
                    $prepayparams['noncestr']  = $result['nonce_str'];
                    $prepayparams['package']   = 'Sign=WXPay';
                    $prepayparams['timestamp'] = time();
                    $prepayparams['sign']      = $this->MakeSign($prepayparams); // 签名
                    $return['json']            = json_encode($prepayparams);
                    return $return;
                }
            }
        } else {
            // 获取用户openId,微信公众号JSAPI支付必须
            $openId = $this->GetOpenid();
            $param  = array(
                'appid'            => $this->config['appid'],
                'mch_id'           => $this->config['mchid'],
                'nonce_str'        => $this->getNonceStr(),
                'body'             => $pay_data['body'],
                'out_trade_no'     => $pay_data['out_trade_no'],
                'total_fee'        => $pay_data['money'] * 100,
                'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
                'notify_url'       => $this->config['notify_url'],
                'trade_type'       => 'JSAPI',
                'openid'           => $openId,
            );

            // 签名
            $param['sign'] = $this->MakeSign($param);
            $xml_param     = $this->ToXml($param);
            $result        = $this->FromXml($this->postXmlCurl($xml_param, $this->gateway));
            if ($result['return_code'] === 'SUCCESS') {
                if ($this->CheckSign($result)) {
                    // 获取JSAPI所需参数
                    $jsApiParameters = $this->GetJsApiParameters($result);
                    $pay_page        =                          
                            


                                
                                
                                微信支付
                                <script><br /> //调用微信JS api 支付<br /> function jsApiCall()<br /> {<br /> WeixinJSBridge.invoke(<br /> &#039;getBrandWCPayRequest&#039;,<br /> {$jsApiParameters},<br /> function(res){<br /> WeixinJSBridge.log(res.err_msg);<br /> //alert(res.err_code+res.err_desc+res.err_msg);<br /> }<br /> );<br /> }<br /> <br /> function callpay()<br /> {<br /> if (typeof WeixinJSBridge == "undefined"){<br /> if( document.addEventListener ){<br /> document.addEventListener(&#039;WeixinJSBridgeReady&#039;, jsApiCall, false);<br /> }else if (document.attachEvent){<br /> document.attachEvent(&#039;WeixinJSBridgeReady&#039;, jsApiCall);<br /> document.attachEvent(&#039;onWeixinJSBridgeReady&#039;, jsApiCall);<br /> }<br /> }else{<br /> jsApiCall();<br /> }<br /> }<br /> </script>
                            
                            
                                

                                该笔订单支付金额为{$pay_data['money']}


                                

                                    
                                

                            
                            
EOF;
                    return $pay_page;
                }
            } else {
                E("微信订单错误!" . $result['return_msg']);
            }
        }
    }

    /**
     * 异步通知验证
     */
    public function verifyNotify($notify)
    {
        //获取通知的数据
        if ($notify['return_code'] === 'SUCCESS') {
            if (!array_key_exists("transaction_id", $notify)) {
                E("输入参数不正确!");
            }
            $param['transaction_id'] = $notify["transaction_id"];
            $param['appid']          = $this->config['appid'];
            $param['mch_id']         = $this->config['mchid'];
            $param['nonce_str']      = $this->getNonceStr();
            $param['sign']           = $this->MakeSign($param);
            $xml_param               = $this->ToXml($param);
            $result                  = $this->FromXml($this->postXmlCurl($xml_param, $this->orderquery));
            if ($this->CheckSign($result)) {
                $result['status'] = ($result['result_code'] == 'SUCCESS') ? true : false;
                $result['money']  = $result['total_fee'] / 100;
                $this->info       = $result;
                return true;
            }
        } else {
            E('通知错误');
        }
    }

    /**
     *
     * 获取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'] == "") {
            E("参数错误");
        }
        $jsapi['appId']     = $UnifiedOrderResult["appid"];
        $jsapi['timeStamp'] = (string) time();
        $jsapi['nonceStr']  = $this->getNonceStr();
        $jsapi['appId']     = $UnifiedOrderResult["appid"];
        $jsapi['package']   = "prepay_id=" . $UnifiedOrderResult['prepay_id'];
        $jsapi['signType']  = 'MD5';
        $jsapi['paySign']   = $this->MakeSign($jsapi);
        $parameters         = json_encode($jsapi);
        return $parameters;
    }

    /**
     * 以post方式提交xml到对应的接口url
     *
     * @param string $xml  需要post的xml数据
     * @param string $url  url
     * @param bool $useCert 是否需要证书,默认不需要
     * @param int $second   url执行超时时间,默认30s
     * @throws WxPayException
     */
    private static function postXmlCurl($xml, $url, $useCert = false, $second = 30)
    {
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);

        //如果有配置代理这里就设置代理
        // if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0"
        //             && WxPayConfig::CURL_PROXY_PORT != 0){
        //             curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
        //             curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
        //         }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //严格校验
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, false);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        if ($useCert == true) {
            //设置证书
            //使用证书:cert 与 key 分别属于两个.pem文件
            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH);
            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLKEY, WxPayConfig::SSLKEY_PATH);
        }
        //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);
            curl_close($ch);
            E("curl出错,错误码:$error");
        }
    }

    /*
     * 产生随机字符串,不长于32位
     * @param int $length
     * @return 产生的随机字符串
     */
    public static function getNonceStr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str   = "";
        for ($i = 0; $i              $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * 生成签名
     * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
     */
    public function MakeSign($param)
    {
        //签名步骤一:按字典序排序参数
        ksort($param);
        $string = $this->ToUrlParams($param);
        //签名步骤二:在string后加入KEY
        $string = $string . "&key=" . $this->config['key'];
        //签名步骤三:MD5加密
        $string = md5($string);
        //签名步骤四:所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    /**
     *
     * 检测签名
     */
    public function CheckSign($param)
    {
        $sign = $this->MakeSign($param);
        if ($param['sign'] == $sign) {
            return true;
        } else {
            E("签名错误!");
        }
    }

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

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

    /**
     * 输出xml字符
     * @throws WxPayException
     **/
    public function ToXml($param)
    {
        if (!is_array($param)
            || count($param)              E("数组数据异常!");
        }

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

    /**
     * 将xml转为array
     * @param string $xml
     * @throws WxPayException
     */
    public function FromXml($xml)
    {
        if (!$xml) {
            E("xml数据异常!");
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $this->values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $this->values;
    }

    /**
     *
     * 通过跳转获取用户的openid,跳转流程如下:
     * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
     * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
     *
     * @return 用户的openid
     */
    public function GetOpenid()
    {
        //通过code获得openid
        if (!isset($_GET['code'])) {
            //触发微信返回code码
            $baseUrl = urlencode('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
            $url     = $this->__CreateOauthUrlForCode($baseUrl);
            Header("Location: $url");
            exit();
        } else {
            //获取code码,以获取openid
            $code   = $_GET['code'];
            $openid = $this->getOpenidFromMp($code);
            return $openid;
        }
    }

    /**
     *
     * 通过code从工作平台获取openid机器access_token
     * @param string $code 微信跳转回来带上的code
     *
     * @return openid
     */
    public function GetOpenidFromMp($code)
    {
        $url = $this->__CreateOauthUrlForOpenid($code);
        //初始化curl
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0"
        //             && WxPayConfig::CURL_PROXY_PORT != 0){
        //             curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
        //             curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
        //         }
        //运行curl,结果以jason形式返回
        $res = curl_exec($ch);
        curl_close($ch);
        //取出openid
        $data       = json_decode($res, true);
        $this->data = $data;
        $openid     = $data['openid'];
        return $openid;
    }

    /**
     *
     * 构造获取code的url连接
     * @param string $redirectUrl 微信服务器回跳的url,需要url编码
     *
     * @return 返回构造好的url
     */
    private function __CreateOauthUrlForCode($redirectUrl)
    {
        $urlObj["appid"]         = $this->config['appid'];
        $urlObj["redirect_uri"]  = "$redirectUrl";
        $urlObj["response_type"] = "code";
        $urlObj["scope"]         = "snsapi_base";
        $urlObj["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)
    {
        $urlObj["appid"]      = $this->config['appid'];
        $urlObj["secret"]     = $this->config['appsecret'];
        $urlObj["code"]       = $code;
        $urlObj["grant_type"] = "authorization_code";
        $bizString            = $this->ToUrlParams($urlObj);
        return "https://api.weixin.qq.com/sns/oauth2/access_token?" . $bizString;
    }
}

微信app下载
微信app下载

微信是一款手机通信软件,支持通过手机网络发送语音短信、视频、图片和文字。微信可以单聊及群聊,还能根据地理位置找到附近的人,带给大家全新的移动沟通体验,有需要的小伙伴快来保存下载体验吧!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号