gaolei/wechat-pay

可简单调用就能实现的微信支付 PHP 依赖包

v3.0.6 2024-12-23 11:19 UTC

This package is auto-updated.

Last update: 2025-03-23 12:24:23 UTC


README

可简单调用就能实现的 微信支付 依赖包,使用微信最新的v3 接口

* 需要使用到商户证书

已实现功能

  • JsApi 微信内网页、小程序支付
  • H5 微信外网页支付
  • Native 扫码支付
  • App App应用支付
  • Refund 退款申请
  • Close 关闭订单
  • Notify 异步回调处理
  • 商户平台证书生成

安装方式

composer require gaolei/wechat-pay:~v3

使用方式

Config 配置项

  • 老版平台证书模式

    mchCertPath 路径中需要包含文件协议类型

    $config = [
      'mchId' => '1600000001',
      'appId' => 'wx00000000000001',
      'mchCertNo' => 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
      'mchCertPath' => 'file:///cert/1600000001/apiclient_key.pem',
      'wxCertPath' => '/cert/1600000001/wechat_cert.pem',
    ];
    
  • 新版支付公钥模式

mchCertPathwxPubCertPath 路径中均需要包含文件协议类型

$config = [
    'mchId' => '1600000001',
    'appId' => 'wx00000000000001',
    'mchCertNo' => 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
    'mchCertPath' => 'file:///certs/1600000001/apiclient_key.pem',
    'wxPubCertNo' => 'PUB_KEY_ID_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
    'wxPubCertPath' => 'file:///certs/1600000001/pub_key.pem',
];
  • 下方未指定 $config 参数的代码均使用上方的 $config 作为配置参数

这里解释一下,mchId 商户ID mchCertNo 商户证书编号 mchCertPath 商户证书路径 wxCertPath 平台证书路径,生成方式将在文章末尾进行介绍

JsPay 公众号网页、小程序支付

use Gaolei\WechatPay\WechatPay;
$resp = WechatPay::create($config)->jsPay([
    'attach' => 'attach',           // 订单数据包(字符串),异步返回回原样携带
    'title' => '支付测试',           // 订单展示标题
    'order' => 'jspay-' . time(),   // 你的订单编号
    'amount' => 0.01,               // 单位 元
    'time_expire' => 6,             // 订单超时时间(分钟),取值范围为[6,30],区间外默认 6 分钟
    'notify' => 'https://xx.cn/xx', // 支付成功之后的 异步通知地址
    'payer' => [
        'openid' => 'os1-a59lxlc7GyF2zc03j4y8bZoY'
    ]
]);
print_r($resp);
$package = json_encode($resp["body"]["pkg"]);

jsapi 调起支付

var pkg = JSON.parse('<?php echo $package; ?>');

function onBridgeReady(){
	WeixinJSBridge.invoke('getBrandWCPayRequest', pkg, function (res){
		console.log(res)
		if (res.err_msg == "get_brand_wcpay_request:ok") {
			// 使用以上方式判断前端返回,微信团队郑重提示:
			//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
			alert('支付成功')
		}
	});
}

if (typeof WeixinJSBridge == "undefined") {
	if (document.addEventListener) {
		document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
	}else if (document.attachEvent) {
		document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
		document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
	}
}else{
	onBridgeReady();
}

H5Pay h5手机网页支付

use Gaolei\WechatPay\WechatPay;
$resp = WechatPay::create($config)->h5Pay([
    'attach' => 'attach',           // 订单数据包(字符串),异步返回回原样携带
    'title' => '支付测试',           // 订单展示标题
    'order' => 'h5pay-'.time(),     // 你的订单编号
    'amount' => 0.01,               // 单位 元
    'time_expire' => 6,             // 订单超时时间(分钟),取值范围为[6,30],区间外默认 6 分钟
    'notify' => 'https://xx.cn/xx', // 支付成功之后的 异步通知地址
    'scene_info' => [
        "payer_client_ip" => "39.144.137.172",
        'h5_info' => [
            'type' => 'Wap'
        ]
    ]
]);
var_dump($resp);

直接跳转到返回数据中的网页路径即可发起支付

Native 网页扫码支付

use Gaolei\WechatPay\WechatPay;
$resp = WechatPay::create($config)->native([
    'attach' => 'attach',           // 订单数据包(字符串),异步返回回原样携带
    'title' => '支付测试',           // 订单展示标题
    'order' => 'native-'.time(),    // 你的订单编号
    'amount' => 0.01,               // 单位 元
    'time_expire' => 10,            // 订单超时时间(分钟),取值范围为[6,30],区间外默认 6 分钟
    'notify' => 'https://xx.cn/xx', // 支付成功之后的 异步通知地址
]);
var_dump($resp);

AppPay App应用支付

$wechat = \Gaolei\WechatPay\WechatPay::create($config);
$order = 'h5pay-' . time();
$pack = $wechat->appPay([
    'attach' => 'attach',           // 订单数据包(字符串),异步返回回原样携带
    'title' => '支付测试',           // 订单展示标题
    'order' => $order,              // 你的订单编号
    'amount' => 0.01,               // 单位 元
    'time_expire' => 6,             // 订单超时时间(分钟),取值范围为[6,30],区间外默认 6 分钟
    'notify' => 'https://xx.cn/xx', // 支付成功之后的 异步通知地址
]);
echo $order.PHP_EOL;
print_r($pack);
print_r(json_encode($pack['body']['pkg']));

Refund 申请退款

use Gaolei\WechatPay\WechatRefund;

$config = [
    'mchId' => '1600000001',
    'mchCertNo' => 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
    'mchCertPath' => 'file:///Users/user/cert/1600000001/apiclient_key.pem',
    'wxCertPath' => '/Users/user/cert/1600000001/wechat_cert.pem',
];

$config = [
    'mchId' => '1600000001',
    'mchCertNo' => 'XXXXXXXXXXX43EE9B706180FB6675130DAAA',
    'mchCertPath' => 'file://' . __DIR__ . '/certs/1600000001/apiclient_key.pem',
    'wxPubCertNo' => 'PUB_KEY_ID_xxxxxxxxxxxxxxxxxxxxxx',
    'wxPubCertPath' => 'file://' . __DIR__ . '/certs/1600000001/pub_key.pem',
];

$wechat = WechatRefund::create($config);
// 商家退款编号
$refundNo = 'refund-' . time();
$refundParams = [
    'reason' => '测试退款',                  // 退款原因,可选参数
    'order_no' => 'native-1627643208',
    'order_amount' => 0.01,                 // 订单金额 单位元[人民币]
    'refund_no' => $refundNo,
    'refund_amount' => 0.01,                // 退款金额 单位元[人民币]
    'notify_url' => 'https://xx.cn/xx',     // 成功之后的 异步通知地址
];
$resp = $wechat->refund($refundParams);
print_r($resp);

Close 关闭订单

$wechat = \Gaolei\WechatPay\WechatPay::create($config);
$orderNo = '10101010110010101111010';
$rest = $wechat->close($orderNo);
if($rest['error'] === null){
    // 处理成功
}
print_r($rest);
echo PHP_EOL;

Notify 异步回调处理

use Gaolei\WechatPay\WechatPay;

$pack = json_decode(file_get_contents('php://input'), true);
print_r($pack);

$resource = $pack['resource'];

// 商户 apiKeyv3
$apiV3Key = '04F8B9AA596F9F704CE6ECE35CE627AC';
$resource = WechatPay::decryptToString($apiV3Key,$resource['associated_data'], $resource['nonce'], $resource['ciphertext']);

if($resource['error']){
    print_r($resource);
    die;
}

[$eventType, $eventStatus] = explode('.', $pack['event_type']);
$resourceType = $pack['resource_type'];

print_r($resource);
if($eventType === 'REFUND'){
    // 退款回调
    /**
     * $resource['package']  示例值
     * {
            "mchid": "1900000100",
            "transaction_id": "1008450740201411110005820873",
            "out_trade_no": "20150806125346",
            "refund_id": "50200207182018070300011301001",
            "out_refund_no": "7752501201407033233368018",
            "refund_status": "SUCCESS",
            "success_time": "2018-06-08T10:34:56+08:00",
            "user_received_account": "招商银行信用卡0403",
            "amount" : {
                "total": 999,
                "refund": 999,
                "payer_total": 999,
                "payer_refund": 999
            }
     * }
     *
     */
} elseif($eventType === 'TRANSACTION'){
    // 支付回调
    /**
     * $resource['package']  示例值
     * {
            "transaction_id":"1217752501201407033233368018",
            "amount":{
                "payer_total":100,
                "total":100,
                "currency":"CNY",
                "payer_currency":"CNY"
            },
            "mchid":"1230000109",
            "trade_state":"SUCCESS",
            "bank_type":"CMC",
            "success_time":"2018-06-08T10:34:56+08:00",
            "payer":{
                "openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
            },
            "out_trade_no":"1217752501201407033233368018",
            "appid":"wxd678efh567hg6787",
            "trade_state_desc":"支付成功",
            "trade_type":"MICROPAY",
            "attach":"自定义数据",
            "scene_info":{
                "device_id":"013467007045764"
            }
     * }
     *
     */
    $info = WechatPay::getPayRespByResource($resource['package']);
    print_r($info);
}

平台证书生成

仅限老版商户号,请注意查看商户号后台


use Gaolei\WechatPay\WechatCert;

$mchId        = '你的商户ID';        // 例:'1600000001'
$apiV3Key     = '你的V3接口秘钥';      // 例:'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
$mchCertNo    = '你的商户证书编号';   // 例: 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'
$mchCertPath  = '商户证书文件地址';   // 例: '/Users/user/cert/1600000001/apiclient_key.pem'
$certSavePath = '证书保存路径[目录]'; // 例: ./ 或 ./wechat_cert.pem
$res = WechatCert::generate($mchId,$apiV3Key,$mchCertNo,$mchCertPath,$certSavePath);
var_dump($res);