If you are collecting an online payment on your website, you must have heard about the Stripe Payment Gateway. Using Stripe, one can accept 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 gateways 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 which allows us to handle complex checkout flow. As per regulatory changes, some customers have to validate two-factor authentication to complete 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 the Stripe gateway into 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.
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 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.
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 the 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 and initializes 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 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
- PayPal Payment Gateway Integration in PHP using PayPal REST API
- Accept Credit Card Payment Using Authorize.net Payment Gateway in PHP
- Stripe Payment Gateway Integration in Laravel
If you liked this article, then please subscribe to our YouTube Channel for video tutorials.
every thing working fine when i am taking payment in inr but when i am trying to take payment in usd it’s giving error
As per Indian regulations, export transactions require a customer name and address. More info here: https://stripe.com/docs/india-exports
Can you please help me what should i add in codes and where ?
Hi ArtisanWeb, your code was exactly what I was looking for but, when on a staging site, it is generating some error logs, attaching the screenshot , if you could help with this It would be great,
https://i.imgur.com/fVF2UfF.png
Thanks in advance
It needs to debug the issue. From your screenshot, it’s hard to conclude what’s going wrong.
Can you please update it in order to be compliant to the new SCA rules?
Thanks!
I updated the article. It now supports Strong Customer Authentication(SCA).
this is the old process and not functional outside of the us…
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.
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