This commit is contained in:
yansongda 2021-06-22 23:19:54 +08:00
parent 98d78e579a
commit bcad2419a7
6 changed files with 122 additions and 4 deletions

View File

@ -8,6 +8,11 @@ use Yansongda\Pay\Rocket;
class RequestReceived extends Event
{
/**
* @var string
*/
public $provider;
/**
* @var array|\Psr\Http\Message\ServerRequestInterface|null
*/
@ -25,8 +30,9 @@ class RequestReceived extends Event
*
* @param array|\Psr\Http\Message\ServerRequestInterface|null $contents
*/
public function __construct($contents, ?array $params, ?Rocket $rocket)
public function __construct(string $provider, $contents, ?array $params, ?Rocket $rocket)
{
$this->provider = $provider;
$this->contents = $contents;
$this->params = $params;

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace Yansongda\Pay\Plugin\Wechat;
use Closure;
use Yansongda\Pay\Contract\PluginInterface;
use Yansongda\Pay\Exception\InvalidResponseException;
use Yansongda\Pay\Logger;
use Yansongda\Pay\Parser\NoHttpRequestParser;
use Yansongda\Pay\Rocket;
use Yansongda\Supports\Collection;
class CallbackPlugin implements PluginInterface
{
/**
* @throws \Yansongda\Pay\Exception\ContainerDependencyException
* @throws \Yansongda\Pay\Exception\ContainerException
* @throws \Yansongda\Pay\Exception\InvalidConfigException
* @throws \Yansongda\Pay\Exception\ServiceNotFoundException
* @throws \Yansongda\Pay\Exception\InvalidResponseException
*/
public function assembly(Rocket $rocket, Closure $next): Rocket
{
Logger::info('[alipay][CallbackPlugin] 插件开始装载', ['rocket' => $rocket]);
$this->filterPayload($rocket);
if (!($rocket->getParams()['sign'] ?? false)) {
throw new InvalidResponseException(InvalidResponseException::INVALID_RESPONSE_SIGN, '', $rocket->getParams());
}
if (!verify_alipay_response(
$rocket->getParams(),
$this->getSignContent($rocket->getPayload()),
base64_decode($rocket->getParams()['sign']))
) {
throw new InvalidResponseException(InvalidResponseException::INVALID_RESPONSE_SIGN, '', $rocket->getParams());
}
$rocket->setDirection(NoHttpRequestParser::class)
->setDestination($rocket->getPayload());
Logger::info('[alipay][CallbackPlugin] 插件装载完毕', ['rocket' => $rocket]);
return $next($rocket);
}
protected function filterPayload(Rocket $rocket): void
{
$payload = (new Collection($rocket->getParams()))->filter(function ($v, $k) {
return '' !== $v && !is_null($v) && 'sign' != $k && 'sign_type' != $k;
});
$rocket->setPayload($payload);
}
protected function getSignContent(Collection $payload): string
{
return urldecode($payload->sortKeys()->toString());
}
}

View File

@ -55,7 +55,7 @@ class SignPlugin implements PluginInterface
$config->get('mch_id', ''),
$random,
$timestamp,
$config->get('mch_public_cert_serial_number', ''),
$this->getMchPublicCertSerialNumber($config->get('mch_public_cert_path')),
$this->getSign($rocket, $timestamp, $random)
);
@ -114,4 +114,23 @@ class SignPlugin implements PluginInterface
return get_public_crt_or_private_cert($privateKey);
}
/**
* @throws \Yansongda\Pay\Exception\InvalidConfigException
*/
protected function getMchPublicCertSerialNumber(?string $path): string
{
if (is_null($path)) {
throw new InvalidConfigException(InvalidConfigException::WECHAT_CONFIG_ERROR, 'Missing Wechat Config -- [mch_public_cert_path]');
}
$cert = file_get_contents($path);
$ssl = openssl_x509_parse($cert);
if (empty($ssl['serialNumberHex'])) {
throw new InvalidConfigException(InvalidConfigException::WECHAT_CONFIG_ERROR, 'Parse [mch_public_cert_path] Serial Number Error');
}
return $ssl['serialNumberHex'];
}
}

View File

@ -56,7 +56,7 @@ abstract class AbstractProvider implements ProviderInterface
*/
public function pay(array $plugins, array $params)
{
Logger::info('[AbstractProvider] 即将进行支付操作', func_get_args());
Logger::info('[AbstractProvider] 即将进行 pay 操作', func_get_args());
Event::dispatch(new Event\PayStarted($plugins, $params, null));

View File

@ -117,7 +117,7 @@ class Alipay extends AbstractProvider
*/
public function verify($contents = null, ?array $params = null): Collection
{
Event::dispatch(new Event\RequestReceived($contents, $params, null));
Event::dispatch(new Event\RequestReceived('alipay', $contents, $params, null));
$response = $this->getCallbackParams($contents);

View File

@ -5,12 +5,14 @@ declare(strict_types=1);
namespace Yansongda\Pay\Provider;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Yansongda\Pay\Event;
use Yansongda\Pay\Exception\InvalidParamsException;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Plugin\ParserPlugin;
use Yansongda\Pay\Plugin\Wechat\CallbackPlugin;
use Yansongda\Pay\Plugin\Wechat\LaunchPlugin;
use Yansongda\Pay\Plugin\Wechat\PreparePlugin;
use Yansongda\Pay\Plugin\Wechat\SignPlugin;
@ -103,6 +105,13 @@ class Wechat extends AbstractProvider
*/
public function verify($contents = null, ?array $params = null): Collection
{
Event::dispatch(new Event\RequestReceived('wechat', $contents, $params, null));
$response = $this->getCallbackParams($contents);
return $this->pay(
[CallbackPlugin::class], $response->merge($params)->all()
);
}
public function success(): ResponseInterface
@ -123,4 +132,25 @@ class Wechat extends AbstractProvider
[LaunchPlugin::class, ParserPlugin::class],
);
}
/**
* @param array|ServerRequestInterface|null $contents
*/
protected function getCallbackParams($contents = null): Collection
{
if (is_array($contents)) {
return Collection::wrap($contents);
}
if ($contents instanceof ServerRequestInterface) {
return Collection::wrap('GET' === $contents->getMethod() ? $contents->getQueryParams() :
$contents->getParsedBody());
}
$request = ServerRequest::fromGlobals();
return Collection::wrap(
array_merge($request->getQueryParams(), $request->getParsedBody())
);
}
}