Buy

Charge It (The Stripe PHP SDK)

Stripe has a nice, RESTful API, and you're going to spend a lot of time talking with it. Google for "Stripe API docs" to find this amazing page. You can set this as your new homepage: it describes every endpoint: how to create charges, customers and a lot of other things we're going to talk about.

But first, make sure that you select PHP on the top right. Thanks to this, the docs will show you code snippets in PHP. And those code snippets will use Stripe's PHP SDK library. Google for that and open its Github Page.

First, let's get this guy installed. Copy the composer require line, move over to your terminal, open a new tab and paste that:

composer require stripe/stripe-php

While we're waiting for Jordi to finish, let's keep going.

Using the Token to Create a Charge

To actually charge a user, we need to... well, create a Stripe charge. In the Stripe API, click "Charges" on the left and find Create a Charge.

Hey! It wrote the code for us. Copy the code block on the right. Now, go back to OrderController and first, create a new $token variable and set it to the stripeToken POST parameter. Now, paste that code:

58 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 30
public function checkoutAction(Request $request)
{
... lines 33 - 34
if ($request->isMethod('POST')) {
$token = $request->request->get('stripeToken');
\Stripe\Stripe::setApiKey("XXX_PRIVATEKEY_XXX");
\Stripe\Charge::create(array(
"amount" => $this->get('shopping_cart')->getTotal() * 100,
"currency" => "usd",
"source" => $token,
"description" => "First test charge!"
));
... lines 45 - 49
}
... lines 51 - 56
}
}

Let's go check on Composer. It's just finishing - perfect! My editor now sees all these new Stripe classes.

See that API key?

58 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 10
class OrderController extends BaseController
{
... lines 13 - 30
public function checkoutAction(Request $request)
{
... lines 33 - 34
if ($request->isMethod('POST')) {
... lines 36 - 37
\Stripe\Stripe::setApiKey("XXX_PRIVATEKEY_XXX");
... lines 39 - 49
}
... lines 51 - 56
}
}

Once again, this is a real key from our account in the test environment. This time, it's the secret key. The public key is the one in our template:

53 lines app/Resources/views/order/checkout.html.twig
... lines 1 - 3
{% block body %}
<div class="nav-space-checkout">
<div class="container">
<div class="row">
... lines 8 - 34
<div class="col-xs-12 col-sm-6">
<form action="" method="POST">
<script
... line 38
data-key="pk_test_HxZzNHy8LImKK9LDtgMDRBwd"
... lines 40 - 45
</script>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

Update charge details with our real information. To get the total, I'll fetch a service I created for the project called shopping_cart, call getTotal() on this, and then multiply it by 100:

58 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 10
class OrderController extends BaseController
{
... lines 13 - 30
public function checkoutAction(Request $request)
{
... lines 33 - 34
if ($request->isMethod('POST')) {
... lines 36 - 38
\Stripe\Charge::create(array(
"amount" => $this->get('shopping_cart')->getTotal() * 100,
... lines 41 - 43
));
... lines 45 - 49
}
... lines 51 - 56
}
}

For source, replace this fake token with the submitted $token variable:

58 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 10
class OrderController extends BaseController
{
... lines 13 - 30
public function checkoutAction(Request $request)
{
... lines 33 - 34
if ($request->isMethod('POST')) {
$token = $request->request->get('stripeToken');
... lines 37 - 38
\Stripe\Charge::create(array(
... lines 40 - 41
"source" => $token,
... line 43
));
... lines 45 - 49
}
... lines 51 - 56
}
}

The token basically represents the credit card that was just sent. We're saying: Use this card as the source for this charge. And then, put whatever you want for description, like "First test charge":

58 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 10
class OrderController extends BaseController
{
... lines 13 - 30
public function checkoutAction(Request $request)
{
... lines 33 - 34
if ($request->isMethod('POST')) {
... lines 36 - 38
\Stripe\Charge::create(array(
... lines 40 - 42
"description" => "First test charge!"
));
... lines 45 - 49
}
... lines 51 - 56
}
}

When this code runs, it will make an API request to Stripe. If that's successful, the user will be charged. If something goes wrong, Stripe will throw an Exception. More on that later.

Cleaning up after Checkout

But before we try it, we need to finish up a few application-specific things. For example, after check out, we need to empty the shopping cart. The products are great, but the customer probably doesn't want to buy them twice in a row:

58 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 10
class OrderController extends BaseController
{
... lines 13 - 30
public function checkoutAction(Request $request)
{
... lines 33 - 34
if ($request->isMethod('POST')) {
... lines 36 - 38
\Stripe\Charge::create(array(
... lines 40 - 43
));
$this->get('shopping_cart')->emptyCart();
... lines 47 - 49
}
... lines 51 - 56
}
}

Next, I want to show a success message to the user. To do that in Symfony, call $this->addFlash('success', 'Order Complete! Yay!'):

58 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 10
class OrderController extends BaseController
{
... lines 13 - 30
public function checkoutAction(Request $request)
{
... lines 33 - 34
if ($request->isMethod('POST')) {
... lines 36 - 45
$this->get('shopping_cart')->emptyCart();
$this->addFlash('success', 'Order Complete! Yay!');
return $this->redirectToRoute('homepage');
}
... lines 51 - 56
}
}

And finally, you should definitely redirect the page somewhere. I'll use redirectToRoute() to send the user to the homepage.

That is it. Now for the real moment of truth. Hit enter to reload our page without submitting, put in the fake credit card, any date, any CVC, and...

Tip

If you get some sort of API or connection, you may need to upgrade some TLS security settings.

Hey! Okay. No errors. That should mean it worked. How can we know? Go check out the Stripe Dashboard. This time, click "Payments". And there's our payment for $62. You can even see all the information that was used.

Congratulations guys! You just added a checkout to your site in 15 minutes. Now let's make this thing rock-solid.

Leave a comment!

  • 2017-02-15 Victor Bocharsky

    Easy indeed! ;)

    Cheers!

  • 2017-02-15 Blueblazer172

    again I solved it myself :P
    I had to remove the action="/your-server-side-code" parameter in

    <form method="POST">

    in the checkout.html.twig file

    that easy xD

  • 2017-02-15 Victor Bocharsky

    Hey Blueblazer172 ,

    Do you have a similar issue? If you describe the problem a bit more - we'll try to help you.

    Cheers!

  • 2017-02-15 Blueblazer172

    what was the mistake you did ?

  • 2016-12-14 Victor Bocharsky

    Great! Quick catch ;)

    Cheers!

  • 2016-12-14 Kosta Andonovski

    all good i fixed it was a stupid mistake thanks anyway

  • 2016-12-14 Kosta Andonovski

    when i process the payment it tries to redirect me to /your-server-side-code

    This is very strange because my controller specifies to redirect me to my home page "return $this->redirectToRoute('user_home_show'); "
    Is that stripe trying to auto-redirect me somewhere?

  • 2016-08-22 Victor Bocharsky

    Hey Dany,

    As you can see from logs, your form is submitting to the wrong page. Instead of submitting to the "/charge" page you should submit form to the "/checkout", because in this screencast the form handling in CheckoutAction().

    Cheers!

  • 2016-08-11 weaverryan

    Ah, thanks for the note Jovan - very helpful! I hadn't seen this - but I'm sure others will have this exact same error :).

    Cheers!

  • 2016-08-09 Jovan Perović

    Awesome screencast so far! :) Thanks a lot! :)

    Just an extra step: Make sure you upgrade nss, curl and openssl, or else Stripe will reject our request with message saying that we're trying to setup non-TLS1.2 communication. According to their blog (source: https://stripe.com/blog/upg... ), the new users starting from July 1st will have to use TLS 1.2. Prior to upgrade (and error) I had:

    curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
    Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp
    Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz

    Cheers! :)