มิดเดิลแวร์ Guzzle HttpClient ของ WeChat Payment API v3 ดำเนินการสร้างลายเซ็นคำขอและการตรวจสอบลายเซ็นการตอบกลับ
หากคุณเป็นนักพัฒนาการค้าที่ใช้ Guzzle คุณสามารถส่งผ่าน WechatPayGuzzleMiddleware
เมื่อสร้าง GuzzleHttpClient
อินสแตนซ์ GuzzleHttpClient
ที่ได้จะมีข้อมูลการตรวจสอบตัวตนโดยอัตโนมัติเมื่อดำเนินการคำขอ และตรวจสอบลายเซ็น WeChat Pay ของการตอบกลับ
เวอร์ชันปัจจุบันคือเวอร์ชันทดสอบ 0.2.0
โปรดใส่ใจกับความถูกต้องและความเข้ากันได้ของระบบและซอฟต์แวร์ ตลอดจนความเสี่ยงที่เกี่ยวข้อง เมื่อใช้บุคลากรมืออาชีพและด้านเทคนิคของร้านค้า
โครงการนี้อยู่ระหว่าง การบำรุงรักษา เราขอแนะนำให้นักพัฒนาทุกคนให้ความสำคัญกับการใช้ไลบรารี่การพัฒนา PHP ใหม่ของ WeChat Pay wechatpay-php
สภาพแวดล้อมที่เราใช้สำหรับการพัฒนาและการทดสอบมีดังนี้:
หมายเหตุ: สาเหตุเฉพาะที่ทำให้ guzzle7 ไม่ได้รับการสนับสนุนสามารถพบได้ในการสนทนาใน #54 นักพัฒนาซอฟต์แวร์ที่ใช้ guzzle7 โปรดใช้ wechatpay-php
คุณสามารถใช้เครื่องมือจัดการแพ็คเกจ PHP เพื่อแนะนำ SDK ให้กับโปรเจ็กต์ได้:
วิธีที่ 1: ในไดเร็กทอรีโครงการ ให้เพิ่มผ่านบรรทัดคำสั่งของผู้แต่ง:
composer require wechatpay/wechatpay-guzzle-middleware
วิธีที่ 2: เพิ่มการกำหนดค่าต่อไปนี้ให้กับ composer.json ของโครงการ:
"require" : {
"wechatpay/wechatpay-guzzle-middleware" : " ^0.2.0 "
}
หลังจากเพิ่มการกำหนดค่าแล้ว ให้ทำการติดตั้ง
composer install
ขั้นแรก สร้าง WechatPayMiddleware
ผ่าน WechatPayMiddlewareBuilder
แล้วเพิ่มลงใน HandlerStack
ของ GuzzleHttpClient
เรามีวิธีการที่เกี่ยวข้องเพื่อส่งข้อมูลได้อย่างสะดวก เช่น รหัสส่วนตัวของผู้ค้า และใบรับรองแพลตฟอร์มการชำระเงิน WeChat
use GuzzleHttp Exception RequestException ;
use WechatPay GuzzleMiddleware WechatPayMiddleware ;
use WechatPay GuzzleMiddleware Util PemUtil ;
// 商户相关配置
$ merchantId = ' 1000100 ' ; // 商户号
$ merchantSerialNumber = ' XXXXXXXXXX ' ; // 商户API证书序列号
$ merchantPrivateKey = PemUtil:: loadPrivateKey ( ' /path/to/mch/private/key.pem ' ); // 商户私钥
// 微信支付平台配置
$ wechatpayCertificate = PemUtil:: loadCertificate ( ' /path/to/wechatpay/cert.pem ' ); // 微信支付平台证书
// 构造一个WechatPayMiddleware
$ wechatpayMiddleware = WechatPayMiddleware:: builder ()
-> withMerchant ( $ merchantId , $ merchantSerialNumber , $ merchantPrivateKey ) // 传入商户相关配置
-> withWechatPay ([ $ wechatpayCertificate ]) // 可传入多个微信支付平台证书,参数类型为array
-> build ();
// 将WechatPayMiddleware添加到Guzzle的HandlerStack中
$ stack = GuzzleHttp HandlerStack:: create ();
$ stack -> push ( $ wechatpayMiddleware , ' wechatpay ' );
// 创建Guzzle HTTP Client时,将HandlerStack传入
$ client = new GuzzleHttp Client ([ ' handler ' => $ stack ]);
// 接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签
try {
$ resp = $ client -> request ( ' GET ' , ' https://api.mch.weixin.qq.com/v3/... ' , [ // 注意替换为实际URL
' headers ' => [ ' Accept ' => ' application/json ' ]
]);
echo $ resp -> getStatusCode (). ' ' . $ resp -> getReasonPhrase (). "n" ;
echo $ resp -> getBody (). "n" ;
$ resp = $ client -> request ( ' POST ' , ' https://api.mch.weixin.qq.com/v3/... ' , [
' json ' => [ // JSON请求体
' field1 ' => ' value1 ' ,
' field2 ' => ' value2 '
],
' headers ' => [ ' Accept ' => ' application/json ' ]
]);
echo $ resp -> getStatusCode (). ' ' . $ resp -> getReasonPhrase (). "n" ;
echo $ resp -> getBody (). "n" ;
} catch ( RequestException $ e ) {
// 进行错误处理
echo $ e -> getMessage (). "n" ;
if ( $ e -> hasResponse ()) {
echo $ e -> getResponse ()-> getStatusCode (). ' ' . $ e -> getResponse ()-> getReasonPhrase (). "n" ;
echo $ e -> getResponse ()-> getBody ();
}
return ;
}
// 参考上述指引说明,并引入 `MediaUtil` 正常初始化,无额外条件
use WechatPay GuzzleMiddleware Util MediaUtil ;
// 实例化一个媒体文件流,注意文件后缀名需符合接口要求
$ media = new MediaUtil ( ' /your/file/path/with.extension ' );
// 正常使用Guzzle发起API请求
try {
$ resp = $ client -> request ( ' POST ' , ' https://api.mch.weixin.qq.com/v3/[merchant/media/video_upload|marketing/favor/media/image-upload] ' , [
' body ' => $ media -> getStream (),
' headers ' => [
' Accept ' => ' application/json ' ,
' content-type ' => $ media -> getContentType (),
]
]);
// POST 语法糖
$ resp = $ client -> post ( ' merchant/media/upload ' , [
' body ' => $ media -> getStream (),
' headers ' => [
' Accept ' => ' application/json ' ,
' content-type ' => $ media -> getContentType (),
]
]);
echo $ resp -> getStatusCode (). ' ' . $ resp -> getReasonPhrase (). "n" ;
echo $ resp -> getBody (). "n" ;
} catch ( Exception $ e ) {
echo $ e -> getMessage (). "n" ;
if ( $ e -> hasResponse ()) {
echo $ e -> getResponse ()-> getStatusCode (). ' ' . $ e -> getResponse ()-> getReasonPhrase (). "n" ;
echo $ e -> getResponse ()-> getBody ();
}
return ;
}
// 参考上上述说明,引入 `SensitiveInfoCrypto`
use WechatPay GuzzleMiddleware Util SensitiveInfoCrypto ;
// 上行加密API 多于 下行解密,默认为加密,实例后直接当方法用即可
$ encryptor = new SensitiveInfoCrypto (PemUtil:: loadCertificate ( ' /path/to/wechatpay/cert.pem ' ));
// 正常使用Guzzle发起API请求
try {
// POST 语法糖
$ resp = $ client -> post ( ' /v3/applyment4sub/applyment/ ' , [
' json ' => [
' business_code ' => ' APL_98761234 ' ,
' contact_info ' => [
' contact_name ' => $ encryptor ( ' value of `contact_name` ' ),
' contact_id_number ' => $ encryptor ( ' value of `contact_id_number ' ),
' mobile_phone ' => $ encryptor ( ' value of `mobile_phone` ' ),
' contact_email ' => $ encryptor ( ' value of `contact_email` ' ),
],
//...
],
' headers ' => [
// 命令行获取证书序列号
// openssl x509 -in /path/to/wechatpay/cert.pem -noout -serial | awk -F= '{print $2}'
// 或者使用工具类获取证书序列号 `PemUtil::parseCertificateSerialNo($certificate)`
' Wechatpay-Serial ' => ' must be the serial number via the downloaded pem file of `/v3/certificates` ' ,
' Accept ' => ' application/json ' ,
],
]);
echo $ resp -> getStatusCode (). ' ' . $ resp -> getReasonPhrase (). "n" ;
echo $ resp -> getBody (). "n" ;
} catch ( Exception $ e ) {
echo $ e -> getMessage (). "n" ;
if ( $ e -> hasResponse ()) {
echo $ e -> getResponse ()-> getStatusCode (). ' ' . $ e -> getResponse ()-> getReasonPhrase (). "n" ;
echo $ e -> getResponse ()-> getBody ();
}
return ;
}
// 单例加解密示例如下
$ crypto = new SensitiveInfoCrypto ( $ wechatpayCertificate , $ merchantPrivateKey );
$ encrypted = $ crypto ( ' Alice ' );
$ decrypted = $ crypto -> setStage ( ' decrypt ' )( $ encrypted );
เมื่อวิธีการลงนามและการตรวจสอบภายในเริ่มต้นไม่เหมาะกับระบบของคุณ คุณสามารถปรับแต่งการลงนามและการตรวจสอบยืนยันได้โดยใช้ Signer
หรือ Verifier
ตัวอย่างเช่น หากระบบของคุณจัดเก็บคีย์ส่วนตัวของผู้ขายไว้ที่ส่วนกลาง และระบบธุรกิจจำเป็นต้องดำเนินการลายเซ็นผ่านการโทรระยะไกล คุณก็สามารถทำได้
use WechatPay GuzzleMiddleware Auth Signer ;
use WechatPay GuzzleMiddleware Auth SignatureResult ;
use WechatPay GuzzleMiddleware Auth WechatPay2Credentials ;
class CustomSigner implements Signer
{
public function sign ( $ message )
{
// 调用签名RPC服务,然后返回包含签名和证书序列号的SignatureResult
return new SignatureResult ( ' xxxx ' , ' yyyyy ' );
}
}
$ credentials = new WechatPay2Credentials ( $ merchantId , new CustomSigner );
$ wechatpayMiddleware = WechatPayMiddleware:: builder ()
-> withCredentials ( $ credentials )
-> withWechatPay ([ $ wechatpayCertificate ])
-> build ();
การใช้ WechatPayMiddlewareBuilder
จำเป็นต้องโทร withWechatpay
เพื่อตั้งค่าใบรับรองแพลตฟอร์มการชำระเงิน WeChat และสามารถดาวน์โหลดใบรับรองแพลตฟอร์มได้โดยการเรียก Get Platform Certificate API เท่านั้น เพื่อที่จะทำลาย "วงวนไม่สิ้นสุด" คุณสามารถ "ข้าม" การตรวจสอบลายเซ็นการตอบกลับได้ชั่วคราวเมื่อดาวน์โหลดใบรับรองแพลตฟอร์มเป็นครั้งแรกดังนี้
use WechatPay GuzzleMiddleware Validator ;
class NoopValidator implements Validator
{
public function validate ( Psr Http Message ResponseInterface $ response )
{
return true ;
}
}
$ wechatpayMiddleware = WechatPayMiddleware:: builder ()
-> withMerchant ( $ merchantId , $ merchantSerialNumber , $ merchantPrivateKey )
-> withValidator ( new NoopValidator ) // NOTE: 设置一个空的应答签名验证器,**不要**用在业务请求
-> build ();
หมายเหตุ : โปรดใช้กระบวนการเริ่มต้นมาตรฐานสำหรับคำขอทางธุรกิจ และตรวจสอบให้แน่ใจว่าได้ตรวจสอบลายเซ็นการตอบกลับแล้ว
โปรดดูที่ AesUtil.php
ขอแนะนำให้อัปเกรดเป็น swoole 4.6+ โดยเพิ่มการรองรับ Native-Curl (swoole/swoole-src#3863) ใน 4.6.0 เราทดสอบแล้วว่าสามารถใช้งานได้ตามปกติ สำหรับข้อมูลรายละเอียดเพิ่มเติม โปรดดูที่ #36
หากคุณพบ ข้อบกพร่อง หรือมีคำถามหรือข้อเสนอแนะ โปรดให้ข้อเสนอแนะผ่านประเด็นต่างๆ
ยินดีต้อนรับสู่ชุมชนนักพัฒนาของเรา