Skip to content

Commit

Permalink
Merge pull request #288 from cuikangyi/master
Browse files Browse the repository at this point in the history
支持支付宝公钥证书模式
  • Loading branch information
yansongda authored Jan 9, 2020
2 parents 68d189b + 2aa74be commit af18d0d
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 1 deletion.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ class PayController
'ali_public_key' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuWJKrQ6SWvS6niI+4vEVZiYfjkCfLQfoFI2nCp9ZLDS42QtiL4Ccyx8scgc3nhVwmVRte8f57TFvGhvJD0upT4O5O/lRxmTjechXAorirVdAODpOu0mFfQV9y/T9o9hHnU+VmO5spoVb3umqpq6D/Pt8p25Yk852/w01VTIczrXC4QlrbOEe3sr1E9auoC7rgYjjCO6lZUIDjX/oBmNXZxhRDrYx4Yf5X7y8FRBFvygIE2FgxV4Yw+SL3QAa2m5MLcbusJpxOml9YVQfP8iSurx41PvvXUMo49JG3BDVernaCYXQCoUJv9fJwbnfZd7J5YByC+5KM4sblJTq7bXZWQIDAQAB',
// 加密方式: **RSA2**
'private_key' => 'MIIEpAIBAAKCAQEAs6+F2leOgOrvj9jTeDhb5q46GewOjqLBlGSs/bVL4Z3fMr3p+Q1Tux/6uogeVi/eHd84xvQdfpZ87A1SfoWnEGH5z15yorccxSOwWUI+q8gz51IWqjgZxhWKe31BxNZ+prnQpyeMBtE25fXp5nQZ/pftgePyUUvUZRcAUisswntobDQKbwx28VCXw5XB2A+lvYEvxmMv/QexYjwKK4M54j435TuC3UctZbnuynSPpOmCu45ZhEYXd4YMsGMdZE5/077ZU1aU7wx/gk07PiHImEOCDkzqsFo0Buc/knGcdOiUDvm2hn2y1XvwjyFOThsqCsQYi4JmwZdRa8kvOf57nwIDAQABAoIBAQCw5QCqln4VTrTvcW+msB1ReX57nJgsNfDLbV2dG8mLYQemBa9833DqDK6iynTLNq69y88ylose33o2TVtEccGp8Dqluv6yUAED14G6LexS43KtrXPgugAtsXE253ZDGUNwUggnN1i0MW2RcMqHdQ9ORDWvJUCeZj/AEafgPN8AyiLrZeL07jJz/uaRfAuNqkImCVIarKUX3HBCjl9TpuoMjcMhz/MsOmQ0agtCatO1eoH1sqv5Odvxb1i59c8Hvq/mGEXyRuoiDo05SE6IyXYXr84/Nf2xvVNHNQA6kTckj8shSi+HGM4mO1Y4Pbb7XcnxNkT0Inn6oJMSiy56P+CpAoGBAO1O+5FE1ZuVGuLb48cY+0lHCD+nhSBd66B5FrxgPYCkFOQWR7pWyfNDBlmO3SSooQ8TQXA25blrkDxzOAEGX57EPiipXr/hy5e+WNoukpy09rsO1TMsvC+v0FXLvZ+TIAkqfnYBgaT56ku7yZ8aFGMwdCPL7WJYAwUIcZX8wZ3dAoGBAMHWplAqhe4bfkGOEEpfs6VvEQxCqYMYVyR65K0rI1LiDZn6Ij8fdVtwMjGKFSZZTspmsqnbbuCE/VTyDzF4NpAxdm3cBtZACv1Lpu2Om+aTzhK2PI6WTDVTKAJBYegXaahBCqVbSxieR62IWtmOMjggTtAKWZ1P5LQcRwdkaB2rAoGAWnAPT318Kp7YcDx8whOzMGnxqtCc24jvk2iSUZgb2Dqv+3zCOTF6JUsV0Guxu5bISoZ8GdfSFKf5gBAo97sGFeuUBMsHYPkcLehM1FmLZk1Q+ljcx3P1A/ds3kWXLolTXCrlpvNMBSN5NwOKAyhdPK/qkvnUrfX8sJ5XK2H4J8ECgYAGIZ0HIiE0Y+g9eJnpUFelXvsCEUW9YNK4065SD/BBGedmPHRC3OLgbo8X5A9BNEf6vP7fwpIiRfKhcjqqzOuk6fueA/yvYD04v+Da2MzzoS8+hkcqF3T3pta4I4tORRdRfCUzD80zTSZlRc/h286Y2eTETd+By1onnFFe2X01mwKBgQDaxo4PBcLL2OyVT5DoXiIdTCJ8KNZL9+kV1aiBuOWxnRgkDjPngslzNa1bK+klGgJNYDbQqohKNn1HeFX3mYNfCUpuSnD2Yag53Dd/1DLO+NxzwvTu4D6DCUnMMMBVaF42ig31Bs0jI3JQZVqeeFzSET8fkoFopJf3G6UXlrIEAQ==',
// 使用公钥证书模式,请配置下面两个参数,同时修改ali_public_key为以.crt结尾的支付宝公钥证书路径,如(./cert/alipayCertPublicKey_RSA2.crt)
// 'app_cert_public_key' => './cert/appCertPublicKey.crt', //应用公钥证书路径
// 'alipay_root_cert' => './cert/alipayRootCert.crt', //支付宝根证书路径
'log' => [ // optional
'file' => './logs/alipay.log',
'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
Expand Down
5 changes: 5 additions & 0 deletions src/Gateways/Alipay.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ public function __construct(Config $config)
'biz_content' => '',
'app_auth_token' => $config->get('app_auth_token'),
];

if ($config->get('app_cert_public_key') && $config->get('alipay_root_cert')) {
$this->payload['app_cert_sn'] = Support::getCertSN($config->get('app_cert_public_key'));
$this->payload['alipay_root_cert_sn'] = Support::getRootCertSN($config->get('alipay_root_cert'));
}
}

/**
Expand Down
99 changes: 98 additions & 1 deletion src/Gateways/Alipay/Support.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ public static function verifySign(array $data, $sync = false, $sign = null): boo
throw new InvalidConfigException('Missing Alipay Config -- [ali_public_key]');
}

if (Str::endsWith($publicKey, '.pem')) {
if (Str::endsWith($publicKey, '.crt')) {
$publicKey = file_get_contents($publicKey);
} elseif (Str::endsWith($publicKey, '.pem')) {
$publicKey = openssl_pkey_get_public(
Str::startsWith($publicKey, 'file://') ? $publicKey : 'file://'.$publicKey
);
Expand Down Expand Up @@ -371,4 +373,99 @@ protected function setHttpOptions(): self

return $this;
}

/**
* 生成应用证书SN
*
* @author 大冰 https://sbing.vip/archives/2019-new-alipay-php-docking.html
*
* @param $certPath
* @return string
* @throws /Exception
*/
public static function getCertSN($certPath): string
{
if (!is_file($certPath)) {
throw new \Exception('unknown certPath -- [getCertSN]');
}
$x509data = file_get_contents($certPath);
if ($x509data === false) {
throw new \Exception('Alipay CertSN Error -- [getCertSN]');
}
openssl_x509_read($x509data);
$certdata = openssl_x509_parse($x509data);
if (empty($certdata)) {
throw new \Exception('Alipay openssl_x509_parse Error -- [getCertSN]');
}
$issuer_arr = [];
foreach ($certdata['issuer'] as $key => $val) {
$issuer_arr[] = $key . '=' . $val;
}
$issuer = implode(',', array_reverse($issuer_arr));
Log::debug('getCertSN:', [$certPath, $issuer, $certdata['serialNumber']]);
return md5($issuer . $certdata['serialNumber']);
}

/**
* 0x转高精度数字
*
* @author 大冰 https://sbing.vip/archives/2019-new-alipay-php-docking.html
*
* @param $hex
* @return int|string
*/
private static function bchexdec($hex)
{
$dec = 0;
$len = strlen($hex);
for ($i = 1; $i <= $len; $i++) {
$dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
}
return $dec;
}

/**
* 生成支付宝根证书SN
*
* @author 大冰 https://sbing.vip/archives/2019-new-alipay-php-docking.html
*
* @param $certPath
* @return string
* @throws /Exception
*/
public static function getRootCertSN($certPath)
{
if (!is_file($certPath)) {
throw new \Exception('unknown certPath -- [getRootCertSN]');
}
$x509data = file_get_contents($certPath);
if ($x509data === false) {
throw new \Exception('Alipay CertSN Error -- [getRootCertSN]');
}
$kCertificateEnd = "-----END CERTIFICATE-----";
$certStrList = explode($kCertificateEnd, $x509data);
$md5_arr = [];
foreach ($certStrList as $one) {
if (!empty(trim($one))) {
$_x509data = $one . $kCertificateEnd;
openssl_x509_read($_x509data);
$_certdata = openssl_x509_parse($_x509data);
if (in_array($_certdata['signatureTypeSN'], ['RSA-SHA256', 'RSA-SHA1'])) {
$issuer_arr = [];
foreach ($_certdata['issuer'] as $key => $val) {
$issuer_arr[] = $key . '=' . $val;
}
$_issuer = implode(',', array_reverse($issuer_arr));
if (strpos($_certdata['serialNumber'], '0x') === 0) {
$serialNumber = self::bchexdec($_certdata['serialNumber']);
} else {
$serialNumber = $_certdata['serialNumber'];
}
$md5_arr[] = md5($_issuer . $serialNumber);
Log::debug('getRootCertSN Sub:', [$certPath, $_issuer, $serialNumber]);
}
}
}
return implode('_', $md5_arr);
}
}

0 comments on commit af18d0d

Please sign in to comment.