BackendGuy
backend developer

stripe payment Integration in PHP

There are many payment services available in the market to integrate payment gateway in an application. For example, PayPal, Stripe, Sage Pay, CCAvenue and there is a long list out there. They provide API for integrating payment gateway to our software. In many countries, Stripe is the widely used for the transactions with credit and debit cards.

By using a payment gateway services / API, we can enable users to do financial transactions with our application. When it comes to integrating a payment gateway with our application, we need to choose a reputed provider. Because it gives trust to the users and it is important as it involves real money.

In this article, we are going to see about implementing Stripe payment gateway and how to integrate using PHP.Steps to integrate the Stripe payment gateway

1. Get API keys

Create a Stripe account and login to the dashboard. Navigate through the Developers -> API keys menu to get the API keys. There is two type of standard API keys named secret key and publishable key. The secret key will be masked by default which has to be revealed by clicking reveal key tokencontrol explicitly.

Stripe-Payment-Gateway-API-Key

These keys are stored in a config file as PHP constants and will be used in the Stripe payment code later.

2. HTML Stripe Payment Form

In this HTML form, it includes fields like cardholder name, card number, CVC, expiration month/year to get the user input. We have already created this form with such fields for the credit card validator example. It also includes the item_number, item_name, amount and currency_code as the hidden input.

Stripe API recommends using tokens instead of submitting test card details while testing the Payment integration. The test tokens are mapped with the tokenized card details by using Stripe JavaScript library.

<?php if(!empty($successMessage)) { ?>
<div id="success-message"><?php echo $successMessage; ?></div>
<?php  } ?>
<div id="error-message"></div>

<form id="frmStripePayment" action="" method="post">
    <div class="field-row">
        <label>Card Holder Name</label> <span id="card-holder-name-info"
            class="info"></span><br> <input type="text" id="name"
            name="name" class="demoInputBox">
    </div>
    <div class="field-row">
        <label>Email</label> <span id="email-info" class="info"></span><br>
        <input type="text" id="email" name="email" class="demoInputBox">
    </div>
    <div class="field-row">
        <label>Card Number</label> <span id="card-number-info"
            class="info"></span><br> <input type="text" id="card-number"
            name="card-number" class="demoInputBox">
    </div>
    <div class="field-row">
        <div class="contact-row column-right">
            <label>Expiry Month / Year</label> <span id="userEmail-info"
                class="info"></span><br> <select name="month" id="month"
                class="demoSelectBox">
                <option value="08">08</option>
                <option value="09">9</option>
                <option value="10">10</option>
                <option value="11">11</option>
                <option value="12">12</option>
            </select> <select name="year" id="year"
                class="demoSelectBox">
                <option value="18">2018</option>
                <option value="19">2019</option>
                <option value="20">2020</option>
                <option value="21">2021</option>
                <option value="22">2022</option>
                <option value="23">2023</option>
                <option value="24">2024</option>
                <option value="25">2025</option>
                <option value="26">2026</option>
                <option value="27">2027</option>
                <option value="28">2028</option>
                <option value="29">2029</option>
                <option value="30">2030</option>
            </select>
        </div>
        <div class="contact-row cvv-box">
            <label>CVC</label> <span id="cvv-info" class="info"></span><br>
            <input type="text" name="cvc" id="cvc"
                class="demoInputBox cvv-input">
        </div>
    </div>
    <div>
        <input type="submit" name="pay_now" value="Submit"
            id="submit-btn" class="btnAction"
            onClick="stripePay(event);">

        <div id="loader">
            <img alt="loader" src="LoaderIcon.gif">
        </div>
    </div>
    <input type='hidden' name='amount' value='0.5'> <input type='hidden'
        name='currency_code' value='USD'> <input type='hidden'
        name='item_name' value='Test Product'> <input type='hidden'
        name='item_number' value='PHPPOTEG#1'>
</form>

3. Client-Side Card Validation and Response Handler with Stripe JavaScript Library

On submitting the card details, the entered data will be validated in the client side. Once the validation returns true, then the card details will be sent to the get Stripe server to get a token. The Stripe API will return the token and it will be added to the payment form fields using Stripe ResponseHandler. This is the most welcoming feature of the Stripe payment handling card details and validation with Stripe server via JavaScript.

After inserting the token, the form will be submitted programmatically using the Javascript.

<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script src="vendor/jquery/jquery-3.2.1.min.js" type="text/javascript"></script>
<script>
function cardValidation () {
    var valid = true;
    var name = $('#name').val();
    var email = $('#email').val();
    var cardNumber = $('#card-number').val();
    var month = $('#month').val();
    var year = $('#year').val();
    var cvc = $('#cvc').val();

    $("#error-message").html("").hide();

    if (name.trim() == "") {
        valid = false;
    }
    if (email.trim() == "") {
    	   valid = false;
    }
    if (cardNumber.trim() == "") {
    	   valid = false;
    }

    if (month.trim() == "") {
    	    valid = false;
    }
    if (year.trim() == "") {
        valid = false;
    }
    if (cvc.trim() == "") {
        valid = false;
    }

    if(valid == false) {
        $("#error-message").html("All Fields are required").show();
    }

    return valid;
}
//set your publishable key
Stripe.setPublishableKey("<?php echo STRIPE_PUBLISHABLE_KEY; ?>");

//callback to handle the response from stripe
function stripeResponseHandler(status, response) {
    if (response.error) {
        //enable the submit button
        $("#submit-btn").show();
        $( "#loader" ).css("display", "none");
        //display the errors on the form
        $("#error-message").html(response.error.message).show();
    } else {
        //get token id
        var token = response['id'];
        //insert the token into the form
        $("#frmStripePayment").append("<input type='hidden' name='token' value='" + token + "' />");
        //submit form to the server
        $("#frmStripePayment").submit();
    }
}
function stripePay(e) {
    e.preventDefault();
    var valid = cardValidation();

    if(valid == true) {
        $("#submit-btn").hide();
        $( "#loader" ).css("display", "inline-block");
        Stripe.createToken({
            number: $('#card-number').val(),
            cvc: $('#cvc').val(),
            exp_month: $('#month').val(),
            exp_year: $('#year').val()
        }, stripeResponseHandler);

        //submit from callback
        return false;
    }
}
</script>

4. Process Charges via Stripe in PHP

Download Stripe PHP library which is required for processing charges using PHP code. The payment related functions are created in a PHP class StripePayment.php. It processes the Stripe charges by sending the API token and other payment request data like customer id, amount, currency and more. After processing the payment request the Stripe API will return the payment response as a JSON object.

<?php
namespace backendguy\Service;

require_once 'vendor/stripe/autoload.php';

use \Stripe\Stripe;
use \Stripe\Customer;
use \Stripe\ApiOperations\Create;
use \Stripe\Charge;

class StripePayment
{

    private $apiKey;

    private $stripeService;

    public function __construct()
    {
        require_once "config.php";
        $this->apiKey = STRIPE_SECRET_KEY;
        $this->stripeService = new \Stripe\Stripe();
        $this->stripeService->setVerifySslCerts(false);
        $this->stripeService->setApiKey($this->apiKey);
    }

    public function addCustomer($customerDetailsAry)
    {
        
        $customer = new Customer();
        
        $customerDetails = $customer->create($customerDetailsAry);
        
        return $customerDetails;
    }

    public function chargeAmountFromCard($cardDetails)
    {
        $customerDetailsAry = array(
            'email' => $cardDetails['email'],
            'source' => $cardDetails['token']
        );
        $customerResult = $this->addCustomer($customerDetailsAry);
        $charge = new Charge();
        $cardDetailsAry = array(
            'customer' => $customerResult->id,
            'amount' => $cardDetails['amount']*100 ,
            'currency' => $cardDetails['currency_code'],
            'description' => $cardDetails['item_name'],
            'metadata' => array(
                'order_id' => $cardDetails['item_number']
            )
        );
        $result = $charge->create($cardDetailsAry);

        return $result->jsonSerialize();
    }
}

5. Store and Display Stripe Payment Response

The serialized JSON object is parsed to get the payment status and response. The details like email, item_number, item_name, payment status and response are stored in the tbl_payment table by using the MySQL insert. I used the prepared statement with MySQLi for handling the database operations.

<?php
use \backendguy\Service\StripePayment;

if (!empty($_POST["token"])) {
    require_once 'StripePayment.php';
    $stripePayment = new StripePayment();
    
    $stripeResponse = $stripePayment->chargeAmountFromCard($_POST);
    
    require_once "DBController.php";
    $dbController = new DBController();
    
    $amount = $stripeResponse["amount"] /100;
    
    $param_type = 'ssdssss';
    $param_value_array = array(
        $_POST['email'],
        $_POST['item_number'],
        $amount,
        $stripeResponse["currency"],
        $stripeResponse["balance_transaction"],
        $stripeResponse["status"],
        json_encode($stripeResponse)
    );
    $query = "INSERT INTO tbl_payment (email, item_number, amount, currency_code, txn_id, payment_status, payment_response) values (?, ?, ?, ?, ?, ?, ?)";
    $id = $dbController->insert($query, $param_type, $param_value_array);
    
    if ($stripeResponse['amount_refunded'] == 0 && empty($stripeResponse['failure_code']) && $stripeResponse['paid'] == 1 && $stripeResponse['captured'] == 1 && $stripeResponse['status'] == 'succeeded') {
       $successMessage = "Stripe payment is completed successfully. The TXN ID is " . $stripeResponse["balance_transaction"];
    }
}
?>

Payment Database Structure

The following SQL script shows the query statement for creating the payment database table to store the payment data returned by the Stripe API after processing our payment request.

--
-- Table structure for table `tbl_payment`
--

CREATE TABLE `tbl_payment` (
  `id` int(11) NOT NULL,
  `email` varchar(255) NOT NULL,
  `item_number` varchar(255) NOT NULL,
  `amount` double(10,2) NOT NULL,
  `currency_code` varchar(55) NOT NULL,
  `txn_id` varchar(255) NOT NULL,
  `payment_status` varchar(255) NOT NULL,
  `payment_response` text NOT NULL,
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Indexes for table `tbl_payment`
--
ALTER TABLE `tbl_payment`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for table `tbl_payment`
--
ALTER TABLE `tbl_payment`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;

Testing with Stripe Payment Gateway Demo

You can find more test data in the Stripe API testing documentation. You can use the test card numbers to demonstrate Stripe payment integration.

Note: Before going to live, we need to test Stripe payment in test data mode. Once we found everything is working good with the test mode, then it will be easy to go live by toggling the data mode.

BackendGuy

Add comment

Your Header Sidebar area is currently empty. Hurry up and add some widgets.