PHP 7 Script to Integrate Stripe Subscription Payment in Website Using 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;
CREATE TABLE `user_subscriptions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL DEFAULT '0',
`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,
`payer_email` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`created` datetime NOT NULL,
`plan_period_start` datetime NOT NULL,
`plan_period_end` datetime NOT NULL,
`status` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
<?php
// Subscription plans
// Minimum amount is $0.50 US
// Interval day, week, month or year
$plans = array(
'1' => array(
'name' => 'Weekly Subscription',
'price' => 25,
'interval' => 'week'
),
'2' => array(
'name' => 'Monthly Subscription',
'price' => 85,
'interval' => 'month'
),
'3' => array(
'name' => 'Yearly Subscription',
'price' => 950,
'interval' => 'year'
)
);
$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_API_KEY', 'Your_API_Secret_key');
define('STRIPE_PUBLISHABLE_KEY', 'Your_API_Publishable_key');
// Database configuration
define('DB_HOST', 'MySQL_Database_Host');
define('DB_USERNAME', 'MySQL_Database_Username');
define('DB_PASSWORD', 'MySQL_Database_Password');
define('DB_NAME', 'MySQL_Database_Name');
<?php
// Connect with the database
$db = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);
// Display error if failed to connect
if ($db->connect_errno) {
printf("Connect failed: %s\n", $db->connect_error);
exit();
}
<?php
// Include configuration file
require_once 'config.php';
?>
<div class="panel">
<form action="payment.php" 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 $id=>$plan){ ?>
<option value="<?php echo $id; ?>"><?php echo $plan['name'].' [
<script src="https://js.stripe.com/v3/"></script>
<script>
// Create an instance of the Stripe object
// Set your publishable API key
var stripe = Stripe('<?php echo 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>
<?php
// Include configuration file
require_once 'config.php';
// Get user ID from current SESSION
$userID = isset($_SESSION['loggedInUserID'])?$_SESSION['loggedInUserID']:1;
$payment_id = $statusMsg = $api_error = '';
$ordStatus = 'error';
// Check whether stripe token is not empty
if(!empty($_POST['subscr_plan']) && !empty($_POST['stripeToken'])){
// Retrieve stripe token and user info from the submitted form data
$token = $_POST['stripeToken'];
$name = $_POST['name'];
$email = $_POST['email'];
// Plan info
$planID = $_POST['subscr_plan'];
$planInfo = $plans[$planID];
$planName = $planInfo['name'];
$planPrice = $planInfo['price'];
$planInterval = $planInfo['interval'];
// Include Stripe PHP library
require_once 'stripe-php/init.php';
// Set API key
\Stripe\Stripe::setApiKey(STRIPE_API_KEY);
// Add customer to stripe
try {
$customer = \Stripe\Customer::create(array(
'email' => $email,
'source' => $token
));
}catch(Exception $e) {
$api_error = $e->getMessage();
}
if(empty($api_error) && $customer){
// Convert price to cents
$priceCents = round($planPrice*100);
// Create a plan
try {
$plan = \Stripe\Plan::create(array(
"product" => [
"name" => $planName
],
"amount" => $priceCents,
"currency" => $currency,
"interval" => $planInterval,
"interval_count" => 1
));
}catch(Exception $e) {
$api_error = $e->getMessage();
}
if(empty($api_error) && $plan){
// Creates a new subscription
try {
$subscription = \Stripe\Subscription::create(array(
"customer" => $customer->id,
"items" => array(
array(
"plan" => $plan->id,
),
),
));
}catch(Exception $e) {
$api_error = $e->getMessage();
}
if(empty($api_error) && $subscription){
// Retrieve subscription data
$subsData = $subscription->jsonSerialize();
// Check whether the subscription activation is successful
if($subsData['status'] == 'active'){
// Subscription info
$subscrID = $subsData['id'];
$custID = $subsData['customer'];
$planID = $subsData['plan']['id'];
$planAmount = ($subsData['plan']['amount']/100);
$planCurrency = $subsData['plan']['currency'];
$planinterval = $subsData['plan']['interval'];
$planIntervalCount = $subsData['plan']['interval_count'];
$created = date("Y-m-d H:i:s", $subsData['created']);
$current_period_start = date("Y-m-d H:i:s", $subsData['current_period_start']);
$current_period_end = date("Y-m-d H:i:s", $subsData['current_period_end']);
$status = $subsData['status'];
// Include database connection file
include_once 'dbConnect.php';
// Insert transaction data into the database
$sql = "INSERT INTO user_subscriptions(user_id,stripe_subscription_id,stripe_customer_id,stripe_plan_id,plan_amount,plan_amount_currency,plan_interval,plan_interval_count,payer_email,created,plan_period_start,plan_period_end,status) VALUES('".$userID."','".$subscrID."','".$custID."','".$planID."','".$planAmount."','".$planCurrency."','".$planinterval."','".$planIntervalCount."','".$email."','".$created."','".$current_period_start."','".$current_period_end."','".$status."')";
$insert = $db->query($sql);
// Update subscription id in the users table
if($insert && !empty($userID)){
$subscription_id = $db->insert_id;
$update = $db->query("UPDATE users SET subscription_id = {$subscription_id} WHERE id = {$userID}");
}
$ordStatus = 'success';
$statusMsg = 'Your Subscription Payment has been Successful!';
}else{
$statusMsg = "Subscription activation failed!";
}
}else{
$statusMsg = "Subscription creation failed! ".$api_error;
}
}else{
$statusMsg = "Plan creation failed! ".$api_error;
}
}else{
$statusMsg = "Invalid card details! $api_error";
}
}else{
$statusMsg = "Error on form submission, please try again.";
}
?>
<div class="container">
<div class="status">
<h1 class="<?php echo $ordStatus; ?>"><?php echo $statusMsg; ?></h1>
<?php if(!empty($subscrID)){ ?>
<h4>Payment Information</h4>
<p><b>Reference Number:</b> <?php echo $subscription_id; ?></p>
<p><b>Transaction ID:</b> <?php echo $subscrID; ?></p>
<p><b>Amount:</b> <?php echo $planAmount.' '.$planCurrency; ?></p>
<h4>Subscription Information</h4>
<p><b>Plan Name:</b> <?php echo $planName; ?></p>
<p><b>Amount:</b> <?php echo $planPrice.' '.$currency; ?></p>
<p><b>Plan Interval:</b> <?php echo $planInterval; ?></p>
<p><b>Period Start:</b> <?php echo $current_period_start; ?></p>
<p><b>Period End:</b> <?php echo $current_period_end; ?></p>
<p><b>Status:</b> <?php echo $status; ?></p>
<?php } ?>
</div>
<a href="index.php" class="btn-link">Back to Subscription Page</a>
</div>
.$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>