-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
237 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 GitHub Actions / lint
|
||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Services\Gateway; | ||
|
||
use App\Models\Paylist; | ||
use App\Models\Config; | ||
use App\Services\Auth; | ||
use App\Services\View; | ||
use Exception; | ||
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')); | ||
|
||
$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), | ||
'notify_url' => self::getCallbackUrl() | ||
]; | ||
$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'))) { | ||
die('FAIL'); | ||
} | ||
$this->postPayment($request->getParam('out_trade_no'), 'smogate'); | ||
die('SUCCESS'); | ||
} | ||
|
||
public static function getPurchaseHTML(): string | ||
{ | ||
return View::getSmarty()->fetch('gateway/smogate.tpl'); | ||
} | ||
} | ||