Stripe Payment Gateway Integration in PHP

The Stripe payment gateway provides an easy and powerful way to accept credit cards directly on the web application. Stripe make it easy to integrate the checkout system and collect payment on the website. The Stripe API is a powerful solution to integrate the checkout system into the web application to provide a smooth payment experience.

If you want to accept credit card payments on your website, Stripe will be the best option for that. You can easily integrate the checkout system into your PHP-based website, which allows the user to make payments through credit or debit cards without leaving your website. This tutorial will show you how to integrate the Stripe payment gateway in PHP for collecting payments online using credit or debit cards.

In the example script, we will implement the following functionality to demonstrate the Stripe payment gateway integration process.

  • Create an HTML form to collect credit card information.
  • Create a PaymentIntent using the Stripe PHP library.
  • Attach card input elements to HTML form using Stripe JS library.
  • Securely transmit card information, validate, charge and confirm the payment using Stripe API.
  • Retrieve PaymentIntent and customer information using Stripe API.
  • Insert transaction details in the database and display the payment status.
  • Integrate 3D Secure payment to support Strong Customer Authentication (SCA).

Stripe Test API Keys Data

Before making your Stripe payment gateway integration live, you need to test it thoroughly. To test the credit card payment process with Stripe, the test API Keys are required. You can generate and get the TEST DATA in your Stripe account.

  • Login to your Stripe account and navigate to the Developers » API keys page.
  • In the TEST DATA, you’ll see the API keys (Publishable key and Secret key) are listed under the Standard keys section. To show the Secret key, click on Reveal test key button.
    stripe-developer-test-data-publishable-secret-api-keys-codexworld

Collect the Publishable key and Secret key to later use in the script.

Before getting started to implement Stripe payment gateway in PHP, take a look at the file structure.

stripe_integration_php/
├── config.php
├── dbConnect.php
├── index.php
├── payment_init.php
├── payment-status.php
├── stripe-php/
├── js/
|    └── checkout.js
└── css/
    └── style.css

Create Database Table

To store the transaction details, a table is required to be created in the database. The following SQL creates a transactions table in the MySQL database.

CREATE TABLE `transactions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `customer_name` varchar(50) DEFAULT NULL,
  `customer_email` varchar(50) DEFAULT NULL,
  `item_name` varchar(255) DEFAULT NULL,
  `item_price` float(10,2) DEFAULT NULL,
  `item_price_currency` varchar(10) DEFAULT NULL,
  `paid_amount` float(10,2) NOT NULL,
  `paid_amount_currency` varchar(10) NOT NULL,
  `txn_id` varchar(50) NOT NULL,
  `payment_status` varchar(25) NOT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Stripe API and Database Configuration (config.php)

In the config.php file, constant variables of the Stripe API and database settings are defined.

Product Information:

  • $itemName – Name of the product.
  • $itemPrice – Product price.
  • $currency – Currency code.

Stripe API Constants:

  • STRIPE_PUBLISHABLE_KEY – Specify the API Publishablekey.
  • STRIPE_SECRET_KEY – Specify the API Secret key.

Database Constants:

  • DB_HOST – Specify the database host.
  • DB_USERNAME – Specify the database username.
  • DB_PASSWORD – Specify the database password.
  • DB_NAME – Specify the database name.
<?php 

// Product Details
// Minimum amount is $0.50 US
$itemName "Demo Product";
$itemPrice 25
$currency "USD"

/* Stripe API configuration
 * Remember to switch to your live publishable and secret key in production!
 * See your keys here: https://dashboard.stripe.com/account/apikeys
 */
define('STRIPE_PUBLISHABLE_KEY''Insert_Stripe_API_Publishable_Key');
define('STRIPE_SECRET_KEY''Insert_Stripe_API_Secret_Key');
 
// Database configuration 
define('DB_HOST''localhost'); 
define('DB_USERNAME''root'); 
define('DB_PASSWORD''root'); 
define('DB_NAME''codexworld_db');

?>

Note that: Stripe API Secret key and Publishable key will be found in the API Keys Data section of your Stripe account.

Database Connection (dbConnect.php)

The dbConnect.php file helps to connect the database using PHP and MySQL.

<?php  
// Connect with the database 
$db = new mysqli(DB_HOSTDB_USERNAMEDB_PASSWORDDB_NAME); 
 
// Display error if failed to connect 
if ($db->connect_errno) { 
    
printf("Connect failed: %s\n"$db->connect_error); 
    exit(); 
}

Stripe Checkout Form (index.php)

At first, include the configuration file.

<?php 
// Include configuration file 
require_once 'config.php';
?>

Stripe JS Library:
Include the Stripe.js v3 library that helps securely sending the sensitive information to Stripe directly from the browser.

<!-- Stripe JS library -->
<script src="https://js.stripe.com/v3/"></script>

Checkout JS Script:
Include the custom script (checkout.js) to process checkout with Stripe API using JavaScript.

  • Pass the Stripe API Key to the JS script in the STRIPE_PUBLISHABLE_KEY attribute.
<script src="js/checkout.js" STRIPE_PUBLISHABLE_KEY="<?php echo STRIPE_PUBLISHABLE_KEY?>" defer></script>

HTML Payment Form:
Initially, the product details are displayed with an HTML form to collect the user information (name and email) and card details (Card Number, Expiration Date, and CVC No.).

  • Define an HTML element (paymentElement) to attach Payment Elements by Stripe.js library.
  • Define element to display payment processing notification.
  • Define element to display payment re-initiate button.
<div class="panel">
    <div class="panel-heading">
        <h3 class="panel-title">Charge <?php echo '$'.$itemPrice?> with Stripe</h3>
        
        <!-- Product Info -->
        <p><b>Item Name:</b> <?php echo $itemName?></p>
        <p><b>Price:</b> <?php echo '$'.$itemPrice.' '.$currency?></p>
    </div>
    <div class="panel-body">
        <!-- Display status message -->
        <div id="paymentResponse" class="hidden"></div>
        
        <!-- Display a payment form -->
        <form id="paymentFrm" class="hidden">
            <div class="form-group">
                <label>NAME</label>
                <input type="text" id="name" class="field" placeholder="Enter name" required="" autofocus="">
            </div>
            <div class="form-group">
                <label>EMAIL</label>
                <input type="email" id="email" class="field" placeholder="Enter email" required="">
            </div>
            
            <div id="paymentElement">
                <!--Stripe.js injects the Payment Element-->
            </div>
            
            <!-- Form submit button -->
            <button id="submitBtn" class="btn btn-success">
                <div class="spinner hidden" id="spinner"></div>
                <span id="buttonText">Pay Now</span>
            </button>
        </form>
        
        <!-- Display processing notification -->
        <div id="frmProcess" class="hidden">
            <span class="ring"></span> Processing...
        </div>
        
        <!-- Display re-initiate button -->
        <div id="payReinit" class="hidden">
            <button class="btn btn-primary" onClick="window.location.href=window.location.href.split('?')[0]"><i class="rload"></i>Re-initiate Payment</button>
        </div>
    </div>
</div>

Checkout Script (checkout.js)

The following JavaScript code is used to initialize Stripe Elements and create PaymentElement with Stripe JS v3 library.

  • Create an instance of the Stripe object and set the publishable API key.
  • initialize() function is used to,
    • Fetch a payment intent from server-side script (payment_init.php) and capture the client secret.
    • Create an instance of the Elements UI library and attach the client secret.
    • Mount payment elements to the HTML element (#paymentElement) defined in the payment form.
  • handleSubmit() function is used to,
    • Post customer details to the server-side script (payment_init.php).
    • Confirm a PaymentIntent using stripe.confirmPayment of Stripe Payment Intents JS API.
  • checkStatus() function is used to,
    • Fetch the PaymentIntent status after payment submission using stripe.retrievePaymentIntent method of Stripe Payment Intents JS API.
    • Post the transaction info to the server-side script (payment_init.php) and redirect to the payment status page (payment-status.php).
  • showMessage() function helps to display status messages.
  • setLoading() function disable submit button and show a spinner on payment submission.
  • setProcessing() function disable the payment form and show the notification about payment processing.
  • setReinit() function help to disable the payment form and display the payment re-initiate button..
// Get API Key
let STRIPE_PUBLISHABLE_KEY = document.currentScript.getAttribute('STRIPE_PUBLISHABLE_KEY');

// Create an instance of the Stripe object and set your publishable API key
const stripe = Stripe(STRIPE_PUBLISHABLE_KEY);

let elements; // Define card elements
const paymentFrm = document.querySelector("#paymentFrm"); // Select payment form element

// Get payment_intent_client_secret param from URL
const clientSecretParam = new URLSearchParams(window.location.search).get(
    "payment_intent_client_secret"
);

// Check whether the payment_intent_client_secret is already exist in the URL
setProcessing(true);
if(!clientSecretParam){
    setProcessing(false);
    
    // Create an instance of the Elements UI library and attach the client secret
    initialize();
}

// Check the PaymentIntent creation status
checkStatus();

// Attach an event handler to payment form
paymentFrm.addEventListener("submit", handleSubmit);

// Fetch a payment intent and capture the client secret
let payment_intent_id;
async function initialize() {
    const { id, clientSecret } = await fetch("payment_init.php", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ request_type:'create_payment_intent' }),
    }).then((r) => r.json());
    
    const appearance = {
        theme: 'stripe',
        rules: {
            '.Label': {
                fontWeight: 'bold',
                textTransform: 'uppercase',
            }
        }
    };
    
    elements = stripe.elements({ clientSecret, appearance });
    
    const paymentElement = elements.create("payment");
    paymentElement.mount("#paymentElement");
    
    payment_intent_id = id;
}

// Card form submit handler
async function handleSubmit(e) {
    e.preventDefault();
    setLoading(true);
    
    let customer_name = document.getElementById("name").value;
    let customer_email = document.getElementById("email").value;
    
    const { id, customer_id } = await fetch("payment_init.php", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ request_type:'create_customer', payment_intent_id: payment_intent_id, name: customer_name, email: customer_email }),
    }).then((r) => r.json());
    
    const { error } = await stripe.confirmPayment({
        elements,
        confirmParams: {
            // Make sure to change this to your payment completion page
            return_url: window.location.href+'?customer_id='+customer_id,
        },
    });
    
    // This point will only be reached if there is an immediate error when
    // confirming the payment. Otherwise, your customer will be redirected to
    // your `return_url`. For some payment methods like iDEAL, your customer will
    // be redirected to an intermediate site first to authorize the payment, then
    // redirected to the `return_url`.
    if (error.type === "card_error" || error.type === "validation_error") {
        showMessage(error.message);
    } else {
        showMessage("An unexpected error occured.");
    }
    
    setLoading(false);
}

// Fetch the PaymentIntent status after payment submission
async function checkStatus() {
    const clientSecret = new URLSearchParams(window.location.search).get(
        "payment_intent_client_secret"
    );
    
    const customerID = new URLSearchParams(window.location.search).get(
        "customer_id"
    );
    
    if (!clientSecret) {
        return;
    }
    
    const { paymentIntent } = await stripe.retrievePaymentIntent(clientSecret);
    
    if (paymentIntent) {
        switch (paymentIntent.status) { 
            case "succeeded":
                //showMessage("Payment succeeded!");
                
                // Post the transaction info to the server-side script and redirect to the payment status page
                fetch("payment_init.php", {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ request_type:'payment_insert', payment_intent: paymentIntent, customer_id: customerID }),
                })
                .then(response => response.json())
                .then(data => {
                    if (data.payment_txn_id) {
                        window.location.href = 'payment-status.php?pid='+data.payment_txn_id;
                    } else {
                        showMessage(data.error);
                        setReinit();
                    }
                })
                .catch(console.error);
                
                break;
            case "processing":
                showMessage("Your payment is processing.");
                setReinit();
                break;
            case "requires_payment_method":
                showMessage("Your payment was not successful, please try again.");
                setReinit();
                break;
            default:
                showMessage("Something went wrong.");
                setReinit();
                break;
        }
    } else {
        showMessage("Something went wrong.");
        setReinit();
    }
}


// Display message
function showMessage(messageText) {
    const messageContainer = document.querySelector("#paymentResponse");
    
    messageContainer.classList.remove("hidden");
    messageContainer.textContent = messageText;
    
    setTimeout(function () {
        messageContainer.classList.add("hidden");
        messageContainer.textContent = "";
    }, 5000);
}

// Show a spinner on payment submission
function setLoading(isLoading) {
    if (isLoading) {
        // Disable the button and show a spinner
        document.querySelector("#submitBtn").disabled = true;
        document.querySelector("#spinner").classList.remove("hidden");
        document.querySelector("#buttonText").classList.add("hidden");
    } else {
        // Enable the button and hide spinner
        document.querySelector("#submitBtn").disabled = false;
        document.querySelector("#spinner").classList.add("hidden");
        document.querySelector("#buttonText").classList.remove("hidden");
    }
}

// Show a spinner on payment form processing
function setProcessing(isProcessing) {
    if (isProcessing) {
        paymentFrm.classList.add("hidden");
        document.querySelector("#frmProcess").classList.remove("hidden");
    } else {
        paymentFrm.classList.remove("hidden");
        document.querySelector("#frmProcess").classList.add("hidden");
    }
}

// Show payment re-initiate button
function setReinit() {
    document.querySelector("#frmProcess").classList.add("hidden");
    document.querySelector("#payReinit").classList.remove("hidden");
}

Stripe PHP Library

The Stripe PHP SDK library is used to create PaymentIntent, charge, and process the card payment. All the required library files are included in our source code, you don’t need to download them separately.

Process Payment and Charge Card (payment_init.php)

This server-side script is accessed by the client-side Fetch API in the JavaScript code to create PaymentIntent and process credit card charge using Stripe API library with PHP.

  • Include the Stripe PHP library.
  • Set API Secret key using setApiKey() method of Stripe class.
  • Retrieve JSON from the POST body using file_get_contents() and json_decode() in PHP.
  • If create_payment_intent request is submitted:
    • Create PaymentIntent with amount and currency using create() method of Stripe Payment Intents API.
    • Return clientSecret token to the client-side.
  • If create_customer request is submitted:
    • Create customer using create() method of Stripe Customer API.
    • Update PaymentIntent with the customer ID using update() method of Payment Intents API.
  • If payment_insert request is submitted:
    • Retrieve customer details using retrieve() method of Stripe Customer API.
    • Insert transaction data into the database using MySQL Prepared Statements with PHP.
    • Return the transaction ID in base64 encoded format to the client-side.
<?php 

// Include the configuration file
require_once 'config.php';

// Include the database connection file
include_once 'dbConnect.php';

// Include the Stripe PHP library
require_once 'stripe-php/init.php';

// Set API key
$stripe = new \Stripe\StripeClient(STRIPE_SECRET_KEY);

// Retrieve JSON from POST body
$jsonStr file_get_contents('php://input');
$jsonObj json_decode($jsonStr);

if(
$jsonObj->request_type == 'create_payment_intent'){
    
// Define item price and convert to cents
    
$itemPriceCents round($itemPrice*100);
    
    try {
        
// Create PaymentIntent with amount and currency
        
$paymentIntent $stripe->paymentIntents->create([
            
'amount' => $itemPriceCents,
            
'currency' => $currency,
            
'description' => $itemName,
            
'payment_method_types' => [
                
'card'
            
]
            
/*'automatic_payment_methods' => [
                'enabled' => true
            ]*/
        
]);
    
        
$output = [
            
'id' => $paymentIntent->id,
            
'clientSecret' => $paymentIntent->client_secret
        
];
    
        echo 
json_encode($output);
    } catch (
Error $e) {
        
http_response_code(500);
        echo 
json_encode(['error' => $e->getMessage()]);
    }
}elseif(
$jsonObj->request_type == 'create_customer'){
    
$payment_intent_id = !empty($jsonObj->payment_intent_id)?$jsonObj->payment_intent_id:'';
    
$name = !empty($jsonObj->name)?$jsonObj->name:'';
    
$email = !empty($jsonObj->email)?$jsonObj->email:'';

    
// Check if PaymentIntent already has a customer
    
if(!empty($payment_intent_id)){
        
$paymentIntent $stripe->paymentIntents->retrieve($payment_intent_id);
        if(!empty(
$paymentIntent->customer)){
            
$customer_id $paymentIntent->customer;
        }
    }
    
    
// Add customer to stripe if not created already
    
if(empty($customer_id)){
        try {  
            
$customer $stripe->customers->create([
                
'name' => $name
                
'email' => $email
            
]); 
            
$customer_id $customer->id;
        }catch(
Error $e) {  
            
$api_error $e->getMessage();  
        }
    }
    
    if(empty(
$api_error) && !empty($customer_id)){
        try {
            
// Update PaymentIntent with the customer ID
            
$paymentIntent $stripe->paymentIntents->update($payment_intent_id, [
                
'customer' => $customer_id
            
]);
        } catch (
Error $e) { 
            
$api_error $e->getMessage(); 
        }
        
        if(empty(
$api_error) && $paymentIntent){
            
$output = [
                
'id' => $payment_intent_id,
                
'customer_id' => $customer_id
            
];
            echo 
json_encode($output);
        }else{
            
http_response_code(500);
            echo 
json_encode(['error' => $api_error]);
        }
    }else{
        
http_response_code(500);
        echo 
json_encode(['error' => $api_error]);
    }
}elseif(
$jsonObj->request_type == 'payment_insert'){
    
$payment_intent = !empty($jsonObj->payment_intent)?$jsonObj->payment_intent:'';
    
$customer_id = !empty($jsonObj->customer_id)?$jsonObj->customer_id:'';
    
    
// Retrieve customer info
    
try {  
        
$customer $stripe->customers->retrieve($customer_id); 
    }catch(
Error $e) {  
        
$api_error $e->getMessage();  
    }
    
    
// Check whether the charge was successful
    
if(!empty($payment_intent) && $payment_intent->status == 'succeeded'){
        
// Transaction details 
        
$transaction_id $payment_intent->id;
        
$paid_amount $payment_intent->amount;
        
$paid_amount = ($paid_amount/100);
        
$paid_currency $payment_intent->currency;
        
$payment_status $payment_intent->status;
        
        
$customer_name $customer_email '';
        if(!empty(
$customer)){
            
$customer_name = !empty($customer->name)?$customer->name:'';
            
$customer_email = !empty($customer->email)?$customer->email:'';
        }
        
        
// Check if any transaction data exists already with the same TXN ID
        
$sqlQ "SELECT id FROM transactions WHERE txn_id = ?";
        
$stmt $db->prepare($sqlQ); 
        
$stmt->bind_param("s"$transaction_id);
        
$stmt->execute();
        
$stmt->bind_result($row_id);
        
$stmt->fetch();
        
        
$payment_id 0;
        if(!empty(
$row_id)){
            
$payment_id $row_id;
        }else{
            
// Insert transaction data into the database
            
$sqlQ "INSERT INTO transactions (customer_name,customer_email,item_name,item_price,item_price_currency,paid_amount,paid_amount_currency,txn_id,payment_status,created,modified) VALUES (?,?,?,?,?,?,?,?,?,NOW(),NOW())";
            
$stmt $db->prepare($sqlQ);
            
$stmt->bind_param("sssdsdsss"$customer_name$customer_email$itemName$itemPrice$currency$paid_amount$paid_currency$transaction_id$payment_status);
            
$insert $stmt->execute();
            
            if(
$insert){
                
$payment_id $stmt->insert_id;
            }
        }
        
        
$output = [
            
'payment_txn_id' => base64_encode($transaction_id)
        ];
        echo 
json_encode($output);
    }else{
        
http_response_code(500);
        echo 
json_encode(['error' => 'Transaction has been failed!']);
    }
}

?>

Payment Status (payment-status.php)

Based on the paymentIntent.status the user is redirected to this page.

  • Fetch transaction data from the database using PHP and MySQL.
  • Display payment status with customer details.
<?php 
// Include the configuration file 
require_once 'config.php';

// Include the database connection file 
require_once 'dbConnect.php';

$payment_ref_id $statusMsg '';
$status 'error';

// Check whether the payment ID is not empty
if(!empty($_GET['pid'])){
    
$payment_txn_id  base64_decode($_GET['pid']);
    
    
// Fetch transaction data from the database
    
$sqlQ "SELECT id,txn_id,paid_amount,paid_amount_currency,payment_status,customer_name,customer_email FROM transactions WHERE txn_id = ?";
    
$stmt $db->prepare($sqlQ); 
    
$stmt->bind_param("s"$payment_txn_id);
    
$stmt->execute();
    
$stmt->store_result();

    if(
$stmt->num_rows 0){
        
// Get transaction details
        
$stmt->bind_result($payment_ref_id$txn_id$paid_amount$paid_amount_currency$payment_status$customer_name$customer_email);
        
$stmt->fetch();
        
        
$status 'success';
        
$statusMsg 'Your Payment has been Successful!';
    }else{
        
$statusMsg "Transaction has been failed!";
    }
}else{
    
header("Location: index.php");
    exit;
}
?> <?php if(!empty($payment_ref_id)){ ?> <h1 class="<?php echo $status?>"><?php echo $statusMsg?></h1> <h4>Payment Information</h4> <p><b>Reference Number:</b> <?php echo $payment_ref_id?></p> <p><b>Transaction ID:</b> <?php echo $txn_id?></p> <p><b>Paid Amount:</b> <?php echo $paid_amount.' '.$paid_amount_currency?></p> <p><b>Payment Status:</b> <?php echo $payment_status?></p> <h4>Customer Information</h4> <p><b>Name:</b> <?php echo $customer_name?></p> <p><b>Email:</b> <?php echo $customer_email?></p> <h4>Product Information</h4> <p><b>Name:</b> <?php echo $itemName?></p> <p><b>Price:</b> <?php echo $itemPrice.' '.$currency?></p> <?php }else{ ?> <h1 class="error">Your Payment been failed!</h1> <p class="error"><?php echo $statusMsg?></p> <?php ?>

Test Card Details

To test the payment process, you need test card details. Use any of the following test card numbers, a valid future expiration date, and any random CVC number, to test Stripe payment gateway integration in PHP.

  • 4242 4242 4242 4242 – Visa
  • 4000 0566 5566 5556 – Visa (debit)
  • 5555 5555 5555 4444 – Mastercard
  • 5200 8282 8282 8210 – Mastercard (debit)
  • 3782 822463 10005 – American Express
  • 6011 1111 1111 1117 – Discover
  • 3566 0020 2036 0505 – JCB
  • 6200 0000 0000 0005 – UnionPay

3D Secure Authentication

The 3D Secure feature requires additional authentication for credit card transactions. Use the following test cards to simulate the payment process that involves 3D Secure authentication.

  • 4000 0027 6000 3184
  • 4000 0000 0000 3063

Make Stripe Payment Gateway Live

Once the integration is completed and the payment process is working properly, follow the below steps to make Stripe payment gateway live.

  • Login to your Stripe account and navigate to the Developers » API keys page.
  • Collect the API keys (Publishable key and Secret key) from Live Data.
  • In the config.php file, replace the Test API keys (Publishable key and Secret key) with the Live API keys (Publishable key and Secret key).
    define('STRIPE_PUBLISHABLE_KEY''LIVE_API_Publishable_key'); 
    define('STRIPE_SECRET_KEY''LIVE_API_Secret_key');

PayPal Payment Gateway Integration in PHP

Conclusion

The Stripe payment gateway is the easiest way to accept credit card payment on the web application. Our example code uses the Stripe PHP library to create a charge and make payment with a credit/debit card. The 3D Secure authentication is integrated to make this Stripe integration script ready for SCA (Strong Customer Authentication). If you want to use Stripe hosted checkout system, integrate redirect-based Stripe Checkout in PHP.

Do you want to get implementation help, or enhance the functionality of this script? Click here to Submit Service Request

56 Comments

  1. Eric Said...

Leave a reply

keyboard_double_arrow_up