IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> 微信H5支付&实战踩坑 -> 正文阅读

[PHP知识库]微信H5支付&实战踩坑

准备

需求

需求就是最简单的对接微信H5支付接口

方案心路历程

  1. 之前直接用http对接过,不过这次想用官方提供的SDK
  2. 一方面SDK提供的接口比较完整,二方面感觉应该使用别人辛苦写下来的封装
  3. 百度了一下官方文档

注:上述的上个文档下面姑且成为D1 D2 D3

实操

微信商户平台配置

注:这里是后面回忆编写,可能有点出入,后续有再进行实操时再截图回来进行完善
一下会获取几个关键信息 标注为kn

获取基本配置

登录微信商户平台—进入后台—我忘了[狗头]
k1 mchId 商户id
k2 appid 商户appid

API证书

进入后台—点击账户中心—API安全—API证书管理—申请证书—按照指示操作
k3 API证书序列号
k4 API证书KEY 文件名是apiclient_key.pem,其他文件在v3接口中暂时没有使用到
拿到的证书中有一个文件为apiclient_cert.pem 注意这个是API证书,并不是下面使用到的平台证书

v3key

API安全—申请v3key—申请证书
k5 v3key

编码

这里我们使用的是laravel框架为例
接口是H5支付,使用的是v3接口对接

查看 D2
引入SDK

composer require wechatpay/wechatpay

微信商户服务类-引入SDK

<?php
namespace App\Services\Support\Wechat;
use App\Utils\Common\HttpC;
use Illuminate\Support\Facades\Log;
use WeChatPay\Builder;
use WeChatPay\Util\PemUtil;
class Mch
{
    private $merchantId = '';
    private $instance = null;
    public function baseUrl()
    {
        return config('wechat.mch.base_url');
    }
   	// 在构造函数中构造好SDK的工厂实例,待使用
    public function __construct()
    {
        // 商户号,假定为`1000100`
        $this->merchantId = config('wechat.mch.id');
        // 商户私钥,文件路径假定为 `/path/to/merchant/apiclient_key.pem`
        $merchantPrivateKeyFilePath = config('wechat.mch.ssl_key');
        // 加载商户私钥
        $merchantPrivateKeyInstance = PemUtil::loadPrivateKey($merchantPrivateKeyFilePath);
        $merchantCertificateSerial = config('wechat.mch.serial'); // API证书不重置,商户证书序列号就是个常量
        // 平台证书,可由下载器 `./bin/CertificateDownloader.php` 生成并假定保存为 `/path/to/wechatpay/cert.pem`
        $platformCertificateFilePath = config('wechat.mch.wechatpay_cert');
        // 加载平台证书
        $platformCertificateInstance = PemUtil::loadCertificate($platformCertificateFilePath);
        // 解析平台证书序列号
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateInstance);
        // 工厂方法构造一个实例
        $this->instance = Builder::factory([
            'mchid'      => $this->merchantId,
            'serial'     => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs'      => [
                $platformCertificateSerial => $platformCertificateInstance,
            ],
        ]);
    }
    /**
     * 支付下单
     * 以下只以H5支付为例,后续加入其他支付类型可优化为工厂或策略模式
     * @param  string  out_trade_no 订单id
     * @param  string  description  详情
     * @param  string  notify_url   异步回调api
     * @param  integer amount       支付金额
     * @param  string  ip           支付用户ip
     * @return boolean
     */
    public function pay($data)
    {
        try {
            $resp = $this->instance
                ->v3->pay->transactions->h5
                ->post(['json' => [
                    'mchid'        => $this->merchantId,
                    'out_trade_no' => $data['out_trade_no'],
                    'appid'        => config('wechat.mch.appid'),
                    'description'  => $data['description'],
                    'notify_url'   => $data['notify_url'],
                    'amount'       => [
                        'total'    => $data['amount'], // 订单总金额,单位为分
                        'currency' => 'CNY'
                    ],
                    'scene_info'   => [
                        "payer_client_ip" => $data['ip'],
                        "h5_info" => [
                            "type" => $data['h5_type'] ?? "Wap"
                        ]
                    ]
                ]]);
            $code = $resp->getStatusCode();
            $message = $resp->getReasonPhrase();
            $body = $resp->getBody();
            Log::info(sprintf("Wechat/Mch->pay statusCode: %s, reasonPhrase: %s, body: %s", $code, $message, $body));
            $res = [
                'code' => $code,
                'data' => json_decode($body, true) ?? [],
                'message' => $message
            ];
        } catch (\Exception $e) {
            // 进行错误处理
            Log::error("Fail to Wechat/Mch->pay: " . $e->getMessage() . "\n");
            $code = 500;
            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                $r = $e->getResponse();
                Log::error("" . $r->getStatusCode() . ' ' . $r->getReasonPhrase() . "\n");
                Log::error("" . $r->getBody()->getContents() . "\n\n\n");
                $code = $r->getStatusCode();
            }
            Log::error("getTraceAsString: " . $e->getTraceAsString() . "\n");
            $res = [
                'code' => $code,
                'data' => json_decode($body, true) ?? [],
                'message' => $e->getMessage() ?? '请稍后重试'
            ];
        }
        return $res;
        // 返回结果 {"code": 200, "data": {"h5_url": "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=xxx&package=xxx"}, "message": "OK"}
    }
}

引用封装后的支付方法

use Mch;

$mch= new Mch();
$options = [
    'out_trade_no' => $data['order_id'],
    "description" => $data['subject'],
    "amount" => $data['amount'],
    'return_url' => config('ali.alipay.returnUrl'),
    'notify_url' => config('ali.alipay.notifyUrl') . $data['pay_type'],
    'ip' => config('ali.alipay.quitUrl'),
];
$res = $mch->pay($options);

前端使用-微信的H5支付前端对接起来比较方便-拿到后端返回的h5_url之后直接跳转即可
后端异步处理-可参考另一篇支付宝手机网站支付&实战踩坑

踩坑

SDK文档

平台证书,可由下载器 ./bin/CertificateDownloader.php 生成并假定保存为 /path/to/wechatpay/cert.pem 这句话特别关键
这里的平台证书API证书是两个不同的证书,以上的下载器与API证书的下载器也是两个不同的下载器
平台证书需要通过SDK中的./bin/CertificateDownloader.php使用命令行生成

查看 D3
生成命令-这里我们是使用composer安装的软件包,可以通过如下命令下载

vendor/bin/CertificateDownloader.php -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath}
  1. ${mchId} = k1
  2. ${apiV3key} = k5
  3. ${mchPrivateKeyFilePath} = k4
  4. ${mchSerialNo} = k3
  5. ${outputFilePath} 生成后的平台证书的所在目录,不需要带文件名
  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-08-13 11:42:08  更:2021-08-13 11:43:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/12 23:24:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码