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.
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.
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
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;
stripe.php
The configuration variables of the Stripe library are defined in this file.
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.
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.
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
).
<?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;
}
}
}
The Subscription controller handles the plan subscription and payment process with the Stripe library.
payment()
function and pass posted data to make the payment.getPlans()
method of the User model.addCustomer()
method of Stripe library.createPlan()
method of the Stripe library.createSubscription()
method of Stripe library.insertSubscription()
method of the User model.getSubscription()
method of the User model.<?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);
}
}
The User model handles database related (fetch, insert, and update) operations.
users
table.user_subscriptions
and plans
table.user_subscriptions
table.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;
}
}
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.).
<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.
stripe.elements()
method.elements.create()
method.element.mount()
method.createToken()
function creates a single-use token using stripe.createToken()
method and card elements.stripeTokenHandler()
function creates a hidden input with the Stripe token and appends it to the payment form.<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 } ?>
Once the Stripe checkout process is working properly, follow the below steps to make Stripe payment gateway live.
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
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
I have updated this script to CI4. everything is working fine but when i call createSubscription() then it give me status incomplete
[status] => incomplete
[test_clock] =>
[transfer_data] =>
[trial_end] =>
[trial_settings] => Array
(
[end_behavior] => Array
(
[missing_payment_method] => create_invoice
)
)
cOUPLD YOU PLEASE HELP OM THIS
Thank you