[ Laravel 5.2 文档 ] 服务 -- 订阅支付实现:Laravel Cashier
1、简介
LaravelCashier 为通过 Stripe实现订阅支付服务提供了一个优雅平滑的接口。它封装了几乎所有你恐惧编写的样板化的订阅支付代码。除了基本的订阅管理外,Cashier还支持处理优惠券、订阅升级/替换、订阅“数量”、取消宽限期,甚至生成PDF 发票。
1.1 安装&配置
Composer
首先,添加 Cashier 包到 composer.json文件并运行 composer update命令:
"laravel/cashier": "~6.0"
服务提供者
接下来,在 config/app.php配置文件中注册服务提供者: Laravel\Cashier\CashierServiceProvider。
迁移
使用 Cashier 之前,我们需要准备好数据库。我们需要添加一个字段到 users表,还要创建新的 subscriptions表来处理所有用户订阅:
Schema::table('users', function ($table) { $table->string('stripe_id')->nullable(); $table->string('card_brand')->nullable(); $table->string('card_last_four')->nullable();});Schema::create('subscriptions', function ($table) { $table->increments('id'); $table->integer('user_id'); $table->string('name'); $table->string('stripe_id'); $table->string('stripe_plan'); $table->integer('quantity'); $table->timestamp('trial_ends_at')->nullable(); $table->timestamp('ends_at')->nullable(); $table->timestamps();});
创建好迁移后,只需简单运行 migrate命令,相应修改就会更新到数据库。
设置模型
接下来,添加 Billabletrait 到 User模型类:
use Laravel\Cashier\Billable;class User extends Authenticatable{ use Billable;}
Stripe键
最后,在配置文件 config/services.php中设置 Stripe 键:
'stripe' => [ 'model' => 'User', 'secret' => env('STRIPE_API_SECRET'),],
2、订阅实现
2.1 创建订阅
要创建一个订阅,首先要获取一个账单模型的实例,通常是 App\User的实例。获取到该模型实例之后,你可以使用 newSubscription方法来创建该模型的订阅:
$user = User::find(1);$user->newSubscription('main', 'monthly')->create($creditCardToken);
第一个传递给 newSubscription方法的参数是该订阅的名字,如果应用只有一个订阅,可以将其称作 main或 primary,第二个参数用于指定用户订阅的 Stripe计划,该值对应 Stripe 中相应计划的 id。
create方法会自动创建这个 Stripe 订阅,同时更新数据库中 Stripe 的客户 ID(即 users表中的 stripe_id)和其它相关的账单信息。如果你的订阅计划有试用期,试用期结束时间也会自动被设置到数据库相应字段。
额外的用户信息
如果你想要指定额外的客户信息,你可以将其作为第二个参数传递给 create方法:
$user->newSubscription('main', 'monthly')->create($creditCardToken, [ 'email' => $email, 'description' => 'Our First Customer']);
要了解更多 Stripe 支持的字段,可以查看 Stripe 关于 创建消费者的文档。
优惠券
如果你想要在创建订阅的时候使用优惠券,可以使用 withCoupon方法:
$user->newSubscription('main', 'monthly') ->withCoupon('code') ->create($creditCardToken);
2.2 检查订阅状态
用户订阅你的应用后,你可以使用各种便利的方法来简单检查订阅状态。首先,如果用户有一个有效的订阅,则 subscribed方法返回 true,即使订阅现在出于试用期:
if ($user->subscribed('main')) { //}
subscribed方法还可以用于路由中间件,基于用户订阅状态允许你对路由和控制器的访问进行过滤:
public function handle($request, Closure $next){ if ($request->user() && ! $request->user()->subscribed('main')) { // This user is not a paying customer... return redirect('billing'); } return $next($request);}
如果你想要判断一个用户是否还在试用期,可以使用 onTrial方法,该方法在为还处于试用期的用户显示警告信息很有用:
if ($user->->subscription('main')->onTrial()) { //}
onPlan方法可用于判断用户是否基于 Stripe ID 订阅了给定的计划:
if ($user->onPlan('monthly')) { //}
已取消的订阅状态
要判断用户是否曾经是有效的订阅者,但现在取消了订阅,可以使用 cancelled方法:
if ($user->subscription('main')->cancelled()) { //}
你还可以判断用户是否曾经取消过订阅,但现在仍然在“宽限期”直到完全失效。例如,如果一个用户在3月5号取消了一个实际有效期到3月10号的订阅,该用户处于“宽限期”直到3月10号。注意 subscribed方法在此期间仍然返回 true。
if ($user->subscription('main')->onGracePeriod()) { //}
2.3 修改订阅
用户订阅应用后,偶尔想要改变到新的订阅计划,要将用户切换到新的订阅,使用 swap方法。例如,我们可以轻松切换用户到 premium订阅:
$user = App\User::find(1);$user->subscription('main')->swap('stripe-plan-id');
如果用户在试用,试用期将会被维护。还有,如果订阅存在数量,数量也可以被维护。切换订阅计划后,
可以使用 invoice方法立即给用户开发票:
$user->subscription('main')->swap('stripe-plan-id');$user->invoice();
2.4 订阅数量
有时候订阅也会被数量影响,例如,应用中每个账户每月需要付费$10,要简单增加或减少订阅数量,使用 incrementQuantity和 decrementQuantity方法:
$user = User::find(1);$user->subscription('main')->incrementQuantity();// Add five to the subscription's current quantity...$user->subscription('main')->incrementQuantity(5);$user->subscription('main')->decrementQuantity();// Subtract five to the subscription's current quantity...$user->subscription('main')->decrementQuantity(5);
你也可以使用 updateQuantity方法指定数量:
$user->subscription('main')->updateQuantity(10);
想要了解更多订阅数量信息,查阅相关 Stripe文档。
2.5 订阅税金
在 Cashier 中,提供 tax_percent值发送给 Stripe 很简单。要指定用户支付订阅的税率,实现账单模型的 getTaxPercent方法,并返回一个在0到100之间的数值,不要超过两位小数:
public function getTaxPercent() { return 20;}
这将使你可以在模型基础上使用税率,对跨越不同国家的用户很有用。
2.6 取消订阅
要取消订阅,可以调用用户订阅上的 cancel方法:
$user->subscription('main')->cancel();
当订阅被取消时,Cashier 将会自动设置数据库中的 subscription_ends_at字段。该字段用于了解 subscribed方法什么时候开始返回 false。例如,如果客户3月1号份取消订阅,但订阅直到3月5号才会结束,那么 subscribed方法继续返回 true直到3月5号。
你可以使用 onGracePeriod方法判断用户是否已经取消订阅但仍然在“宽限期”:
if ($user->subscription('main')->onGracePeriod()) { //}
2.7 恢复订阅
如果用户已经取消订阅但想要恢复该订阅,可以使用 resume方法,前提是该用户必须在宽限期内:
$user->subscription('main')->resume();
如果该用户取消了一个订阅然后在订阅失效之前恢复了这个订阅,则不会立即支付该账单,取而代之的,他们的订阅只是被重新激活,并回到正常的支付周期。
3、处理 StripeWebhook
3.1 订阅失败处理
如果客户的信用卡失效怎么办?不用担心—— Cashier 自带了 Webhook 控制器,该控制器可以很方便地为你取消客户订阅。只需要定义如下控制器路由:
Route::post('stripe/webhook', 'Laravel\Cashier\WebhookController@handleWebhook');
就是这样!失败的支付将会被该控制器捕获和处理。当 Stripe 判断订阅失败(正常情况下尝试支付失败三次后)时该控制器将会取消客户的订阅。不要忘了:你需要在 Stripe 控制面板设置中配置相应的 webhook URI,否则不能正常工作。
由于 Stripe webhooks 需要通过 Laravel 的CSRF验证,所以我们将该 URI 置于 VerifyCsrfToken中间件排除列表中:
protected $except = [ 'stripe/*',];
3.2 其它Webhooks
如果你有额外想要处理的 Stripe webhook 事件,只需简单继承 Webhook 控制器, 你的方法名应该和 Cashier 期望的约定一致,尤其是方法应该以“handle”开头并以驼峰命名法命名。例如,如果你想要处理 invoice.payment_succeededwebhook,你应该添加 handleInvoicePaymentSucceeded方法到控制器:
<?phpnamespace App\Http\Controller;use Laravel\Cashier\WebhookController as BaseController;class WebhookController extends BaseController{ /** * 处理 stripe webhook. * * @param array $payload * @return Response */ public function handleInvoicePaymentSucceeded($payload) { // 处理该事件 }}
4、一次性付款
如果你想要使用订阅客户的信用卡一次性结清账单,可以使用账单模型实例上的 charge方法,该方法接收付款金额(应用使用的货币的最小单位对应的金额数值)作为参数,例如,下面的例子使用信用卡支付100美分,或1美元:
$user->charge(100);
charge方法接收一个数组作为第二个参数,允许你传递任何你想要传递的底层 Stripe 账单创建参数:
$user->charge(100, [ 'source' => $token, 'receipt_email' => $user->email,]);
如果支付失败 charge方法将返回 false,这通常表明付款被拒绝:
if ( ! $user->charge(100)) { // The charge was denied...}
如果支付成功,该方法将会返回一个完整的 Stripe 响应。
5、发票
你可以使用 invoices方法轻松获取账单模型的发票数组:
$invoices = $user->invoices();
当列出客户发票时,你可以使用发票的辅助函数来显示相关的发票信息。例如,你可能想要在表格中列出每张发票,从而方便用户下载它们:
<table> @foreach ($invoices as $invoice) <tr> <td>{{ $invoice->dateString() }}</td> <td>{{ $invoice->dollars() }}</td> <td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td> </tr> @endforeach</table>
生成PDF发票
在生成PDF分票之前,需要安装 PHP 库 dompdf:
composer require dompdf/dompdf
在路由或控制器中,使用 downloadInvoice方法生成发票的 PDF 下载,该方法将会自动生成相应的 HTTP 响应发送下载到浏览器:
Route::get('user/invoice/{invoice}', function ($invoiceId) { return Auth::user()->downloadInvoice($invoiceId, [ 'vendor' => 'Your Company', 'product' => 'Your Product', ]);});

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在PHP中,應使用password_hash和password_verify函數實現安全的密碼哈希處理,不應使用MD5或SHA1。1)password_hash生成包含鹽值的哈希,增強安全性。 2)password_verify驗證密碼,通過比較哈希值確保安全。 3)MD5和SHA1易受攻擊且缺乏鹽值,不適合現代密碼安全。

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP類型提示提升代碼質量和可讀性。 1)標量類型提示:自PHP7.0起,允許在函數參數中指定基本數據類型,如int、float等。 2)返回類型提示:確保函數返回值類型的一致性。 3)聯合類型提示:自PHP8.0起,允許在函數參數或返回值中指定多個類型。 4)可空類型提示:允許包含null值,處理可能返回空值的函數。

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。
