Le middleware Guzzle HttpClient de l'API WeChat Payment v3 implémente la génération de signatures de requête et la vérification des signatures de réponse.
Si vous êtes un développeur marchand utilisant Guzzle, vous pouvez transmettre WechatPayGuzzleMiddleware
lors de la construction de GuzzleHttpClient
. L'instance GuzzleHttpClient
résultante portera automatiquement les informations d'authentification d'identité lors de l'exécution d'une demande et vérifiera la signature WeChat Pay de la réponse.
La version actuelle est la version de test 0.2.0
. Veuillez prêter attention à l'exactitude et à la compatibilité du système et du logiciel, ainsi qu'aux risques encourus, lors de l'utilisation du personnel professionnel et technique du commerçant.
Ce projet est en maintenance . Nous recommandons à tous les développeurs d'utiliser en priorité la nouvelle bibliothèque de développement PHP de WeChat Pay, wechatpay-php.
L'environnement que nous utilisons pour le développement et les tests est le suivant :
Remarque : La raison spécifique pour laquelle guzzle7 n'est pas pris en charge peut être trouvée dans la discussion au #54. Les développeurs qui comptent sur guzzle7 doivent utiliser wechatpay-php.
Vous pouvez utiliser l'outil de gestion de packages PHP composer pour introduire le SDK dans le projet :
Méthode 1 : Dans le répertoire du projet, ajoutez via la ligne de commande composer :
composer require wechatpay/wechatpay-guzzle-middleware
Méthode 2 : ajoutez la configuration suivante au composer.json du projet :
"require" : {
"wechatpay/wechatpay-guzzle-middleware" : " ^0.2.0 "
}
Après avoir ajouté la configuration, effectuez l'installation
composer install
Commencez par créer un WechatPayMiddleware
via WechatPayMiddlewareBuilder
, puis ajoutez-le au HandlerStack
de GuzzleHttpClient
. Nous proposons des méthodes correspondantes pour transmettre facilement des informations telles que les clés privées des commerçants et les certificats de la plateforme de paiement 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 );
Lorsque les méthodes locales de signature et de vérification par défaut ne conviennent pas à votre système, vous pouvez personnaliser la signature et la vérification en implémentant Signer
ou Verifier
. Par exemple, si votre système stocke de manière centralisée les clés privées des commerçants et que le système d'entreprise doit effectuer des signatures via des appels à distance, vous pouvez le faire.
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 ();
L'utilisation de WechatPayMiddlewareBuilder
nécessite d'appeler withWechatpay
pour définir le certificat de la plateforme de paiement WeChat, et le certificat de la plateforme ne peut être téléchargé qu'en appelant l'API Get Platform Certificate. Afin de rompre la « boucle infinie », vous pouvez temporairement « ignorer » la vérification de la signature de réponse lors du premier téléchargement du certificat de plateforme comme suit.
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 ();
Remarque : Veuillez utiliser le processus d'initialisation standard pour les demandes commerciales et assurez-vous de vérifier la signature de la réponse.
Veuillez vous référer à AesUtil.php.
Il est recommandé de mettre à niveau vers swoole 4.6+. Swoole a ajouté la prise en charge native-curl (swoole/swoole-src#3863) dans la version 4.6.0. Nous avons testé qu'il peut être utilisé normalement. Pour des informations plus détaillées, veuillez vous référer au #36.
Si vous trouvez un BUG ou si vous avez des questions ou des suggestions, veuillez nous faire part de vos commentaires via le problème.
Bienvenue également dans notre communauté de développeurs.