Skip to content

Commit

Permalink
feat(payment): init smogate gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
Anankke committed Sep 28, 2024
1 parent 256a52f commit 75b4b3e
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 0 deletions.
18 changes: 18 additions & 0 deletions config/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,24 @@
"default": "en_US",
"mark": "PayPal语言"
},
{
"item": "smogate_app_id",
"value": "",
"class": "billing",
"is_public": 1,
"type": "string",
"default": "",
"mark": "Smogate APP ID"
},
{
"item": "smogate_app_secret",
"value": "",
"class": "billing",
"is_public": 0,
"type": "string",
"default": "",
"mark": "Smogate APP Secret"
},
{
"item": "email_driver",
"value": "none",
Expand Down
21 changes: 21 additions & 0 deletions resources/views/tabler/admin/setting/billing.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
<li class="nav-item">
<a href="#paypal" class="nav-link" data-bs-toggle="tab">PayPal</a>
</li>
<li class="nav-item">
<a href="#smogate" class="nav-link" data-bs-toggle="tab">Smogate</a>
</li>
</ul>
</div>
<div class="card-body">
Expand Down Expand Up @@ -304,6 +307,24 @@
</div>
</div>
</div>
<div class="tab-pane" id="smogate">
<div class="card-body">
<div class="form-group mb-3 row">
<label class="form-label col-3 col-form-label">App ID</label>
<div class="col">
<input id="smogate_app_id" type="text" class="form-control"
value="{$settings['smogate_app_id']}">
</div>
</div>
<div class="form-group mb-3 row">
<label class="form-label col-3 col-form-label">App Secret</label>
<div class="col">
<input id="smogate_app_secret" type="text" class="form-control"
value="{$settings['smogate_app_secret']}">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Expand Down
54 changes: 54 additions & 0 deletions resources/views/tabler/gateway/smogate.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<div class="card-inner">
<h4>
支付宝当面付
</h4>
<p class="card-heading"></p>
<input hidden id="amount-smogate" name="amount-smogate" value="{$invoice->price}">
<input hidden id="invoice_id" name="invoice_id" value="{$invoice->id}">
<div id="smogate-qrcode"></div>
<button class="btn btn-flat waves-attach" id="smogate-button" type="button" onclick="smogate();">
充值
</button>
</div>

<script>
let pid = 0;
let flag = false;
let paymentButton = $('#smogate-button');
function smogate() {
paymentButton.attr('disabled', true);
$.ajax({
type: "POST",
url: "/user/payment/purchase/smogate",
dataType: "json",
data: {
amount: $('#amount-smogate').val(),
invoice_id: $('#invoice_id').val(),
},
success: (data) => {
paymentButton.attr('disabled', false);
if (data.ret === 1) {
pid = data.pid;
paymentButton.remove();
paymentButton.append('<div class="text-center"><p>支付宝扫描支付</p></div>');
new QRCode("smogate-qrcode", {
render: "canvas",
width: 200,
height: 200,
text: encodeURI(data.qrcode)
});
paymentButton.append('<div class="text-center my-3"><p>支付成功后请手动刷新页面</p></div>');
paymentButton.attr('href', data.qrcode);
} else {
$('#fail-message').text(data.msg);
$('#fail-dialog').modal('show');
}
},
error: () => {
paymentButton.attr('disabled', false);
}
})
}
</script>
3 changes: 3 additions & 0 deletions src/Controllers/Admin/Setting/BillingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ final class BillingController extends BaseController
'paypal_client_secret',
'paypal_currency',
'paypal_locale',
// Smogate
'smogate_app_id',
'smogate_app_secret',
];

/**
Expand Down
141 changes: 141 additions & 0 deletions src/Services/Gateway/Smogate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

Check failure on line 1 in src/Services/Gateway/Smogate.php

View workflow job for this annotation

GitHub Actions / lint

* [Single blank line at eof] @@ -140,2 +140,2 @@ } -} \ No newline at end of file +} * [Cast spaces] @@ -92,3 +92,3 @@ 'out_trade_no' => $pl->tradeno, - 'total_amount' => (int)($pl->total * 100), + 'total_amount' => (int) ($pl->total * 100), 'notify_url' => self::getCallbackUrl() * [No extra blank lines] @@ -121,3 +121,2 @@ - private function isMobile() * [No whitespace in blank line] @@ -71,3 +71,3 @@ $invoice_id = $this->antiXss->xss_clean($request->getParam('invoice_id')); - + $user = Auth::getUser(); * [Single quote] @@ -35,3 +35,3 @@ $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL, "https://" . Config::obtain('smogate_app_id') . ".vless.org/v1/gateway/pay"); + curl_setopt($curl, CURLOPT_URL, 'https://' . Config::obtain('smogate_app_id') . '.vless.org/v1/gateway/pay'); curl_setopt($curl, CURLOPT_HEADER, 0); * [Ordered class elements] @@ -121,8 +121,2 @@ - - private function isMobile() - { - return strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'mobile') !== false; - } - public function notify($request, $response, $args): ResponseInterface @@ -139,2 +133,8 @@ return View::getSmarty()->fetch('gateway/smogate.tpl'); + } + + + private function isMobile() + { + return strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'mobile') !== false; }

declare(strict_types=1);

namespace App\Services\Gateway;

use App\Models\Paylist;
use App\Models\Config;

Check failure on line 8 in src/Services/Gateway/Smogate.php

View workflow job for this annotation

GitHub Actions / lint

* [Alphabetically sorted uses] Use statements should be sorted alphabetically. The first wrong one is App\Models\Config.
use App\Services\Auth;
use App\Services\View;
use Exception;

Check failure on line 11 in src/Services/Gateway/Smogate.php

View workflow job for this annotation

GitHub Actions / lint

* [Unused uses] Type Exception is not used in this file.
use Psr\Http\Message\ResponseInterface;
use Slim\Http\Response;
use Slim\Http\ServerRequest;

final class Smogate extends Base
{
public static function _name(): string
{
return 'smogate';
}

public static function _enable(): bool
{
return true;
}

public static function _readableName(): string
{
return '支付宝在线充值';
}

public function post($data)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "https://" . Config::obtain('smogate_app_id') . ".vless.org/v1/gateway/pay");
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_HTTPHEADER, ['User-Agent: Smogate ' . Config::obtain('smogate_app_id')]);
$data = curl_exec($curl);
curl_close($curl);

return $data;
}

public function prepareSign($data)
{
ksort($data);
return http_build_query($data);
}

public function sign($data)
{
return strtolower(md5($data . Config::obtain('smogate_app_secret')));
}

public function verify($data, $signature)
{
unset($data['sign']);
$mySign = $this->sign($this->prepareSign($data));
return $mySign === $signature;
}

public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface
{
$amount = $this->antiXss->xss_clean($request->getParam('amount'));
$invoice_id = $this->antiXss->xss_clean($request->getParam('invoice_id'));

Check failure on line 72 in src/Services/Gateway/Smogate.php

View workflow job for this annotation

GitHub Actions / lint

* [Superfluous whitespace] Whitespace found at end of line
$user = Auth::getUser();
if ($amount === '') {
return $response->withJson([
'ret' => 0,
'msg' => '订单金额错误:' . $amount,
]);
}

$pl = new Paylist();
$pl->userid = $user->id;
$pl->total = $amount;
$pl->invoice_id = $invoice_id;
$pl->tradeno = self::generateGuid();
$pl->gateway = self::_readableName();
$pl->save();

$data = [
'method' => 'alipay',
'app_id' => Config::obtain('smogate_app_id'),
'out_trade_no' => $pl->tradeno,
'total_amount' => (int)($pl->total * 100),

Check failure on line 93 in src/Services/Gateway/Smogate.php

View workflow job for this annotation

GitHub Actions / lint

* [Space after cast] Expected 1 space after cast statement; 0 found
'notify_url' => self::getCallbackUrl()

Check failure on line 94 in src/Services/Gateway/Smogate.php

View workflow job for this annotation

GitHub Actions / lint

* [Trailing array comma] Multi-line arrays must have a trailing comma after the last element.
];
$params = $this->prepareSign($data);
$data['sign'] = $this->sign($params);
$result = json_decode($this->post($data), true);

if (isset($result['errors'])) {
return $response->withJson([
'ret' => 0,
'msg' => $result['errors'][array_keys($result['errors'])[0]],
]);
}
if (isset($result['message'])) {
return $response->withJson([
'ret' => 0,
'msg' => $result['message'],
]);
}

return $response->withJson([
'ret' => 1,
'type' => $this->isMobile() ? 'url' : 'qrcode',
'qrcode' => $result['data'],
'amount' => $pl->total,
'pid' => $pl->tradeno,
]);
}


private function isMobile()
{
return strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'mobile') !== false;
}

public function notify($request, $response, $args): ResponseInterface
{
if (!$this->verify($request->getParams(), $request->getParam('sign'))) {

Check failure on line 130 in src/Services/Gateway/Smogate.php

View workflow job for this annotation

GitHub Actions / lint

* [Space after not] Expected 1 space after NOT operator; 0 found
die('FAIL');
}
$this->postPayment($request->getParam('out_trade_no'), 'smogate');
die('SUCCESS');
}

public static function getPurchaseHTML(): string
{
return View::getSmarty()->fetch('gateway/smogate.tpl');
}
}

Check failure on line 141 in src/Services/Gateway/Smogate.php

View workflow job for this annotation

GitHub Actions / lint

* [End file newline] Expected 1 newline at end of file; 0 found

0 comments on commit 75b4b3e

Please sign in to comment.