From 261487437b10d648571ed4b91fafeaf8433234e5 Mon Sep 17 00:00:00 2001 From: LinusX Date: Wed, 5 Jun 2024 07:55:49 +0800 Subject: [PATCH] =?UTF-8?q?[update]=20=E6=96=B0=E5=A2=9Estripe=E8=81=9A?= =?UTF-8?q?=E5=90=88=E6=94=AF=E4=BB=98=E6=96=B9=E5=BC=8F=EF=BC=8C=E9=87=87?= =?UTF-8?q?=E7=94=A8=E5=85=A8=E6=96=B0=E7=9A=84paymentIntents=20API=20[fix?= =?UTF-8?q?]=20=E4=BF=AE=E6=94=B9=E6=94=AF=E4=BB=98=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=B0=8Fbug=20[update]=20=E5=B0=86stripe-php?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8D=87=E7=BA=A7=E8=87=B3=E6=9C=80=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Payments/BTCPay.php | 5 +- app/Payments/StripeALLInOne.php | 173 ++++++++++++++++++++++++++++++++ composer.json | 2 +- 3 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 app/Payments/StripeALLInOne.php diff --git a/app/Payments/BTCPay.php b/app/Payments/BTCPay.php index f2db1d1..60ca039 100644 --- a/app/Payments/BTCPay.php +++ b/app/Payments/BTCPay.php @@ -76,14 +76,13 @@ class BTCPay //NOT BTCPay-Sig //API doc is WRONG! $headerName = 'Btcpay-Sig'; - $signraturHeader = isset($headers[$headerName]) ? $headers[$headerName] : ''; + $signatureHeader = isset($headers[$headerName]) ? $headers[$headerName] : ''; $json_param = json_decode($payload, true); $computedSignature = "sha256=" . \hash_hmac('sha256', $payload, $this->config['btcpay_webhook_key']); - if (!self::hashEqual($signraturHeader, $computedSignature)) { + if (!self::hashEqual($signatureHeader, $computedSignature)) { throw new ApiException('HMAC signature does not match', 400); - return false; } //get order id store in metadata diff --git a/app/Payments/StripeALLInOne.php b/app/Payments/StripeALLInOne.php new file mode 100644 index 0000000..9543d51 --- /dev/null +++ b/app/Payments/StripeALLInOne.php @@ -0,0 +1,173 @@ +config = $config; + } + + public function form() + { + return [ + 'currency' => [ + 'label' => '货币单位', + 'description' => '请使用符合ISO 4217标准的三位字母,例如GBP', + 'type' => 'input', + ], + 'stripe_sk_live' => [ + 'label' => 'SK_LIVE', + 'description' => '', + 'type' => 'input', + ], + 'stripe_webhook_key' => [ + 'label' => 'WebHook密钥签名', + 'description' => 'whsec_....', + 'type' => 'input', + ], + 'description' => [ + 'label' => '自定义商品介绍', + 'description' => '', + 'type' => 'input', + ], + 'payment_method' => [ + 'label' => '支付方式', + 'description' => '请输入alipay或者wechat_pay', + 'type' => 'input', + ] + ]; + } + + public function pay($order) + { + $currency = $this->config['currency']; + $exchange = $this->exchange('CNY', strtoupper($currency)); + if (!$exchange) { + throw new ApiException(__('Currency conversion has timed out, please try again later')); + } + $stripe = new \Stripe\StripeClient($this->config['stripe_sk_live']); + + + $stripePaymentMethod = $stripe->paymentMethods->create([ + 'type' => $this->config['payment_method'], + ]); + // 准备支付意图的基础参数 + $params = [ + 'amount' => floor($order['total_amount'] * $exchange), + 'currency' => $currency, + 'confirm' => true, + 'payment_method' => $stripePaymentMethod->id, + 'automatic_payment_methods' => ['enabled' => true], + 'statement_descriptor' => 'sub-' . $order['user_id'] . '-' . substr($order['trade_no'], -8), + 'description' => $this->config['description'], + 'metadata' => [ + 'user_id' => $order['user_id'], + 'out_trade_no' => $order['trade_no'], + 'identifier' => '' + ], + 'return_url' => $order['return_url'] + ]; + + // 如果支付方式为 wechat_pay,添加相应的支付方式选项 + if ($this->config['payment_method'] === 'wechat_pay') { + $params['payment_method_options'] = [ + 'wechat_pay' => [ + 'client' => 'web' + ], + ]; + } + //更新支持最新的paymentIntents方法,Sources API将在今年被彻底替 + $stripeIntents = $stripe->paymentIntents->create($params); + + $nextAction = null; + //jump url + $jumpUrl = null; + $actionType = 0; + if (!$stripeIntents['next_action']) { + throw new ApiException(__('Payment gateway request failed')); + }else { + $nextAction = $stripeIntents['next_action']; + } + + switch ($this->config['payment_method']){ + case "alipay": + if (isset($nextAction['alipay_handle_redirect'])){ + $jumpUrl = $nextAction['alipay_handle_redirect']['url']; + $actionType = 1; + }else { + throw new ApiException('unable get alipay redirect url', 500); + } + break; + case "wechat_pay": + if (isset($nextAction['wechat_pay_display_qr_code'])){ + $jumpUrl = $nextAction['wechat_pay_display_qr_code']['data']; + Log::info($jumpUrl); + }else { + throw new ApiException('unable get alipay redirect url', 500); + } + } + return [ + 'type' => $actionType, + 'data' => $jumpUrl + ]; + } + + public function notify($params) + { + try { + \Stripe\Stripe::setApiKey($this->config['stripe_sk_live']); + //Workerman不支持使用php://input, stripe同时要求验证签名的payload不能经过修改,所以使用这个方法 + $payload = $GLOBALS['HTTP_RAW_POST_DATA']; + $headers = getallheaders(); + $headerName = 'Stripe-Signature'; + $signatureHeader = $headers[$headerName] ?? ''; + $event = \Stripe\Webhook::constructEvent( + $payload, + $signatureHeader, + $this->config['stripe_webhook_key'] + ); + + } catch (\UnexpectedValueException $e){ + throw new ApiException('Error parsing payload', 400); + + } + catch (\Stripe\Exception\SignatureVerificationException $e) { + throw new ApiException('signature not match', 400); + } + switch ($event->type) { + case 'payment_intent.succeeded': + $object = $event->data->object; + if ($object->status === 'succeeded') { + if (!isset($object->metadata->out_trade_no)) { + return('order error'); + } + $metaData = $object->metadata; + $tradeNo = $metaData->out_trade_no; + return [ + 'trade_no' => $tradeNo, + 'callback_no' => $object->id + ]; + } + break; + default: + throw new ApiException('event is not support'); + } + return('success'); + } + + private function exchange($from, $to) + { + $from = strtolower($from); + $to = strtolower($to); + $result = file_get_contents("https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/" . $from . ".min.json"); + $result = json_decode($result, true); + return $result[$from][$to]; + } +} diff --git a/composer.json b/composer.json index bfccc63..70c2c94 100755 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "paragonie/sodium_compat": "^1.20", "php-curl-class/php-curl-class": "^8.6", "spatie/db-dumper": "^3.4", - "stripe/stripe-php": "^7.36.1", + "stripe/stripe-php": "^v14.9.0", "symfony/http-client": "^6.4", "symfony/mailgun-mailer": "^6.4", "symfony/yaml": "*",