refactor: core plugins to plugins-core

This commit is contained in:
xboard
2026-04-18 23:31:19 +08:00
parent fe62542b7c
commit c0b6ee1763
25 changed files with 139 additions and 109 deletions
+105
View File
@@ -0,0 +1,105 @@
<?php
namespace Plugin\AlipayF2f;
use App\Services\Plugin\AbstractPlugin;
use App\Contracts\PaymentInterface;
use App\Exceptions\ApiException;
use Illuminate\Support\Facades\Log;
use Plugin\AlipayF2f\library\AlipayF2F;
class Plugin extends AbstractPlugin implements PaymentInterface
{
public function boot(): void
{
$this->filter('available_payment_methods', function ($methods) {
if ($this->getConfig('enabled', true)) {
$methods['AlipayF2F'] = [
'name' => $this->getConfig('display_name', '支付宝当面付'),
'icon' => $this->getConfig('icon', '💙'),
'plugin_code' => $this->getPluginCode(),
'type' => 'plugin'
];
}
return $methods;
});
}
public function form(): array
{
return [
'app_id' => [
'label' => '支付宝APPID',
'type' => 'string',
'required' => true,
'description' => '支付宝开放平台应用的APPID'
],
'private_key' => [
'label' => '支付宝私钥',
'type' => 'text',
'required' => true,
'description' => '应用私钥,用于签名'
],
'public_key' => [
'label' => '支付宝公钥',
'type' => 'text',
'required' => true,
'description' => '支付宝公钥,用于验签'
],
'product_name' => [
'label' => '自定义商品名称',
'type' => 'string',
'description' => '将会体现在支付宝账单中'
]
];
}
public function pay($order): array
{
try {
$gateway = new AlipayF2F();
$gateway->setMethod('alipay.trade.precreate');
$gateway->setAppId($this->getConfig('app_id'));
$gateway->setPrivateKey($this->getConfig('private_key'));
$gateway->setAlipayPublicKey($this->getConfig('public_key'));
$gateway->setNotifyUrl($order['notify_url']);
$gateway->setBizContent([
'subject' => $this->getConfig('product_name') ?? (admin_setting('app_name', 'XBoard') . ' - 订阅'),
'out_trade_no' => $order['trade_no'],
'total_amount' => $order['total_amount'] / 100
]);
$gateway->send();
return [
'type' => 0,
'data' => $gateway->getQrCodeUrl()
];
} catch (\Exception $e) {
Log::error($e);
throw new ApiException($e->getMessage());
}
}
public function notify($params): array|bool
{
if ($params['trade_status'] !== 'TRADE_SUCCESS')
return false;
$gateway = new AlipayF2F();
$gateway->setAppId($this->getConfig('app_id'));
$gateway->setPrivateKey($this->getConfig('private_key'));
$gateway->setAlipayPublicKey($this->getConfig('public_key'));
try {
if ($gateway->verify($params)) {
return [
'trade_no' => $params['out_trade_no'],
'callback_no' => $params['trade_no']
];
} else {
return false;
}
} catch (\Exception $e) {
return false;
}
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"name": "AlipayF2F",
"code": "alipay_f2f",
"type": "payment",
"version": "1.0.0",
"description": "AlipayF2F payment plugin",
"author": "XBoard Team"
}
@@ -0,0 +1,169 @@
<?php
namespace Plugin\AlipayF2f\library;
use Illuminate\Support\Facades\Http;
class AlipayF2F
{
private $appId;
private $privateKey;
private $alipayPublicKey;
private $signType = 'RSA2';
public $bizContent;
public $method;
public $notifyUrl;
public $response;
public function __construct()
{
}
public function verify($data): bool
{
if (is_string($data)) {
parse_str($data, $data);
}
$sign = $data['sign'];
unset($data['sign']);
unset($data['sign_type']);
ksort($data);
$data = $this->buildQuery($data);
$res = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($this->alipayPublicKey, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
if ("RSA2" == $this->signType) {
$result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256) === 1);
} else {
$result = (openssl_verify($data, base64_decode($sign), $res) === 1);
}
openssl_free_key(openssl_get_publickey($res));
return $result;
}
public function setBizContent($bizContent = [])
{
$this->bizContent = json_encode($bizContent);
}
public function setMethod($method)
{
$this->method = $method;
}
public function setAppId($appId)
{
$this->appId = $appId;
}
public function setPrivateKey($privateKey)
{
$this->privateKey = $privateKey;
}
public function setAlipayPublicKey($alipayPublicKey)
{
$this->alipayPublicKey = $alipayPublicKey;
}
public function setNotifyUrl($url)
{
$this->notifyUrl = $url;
}
public function send()
{
$response = Http::get('https://openapi.alipay.com/gateway.do', $this->buildParam())->json();
$resKey = str_replace('.', '_', $this->method) . '_response';
if (!isset($response[$resKey]))
throw new \Exception('从支付宝请求失败');
$response = $response[$resKey];
if ($response['msg'] !== 'Success')
throw new \Exception($response['sub_msg']);
$this->response = $response;
}
public function getQrCodeUrl()
{
$response = $this->response;
if (!isset($response['qr_code']))
throw new \Exception('获取付款二维码失败');
return $response['qr_code'];
}
public function getResponse()
{
return $this->response;
}
public function buildParam(): array
{
$params = [
'app_id' => $this->appId,
'method' => $this->method,
'charset' => 'UTF-8',
'sign_type' => $this->signType,
'timestamp' => date('Y-m-d H:m:s'),
'biz_content' => $this->bizContent,
'version' => '1.0',
'_input_charset' => 'UTF-8'
];
if ($this->notifyUrl)
$params['notify_url'] = $this->notifyUrl;
ksort($params);
$params['sign'] = $this->buildSign($this->buildQuery($params));
return $params;
}
public function buildQuery($query)
{
if (!$query) {
throw new \Exception('参数构造错误');
}
//将要 参数 排序
ksort($query);
//重新组装参数
$params = array();
foreach ($query as $key => $value) {
$params[] = $key . '=' . $value;
}
$data = implode('&', $params);
return $data;
}
private function buildSign(string $signData): string
{
$privateKey = $this->privateKey;
$p_key = array();
//如果私钥是 1行
if (!stripos($privateKey, "\n")) {
$i = 0;
while ($key_str = substr($privateKey, $i * 64, 64)) {
$p_key[] = $key_str;
$i++;
}
}
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . implode("\n", $p_key);
$privateKey = $privateKey . "\n-----END RSA PRIVATE KEY-----";
//私钥
$privateId = openssl_pkey_get_private($privateKey, '');
// 签名
$signature = '';
if ("RSA2" == $this->signType) {
openssl_sign($signData, $signature, $privateId, OPENSSL_ALGO_SHA256);
} else {
openssl_sign($signData, $signature, $privateId, OPENSSL_ALGO_SHA1);
}
openssl_free_key($privateId);
//加密后的内容通常含有特殊字符,需要编码转换下
$signature = base64_encode($signature);
return $signature;
}
}