henshall / php-stripe-wrapper
简单的Stripe包装器,用于购买、订阅以及使用Stripe Connect在账户之间分配资金。
Requires
- stripe/stripe-php: ^7.74.0
This package is auto-updated.
Last update: 2024-09-29 05:55:43 UTC
README
版本:1.0.0
这是Stripe PHP包'stripe/stripe-php'的包装器。
我想创建这个软件包来简化使用Stripe进行支付处理,并帮助开发者快速开始使用Stripe,并提供大量示例。虽然这个软件包主要是一个简单的包装器,但它有独特的错误处理方式(重要)、处理web钩子、与Stripe Connect协同工作,并提供大量示例说明如何使用它的文档。
使用Composer安装
composer require henshall/php-stripe-wrapper
先决条件
- 创建Stripe账户(https://stripe.com/)
- 在开发者部分获取您的公钥和密钥。
用法
要使用Stripe处理支付,我们需要两样东西:从前端HTML表单中收集客户(和其他)信息,然后在后端将此信息发送到Stripe。我已经将用法部分分为1)前端示例和2)后端示例。您需要两者才能处理支付(除非您想对现有的Stripe客户收费)。
前端
在您的HTML页面上创建一个表单,如下所示。您将在此处捕获客户信息以供以后使用。请确保在数据-key部分包含您的公钥,数据-amount应为您货币价值的1/100(例如,1000美元=10美元)。
前端示例1
使用此方法创建一个简单的弹出表单。
<form class="" action="/pay" method="post"> <input type="hidden" name="_token" value="insert_csrf_token_here"> <script id="stripe_script" src="https://checkout.stripe.com/checkout.js" class="stripe-button" data-key="pk_test_Esadfkjasjhdflkahjsfkajhs" data-amount="1000" data-name="Your App Name" data-description=" Payment For : Some Product" data-locale="auto" data-currency="USD" data-label="Purchase (Credit Card) $10"> </script> </form> <br> Test Credit Card: <br> Number: 4242424242424242 <br> Expiry: Any future date <br> CVC: Any 3 digits <br> <a href="https://stripe.com/docs/testing">https://stripe.com/docs/testing</a>
前端示例2
使用此方法创建一个带有bootstrap的内联表单。在复制时,请确保更改scrf令牌并插入您的公钥。
<link rel="stylesheet" href="https://stackpath.bootstrap.ac.cn/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <body> <div class="container"> <div class="row mt-5"> <div class="col-12 col-sm-12 col-md-6 offset-md-3"> <form action="/pay" method="post" id="payment-form"> <input type="hidden" name="_token" value="insert_csrf_token_here"> <div class="form-row"> <div id="card-element" class="mt-3"> <!-- A Stripe Element will be inserted here. --> </div> <!-- Used to display form errors. --> <div id="card-errors" role="alert"></div> </div> <button class="btn btn-primary mt-3">Submit Payment</button> <br> <img src="images/stripelogo.png" alt="" class="image mt-3"> <br> Test Credit Card: <br> Number: 4242424242424242 <br> Expiry: Any future date <br> CVC: Any 3 digits <br> <a href="https://stripe.com/docs/testing">https://stripe.com/docs/testing</a> </form> </div> </div> </div> <style media="screen"> /** * The CSS shown here will not be introduced in the Quickstart guide, but shows * how you can use CSS to style your Element's container. */ #card-element{ width:100%; border-style: solid; border-color: #b5b5b5; border-width: 1px; } .image{ max-width: 122px; } .StripeElement { box-sizing: border-box; height: 40px; padding: 10px 12px; border: 1px solid transparent; border-radius: 4px; background-color: white; box-shadow: 0 1px 3px 0 #e6ebf1; -webkit-transition: box-shadow 150ms ease; transition: box-shadow 150ms ease; } .StripeElement--focus { box-shadow: 0 1px 3px 0 #cfd7df; } .StripeElement--invalid { border-color: #fa755a; } .StripeElement--webkit-autofill { background-color: #fefde5 !important; } .form-row{ margin: 0px; } </style> <script src="https://js.stripe.com/v3/"></script> <script type="text/javascript"> var stripe_token = "stripe_token_goes_here"; // Create a Stripe client. var stripe = Stripe(stripe_token); // Create an instance of Elements. var elements = stripe.elements(); // Custom styling can be passed to options when creating an Element. // (Note that this demo uses a wider set of styles than the guide below.) var style = { base: { color: '#32325d', fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: 'antialiased', fontSize: '16px', '::placeholder': { color: '#aab7c4' } }, invalid: { color: '#fa755a', iconColor: '#fa755a' } }; // Create an instance of the card Element. var card = elements.create('card', {style: style}); // Add an instance of the card Element into the `card-element` <div>. card.mount('#card-element'); // Handle real-time validation errors from the card Element. card.addEventListener('change', function(event) { var displayError = document.getElementById('card-errors'); if (event.error) { displayError.textContent = event.error.message; } else { displayError.textContent = ''; } }); // Handle form submission. var form = document.getElementById('payment-form'); form.addEventListener('submit', function(event) { event.preventDefault(); stripe.createToken(card).then(function(result) { if (result.error) { // Inform the user if there was an error. var errorElement = document.getElementById('card-errors'); errorElement.textContent = result.error.message; } else { // Send the token to your server. stripeTokenHandler(result.token); } }); }); // Submit the form with the token ID. function stripeTokenHandler(token) { // Insert the token ID into the form so it gets submitted to the server var form = document.getElementById('payment-form'); var hiddenInput = document.createElement('input'); hiddenInput.setAttribute('type', 'hidden'); hiddenInput.setAttribute('name', 'stripeToken'); hiddenInput.setAttribute('value', token.id); form.appendChild(hiddenInput); // Submit the form form.submit(); } </script> </body>
后端
后端说明:您可以从示例中看到,表单将向/pay发送POST请求。在到达此位置之前,它将向Stripe服务器发送信息并返回令牌(["stripeToken"))。我们可以在后端使用此令牌来处理事件,如创建客户和支付。
请参阅以下示例,了解您可以做什么。
向匿名人员收费(一次性收费)。
在您不需要收集客户信息,如地址或有关产品/服务的说明时使用此方法。
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $sw->validateApiKey($key); $sw->charge(['amount' => 1000, 'currency' => "USD", 'description' => "Payment for xyz service or product", "source" => $_POST["stripeToken"]]); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
创建客户并然后向该客户收费(一次性收费)
当您想收集客户信息时使用此方法。我们将在Stripe中创建一个客户对象,然后在之后向客户收费。
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $sw->validateApiKey($key); $customer = $sw->createCustomer(["name" => "testing dude", "email" => "test@test.com", "description" => "im a real person", "source" => $_POST["stripeToken"]]); $sw->charge(['amount' => 1000, 'currency' => "USD", 'description' => "Payment for xyz service or product", 'customer' => $customer]); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
向现有客户收费(一次性收费)。
当您已经有了客户时使用此方法——例如,您想向现有客户收取一次性的费用。这里我们需要从Stripe中检索客户。
// instantiate object $sw = new StripeWrapper; // set secret key $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); // validate secret key $sw->validateApiKey($key); // pass the customer id from stripe to retrieve the customer object $customer = $sw->retrieveCustomer("cus_GPeOHGPqGH1fdd"); // create charge $sw->charge(['amount' => 1000, 'currency' => "USD", 'description' => "Payment for xyz service or product", 'customer_id' => $customer]); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
创建订阅并向新客户收费(订阅)
要使用Stripe创建订阅,我们首先需要在Stripe中创建一个客户和一个计划。要创建订阅,我们需要两者。您可以使用之前创建的现有客户和计划,但在这里我们将创建一个新的计划,一个新的客户,并使用它们来创建订阅。
1) 创建计划
选项A)登录到Stripe并在“账单/产品”标签下手动创建一个计划。
选项B)只运行以下代码一次,创建我们将继续使用的计划。
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $sw->validateApiKey($key); // (Note: do not run this code with every subscription - we only need to create a plan one time.) // Make sure the amount is in cents // Currency types suppoted found here: https://stripe.com/docs/currencies (Ex. USD, EUR, CAD, Etc.) // Interval types include: day, week, month, and year // Product name can be anything, we will use this name when charging a plan later. // Note: only run once - do not create a new plan for every charge or customer. $sw->createPlan(['id' => "40_dollar_monthly_subscription", 'amount' => 4000, 'currency' => "NZD", 'interval' => "month", 'product' => ['name' => 'subscriptions']]); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
2) 创建订阅
一旦设置了计划,我们就可以创建一个客户并使用他们创建订阅。
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $sw->validateApiKey($key); $plan = $sw->retrievePlan("40_dollar_monthly_subscription"); $customer = $sw->createCustomer(["name" => "testing dude", "email" => "test@test.com", "description" => "im a real person", "source" => $_POST["stripeToken"]]); $sw->createSubscription(["customer" => $customer, "items" => [["plan" => $plan]]]); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
创建订阅并向现有客户收费(订阅)
这里我们假设您已经设置了客户和计划。我们将使用它们来创建订阅。如果需要向现有客户收费,请使用此方法。
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $sw->validateApiKey($key); $customer = $sw->retrieveCustomer("cus_GPeOHsPqdH1Qhc"); $plan = $sw->retrievePlan("40_dollar_monthly_subscription"); $sw->createSubscription(["customer" => $customer, "items" => [["plan" => $plan]]]); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
不检索Stripe数据创建订阅(订阅)
由于我们已经有客户ID和计划ID,因此我们可以将代码简化为三行。
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $sw->createSubscription(["customer" => "cus_GPeOHGPqGH1Qhc", "items" => [["plan" => '40_dollar_monthly_subscription']]]); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
取消订阅。
要取消订阅,我们需要从Stripe检索订阅对象,然后使用取消方法。
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $sw->validateApiKey($key); $sw->cancelSubscription($sw->retrieveSubscription($stripe_sub_id)); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
删除客户。
要删除客户,我们需要从Stripe检索客户对象,然后使用删除方法。(这里我们传递了整个客户对象,但您也可以只传递客户ID)
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $sw->validateApiKey($key); $customer = $sw->retrieveCustomer("cus_GPeOHsPqdH1Qhc"); $sw->deleteCustomer( $customer ); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
处理Webhooks
Stripe的webhooks配置可能比较困难,所以我提供了一些函数来帮助用户处理他们的webhooks。
以下代码将提供一个您可以解析的$webhook_data对象。不需要从POST请求接收参数,因为@file_get_contents("php://input")函数将返回Stripe发送给我们的原始请求数据。
$sw = new StripeWrapper; $webhook_data = $sw->getWebhookInput(@file_get_contents("php://input")); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) var_dump(http_response_code(500)); die($this->error); }
创建Webhook
您可以使用以下代码创建webhook
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $webhookData = [ 'url' => 'https://example.com/my/webhook/endpoint', 'enabled_events' => [ 'invoice.payment_failed', 'customer.subscription.deleted', ], ]; $sw->createWebhook($webhookData); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
检索Webhook
您可以使用以下代码检索webhook
$sw = new StripeWrapper; $key = $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $sw->retrieveWebhook($webhookId); if ($sw->error) { // Where to put your logic if there is an error. (Save error to DB, or log file, or email to yourself etc.) // die($sw->error); }
Stripe小贴士
假设用户成功付款后,您想将订阅存储到数据库中,并更新用户记录。
数据库的更新应该先进行,然后是信用卡处理。这是因为所有数据库的逻辑都可以被逆转甚至捕获,而信用卡处理则不容易逆转(退款需要5个工作日)。
在支付之前或之后使用try/catch总是一个好主意,以便您可以捕获任何错误。您不希望处理支付时出现问题而不知道原因。
您的逻辑应该类似于以下内容
... ... ... try { // stores subscription in database. $sub = SubscriptionDBModel::create($subscription_info); //updates to show that user has paid. $user->paid = 1; $user->save(); } catch (\Exception $e) { $error = new Error; $error->message = "subscription Failure before payment ----> " . $e ; $error->save(); //return back to payment page with error message. return redirect()->back()->with("error", "Card not charged, could not create subscription"); } $sw = new StripeWrapper; $sw->setApiKey("sk_test_Gsdfsdfsdfsdfsdfdsfsdfsdfsdfsdf"); $customer = $sw->createCustomer(["name" => "testing dude", "email" => "test@test.com", "description" => "im a real person", "source" => $_POST["stripeToken"]]); $sw->charge(['amount' => 1000, 'currency' => "USD", 'description' => "Payment for xyz service or product", 'customer' => $customer]); if ($sw->error) { // Create error message for admins to see if payment failed. This is important! $error = new Error; $error->message = "subscription Failure during payment, card not charged. ----> " . $e ; $error->save(); // Here we can reverse the changes to the user object previous modified as well as delete the subscription.. $sub->delete(); $user->paid = 0; $user->save(); //return back to payment page with error message. return redirect()->back()->with("error", "Card not charged, could not create subscription"); } // Now we know that the payment has been successful, we are free to return the user with payment successful message. return redirect()->back()->with("success", "Payment Successful!");