Stripe Subscription Payment Integration in CodeIgniter

The Stripe payment gateway provides an easy way to accept subscription payments on the web application. You can implement the membership subscription system with recurring billing using Stripe API. The Stripe Plans and Subscription API allows you to integrate recurring payment functionality in a quick and effective manner. Stripe Subscription is the powerful option to allow your website’s members to purchase/subscribe membership online using their credit card.

Stripe PHP library helps to integrate Stripe Subscription API in PHP. If your website builds with the CodeIgniter framework, the Stripe PHP library and API need to be integrated into the CodeIgniter application. In the Stripe subscription payment system, the subscriber charged recurringly based on the specific interval. The subscriber can purchase a membership plan of your website with their credit/debit card without leaving the web application. In this tutorial, we will show you how to integrate Stripe subscription payment functionality in CodeIgniter.

In this example script, the following functionality will be implemented to build a CodeIgniter Subscription application with Stripe API.

  • Fetch subscription plans from the database and list them under a dropdown.
  • Create an HTML form to select a plan and provide the credit card information.
  • Create Stripe token to securely transmit card information.
  • Verify the card details and create a subscription plan with Stripe API.
  • Store transaction data and subscription plan info in the database.

Stripe Test API Keys

Before making the Stripe payment gateway live, it needs to be checked whether the checkout process is working properly. You need to use the test API keys data to check the credit card payment process.

  • 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 token 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 integrate Stripe Subscription payment in CodeIgniter, take a look at the file structure.

codeigniter_stripe_subscription_payment_integration/
├── application/
│   ├── config/
│   │   └── stripe.php
│   ├── controllers/
│   │   └── Subscription.php
│   ├── libraries/
│   │   └── Stripe_lib.php
│   ├── models/
│   │   └── User.php
│   ├── third_party/
│   │   └── stripe-php/
│   ├── views/
│   │   └── subscription/
│   │       ├── index.php
│   │       └── payment-status.php
└── assets/
    └── css/
        └── style.css

Create Database Tables

3 tables are required to store the plan, member, and subscription information in the database.

1. The following SQL creates a plans table to hold the subscription plan information in the MySQL database.

CREATE TABLE `plans` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `price` float(10,2) NOT NULL,
 `currency` varchar(10) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'USD',
 `interval` enum('week','month','year') COLLATE utf8_unicode_ci NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

2. The following SQL creates a users table to hold the website member’s information in the MySQL database.

CREATE TABLE `users` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `subscription_id` int(11) NOT NULL DEFAULT 0,
 `first_name` varchar(25) COLLATE utf8_unicode_ci NOT NULL,
 `last_name` varchar(25) COLLATE utf8_unicode_ci NOT NULL,
 `email` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `gender` enum('Male','Female') COLLATE utf8_unicode_ci NOT NULL,
 `phone` varchar(15) COLLATE utf8_unicode_ci NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 `status` enum('1','0') COLLATE utf8_unicode_ci NOT NULL DEFAULT '1',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

3. The following SQL creates a user_subscriptions table to hold the subscription and payment information in the MySQL database.

CREATE TABLE `user_subscriptions` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `user_id` int(11) NOT NULL DEFAULT 0,
 `plan_id` int(11) NOT NULL,
 `payment_method` enum('stripe') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'stripe',
 `stripe_subscription_id` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 `stripe_customer_id` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 `stripe_plan_id` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 `plan_amount` float(10,2) NOT NULL,
 `plan_amount_currency` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
 `plan_interval` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
 `plan_interval_count` tinyint(2) NOT NULL,
 `plan_period_start` datetime NOT NULL,
 `plan_period_end` datetime NOT NULL,
 `payer_email` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 `created` datetime NOT NULL,
 `status` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Config

stripe.php
The configuration variables of the Stripe library are defined in this file.

  • Specify the Stripe API Secret key (stripe_api_key), API Publishable key (stripe_publishable_key), and currency code (stripe_currency).
<?php 
defined
('BASEPATH') OR exit('No direct script access allowed');
/*
| -------------------------------------------------------------------
|  Stripe API Configuration
| -------------------------------------------------------------------
|
| You will get the API keys from Developers panel of the Stripe account
| Login to Stripe account (https://dashboard.stripe.com/)
| and navigate to the Developers » API keys page
| Remember to switch to your live publishable and secret key in production!
|
|  stripe_api_key            string   Your Stripe API Secret key.
|  stripe_publishable_key    string   Your Stripe API Publishable key.
|  stripe_currency           string   Currency code.
*/
$config['stripe_api_key']         = 'Your_API_Secret_key';
$config['stripe_publishable_key'] = 'Your_API_Publishable_key';
$config['stripe_currency']        = 'usd';

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

Third Party

stripe-php/
Stripe PHP bindings library is used to create customer, plan, and subscription with Stripe API. The Stripe PHP library needs to be placed in the third_party/ directory of your CodeIgniter application.

Note that: You don’t need to download the Stripe PHP library separately, all the required files are included in the source code.

Library

Stripe_lib.php
The Stripe CodeIgniter Library helps to integrate Stripe subscription payment in CodeIgniter 3 application. This library has the dependency of a configuration file (application/config/stripe.php) and Stripe PHP bindings library (application/third_party/stripe-php).

  • __construct() – Set an API key and initiate the Stripe class.
  • addCustomer() – Add a customer to Stripe account using Stripe Customer API.
  • createPlan() – Create a plan using Stripe Plan API.
  • createSubscription() – Create a subscription using Stripe Subscription API.
<?php 
defined
('BASEPATH') OR exit('No direct script access allowed');

/**
 * Stripe Library for CodeIgniter 3.x
 *
 * Library for Stripe payment gateway. It helps to integrate Stripe payment gateway
 * in CodeIgniter application.
 *
 * This library requires the Stripe PHP bindings and it should be placed in the third_party folder.
 * It also requires Stripe API configuration file and it should be placed in the config directory.
 *
 * @package     CodeIgniter
 * @category    Libraries
 * @author      CodexWorld
 * @license     http://www.codexworld.com/license/
 * @link        http://www.codexworld.com
 * @version     3.0
 */

class Stripe_lib{
    var 
$CI;
    var 
$api_error;
    
    function 
__construct(){
        
$this->api_error '';
        
$this->CI =& get_instance();
        
$this->CI->load->config('stripe');
        
        
// Include the Stripe PHP bindings library
        
require APPPATH .'third_party/stripe-php/init.php';
        
        
// Set API key
        
\Stripe\Stripe::setApiKey($this->CI->config->item('stripe_api_key'));
    }

    function 
addCustomer($name$email$token){
        try {
            
// Add customer to stripe
            
$customer = \Stripe\Customer::create(array(
                
'name' => $name,
                
'email' => $email,
                
'source'  => $token
            
));
            return 
$customer;
        }catch(
Exception $e) {
            
$this->api_error $e->getMessage();
            return 
false;
        }
    }
    
    function 
createPlan($planName$planPrice$planInterval){
        
// Convert price to cents
        
$priceCents = ($planPrice*100);
        
$currency $this->CI->config->item('stripe_currency');
        
        try {
            
// Create a plan
            
$plan = \Stripe\Plan::create(array(
                
"product" => [
                    
"name" => $planName
                
],
                
"amount" => $priceCents,
                
"currency" => $currency,
                
"interval" => $planInterval,
                
"interval_count" => 1
            
));
            return 
$plan;
        }catch(
Exception $e) {
            
$this->api_error $e->getMessage();
            return 
false;
        }
    }
    
    function 
createSubscription($customerID$planID){
        try {
            
// Creates a new subscription
            
$subscription = \Stripe\Subscription::create(array(
                
"customer" => $customerID,
                
"items" => array(
                    array(
                        
"plan" => $planID
                    
),
                ),
            ));
            
            
// Retrieve charge details
            
$subsData $subscription->jsonSerialize();
            return 
$subsData;
        }catch(
Exception $e) {
            
$this->api_error $e->getMessage();
            return 
false;
        }
    }
}

Controller (Subscription.php)

The Subscription controller handles the plan subscription and payment process with the Stripe library.

  • __construct()
    • Loads the Stripe library and user model.
    • Get the logged-in user ID from the SESSION.
  • index()
    • Fetch the plans data from the database and pass to view for plan listing.
    • If payment form is submitted,
      • Check whether it has a valid stripe token.
      • Retrieve stripe token, subscriber, and plan info from the submitted form data.
      • Call the payment() function and pass posted data to make the payment.
    • If payment is successful, redirect to the subscription status page.
  • payment() – This function is for internal use by the Subscription controller.
    • Get the stripe token and user info.
    • Fetch a specific plan data from the database using the getPlans() method of the User model.
    • Add customer by submitted name, email, and token using addCustomer() method of Stripe library.
    • Create a plan by selected plan info using the createPlan() method of the Stripe library.
    • Create a subscription by customer ID and plan ID using createSubscription() method of Stripe library.
    • If the subscription activation is successful,
      • Insert transaction and subscription details into the database using insertSubscription() method of the User model.
      • Return subscription ID.
  • payment_status()
    • Fetch the subscription details from the database using getSubscription() method of the User model.
    • Pass subscription data to the view for showing the subscription status.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 

class 
Subscription extends CI_Controller {
    
    function 
__construct() {
        
parent::__construct();
        
        
// Load Stripe library
        
$this->load->library('stripe_lib');
        
        
// Load product model
        
$this->load->model('user');
        
        
// Get user ID from current SESSION
        
$this->userID = isset($_SESSION['loggedInUserID'])?$_SESSION['loggedInUserID']:1;
    }
    
    public function 
index(){
        
$data = array();
        
        
// If payment form is submitted with token
        
if($this->input->post('stripeToken')){
            
// Retrieve stripe token and user info from the posted form data
            
$postData $this->input->post();
            
            
// Make payment
            
$paymentID $this->payment($postData);
            
            
// If payment successful
            
if($paymentID){
                
redirect('subscription/payment_status/'.$paymentID);
            }else{
                
$apiError = !empty($this->stripe_lib->api_error)?' ('.$this->stripe_lib->api_error.')':'';
                
$data['error_msg'] = 'Transaction has been failed!'.$apiError;
            }
        }
        
        
// Get plans from the database
        
$data['plans'] = $this->user->getPlans();
        
        
// Pass plans data to the list view
        
$this->load->view('subscription/index'$data);
    }
    
    function 
payment($postData){
        
        
// If post data is not empty
        
if(!empty($postData)){
            
// Retrieve stripe token and user info from the submitted form data
            
$token  $postData['stripeToken'];
            
$name $postData['name'];
            
$email $postData['email'];
            
            
// Plan info
            
$planID $_POST['subscr_plan'];
            
$planInfo $this->user->getPlans($planID);
            
$planName $planInfo['name'];
            
$planPrice $planInfo['price'];
            
$planInterval $planInfo['interval'];
            
            
// Add customer to stripe
            
$customer $this->stripe_lib->addCustomer($name$email$token);
            
            if(
$customer){
                
// Create a plan
                
$plan $this->stripe_lib->createPlan($planName$planPrice$planInterval);
                
                if(
$plan){
                    
// Creates a new subscription
                    
$subscription $this->stripe_lib->createSubscription($customer->id$plan->id);
                    
                    if(
$subscription){
                        
// Check whether the subscription activation is successful
                        
if($subscription['status'] == 'active'){
                            
// Subscription info
                            
$subscrID $subscription['id'];
                            
$custID $subscription['customer'];
                            
$planID $subscription['plan']['id'];
                            
$planAmount = ($subscription['plan']['amount']/100);
                            
$planCurrency $subscription['plan']['currency'];
                            
$planInterval $subscription['plan']['interval'];
                            
$planIntervalCount $subscription['plan']['interval_count'];
                            
$created date("Y-m-d H:i:s"$subscription['created']);
                            
$current_period_start date("Y-m-d H:i:s"$subscription['current_period_start']);
                            
$current_period_end date("Y-m-d H:i:s"$subscription['current_period_end']);
                            
$status $subscription['status'];
                            
                            
// Insert tansaction data into the database
                            
$subscripData = array(
                                
'user_id' => $this->userID,
                                
'plan_id' => $planInfo['id'],
                                
'stripe_subscription_id' => $subscrID,
                                
'stripe_customer_id' => $custID,
                                
'stripe_plan_id' => $planID,
                                
'plan_amount' => $planAmount,
                                
'plan_amount_currency' => $planCurrency,
                                
'plan_interval' => $planInterval,
                                
'plan_interval_count' => $planIntervalCount,
                                
'plan_period_start' => $current_period_start,
                                
'plan_period_end' => $current_period_end,
                                
'payer_email' => $email,
                                
'created' => $created,
                                
'status' => $status
                            
);
                            
$subscription_id $this->user->insertSubscription($subscripData);
                            
                            
// Update subscription id in the users table 
                            
if($subscription_id && !empty($this->userID)){
                                
$data = array('subscription_id' => $subscription_id);
                                
$update $this->user->updateUser($data$this->userID);
                            }
                            
                            return 
$subscription_id;
                        }
                    }
                }
            }
        }
        return 
false;
    }
    
    function 
payment_status($id){
        
$data = array();
        
        
// Get subscription data from the database
        
$subscription $this->user->getSubscription($id);
        
        
// Pass subscription data to the view
        
$data['subscription'] = $subscription;
        
$this->load->view('subscription/payment-status'$data);
    }
}

Model (User.php)

The User model handles database related (fetch, insert, and update) operations.

  • __construct() – Defines the name of the database tables.
  • updateUser() – Update user data in the users table.
  • getSubscription() – Fetch the subscription data from the user_subscriptions and plans table.
  • insertSubscription() – Insert the subscription data in the user_subscriptions table.
  • getPlans() – Fetch the records from the plans table and returns as an array.
<?php 
if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class 
User extends CI_Model {
    function 
__construct(){
        
$this->userTbl        'users';
        
$this->planTbl    'plans';
        
$this->subscripTbl    'user_subscriptions';
    }
    
    
/*
     * Update user data to the database
     * @param data array
     * @param id specific user
     */
    
public function updateUser($data$id){
        
$update $this->db->update($this->userTbl$data, array('id' => $id));
        return 
$update?true:false;
    }
    
    
/*
     * Fetch order data from the database
     * @param id returns a single record
     */
    
public function getSubscription($id){
        
$this->db->select('s.*, p.name as plan_name, p.price as plan_price, p.currency as plan_price_currency, p.interval');
        
$this->db->from($this->subscripTbl.' as s');
        
$this->db->join($this->planTbl.' as p''p.id = s.plan_id''left');
        
$this->db->where('s.id'$id);
        
$query  $this->db->get();
        return (
$query->num_rows() > 0)?$query->row_array():false;
    }
    
    
/*
     * Insert subscription data in the database
     * @param data array
     */
    
public function insertSubscription($data){
        
$insert $this->db->insert($this->subscripTbl,$data);
        return 
$insert?$this->db->insert_id():false;
    }
    
    
/*
     * Fetch plans data from the database
     * @param id returns a single record if specified, otherwise all records
     */
    
public function getPlans($id ''){
        
$this->db->select('*');
        
$this->db->from($this->planTbl);
        if(
$id){
            
$this->db->where('id'$id);
            
$query  $this->db->get();
            
$result = ($query->num_rows() > 0)?$query->row_array():array();
        }else{
            
$this->db->order_by('id''asc');
            
$query  $this->db->get();
            
$result = ($query->num_rows() > 0)?$query->result_array():array();
        }
        
        
// return fetched data
        
return !empty($result)?$result:false;
    }
}

View

1. subscription/index.php
Plan selection dropdown with payment form is displayed on this page.

Plan and Payment Form:
The HTML form collects the user information (name and email) and card details (Card Number, Expiration Date, and CVC No.).

  • All the available plans are listed under a dropdown.
<div class="panel">
    <form action="" method="POST" id="paymentFrm">
        <div class="panel-heading">
            <h3 class="panel-title">Plan Subscription with Stripe</h3>
            <!-- Plan Info -->
            <p>
                <b>Select Plan:</b>
                <select name="subscr_plan" id="subscr_plan">
                    <?php foreach($plans as $plan){ ?>
                    <option value="<?php echo $plan['id']; ?>"><?php echo $plan['name'].' [$'.$plan['price'].'/'.$plan['interval'].']'?></option>
                    <?php ?>
                </select>
            </p>
        </div>
        <div class="panel-body">
            <!-- Display errors returned by createToken -->
            <div id="paymentResponse"></div>
			
            <!-- Payment form -->
            <div class="form-group">
                <label>NAME</label>
                <input type="text" name="name" id="name" class="field" placeholder="Enter name" required="" autofocus="">
            </div>
            <div class="form-group">
                <label>EMAIL</label>
                <input type="email" name="email" id="email" class="field" placeholder="Enter email" required="">
            </div>
            <div class="form-group">
                <label>CARD NUMBER</label>
                <div id="card_number" class="field"></div>
            </div>
            <div class="row">
                <div class="left">
                    <div class="form-group">
                        <label>EXPIRY DATE</label>
                        <div id="card_expiry" class="field"></div>
                    </div>
                </div>
                <div class="right">
                    <div class="form-group">
                        <label>CVC CODE</label>
                        <div id="card_cvc" class="field"></div>
                    </div>
                </div>
            </div>
            <button type="submit" class="btn btn-success" id="payBtn">Submit Payment</button>
        </div>
    </form>
</div>

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

<script src="https://js.stripe.com/v3/"></script>

The following JavaScript code is used to create a token with the Stripe JS v3 library.

  • Set your publishable API key that identifies your website to Stripe.
  • Use Stripe Elements to customize UI components in the payment form.
  • Create an instance of Elements using stripe.elements() method.
  • Create an instance of a specific Element using elements.create() method.
  • Attach your Element to the DOM using element.mount() method.
  • The createToken() function creates a single-use token using stripe.createToken() method and card elements.
  • The stripeTokenHandler() function creates a hidden input with the Stripe token and appends it to the payment form.
  • On success, the card details are submitted to the server-side. Otherwise, the error message is shown.
<script>
// Create an instance of the Stripe object
// Set your publishable API key
var stripe = Stripe('<?php echo $this->config->item('stripe_publishable_key'); ?>');

// Create an instance of elements
var elements = stripe.elements();

var style = {
    base: {
        fontWeight: 400,
        fontFamily: 'Roboto, Open Sans, Segoe UI, sans-serif',
        fontSize: '16px',
        lineHeight: '1.4',
        color: '#555',
        backgroundColor: '#fff',
        '::placeholder': {
            color: '#888',
        },
    },
    invalid: {
        color: '#eb1c26',
    }
};

var cardElement = elements.create('cardNumber', {
    style: style
});
cardElement.mount('#card_number');

var exp = elements.create('cardExpiry', {
    'style': style
});
exp.mount('#card_expiry');

var cvc = elements.create('cardCvc', {
    'style': style
});
cvc.mount('#card_cvc');

// Validate input of the card elements
var resultContainer = document.getElementById('paymentResponse');
cardElement.addEventListener('change', function(event) {
    if (event.error) {
        resultContainer.innerHTML = '<p>'+event.error.message+'</p>';
    } else {
        resultContainer.innerHTML = '';
    }
});

// Get payment form element
var form = document.getElementById('paymentFrm');

// Create a token when the form is submitted.
form.addEventListener('submit', function(e) {
    e.preventDefault();
    createToken();
});

// Create single-use token to charge the user
function createToken() {
    stripe.createToken(cardElement).then(function(result) {
        if (result.error) {
            // Inform the user if there was an error
            resultContainer.innerHTML = '<p>'+result.error.message+'</p>';
        } else {
            // Send the token to your server
            stripeTokenHandler(result.token);
        }
    });
}

// Callback to handle the response from stripe
function stripeTokenHandler(token) {
    // Insert the token ID into the form so it gets submitted to the server
    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();
}
</script>

2. subscription/payment-status.php
The subscription details and payment status are shown on this page.

<?php if(!empty($subscription)){ ?>
    <?php if($subscription['status'] == 'active'){ ?>
    <h1 class="success">Your Subscription Payment has been Successful!</h1>
    <?php }else{ ?>
    <h1 class="error">Subscription activation failed!</h1>
    <?php ?>

    <h4>Payment Information</h4>
    <p><b>Reference Number:</b> <?php echo $subscription['id']; ?></p>
    <p><b>Transaction ID:</b> <?php echo $subscription['stripe_subscription_id']; ?></p>
    <p><b>Amount:</b> <?php echo $subscription['plan_amount'].' '.$subscription['plan_amount_currency']; ?></p>
    
    <h4>Subscription Information</h4>
    <p><b>Plan Name:</b> <?php echo $subscription['plan_name']; ?></p>
    <p><b>Amount:</b> <?php echo $subscription['plan_price'].' '.$subscription['plan_price_currency']; ?></p>
    <p><b>Plan Interval:</b> <?php echo $subscription['plan_interval']; ?></p>
    <p><b>Period Start:</b> <?php echo $subscription['plan_period_start']; ?></p>
    <p><b>Period End:</b> <?php echo $subscription['plan_period_end']; ?></p>
    <p><b>Status:</b> <?php echo $subscription['status']; ?></p>
<?php }else{ ?>
    <h1 class="error">The transaction has been failed!</h1>
<?php ?>

Make Stripe Payment Gateway Live

Once the Stripe checkout 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 application/config/stripe.php file, replace the Test API keys (Publishable key and Secret key) by the Live API keys (Publishable key and Secret key).

Stripe Payment Gateway Integration in CodeIgniter

Conclusion

Stripe Subscription API is very useful when you want to recurring billing to the customer weekly/monthly/yearly. This example script is very useful to integrate the membership subscription payment system on your website. You can allow users to purchase a subscription on your CodeIgniter website using a credit/debit card. Our example code makes the subscription payment process user-friendly and checkout can be completed on a single page using Stripe API.

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

2 Comments

  1. Pankaj Thakur Said...
  2. Hanna Said...

Leave a reply

keyboard_double_arrow_up