Compare commits

...

6 Commits

Author SHA1 Message Date
邹景立
c806ba514a 修改证书配置 2023-05-02 23:39:44 +08:00
邹景立
4d77813064 修改支付宝支付参数 2023-05-02 22:56:55 +08:00
邹景立
0595f9bcb2 修改接口 2023-05-02 22:54:26 +08:00
邹景立
c5ff92f778 企业打款增加大于2000的RSA名称加密 2023-05-02 21:17:17 +08:00
邹景立
dc29ee61a7 增加订单创建异常输出 2023-05-02 21:16:50 +08:00
邹景立
196edc08a2 #I6K2RH 增加 RSA 加密 2023-05-02 20:56:08 +08:00
8 changed files with 132 additions and 57 deletions

View File

@ -83,24 +83,5 @@ class Transfer extends BasicAliPay
return $this->getResult($options);
}
/**
* 新版 设置网关应用公钥证书SN、支付宝根证书SN
*/
protected function setAppCertSnAndRootCertSn()
{
if (!$this->config->get('app_cert')) {
throw new InvalidArgumentException("Missing Config -- [app_cert]");
}
if (!$this->config->get('root_cert')) {
throw new InvalidArgumentException("Missing Config -- [root_cert]");
}
$this->options->set('app_cert_sn', $this->getCertSN($this->config->get('app_cert')));
$this->options->set('alipay_root_cert_sn', $this->getRootCertSN($this->config->get('root_cert')));
if (!$this->options->get('app_cert_sn')) {
throw new InvalidArgumentException("Missing options -- [app_cert_sn]");
}
if (!$this->options->get('alipay_root_cert_sn')) {
throw new InvalidArgumentException("Missing options -- [alipay_root_cert_sn]");
}
}
}

View File

@ -297,10 +297,9 @@ abstract class BasicAliPay
* @param string $sign
* @return string
*/
public function getCertSN($sign)
private function getAppCertSN($sign)
{
// if (file_exists($sign)) $sign = file_get_contents($sign);
$ssl = openssl_x509_parse($sign);
$ssl = openssl_x509_parse($sign, true);
return md5($this->_arr2str(array_reverse($ssl['issuer'])) . $ssl['serialNumber']);
}
@ -309,27 +308,57 @@ abstract class BasicAliPay
* @param string $sign
* @return string|null
*/
public function getRootCertSN($sign)
private function getRootCertSN($sign)
{
$sn = null;
// if (file_exists($sign)) $sign = file_get_contents($sign);
$array = explode("-----END CERTIFICATE-----", $sign);
$array = explode('-----END CERTIFICATE-----', $sign);
for ($i = 0; $i < count($array) - 1; $i++) {
$ssl[$i] = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----");
$ssl[$i] = openssl_x509_parse($array[$i] . '-----END CERTIFICATE-----', true);
if (strpos($ssl[$i]['serialNumber'], '0x') === 0) {
$ssl[$i]['serialNumber'] = $this->_hex2dec($ssl[$i]['serialNumber']);
$ssl[$i]['serialNumber'] = $this->_hex2dec(isset($ssl[$i]['serialNumberHex']) ? $ssl[$i]['serialNumberHex'] : $ssl[$i]['serialNumber']);
}
if ($ssl[$i]['signatureTypeLN'] == "sha1WithRSAEncryption" || $ssl[$i]['signatureTypeLN'] == "sha256WithRSAEncryption") {
if ($sn == null) {
$sn = md5($this->_arr2str(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']);
} else {
$sn = $sn . "_" . md5($this->_arr2str(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']);
$sn = $sn . '_' . md5($this->_arr2str(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']);
}
}
}
return $sn;
}
/**
* 新版 设置网关应用公钥证书SN、支付宝根证书SN
*/
protected function setAppCertSnAndRootCertSn()
{
$appCert = $this->config->get('app_cert');
$rootCert = $this->config->get('root_cert');
$appCertPath = $this->config->get('app_cert_path');
$rootCertPath = $this->config->get('root_cert_path');
if (empty($appCert) && !empty($appCertPath) && is_file($appCertPath)) {
$appCert = file_get_contents($appCertPath);
}
if (empty($rootCert) && !empty($rootCertPath) && is_file($rootCertPath)) {
$rootCert = file_get_contents($rootCertPath);
}
if (empty($appCert)) {
throw new InvalidArgumentException('Missing Config -- [app_cert|app_cert_path]');
}
if (empty($rootCert)) {
throw new InvalidArgumentException('Missing Config -- [root_cert|root_cert_path]');
}
$this->options->set('app_cert_sn', $this->getAppCertSN($appCert));
$this->options->set('alipay_root_cert_sn', $this->getRootCertSN($rootCert));
if (!$this->options->get('app_cert_sn')) {
throw new InvalidArgumentException('Missing options -- [app_cert_sn]');
}
if (!$this->options->get('alipay_root_cert_sn')) {
throw new InvalidArgumentException('Missing options -- [alipay_root_cert_sn]');
}
}
/**
* 新版 数组转字符串
* @param array $array
@ -346,7 +375,6 @@ abstract class BasicAliPay
return implode(',', $string);
}
/**
* 新版 0x转高精度数字
* @param string $hex
@ -367,5 +395,4 @@ abstract class BasicAliPay
* @return mixed
*/
abstract public function apply($options);
}

View File

@ -18,6 +18,7 @@ namespace WePayV3\Contracts;
use WeChat\Contracts\Tools;
use WeChat\Exceptions\InvalidArgumentException;
use WeChat\Exceptions\InvalidDecryptException;
use WeChat\Exceptions\InvalidResponseException;
use WePayV3\Cert;
@ -156,8 +157,11 @@ abstract class BasicWePay
$location = (preg_match('|^https?://|', $pathinfo) ? '' : $this->base) . $pathinfo;
list($header, $content) = $this->_doRequestCurl($method, $location, [
'data' => $jsondata, 'header' => [
"Accept: application/json", "Content-Type: application/json",
'User-Agent: https://thinkadmin.top', "Authorization: WECHATPAY2-SHA256-RSA2048 {$token}",
'Accept: application/json',
'Content-Type: application/json',
'User-Agent: https://thinkadmin.top',
"Authorization: WECHATPAY2-SHA256-RSA2048 {$token}",
"Wechatpay-Serial: {$this->config['cert_serial']}"
],
]);
@ -260,4 +264,36 @@ abstract class BasicWePay
return Tools::setCache($name, base64_encode($content), 7200);
}
}
/**
* RSA加密处理
* @param string $string
* @return string
* @throws \WeChat\Exceptions\InvalidDecryptException
*/
protected function rsaEncode($string)
{
$publicKey = file_get_contents($this->config['cert_public']);
if (openssl_public_encrypt($string, $encrypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING)) {
return base64_encode($encrypted);
} else {
throw new InvalidDecryptException('Rsa Encrypt Error.');
}
}
/**
* RSA 解密处理
* @param string $string
* @return string
* @throws \WeChat\Exceptions\InvalidDecryptException
*/
protected function rsaDecode($string)
{
$private = file_get_contents($this->config['cert_private']);
if (openssl_private_decrypt(base64_decode($string), $content, $private, OPENSSL_PKCS1_OAEP_PADDING)) {
return $content;
} else {
throw new InvalidDecryptException('Rsa Decrypt Error.');
}
}
}

View File

@ -18,6 +18,7 @@ namespace WePayV3;
use WeChat\Contracts\Tools;
use WeChat\Exceptions\InvalidArgumentException;
use WeChat\Exceptions\InvalidResponseException;
use WePayV3\Contracts\BasicWePay;
use WePayV3\Contracts\DecryptAes;
@ -54,9 +55,13 @@ class Order extends BasicWePay
} else {
// 创建预支付码
$result = $this->doRequest('POST', $types[$type], json_encode($data, JSON_UNESCAPED_UNICODE), true);
if (empty($result['prepay_id'])) return $result;
if (empty($result['h5_url']) && empty($result['code_url']) && empty($result['prepay_id'])) {
$message = isset($result['code']) ? "[ {$result['code']} ] " : '';
$message .= isset($result['message']) ? $result['message'] : json_encode($result, JSON_UNESCAPED_UNICODE);
throw new InvalidResponseException($message);
}
// 支付参数签名
$time = (string)time();
$time = strval(time());
$appid = $this->config['appid'];
$prepayId = $result['prepay_id'];
$nonceStr = Tools::createNoncestr();

View File

@ -20,7 +20,7 @@ use WePayV3\Contracts\BasicWePay;
/**
* 普通商户商家转账到零钱
* Class Transfers
* @class Transfers
* @package WePayV3
*/
class Transfers extends BasicWePay
@ -29,10 +29,16 @@ class Transfers extends BasicWePay
* 发起商家批量转账
* @param array $body
* @return array
* @throws \WeChat\Exceptions\InvalidDecryptException
* @throws \WeChat\Exceptions\InvalidResponseException
*/
public function batchs($body)
{
if (isset($body['transfer_detail_list']) && is_array($body['transfer_detail_list'])) {
foreach ($body['transfer_detail_list'] as &$item) if (isset($item['user_name'])) {
$item['user_name'] = $this->rsaEncode($item['user_name']);
}
}
return $this->doRequest('POST', '/v3/transfer/batches', json_encode($body, JSON_UNESCAPED_UNICODE), true);
}

View File

@ -28,7 +28,7 @@ try {
// 请参考请求参数https://docs.open.alipay.com/api_1/alipay.trade.app.pay
$result = $pay->apply([
'out_trade_no' => time(), // 商户订单号
'out_trade_no' => strval(time()), // 商户订单号
'total_amount' => '1', // 支付金额
'subject' => '支付宝订单标题', // 支付订单描述
]);

View File

@ -14,21 +14,41 @@
// | github 代码仓库https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
/**
* 名词解释
* 应用私钥:用来给应用消息进行签名,请务必要妥善保管,避免遗失或泄露。
* 应用公钥:需要提供给支付宝开放平台,平台会对应用发送的消息进行签名验证。
* 支付宝公钥:应用收到支付宝发送的同步、异步消息时,使用支付宝公钥验证签名信息。
* CSR 文件CSR 即证书签名请求Certificate Signing RequestCSR 文件(.csr是申请证书时所需要的一个数据文件。
* 应用公钥证书:在开放平台上传 CSR 文件后可以获取 CA 机构颁发的应用证书文件(.crt其中包含了组织/公司名称、应用公钥、证书有效期等内容,一般有效期为 5 年。
* 支付宝公钥证书:用来验证支付宝消息,包含了支付宝公钥、支付宝公司名称、证书有效期等内容,一般有效期为 5 年。
* 支付宝根证书:用来验证支付宝消息,包含了根 CA 名称、根 CA 的公钥、证书有效期等内容。
*/
/**
* 应用公钥证书SNapp_cert_sn和支付宝根证书SNalipay_root_cert_sn sn 是指什么?
* 使用公钥证书签名方式下, 请求参数中需要携带应用公钥证书SNapp_cert_sn、支付宝根证书SNalipay_root_cert_sn这里的SN是指基于开放平台提供的计算规则动态计算出来的公钥证书序列号与X.509证书中内置的序列号serialNumber不同。
* 具体的计算规则如下解析X.509证书文件获取证书签发机构名称name以及证书内置序列号serialNumber 将name与serialNumber拼接成字符串再对该字符串做MD5计算。
* 可以参考开放平台SDK源码中的 AlipaySignature.getCertSN 方法实现
*
* 不直接使用证书文件中内置的序列号原因开放平台支持开发者上传自己找第三方权威CA签发的证书而证书文件中内置序列号只能保证同一家签发机构签发的证书不重复
*/
return [
// 沙箱模式
'debug' => true,
// 签名类型RSA|RSA2
'sign_type' => "RSA2",
'sign_type' => 'RSA2',
// 应用ID
'appid' => '2016090900468879',
// 应用私钥的内容 (1行填写特别注意这里的应用私钥通常由支付宝密钥管理工具生成)
'private_key' => 'MIIEpAIBAAKCAQEArr8ymPBh/lQ46y76f3VZW4HGV8tClTHJhhlt7BPmn0F8fSc3alKFCiHXIT01ccy3xTPVgcYX26/vvQBt9cJZqxEWapj4hb8BH6lr5BH5MMQ88eyyPLlYicGzt5S4iXUjuImsUguaCO12SoFmM1eaMYKqrELkg3Apbc+16Ktq+puKAohZeozd80NnDc1ossrZtHU1DkUkEJrBeaC7/D+0H/HBHJzc60EMYpvSGgyKzP/ke6xF4ZGilFSKsdoKgS8u7paVMh2SlSO5AsMoELTTlsFS4eYOgD6ZThkBTZZIcyKHM1Wjq6qDfhU3oTkJDYqnLWdtzoqgnUPNQ8nYpYrdeQIDAQABAoIBAQCKWRmH+Bi9MJT3rfPo4VFjnzUW4PfQAuDX6F4coAzgXQpgU6IN7VMjGHOn/zvG4xtDZ6xL2DefWIVnj2V/QuWXCCpFLuLjkLslBA9FO+2b7GGL76eVZ/Bu8AqG95m6SiGDwovJUSIcm1Qh3Jy7XUnYlOjnBPbCERTbuaz9jmleCmOmh4RnpL0DmzvUffNmEuqJfgnF0h2h6CwYBUyGY8G3zpGAyqY+viVPjKA8catcQTqDRywe3ktXxIbi0JqTAYDpb81Ih4NQeHxGMUWHabwij9UTYdPYBgzwVxjcJF4O1cPGdnYeRXm8Neq6L2HbEPRqe/Jiw4i4AB4V3cVWExPhAoGBANWyjP43kguThkFsQZPfDP5xuXIQJ5W24ZcDIwcFYZ5glh+hddHuWsrCf68VHXsf2epeNdqz57xbdtg84FI8N0HmjTCtfuagxXUMPbX4NqqzPqOu2m0T5/b8HCEDV3zWqfMOt+kHR4NytFxLKLwR0a9kypsfZ2z/X4BYXBi6PiZFAoGBANFWw+AL9hJ2q51ePTcZrE788hPepcsdv3OfJjnspykKighTiFgT+m+Kr/AEa9IU/njz/+tcWJuAwOPKDFVd0zVRcxK2Y5WLfo8fYEt6yhq8oa5OKFwInXXVmCPMn0+qduNmZMTzSqL2kaN0U+AH5Te1vlv7I7yuwHDE9vwknBelAoGAbpPN0V3//G2B8yiJZnLszl0akKM7WIUhhnrhDSkDsmhYRlXOGas03+Z1G6vZbXS11kiZpWmiaB0MCii2CteN4FPki2O7XquigUasSBUAdKP7rcc0z2yVg4BBLfQEuVx65IKhN7vEjYg1O+zIT0kJL7EABfTiF8ytJkSSo1j7/+ECgYEA0NPuKHWmLvsE7cKR7IKG2nEIiHvGBl6RmyS7PHNwucdStUWnML4VSOof4p52dKcOx9gYh1Ci79U8FsB7Fzm2tWygD520r/zs7peNNx6xuIROAZTkPBM4CNFfqO66Sf2yBd0iTzqoTPMNi/JCra0So0WBNT7Ngq8NODG0dQmMUSUCgYANC6Y4JIq24nh27jZjTlsVA+jkv5tFK2aKnfRwOYcNhjVNaMyMz5BbvE07zlr/CgViauEMEJorTs+eNY1TEW7ZOOr2lFgbUnT+h/GLCvgwV00nYBEimfIJ96jfIotOLYB74oJJni9wCaJCuurLNfJ0E1XS/8d+1BkFQ+Q7VSDYpg==',
// 支付宝公钥内容 (1行填写特别注意这里不是应用公钥而是支付宝公钥通常是上传应用公钥换取支付宝公钥在网页可以复制)
// 支付宝公钥内容 (需1行填写特别注意这里不是应用公钥而是支付宝公钥通常是上传应用公钥换取支付宝公钥在网页可以复制)
'public_key' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtU71NY53UDGY7JNvLYAhsNa+taTF6KthIHJmGgdio9bkqeJGhHk6ttkTKkLqFgwIfgAkHpdKiOv1uZw6gVGZ7TCu5LfHTqKrCd6Uz+N7hxhY+4IwicLgprcV1flXQLmbkJYzFMZqkXGkSgOsR2yXh4LyQZczgk9N456uuzGtRy7MoB4zQy34PLUkkxR6W1B2ftNbLRGXv6tc7p/cmDcrY6K1bSxnGmfRxFSb8lRfhe0V0UM6pKq2SGGSeovrKHN0OLp+Nn5wcULVnFgATXGCENshRlp96piPEBFwneXs19n+sX1jx60FTR7/rME3sW3AHug0fhZ9mSqW4x401WjdnwIDAQAB',
// 应用公钥的内容(新版资金类接口转 app_cert_sn
'app_cert' => '',
// 支付宝根证书内容(新版资金类接口转 alipay_root_cert_sn
'root_cert' => '',
// 应用私钥的内容 (需1行填写特别注意这里的应用私钥通常由支付宝密钥管理工具生成)
'private_key' => 'MIIEpAIBAAKCAQEArr8ymPBh/lQ46y76f3VZW4HGV8tClTHJhhlt7BPmn0F8fSc3alKFCiHXIT01ccy3xTPVgcYX26/vvQBt9cJZqxEWapj4hb8BH6lr5BH5MMQ88eyyPLlYicGzt5S4iXUjuImsUguaCO12SoFmM1eaMYKqrELkg3Apbc+16Ktq+puKAohZeozd80NnDc1ossrZtHU1DkUkEJrBeaC7/D+0H/HBHJzc60EMYpvSGgyKzP/ke6xF4ZGilFSKsdoKgS8u7paVMh2SlSO5AsMoELTTlsFS4eYOgD6ZThkBTZZIcyKHM1Wjq6qDfhU3oTkJDYqnLWdtzoqgnUPNQ8nYpYrdeQIDAQABAoIBAQCKWRmH+Bi9MJT3rfPo4VFjnzUW4PfQAuDX6F4coAzgXQpgU6IN7VMjGHOn/zvG4xtDZ6xL2DefWIVnj2V/QuWXCCpFLuLjkLslBA9FO+2b7GGL76eVZ/Bu8AqG95m6SiGDwovJUSIcm1Qh3Jy7XUnYlOjnBPbCERTbuaz9jmleCmOmh4RnpL0DmzvUffNmEuqJfgnF0h2h6CwYBUyGY8G3zpGAyqY+viVPjKA8catcQTqDRywe3ktXxIbi0JqTAYDpb81Ih4NQeHxGMUWHabwij9UTYdPYBgzwVxjcJF4O1cPGdnYeRXm8Neq6L2HbEPRqe/Jiw4i4AB4V3cVWExPhAoGBANWyjP43kguThkFsQZPfDP5xuXIQJ5W24ZcDIwcFYZ5glh+hddHuWsrCf68VHXsf2epeNdqz57xbdtg84FI8N0HmjTCtfuagxXUMPbX4NqqzPqOu2m0T5/b8HCEDV3zWqfMOt+kHR4NytFxLKLwR0a9kypsfZ2z/X4BYXBi6PiZFAoGBANFWw+AL9hJ2q51ePTcZrE788hPepcsdv3OfJjnspykKighTiFgT+m+Kr/AEa9IU/njz/+tcWJuAwOPKDFVd0zVRcxK2Y5WLfo8fYEt6yhq8oa5OKFwInXXVmCPMn0+qduNmZMTzSqL2kaN0U+AH5Te1vlv7I7yuwHDE9vwknBelAoGAbpPN0V3//G2B8yiJZnLszl0akKM7WIUhhnrhDSkDsmhYRlXOGas03+Z1G6vZbXS11kiZpWmiaB0MCii2CteN4FPki2O7XquigUasSBUAdKP7rcc0z2yVg4BBLfQEuVx65IKhN7vEjYg1O+zIT0kJL7EABfTiF8ytJkSSo1j7/+ECgYEA0NPuKHWmLvsE7cKR7IKG2nEIiHvGBl6RmyS7PHNwucdStUWnML4VSOof4p52dKcOx9gYh1Ci79U8FsB7Fzm2tWygD520r/zs7peNNx6xuIROAZTkPBM4CNFfqO66Sf2yBd0iTzqoTPMNi/JCra0So0WBNT7Ngq8NODG0dQmMUSUCgYANC6Y4JIq24nh27jZjTlsVA+jkv5tFK2aKnfRwOYcNhjVNaMyMz5BbvE07zlr/CgViauEMEJorTs+eNY1TEW7ZOOr2lFgbUnT+h/GLCvgwV00nYBEimfIJ96jfIotOLYB74oJJni9wCaJCuurLNfJ0E1XS/8d+1BkFQ+Q7VSDYpg==',
// 应用公钥的内容(新版资金类接口转 app_cert_sn如文件 appCertPublicKey_2019051064521003.crt
'app_cert' => '', // 'app_cert_path' => '',
// 支付宝根证书的内容(新版资金类接口转 alipay_root_cert_sn如文件 alipayRootCert.crt
'root_cert' => '', // 'root_cert_path' => ''
// 支付成功通知地址
'notify_url' => '',
// 网页支付回跳地址

View File

@ -199,19 +199,19 @@ try {
```php
$config = [
// 沙箱模式
'debug' => true,
'debug' => true,
// 签名类型RSA|RSA2
'sign_type' => "RSA2",
// 应用ID
'appid' => '2016090900468879',
// 支付宝公钥文字内容 (1行填写特别注意这里是支付宝公钥不是应用公钥最好从开发者中心的网页上去复制)
'public_key' => 'MIIBIjANBgkqhkiG9...',
// 支付宝私钥文字内容 (1行填写)
'private_key' => 'MIIEvQIBADANBgkqh...',
// 应用公钥证书完整内容(新版资金类接口转 app_cert_sn
'app_cert' => '',
// 支付宝根证书完整内容(新版资金类接口转 alipay_root_cert_sn
'root_cert' => '',
'sign_type' => "RSA2",
// 应用APPID
'appid' => '2016090900468879',
// 支付宝公钥内容 (需1行填写特别注意这里不是应用公钥而是支付宝公钥通常是上传应用公钥换取支付宝公钥在网页可以复制)
'public_key' => 'MIIBIjAN...',
// 应用私钥的内容 (需1行填写特别注意这里的应用私钥通常由支付宝密钥管理工具生成)
'private_key' => 'MIIEpAIB...',
// 应用公钥的内容(新版资金类接口转 app_cert_sn如文件 appCertPublicKey_2019051064521003.crt
'app_cert' => '', // 'app_cert_path' => '',
// 支付宝根证书内容(新版资金类接口转 alipay_root_cert_sn,如文件 alipayRootCert.crt
'root_cert' => '', // 'root_cert_path' => ''
// 支付成功通知地址
'notify_url' => '',
// 网页支付回跳地址