fuc/src/Services/Gateway/Stripe.php
2025-02-23 13:30:57 +08:00

164 lines
4.8 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace App\Services\Gateway;
use App\Models\Config;
use App\Models\Paylist;
use App\Services\Auth;
use App\Services\Exchange;
use App\Services\View;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Http\Message\ResponseInterface;
use RedisException;
use Slim\Http\Response;
use Slim\Http\ServerRequest;
use Stripe\Checkout\Session;
use Stripe\Exception\ApiErrorException;
use Stripe\Exception\SignatureVerificationException;
use Stripe\Stripe as StripeSDK;
use Stripe\Webhook;
use UnexpectedValueException;
use voku\helper\AntiXSS;
final class Stripe extends Base
{
public function __construct()
{
$this->antiXss = new AntiXSS();
}
public static function _name(): string
{
return 'stripe';
}
public static function _enable(): bool
{
return self::getActiveGateway('stripe');
}
public static function _readableName(): string
{
return 'Stripe';
}
/**
* @throws GuzzleException
* @throws RedisException
*/
public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface
{
$price = $this->antiXss->xss_clean($request->getParam('price'));
$invoice_id = $this->antiXss->xss_clean($request->getParam('invoice_id'));
$trade_no = self::generateGuid();
if ($price < Config::obtain('stripe_min_recharge') ||
$price > Config::obtain('stripe_max_recharge')
) {
return $response->withJson([
'ret' => 0,
'msg' => '非法的金额',
]);
}
$user = Auth::getUser();
$pl = new Paylist();
$pl->userid = $user->id;
$pl->total = $price;
$pl->invoice_id = $invoice_id;
$pl->tradeno = $trade_no;
$pl->gateway = self::_readableName();
$pl->save();
$exchange_amount = (new Exchange())->exchange((float) $price, 'CNY', Config::obtain('stripe_currency'));
StripeSDK::setApiKey(Config::obtain('stripe_sk'));
$session = null;
try {
$session = Session::create([
'customer_email' => $user->email,
'line_items' => [
[
'price_data' => [
'currency' => Config::obtain('stripe_currency'),
'product_data' => [
'name' => 'Invoice #' . $invoice_id,
],
'unit_amount' => (int) $exchange_amount,
],
'quantity' => 1,
],
],
'mode' => 'payment',
'payment_intent_data' => [
'metadata' => [
'trade_no' => $trade_no,
],
],
'success_url' => $_ENV['baseUrl'] . '/user/invoice/' . $invoice_id,
'cancel_url' => $_ENV['baseUrl'] . '/user/invoice/' . $invoice_id,
]);
} catch (ApiErrorException $e) {
return $response->withJson([
'ret' => 0,
'msg' => 'Stripe API error',
]);
}
return $response->withHeader('HX-Redirect', $session->url)->withJson([
'ret' => 1,
'msg' => '订单发起成功,正在跳转到支付页面...',
]);
}
public function notify(ServerRequest $request, Response $response, array $args): ResponseInterface
{
try {
$event = Webhook::constructEvent(
$request->getBody()->getContents(),
$request->getHeaderLine('Stripe-Signature'),
Config::obtain('stripe_endpoint_secret')
);
} catch (UnexpectedValueException) {
return $response->withStatus(400)->withJson([
'ret' => 0,
'msg' => 'Unexpected Value error',
]);
} catch (SignatureVerificationException) {
return $response->withStatus(400)->withJson([
'ret' => 0,
'msg' => 'Signature Verification error',
]);
}
$payment_intent = $event->data->object;
if ($event->type === 'payment_intent.succeeded' && $payment_intent->status === 'succeeded') {
$this->postPayment($payment_intent->metadata->trade_no);
return $response->withJson([
'ret' => 1,
'msg' => 'Payment success',
]);
}
return $response->withJson([
'ret' => 0,
'msg' => 'Payment failed',
]);
}
/**
* @throws Exception
*/
public static function getPurchaseHTML(): string
{
return View::getSmarty()->fetch('gateway/stripe.tpl');
}
}