微信小程序v3SDK使用-PHP版

关于微信支付的网站

微信支付开发文档 https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml
微信支付开发SDK https://github.com/wechatpay-apiv3/wechatpay-php
微信支付官网 https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F

下载SDK 然后放到项目中 并引用

use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;
// 商户号,假定为`1000100`
$merchantId = '1000100';
// 商户私钥,文件路径假定为 `/path/to/merchant/apiclient_key.pem`
$merchantPrivateKeyFilePath = 'file:///path/to/merchant/apiclient_key.pem';// 注意 `file://` 开头协议不能少
// 加载商户私钥
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
$merchantCertificateSerial = '可以从商户平台直接获取到';// API证书不重置,商户证书序列号就是个常量
// // 也可以使用openssl命令行获取证书序列号
// // openssl x509 -in /path/to/merchant/apiclient_cert.pem -noout -serial | awk -F= '{print $2}'
// // 或者从以下代码也可以直接加载
// // 「商户证书」,文件路径假定为 `/path/to/merchant/apiclient_cert.pem`
// $merchantCertificateFilePath = 'file:///path/to/merchant/apiclient_cert.pem';// 注意 `file://` 开头协议不能少
// // 解析「商户证书」序列号
// $merchantCertificateSerial = PemUtil::parseCertificateSerialNo($merchantCertificateFilePath);
// 「平台证书」,可由下载器 `./bin/CertificateDownloader.php` 生成并假定保存为 `/path/to/wechatpay/cert.pem`
$platformCertificateFilePath = 'file:///path/to/wechatpay/cert.pem';// 注意 `file://` 开头协议不能少
// 加载「平台证书」公钥
$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
// 解析「平台证书」序列号,「平台证书」当前五年一换,缓存后就是个常量
$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
// 工厂方法构造一个实例
$instance = Builder::factory([
    'mchid'      => $merchantId,
    'serial'     => $merchantCertificateSerial,
    'privateKey' => $merchantPrivateKeyInstance,
    'certs'      => [
        $platformCertificateSerial => $platformPublicKeyInstance,
    ],
    // APIv2密钥(32字节)--不使用APIv2可选
    // 'secret' => 'exposed_your_key_here_have_risks',// 值为占位符,如需使用APIv2请替换为实际值
    // 'merchant' => [// --不使用APIv2可选
    //     // 商户证书 文件路径 --不使用APIv2可选
    //     'cert' => $merchantCertificateFilePath,
    //     // 商户API私钥 文件路径 --不使用APIv2可选
    //     'key' => $merchantPrivateKeyFilePath,
    // ],
]);

下面说一下各个参数的由来

appid 和 mch_id(商户号)

登录微信支付官网
在这里插入图片描述
在这里插入图片描述

商户私钥和商户证书

按照教程获取这两个文件 https://kf.qq.com/faq/161222NneAJf161222U7fARv.html

平台证书获取

代码

//获取平台证书
public function aes_util()
{
    //获取平台证书列表
    $url = 'https://api.mch.weixin.qq.com/v3/certificates';
    $method = 'GET';
    $token = $this->sign($url,$method,'');
    $response = $this->curlGet($url,$token);
    //证书和回调报文解密
	$api_v3_key = '';//APIv3秘钥
	$associatedData = '';//平台列表接口返回的 associated_data
	$nonceStr = '';//平台列表接口返回的 nonce
	$ciphertext  = '';//平台列表接口返回的 ciphertext
	$AesUtil= new AesUtil($api_v3_key);
	$back=$AesUtil->decryptToString($associatedData,$nonceStr,$ciphertext);
    $back=$AesUtil->decryptToString($associatedData,$nonceStr,$ciphertext);
}

//获取签名
public function sign($url,$method,$body)
{
    $timestamp = time();
    $url_parts = parse_url($url);
    $nonce = $timestamp.rand('10000','99999');
    $serial_no = '';//API证书序列号
    $merchant_id = '';//商户号
    $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
    $message = $method."\n".
        $canonical_url."\n".
        $timestamp."\n".
        $nonce."\n".
        $body."\n";
    $apiclient_key_path = INDEX_PATH . '\certificate\apiclient_key.pem';//商户私钥文件路径
    $pkeyid = openssl_get_privatekey(file_get_contents($apiclient_key_path));
    openssl_sign($message, $raw_sign, $pkeyid, 'sha256WithRSAEncryption');
    $sign = base64_encode($raw_sign);//签名
    $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
        $merchant_id, $nonce, $timestamp, $serial_no, $sign);
    return $token;
}

function curlGet($url,$token)
{
    //初始化
    $ch = curl_init();
    //设置抓取的url
    curl_setopt($ch, CURLOPT_URL, $url);
    //设置获取的信息以文件流的形式返回,而不是直接输出。
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // https请求 不验证hosts
    //设置header
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    $schema = 'WECHATPAY2-SHA256-RSA2048';
    $header=array(
        'Authorization:' . $schema . ' ' . $token,
        'Accept: application/json',
        'Content-Type: application/json; charset=utf-8',
        'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
    );
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);//模拟头部信息
    //执行命令
    $output = curl_exec($ch);//返回api的json对象
    curl_close($ch); //释放curl句柄
    return json_decode($output,true);
    //1.1、组装请求携带数据(初始化)
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
    $schema = 'WECHATPAY2-SHA256-RSA2048';
    $header = [
        "Content-Type" => "application/json",
        "Accept" => "application/json",
        "User-Agent" => "*/*",
        "Authorization" => $schema . ' ' . $token
    ];
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);//模拟头部信息
    //按需打开
    // $headerArray = array("Content-Type:application/json;charset=utf-8", "Accept:application/json");
    // curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray);
    //1.2、发送请求
    $output = curl_exec($ch);
    //按需打开
    // $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 这一步必须在curl_close()调用之前调用
    //1.3、关闭请求通道
    curl_close($ch);
    //2、解析数据
    //2.1、解决中文乱码。【返回的字符(数据)编码格式可能是:UTF-8、GBK、GB2312、BIG5等,这里统一转换成UTF-8编码格式】
    $output = mb_convert_encoding($output, 'UTF-8', 'UTF-8,GBK,GB2312,BIG5');
    //2.2、将数据转换成数组格式。【PHP最常用的数据结构就是数组,固这里转换成数组】
    $output = json_decode($output, true);
    //3、数据传给调用者
    return $output;
}
讲解一下流程
调用平台证书列表接口

在这里插入图片描述
v3版本请求都需要带个头部信息 主要难点是 签名生成
如果没有带头部信息会报以下错误
在这里插入图片描述

获取签名
//获取签名
public function sign($url,$method,$body)
{
    $timestamp = time();
    $url_parts = parse_url($url);
    $nonce = $timestamp.rand('10000','99999');
    $serial_no = '';//API证书序列号
    $merchant_id = '';//商户号
    $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
    $message = $method."\n".
        $canonical_url."\n".
        $timestamp."\n".
        $nonce."\n".
        $body."\n";
    $apiclient_key_path = '';//商户私钥文件路径
    $pkeyid = openssl_get_privatekey(file_get_contents($apiclient_key_path));
    openssl_sign($message, $raw_sign, $pkeyid, 'sha256WithRSAEncryption');
    $sign = base64_encode($raw_sign);//签名
    $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
        $merchant_id, $nonce, $timestamp, $serial_no, $sign);
    return $token;
}

API证书序列号
在这里插入图片描述

证书解密

通过调取平台证书列表接口 返回的数据还得经过解密才是我们想要的数据
在这里插入图片描述

<?php

class AesUtil
{
    /**
     * AES key
     *
     * @var string
     */
    private $aesKey;
    const KEY_LENGTH_BYTE = 32;
    const AUTH_TAG_LENGTH_BYTE = 16;
    /**
     * Constructor
     */
    public function __construct($aesKey)
    {
        if (strlen($aesKey) != self::KEY_LENGTH_BYTE) {
            throw new InvalidArgumentException('无效的ApiV3Key,长度应为32个字节');
        }
        $this->aesKey = $aesKey;
    }
    /**
     * Decrypt AEAD_AES_256_GCM ciphertext
     *
     * @param string    $associatedData     AES GCM additional authentication data
     * @param string    $nonceStr           AES GCM nonce
     * @param string    $ciphertext         AES GCM cipher text
     *
     * @return string|bool      Decrypted string on success or FALSE on failure
     */
    public function decryptToString($associatedData, $nonceStr, $ciphertext)
    {
        $ciphertext = \base64_decode($ciphertext);
        if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
            return false;
        }
        // ext-sodium (default installed on >= PHP 7.2)
        if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') &&
            \sodium_crypto_aead_aes256gcm_is_available()) {
            return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
        }
        // ext-libsodium (need install libsodium-php 1.x via pecl)
        if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') &&
            \Sodium\crypto_aead_aes256gcm_is_available()) {
            return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
        }
        // openssl (PHP >= 7.1 support AEAD)
        if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
            $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
            $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);
            return \openssl_decrypt($ctext, 'aes-256-gcm', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr,
                $authTag, $associatedData);
        }
        throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
    }
}

引用之后调用

$api_v3_key = '';//APIv3秘钥
$associatedData = '';//平台列表接口返回的 associated_data
$nonceStr = '';//平台列表接口返回的 nonce
$ciphertext  = '';//平台列表接口返回的 ciphertext
$AesUtil= new AesUtil($api_v3_key);
$back=$AesUtil->decryptToString($associatedData,$nonceStr,$ciphertext);

APIv3秘钥

在这里插入图片描述
调取成功之后 返回类似下面的数据
在这里插入图片描述
把上面的返回的 复制 然后创建一个 .pem 文件 复制进去

平台证书列表 下面有个主意事项
在这里插入图片描述
可以写个定时任务 把返回的数据写入文件里

调用微信小程序下单

try {
    $resp = $instance
    ->v3->pay->transactions->native
    ->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;
}

[调用微信小程序支付](https://github.com/wechatpay-apiv3/wechatpay-php

use WeChatPay\Formatter;
use WeChatPay\Crypto\Rsa;

$merchantPrivateKeyFilePath = 'file:///path/to/merchant/apiclient_key.pem';
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath);

$params = [
    'appId'     => 'wx8888888888888888',
    'timeStamp' => (string)Formatter::timestamp(),
    'nonceStr'  => Formatter::nonce(),
    'package'   => 'prepay_id=',//微信小程序下单返回的prepay_id 主意格式
];
$params += ['paySign' => Rsa::sign(
    Formatter::joinedByLineFeed(...array_values($params)),
    $merchantPrivateKeyInstance
), 'signType' => 'RSA'];

echo json_encode($params);

调用支付接口返回的数据 返回给前端

前端调用wx.requestPayment发起微信支付

其他的接口调用方式都一样的 按照git教程来

注:如果不想用SDK的 调用各个接口的时候 记得带上头部信息 和 请求平台证书列表一样的做法 只是 传参 不同

### 回答1: 微信小程序支付api-v3微信提供的一种支付方式,它基于RESTful风格的API设计,使用HTTP协议传输数据,全部使用JSON格式,具有优秀的跨平台性能和安全性。本文将为大家提供微信小程序支付api-v3 php的完整代码。 微信小程序支付api-v3 php完整代码: 首先,需要获取商户的API密钥和证书文件,然后设置请求头信息,代码如下: $merchant_api_secret = 'Your Secret Key'; //商户API密钥 $merchant_cert_file = 'path/to/cert.pem'; //商户证书文件路径 $merchant_key_file = 'path/to/key.pem'; //商户密钥文件路径 $timestamp = time(); $nonce_str = uniqid(); $signature = generate_signature($merchant_api_secret, $timestamp, $nonce_str, $http_method, $http_uri, $query_string, $body); $header = array( 'Authorization: ' . $authorization, 'Accept: application/json', 'Content-Type: application/json', 'User-Agent: your-device', 'Wechatpay-Serial: your-certificate-serial-number', 'Wechatpay-Timestamp: ' . $timestamp, 'Wechatpay-Nonce: ' . $nonce_str, 'Wechatpay-Signature: ' . $signature, ); 然后,我们需要调用微信小程序支付api-v3接口,具体如下: $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $api_url); curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM'); curl_setopt($ch, CURLOPT_SSLCERT, $merchant_cert_file); curl_setopt($ch, CURLOPT_SSLKEY, $merchant_key_file); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $http_method); if (!empty($body)){ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body)); } $response = curl_exec($ch); $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($status_code !== 200){ throw new Exception('微信小程序支付api-v3调用错误,错误代码' . $status_code); } $response_payload = json_decode($response, true); curl_close($ch); 以上就是微信小程序支付api-v3 php的完整代码,通过以上代码可以实现微信小程序支付api-v3的接口调用,实现支付等操作。同时需要注意的是,具体代码需要根据自己的实际情况进行调整。 ### 回答2: 微信小程序支付API-v3是一套用于支付的接口,支持PHP语言,这里提供完整的代码实现。 在使用微信小程序支付API-v3前需要进行身份验证,将私钥转换为PKCS8格式和获取API证书,并将两者合成一个PEM格式的文件。接下来就可以创建支付订单并进行支付了。 以下是PHP代码的示例: ```php <?php require_once "wxpayloader.php"; $wxpayConfig = new WxPayConfig(); // 公众号ID $wxpayConfig->setAppId("your app id"); // 商户号 $wxpayConfig->setMchId("your mch id"); // 商户API秘钥 $wxpayConfig->setApiKey("your api key"); // 商户API证书路径 $wxpayConfig->setSslCertPath("path/to/your/apiclient_cert.pem"); // 商户API证书密钥路径 $wxpayConfig->setSslKeyPath("path/to/your/apiclient_key.pem"); // 微信支付平台API证书路径 $wxpayConfig->setSslRootCaPath("path/to/your/rootca.pem"); // 接口请求地址 $wxpayConfig->setApiUrl("https://api.mch.weixin.qq.com/"); // 验证商户API证书 $result = WxPayApi::sslVerify($wxpayConfig); if($result['result'] != 0) { die("SSL证书验证失败:" . $result['errmsg']); } // 创建订单 $out_trade_no = "20170525" . rand(10000, 99999); $total_fee = 1; $trade_type = "JSAPI"; // 交易类型为小程序支付 $notify_url = "http://your.domain.com/weixin/paynotify.php"; // 支付结果通知URL $wxpayData = new WxPayData(); $wxpayData->setBody("test"); $wxpayData->setOutTradeNo($out_trade_no); $wxpayData->setTotalFee($total_fee); $wxpayData->setTradeType($trade_type); $wxpayData->setNotifyUrl($notify_url); $wxpayData->setOpenid("your openid"); // 用户的openid,小程序通过wx.login获取 // 统一下单 $result = WxPayApi::unifiedOrder($wxpayConfig, $wxpayData); if($result['return_code'] != 'SUCCESS' || $result['result_code'] != 'SUCCESS') { die("统一下单失败:" . $result['err_code_des']); } // 获取微信小程序支付参数 $prepay_id = $result["prepay_id"]; $wxpayData = new WxPayData(); $wxpayData->setAppId($wxpayConfig->getAppId()); $wxpayData->setTimeStamp(time()); $wxpayData->setNonceStr(WxPayApi::generateNonceStr()); $wxpayData->setPackage("prepay_id=" . $prepay_id); $wxpayData->setSignType("RSA"); // 生成签名 $sign = WxPayApi::generateSignature($wxpayData, $wxpayConfig); // 将签名加到数据包中 $wxpayData->setPaySign($sign); // 返回小程序支付参数 echo json_encode($wxpayData->getValues()); ``` 以上代码首先创建了WxPayConfig对象,将商户号、API密钥、API证书路径等信息设置进去。然后创建订单数据包,通过WxPayApi::unifiedOrder方法提交到微信支付平台统一下单。如果成功,则获取预支付ID,按照微信小程序支付的规定生成签名,再将签名加到数据包中,最终返回给小程序,由小程序前端发起支付请求。 获取API证书和PKCS8格式私钥的方法,请参考微信支付平台官方文档。 ### 回答3: 微信小程序支付 API-v3 提供了一种安全、高效、简便的支付方式,帮助开发者更好地满足用户需求。以下是微信小程序支付 API-v3 PHP 完整代码。 首先,要使用微信小程序支付 API-v3,需要先在微信支付商户平台上注册并开通服务。 接下来,下载 PHP SDK 安装包,将下载得到的文件解压后,将文件夹内的文件复制到项目代码所在的目录中。 在代码中导入 SDK 中的类库: ```php require_once "lib/WxPay.Api.php"; require_once "lib/WxPay.Data.php"; ``` 接着,需要通过商户号和 API 密钥进行身份验证: ```php $config = new WxPayConfig(); $config->SetMerchantId("商户号"); $config->SetKey("API密钥"); ``` 然后,实例化一个统一下单对象,并设置相关支付参数: ```php $input = new WxPayUnifiedOrder(); $input->SetBody("商品描述"); // 商品描述 $input->SetAttach("附加数据"); // 附加数据 $input->SetOut_trade_no("商户订单号"); // 商户订单号 $input->SetNotify_url("回调URL"); // 回调URL $input->SetTotal_fee("总金额"); // 总金额(单位:分) $input->SetTrade_type("JSAPI"); // 交易类型 $input->SetOpenid("用户openid"); // 用户openid ``` 接着,调用统一下单 API 并获取支付参数: ```php $order = WxPayApi::unifiedOrder($config, $input); $prepayId = $order["prepay_id"]; $nonceStr = WxPayApi::getNonceStr(); $timeStamp = time(); $package = "prepay_id=" . $prepayId; $signType = "HMAC-SHA256"; $paySign = WxPayApi::getPaySign($config, $nonceStr, $package, $signType, $timeStamp); ``` 最后,在前端页面中使用获取到的支付参数调起微信支付即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值