A Guide for Stripe Integration in Website with PHP

If you are collecting an online payment on your website, you must have heard about the Stripe Payment Gateway. Using Stripe, one can accept the payment using a credit or debit card. This is a more convenient way to pay online for your customers. In this article, we study Stripe integration in the website with PHP.

Why Should Use Stripe Payment Gateway?

Stripe is one of the most popular and secure payment gateway on the Internet. The user’s card details are always safe with Stripe payments. In fact, on Stripe checkout they provide generated elements where a user has to enter card details. These elements are generated by Stripe at runtime which makes this gateway more secure.

After entering the card details, Stripe generates a token that will be used to charge the card payment. As a result, there is no need to store card details at all.

For this tutorial, I am going to use Stripe Payment Intents API that allows us to handle complex checkout flow. As per regulatory changes, some customers have to validate two-factor authentication to complete the online purchases. The Payment Intents API  triggers additional authentication like 3D secure that protects customers from fraudulent card payments.

Get API Keys for Stripe Integration

For getting started, you should have a Stripe account. To integrate Stripe gateway in your application, you need to get your Stripe secret key and publishable key.

Login to your Stripe dashboard. You will get those keys from Developers->API Keys. I recommend you should first test transactions with the test mode. If everything works well, then go for live mode. Grab your API keys for testing mode.

stripe-api-credentials

Basic Configuration

Whenever we integrate a payment gateway on the website, we need to store the transaction details in the database. To store our transactions, create a <code>payments</code> table using the below SQL query.

CREATE TABLE `payments` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `payment_id` varchar(255) NOT NULL,
 `amount` float(10,2) NOT NULL,
 `currency` varchar(255) NOT NULL,
 `payment_status` varchar(255) NOT NULL,
 `captured_at` datetime NOT NULL DEFAULT current_timestamp(),
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

To interact with this database table, let’s create a class that makes database connections and insert the records in the payments table.

class-db.php

<?php
class DB {
    private $dbHost     = "DB_HOST";
    private $dbUsername = "DB_USERNAME";
    private $dbPassword = "DB_PASSWORD";
    private $dbName     = "DB_NAME";

    public function __construct(){
        if(!isset($this->db)){
            // Connect to the database
            $conn = new mysqli($this->dbHost, $this->dbUsername, $this->dbPassword, $this->dbName);
            if($conn->connect_error){
                die("Failed to connect with MySQL: " . $conn->connect_error);
            }else{
                $this->db = $conn;
            }
        }
    }

    public function insert_payment_details($arr_data = array()) {
        $isPaymentExist = $this->db->query("SELECT * FROM payments WHERE payment_id = '".$arr_data['payment_id']."'");

        if($isPaymentExist->num_rows == 0) {
            $i = 0;
            $values = '';
            foreach($arr_data as $key=>$val){
                $pre = ($i > 0)?', ':'';
                $values .= $pre."'".$this->db->real_escape_string($val)."'";
                $i++;
            }

            $insert = $this->db->query("INSERT INTO payments(".implode(",", array_keys($arr_data)).") VALUES(".$values.")");
        }
    }
}

For executing a payment using Stripe, I am going to use the Omnipay library. This is a popular payment processing library that gives support for Stripe gateway. Install the library using the command below.

composer require league/omnipay omnipay/stripe

After this, create a config.php file. It stores the Stripe API credentials, initialize Stripe Payment Intents through Omnipay.

config.php

<?php
session_start();

require_once "vendor/autoload.php";
require_once "class-db.php";

use Omnipay\Omnipay;

define('STRIPE_PUBLISHABLE_KEY', 'PASTE_STRIPE_PUBLISHABLE_KEY');
define('STRIPE_SECRET_KEY', 'PASTE_STRIPE_SECRET_KEY');
define('RETURN_URL', 'DOMAIN_URL/confirm.php');
define('PAYMENT_CURRENCY', 'USD');

$gateway = Omnipay::create('Stripe\PaymentIntents');
$gateway->setApiKey(STRIPE_SECRET_KEY);

Make sure to replace placeholders with their actual values.

Stripe Checkout Form

As I mentioned, Stripe generates card elements for you. We will generate these elements into the checkout form by following the Stripe documentation.

Create index.php file and place the below code in it.

<?php
require_once 'config.php';
?>
<link rel="stylesheet" href="style.css" />
<script src="https://js.stripe.com/v3/"></script>

<?php if ( isset($_SESSION['payment_id']) ) { ?>
    <div class="success">
        <strong><?php echo 'Payment is successful. Payment ID is :'. $_SESSION['payment_id']; ?></strong>
    </div>
    <?php unset($_SESSION['payment_id']); ?>
<?php } elseif ( isset($_SESSION['payment_error']) ) { ?>
    <div class="error">
        <strong><?php echo $_SESSION['payment_error']; ?></strong>
    </div>
    <?php unset($_SESSION['payment_error']); ?>
<?php } ?>

<form action="charge.php" method="post" id="payment-form">
    <div class="form-row">
        <input type="text" name="amount" placeholder="Enter Amount" />
        <p><label for="card-element">Credit or debit card</label></p>
        <div id="card-element">
        <!-- A Stripe Element will be inserted here. -->
        </div>
 
        <!-- Used to display form errors. -->
        <div id="card-errors" role="alert"></div>
    </div>
    <p><button>Submit Payment</button></p>
</form>

<script>
var publishable_key = '<?php echo STRIPE_PUBLISHABLE_KEY; ?>';
</script>
<script src="card.js"></script>

Add some styling to the HTML form by entering a few properties into the style.css file.

.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;
}

After this, to generate card elements and stripeToken add the following JavaScript code in the card.js file. This JavaScript code also validates the card details.

// Create a Stripe client.
var stripe = Stripe(publishable_key);
 
// 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();
}

I have added random styling to the form. You can adjust the form design to fit with your website. Stripe also provides different designs of card elements. Read more about it in the documentation.

When the user submits a form with card details, Stripe generates a token in the background which will be set as a hidden field ‘token’. This token will be used to charge card payments on the server side.

We are posting the form data to the charge.php. In this PHP file, we will charge the card and execute the payment.

Stripe Payment Intents API Integration with PHP

While charging a card for payment, some cards required additional authentication and some did not. When cards require 2-step authentication, it goes on the Bank’s hosted pages for authentication and comes back to confirm.php to confirm the payment.

The charge.php charges the cards directly which does not require authentication. It also redirects customers to the respective pages for additional authentication.

charge.php

<?php
require_once "config.php";

if (isset($_POST['stripeToken']) && !empty($_POST['stripeToken'])) {
 
    $response = $gateway->authorize([
        'amount' => $_POST['amount'],
        'currency' => PAYMENT_CURRENCY,
        'description' => 'This is a X purchase transaction.',
        'token' => $_POST['stripeToken'],
        'returnUrl' => RETURN_URL,
        'confirm' => true,
    ])->send();

    if($response->isSuccessful()) {
        $response = $gateway->capture([
            'amount' => $_POST['amount'],
            'currency' => PAYMENT_CURRENCY,
            'paymentIntentReference' => $response->getPaymentIntentReference(),
        ])->send();

        $arr_payment_data = $response->getData();

        // Insert transaction data into the database
        $db = new DB();
        $db->insert_payment_details(
            array(
                "payment_id" => $arr_payment_data['id'],
                "amount" => $_POST['amount'],
                'currency' => PAYMENT_CURRENCY,
                'payment_status' => $arr_payment_data['status'],
            )
        );

        $_SESSION['payment_id'] = $arr_payment_data['id'];
        header('Location: index.php');
    } elseif($response->isRedirect()) {
        $_SESSION['amount'] = $_POST['amount'];
        $response->redirect();
    } else {
        $_SESSION['payment_error'] = $response->getMessage();
        header('Location: index.php');
    }
}

When a customer authenticates their card for a transaction, control goes to the confirm.php which then is responsible to capture the payment.

confirm.php

<?php
require_once "config.php";

$response = $gateway->confirm([
    'paymentIntentReference' => $_GET['payment_intent'],
    'returnUrl' => RETURN_URL,
])->send();

if($response->isSuccessful()) {
    $response = $gateway->capture([
        'amount' => $_SESSION['amount'],
        'currency' => PAYMENT_CURRENCY,
        'paymentIntentReference' => $_GET['payment_intent'],
    ])->send();

    $arr_payment_data = $response->getData();

    // Insert transaction data into the database
    $db = new DB();
    $db->insert_payment_details(
        array(
            "payment_id" => $arr_payment_data['id'],
            "amount" => $_SESSION['amount'],
            'currency' => PAYMENT_CURRENCY,
            'payment_status' => $arr_payment_data['status'],
        )
    );

    $_SESSION['payment_id'] = $arr_payment_data['id'];
    header('Location: index.php');
} else {
    $_SESSION['payment_error'] = $response->getMessage();
    header('Location: index.php');
}

We are done with the coding part. Go ahead and test the sandbox payments. Stripe provides dummy card details to test the payment.

Whenever you decide to go live, you just need to change your secret and publishable key with the live credentials.

I hope you may learn about the Stripe integration on a website with PHP. I would like to hear your thoughts and suggestions in the comment section below.

Related Articles

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

5 thoughts on “A Guide for Stripe Integration in Website with PHP

  1. Just pointing out the spelling mistake

    Stripe Integration
    For getting started, you should have Stripe account. To accept payment online you need to get your Stripe secret “kay” and publishable key.

  2. Thank you for this tutorial. The payment.php file fails at the line:

    \Stripe\Stripe::setApiKey($stripe[‘secret_key’]);

    I’ve tried both my test and live keys. I think it’s a problem accessing the Stripe PHP library. How can I verify this?

    Much thanks, Jeff

Leave a Reply

Your email address will not be published. Required fields are marked *