Adam. R

How to integrate Stripe to your website with PHP!

Created March 8, 2022

Introduction

Stripe is one of the biggiest services that many companies use to recieve online payments, its fast and secure! So, I will explain how to integate Stripe onto your online shop! I will use PHP for this tutorial. Let's go!


Get API keys

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-dev.png.

Basic Config

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 payments 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.

<?php
// class-db.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

Omnipay link: Omnipay GitHub 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.


Conclusion

Woah, that was A LOT! That's why i didn't post in a while. Well, I hope this post goes well to make that post worth it. If you found this usful then please share this and follow me! Also check out my Buy Me A Coffee!

Buy Me A Coffee how2ubuntu