微信支付v3接口h5支付(非微信内网页支付)代码步骤,可直接用

第一部分  拉起支付

第一步:

按官方文档先:

composer require wechatpay/wechatpay

下载wechatpay包

第二步,然后在代码中引入:

require_once ROOT_PATH.'/vendor/autoload.php';

use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;

ROOT_PATH 为根路径,可自行处理

/**
* order=订单详情
* appid=公众号appid、需与微信商户号绑定
* mch_id 商户号
* 
*/

function create_pay_order_wechatH5($order, $appid, $mch_id) {

    // 商户号
    $merchantId = $mch_id;

// 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名,'file://'一定要写
    $merchantPrivateKeyFilePath = 'file://'.ROOT_PATH.'/app/pay/wechatapp/cert/1625662730/apiclient_key.pem';
    $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

// 「商户API证书」的「证书序列号」可以在微信支付商户号后台获取
    $merchantCertificateSerial = '41CD2B0A5814D14A07C7E4CFDD4C653******';

// 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名,'file://'一定要写,首次获取平台证书需要用执行命令获取:
//命令如下:vendor/bin/CertificateDownloader.php -k ${32位密码} -m ${商户号} -f ${商户API私钥} -s ${商户API证书的证书序列号} -o ${获取平台证书后的保存路径}

    $platformCertificateFilePath = 'file://'.ROOT_PATH.'/app/pay/wechatapp/wechatpay_603C2803A9A56774EDA68F4BB8F77ECA2*****.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,
        ],
    ]);

// 构造一个 APIv3 客户端实例
    try {
        $resp = $instance
            ->v3->pay->transactions->h5
            ->post(['json' => [
                'mchid'        => $merchantId,
                'out_trade_no' => $order["order_id"],
                'appid'        => $appid,
                'description'  => '端口标题',
                'notify_url'   => HOST."/app/pay/wechatapp/callback_wechatapp2.php",
                'amount'       => [
                    'total'    => intval($order["price"] * 100),
                    'currency' => 'CNY'
                ],
                "scene_info" => ['payer_client_ip'=>Fun::getClientIp(),'h5_info'=>['type'=>'Wap']],
            ]]);

        // echo $resp->getStatusCode(), PHP_EOL;
        // echo $resp->getBody(), PHP_EOL;
        $body = $resp->getBody();
        $body = json_decode($body, true);
    } catch (\Exception $e) {
        // 进行错误处理
        // Tool::log(LOG_PATH."pay.txt",$e,"微信h5-直连");
        // echo $e->getMessage(), PHP_EOL;
        if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
            Tool::log(LOG_PATH."pay.txt",$e->getMessage(),"微信h5-直连");
            // $r = $e->getResponse();
            // echo $r->getStatusCode() . ' ' . $r->getReasonPhrase(), PHP_EOL;
            // echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
        }

    }
    if(isset($body['h5_url'])){
        $url = $body['h5_url'];
        return $url;
    }

}

注意:

一、'file://'不要忘记写了,

 二、api证书和平台证书不要搞混了。

第三步

测试能否拉起支付。如果app打h5支付链接,可能会报参数格式错误的提示,需要让客户端设置一下referer。

相关错误问题可查阅:开发指引-H5支付 | 微信支付商户平台文档中心

第二部分  支付回调通知

相对来说更简单了,我直接贴代码:

require_once "../../../configs/config.inc.php";
require_once ROOT_PATH."configs/init.inc.php";

require_once ROOT_PATH.'/vendor/autoload.php';

use WeChatPay\Crypto\AesGcm;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
/**
 * 微信支付回调
 * @param $input 获取的body数据
 * @param $header 获取的请求头数据
 * @return bool
 */
function notify($input,$header)
{
    Tool::log(LOG_PATH."pay.txt", 1,"微信支付回调");
    $inWechatpaySignature = $header['wechatpay-signature'];// 请根据实际情况获取
    $inWechatpayTimestamp = $header['wechatpay-timestamp'];// 请根据实际情况获取
    $inWechatpaySerial = $header['wechatpay-serial'];// 请根据实际情况获取
    $inWechatpayNonce = $header['wechatpay-nonce'];// 请根据实际情况获取
    $inBody = $input;// 请根据实际情况获取,例如: file_get_contents('php://input');

    $apiv3Key = '********_fd5hgasg5gda6gdf8gfd';// 在商户平台上设置的APIv3密钥

    // 根据通知的平台证书序列号,查询本地平台证书文件,
    // 假定为 `/path/to/wechatpay/inWechatpaySerial.pem`
    $platformPublicKeyInstance = Rsa::from('file://'.ROOT_PATH.'/app/pay/wechatapp/wechatpay_603C2803A9A56774EDA68F4BB8F77********.pem', Rsa::KEY_TYPE_PUBLIC);
    Tool::log(LOG_PATH."pay.txt", 2,"微信支付回调");
    // 检查通知时间偏移量,允许5分钟之内的偏移
    $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);

    $verifiedStatus = Rsa::verify(
    // 构造验签名串
        Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
        $inWechatpaySignature,
        $platformPublicKeyInstance
    );
    Tool::log(LOG_PATH."pay.txt", $verifiedStatus,"verifiedStatus");
    if ($timeOffsetStatus && $verifiedStatus) {
        // 转换通知的JSON文本消息为PHP Array数组
        $inBodyArray = (array)json_decode($inBody, true);
        // 使用PHP7的数据解构语法,从Array中解构并赋值变量
        ['resource' => [
            'ciphertext'      => $ciphertext,
            'nonce'           => $nonce,
            'associated_data' => $aad
        ]] = $inBodyArray;

        // 加密文本消息解密
        $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
        // 把解密后的文本转换为PHP Array数组
        $inBodyResourceArray = (array)json_decode($inBodyResource, true);
        Tool::log(LOG_PATH."pay.txt", $inBodyResourceArray,"inBodyResourceArray");
        if ($inBodyResourceArray['trade_state'] == 'SUCCESS') {
            // 这里写业务逻辑
            $order_id = (string)$inBodyResourceArray["out_trade_no"];
            $trade_id = (string)$inBodyResourceArray["transaction_id"];
            include(ROOT_PATH."app/pay/pay_callback_common.php");
            $result = [
                'code'=>'SUCCESS',
                'message'=>'成功',
            ];
            echo json_encode($result);exit;
        }

    }
}
// 获取header头的方法
function get_all_header()
{
    // 忽略获取的header数据。这个函数后面会用到。主要是起过滤作用
    $ignore = array('host','accept','content-length','content-type','connection','accept-encoding');    $headers = array();    //这里大家有兴趣的话,可以打印一下。会出来很多的header头信息。咱们想要的部分,都是‘http_'开头的。所以下面会进行过滤输出。/*    var_dump($_SERVER);
    foreach($_SERVER as $key=>$value){      if(substr($key, 0, 5)==='HTTP_'){      //这里取到的都是'http_'开头的数据。
        //前去开头的前5位
        $key = substr($key, 5);        //把$key中的'_'下划线都替换为空字符串
        $key = str_replace('_', ' ', $key);        //再把$key中的空字符串替换成‘-’
        $key = str_replace(' ', '-', $key);        //把$key中的所有字符转换为小写
        $key = strtolower($key);    //这里主要是过滤上面写的$ignore数组中的数据
        if(!in_array($key, $ignore)){          $headers[$key] = $value;
        }
    }
    }//输出获取到的header
    return $headers;

}

$headers = get_all_header();
$input = file_get_contents('php://input');
notify($input,$headers);

回调里只要平台证书引入对就会验签正确、还有api3密钥32位要填一下。

看官方文档太乱了,这一点那一点的,我就整理一下逻辑就好,代码可以直接,相关文件路径可能要调整一下。

相关链接:

https://github.com/wechatpay-apiv3/wechatpay-php#%E5%A6%82%E4%BD%95%E4%B8%8B%E8%BD%BD%E5%B9%B3%E5%8F%B0%E8%AF%81%E4%B9%A6https://github.com/wechatpay-apiv3/wechatpay-php#%E5%A6%82%E4%BD%95%E4%B8%8B%E8%BD%BD%E5%B9%B3%E5%8F%B0%E8%AF%81%E4%B9%A6微信支付-开发者文档

以下是一个 Java 版本的微信 H5 支付 V3 API 异步通知的示例代码: ```java import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Base64; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class WeChatH5NotifyHandler { private static final String WECHAT_API_CERT_SERIAL_NUMBER = "YOUR_WECHAT_API_CERT_SERIAL_NUMBER"; private static final String WECHAT_API_CERTIFICATE = "YOUR_WECHAT_API_CERTIFICATE"; private static final String WECHAT_API_CERTIFICATE_PRIVATE_KEY = "YOUR_WECHAT_API_CERTIFICATE_PRIVATE_KEY"; public static void handleNotify(HttpServletRequest request, HttpServletResponse response) throws IOException { try { InputStream inputStream = request.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder requestBody = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { requestBody.append(line); } // 验证通知的签名 String wechatSerialNumber = request.getHeader("Wechatpay-Serial"); String wechatSignature = request.getHeader("Wechatpay-Signature"); String wechatTimestamp = request.getHeader("Wechatpay-Timestamp"); String wechatNonce = request.getHeader("Wechatpay-Nonce"); if (verifySignature(wechatSerialNumber, wechatSignature, wechatTimestamp, wechatNonce, requestBody.toString())) { // 验证签名成功 // 处理支付成功的逻辑 // ... // 返回成功响应给微信服务器 response.setStatus(HttpServletResponse.SC_OK); response.getWriter().write("OK"); } else { // 验证签名失败,返回失败响应给微信服务器 response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.getWriter().write("Signature verification failed."); } } catch (Exception e) { e.printStackTrace(); // 返回失败响应给微信服务器 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.getWriter().write("Internal Server Error"); } } private static boolean verifySignature(String wechatSerialNumber, String wechatSignature, String wechatTimestamp, String wechatNonce, String requestBody) throws Exception { String message = wechatTimestamp + "\n" + wechatNonce + "\n" + requestBody + "\n"; String signature = "SHA256withRSA"; X509Certificate certificate = getCertificate(); certificate.checkValidity(); certificate.verify(certificate.getPublicKey()); return true; // 假设签名验证成功 } private static X509Certificate getCertificate() throws CertificateException { byte[] certBytes = Base64.getDecoder().decode(WECHAT_API_CERTIFICATE.getBytes(StandardCharsets.UTF_8)); CertificateFactory certificateFactory = CertificateFactory.getInstance("X509"); InputStream inputStream = new ByteArrayInputStream(certBytes); return (X509Certificate) certificateFactory.generateCertificate(inputStream); } } ``` 在上述代码中,我们创建了一个名为 `WeChatH5NotifyHandler` 的类,其中的 `handleNotify` 方法用于处理微信 H5 支付 V3 API 的异步通知。该方法接收 `HttpServletRequest` 和 `HttpServletResponse` 对象作为参数,从请求中获取异步通知的数据,并进行相应的处理逻辑。 在 `handleNotify` 方法中,我们首先获取请求中的数据,并从请求头中获取签名相关信息(`Wechatpay-Serial`、`Wechatpay-Signature`、`Wechatpay-Timestamp`、`Wechatpay-Nonce`)。然后,我们使用 `verifySignature` 方法验证通知的签名是否正确。在示例代码中,我们假设签名验证成功。 如果签名验证成功,则表示支付成功,可以进行相应的处理逻辑,并返回成功响应给微信服务器。如果签名验证失败,则返回失败响应给微信服务器。 请注意,真实的微信 H5 支付 V3 API 的异步通知处理可能涉及到与微信服务器的交互、密钥管理、验签等复杂操作,需要仔细阅读微信支付文档,并使用微信提供的 SDK 或工具类来简化开发。以上示例代码仅供参考,需要根据实际情况进行修改和完善。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值