代码初始化
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
interface ConfigInterface
|
||||
{
|
||||
/**
|
||||
* @param mixed $default default value of the entry when does not found
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, $default = null);
|
||||
|
||||
public function has(string $key): bool;
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set(string $key, $value): void;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
interface ContainerInterface extends \Psr\Container\ContainerInterface
|
||||
{
|
||||
/**
|
||||
* factory make.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function make(string $name, array $parameters = []);
|
||||
|
||||
/**
|
||||
* @param mixed $entry
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function set(string $name, $entry);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface DirectionInterface
|
||||
{
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function parse(PackerInterface $packer, ?ResponseInterface $response);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
interface EventDispatcherInterface extends \Psr\EventDispatcher\EventDispatcherInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
|
||||
interface HttpClientInterface extends ClientInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
interface LoggerInterface extends \Psr\Log\LoggerInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
interface PackerInterface
|
||||
{
|
||||
public function pack(array $payload): string;
|
||||
|
||||
public function unpack(string $payload): ?array;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
interface PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\InvalidParamsException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Supports\Collection;
|
||||
|
||||
interface ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @return null|array|Collection|MessageInterface
|
||||
*
|
||||
* @throws ContainerException
|
||||
* @throws InvalidParamsException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function pay(array $plugins, array $params);
|
||||
|
||||
/**
|
||||
* @param array|string $order
|
||||
*
|
||||
* @return array|Collection
|
||||
*/
|
||||
public function find($order);
|
||||
|
||||
/**
|
||||
* @param array|string $order
|
||||
*
|
||||
* @return array|Collection|void
|
||||
*/
|
||||
public function cancel($order);
|
||||
|
||||
/**
|
||||
* @param array|string $order
|
||||
*
|
||||
* @return array|Collection|void
|
||||
*/
|
||||
public function close($order);
|
||||
|
||||
/**
|
||||
* @return array|Collection
|
||||
*/
|
||||
public function refund(array $order);
|
||||
|
||||
/**
|
||||
* @param null|array|ServerRequestInterface $contents
|
||||
*/
|
||||
public function callback($contents = null, ?array $params = null): Collection;
|
||||
|
||||
public function success(): ResponseInterface;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
|
||||
interface ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* @param mixed $data
|
||||
*
|
||||
* @throws ContainerException
|
||||
*/
|
||||
public function register($data = null): void;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Contract;
|
||||
|
||||
interface ShortcutInterface
|
||||
{
|
||||
/**
|
||||
* @return PluginInterface[]|string[]
|
||||
*/
|
||||
public function getPlugins(array $params): array;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Direction;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Yansongda\Pay\Contract\DirectionInterface;
|
||||
use Yansongda\Pay\Contract\PackerInterface;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidResponseException;
|
||||
|
||||
class ArrayDirection implements DirectionInterface
|
||||
{
|
||||
/**
|
||||
* @throws InvalidResponseException
|
||||
*/
|
||||
public function parse(PackerInterface $packer, ?ResponseInterface $response): array
|
||||
{
|
||||
if (is_null($response)) {
|
||||
throw new InvalidResponseException(Exception::RESPONSE_NONE);
|
||||
}
|
||||
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
if (!is_null($result = $packer->unpack($body))) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
throw new InvalidResponseException(Exception::UNPACK_RESPONSE_ERROR, 'Unpack Response Error', ['body' => $body, 'response' => $response]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Direction;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Yansongda\Pay\Contract\DirectionInterface;
|
||||
use Yansongda\Pay\Contract\PackerInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Pay;
|
||||
use Yansongda\Supports\Collection;
|
||||
|
||||
class CollectionDirection implements DirectionInterface
|
||||
{
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function parse(PackerInterface $packer, ?ResponseInterface $response): Collection
|
||||
{
|
||||
return new Collection(
|
||||
Pay::get(ArrayDirection::class)->parse($packer, $response)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Direction;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Yansongda\Pay\Contract\DirectionInterface;
|
||||
use Yansongda\Pay\Contract\PackerInterface;
|
||||
|
||||
class NoHttpRequestDirection implements DirectionInterface
|
||||
{
|
||||
public function parse(PackerInterface $packer, ?ResponseInterface $response): ?ResponseInterface
|
||||
{
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Direction;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Yansongda\Pay\Contract\DirectionInterface;
|
||||
use Yansongda\Pay\Contract\PackerInterface;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidResponseException;
|
||||
|
||||
class OriginResponseDirection implements DirectionInterface
|
||||
{
|
||||
/**
|
||||
* @throws InvalidResponseException
|
||||
*/
|
||||
public function parse(PackerInterface $packer, ?ResponseInterface $response): ?ResponseInterface
|
||||
{
|
||||
if (!is_null($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
throw new InvalidResponseException(Exception::INVALID_RESPONSE_CODE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Direction;
|
||||
|
||||
class ResponseDirection extends NoHttpRequestDirection
|
||||
{
|
||||
}
|
||||
38
addons/epay/library/v3/Yansongda/Pay/Event.php
Normal file
38
addons/epay/library/v3/Yansongda/Pay/Event.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay;
|
||||
|
||||
use Yansongda\Pay\Contract\EventDispatcherInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
|
||||
/**
|
||||
* @method static Event\Event dispatch(object $event)
|
||||
*/
|
||||
class Event
|
||||
{
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
public static function __callStatic(string $method, array $args): void
|
||||
{
|
||||
if (!Pay::hasContainer() || !Pay::has(EventDispatcherInterface::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$class = Pay::get(EventDispatcherInterface::class);
|
||||
|
||||
if ($class instanceof \Psr\EventDispatcher\EventDispatcherInterface) {
|
||||
$class->{$method}(...$args);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new InvalidConfigException(Exception\Exception::EVENT_CONFIG_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Event;
|
||||
|
||||
class ApiRequested extends Event
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Event;
|
||||
|
||||
class ApiRequesting extends Event
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Event;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
class CallbackReceived extends Event
|
||||
{
|
||||
public string $provider;
|
||||
|
||||
public ?array $params = null;
|
||||
|
||||
/**
|
||||
* @var null|array|ServerRequestInterface
|
||||
*/
|
||||
public $contents;
|
||||
|
||||
/**
|
||||
* @param null|array|ServerRequestInterface $contents
|
||||
*/
|
||||
public function __construct(string $provider, $contents, ?array $params = null, ?Rocket $rocket = null)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
$this->contents = $contents;
|
||||
$this->params = $params;
|
||||
|
||||
parent::__construct($rocket);
|
||||
}
|
||||
}
|
||||
17
addons/epay/library/v3/Yansongda/Pay/Event/Event.php
Normal file
17
addons/epay/library/v3/Yansongda/Pay/Event/Event.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Event;
|
||||
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
class Event
|
||||
{
|
||||
public ?Rocket $rocket = null;
|
||||
|
||||
public function __construct(?Rocket $rocket = null)
|
||||
{
|
||||
$this->rocket = $rocket;
|
||||
}
|
||||
}
|
||||
25
addons/epay/library/v3/Yansongda/Pay/Event/MethodCalled.php
Normal file
25
addons/epay/library/v3/Yansongda/Pay/Event/MethodCalled.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Event;
|
||||
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
class MethodCalled extends Event
|
||||
{
|
||||
public string $provider;
|
||||
|
||||
public string $name;
|
||||
|
||||
public array $params;
|
||||
|
||||
public function __construct(string $provider, string $name, array $params, ?Rocket $rocket = null)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
$this->name = $name;
|
||||
$this->params = $params;
|
||||
|
||||
parent::__construct($rocket);
|
||||
}
|
||||
}
|
||||
9
addons/epay/library/v3/Yansongda/Pay/Event/PayFinish.php
Normal file
9
addons/epay/library/v3/Yansongda/Pay/Event/PayFinish.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Event;
|
||||
|
||||
class PayFinish extends Event
|
||||
{
|
||||
}
|
||||
26
addons/epay/library/v3/Yansongda/Pay/Event/PayStarted.php
Normal file
26
addons/epay/library/v3/Yansongda/Pay/Event/PayStarted.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Event;
|
||||
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
class PayStarted extends Event
|
||||
{
|
||||
/**
|
||||
* @var PluginInterface[]
|
||||
*/
|
||||
public array $plugins;
|
||||
|
||||
public array $params;
|
||||
|
||||
public function __construct(array $plugins, array $params, ?Rocket $rocket = null)
|
||||
{
|
||||
$this->plugins = $plugins;
|
||||
$this->params = $params;
|
||||
|
||||
parent::__construct($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Exception;
|
||||
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Throwable;
|
||||
|
||||
class ContainerException extends Exception implements ContainerExceptionInterface
|
||||
{
|
||||
/**
|
||||
* @param mixed $extra
|
||||
*/
|
||||
public function __construct(string $message = '', int $code = self::CONTAINER_ERROR, $extra = null, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $extra, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class ContainerNotFoundException extends ContainerException
|
||||
{
|
||||
/**
|
||||
* @param mixed $extra
|
||||
*/
|
||||
public function __construct(string $message = 'Container Not Found', int $code = self::CONTAINER_NOT_FOUND, $extra = null, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $extra, $previous);
|
||||
}
|
||||
}
|
||||
114
addons/epay/library/v3/Yansongda/Pay/Exception/Exception.php
Normal file
114
addons/epay/library/v3/Yansongda/Pay/Exception/Exception.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
public const UNKNOWN_ERROR = 9999;
|
||||
|
||||
/**
|
||||
* 关于容器.
|
||||
*/
|
||||
public const CONTAINER_ERROR = 1000;
|
||||
|
||||
public const CONTAINER_NOT_FOUND = 1001;
|
||||
|
||||
public const CONTAINER_NOT_FOUND_ENTRY = 1002;
|
||||
|
||||
/**
|
||||
* 关于容器的服务.
|
||||
*/
|
||||
public const SERVICE_ERROR = 2000;
|
||||
|
||||
public const SERVICE_NOT_FOUND_ERROR = 2001;
|
||||
|
||||
/*
|
||||
* 关于配置.
|
||||
*/
|
||||
public const CONFIG_ERROR = 3000;
|
||||
|
||||
public const INVALID_PARSER = 3001;
|
||||
|
||||
public const ALIPAY_CONFIG_ERROR = 3002;
|
||||
|
||||
public const LOGGER_CONFIG_ERROR = 3003;
|
||||
|
||||
public const HTTP_CLIENT_CONFIG_ERROR = 3004;
|
||||
|
||||
public const EVENT_CONFIG_ERROR = 3005;
|
||||
|
||||
public const WECHAT_CONFIG_ERROR = 3006;
|
||||
|
||||
public const UNIPAY_CONFIG_ERROR = 3007;
|
||||
|
||||
public const INVALID_PACKER = 3008;
|
||||
|
||||
/*
|
||||
* 关于参数.
|
||||
*/
|
||||
public const PARAMS_ERROR = 4000;
|
||||
|
||||
public const SHORTCUT_NOT_FOUND = 4001;
|
||||
|
||||
public const PLUGIN_ERROR = 4002;
|
||||
|
||||
public const SHORTCUT_MULTI_ACTION_ERROR = 4003;
|
||||
|
||||
public const METHOD_NOT_SUPPORTED = 4004;
|
||||
|
||||
public const REQUEST_NULL_ERROR = 4005;
|
||||
|
||||
public const MISSING_NECESSARY_PARAMS = 4006;
|
||||
|
||||
public const NOT_IN_SERVICE_MODE = 4007;
|
||||
|
||||
public const WECHAT_SERIAL_NO_NOT_FOUND = 4008;
|
||||
|
||||
public const UNIPAY_FIND_STRING_NOT_SUPPORTED = 4009;
|
||||
|
||||
public const UNIPAY_CANCEL_STRING_NOT_SUPPORTED = 4010;
|
||||
|
||||
/**
|
||||
* 关于api.
|
||||
*/
|
||||
public const RESPONSE_ERROR = 5000;
|
||||
|
||||
public const REQUEST_RESPONSE_ERROR = 5001;
|
||||
|
||||
public const UNPACK_RESPONSE_ERROR = 5002;
|
||||
|
||||
public const INVALID_RESPONSE_SIGN = 5003;
|
||||
|
||||
public const INVALID_RESPONSE_CODE = 5004;
|
||||
|
||||
public const RESPONSE_MISSING_NECESSARY_PARAMS = 5005;
|
||||
|
||||
public const RESPONSE_NONE = 5006;
|
||||
|
||||
public const INVALID_CIPHERTEXT_PARAMS = 5007;
|
||||
|
||||
public const INVALID_REQUEST_ENCRYPTED_DATA = 5008;
|
||||
|
||||
public const INVALID_REQUEST_ENCRYPTED_METHOD = 5009;
|
||||
|
||||
/**
|
||||
* raw.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $extra;
|
||||
|
||||
/**
|
||||
* @param mixed $extra
|
||||
*/
|
||||
public function __construct(string $message = 'Unknown Error', int $code = self::UNKNOWN_ERROR, $extra = null, Throwable $previous = null)
|
||||
{
|
||||
$this->extra = $extra;
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class InvalidConfigException extends Exception
|
||||
{
|
||||
/**
|
||||
* @param mixed $extra
|
||||
*/
|
||||
public function __construct(int $code = self::CONFIG_ERROR, string $message = 'Config Error', $extra = null, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $extra, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class InvalidParamsException extends Exception
|
||||
{
|
||||
/**
|
||||
* @param mixed $extra
|
||||
*/
|
||||
public function __construct(int $code = self::PARAMS_ERROR, string $message = 'Params Error', $extra = null, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $extra, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class InvalidResponseException extends Exception
|
||||
{
|
||||
public ?Throwable $exception = null;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $response;
|
||||
|
||||
/**
|
||||
* @param mixed $extra
|
||||
*/
|
||||
public function __construct(
|
||||
int $code = self::RESPONSE_ERROR,
|
||||
string $message = 'Provider response Error',
|
||||
$extra = null,
|
||||
?Throwable $exception = null,
|
||||
Throwable $previous = null
|
||||
) {
|
||||
$this->response = $extra;
|
||||
$this->exception = $exception;
|
||||
|
||||
parent::__construct($message, $code, $extra, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class ServiceException extends Exception
|
||||
{
|
||||
/**
|
||||
* @param mixed $extra
|
||||
*/
|
||||
public function __construct(string $message = 'Service Error', int $code = self::SERVICE_ERROR, $extra = null, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $extra, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Exception;
|
||||
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Throwable;
|
||||
|
||||
class ServiceNotFoundException extends Exception implements NotFoundExceptionInterface
|
||||
{
|
||||
/**
|
||||
* @param mixed $extra
|
||||
*/
|
||||
public function __construct(string $message = 'Service Not Found', int $code = self::SERVICE_NOT_FOUND_ERROR, $extra = null, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $extra, $previous);
|
||||
}
|
||||
}
|
||||
403
addons/epay/library/v3/Yansongda/Pay/Functions.php
Normal file
403
addons/epay/library/v3/Yansongda/Pay/Functions.php
Normal file
@@ -0,0 +1,403 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay;
|
||||
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Yansongda\Pay\Contract\ConfigInterface;
|
||||
use Yansongda\Pay\Direction\NoHttpRequestDirection;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\InvalidParamsException;
|
||||
use Yansongda\Pay\Exception\InvalidResponseException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Plugin\ParserPlugin;
|
||||
use Yansongda\Pay\Plugin\Wechat\PreparePlugin;
|
||||
use Yansongda\Pay\Plugin\Wechat\RadarSignPlugin;
|
||||
use Yansongda\Pay\Plugin\Wechat\WechatPublicCertsPlugin;
|
||||
use Yansongda\Pay\Provider\Wechat;
|
||||
use Yansongda\Supports\Str;
|
||||
|
||||
if (!function_exists('should_do_http_request')) {
|
||||
function should_do_http_request(string $direction): bool
|
||||
{
|
||||
return NoHttpRequestDirection::class !== $direction
|
||||
&& !in_array(NoHttpRequestDirection::class, class_parents($direction));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_tenant')) {
|
||||
function get_tenant(array $params = []): string
|
||||
{
|
||||
return strval($params['_config'] ?? 'default');
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_alipay_config')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
function get_alipay_config(array $params = []): array
|
||||
{
|
||||
$alipay = Pay::get(ConfigInterface::class)->get('alipay');
|
||||
|
||||
return $alipay[get_tenant($params)] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_public_cert')) {
|
||||
function get_public_cert(string $key): string
|
||||
{
|
||||
return Str::endsWith($key, ['.cer', '.crt', '.pem']) ? file_get_contents($key) : $key;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_private_cert')) {
|
||||
function get_private_cert(string $key): string
|
||||
{
|
||||
if (Str::endsWith($key, ['.crt', '.pem'])) {
|
||||
return file_get_contents($key);
|
||||
}
|
||||
|
||||
return "-----BEGIN RSA PRIVATE KEY-----\n".
|
||||
wordwrap($key, 64, "\n", true).
|
||||
"\n-----END RSA PRIVATE KEY-----";
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('verify_alipay_sign')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidResponseException
|
||||
*/
|
||||
function verify_alipay_sign(array $params, string $contents, string $sign): void
|
||||
{
|
||||
$public = get_alipay_config($params)['alipay_public_cert_path'] ?? null;
|
||||
|
||||
if (empty($public)) {
|
||||
throw new InvalidConfigException(Exception::ALIPAY_CONFIG_ERROR, 'Missing Alipay Config -- [alipay_public_cert_path]');
|
||||
}
|
||||
|
||||
// 优化publickey判断
|
||||
if (!Str::endsWith($public, ['.cer', '.crt', '.pem']) && stripos($public, '-----BEGIN PUBLIC KEY-----') === false) {
|
||||
$public = "-----BEGIN PUBLIC KEY-----\n".
|
||||
wordwrap($public, 64, "\n", true).
|
||||
"\n-----END PUBLIC KEY-----";
|
||||
}
|
||||
|
||||
$result = 1 === openssl_verify(
|
||||
$contents,
|
||||
base64_decode($sign),
|
||||
get_public_cert($public),
|
||||
OPENSSL_ALGO_SHA256
|
||||
);
|
||||
|
||||
if (!$result) {
|
||||
throw new InvalidResponseException(Exception::INVALID_RESPONSE_SIGN, 'Verify Alipay Response Sign Failed', func_get_args());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_wechat_config')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
function get_wechat_config(array $params): array
|
||||
{
|
||||
$wechat = Pay::get(ConfigInterface::class)->get('wechat');
|
||||
|
||||
return $wechat[get_tenant($params)] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_wechat_base_uri')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
function get_wechat_base_uri(array $params): string
|
||||
{
|
||||
$config = get_wechat_config($params);
|
||||
|
||||
return Wechat::URL[$config['mode'] ?? Pay::MODE_NORMAL];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_wechat_sign')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
function get_wechat_sign(array $params, string $contents): string
|
||||
{
|
||||
$privateKey = get_wechat_config($params)['mch_secret_cert'] ?? null;
|
||||
|
||||
if (empty($privateKey)) {
|
||||
throw new InvalidConfigException(Exception::WECHAT_CONFIG_ERROR, 'Missing Wechat Config -- [mch_secret_cert]');
|
||||
}
|
||||
|
||||
$privateKey = get_private_cert($privateKey);
|
||||
|
||||
openssl_sign($contents, $sign, $privateKey, 'sha256WithRSAEncryption');
|
||||
|
||||
return base64_encode($sign);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_wechat_sign_v2')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
function get_wechat_sign_v2(array $params, array $payload, bool $upper = true): string
|
||||
{
|
||||
$key = get_wechat_config($params)['mch_secret_key_v2'] ?? null;
|
||||
|
||||
if (empty($key)) {
|
||||
throw new InvalidConfigException(Exception::WECHAT_CONFIG_ERROR, 'Missing Wechat Config -- [mch_secret_key_v2]');
|
||||
}
|
||||
|
||||
ksort($payload);
|
||||
|
||||
$buff = '';
|
||||
|
||||
foreach ($payload as $k => $v) {
|
||||
$buff .= ('sign' != $k && '' != $v && !is_array($v)) ? $k.'='.$v.'&' : '';
|
||||
}
|
||||
|
||||
$sign = md5($buff.'key='.$key);
|
||||
|
||||
return $upper ? strtoupper($sign) : $sign;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('verify_wechat_sign')) {
|
||||
/**
|
||||
* @param ResponseInterface|ServerRequestInterface $message
|
||||
*
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws InvalidResponseException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidParamsException
|
||||
*/
|
||||
function verify_wechat_sign(MessageInterface $message, array $params): void
|
||||
{
|
||||
if ($message instanceof ServerRequestInterface && 'localhost' === $message->getUri()->getHost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wechatSerial = $message->getHeaderLine('Wechatpay-Serial');
|
||||
$timestamp = $message->getHeaderLine('Wechatpay-Timestamp');
|
||||
$random = $message->getHeaderLine('Wechatpay-Nonce');
|
||||
$sign = $message->getHeaderLine('Wechatpay-Signature');
|
||||
$body = (string) $message->getBody();
|
||||
|
||||
$content = $timestamp."\n".$random."\n".$body."\n";
|
||||
$public = get_wechat_config($params)['wechat_public_cert_path'][$wechatSerial] ?? null;
|
||||
|
||||
if (empty($sign)) {
|
||||
throw new InvalidResponseException(Exception::INVALID_RESPONSE_SIGN, '', ['headers' => $message->getHeaders(), 'body' => $body]);
|
||||
}
|
||||
|
||||
$public = get_public_cert(
|
||||
empty($public) ? reload_wechat_public_certs($params, $wechatSerial) : $public
|
||||
);
|
||||
|
||||
$result = 1 === openssl_verify(
|
||||
$content,
|
||||
base64_decode($sign),
|
||||
$public,
|
||||
'sha256WithRSAEncryption'
|
||||
);
|
||||
|
||||
if (!$result) {
|
||||
throw new InvalidResponseException(Exception::INVALID_RESPONSE_SIGN, '', ['headers' => $message->getHeaders(), 'body' => $body]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('encrypt_wechat_contents')) {
|
||||
function encrypt_wechat_contents(string $contents, string $publicKey): ?string
|
||||
{
|
||||
if (openssl_public_encrypt($contents, $encrypted, get_public_cert($publicKey), OPENSSL_PKCS1_OAEP_PADDING)) {
|
||||
return base64_encode($encrypted);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('reload_wechat_public_certs')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidParamsException
|
||||
* @throws InvalidResponseException
|
||||
*/
|
||||
function reload_wechat_public_certs(array $params, ?string $serialNo = null): string
|
||||
{
|
||||
$data = Pay::wechat()->pay(
|
||||
[PreparePlugin::class, WechatPublicCertsPlugin::class, RadarSignPlugin::class, ParserPlugin::class],
|
||||
$params
|
||||
)->get('data', []);
|
||||
|
||||
foreach ($data as $item) {
|
||||
$certs[$item['serial_no']] = decrypt_wechat_resource($item['encrypt_certificate'], $params)['ciphertext'] ?? '';
|
||||
}
|
||||
|
||||
$wechatConfig = get_wechat_config($params);
|
||||
|
||||
Pay::get(ConfigInterface::class)->set(
|
||||
'wechat.'.get_tenant($params).'.wechat_public_cert_path',
|
||||
((array) ($wechatConfig['wechat_public_cert_path'] ?? [])) + ($certs ?? [])
|
||||
);
|
||||
|
||||
if (!is_null($serialNo) && empty($certs[$serialNo])) {
|
||||
throw new InvalidConfigException(Exception::WECHAT_CONFIG_ERROR, 'Get Wechat Public Cert Error');
|
||||
}
|
||||
|
||||
return $certs[$serialNo] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_wechat_public_certs')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidParamsException
|
||||
* @throws InvalidResponseException
|
||||
*/
|
||||
function get_wechat_public_certs(array $params = [], ?string $path = null): void
|
||||
{
|
||||
reload_wechat_public_certs($params);
|
||||
|
||||
$config = get_wechat_config($params);
|
||||
|
||||
if (empty($path)) {
|
||||
var_dump($config['wechat_public_cert_path']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($config['wechat_public_cert_path'] as $serialNo => $cert) {
|
||||
file_put_contents($path.'/'.$serialNo.'.crt', $cert);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('decrypt_wechat_resource')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws InvalidResponseException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
function decrypt_wechat_resource(array $resource, array $params): array
|
||||
{
|
||||
$ciphertext = base64_decode($resource['ciphertext'] ?? '');
|
||||
$secret = get_wechat_config($params)['mch_secret_key'] ?? null;
|
||||
|
||||
if (strlen($ciphertext) <= Wechat::AUTH_TAG_LENGTH_BYTE) {
|
||||
throw new InvalidResponseException(Exception::INVALID_CIPHERTEXT_PARAMS);
|
||||
}
|
||||
|
||||
if (is_null($secret) || Wechat::MCH_SECRET_KEY_LENGTH_BYTE != strlen($secret)) {
|
||||
throw new InvalidConfigException(Exception::WECHAT_CONFIG_ERROR, 'Missing Wechat Config -- [mch_secret_key]');
|
||||
}
|
||||
|
||||
switch ($resource['algorithm'] ?? '') {
|
||||
case 'AEAD_AES_256_GCM':
|
||||
$resource['ciphertext'] = decrypt_wechat_resource_aes_256_gcm($ciphertext, $secret, $resource['nonce'] ?? '', $resource['associated_data'] ?? '');
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidResponseException(Exception::INVALID_REQUEST_ENCRYPTED_METHOD);
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('decrypt_wechat_resource_aes_256_gcm')) {
|
||||
/**
|
||||
* @return array|string
|
||||
*
|
||||
* @throws InvalidResponseException
|
||||
*/
|
||||
function decrypt_wechat_resource_aes_256_gcm(string $ciphertext, string $secret, string $nonce, string $associatedData)
|
||||
{
|
||||
$decrypted = openssl_decrypt(
|
||||
substr($ciphertext, 0, -Wechat::AUTH_TAG_LENGTH_BYTE),
|
||||
'aes-256-gcm',
|
||||
$secret,
|
||||
OPENSSL_RAW_DATA,
|
||||
$nonce,
|
||||
substr($ciphertext, -Wechat::AUTH_TAG_LENGTH_BYTE),
|
||||
$associatedData
|
||||
);
|
||||
|
||||
if ('certificate' !== $associatedData) {
|
||||
$decrypted = json_decode(strval($decrypted), true);
|
||||
|
||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||
throw new InvalidResponseException(Exception::INVALID_REQUEST_ENCRYPTED_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
return $decrypted;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_unipay_config')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
function get_unipay_config(array $params): array
|
||||
{
|
||||
$unipay = Pay::get(ConfigInterface::class)->get('unipay');
|
||||
|
||||
return $unipay[get_tenant($params)] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('verify_unipay_sign')) {
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws InvalidResponseException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
function verify_unipay_sign(array $params, string $contents, string $sign): void
|
||||
{
|
||||
if (empty($params['signPubKeyCert'])
|
||||
&& empty($public = get_unipay_config($params)['unipay_public_cert_path'] ?? null)) {
|
||||
throw new InvalidConfigException(Exception::UNIPAY_CONFIG_ERROR, 'Missing Unipay Config -- [unipay_public_cert_path]');
|
||||
}
|
||||
|
||||
$result = 1 === openssl_verify(
|
||||
hash('sha256', $contents),
|
||||
base64_decode($sign),
|
||||
get_public_cert($params['signPubKeyCert'] ?? $public ?? ''),
|
||||
'sha256'
|
||||
);
|
||||
|
||||
if (!$result) {
|
||||
throw new InvalidResponseException(Exception::INVALID_RESPONSE_SIGN, 'Verify Unipay Response Sign Failed', func_get_args());
|
||||
}
|
||||
}
|
||||
}
|
||||
48
addons/epay/library/v3/Yansongda/Pay/Logger.php
Normal file
48
addons/epay/library/v3/Yansongda/Pay/Logger.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay;
|
||||
|
||||
use Yansongda\Pay\Contract\ConfigInterface;
|
||||
use Yansongda\Pay\Contract\LoggerInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
|
||||
/**
|
||||
* @method static void emergency($message, array $context = [])
|
||||
* @method static void alert($message, array $context = [])
|
||||
* @method static void critical($message, array $context = [])
|
||||
* @method static void error($message, array $context = [])
|
||||
* @method static void warning($message, array $context = [])
|
||||
* @method static void notice($message, array $context = [])
|
||||
* @method static void info($message, array $context = [])
|
||||
* @method static void debug($message, array $context = [])
|
||||
* @method static void log($message, array $context = [])
|
||||
*/
|
||||
class Logger
|
||||
{
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
public static function __callStatic(string $method, array $args): void
|
||||
{
|
||||
if (!Pay::hasContainer() || !Pay::has(LoggerInterface::class)
|
||||
|| false === Pay::get(ConfigInterface::class)->get('logger.enable', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$class = Pay::get(LoggerInterface::class);
|
||||
|
||||
if ($class instanceof \Psr\Log\LoggerInterface || $class instanceof \Yansongda\Supports\Logger) {
|
||||
$class->{$method}(...$args);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new InvalidConfigException(Exception\Exception::LOGGER_CONFIG_ERROR);
|
||||
}
|
||||
}
|
||||
26
addons/epay/library/v3/Yansongda/Pay/Packer/JsonPacker.php
Normal file
26
addons/epay/library/v3/Yansongda/Pay/Packer/JsonPacker.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Packer;
|
||||
|
||||
use Yansongda\Pay\Contract\PackerInterface;
|
||||
|
||||
class JsonPacker implements PackerInterface
|
||||
{
|
||||
public function pack(array $payload): string
|
||||
{
|
||||
return json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
public function unpack(string $payload): ?array
|
||||
{
|
||||
$data = json_decode($payload, true);
|
||||
|
||||
if (JSON_ERROR_NONE === json_last_error()) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
33
addons/epay/library/v3/Yansongda/Pay/Packer/QueryPacker.php
Normal file
33
addons/epay/library/v3/Yansongda/Pay/Packer/QueryPacker.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Packer;
|
||||
|
||||
use Yansongda\Pay\Contract\PackerInterface;
|
||||
use Yansongda\Supports\Str;
|
||||
|
||||
class QueryPacker implements PackerInterface
|
||||
{
|
||||
public function pack(array $payload): string
|
||||
{
|
||||
return http_build_query($payload, '', '&');
|
||||
}
|
||||
|
||||
public function unpack(string $payload): ?array
|
||||
{
|
||||
if (empty($payload) || !Str::contains($payload, '=')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach (explode('&', $payload) as $item) {
|
||||
$pos = strpos($item, '=');
|
||||
|
||||
$result[substr($item, 0, $pos)] = substr($item, $pos + 1);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
46
addons/epay/library/v3/Yansongda/Pay/Packer/XmlPacker.php
Normal file
46
addons/epay/library/v3/Yansongda/Pay/Packer/XmlPacker.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Packer;
|
||||
|
||||
use Yansongda\Pay\Contract\PackerInterface;
|
||||
|
||||
class XmlPacker implements PackerInterface
|
||||
{
|
||||
public function pack(array $payload): string
|
||||
{
|
||||
$xml = '<xml>';
|
||||
|
||||
foreach ($payload as $key => $val) {
|
||||
$xml .= is_numeric($val) ? '<'.$key.'>'.$val.'</'.$key.'>' :
|
||||
'<'.$key.'><![CDATA['.$val.']]></'.$key.'>';
|
||||
}
|
||||
|
||||
$xml .= '</xml>';
|
||||
|
||||
return $xml;
|
||||
}
|
||||
|
||||
public function unpack(string $payload): ?array
|
||||
{
|
||||
if (empty($payload)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (PHP_VERSION_ID < 80000) {
|
||||
libxml_disable_entity_loader();
|
||||
}
|
||||
|
||||
$data = json_decode(json_encode(
|
||||
simplexml_load_string($payload, 'SimpleXMLElement', LIBXML_NOCDATA),
|
||||
JSON_UNESCAPED_UNICODE
|
||||
), true);
|
||||
|
||||
if (JSON_ERROR_NONE === json_last_error()) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
267
addons/epay/library/v3/Yansongda/Pay/Pay.php
Normal file
267
addons/epay/library/v3/Yansongda/Pay/Pay.php
Normal file
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Container\Container as LaravelContainer;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Throwable;
|
||||
use Yansongda\Pay\Contract\DirectionInterface;
|
||||
use Yansongda\Pay\Contract\PackerInterface;
|
||||
use Yansongda\Pay\Contract\ServiceProviderInterface;
|
||||
use Yansongda\Pay\Direction\CollectionDirection;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\ContainerNotFoundException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Packer\JsonPacker;
|
||||
use Yansongda\Pay\Provider\Alipay;
|
||||
use Yansongda\Pay\Provider\Unipay;
|
||||
use Yansongda\Pay\Provider\Wechat;
|
||||
use Yansongda\Pay\Service\AlipayServiceProvider;
|
||||
use Yansongda\Pay\Service\ConfigServiceProvider;
|
||||
use Yansongda\Pay\Service\ContainerServiceProvider;
|
||||
use Yansongda\Pay\Service\EventServiceProvider;
|
||||
use Yansongda\Pay\Service\HttpServiceProvider;
|
||||
use Yansongda\Pay\Service\LoggerServiceProvider;
|
||||
use Yansongda\Pay\Service\UnipayServiceProvider;
|
||||
use Yansongda\Pay\Service\WechatServiceProvider;
|
||||
|
||||
/**
|
||||
* @method static Alipay alipay(array $config = [], $container = null)
|
||||
* @method static Wechat wechat(array $config = [], $container = null)
|
||||
* @method static Unipay unipay(array $config = [], $container = null)
|
||||
*/
|
||||
class Pay
|
||||
{
|
||||
/**
|
||||
* 正常模式.
|
||||
*/
|
||||
public const MODE_NORMAL = 0;
|
||||
|
||||
/**
|
||||
* 沙箱模式.
|
||||
*/
|
||||
public const MODE_SANDBOX = 1;
|
||||
|
||||
/**
|
||||
* 服务商模式.
|
||||
*/
|
||||
public const MODE_SERVICE = 2;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $service = [
|
||||
AlipayServiceProvider::class,
|
||||
WechatServiceProvider::class,
|
||||
UnipayServiceProvider::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private array $coreService = [
|
||||
ContainerServiceProvider::class,
|
||||
ConfigServiceProvider::class,
|
||||
LoggerServiceProvider::class,
|
||||
EventServiceProvider::class,
|
||||
HttpServiceProvider::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var null|Closure|ContainerInterface
|
||||
*/
|
||||
private static $container;
|
||||
|
||||
/**
|
||||
* @param null|Closure|ContainerInterface $container
|
||||
*
|
||||
* @throws ContainerException
|
||||
*/
|
||||
private function __construct(array $config, $container = null)
|
||||
{
|
||||
$this->registerServices($config, $container);
|
||||
|
||||
Pay::set(DirectionInterface::class, CollectionDirection::class);
|
||||
Pay::set(PackerInterface::class, JsonPacker::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public static function __callStatic(string $service, array $config)
|
||||
{
|
||||
if (!empty($config)) {
|
||||
self::config(...$config);
|
||||
}
|
||||
|
||||
return self::get($service);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|Closure|ContainerInterface $container
|
||||
*
|
||||
* @throws ContainerException
|
||||
*/
|
||||
public static function config(array $config = [], $container = null): bool
|
||||
{
|
||||
if (self::hasContainer() && !($config['_force'] ?? false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
new self($config, $container);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @throws ContainerException
|
||||
*/
|
||||
public static function set(string $name, $value): void
|
||||
{
|
||||
try {
|
||||
$container = Pay::getContainer();
|
||||
|
||||
if ($container instanceof LaravelContainer) {
|
||||
$container->singleton($name, $value instanceof Closure ? $value : static fn () => $value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (method_exists($container, 'set')) {
|
||||
$container->set(...func_get_args());
|
||||
|
||||
return;
|
||||
}
|
||||
} catch (ContainerNotFoundException $e) {
|
||||
throw $e;
|
||||
} catch (Throwable $e) {
|
||||
throw new ContainerException($e->getMessage());
|
||||
}
|
||||
|
||||
throw new ContainerException('Current container does NOT support `set` method');
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws ContainerException
|
||||
*/
|
||||
public static function make(string $service, array $parameters = [])
|
||||
{
|
||||
try {
|
||||
$container = Pay::getContainer();
|
||||
|
||||
if (method_exists($container, 'make')) {
|
||||
return $container->make(...func_get_args());
|
||||
}
|
||||
} catch (ContainerNotFoundException $e) {
|
||||
throw $e;
|
||||
} catch (Throwable $e) {
|
||||
throw new ContainerException($e->getMessage());
|
||||
}
|
||||
|
||||
$parameters = array_values($parameters);
|
||||
|
||||
return new $service(...$parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws ContainerException
|
||||
*/
|
||||
public static function get(string $service)
|
||||
{
|
||||
try {
|
||||
return Pay::getContainer()->get($service);
|
||||
} catch (NotFoundExceptionInterface $e) {
|
||||
throw new ServiceNotFoundException($e->getMessage());
|
||||
} catch (ContainerNotFoundException $e) {
|
||||
throw $e;
|
||||
} catch (Throwable $e) {
|
||||
throw new ContainerException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerNotFoundException
|
||||
*/
|
||||
public static function has(string $service): bool
|
||||
{
|
||||
return Pay::getContainer()->has($service);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|Closure|ContainerInterface $container
|
||||
*/
|
||||
public static function setContainer($container): void
|
||||
{
|
||||
self::$container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerNotFoundException
|
||||
*/
|
||||
public static function getContainer(): ContainerInterface
|
||||
{
|
||||
if (self::$container instanceof ContainerInterface) {
|
||||
return self::$container;
|
||||
}
|
||||
|
||||
if (self::$container instanceof Closure) {
|
||||
return (self::$container)();
|
||||
}
|
||||
|
||||
throw new ContainerNotFoundException('`getContainer()` failed! Maybe you should `setContainer()` first', Exception\Exception::CONTAINER_NOT_FOUND);
|
||||
}
|
||||
|
||||
public static function hasContainer(): bool
|
||||
{
|
||||
return self::$container instanceof ContainerInterface || self::$container instanceof Closure;
|
||||
}
|
||||
|
||||
public static function clear(): void
|
||||
{
|
||||
self::$container = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
*
|
||||
* @throws ContainerException
|
||||
*/
|
||||
public static function registerService(string $service, $data): void
|
||||
{
|
||||
$var = new $service();
|
||||
|
||||
if ($var instanceof ServiceProviderInterface) {
|
||||
$var->register($data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|Closure|ContainerInterface $container
|
||||
*
|
||||
* @throws ContainerException
|
||||
*/
|
||||
private function registerServices(array $config, $container = null): void
|
||||
{
|
||||
foreach (array_merge($this->coreService, $this->service) as $service) {
|
||||
self::registerService($service, ContainerServiceProvider::class == $service ? $container : $config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Direction\NoHttpRequestDirection;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\InvalidResponseException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Supports\Collection;
|
||||
use Yansongda\Supports\Str;
|
||||
|
||||
use function Yansongda\Pay\verify_alipay_sign;
|
||||
|
||||
class CallbackPlugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidResponseException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][CallbackPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$this->formatPayload($rocket);
|
||||
$sign = $rocket->getParams()['sign'] ?? false;
|
||||
|
||||
if (!$sign) {
|
||||
throw new InvalidResponseException(Exception::INVALID_RESPONSE_SIGN, '', $rocket->getParams());
|
||||
}
|
||||
|
||||
verify_alipay_sign($rocket->getParams(), $this->getSignContent($rocket->getPayload()), $sign);
|
||||
|
||||
$rocket->setDirection(NoHttpRequestDirection::class)
|
||||
->setDestination($rocket->getPayload())
|
||||
;
|
||||
|
||||
Logger::info('[alipay][CallbackPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
|
||||
protected function formatPayload(Rocket $rocket): void
|
||||
{
|
||||
$payload = (new Collection($rocket->getParams()))
|
||||
->filter(fn ($v, $k) => '' !== $v && !is_null($v) && 'sign' != $k && 'sign_type' != $k && !Str::startsWith($k, '_'))
|
||||
;
|
||||
|
||||
$rocket->setPayload($payload);
|
||||
}
|
||||
|
||||
protected function getSignContent(Collection $payload): string
|
||||
{
|
||||
return $payload->sortKeys()->toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Data;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02fkbl
|
||||
*/
|
||||
class BillDownloadUrlQueryPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.data.dataservice.bill.downloadurl.query';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Data;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/029p6g
|
||||
*/
|
||||
class BillEreceiptApplyPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][BillEreceiptApplyPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.data.bill.ereceipt.apply',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'type' => 'FUND_DETAIL',
|
||||
],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][BillEreceiptApplyPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Data;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/029i7e
|
||||
*/
|
||||
class BillEreceiptQueryPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.data.bill.ereceipt.query';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Ebpp;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02hd36
|
||||
*/
|
||||
class PdeductBillStatusPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.ebpp.pdeduct.bill.pay.status';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Ebpp;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02hd35
|
||||
*/
|
||||
class PdeductPayPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][PdeductPayPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.ebpp.pdeduct.pay',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'agent_channel' => 'PUBLICFORM',
|
||||
],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][PdeductPayPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Ebpp;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02hd33
|
||||
*/
|
||||
class PdeductSignAddPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][PdeductSignAddPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.ebpp.pdeduct.sign.add',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'charge_inst' => 'CQCENTERELECTRIC',
|
||||
'agent_channel' => 'PUBLICPLATFORM',
|
||||
'deduct_prod_code' => 'INST_DIRECT_DEDUCT',
|
||||
],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][PdeductSignAddPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Ebpp;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02hd34
|
||||
*/
|
||||
class PdeductSignCancelPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][PdeductSignCancelPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.ebpp.pdeduct.sign.cancel',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'agent_channel' => 'PUBLICPLATFORM',
|
||||
],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][PdeductSignCancelPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Fund;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02byuq?scene=common
|
||||
*/
|
||||
class AccountQueryPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][AccountQueryPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.fund.account.query',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'product_code' => 'TRANS_ACCOUNT_NO_PWD',
|
||||
],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][AccountQueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Fund;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02fkb9
|
||||
*/
|
||||
class AuthOrderFreezePlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][AuthOrderFreezePlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.fund.auth.order.freeze',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'product_code' => 'PRE_AUTH',
|
||||
],
|
||||
$rocket->getParams()
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][AuthOrderFreezePlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Fund;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02fkbc
|
||||
*/
|
||||
class AuthOrderUnfreezePlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.fund.auth.order.unfreeze';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Fund;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02byve
|
||||
*/
|
||||
class TransCommonQueryPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][TransCommonQueryPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.fund.trans.common.query',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'product_code' => 'TRANS_ACCOUNT_NO_PWD',
|
||||
'biz_scene' => 'DIRECT_TRANSFER',
|
||||
],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][TransCommonQueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Fund;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Direction\ResponseDirection;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/03rbye
|
||||
*/
|
||||
class TransPagePayPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][TransPagePayPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->setDirection(ResponseDirection::class)
|
||||
->mergePayload([
|
||||
'method' => 'alipay.fund.trans.page.pay',
|
||||
'biz_content' => $rocket->getParams(),
|
||||
])
|
||||
;
|
||||
|
||||
Logger::info('[alipay][TransPagePayPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Fund;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
class TransTobankTransferPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.fund.trans.tobank.transfer';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Fund;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02byuo?scene=common
|
||||
*/
|
||||
class TransUniTransferPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][TransUniTransferPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.fund.trans.uni.transfer',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'biz_scene' => 'DIRECT_TRANSFER',
|
||||
'product_code' => 'TRANS_ACCOUNT_NO_PWD',
|
||||
],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][TransUniTransferPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
abstract class GeneralPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][GeneralPlugin] 通用插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$this->doSomethingBefore($rocket);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => $this->getMethod(),
|
||||
'biz_content' => $rocket->getParams(),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][GeneralPlugin] 通用插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
|
||||
protected function doSomethingBefore(Rocket $rocket): void
|
||||
{
|
||||
}
|
||||
|
||||
abstract protected function getMethod(): string;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay;
|
||||
|
||||
use Closure;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Supports\Collection;
|
||||
|
||||
class HtmlResponsePlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
/* @var Rocket $rocket */
|
||||
$rocket = $next($rocket);
|
||||
|
||||
Logger::debug('[alipay][HtmlResponsePlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$radar = $rocket->getRadar();
|
||||
|
||||
$response = 'GET' === $radar->getMethod() ?
|
||||
$this->buildRedirect($radar->getUri()->__toString(), $rocket->getPayload()) :
|
||||
$this->buildHtml($radar->getUri()->__toString(), $rocket->getPayload());
|
||||
|
||||
$rocket->setDestination($response);
|
||||
|
||||
Logger::info('[alipay][HtmlResponsePlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $rocket;
|
||||
}
|
||||
|
||||
protected function buildRedirect(string $endpoint, Collection $payload): Response
|
||||
{
|
||||
$url = $endpoint.(false === strpos($endpoint, '?') ? '?' : '&').$payload->query();
|
||||
|
||||
$content = sprintf(
|
||||
'<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="refresh" content="0;url=\'%1$s\'" />
|
||||
|
||||
<title>Redirecting to %1$s</title>
|
||||
</head>
|
||||
<body>
|
||||
Redirecting to %1$s.
|
||||
</body>
|
||||
</html>',
|
||||
htmlspecialchars($url, ENT_QUOTES)
|
||||
);
|
||||
|
||||
return new Response(302, ['Location' => $url], $content);
|
||||
}
|
||||
|
||||
protected function buildHtml(string $endpoint, Collection $payload): Response
|
||||
{
|
||||
$sHtml = "<form id='alipay_submit' name='alipay_submit' action='".$endpoint."' method='POST'>";
|
||||
foreach ($payload->all() as $key => $val) {
|
||||
$val = str_replace("'", ''', $val);
|
||||
$sHtml .= "<input type='hidden' name='".$key."' value='".$val."'/>";
|
||||
}
|
||||
$sHtml .= "<input type='submit' value='ok' style='display:none;'></form>";
|
||||
$sHtml .= "<script>document.forms['alipay_submit'].submit();</script>";
|
||||
|
||||
return new Response(200, [], $sHtml);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\InvalidResponseException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Supports\Collection;
|
||||
|
||||
use function Yansongda\Pay\should_do_http_request;
|
||||
use function Yansongda\Pay\verify_alipay_sign;
|
||||
|
||||
class LaunchPlugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws InvalidResponseException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
/* @var Rocket $rocket */
|
||||
$rocket = $next($rocket);
|
||||
|
||||
Logger::debug('[alipay][LaunchPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
if (should_do_http_request($rocket->getDirection())) {
|
||||
$response = Collection::wrap($rocket->getDestination());
|
||||
$result = $response->get($this->getResultKey($rocket->getPayload()));
|
||||
|
||||
$this->verifySign($rocket->getParams(), $response, $result);
|
||||
|
||||
$rocket->setDestination(Collection::wrap($result));
|
||||
}
|
||||
|
||||
Logger::info('[alipay][LaunchPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $rocket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws InvalidResponseException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function verifySign(array $params, Collection $response, ?array $result): void
|
||||
{
|
||||
$sign = $response->get('sign', '');
|
||||
|
||||
if ('' === $sign || is_null($result)) {
|
||||
throw new InvalidResponseException(Exception::INVALID_RESPONSE_SIGN, 'Verify Alipay Response Sign Failed: sign is empty', $response);
|
||||
}
|
||||
|
||||
verify_alipay_sign($params, json_encode($result, JSON_UNESCAPED_UNICODE), $sign);
|
||||
}
|
||||
|
||||
protected function getResultKey(Collection $payload): string
|
||||
{
|
||||
$method = $payload->get('method');
|
||||
|
||||
return str_replace('.', '_', $method).'_response';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\ConfigInterface;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Pay;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
use function Yansongda\Pay\get_alipay_config;
|
||||
use function Yansongda\Pay\get_tenant;
|
||||
|
||||
class PreparePlugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][PreparePlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload($this->getPayload($rocket->getParams()));
|
||||
|
||||
Logger::info('[alipay][PreparePlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
protected function getPayload(array $params): array
|
||||
{
|
||||
$tenant = get_tenant($params);
|
||||
$config = get_alipay_config($params);
|
||||
|
||||
$payload = [
|
||||
'app_id' => $config['app_id'] ?? '',
|
||||
'method' => '',
|
||||
'format' => 'JSON',
|
||||
'return_url' => $this->getReturnUrl($params, $config),
|
||||
'charset' => 'utf-8',
|
||||
'sign_type' => 'RSA2',
|
||||
'sign' => '',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'version' => '1.0',
|
||||
'notify_url' => $this->getNotifyUrl($params, $config),
|
||||
'app_auth_token' => $this->getAppAuthToken($params, $config),
|
||||
'biz_content' => [],
|
||||
];
|
||||
if (!empty($config['app_cert_public_key']) && !empty($config['alipay_root_cert'])) {
|
||||
$payload = array_merge($payload, ['app_cert_sn' => $this->getAppCertSn($tenant, $config), 'alipay_root_cert_sn' => $this->getAlipayRootCertSn($tenant, $config)]);
|
||||
}
|
||||
return $payload;
|
||||
}
|
||||
|
||||
protected function getReturnUrl(array $params, array $config): string
|
||||
{
|
||||
if (!empty($params['_return_url'])) {
|
||||
return $params['_return_url'];
|
||||
}
|
||||
|
||||
return $config['return_url'] ?? '';
|
||||
}
|
||||
|
||||
protected function getNotifyUrl(array $params, array $config): string
|
||||
{
|
||||
if (!empty($params['_notify_url'])) {
|
||||
return $params['_notify_url'];
|
||||
}
|
||||
|
||||
return $config['notify_url'] ?? '';
|
||||
}
|
||||
|
||||
protected function getAppAuthToken(array $params, array $config): string
|
||||
{
|
||||
if (!empty($params['_app_auth_token'])) {
|
||||
return $params['_app_auth_token'];
|
||||
}
|
||||
|
||||
return $config['app_auth_token'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function getAppCertSn(string $tenant, array $config): string
|
||||
{
|
||||
if (!empty($config['app_public_cert_sn'])) {
|
||||
return $config['app_public_cert_sn'];
|
||||
}
|
||||
|
||||
$path = $config['app_public_cert_path'] ?? null;
|
||||
|
||||
if (is_null($path)) {
|
||||
throw new InvalidConfigException(Exception::ALIPAY_CONFIG_ERROR, 'Missing Alipay Config -- [app_public_cert_path]');
|
||||
}
|
||||
|
||||
$cert = file_get_contents($path);
|
||||
$ssl = openssl_x509_parse($cert);
|
||||
|
||||
if (false === $ssl) {
|
||||
throw new InvalidConfigException(Exception::ALIPAY_CONFIG_ERROR, 'Parse `app_public_cert_path` Error');
|
||||
}
|
||||
|
||||
$result = $this->getCertSn($ssl['issuer'] ?? [], $ssl['serialNumber'] ?? '');
|
||||
|
||||
Pay::get(ConfigInterface::class)->set('alipay.'.$tenant.'.app_public_cert_sn', $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function getAlipayRootCertSn(string $tenant, array $config): string
|
||||
{
|
||||
if (!empty($config['alipay_root_cert_sn'])) {
|
||||
return $config['alipay_root_cert_sn'];
|
||||
}
|
||||
|
||||
$path = $config['alipay_root_cert_path'] ?? null;
|
||||
|
||||
if (is_null($path)) {
|
||||
throw new InvalidConfigException(Exception::ALIPAY_CONFIG_ERROR, 'Missing Alipay Config -- [alipay_root_cert_path]');
|
||||
}
|
||||
|
||||
$sn = '';
|
||||
$exploded = explode('-----END CERTIFICATE-----', file_get_contents($path));
|
||||
|
||||
foreach ($exploded as $cert) {
|
||||
if (empty(trim($cert))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ssl = openssl_x509_parse($cert.'-----END CERTIFICATE-----');
|
||||
|
||||
if (false === $ssl) {
|
||||
throw new InvalidConfigException(Exception::ALIPAY_CONFIG_ERROR, 'Invalid alipay_root_cert');
|
||||
}
|
||||
|
||||
$detail = $this->formatCert($ssl);
|
||||
|
||||
if ('sha1WithRSAEncryption' == $detail['signatureTypeLN'] || 'sha256WithRSAEncryption' == $detail['signatureTypeLN']) {
|
||||
$sn .= $this->getCertSn($detail['issuer'], $detail['serialNumber']).'_';
|
||||
}
|
||||
}
|
||||
|
||||
$result = substr($sn, 0, -1);
|
||||
|
||||
Pay::get(ConfigInterface::class)->set('alipay.'.$tenant.'.alipay_root_cert_sn', $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function getCertSn(array $issuer, string $serialNumber): string
|
||||
{
|
||||
return md5(
|
||||
$this->array2string(array_reverse($issuer)).$serialNumber
|
||||
);
|
||||
}
|
||||
|
||||
protected function array2string(array $array): string
|
||||
{
|
||||
$string = [];
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
$string[] = $key.'='.$value;
|
||||
}
|
||||
|
||||
return implode(',', $string);
|
||||
}
|
||||
|
||||
protected function formatCert(array $ssl): array
|
||||
{
|
||||
if (0 === strpos($ssl['serialNumber'] ?? '', '0x')) {
|
||||
$ssl['serialNumber'] = $this->hex2dec($ssl['serialNumberHex'] ?? '');
|
||||
}
|
||||
|
||||
return $ssl;
|
||||
}
|
||||
|
||||
protected function hex2dec(string $hex): string
|
||||
{
|
||||
$dec = '0';
|
||||
$len = strlen($hex);
|
||||
|
||||
for ($i = 1; $i <= $len; ++$i) {
|
||||
$dec = bcadd(
|
||||
$dec,
|
||||
bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i), 0), 0),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
return $dec;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Pay;
|
||||
use Yansongda\Pay\Provider\Alipay;
|
||||
use Yansongda\Pay\Request;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Supports\Collection;
|
||||
use Yansongda\Supports\Str;
|
||||
|
||||
use function Yansongda\Pay\get_alipay_config;
|
||||
use function Yansongda\Pay\get_private_cert;
|
||||
|
||||
class RadarSignPlugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][RadarSignPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$this->sign($rocket);
|
||||
|
||||
$this->reRadar($rocket);
|
||||
|
||||
Logger::info('[alipay][RadarSignPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function sign(Rocket $rocket): void
|
||||
{
|
||||
$this->formatPayload($rocket);
|
||||
|
||||
$sign = $this->getSign($rocket);
|
||||
|
||||
$rocket->mergePayload(['sign' => $sign]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function reRadar(Rocket $rocket): void
|
||||
{
|
||||
$params = $rocket->getParams();
|
||||
|
||||
$rocket->setRadar(new Request(
|
||||
$this->getMethod($params),
|
||||
$this->getUrl($params),
|
||||
$this->getHeaders(),
|
||||
$this->getBody($rocket->getPayload()),
|
||||
));
|
||||
}
|
||||
|
||||
protected function formatPayload(Rocket $rocket): void
|
||||
{
|
||||
$payload = $rocket->getPayload()->filter(fn ($v, $k) => '' !== $v && !is_null($v) && 'sign' != $k);
|
||||
|
||||
$contents = array_filter($payload->get('biz_content', []), fn ($v, $k) => !Str::startsWith(strval($k), '_'), ARRAY_FILTER_USE_BOTH);
|
||||
|
||||
$rocket->setPayload(
|
||||
$payload->merge(['biz_content' => json_encode($contents)])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function getSign(Rocket $rocket): string
|
||||
{
|
||||
$privateKey = $this->getPrivateKey($rocket->getParams());
|
||||
|
||||
$content = $rocket->getPayload()->sortKeys()->toString();
|
||||
|
||||
openssl_sign($content, $sign, $privateKey, OPENSSL_ALGO_SHA256);
|
||||
|
||||
return base64_encode($sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function getPrivateKey(array $params): string
|
||||
{
|
||||
$privateKey = get_alipay_config($params)['app_secret_cert'] ?? null;
|
||||
|
||||
if (is_null($privateKey)) {
|
||||
throw new InvalidConfigException(Exception::ALIPAY_CONFIG_ERROR, 'Missing Alipay Config -- [app_secret_cert]');
|
||||
}
|
||||
|
||||
return get_private_cert($privateKey);
|
||||
}
|
||||
|
||||
protected function getMethod(array $params): string
|
||||
{
|
||||
return strtoupper($params['_method'] ?? 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function getUrl(array $params): string
|
||||
{
|
||||
$config = get_alipay_config($params);
|
||||
|
||||
return Alipay::URL[$config['mode'] ?? Pay::MODE_NORMAL];
|
||||
}
|
||||
|
||||
protected function getHeaders(): array
|
||||
{
|
||||
return [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
];
|
||||
}
|
||||
|
||||
protected function getBody(Collection $payload): string
|
||||
{
|
||||
return $payload->query();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Closure;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\AppPayPlugin;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Supports\Arr;
|
||||
use Yansongda\Supports\Collection;
|
||||
|
||||
class AppShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
AppPayPlugin::class,
|
||||
$this->buildResponse(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function buildResponse(): PluginInterface
|
||||
{
|
||||
return new class() implements PluginInterface {
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
$rocket->setDestination(new Response());
|
||||
|
||||
/* @var Rocket $rocket */
|
||||
$rocket = $next($rocket);
|
||||
|
||||
$response = $this->buildHtml($rocket->getPayload());
|
||||
|
||||
return $rocket->setDestination($response);
|
||||
}
|
||||
|
||||
protected function buildHtml(Collection $payload): Response
|
||||
{
|
||||
return new Response(200, [], Arr::query($payload->all()));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\CancelPlugin;
|
||||
|
||||
class CancelShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
CancelPlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\ClosePlugin;
|
||||
|
||||
class CloseShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
ClosePlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\CreatePlugin;
|
||||
|
||||
class MiniShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
CreatePlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\PayPlugin;
|
||||
|
||||
class PosShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
PayPlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidParamsException;
|
||||
use Yansongda\Pay\Plugin\Alipay\Fund\TransCommonQueryPlugin;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\FastRefundQueryPlugin;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\QueryPlugin;
|
||||
use Yansongda\Supports\Str;
|
||||
|
||||
class QueryShortcut implements ShortcutInterface
|
||||
{
|
||||
/**
|
||||
* @throws InvalidParamsException
|
||||
*/
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
$typeMethod = Str::camel($params['_action'] ?? 'default').'Plugins';
|
||||
|
||||
if (isset($params['out_request_no'])) {
|
||||
return $this->refundPlugins();
|
||||
}
|
||||
|
||||
if (method_exists($this, $typeMethod)) {
|
||||
return $this->{$typeMethod}();
|
||||
}
|
||||
|
||||
throw new InvalidParamsException(Exception::SHORTCUT_MULTI_ACTION_ERROR, "Query action [{$typeMethod}] not supported");
|
||||
}
|
||||
|
||||
protected function defaultPlugins(): array
|
||||
{
|
||||
return [
|
||||
QueryPlugin::class,
|
||||
];
|
||||
}
|
||||
|
||||
protected function refundPlugins(): array
|
||||
{
|
||||
return [
|
||||
FastRefundQueryPlugin::class,
|
||||
];
|
||||
}
|
||||
|
||||
protected function transferPlugins(): array
|
||||
{
|
||||
return [
|
||||
TransCommonQueryPlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\RefundPlugin;
|
||||
|
||||
class RefundShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
RefundPlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\PreCreatePlugin;
|
||||
|
||||
class ScanShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
PreCreatePlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\Fund\TransUniTransferPlugin;
|
||||
|
||||
class TransferShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
TransUniTransferPlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\HtmlResponsePlugin;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\WapPayPlugin;
|
||||
|
||||
class WapShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
WapPayPlugin::class,
|
||||
HtmlResponsePlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Shortcut;
|
||||
|
||||
use Yansongda\Pay\Contract\ShortcutInterface;
|
||||
use Yansongda\Pay\Plugin\Alipay\HtmlResponsePlugin;
|
||||
use Yansongda\Pay\Plugin\Alipay\Trade\PagePayPlugin;
|
||||
|
||||
class WebShortcut implements ShortcutInterface
|
||||
{
|
||||
public function getPlugins(array $params): array
|
||||
{
|
||||
return [
|
||||
PagePayPlugin::class,
|
||||
HtmlResponsePlugin::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Tools;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/isv/03l9c0
|
||||
*/
|
||||
class OpenAuthTokenAppPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.open.auth.token.app';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Tools;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/isv/03l8ca
|
||||
*/
|
||||
class OpenAuthTokenAppQueryPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.open.auth.token.app.query';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Tools;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02ailc
|
||||
*/
|
||||
class SystemOauthTokenPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function doSomethingBefore(Rocket $rocket): void
|
||||
{
|
||||
$rocket->mergePayload($rocket->getParams());
|
||||
}
|
||||
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.system.oauth.token';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Direction\ResponseDirection;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Pay\Traits\SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02e7gq?scene=common
|
||||
*/
|
||||
class AppPayPlugin implements PluginInterface
|
||||
{
|
||||
use SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][AppPayPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$this->loadAlipayServiceProvider($rocket);
|
||||
|
||||
$rocket->setDirection(ResponseDirection::class)
|
||||
->mergePayload([
|
||||
'method' => 'alipay.trade.app.pay',
|
||||
'biz_content' => array_merge(
|
||||
['product_code' => 'QUICK_MSECURITY_PAY'],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
])
|
||||
;
|
||||
|
||||
Logger::info('[alipay][AppPayPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02ekfi
|
||||
*/
|
||||
class CancelPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.trade.cancel';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02o6e7
|
||||
*/
|
||||
class ClosePlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.trade.close';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02ekfj
|
||||
*/
|
||||
class CreatePlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.trade.create';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/028sma
|
||||
*/
|
||||
class FastRefundQueryPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.trade.fastpay.refund.query';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
class OrderPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.trade.order.pay';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/028xqz
|
||||
*/
|
||||
class OrderSettlePlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.trade.order.settle';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Direction\ResponseDirection;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Pay\Traits\SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/028r8t?scene=22
|
||||
*/
|
||||
class PagePayPlugin implements PluginInterface
|
||||
{
|
||||
use SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][PagePayPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$this->loadAlipayServiceProvider($rocket);
|
||||
|
||||
$rocket->setDirection(ResponseDirection::class)
|
||||
->mergePayload([
|
||||
'method' => 'alipay.trade.page.pay',
|
||||
'biz_content' => array_merge(
|
||||
['product_code' => 'FAST_INSTANT_TRADE_PAY'],
|
||||
$rocket->getParams()
|
||||
),
|
||||
])
|
||||
;
|
||||
|
||||
Logger::info('[alipay][PagePayPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Direction\ResponseDirection;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
class PageRefundPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][PageRefundPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->setDirection(ResponseDirection::class)
|
||||
->mergePayload([
|
||||
'method' => 'alipay.trade.page.refund',
|
||||
'biz_content' => $rocket->getParams(),
|
||||
])
|
||||
;
|
||||
|
||||
Logger::info('[alipay][PageRefundPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Pay\Traits\SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02fkat?ref=api&scene=common
|
||||
*/
|
||||
class PayPlugin implements PluginInterface
|
||||
{
|
||||
use SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][PayPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$this->loadAlipayServiceProvider($rocket);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.trade.pay',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'product_code' => 'FACE_TO_FACE_PAYMENT',
|
||||
'scene' => 'bar_code',
|
||||
],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][PayPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Pay\Traits\SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02ekfg?scene=common
|
||||
*/
|
||||
class PreCreatePlugin extends GeneralPlugin
|
||||
{
|
||||
use SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function doSomethingBefore(Rocket $rocket): void
|
||||
{
|
||||
$this->loadAlipayServiceProvider($rocket);
|
||||
}
|
||||
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.trade.precreate';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02ekfh?scene=common
|
||||
*/
|
||||
class QueryPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.trade.query';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02ekfk
|
||||
*/
|
||||
class RefundPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.trade.refund';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\Trade;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Direction\ResponseDirection;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Pay\Traits\SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02ivbs?scene=common
|
||||
*/
|
||||
class WapPayPlugin implements PluginInterface
|
||||
{
|
||||
use SupportServiceProviderTrait;
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][WapPayPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$this->loadAlipayServiceProvider($rocket);
|
||||
|
||||
$rocket->setDirection(ResponseDirection::class)
|
||||
->mergePayload([
|
||||
'method' => 'alipay.trade.wap.pay',
|
||||
'biz_content' => array_merge(
|
||||
[
|
||||
'product_code' => 'QUICK_WAP_PAY',
|
||||
],
|
||||
$rocket->getParams(),
|
||||
),
|
||||
])
|
||||
;
|
||||
|
||||
Logger::info('[alipay][WapPayPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\User;
|
||||
|
||||
use Yansongda\Pay\Plugin\Alipay\GeneralPlugin;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02fkaq?ref=api
|
||||
*/
|
||||
class AgreementExecutionPlanModifyPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'alipay.user.agreement.executionplan.modify';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\User;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Direction\ResponseDirection;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02fkan?ref=api&scene=35
|
||||
*/
|
||||
class AgreementPageSignPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][AgreementPageSignPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->setDirection(ResponseDirection::class)
|
||||
->mergePayload([
|
||||
'method' => 'alipay.user.agreement.page.sign',
|
||||
'biz_content' => array_merge(
|
||||
['product_code' => 'CYCLE_PAY_AUTH'],
|
||||
$rocket->getParams()
|
||||
),
|
||||
])
|
||||
;
|
||||
|
||||
Logger::info('[alipay][AgreementPageSignPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\User;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02fkao?ref=api&scene=8837b4183390497f84bb53783b488ecc
|
||||
*/
|
||||
class AgreementQueryPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][AgreementQueryPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.user.agreement.query',
|
||||
'biz_content' => array_merge(
|
||||
['personal_product_code' => 'CYCLE_PAY_AUTH_P'],
|
||||
$rocket->getParams()
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][AgreementQueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\User;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02fkar?ref=api
|
||||
*/
|
||||
class AgreementTransferPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][AgreementTransferPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.user.agreement.transfer',
|
||||
'biz_content' => array_merge(
|
||||
['target_product_code' => 'CYCLE_PAY_AUTH_P'],
|
||||
$rocket->getParams()
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][AgreementTransferPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\User;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02fkap?ref=api&scene=90766afb41f74df6ae1676e89625ebac
|
||||
*/
|
||||
class AgreementUnsignPlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][AgreementUnsignPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.user.agreement.unsign',
|
||||
'biz_content' => array_merge(
|
||||
['personal_product_code' => 'CYCLE_PAY_AUTH_P'],
|
||||
$rocket->getParams()
|
||||
),
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][AgreementUnsignPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Alipay\User;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/02aild
|
||||
*/
|
||||
class InfoSharePlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[alipay][InfoSharePlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->mergePayload([
|
||||
'method' => 'alipay.user.info.share',
|
||||
'auth_token' => $rocket->getParams()['auth_token'] ?? '',
|
||||
]);
|
||||
|
||||
Logger::info('[alipay][InfoSharePlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
}
|
||||
74
addons/epay/library/v3/Yansongda/Pay/Plugin/ParserPlugin.php
Normal file
74
addons/epay/library/v3/Yansongda/Pay/Plugin/ParserPlugin.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin;
|
||||
|
||||
use Closure;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Yansongda\Pay\Contract\DirectionInterface;
|
||||
use Yansongda\Pay\Contract\PackerInterface;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Pay;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
class ParserPlugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
/* @var Rocket $rocket */
|
||||
$rocket = $next($rocket);
|
||||
|
||||
/* @var ResponseInterface $response */
|
||||
$response = $rocket->getDestination();
|
||||
|
||||
return $rocket->setDestination(
|
||||
$this->getDirection($rocket)->parse($this->getPacker($rocket), $response)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function getDirection(Rocket $rocket): DirectionInterface
|
||||
{
|
||||
$packer = Pay::get($rocket->getDirection());
|
||||
|
||||
$packer = is_string($packer) ? Pay::get($packer) : $packer;
|
||||
|
||||
if (!$packer instanceof DirectionInterface) {
|
||||
throw new InvalidConfigException(Exception::INVALID_PARSER);
|
||||
}
|
||||
|
||||
return $packer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function getPacker(Rocket $rocket): PackerInterface
|
||||
{
|
||||
$packer = Pay::get($rocket->getPacker());
|
||||
|
||||
$packer = is_string($packer) ? Pay::get($packer) : $packer;
|
||||
|
||||
if (!$packer instanceof PackerInterface) {
|
||||
throw new InvalidConfigException(Exception::INVALID_PACKER);
|
||||
}
|
||||
|
||||
return $packer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Unipay;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Direction\NoHttpRequestDirection;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\Exception;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\InvalidResponseException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Supports\Collection;
|
||||
use Yansongda\Supports\Str;
|
||||
|
||||
use function Yansongda\Pay\verify_unipay_sign;
|
||||
|
||||
class CallbackPlugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws InvalidResponseException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[unipay][CallbackPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$this->formatPayload($rocket);
|
||||
|
||||
$params = $rocket->getParams();
|
||||
$signature = $params['signature'] ?? false;
|
||||
|
||||
if (!$signature) {
|
||||
throw new InvalidResponseException(Exception::INVALID_RESPONSE_SIGN, '', $params);
|
||||
}
|
||||
|
||||
verify_unipay_sign($params, $rocket->getPayload()->sortKeys()->toString(), $signature);
|
||||
|
||||
$rocket->setDirection(NoHttpRequestDirection::class)
|
||||
->setDestination($rocket->getPayload())
|
||||
;
|
||||
|
||||
Logger::info('[unipay][CallbackPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
|
||||
protected function formatPayload(Rocket $rocket): void
|
||||
{
|
||||
$payload = (new Collection($rocket->getParams()))
|
||||
->filter(fn ($v, $k) => 'signature' != $k && !Str::startsWith($k, '_'))
|
||||
;
|
||||
|
||||
$rocket->setPayload($payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Unipay;
|
||||
|
||||
use Closure;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Pay;
|
||||
use Yansongda\Pay\Provider\Unipay;
|
||||
use Yansongda\Pay\Request;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
use function Yansongda\Pay\get_unipay_config;
|
||||
|
||||
abstract class GeneralPlugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
* @throws ServiceNotFoundException
|
||||
* @throws ContainerException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
Logger::debug('[unipay][GeneralPlugin] 通用插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$rocket->setRadar($this->getRequest($rocket));
|
||||
$this->doSomething($rocket);
|
||||
|
||||
Logger::info('[unipay][GeneralPlugin] 通用插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $next($rocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function getRequest(Rocket $rocket): RequestInterface
|
||||
{
|
||||
return new Request(
|
||||
$this->getMethod(),
|
||||
$this->getUrl($rocket),
|
||||
$this->getHeaders(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getMethod(): string
|
||||
{
|
||||
return 'POST';
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
protected function getUrl(Rocket $rocket): string
|
||||
{
|
||||
$url = $this->getUri($rocket);
|
||||
|
||||
if (0 === strpos($url, 'http')) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$config = get_unipay_config($rocket->getParams());
|
||||
|
||||
return Unipay::URL[$config['mode'] ?? Pay::MODE_NORMAL].$url;
|
||||
}
|
||||
|
||||
protected function getHeaders(): array
|
||||
{
|
||||
return [
|
||||
'User-Agent' => 'yansongda/pay-v3',
|
||||
'Content-Type' => 'application/x-www-form-urlencoded;charset=utf-8',
|
||||
];
|
||||
}
|
||||
|
||||
abstract protected function doSomething(Rocket $rocket): void;
|
||||
|
||||
abstract protected function getUri(Rocket $rocket): string;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Unipay;
|
||||
|
||||
use Closure;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Supports\Collection;
|
||||
|
||||
class HtmlResponsePlugin implements PluginInterface
|
||||
{
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
/* @var Rocket $rocket */
|
||||
$rocket = $next($rocket);
|
||||
|
||||
Logger::debug('[unipay][HtmlResponsePlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
$radar = $rocket->getRadar();
|
||||
|
||||
$response = $this->buildHtml($radar->getUri()->__toString(), $rocket->getPayload());
|
||||
|
||||
$rocket->setDestination($response);
|
||||
|
||||
Logger::info('[unipay][HtmlResponsePlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $rocket;
|
||||
}
|
||||
|
||||
protected function buildHtml(string $endpoint, Collection $payload): Response
|
||||
{
|
||||
$sHtml = "<form id='pay_form' name='pay_form' action='".$endpoint."' method='POST'>";
|
||||
foreach ($payload->all() as $key => $val) {
|
||||
$sHtml .= "<input type='hidden' name='".$key."' value='".$val."'/>";
|
||||
}
|
||||
$sHtml .= "<input type='submit' value='ok' style='display:none;'></form>";
|
||||
$sHtml .= "<script>document.forms['pay_form'].submit();</script>";
|
||||
|
||||
return new Response(200, [], $sHtml);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Unipay;
|
||||
|
||||
use Closure;
|
||||
use Yansongda\Pay\Contract\PluginInterface;
|
||||
use Yansongda\Pay\Exception\ContainerException;
|
||||
use Yansongda\Pay\Exception\InvalidConfigException;
|
||||
use Yansongda\Pay\Exception\InvalidResponseException;
|
||||
use Yansongda\Pay\Exception\ServiceNotFoundException;
|
||||
use Yansongda\Pay\Logger;
|
||||
use Yansongda\Pay\Rocket;
|
||||
use Yansongda\Supports\Collection;
|
||||
|
||||
use function Yansongda\Pay\should_do_http_request;
|
||||
use function Yansongda\Pay\verify_unipay_sign;
|
||||
|
||||
class LaunchPlugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
* @throws ContainerException
|
||||
* @throws InvalidConfigException
|
||||
* @throws InvalidResponseException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function assembly(Rocket $rocket, Closure $next): Rocket
|
||||
{
|
||||
/* @var Rocket $rocket */
|
||||
$rocket = $next($rocket);
|
||||
|
||||
Logger::debug('[unipay][LaunchPlugin] 插件开始装载', ['rocket' => $rocket]);
|
||||
|
||||
if (should_do_http_request($rocket->getDirection())) {
|
||||
$response = Collection::wrap($rocket->getDestination());
|
||||
$signature = $response->get('signature');
|
||||
$response->forget('signature');
|
||||
|
||||
verify_unipay_sign(
|
||||
$rocket->getParams(),
|
||||
$response->sortKeys()->toString(),
|
||||
$signature
|
||||
);
|
||||
|
||||
$rocket->setDestination($response);
|
||||
}
|
||||
|
||||
Logger::info('[unipay][LaunchPlugin] 插件装载完毕', ['rocket' => $rocket]);
|
||||
|
||||
return $rocket;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Unipay\OnlineGateway;
|
||||
|
||||
use Yansongda\Pay\Plugin\Unipay\GeneralPlugin;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://open.unionpay.com/tjweb/acproduct/APIList?acpAPIId=755&apiservId=448&version=V2.2&bussType=0
|
||||
*/
|
||||
class CancelPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getUri(Rocket $rocket): string
|
||||
{
|
||||
return 'gateway/api/backTransReq.do';
|
||||
}
|
||||
|
||||
protected function doSomething(Rocket $rocket): void
|
||||
{
|
||||
$rocket->mergePayload([
|
||||
'bizType' => '000000',
|
||||
'txnType' => '31',
|
||||
'txnSubType' => '00',
|
||||
'channelType' => '07',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Unipay\OnlineGateway;
|
||||
|
||||
use Yansongda\Pay\Direction\ResponseDirection;
|
||||
use Yansongda\Pay\Plugin\Unipay\GeneralPlugin;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://open.unionpay.com/tjweb/acproduct/APIList?acpAPIId=754&apiservId=448&version=V2.2&bussType=0
|
||||
*/
|
||||
class PagePayPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getUri(Rocket $rocket): string
|
||||
{
|
||||
return 'gateway/api/frontTransReq.do';
|
||||
}
|
||||
|
||||
protected function doSomething(Rocket $rocket): void
|
||||
{
|
||||
$rocket->setDirection(ResponseDirection::class)
|
||||
->mergePayload([
|
||||
'bizType' => '000201',
|
||||
'txnType' => '01',
|
||||
'txnSubType' => '01',
|
||||
'channelType' => '07',
|
||||
])
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yansongda\Pay\Plugin\Unipay\OnlineGateway;
|
||||
|
||||
use Yansongda\Pay\Plugin\Unipay\GeneralPlugin;
|
||||
use Yansongda\Pay\Rocket;
|
||||
|
||||
/**
|
||||
* @see https://open.unionpay.com/tjweb/acproduct/APIList?acpAPIId=757&apiservId=448&version=V2.2&bussType=0
|
||||
*/
|
||||
class QueryPlugin extends GeneralPlugin
|
||||
{
|
||||
protected function getUri(Rocket $rocket): string
|
||||
{
|
||||
return 'gateway/api/queryTrans.do';
|
||||
}
|
||||
|
||||
protected function doSomething(Rocket $rocket): void
|
||||
{
|
||||
$rocket->mergePayload([
|
||||
'bizType' => '000000',
|
||||
'txnType' => '00',
|
||||
'txnSubType' => '00',
|
||||
]);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user