php对接微信H5支付 wechatpay-apiv3 / wechatpay-php 下单和回调

1、下载官方提供的sdk(https://github.com/wechatpay-apiv3/wechatpay-php)
2、创建订单

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

   /**
     * @param $out_trade_no 订单号
     * @param $total_fee 支付金额
     * @param $attach 扩展字段
     * @param $body 描述
     * @return mixed
     */
    public static function h5($out_trade_no, $total_fee, $attach, $body){
        // 商户号
        $merchantId = 'xxx';

        // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = 'file://这里写apiclient_key.pem文件地址绝对路径';
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

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

       // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名(php需要用工具或者时接口获取,见我的另一篇文章记录)
        $platformCertificateFilePath = 'file://这里写平台证书地址绝对路径';
        $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,
            ],
        ]);

        try {
            $resp = $instance
                ->chain('v3/pay/transactions/h5')
                ->post(['json' => [
                    'mchid'        => '',
                    'attach'        => $attach,
                    'out_trade_no' => $out_trade_no,
                    'appid'        => '',
                    'description'  => $body,
                    'notify_url'   => '',
                    'amount'       => [
                        'total'    => $total_fee,
                        'currency' => 'CNY'
                    ],
                    'scene_info' => [
                        'payer_client_ip' => '',
                        'h5_info' => [
                            'type' => 'Wap',
                        ],
                    ],
                ]]);

            $res = json_decode($resp->getBody(),true);
            return $res['h5_url']; // 返回给前端,前端在浏览器跳转该地址就可以唤起微信支付
        } 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;
        }
    }
/**
     * 微信支付回调
     * @param $input 获取的body数据
     * @param $header 获取的请求头数据
     * @return bool
     */
    public function notify($input,$header)
    {
        $inWechatpaySignature = $header['wechatpay-signature'];// 请根据实际情况获取
        $inWechatpayTimestamp = $header['wechatpay-timestamp'];// 请根据实际情况获取
        $inWechatpaySerial = $header['wechatpay-serial'];// 请根据实际情况获取
        $inWechatpayNonce = $header['wechatpay-nonce'];// 请根据实际情况获取
        $inBody = $input;// 请根据实际情况获取,例如: file_get_contents('php://input');

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

         // 根据通知的平台证书序列号,查询本地平台证书文件,
        // 假定为 `/path/to/wechatpay/inWechatpaySerial.pem`
        $platformPublicKeyInstance = Rsa::from('file://平台证书地址', Rsa::KEY_TYPE_PUBLIC);

        // 检查通知时间偏移量,允许5分钟之内的偏移
        $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);

        $verifiedStatus = Rsa::verify(
        // 构造验签名串
            Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
            $inWechatpaySignature,
            $platformPublicKeyInstance
        );
        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);
            if ($inBodyResourceArray['trade_state'] == 'SUCCESS') {
                // 这里写业务逻辑

                $result = [
		            'code'=>'SUCCESS',
		            'message'=>'成功',
        			];
        		echo json_encode($result);exit;
            }

        }

    }
    // 获取header头的方法
	public 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;

    }

要使用 `com.github.wechatpay-apiv3` 库处理微信 H5 支付的异步通知,您可以按照以下步骤进行操作: 1. 在项目的 Maven 配置文件(例如 `pom.xml`)中添加 `com.github.wechatpay-apiv3` 的依赖项: ```xml <dependencies> <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>1.0.0-beta4</version> </dependency> </dependencies> ``` 2. 在异步通知的接口中编写代码。 ```java import com.github.wechatpay.apiv3.WxPayApiV3; import com.github.wechatpay.apiv3.WxPayApiV3Config; import com.github.wechatpay.apiv3.model.notify.WxPayOrderNotifyResult; import com.github.wechatpay.apiv3.model.notify.WxPayOrderNotifyResult.NotifyResponse; import com.github.wechatpay.apiv3.model.notify.WxPayOrderNotifyResult.Resource; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityConsumer; import org.apache.hc.core5.ssl.SSLContextBuilder; import org.apache.hc.core5.util.Timeout; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.KeyStore; 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_PATH = "path/to/your/wechat/api/certificate.p12"; private static final String WECHAT_API_CERTIFICATE_PASSWORD = "your_certificate_password"; public void handleNotify(HttpServletRequest request, HttpServletResponse response) throws IOException { try { // 创建微信支付 API 配置 WxPayApiV3Config config = new WxPayApiV3Config.Builder() .appId("your_app_id") .merchantId("your_merchant_id") .privateKeySerialNumber(WECHAT_API_CERT_SERIAL_NUMBER) .privateKey(getPrivateKey()) .build(); // 创建微信支付 API 实例 WxPayApiV3 wxPayApiV3 = new WxPayApiV3(config); // 读取异步通知的请求体 String notifyData = EntityUtils.toString(new BasicAsyncEntityConsumer(), request.getInputStream(), StandardCharsets.UTF_8); // 解析异步通知数据 WxPayOrderNotifyResult notifyResult = wxPayApiV3.parseOrderNotifyResult(notifyData); // 验证签名 if (wxPayApiV3.verifySignature(notifyResult)) { // 签名验证成功 // 处理支付成功的逻辑 // ... // 返回成功响应给微信服务器 response.setStatus(HttpServletResponse.SC_OK); response.getWriter().write("SUCCESS"); } else { // 签名验证失败,返回失败响应给微信服务器 response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.getWriter().write("FAIL"); } } catch (Exception e) { e.printStackTrace(); // 返回失败响应给微信服务器 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.getWriter().write("FAIL"); } } private KeyStore getPrivateKey() throws Exception { return SSLContextBuilder .create() .loadKeyMaterial(getClass().getClassLoader().getResourceAsStream(WECHAT_API_CERTIFICATE_PATH), WECHAT_API_CERTIFICATE_PASSWORD.toCharArray()) .build() .getKeyStore(); } } ``` 在上述代码中,我们创建了一个名为 `WeChatH5NotifyHandler` 的类,其中的 `handleNotify` 方法用于处理微信 H5 支付的异步通知。该方法接收 `HttpServletRequest` 和 `HttpServletResponse` 对象作为参数,从请求中获取异步通知的数据,并进行相应的处理逻辑。 在 `handleNotify` 方法中,我们首先创建了一个 `WxPayApiV3Config` 对象,用于配置微信支付 API 的相关参数。其中,我们需要提供应用 ID(`appId`)、商户号(`merchantId`)、微信支付 API 证书的序列号(`privateKeySerialNumber`)以及证书的私钥(`privateKey`)。您需要将这些参数替换为您自己的值。 然后,我们使用 `WxPayApiV3` 实例来解析异步通知数据,并验证签名。如果签名验证成功,则表示支付成功,可以进行相应的处理逻辑,并返回成功响应给微信服务器。如果签名验证失败,则返回失败响应给微信服务器。 请注意,以上示例代码仅供参考,具体的实现可能因应用的需求而有所不同。您需要根据实际情况进行修改和完善。另外,在真实的项目中,请确保您已正确配置和保护微信支付 API 证书的私钥。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值