- wechatpay-apache-httpclient,适用于使用Apache HttpClient处理HTTP的Java开发者。
- wechatpay-guzzle-middleware,适用于PHP开发者。
这里用的是PHP,所以使用 wechatpay-guzzle-middleware 。
下载微信支付平台证书主要文件 CertificateDownloader.php
private function downloadCert($opts=[])
{
try {
// 构造一个WechatPayMiddleware
$builder = WechatPayMiddleware::builder()
->withMerchant($opts['mchid'], $opts['serialno'], PemUtil::loadPrivateKey($opts['privatekey'])); // 传入商户相关配置
if (isset($opts['wechatpay-cert'])) {
$builder->withWechatPay([ PemUtil::loadCertificate($opts['wechatpay-cert']) ]); // 使用平台证书验证
}
else {
$builder->withValidator(new NoopValidator); // 临时"跳过”应答签名的验证
}
$wechatpayMiddleware = $builder->build();
// 将WechatPayMiddleware添加到Guzzle的HandlerStack中
$stack = HandlerStack::create();
$stack->push($wechatpayMiddleware, 'wechatpay');
// 创建Guzzle HTTP Client时,将HandlerStack传入
$client = new Client(['handler' => $stack]);
// 接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签
$resp = $client->request("GET", "https://api.mch.weixin.qq.com/v3/certificates", [
'headers' => [ 'Accept' => 'application/json','User-Agent'=>'https://zh.wikipedia.org/wiki/User_agent' ]
]);
if ($resp->getStatusCode() < 200 || $resp->getStatusCode() > 299) {
echo "download failed, code={$resp->getStatusCode()}, body=[{$resp->getBody()}]\n";
return;
}
$list = json_decode($resp->getBody(), true);
$plainCerts = [];
$x509Certs = [];
$decrypter = new AesUtil($opts['key']);
foreach ($list['data'] as $item) {
$encCert = $item['encrypt_certificate'];
$plain = $decrypter->decryptToString($encCert['associated_data'],
$encCert['nonce'], $encCert['ciphertext']);
if (!$plain) {
echo "encrypted certificate decrypt fail!\n";
exit(1);
}
// 通过加载对证书进行简单合法性检验
$cert = \openssl_x509_read($plain); // 从字符串中加载证书
if (!$cert) {
echo "downloaded certificate check fail!\n";
exit(1);
}
$plainCerts[] = $plain;
$x509Certs[] = $cert;
}
// 使用下载的证书再来验证一次应答的签名
$validator = new WechatPay2Validator(new CertificateVerifier($x509Certs));
if (!$validator->validate($resp)) {
echo "validate response fail using downloaded certificates!";
exit(1);
}
// 输出证书信息,并保存到文件
foreach ($list['data'] as $index => $item) {
// echo "Certificate {\n";
// echo " Serial Number: ".$item['serial_no']."\n";
// echo " Not Before: ".(new DateTime($item['effective_time']))->format('Y-m-d H:i:s')."\n";
// echo " Not After: ".(new DateTime($item['expire_time']))->format('Y-m-d H:i:s')."\n";
// echo " Text: \n ".str_replace("\n", "\n ", $plainCerts[$index])."\n";
// echo "}\n";
$outpath = $opts['output'].DIRECTORY_SEPARATOR.'wechatpay_'.$item['serial_no'].'.pem';
file_put_contents($outpath, $plainCerts[$index]);
}
// return [$opts,$list['data'],$outpath,$plainCerts];
}
catch (RequestException $e) {
echo "download failed, message=[{$e->getMessage()}] ";
if ($e->hasResponse()) {
echo "code={$e->getResponse()->getStatusCode()}, body=[{$e->getResponse()->getBody()}]\n";
}
exit(1);
}
catch (Exception $e) {
echo "download failed, message=[{$e->getMessage()}]\n";
echo $e;
exit(1);
}
}