Unit 13 ยท E-commerce and Web-Related Components

13.8Service Integration: Payment Gateway, Email and Others

On this page
  1. Payment gateways
  2. Email integration
  3. Other common integrations

Modern websites connect to external services through their APIs. You send an HTTP request (usually JSON) with a secret key, and the service does the specialised work.

Payment gateways

A payment gateway securely takes card or wallet payments. Your site should never receive or store card numbers; the gateway's hosted page handles them (this keeps you out of the heaviest PCI-DSS obligations). Popular gateways include PayHere (widely used in Sri Lanka), Stripe, PayPal, and local bank gateways. All provide a sandbox (test mode) with fake cards.

Typical hosted-checkout flow

Customer's browserYour serverPayment gateway1click Paycreate order: status = pending2form with order id, amount, hash3customer pays on the gateway page4redirect to return_url (display only)5notify_url webhook + signature(server to server)6verify signature and amount,then mark the order paidOnly step 5 (the verified webhook) proves payment; the return page can be faked.
Hosted checkout: card details go to the gateway, and your server trusts only the verified webhook

Illustrative PayHere-style form (check the gateway's current documentation for the exact field names and hash formula; the steps below are the same for any gateway):

PHP
<?php
$merchantId     = getenv('PAYHERE_MERCHANT_ID');       // from environment/config, never from the browser
$merchantSecret = getenv('PAYHERE_SECRET');
$orderId  = $order['id'];
$amount   = number_format($order['total'], 2, '.', '');
$currency = 'LKR';
$hash = strtoupper(md5($merchantId . $orderId . $amount . $currency . strtoupper(md5($merchantSecret))));
?>
<form method='post' action='https://sandbox.payhere.lk/pay/checkout'>
  <input type='hidden' name='merchant_id' value='<?= $merchantId ?>'>
  <input type='hidden' name='return_url'  value='https://yourshop.com/order_success.php'>
  <input type='hidden' name='cancel_url'  value='https://yourshop.com/cart.php'>
  <input type='hidden' name='notify_url'  value='https://yourshop.com/payment_notify.php'>
  <input type='hidden' name='order_id'    value='<?= $orderId ?>'>
  <input type='hidden' name='items'       value='My Shop order <?= $orderId ?>'>
  <input type='hidden' name='currency'    value='<?= $currency ?>'>
  <input type='hidden' name='amount'      value='<?= $amount ?>'>
  <input type='hidden' name='hash'        value='<?= $hash ?>'>
  <!-- plus first_name, last_name, email, phone, address, city, country -->
  <button type='submit'>Pay now</button>
</form>

Webhook handler (payment_notify.php): the only place an order becomes "paid".

PHP
<?php
require 'config/db.php';
// 1. Recompute the signature from the posted fields using YOUR secret (see gateway docs)
// 2. Compare with the signature the gateway sent, using hash_equals
// 3. Confirm the status code means success and the amount equals the order total in YOUR database
// 4. Only then update: UPDATE orders SET status='paid' WHERE id=? AND status='pending'
// 5. Log everything; respond with HTTP 200

Payment integration checklist: build and test fully in sandbox; keep keys in environment variables or a config file outside the web root; use HTTPS everywhere; recalculate amounts on the server; make the webhook idempotent (a repeated notification must not process the order twice); store the gateway's transaction id; handle cancel, failure and pending states.

Email integration

PHP's mail() function is unreliable (messages usually land in spam). Use SMTP through a library such as PHPMailer, installed with Composer (composer require phpmailer/phpmailer), and an email provider (your hosting mail server, Gmail SMTP with an app password, SendGrid, Mailgun, Amazon SES).

includes/mail.php:

PHP
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require __DIR__ . '/../vendor/autoload.php';

function send_mail(string $to, string $subject, string $body): bool {
    $mail = new PHPMailer(true);
    try {
        $mail->isSMTP();
        $mail->Host       = getenv('SMTP_HOST');          // e.g. smtp.gmail.com
        $mail->SMTPAuth   = true;
        $mail->Username   = getenv('SMTP_USER');
        $mail->Password   = getenv('SMTP_PASS');
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
        $mail->Port       = 587;

        $mail->setFrom('[email protected]', 'My Shop');
        $mail->addAddress($to);
        $mail->Subject = $subject;
        $mail->Body    = $body;                           // for HTML mail use isHTML(true)
        $mail->send();
        return true;
    } catch (Exception $e) {
        error_log('Mail error: ' . $mail->ErrorInfo);
        return false;
    }
}

Use cases: welcome email, order confirmation with a summary, shipping notification, password reset link, contact form messages to the owner. Never put user-supplied text directly into email headers (header injection); validate the address with filter_var. For better delivery, configure SPF, DKIM and DMARC records in DNS (Unit 14).

Other common integrations

ServicePurpose
Google Maps / OpenStreetMapShow store locations, delivery addresses
SMS gatewaysOrder alerts and one-time passwords
Social login (Google, Facebook OAuth)"Sign in with Google"
reCAPTCHA / hCaptchaStop bots on registration, login, contact forms
Shipping and courier APIsRates and tracking numbers
Analytics (Google Analytics)Traffic and conversion statistics
Cloud storage (S3, Cloudinary)Store and resize product images

Calling any REST API from PHP with cURL:

PHP
$ch = curl_init('https://api.example.com/v1/rates');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Content-Type: application/json', 'Authorization: Bearer ' . getenv('API_KEY')],
    CURLOPT_POSTFIELDS     => json_encode(['weight' => 2, 'city' => 'Colombo']),
    CURLOPT_TIMEOUT        => 10,
]);
$response = curl_exec($ch);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($response, true);

Check yourself. The questions for this part are on the 13.9 Review Questions page, with answers to check your work.