您好,欢迎来到惠州网站建设_网页设计制作公司_高端网站建设_模板建站_欣欣仿站



模板搜索:搜索
热门搜索: ALL房产金融汽车室内设计

微信支付v3的jsapi接口接入thinkphp6完整流程 2023-06-29 14:39:50

当前位置: >首页>新闻列表>微信支付v3的jsapi接口接入thinkphp6完整流程

相信,写过微信支付接口的程序员,都会骂一句,什么垃圾文档。惠州网站建设今天给个完整的解决案例。哎,绕来绕去,把你绕坑里。我也是不知道掉了多少坑才写出这个避坑文档。目的是想让自己记住thinkphp6在接入微信支付v3时候jsapi的时候,不要在掉一次坑。因为,官网文档的说明内容真的让人无语。都严重怀疑,他不想让人成功接入他们支付一样。

        下面说下我们怎么掉坑和出坑的。

        1,打开 https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_1.shtml  阅读里面的相关设置信息,配置好你的商户号i信息那些。这个配置就不多说了,根据流程操作就好了。

        2,有了相关信息之后,一般,我们这里要求,A要有证书文件,这里文件有三个,可以看下截图。

            (图1)

        这三个文件中,我们这里测试和使用的时候,目前就只用到 apiclient_key.pem,其他文件,我这里暂时没用到,可能技术不够吧。但是目前我就只用到这个文件,其他三个文件是放在一起的。放到你的站点中。这个路径要你的程序能访问到。

        B,获取微信商户ID,公众号的ID,公众号的密钥,微信支付api v3的密钥。

        C,平台证书,这个也是巨坑之一,不认证看文档,你都不知道要用来干啥。


        3,开发之前,我们先疏通下微信支付的流程。

        先上官方的流程图。

        (图2)


        你晕不晕,我不清楚,反正我是挺晕的。说了半天,没告诉你,什么时候要用上面提到的哪个文件。用哪个接口去申请流程。

        这个时候,我们想到的是他们提供的接口。好家伙,不提还好。一提,把几火。

        先看他们的demo吧。下面是demo下载地址。

        https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay6_0.shtml

        (图3)

        我们是php的,所以选择这个 wechatpay-php就可以了,后面的哪个东西,你不要管。wechatpay-guzzle-middleware这个不知道是哪个专家非得跟他放一起,还不写清楚是干啥的。其实这wechatpay-guzzle-middleware就是一个将php扩展。用来做网页请求的。这里,你就把他当成html里面的ajax这样的东西就好了。放在一起,只能让人掉坑里。

        然后,我们看看代码。继续掉坑。后面,我们在整理出自己的流程图和使用哪个接口。

        下载demo的时候,他提供composer的方法,我们就用这个方法。其他方法,可能会缺少依赖。

       (图4)

        

    composer require wechatpay/wechatpay


        这个时候,https://github.com/wechatpay-apiv3/wechatpay-php  ,我们要从这个文档里面拿到的代码,基本就是可以用的。其他百度回来的代码,就各种问题。不过这里的代码不是直接用的,要各种修改。这里拿最原本的代码来说吧。直接上代码。



        首先,我们新建一个叫 wxPay.php的文件,然后,第一段代码加入进去。我们上代码吧。

        (图5)

        因为我们当初是放在index这个文件下面的,所以就没改成wxPay了,将就着用吧。然后下面将他们的代码加入进来。

        

public function wxpay(){
    // 商户号
    $merchantId = '190000****';

    // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
    $merchantPrivateKeyFilePath = 'file:///path/to/merchant/apiclient_key.pem';
    $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

    // 「商户API证书」的「证书序列号」
    $merchantCertificateSerial = '3775B6A45ACD588826D15E583A95F5DD********';

    // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
    $platformCertificateFilePath = 'file:///path/to/wechatpay/cert.pem';
    $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

    // 从「微信支付平台证书」中获取「证书序列号」
    $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);

    // 构造一个 APIv3 客户端实例
    $instance = Builder::factory([
        'mchid'      => $merchantId,
        'serial'     => $merchantCertificateSerial,
        'privateKey' => $merchantPrivateKeyInstance,
        'certs'      => [
            $platformCertificateSerial => $platformPublicKeyInstance,
        ],
    ]);

    // 发送请求
    $resp = $instance->chain('v3/certificates')->get(
        ['debug' => true] // 调试模式,https://docs.guzzlephp.org/en/stable/request-options.html#debug
    );
    echo $resp->getBody(), PHP_EOL;
}


        用这个作为 第一个输入的地方,因为 ['debug' => true] ,所以,有错误的话是可以直接显示出来的。

        上面的参数按照提示补充进去就可以了。

        这里有个坑,上面的两个证书,直接用我们的下载到的商户证书就可以了,不要用平台证书。

        还有个就是 file:///这个地方是3个/,为什么呢?file://算是php的读取格式吧,跟ftp://一个道理。然后,第三个/ 是文件路径。

        

然后,根据他们的文档,下面的是native的支付,其实,是什么支付,主要就是看传什么参数,这里,我们调整下,改成jsapi。

        

try {
    $resp = $instance
    ->chain('v3/pay/transactions/jsapi')
    ->post(['json' => [
        'mchid'        => '1900006XXX',
        'out_trade_no' => 'native12177525012014070332333',
        'appid'        => 'wxdace645e0bc2cXXX',
        'description'  => 'Image形象店-深圳腾大-QQ公仔',
        'notify_url'   => 'https://weixin.qq.com/',
        'amount'       => [
            'total'    => 1,
            'currency' => 'CNY'
        ],
    ]]);

    echo$resp->getStatusCode(), PHP_EOL;
    echo$resp->getBody(), PHP_EOL;
} catch (\Exception$e) {
    // 进行错误处理
    echo$e->getMessage(), PHP_EOL;
    if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
        $r = $e->getResponse();
        echo$r->getStatusCode() .' '.$r->getReasonPhrase(), PHP_EOL;
        echo$r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
    }
    echo$e->getTraceAsString(), PHP_EOL;
}

        到这里,我们就可以获得$resp,这个东西有什么用呢?这个东西就是下面用来给微信支付接口发送数据的东东,这里暂时叫他一个实例后的对象。然后,我们继续往下看。

        到这里,我们的预支付就完成了,返回的$resp->getBody()里面就带有prepay_id,这个参数就是唤醒微信支付的参数。好了,到这里,哪个官方的说明文档又开始犯二了。到这里,他就不告诉你下面要怎么办。如果你以前有过微信开发经验的话,可能知道要怎么办。但是,像我这种刚接触微信支付的新手来说,就懵懵懂懂了。不知道怎么搞了。

        这个时候,我们回去看文档。https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml,这个地方,有一个叫唤醒jsapi支付的。好吧,我们接着弄。那具体怎么弄呢?

        文档,我们就不说了,大家自己看吧,这里,我们拿出这个代码来给大家展示下。

        

function onBridgeReady() {
        WeixinJSBridge.invoke('getBrandWCPayRequest', {
            "appId": "wx2421b1c4370ec43b",     //公众号ID,由商户传入    
            "timeStamp": "1395712654",     //时间戳,自1970年以来的秒数    
            "nonceStr": "e61463f8efa94090b1f366cccfbbb444",      //随机串    
            "package": "prepay_id=up_wx21201855730335ac86f8c43d1889123400",
            "signType": "RSA",     //微信签名方式:    
            "paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg=="//微信签名
        },
        function(res) {
            if (res.err_msg =="get_brand_wcpay_request:ok") {
                // 使用以上方式判断前端返回,微信团队郑重提示:
                //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
            }
        });
    }
    if (typeof WeixinJSBridge=="undefined") {
        if (document.addEventListener) {
            document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
        } elseif (document.attachEvent) {
            document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
            document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
        }
    } else {
        onBridgeReady();
    }

        是不是有点蒙,刚开的时候,我还以为是个php函数,后来在微信支付文档里面看到说WeixinJSBridge 是微信内置浏览器的对象,其他浏览器没有。所以嘛,简单来说,这个就是客户端的东西。既然是js调用的,我们就在获得预支付结果的pid哪里,将这个唤醒微信支付的js输出到微信就好了。好了,到这里,神奇的事情发生了。微信支付,成功唤醒了。

        到这里,是不是很觉得云里雾里呢?是的,没看到代码之前,都是蒙的。文档的最后,我们会把完整的tp6写的微信支付v3的代码,显示出来。

        到这里,微信支付v3的tp6开发,支付部分就完成了。但是回调还没写。回调又是怎么样的呢?

        先留个悬念。我们这里先解决下微信支付思路的问题。

        

        目前我们这里之说,jsapi的微信支付问题。其他的可能参数不同,流程可能有些差异。

        A,使用微信登录获得openid,这个一般微信登录的时候,都会有返回,这个是用来验证微信登录是否成功的重要参数,也是微信支付的时候,判断是哪个账号支付的。

        B,使用商户号,商户证书,openid这写参数,生成$resp对象,这个就是一个用php来模拟浏览器访问微信接口的东西,返回出来的一个对象。这个对象可以用来预支付。

        C,预支付之后,我们要用预支付返回的prepay_id,和商户证书,和其他参数生成一个签名,这个签名成功之后,我们在调用WeixinJSBridge这个,唤醒微信支付。

        好吧,这个就是微信支付从下单到唤醒的流程。

        下面,我们给出这个部分的代码。

         获得openid的代码


<?php
    $url="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx5f7e1393xxxxxx&redirect_uri=http%3A%2F%2Fwww.xxxx.cn%2Fapi.php%2Fajax%2Fhuidiaourl&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
    header("Location:".$url);

    //这里的重点是  回调的url    redirect_uri=http%3A%2F%2Fwww.xxxx.cn%2Fapi.php%2Fajax%2Fhuidiaourl

    function huidiaourl(){
        $post=Request::param();
       // dump($post);
        if(is_array($post)){
            $url2="https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx5f7e1393932628df&secret=821bf3340ad1eace4c585b6cb5e754a5&code=".$post["code"]."&grant_type=authorization_code";
            $str=get_urls($url2);
            $arr=json_decode($str,true);
           
            $arr['openid'];   //这个$arr数组就含有openid,需要的时候,大家可以自己打印出来看看
        }
    }
?>

        获得openid之后,下面给出完整的调用代码。

        

<?php
publicfunctionwxpay(){
    $configdb=Db::name("config");
    $configdata=$configdb->where("name in ('web_keywords','web_name','web_logo','ico_log','web_basehost','web_description','web_attr_15','web_attr_16','web_attr_17','web_attr_18','web_attr_19','web_attr_20','web_attr_21')")->order("id desc")->column('*','id');
    $data_users=Db::name("users")->where("open_id",Session::get("wxcode"))->find();
     $post=Request::post();//接收本站提交的参数
     $get=Request::get();//接收微信回调过来的信息
    $yicun=false;

    $openid=Session::get("openid");
    if(!$openid){
        echo"openid错误...";
        exit();
    }
    $payorder=Db::name("payorder")->where([["openid","=",$openid],["paystatus","=",0]])->order("id desc")->find();
    if($payorder){
        if(time()-$payorder['addtime']<=60 ){
            $out_trade_no=$payorder["out_trade_no"];
            $yicun=true;
        }else{
            $out_trade_no='dahonghu'.time().rand(1000,9999);
        }
    }else{
        $out_trade_no='dahonghu'.time().rand(1000,9999);
    }
    // 设置参数
   
    // 商户号
    $merchantId = '16422XXXXX';    
    // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
    $merchantPrivateKeyFilePath = 'file:///apiclient_key.pem';
    $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);    
    // 「商户API证书」的「证书序列号」
    $merchantCertificateSerial = '48185fb88454XXXXXXXXXXXXXX';    
    // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
    $platformCertificateFilePath = 'file:///wechatpay.pem';
    $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);    
    // 从「微信支付平台证书」中获取「证书序列号」
    $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
   
    // 构造一个 APIv3 客户端实例
    $instance = Builder::factory([
        'mchid'      => $merchantId,
        'serial'     => $merchantCertificateSerial,
        'privateKey' => $merchantPrivateKeyInstance,
        'certs'      => [
            $platformCertificateSerial => $platformPublicKeyInstance,
        ],
    ]);    
    // 发送请求
    $resp = $instance->chain('v3/certificates')->get(
        ['debug' => false] // 调试模式,https://docs.guzzlephp.org/en/stable/request-options.html#debug
    );
   
    try {    
        $zhenjia=intval(round($post["tprice"]*100));    
        $resp = $instance
        ->chain('v3/pay/transactions/jsapi')
        ->post(['json' => [
            'mchid'        => '1642XXXXXXX',
            'out_trade_no' => $out_trade_no,
            'appid'        => 'wx5f7XXXXXX',
            'description'  => 'vip年卡',
            'notify_url'   => 'http://www.dahXXXXX.cn/index/wx3_notify',
            'amount'       => [
                'total'    => $zhenjia,
                'currency' => 'CNY'
            ],
            'payer'        =>[
                "openid"=>$openid
                 ]
        ]]);
       
        $inarr=[
                "out_trade_no"=>$out_trade_no,
                "description"=>'vip年卡',
                "openid"=>$openid,
                "addtime"=>time(),
                "days"=>365,
                "jine"=>floatval($zhenjia/100),
                "paytype"=>"wxpay"
            ];
        if($yicun){
            $input_payorder=Db::name("payorder")->where("out_trade_no",$out_trade_no)->save($inarr);
        }else{
            $input_payorder=Db::name("payorder")->save($inarr);  
        }    
        $prepay_id_arr=json_decode($resp->getBody(),true);
        $prepay_id="prepay_id=".$prepay_id_arr["prepay_id"];
        $sn=self::signname($prepay_id);
        $sn_obj=json_decode($sn);
        echo'
             ';
    } catch (\Exception$e) {
        // 进行错误处理
        echo$e->getMessage(), PHP_EOL;
        if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
            $r = $e->getResponse();
            echo$r->getStatusCode() .' '.$r->getReasonPhrase(), PHP_EOL;
            echo$r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
        }
        echo$e->getTraceAsString(), PHP_EOL;
    }
}

           这里还要给一个加密的函数。

        

publicfunctionsignname($package){
        $merchantPrivateKeyFilePath = 'file:///zs/apiclient_key.pem';
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath);
        $params = [
            'appId'     => 'wx5f7e13xxxxxx',
            'timeStamp' => (string)Formatter::timestamp(),
            'nonceStr'  => Formatter::nonce(),
            'package'   => $package,
        ];
        $params += ['paySign' => Rsa::sign(
            Formatter::joinedByLineFeed(...array_values($params)),
            $merchantPrivateKeyInstance
        ), 'signType' => 'RSA'];
        returnjson_encode($params);
    }

            到这里,微信从下单到预支付到拉起微信支付都完成了。

        以上案例由惠州网站建设原创发布,如需要使用相关代码,请备注来源。


点击次数:127  更新时间:2023-06-29  【打印此页
下一条:微信支付v3的jsapi接口接入thinkphp6完整流程--回调部分
上一条:惠州网页设计,怎么做一个自己的验证码呢?
返回产品列表

扫一扫,添加微信

双十一活动季

1:签到7天,即可下载模板

2:开放包月,包年终身会员

3:包月会员,低至10元每月

4:包年会员,低至100元每年

5:终身会员,低至300元永久