如何在PHP应用中从Stripe Checkout获取Charge Object数据?
在PHP中获取Stripe支付完成后的Charge ID并存储到数据库
核心结论
不能直接在纯HTML的success.html页面获取Stripe的Charge对象信息——敏感数据不能暴露在前端,且Stripe不会通过跳转直接返回Charge详情。正确做法是通过后端PHP代码,利用Stripe返回的session_id查询API获取Charge信息,再存储到数据库。
步骤1:将success.html改为success.php(后端处理)
用户支付完成后,Stripe会跳转到你设置的success_url,并附带session_id参数(比如https://你的域名/success.php?session_id=cs_test_xxx)。你需要用PHP后端处理这个请求:
示例代码(success.php)
<?php // 引入Stripe SDK(Composer安装的话用这个,否则手动引入SDK文件) require_once 'vendor/autoload.php'; // 初始化Stripe,替换为你的Stripe秘密密钥 \Stripe\Stripe::setApiKey('sk_test_xxxxxxxxxxxxxxxxxxxxxxxx'); // 获取URL中的session_id $sessionId = $_GET['session_id'] ?? null; if (!$sessionId) { die('缺少有效支付会话ID'); } try { // 从Stripe获取支付会话详情 $session = \Stripe\Checkout\Session::retrieve($sessionId); // 验证支付是否真的成功(防止用户直接访问success页面伪造状态) if ($session->payment_status !== 'paid') { die('支付未完成,请检查支付状态'); } // 通过会话关联的Payment Intent获取Charge ID $paymentIntent = \Stripe\PaymentIntent::retrieve($session->payment_intent); $chargeId = $paymentIntent->charges->data[0]->id; // 取第一个Charge(通常对应本次支付) // -------------------------- // 以下是存储到数据库的示例(PDO方式) // -------------------------- $dbConfig = [ 'host' => 'localhost', 'dbname' => '你的数据库名', 'user' => '数据库用户名', 'pass' => '数据库密码' ]; $pdo = new PDO( "mysql:host={$dbConfig['host']};dbname={$dbConfig['dbname']};charset=utf8mb4", $dbConfig['user'], $dbConfig['pass'] ); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 假设你有一个存储支付记录的表,比如`user_payments` $stmt = $pdo->prepare("INSERT INTO user_payments (user_id, charge_id, session_id, amount, created_at) VALUES (?, ?, ?, ?, NOW())"); // 替换为实际的用户ID(比如从登录会话中获取) $userId = $_SESSION['user_id'] ?? 0; $amount = $session->amount_total / 100; // Stripe金额以分为单位,转换为元 $stmt->execute([$userId, $chargeId, $sessionId, $amount]); // 给用户显示成功信息 echo "<h1>支付成功!</h1>"; echo "<p>你的支付凭证ID:" . htmlspecialchars($chargeId) . "</p>"; } catch (\Stripe\Exception\ApiErrorException $e) { die('获取支付信息失败:' . $e->getMessage()); } catch (PDOException $e) { die('存储支付记录失败:' . $e->getMessage()); } ?>
步骤2:更可靠的方案——Stripe Webhook
上面的跳转方案依赖用户完成跳转,但如果用户支付后直接关闭页面,你的后端就无法获取Charge信息。因此推荐搭配Stripe Webhook监听checkout.session.completed事件,确保无论用户是否跳转,都能收到支付成功的通知。
Webhook处理代码示例(stripe-webhook.php)
<?php require_once 'vendor/autoload.php'; \Stripe\Stripe::setApiKey('sk_test_xxxxxxxxxxxxxxxxxxxxxxxx'); // 获取Webhook请求体和签名 $payload = @file_get_contents('php://input'); $sigHeader = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? ''; // 替换为你的Stripe Webhook密钥(在Stripe后台获取) $webhookSecret = 'whsec_xxxxxxxxxxxxxxxxxxxxxxxx'; try { // 验证Webhook签名,确保请求来自Stripe $event = \Stripe\Webhook::constructEvent( $payload, $sigHeader, $webhookSecret ); } catch (\UnexpectedValueException $e) { http_response_code(400); exit('无效的请求体'); } catch (\Stripe\Exception\SignatureVerificationException $e) { http_response_code(400); exit('无效的签名'); } // 处理支付完成事件 if ($event->type === 'checkout.session.completed') { $session = $event->data->object; // 获取Charge ID $paymentIntent = \Stripe\PaymentIntent::retrieve($session->payment_intent); $chargeId = $paymentIntent->charges->data[0]->id; // 从会话的metadata中获取用户ID(需要创建会话时提前存入) $userId = $session->metadata['user_id'] ?? 0; // 存储到数据库(同success.php的存储逻辑) $pdo = new PDO( "mysql:host=localhost;dbname=你的数据库名;charset=utf8mb4", '数据库用户名', '数据库密码' ); $stmt = $pdo->prepare("INSERT INTO user_payments (user_id, charge_id, session_id, amount, created_at) VALUES (?, ?, ?, ?, NOW())"); $stmt->execute([$userId, $chargeId, $session->id, $session->amount_total / 100]); } // 告诉Stripe已成功接收事件 http_response_code(200); ?>
补充:创建Checkout Session时添加metadata
为了在Webhook中关联用户,创建会话时要把用户ID存入metadata:
$session = \Stripe\Checkout\Session::create([ 'payment_method_types' => ['card'], 'line_items' => [[ 'price_data' => [ 'currency' => 'cny', 'product_data' => ['name' => '你的商品名称'], 'unit_amount' => 1000, // 10元(单位:分) ], 'quantity' => 1, ]], 'mode' => 'payment', 'success_url' => 'https://你的域名/success.php?session_id={CHECKOUT_SESSION_ID}', 'cancel_url' => 'https://你的域名/cancel.php', // 存入用户ID,方便Webhook关联 'metadata' => ['user_id' => $_SESSION['user_id']] ]);
关键注意事项
- 永远不要在前端使用Stripe秘密密钥:所有Stripe API调用必须在后端完成,避免密钥泄露。
- 验证支付状态:无论用跳转还是Webhook,都要验证
payment_status为paid,防止恶意请求。 - 数据库存储:Charge ID是唯一标识支付的凭证,务必关联用户ID和订单信息,方便后续对账和查询。
内容的提问来源于stack exchange,提问作者John Cowan
相关产品推荐
相关产品推荐

