Stripe是一个全球知名的支付处理平台,中文直译(条纹),支持多种支付方式和多个国家/地区的货币。通过集成Stripe订阅支付,可以让独立站接受来自世界各地的订单,并进行方便快捷的跨境支付。

Stripe订阅API提供了一种在网站上集成定期付款的简单方法。如果您想在网站项目上实现会员订阅功能,则需要订阅付费才能定期计费。Stripe 支付网关有助于将定期付款与计划和订阅 API 集成。Stripe 订阅是一种快速有效的方式,允许您的网站会员使用信用卡在线购买会员资格,另外Stripe还支持全球多种信用卡支付,例如:Visa(维萨)、Mastercard(万事达卡)、American Express(美国运通卡)、Discover(发现卡)、 JCB(日本商联卡)、Diners Club(大来卡)、UnionPa(银联卡)等。

在 Stripe 订阅付款中,买家需要根据特定的时间间隔定期付费。您网站的会员可以订阅计划并使用信用卡/借记卡付款,而无需离开网站。在本教程中,我将向您展示如何使用 PHP 集成 Stripe 订阅支付

我将实现以下功能,以通过PHP 中的 Stripe Payment Gateway接受订阅付款。

  • 创建 HTML 表单以选择订阅计划并提供信用卡信息。
  • 使用 Stripe JS 库将 Stripe 卡元素附加到 HTML 表单。
  • 使用 Stripe API 安全地传输卡详细信息、验证并创建订阅。
  • 使用 Stripe API 检索 PaymentIntent 和订阅信息。
  • 通过支持强客户身份验证 (SCA) 流程的 3D 安全身份验证确认卡付款。
  • 验证卡并使用 Stripe API 创建订阅计划。
  • 将交易数据和订阅详细信息存储在数据库中并显示付款状态。

在开始使用PHP集成Stripe之前,我们先看一下文件结构。

stripe_subscription_payment_php/
├── config.php          【存放Stripe API和数据库配置】
├── dbConnect.php       【用于PHP 和 MySQL 连接数据库】
├── index.php           【Stripe订阅表格】
├── payment_init.php    【处理订阅付款】
├── payment-status.php  【付款状态】
├── stripe-php/      
├── js/
|    └── checkout.js    【订阅结帐处理程序脚本】
└── css/
    └── style.css       【页面样式】


Stripe 测试 API 密钥

在Stripe订阅支付网关上线之前,需要检查订阅流程是否正常。你需要测试API密钥数据来检查订阅付款流程。

  • 登录你的Stripe 帐户并导航至开发人员 » API密钥页面。
  • 测试数据块中,您将看到 API 密钥(可发布密钥和秘密密钥)列在标准密钥部分下。要显示密钥,请单击“展示test密钥”按钮。
php集成Stripe订阅支付,解锁外贸独立站的成功之门!-松酷网

先收集可发布密钥秘密密钥以供稍后在脚本中使用。

创建数据库表

我们需要在数据库里创建3个数据表,分别为plans、users、user_subscriptions。

1.第一步先创建一个名为plans表来保存订阅套餐信息。

CREATE TABLE `plans` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `price` float(10,2) NOT NULL DEFAULT 0.00 COMMENT 'Minimum amount is $0.50 US',
  `interval` enum('week','month','year') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'month',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

2.第二步创建一个users表来保存会员信息

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `subscription_id` int(11) NOT NULL DEFAULT 0 COMMENT 'foreign key of "user_subscriptions" table',
  `first_name` varchar(25) COLLATE utf8_unicode_ci NOT NULL,
  `last_name` varchar(25) COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `phone` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created` datetime NOT NULL DEFAULT current_timestamp(),
  `modified` datetime NOT NULL DEFAULT current_timestamp(),
  `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '1=Active | 0=Inactive',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

 

3.第三步创建一个user_subscriptions表来保存订阅信息。

CREATE TABLE `user_subscriptions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL DEFAULT 0 COMMENT 'foreign key of "users" table',
  `plan_id` int(5) DEFAULT NULL COMMENT 'foreign key of "plans" table',
  `payment_method` enum('stripe') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'stripe',
  `stripe_subscription_id` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `stripe_customer_id` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `stripe_payment_intent_id` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `paid_amount` float(10,2) NOT NULL,
  `paid_amount_currency` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
  `plan_interval` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
  `plan_interval_count` tinyint(2) NOT NULL DEFAULT 1,
  `customer_name` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `customer_email` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created` datetime NOT NULL,
  `plan_period_start` datetime DEFAULT NULL,
  `plan_period_end` datetime DEFAULT NULL,
  `status` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

在继续之前,我们需要将一些数据添加到plans数据库的表中,以便用户可以选择订阅计划。

INSERT  INTO  `plans` ( `id` , `name` , `price` , `interval` ) VALUES 
( 1 , '每周订阅' , 25:00 , '周' ),
( 2 , '每月订阅' , 75.00 , '月份' ),
( 3 , '年度订阅' , 799.00 , '年份' );

Stripe API 和数据库配置 (config.php)

在该config.php文件中,为 Stripe API 和数据库设置定义了常量变量。

Stripe API 常量:

  • STRIPE_API_KEY – 指定 API 密钥。
  • STRIPE_PUBLISHABLE_KEY – 指定 API 可发布密钥。
  • STRIPE_CURRENCY – 货币代码。

数据库常量:

  • DB_HOST – 指定数据库主机。
  • DB_USERNAME – 指定数据库用户名。
  • DB_PASSWORD – 指定数据库密码。
  • DB_NAME – 指定数据库名称。
<?php 
/* Stripe API 配置
 * 请记住在生产中切换到您的实时可发布密钥和密钥!
 * 在此处查看您的密钥:https://dashboard.stripe.com/account/apikeys 
 */ 
define ( 'STRIPE_API_KEY' ,  'Your_API_Secret_key' ); 
define ('STRIPE_PUBLISHABLE_KEY' ,  'Your_API_Publishable_key'); 
define ('STRIPE_CURRENCY' ,  '$' ); 
  
// 数据库配置  
define( 'DB_HOST' , 'MySQL_Database_Host' ); 
define('DB_USERNAME',  'MySQL_Database_Username' ); 
define('DB_PASSWORD' ,  'MySQL_Database_Password' ); 
define('DB_NAME' ,  'MySQL_Database_Name');

请注意: Stripe API密钥可发布密钥将在您的 Stripe 帐户的 API 密钥数据部分中找到。

数据库连接(dbConnect.php)

dbConnect.php文件用于使用 PHP 和 MySQL 连接数据库。

<?php  
// 连接数据库 
$db = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);  
  
// 连接失败时显示错误  
if ($db->connect_errno) {  
    printf("Connect failed: %s\n", $db->connect_error);  
    exit();  
}

Stripe 订阅表格 (index.php)

包含配置文件并从数据库中获取订阅计划。

<?php 
// 包含配置文件  
require_once 'config.php'; 
 
// 包含数据库连接文件
include_once 'dbConnect.php'; 
 
// 从数据库获取计划
$sqlQ = "SELECT * FROM plans"; 
$stmt = $db->prepare($sqlQ); 
$stmt->execute(); 
$stmt->store_result(); 
?>

Stripe JS 库:
包含 Stripe.js v3 库,可帮助直接从浏览器安全地将敏感信息发送到 Stripe。

<script src="https://js.stripe.com/v3/"></script>

Checkout JS 脚本:
包括自定义脚本 ( checkout.js),以使用 JavaScript 处理 Stripe API 的订阅。

  • STRIPE_PUBLISHABLE_KEY属性用于将 Stripe API Key 传递给 JS 脚本。
<script src="js/checkout.js" STRIPE_PUBLISHABLE_KEY="<?php echo STRIPE_PUBLISHABLE_KEY; ?>" defer></script>

HTML 订阅表单:
最初,所有计划都列在下拉选择框下,并定义一个 HTML 表单来收集用户信息(姓名和电子邮件)和卡详细信息(卡号、到期日期和 CVC 号码)。

  • #card-element通过 Stripe.js 库定义一个 HTML 元素 ( ) 来附加卡片元素。
  • 定义元素以显示付款处理通知。
<div class="panel">
    <div class="panel-heading">
        <h3 class="panel-title">使用 Stripe 订阅</h3>
        
        <!-- 套餐信息 -->
        <div>
            <b>选择套餐:</b>
            <select id="subscr_plan" class="form-control">
                <?php 
                if($stmt->num_rows > 0){ 
                    $stmt->bind_result($id, $name, $price, $interval); 
                    while($stmt->fetch()){ 
                ?>
                    <option value="<?php echo $id; ?>"><?php echo $name.' [$'.$price.'/'.$interval.']'; ?></option>
                <?php 
                    } 
                } 
                ?>
            </select>
        </div>
    </div>
    <div class="panel-body">
        <!-- 显示状态消息 -->
        <div id="paymentResponse" class="hidden"></div>
        
        <!-- 显示订阅表单 -->
        <form id="subscrFrm">
            <div class="form-group">
                <label>姓名</label>
                <input type="text" id="name" class="form-control" placeholder="Enter name" required="" autofocus="">
            </div>
            <div class="form-group">
                <label>电子邮箱</label>
                <input type="email" id="email" class="form-control" placeholder="Enter email" required="">
            </div>
            
            <div class="form-group">
                <label>信用卡信息</label>
                <div id="card-element">
                    <!-- Stripe.js将在此处创建卡片输入元素 -->
                </div>
            </div>
            
            <!-- 表单提交按钮 -->
            <button id="submitBtn" class="btn btn-success">
                <div class="spinner hidden" id="spinner"></div>
                <span id="buttonText">继续</span>
            </button>
        </form>
    </div>
</div>

订阅结帐处理程序脚本 (checkout.js)

以下 JavaScript 代码用于使用 Stripe JS v3 库处理订阅过程。

  • 创建 Stripe 对象的实例并设置可发布的 API 密钥。
  • 创建card 元素并将cardElement 安装到HTML 元素( #card-element)。
  • 将事件处理程序 (handleSubscrSubmit) 附加到订阅表单。
  • handleSubscrSubmit()函数用于,
    • 将选定的计划 ID 和客户详细信息发布到服务器端脚本 ( payment_init.php)。
    • 加载paymentProcess()方法并在其中传递subscriptionId& Payment Intent 。clientSecret
  • paymentProcess()函数用于,
    • stripe.confirmPayment使用Stripe Payment Intents JS API确认 PaymentIntent 。
    • 将订阅和交易信息发布到服务器端脚本 ( payment_init.php) 并重定向到支付状态页面 ( payment-status.php)。
  • showMessage()功能有助于显示状态消息。
  • setLoading()功能禁用提交按钮并在付款提交时显示微调器。
  • setProcessing()函数禁用付款表单并显示有关付款处理的通知。
// 获取 API 密钥
let STRIPE_PUBLISHABLE_KEY = document.currentScript.getAttribute('STRIPE_PUBLISHABLE_KEY');

//创建Stripe对象的实例并设置可发布的API密钥
const stripe = Stripe(STRIPE_PUBLISHABLE_KEY);

//选择订阅表单元素
const subscrFrm = document.querySelector("#subscrFrm");

//将事件处理程序附加到订阅表单
subscrFrm.addEventListener("submit", handleSubscrSubmit);

let elements = stripe.elements();
var style = {
    base: {
        lineHeight: "30px",
        fontSize: "16px",
        border: "1px solid #ced4da",
    }
};
let cardElement = elements.create('card', { style: style });
cardElement.mount('#card-element');

cardElement.on('change', function (event) {
    displayError(event);
});

function displayError(event) {
    if (event.error) {
        showMessage(event.error.message);
    }
}

async function handleSubscrSubmit(e) {
    e.preventDefault();
    setLoading(true);
    
    let subscr_plan_id = document.getElementById("subscr_plan").value;
    let customer_name = document.getElementById("name").value;
    let customer_email = document.getElementById("email").value;
    
    //将订阅信息发布到服务器端脚本
    fetch("payment_init.php", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ request_type:'create_customer_subscription', subscr_plan_id: subscr_plan_id, name: customer_name, email: customer_email }),
    })
    .then(response => response.json())
    .then(data => {
        if (data.subscriptionId && data.clientSecret) {
            paymentProcess(data.subscriptionId, data.clientSecret, data.customerId);
        } else {
            showMessage(data.error);
        }
        
        setLoading(false);
    })
    .catch(console.error);
}

function paymentProcess(subscriptionId, clientSecret, customerId){
    let subscr_plan_id = document.getElementById("subscr_plan").value;
    let customer_name = document.getElementById("name").value;
    
   //创建付款方式并确认付款意向。
    stripe.confirmCardPayment(clientSecret, {
        payment_method: {
            card: cardElement,
            billing_details: {
                name: customer_name,
            },
        }
    }).then((result) => {
        if(result.error) {
            showMessage(result.error.message);
            setLoading(false);
        } else {
            // 认购付款成功
            // 将交易信息发布到服务器端脚本并重定向到支付状态页面
            fetch("payment_init.php", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ request_type:'payment_insert', subscription_id: subscriptionId, customer_id: customerId, subscr_plan_id: subscr_plan_id,payment_intent: result.paymentIntent }),
            })
            .then(response => response.json())
            .then(data => {
                if (data.payment_id) {
                    window.location.href = 'payment-status.php?sid='+data.payment_id;
                } else {
                    showMessage(data.error);
                    setLoading(false);
                }
            })
            .catch(console.error);
        }
    });
}

//显示消息
function showMessage(messageText) {
    const messageContainer = document.querySelector("#paymentResponse");
    
    messageContainer.classList.remove("hidden");
    messageContainer.textContent = messageText;
    
    setTimeout(function () {
        messageContainer.classList.add("hidden");
        messageText.textContent = "";
    }, 5000);
}

//在提交付款时显示Loading
function setLoading(isLoading) {
    if (isLoading) {
        document.querySelector("#submitBtn").disabled = true;
        document.querySelector("#spinner").classList.remove("hidden");
        document.querySelector("#buttonText").classList.add("hidden");
    } else {
        document.querySelector("#submitBtn").disabled = false;
        document.querySelector("#spinner").classList.add("hidden");
        document.querySelector("#buttonText").classList.remove("hidden");
    }
}

Stripe PHP 库

Stripe PHP 库用于访问 PHP 中的 Stripe API。它有助于使用 Stipre API 创建客户、计划和订阅。所有需要的库文件都包含在我们的源代码中,您无需单独下载。

处理订阅付款( payment_init.php )

该服务器端脚本由 JavaScript 代码 ( ) 中的客户端 Fetch API 访问,js/checkout.js以使用 Stripe API PHP 库创建 PaymentIntent、订阅并处理信用卡支付。

  • 包括 Stripe PHP 库。
  • 使用Stripe 类的setApiKey()方法设置 API 密钥。
  • file_get_contents()在 PHP 中使用和从 POST 正文中检索 JSON json_decode()
  • 从 SESSION 中获取登录用户 ID。

如果create_customer_subscription提交请求:

  • 使用PHP $_POST方法从表单字段获取选定的计划 ID 和买家信息。
  • 根据选定的计划 ID 从数据库中获取计划详细信息。
  • create()使用Stripe Customer API 的方法 创建客户。
    • name- 顾客姓名。
    • email– 客户电子邮件。
  • create()使用Stripe Price API 的方法 创建价格。
    • unit_amount– 以美分为单位的正整数(免费计划为 0),将定期收费。
    • currency– 小写的三字母 ISO 货币代码。
    • recurring.interval– 指定计费频率(日、周、月或年)。
    • recurring.interval_count– 订阅计费之间的间隔数。例如,interval=month 且interval_count=每 2 个月 2 个账单。允许的最长间隔为一年(1 年、12 个月或 52 周)。
    • product_data.name– 订阅计划的名称。
  • 使用 Stripe Subscription API 的方法创建订阅create()
    • customer– 要订阅的客户的标识符。
    • items.price– 价格对象的ID。
    • payment_behavior– 创建状态=不完整的订阅,以使 3DS 身份验证要求完成付款。
    • expand– 使用latest_invoice. payment_intent
  • 将subscriptionId、clientSecret、customerId返回给客户端。

如果payment_insert提交请求:

  • 使用PHP $_POST方法从表单字段获取 payment_intent、subscription_id 和 customer_id 。
  • 使用 Stripe Customer API 的 create() 方法创建客户。
  • 使用 Payment Intents API 的 update() 方法用客户 ID 更新 PaymentIntent。
  • 使用 Stripe Customer API 的retrieve() 方法检索客户详细信息。
  • 检查充值是否成功并验证订阅状态。
  • 使用 Stripe Customer API 的retrieve() 方法检索客户详细信息。
  • 如果用户 ID 在 SESSION 中不可用,请将客户详细信息插入 DB users 表中,并获取将与订阅数据关联的用户 ID。
  • 使用 Stripe Subscription API 的retrieve() 方法检索订阅详细信息。
  • 使用 MySQL 准备语句和 PHP 将事务数据插入数据库。
  • 将DB插入ID作为支付ID返回给客户端。

 

<?php 
// 包括配置文件 
require_once 'config.php'; 
 
// 包括数据库连接文件 
include_once 'dbConnect.php'; 
 
// 包括Stripe PHP库
require_once 'stripe-php/init.php'; 
 
// 设置API密钥
\Stripe\Stripe::setApiKey(STRIPE_API_KEY); 
 
$jsonStr = file_get_contents('php://input'); 
$jsonObj = json_decode($jsonStr); 
 
// 从当前SESSION获取用户ID
$userID = isset($_SESSION['loggedInUserID'])?$_SESSION['loggedInUserID']:0; 
 
if($jsonObj->request_type == 'create_customer_subscription'){ 
    $subscr_plan_id = !empty($jsonObj->subscr_plan_id)?$jsonObj->subscr_plan_id:''; 
    $name = !empty($jsonObj->name)?$jsonObj->name:''; 
    $email = !empty($jsonObj->email)?$jsonObj->email:''; 
     
    //从数据库获取套餐详细信息
    $sqlQ = "SELECT `name`,`price`,`interval` FROM plans WHERE id=?"; 
    $stmt = $db->prepare($sqlQ); 
    $stmt->bind_param("i", $subscr_plan_id); 
    $stmt->execute(); 
    $stmt->bind_result($planName, $planPrice, $planInterval); 
    $stmt->fetch(); 
 
    // 将价格转换为美分 
    $planPriceCents = round($planPrice*100); 
     
    // 将客户添加到Stripe 
    try {   
        $customer = \Stripe\Customer::create([ 
            'name' => $name,  
            'email' => $email 
        ]);  
    }catch(Exception $e) {   
        $api_error = $e->getMessage();   
    } 
     
    if(empty($api_error) && $customer){ 
        try { 
            // 使用订阅信息和间隔创建价格
            $price = \Stripe\Price::create([ 
                'unit_amount' => $planPriceCents, 
                'currency' => STRIPE_CURRENCY, 
                'recurring' => ['interval' => $planInterval], 
                'product_data' => ['name' => $planName], 
            ]); 
        } catch (Exception $e) {  
            $api_error = $e->getMessage(); 
        } 
         
        if(empty($api_error) && $price){ 
            // 创建新订阅
            try { 
                $subscription = \Stripe\Subscription::create([ 
                    'customer' => $customer->id, 
                    'items' => [[ 
                        'price' => $price->id, 
                    ]], 
                    'payment_behavior' => 'default_incomplete', 
                    'expand' => ['latest_invoice.payment_intent'], 
                ]); 
            }catch(Exception $e) { 
                $api_error = $e->getMessage(); 
            } 
             
            if(empty($api_error) && $subscription){ 
                $output = [ 
                    'subscriptionId' => $subscription->id, 
                    'clientSecret' => $subscription->latest_invoice->payment_intent->client_secret, 
                    'customerId' => $customer->id 
                ]; 
             
                echo json_encode($output); 
            }else{ 
                echo json_encode(['error' => $api_error]); 
            } 
        }else{ 
            echo json_encode(['error' => $api_error]); 
        } 
    }else{ 
        echo json_encode(['error' => $api_error]); 
    } 
}elseif($jsonObj->request_type == 'payment_insert'){ 
    $payment_intent = !empty($jsonObj->payment_intent)?$jsonObj->payment_intent:''; 
    $subscription_id = !empty($jsonObj->subscription_id)?$jsonObj->subscription_id:''; 
    $customer_id = !empty($jsonObj->customer_id)?$jsonObj->customer_id:''; 
    $subscr_plan_id = !empty($jsonObj->subscr_plan_id)?$jsonObj->subscr_plan_id:''; 
     
    // 从数据库中获取套餐详细信息 
    $sqlQ = "SELECT `interval` FROM plans WHERE id=?"; 
    $stmt = $db->prepare($sqlQ); 
    $stmt->bind_param("i", $subscr_plan_id); 
    $stmt->execute(); 
    $stmt->bind_result($interval); 
    $stmt->fetch(); 
    $planInterval = $interval; 
    $stmt->close(); 
 
    // 检索客户信息 
    try {   
        $customer = \Stripe\Customer::retrieve($customer_id);  
    }catch(Exception $e) {   
        $api_error = $e->getMessage();   
    } 
     
    // 判断是否支付成功 
    if(!empty($payment_intent) && $payment_intent->status == 'succeeded'){ 
         
        // 检索订阅信息 
        try {   
            $subscriptionData = \Stripe\Subscription::retrieve($subscription_id);  
        }catch(Exception $e) {   
            $api_error = $e->getMessage();   
        } 
 
        $payment_intent_id = $payment_intent->id; 
        $paidAmount = $payment_intent->amount; 
        $paidAmount = ($paidAmount/100); 
        $paidCurrency = $payment_intent->currency; 
        $payment_status = $payment_intent->status; 
         
        $created = date("Y-m-d H:i:s", $payment_intent->created); 
        $current_period_start = $current_period_end = ''; 
        if(!empty($subscriptionData)){ 
            $created = date("Y-m-d H:i:s", $subscriptionData->created); 
            $current_period_start = date("Y-m-d H:i:s", $subscriptionData->current_period_start); 
            $current_period_end = date("Y-m-d H:i:s", $subscriptionData->current_period_end); 
        } 
         
        $customer_name = $customer_email = ''; 
        if(!empty($customer)){ 
            $customer_name = !empty($customer->name)?$customer->name:''; 
            $customer_email = !empty($customer->email)?$customer->email:''; 
 
            if(!empty($customer_name)){ 
                $name_arr = explode(' ', $customer_name); 
                $first_name = !empty($name_arr[0])?$name_arr[0]:''; 
                $last_name = !empty($name_arr[1])?$name_arr[1]:''; 
            } 
             
            // 插入用户详细信息,如果不存在DB用户表中 
            if(empty($userID)){ 
                $sqlQ = "INSERT INTO users (first_name,last_name,email) VALUES (?,?,?)"; 
                $stmt = $db->prepare($sqlQ); 
                $stmt->bind_param("sss", $first_name, $last_name, $customer_email); 
                $insertUser = $stmt->execute(); 
                 
                if($insertUser){ 
                    $userID = $stmt->insert_id; 
                } 
            } 
        } 
         
        // 检查是否存在重复的TXN ID的任何事务数据 
        $sqlQ = "SELECT id FROM user_subscriptions WHERE stripe_payment_intent_id = ?"; 
        $stmt = $db->prepare($sqlQ);  
        $stmt->bind_param("s", $payment_intent_id); 
        $stmt->execute(); 
        $stmt->bind_result($id); 
        $stmt->fetch(); 
        $prevPaymentID = $id; 
        $stmt->close(); 
         
        $payment_id = 0; 
        if(!empty($prevPaymentID)){ 
            $payment_id = $prevPaymentID; 
        }else{ 
            // 将事务数据插入数据库
            $sqlQ = "INSERT INTO user_subscriptions (user_id,plan_id,stripe_subscription_id,stripe_customer_id,stripe_payment_intent_id,paid_amount,paid_amount_currency,plan_interval,customer_name,customer_email,created,plan_period_start,plan_period_end,status) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; 
            $stmt = $db->prepare($sqlQ); 
            $stmt->bind_param("iisssdssssssss", $userID, $subscr_plan_id, $subscription_id, $customer_id, $payment_intent_id, $paidAmount, $paidCurrency, $planInterval, $customer_name, $customer_email, $created, $current_period_start, $current_period_end, $payment_status); 
            $insert = $stmt->execute(); 
             
            if($insert){ 
                $payment_id = $stmt->insert_id; 
                 
                // 在用户表中更新订阅ID 
                $sqlQ = "UPDATE users SET subscription_id=? WHERE id=?"; 
                $stmt = $db->prepare($sqlQ); 
                $stmt->bind_param("ii", $payment_id, $userID); 
                $update = $stmt->execute(); 
            } 
        } 
         
        $output = [ 
            'payment_id' => base64_encode($payment_id) 
        ]; 
        echo json_encode($output); 
    }else{ 
        echo json_encode(['error' => '事务处理失败!']); 
    } 
} 
?>

付款状态( payment-status.php )

根据paymentIntent.status和 3D Secure 身份验证的付款确认,用户将被重定向到此页面。

  • 使用 PHP 和 MySQL 从数据库中获取交易数据。
  • 在网页上显示订阅状态和交易信息。
<?php 
// 包括配置文件  
require_once 'config.php'; 
 
// 包括数据库连接文件  
require_once 'dbConnect.php'; 
 
$payment_id = $statusMsg = ''; 
$status = 'error'; 
 
// 检查订阅ID是否不为空 
if(!empty($_GET['sid'])){ 
    $subscr_id  = base64_decode($_GET['sid']); 
     
    // 从数据库获取订阅信息 
    $sqlQ = "SELECT S.id, S.stripe_subscription_id, S.paid_amount, S.paid_amount_currency, S.plan_interval, S.plan_period_start, S.plan_period_end, S.customer_name, S.customer_email, S.status, P.name as plan_name, P.price as plan_amount FROM user_subscriptions as S LEFT JOIN plans as P On P.id = S.plan_id WHERE S.id = ?"; 
    $stmt = $db->prepare($sqlQ);  
    $stmt->bind_param("s", $subscr_id); 
    $stmt->execute(); 
    $stmt->store_result(); 
     
    if($stmt->num_rows > 0){ 
        // 订阅和交易细节 
        $stmt->bind_result($subscription_id, $stripe_subscription_id, $paid_amount, $paid_amount_currency, $plan_interval, $plan_period_start, $plan_period_end, $customer_name, $customer_email, $subscr_status, $plan_name, $plan_amount); 
        $stmt->fetch(); 
         
        $status = 'success'; 
        $statusMsg = '您的订阅付款成功了!'; 
    }else{ 
        $statusMsg = "交易失败了!"; 
    } 
}else{ 
    header("Location: index.php"); 
    exit; 
} 
?>

<?php if(!empty($subscription_id)){ ?>
    <h1 class="<?php echo $status; ?>"><?php echo $statusMsg; ?></h1>
    
    <h4>付款信息</h4>
    <p><b>参考编号:</b> <?php echo $subscription_id; ?></p>
    <p><b>订阅ID:</b> <?php echo $stripe_subscription_id; ?></p>
    <p><b>支付金额:</b> <?php echo $paid_amount.' '.$paid_amount_currency; ?></p>
    <p><b>支付状态:</b> <?php echo $subscr_status; ?></p>
    
    <h4>订阅信息</h4>
    <p><b>套餐名称:</b> <?php echo $plan_name; ?></p>
    <p><b>数量:</b> <?php echo $plan_amount.' '.STRIPE_CURRENCY; ?></p>
    <p><b>套餐期限:</b> <?php echo $plan_interval; ?></p>
    <p><b>期限开始:</b> <?php echo $plan_period_start; ?></p>
    <p><b>期限结束:</b> <?php echo $plan_period_end; ?></p>
    
    <h4>顾客信息</h4>
    <p><b>顾客名称:</b> <?php echo $customer_name; ?></p>
    <p><b>顾客电子邮箱:</b> <?php echo $customer_email; ?></p>
<?php }else{ ?>
    <h1 class="error">您的交易失败了!</h1>
    <p class="error"><?php echo $statusMsg; ?></p>
<?php } ?>

 

Strip 订阅支付功能

php集成Stripe订阅支付,解锁外贸独立站的成功之门!-松酷网

测试卡详情

要测试 Stripe 订阅支付 API 集成,请使用以下测试卡号、有效的未来到期日期和任何随机 CVC 号。

  • 4242424242424242 – 签证
  • 4000056655665556 – Visa(借记卡)
  • 5555555555554444 – 万事达卡
  • 5200828282828210 – 万事达卡(借记卡)
  • 378282246310005 – 美国运通
  • 6011111111111117 – 发现

3D安全认证测试卡号:

  • 4000002500003155 – 需要 3D 安全身份验证 (SCA)
  • 4000002760003184 – 需要 3D 安全身份验证 (SCA)

启用 Stripe 支付网关

订阅 API 集成完成且支付流程正常运行后,请按照以下步骤启用 Stripe 支付网关。

  • 登录您的Stripe 帐户并导航至开发人员 » API密钥页面。
  • 从实时数据部分收集 API 密钥(可发布密钥和秘密密钥)。
  • 在该config.php文件中,将测试 API 密钥(可发布密钥和秘密密钥)替换为实时 API 密钥(可发布密钥和秘密密钥)。
    定义('STRIPE_API_KEY' ,  'Insert_Stripe_Live_API_Secret_Key_HERE' );  
    定义('STRIPE_PUBLISHABLE_KEY' ,  'Insert_Stripe_Live_API_Publishable_Key_HERE' );

 

总结

Stripe 订阅支付 API 是在线接受订阅信用支付的最简单选项。你可以使用 Stripe API 和 PHP 将定期计费功能添加到 Web 应用程序。我们的示例脚本可帮助您通过 Stripe 在特定时间间隔内定期向用户收费。此外,还集成了3D 安全身份验证功能,使该 Stripe 集成脚本可以用于 SCA(强客户身份验证)。可以根据您的需要增强此Stripe 订阅支付脚本的功能。