add clear
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace wchat\wx\V3;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
|
||||
class TransferDetail
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
public string $out_detail_no,
|
||||
public int|float $transfer_amount,
|
||||
public string $transfer_remark,
|
||||
public string $openid,
|
||||
public string $user_name
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[ArrayShape(['out_detail_no' => "string", 'transfer_amount' => "float|int", 'transfer_remark' => "string", 'openid' => "string", 'user_name' => "string"])]
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'out_detail_no' => $this->out_detail_no,
|
||||
'transfer_amount' => $this->transfer_amount,
|
||||
'transfer_remark' => $this->transfer_remark,
|
||||
'openid' => $this->openid,
|
||||
'user_name' => $this->user_name,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace wchat\wx\V3;
|
||||
|
||||
use Exception;
|
||||
use Kiri\Client;
|
||||
use wchat\wx\SmallProgram;
|
||||
|
||||
class WxV3AppPayment extends SmallProgram
|
||||
{
|
||||
|
||||
|
||||
use WxV3PaymentTait;
|
||||
|
||||
|
||||
/**
|
||||
* @param $orderNo
|
||||
* @param int $total
|
||||
* @param string|null $openId
|
||||
* @param string $payer_client_ip
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function payment($orderNo, int $total, string $openId = NULL, string $payer_client_ip = '127.0.0.1'): array
|
||||
{
|
||||
$body = $this->getInitCore($orderNo, $total);
|
||||
|
||||
$body['scene_info'] = ['payer_client_ip' => $payer_client_ip];
|
||||
|
||||
$sign = $this->signature('POST', '/v3/pay/transactions/components', $json = json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
$client = new Client('api.mch.weixin.qq.com', 443, TRUE);
|
||||
$client->withAddedHeader('Authorization', $sign)->withContentType('application/json')
|
||||
->withAgent('application/json')->withBody($json)
|
||||
->post('/v3/pay/transactions/components');
|
||||
$client->close();
|
||||
|
||||
$json = json_decode($client->getBody(), TRUE);
|
||||
if (!isset($json['prepay_id'])) {
|
||||
throw new Exception('微信支付调用失败');
|
||||
}
|
||||
return $this->createResponse($json, $body);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace wchat\wx\V3;
|
||||
|
||||
use Exception;
|
||||
use Kiri\Client;
|
||||
use Kiri\Message\Stream;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use wchat\wx\SmallProgram;
|
||||
|
||||
class WxV3NativePayment extends SmallProgram
|
||||
{
|
||||
|
||||
|
||||
use WxV3PaymentTait;
|
||||
|
||||
|
||||
/**
|
||||
* @param $orderNo
|
||||
* @param int $total
|
||||
* @param string|null $openId
|
||||
* @param string $payer_client_ip
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
#[ArrayShape(['code_url' => "string"])]
|
||||
public function payment($orderNo, int $total, string $openId = NULL, string $payer_client_ip = '127.0.0.1'): array
|
||||
{
|
||||
$body = $this->getInitCore($orderNo, $total);
|
||||
|
||||
$sign = $this->signature('POST', '/v3/pay/transactions/native', $json = json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
$client = new Client('api.mch.weixin.qq.com', 443, TRUE);
|
||||
$client->withAddedHeader('Authorization', $sign)->withContentType('application/json')
|
||||
->withAgent('application/json')->withBody(new Stream($json))
|
||||
->post('/v3/pay/transactions/native');
|
||||
$client->close();
|
||||
|
||||
$json = json_decode($client->getBody(), TRUE);
|
||||
if (!isset($json['code_url'])) {
|
||||
throw new Exception('微信支付调用失败');
|
||||
}
|
||||
return ['code_url' => $json['code_url']];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace wchat\wx\V3;
|
||||
|
||||
use Exception;
|
||||
use Kiri\Client;
|
||||
use Kiri\Message\Stream;
|
||||
use wchat\wx\SmallProgram;
|
||||
|
||||
class WxV3Payment extends SmallProgram
|
||||
{
|
||||
|
||||
|
||||
use WxV3PaymentTait;
|
||||
|
||||
|
||||
/**
|
||||
* @param $orderNo
|
||||
* @param int $total
|
||||
* @param string|null $openId
|
||||
* @param string $payer_client_ip
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function payment($orderNo, int $total, string $openId = NULL, string $payer_client_ip = '127.0.0.1'): array
|
||||
{
|
||||
$body = $this->getInitCore($orderNo, $total);
|
||||
$body['payer'] = ['openid' => $openId];
|
||||
$body['scene_info'] = ['payer_client_ip' => $payer_client_ip];
|
||||
|
||||
$sign = $this->signature('POST', '/v3/pay/transactions/jsapi', $json = json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
$client = new Client('api.mch.weixin.qq.com', 443, TRUE);
|
||||
$client->withAddedHeader('Authorization', $sign)
|
||||
->withContentType('application/json')
|
||||
->withAddedHeader('User-Agent', 'application/json')
|
||||
->withBody(new Stream($json))
|
||||
->post('/v3/pay/transactions/jsapi');
|
||||
$client->close();
|
||||
|
||||
$json = json_decode($client->getBody(), TRUE);
|
||||
if (!isset($json['prepay_id'])) {
|
||||
throw new Exception('微信支付调用失败');
|
||||
}
|
||||
|
||||
return $this->createResponse($json, $body);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace wchat\wx\V3;
|
||||
|
||||
use Exception;
|
||||
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 $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
|
||||
{
|
||||
$message = $http_method . "\n" . $canonical_url . "\n" . ($time = time()) . "\n" . ($rand = md5(random_bytes(32))) . "\n" . $body . "\n";
|
||||
|
||||
$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()->getSslCert());
|
||||
|
||||
$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 $associatedData
|
||||
* @param $nonceStr
|
||||
* @param $ciphertext
|
||||
* @return bool|string
|
||||
*/
|
||||
public function decryptToString($associatedData, $nonceStr, $ciphertext): bool|string
|
||||
{
|
||||
$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('aes-256-gcm', \openssl_get_cipher_methods())) {
|
||||
$ctext = substr($ciphertext, 0, -AUTH_TAG_LENGTH_BYTE);
|
||||
$authTag = substr($ciphertext, -AUTH_TAG_LENGTH_BYTE);
|
||||
return \openssl_decrypt($ctext, 'aes-256-gcm', 'XGwwZbmMXy6sD5w0IrxfaBHLl7b7jCaR', \OPENSSL_RAW_DATA, $nonceStr, $authTag, $associatedData);
|
||||
}
|
||||
throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace wchat\wx\V3;
|
||||
|
||||
use Exception;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use Kiri\Client;
|
||||
use Kiri\Message\Stream;
|
||||
use wchat\wx\SmallProgram;
|
||||
|
||||
class WxV3Withdrawal extends SmallProgram
|
||||
{
|
||||
|
||||
|
||||
use WxV3PaymentTait;
|
||||
|
||||
|
||||
/**
|
||||
* @param $orderNo
|
||||
* @param string $batch_name
|
||||
* @param string $batch_remark
|
||||
* @param TransferDetail[] $details
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function payment($orderNo, string $batch_name, string $batch_remark, array $details): array
|
||||
{
|
||||
$body = $this->create($orderNo, $batch_name, $batch_remark, $details);
|
||||
|
||||
$sign = $this->signature('POST', '/v3/pay/transactions/batches', $json = json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
$client = new Client('api.mch.weixin.qq.com', 443, TRUE);
|
||||
$client->withAddedHeader('Authorization', $sign)
|
||||
->withContentType('application/json')
|
||||
->withAddedHeader('User-Agent', 'application/json')
|
||||
->withBody(new Stream($json))
|
||||
->post('/v3/pay/transactions/batches');
|
||||
$client->close();
|
||||
|
||||
$json = json_decode($client->getBody(), TRUE);
|
||||
if (!isset($json['prepay_id'])) {
|
||||
throw new Exception('微信支付调用失败');
|
||||
}
|
||||
|
||||
return $this->createResponse($json, $body);
|
||||
}
|
||||
|
||||
|
||||
#[ArrayShape(['transfer_detail_list' => "array", 'total_amount' => "int", 'total_num' => "int", 'batch_remark' => "string", 'batch_name' => "string", 'out_batch_no' => ""])]
|
||||
private function create($orderNo, string $batch_name, string $batch_remark, array $details): array
|
||||
{
|
||||
$total = 0;
|
||||
$body = ['transfer_detail_list' => []];
|
||||
$body['out_batch_no'] = $orderNo;
|
||||
$body['batch_name'] = $batch_name;
|
||||
$body['batch_remark'] = $batch_remark;
|
||||
$body['total_num'] = count($details);
|
||||
foreach ($details as $detail) {
|
||||
$total += $detail->transfer_amount;
|
||||
$body['transfer_detail_list'][] = $detail->toArray();
|
||||
}
|
||||
$body['total_amount'] = $total;
|
||||
return $body;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user