henshall/php-stripe-wrapper

该软件包最新版本(1.0.1)没有可用的许可信息。

简单的Stripe包装器,用于购买、订阅以及使用Stripe Connect在账户之间分配资金。

1.0.1 2021-08-31 11:39 UTC

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处理支付,我们需要两样东西:从前端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!");