Files

176 lines
6.5 KiB
PHP
Raw Permalink Normal View History

2023-11-13 21:20:10 +08:00
<?php
namespace wchat\wx\V3;
use Exception;
2023-11-13 22:57:36 +08:00
use OpenSSLAsymmetricKey;
2023-11-13 22:13:44 +08:00
use Psr\Http\Message\RequestInterface;
2023-11-13 21:20:10 +08:00
use wchat\wx\SmallProgram;
use wchat\wx\V3\Notify\GoodsDetail;
use wchat\wx\V3\Notify\NotifyModel;
use wchat\wx\V3\Notify\PromotionDetail;
2023-11-13 22:37:49 +08:00
const KEY_TYPE_PUBLIC = 'public';
const KEY_TYPE_PRIVATE = 'private';
2023-11-13 22:13:44 +08:00
2023-11-13 21:20:10 +08:00
class WxV3PaymentNotify extends SmallProgram
{
use WxV3PaymentTait;
/**
* @param string $id
* @param string $create_time
* @param string $resource_type
* @param string $event_type
* @param string $summary
* @param array $resource
*/
public function __construct(
2023-11-14 14:10:36 +08:00
public string $id = "EV-2018022511223320873",
public string $create_time = "2015-05-20T13:29:35+08:00",
public string $resource_type = "encrypt-resource",
public string $event_type = "TRANSACTION.SUCCESS",
public string $summary = "支付成功",
public array $resource = []
2023-11-13 21:20:10 +08:00
)
{
}
/**
* @var NotifyModel
*/
public NotifyModel $notifyModel;
2023-11-13 22:13:44 +08:00
/**
* @param RequestInterface $request
* @return bool
2023-12-12 15:35:37 +08:00
* @throws
2023-11-13 22:13:44 +08:00
*/
public function verify(RequestInterface $request): bool
{
2024-06-03 11:41:26 +08:00
$platformPublicKeyInstance = $this->rsaFrom($this->payConfig->pay->wx->mchKey, KEY_TYPE_PUBLIC);
2024-06-03 11:11:48 +08:00
$inWechatpaySignature = $request->getHeaderLine('wechatpay-signature'); // 请根据实际情况获取
$inWechatpayTimestamp = $request->getHeaderLine('wechatpay-timestamp'); // 请根据实际情况获取
$inWechatpayNonce = $request->getHeaderLine('wechatpay-nonce'); // 请根据实际情况获取
2023-11-13 22:42:26 +08:00
$inBody = $request->getBody()->getContents(); // 请根据实际情况获取,例如: file_get_contents('php://input');
2023-11-13 22:14:14 +08:00
$timeOffsetStatus = 300 >= abs(time() - (int)$inWechatpayTimestamp);
$verifiedStatus = $this->notifyVerify(
2024-06-03 11:41:26 +08:00
$this->lineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
2023-11-13 22:14:14 +08:00
$inWechatpaySignature,
$platformPublicKeyInstance);
2025-02-18 09:09:32 +08:00
$this->decode($this->resource['ciphertext'], $this->resource['nonce'], $this->resource['associated_data']);
2023-11-13 22:13:44 +08:00
if (!$timeOffsetStatus || !$verifiedStatus) {
return false;
2025-02-18 09:09:32 +08:00
} else {
return true;
2023-11-13 22:13:44 +08:00
}
}
/**
* @param ...$pieces
* @return string
*/
protected function lineFeed(...$pieces): string
{
return implode("\n", array_merge($pieces, ['']));
}
/**
* @return string|bool
*/
protected function body(): string|bool
{
return json_encode(['id' => $this->id, 'create_time' => $this->create_time, 'resource_type' => $this->resource_type, 'event_type' => $this->event_type, 'summary' => $this->summary, 'resource' => $this->resource]);
}
/**
* @param string $message
* @param string $signature
2023-11-14 14:10:36 +08:00
* @param OpenSSLAsymmetricKey $publicKey
2023-11-13 22:13:44 +08:00
* @return bool
*/
2023-11-14 14:10:36 +08:00
protected function notifyVerify(string $message, string $signature, OpenSSLAsymmetricKey $publicKey): bool
2023-11-13 22:13:44 +08:00
{
if (($result = openssl_verify($message, base64_decode($signature), $publicKey, OPENSSL_ALGO_SHA256)) === false) {
throw new \UnexpectedValueException('Verified the input $message failed, please checking your $publicKey whether or nor correct.');
}
return $result === 1;
}
/**
2023-11-14 14:10:36 +08:00
* @param string $thing
2023-11-13 22:13:44 +08:00
* @param string $type
2023-11-13 22:57:36 +08:00
* @return OpenSSLAsymmetricKey
2023-11-13 22:13:44 +08:00
*/
2023-11-14 14:10:36 +08:00
protected function rsaFrom(string $thing, string $type = KEY_TYPE_PRIVATE): OpenSSLAsymmetricKey
2023-11-13 22:13:44 +08:00
{
2024-06-03 11:07:46 +08:00
$pkey = (($isPublic = $type === KEY_TYPE_PUBLIC) ? openssl_pkey_get_public('file://' . $thing) : openssl_pkey_get_private('file://' . $thing));
2023-11-13 22:13:44 +08:00
if (false === $pkey) {
2023-11-13 22:57:36 +08:00
throw new \UnexpectedValueException(sprintf('Cannot load %s from(%s), please take care about the $thing input.', $isPublic ? 'publicKey' : 'privateKey', gettype($thing)));
2023-11-13 22:13:44 +08:00
}
return $pkey;
}
2023-11-13 21:20:10 +08:00
/**
2023-11-14 14:10:36 +08:00
* @param string $ciphertext
* @param string $nonce
* @param string $associated_data
2023-11-13 22:37:49 +08:00
* @return bool
2023-11-13 21:20:10 +08:00
*/
2023-11-14 14:10:36 +08:00
public function decode(string $ciphertext, string $nonce, string $associated_data): bool
2023-11-13 21:20:10 +08:00
{
2023-11-14 00:06:57 +08:00
$data = $this->decrypt($ciphertext, $this->payConfig->pay->wx->secret, $nonce, $associated_data);
2023-11-13 21:20:10 +08:00
$this->notifyModel = new NotifyModel();
$this->notifyModel->amount = $data['amount'];
$this->notifyModel->payer = $data['payer'];
$this->notifyModel->scene_info = $data['payer'];
$this->notifyModel->appid = $data['appid'];
$this->notifyModel->mchid = $data['mchid'];
$this->notifyModel->out_trade_no = $data['out_trade_no'];
$this->notifyModel->transaction_id = $data['transaction_id'];
$this->notifyModel->trade_type = $data['trade_type'];
$this->notifyModel->trade_state = $data['trade_state'];
$this->notifyModel->trade_state_desc = $data['trade_state_desc'];
$this->notifyModel->bank_type = $data['bank_type'];
$this->notifyModel->attach = $data['attach'];
$this->notifyModel->success_time = $data['success_time'];
$this->notifyModel->promotion_detail = [];
2024-06-03 11:58:53 +08:00
if (!isset($data['promotion_detail'])) {
return true;
}
2023-11-13 21:20:10 +08:00
foreach ($data['promotion_detail'] as $datum) {
$detail = new PromotionDetail();
$detail->amount = $datum['amount'];
$detail->wechatpay_contribute = $datum['wechatpay_contribute'];
$detail->coupon_id = $datum['coupon_id'];
$detail->scope = $datum['scope'];
$detail->merchant_contribute = $datum['merchant_contribute'];
$detail->name = $datum['name'];
$detail->other_contribute = $datum['other_contribute'];
$detail->currency = $datum['currency'];
$detail->stock_id = $datum['stock_id'];
$detail->goods_detail = [];
2024-06-03 11:58:53 +08:00
if (isset($data['goods_detail'])) {
foreach ($datum['goods_detail'] as $value) {
$detail->goods_detail[] = new GoodsDetail($value);
}
2023-11-13 21:20:10 +08:00
}
$this->notifyModel->promotion_detail[] = $detail;
}
2023-11-13 22:37:49 +08:00
return true;
2023-11-13 21:20:10 +08:00
}
2025-02-18 09:09:32 +08:00
}