Files
kiri-wchat/wchat/wx/V3/WxV3PaymentTait.php
T
2023-11-13 21:20:10 +08:00

139 lines
4.9 KiB
PHP

<?php
namespace wchat\wx\V3;
use Exception;
use Kiri\Client;
use wchat\common\Help;
use function Sodium\crypto_aead_aes256gcm_decrypt;
use function Sodium\crypto_aead_aes256gcm_is_available;
const KEY_LENGTH_BYTE = 32;
const AUTH_TAG_LENGTH_BYTE = 16;
trait WxV3PaymentTait
{
/**
* @param $orderNo
* @param $total
* @return array
*/
public function getInitCore($orderNo, $total): array
{
$body['appid'] = $this->getConfig()->getAppid();
$body['mchid'] = $this->getConfig()->getMchId();
$body['description'] = $this->getConfig()->getBody();
$body['out_trade_no'] = $orderNo;
$body['notify_url'] = $this->getConfig()->getNotifyUrl();
$body['amount'] = ['total' => $total, 'currency' => 'CNY'];
return $body;
}
/**
* @param string $sign
* @param string $json
* @return Client
*/
public function createClient(string $sign, string $json): Client
{
$client = new Client('api.mch.weixin.qq.com', 443, TRUE);
$client->withAddedHeader('Authorization', $sign)
->withContentType('application/json')->withAddedHeader('User-Agent', 'application/json')
->withBody($json)->withAddedHeader("Accept", "*/*");
$proxyHost = $this->getConfig()->getProxyHost();
$proxyPort = $this->getConfig()->getProxyPort();
if (!empty($proxyHost) && $proxyPort > 0) {
$client->withProxyHost($proxyHost)->withProxyPort($proxyPort);
}
return $client;
}
/**
* @param string $http_method
* @param string $canonical_url
* @param string $body
* @return string
* @throws Exception
*/
public function signature(string $http_method, string $canonical_url, string $body = ''): string
{
$rand = md5(random_bytes(32));
$time = time();
$message = sprintf("%s\n%s\n%d\n%s\n%s\n", $http_method, $canonical_url, $time, $rand, $body);
$sign = $this->openssl_signature($message);
return sprintf('%s mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $this->getConfig()->getSchema(),
$this->getConfig()->getMchId(), $rand, $time, $this->getConfig()->getSerialNo(), $sign);
}
/**
* @param $body
* @return string
*/
public function openssl_signature($body): string
{
$pem = file_get_contents($this->getConfig()->getMchKey());
$mch_private_key = openssl_get_privatekey($pem);
openssl_sign($body, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
return base64_encode($raw_sign);
}
/**
* @param $json
* @param $body
* @return array
*/
private function createResponse($json, $body): array
{
$responseArray['appId'] = $body['appid'];
$responseArray['timeStamp'] = (string)time();
$responseArray['nonceStr'] = Help::random(32);
$responseArray['package'] = "prepay_id=" . $json['prepay_id'];
$responseBody = $responseArray['appId'] . PHP_EOL . $responseArray['timeStamp'] . PHP_EOL . $responseArray['nonceStr'] . PHP_EOL . $responseArray['package'] . PHP_EOL;
$responseArray['signType'] = 'RSA';
$responseArray['signBody'] = $responseBody;
$responseArray['paySign'] = $this->openssl_signature($responseBody);
$responseArray['prepay_id'] = $json['prepay_id'];
return $responseArray;
}
/**
* @param array $resource
* @return bool|string
*/
public function decryptToString(array $resource): bool|string
{
[$associatedData, $nonceStr, $cipher_algo, $ciphertext] = [$resource['associated_data'], $resource['nonce'], $resource['nonce'], $resource['ciphertext']];
$ciphertext = \base64_decode($ciphertext);
if (strlen($ciphertext) <= AUTH_TAG_LENGTH_BYTE) {
return FALSE;
}
if (function_exists('\sodium\crypto_aead_aes256gcm_is_available') && crypto_aead_aes256gcm_is_available()) {
return crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, 'XGwwZbmMXy6sD5w0IrxfaBHLl7b7jCaR');
}
if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && crypto_aead_aes256gcm_is_available()) {
return crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, 'XGwwZbmMXy6sD5w0IrxfaBHLl7b7jCaR');
}
if (PHP_VERSION_ID >= 70100 && in_array($cipher_algo, \openssl_get_cipher_methods())) {
$ctext = substr($ciphertext, 0, -AUTH_TAG_LENGTH_BYTE);
$authTag = substr($ciphertext, -AUTH_TAG_LENGTH_BYTE);
return \openssl_decrypt($ctext, $cipher_algo, 'XGwwZbmMXy6sD5w0IrxfaBHLl7b7jCaR', \OPENSSL_RAW_DATA, $nonceStr, $authTag, $associatedData);
}
throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
}
}