Chat Widget
Chat with us!

Text.lk SMS Gateway Sri Lanka | Cheapest price on the market (0.64LKR per SMS)

  +94 77 644 00 80

Login         Register

How to Implement OTP (One-Time Password) Verification Using PHP, MySQL & Text.lk SMS Gateway

Below is a complete, production-ready OTP implementation guide using PHP + MySQL + Text.lk SMS Gateway in Sri Lanka

OTP (One-Time Password) verification is commonly used for:

  • User registration
  • Login verification
  • Password reset
  • Sensitive actions (payments, profile changes)

In this tutorial, you’ll learn step-by-step how to implement an OTP system using:

  • PHP (backend)
  • MySQL (database)
  • Text.lk SMS Gateway

OTP Flow Overview

  1. User enters mobile number
  2. System generates a random OTP
  3. OTP is stored in the database (hashed)
  4. OTP is sent via Text.lk SMS
  5. User enters OTP
  6. OTP is verified & expired OTPs rejected

Project Structure

otp-system/
├── config.php
├── db.php
├── send_otp.php
├── verify_otp.php
├── textlk.php
├── index.php
└── verify.php

Step 1: Create MySQL Table

CREATE TABLE otp_verifications (
    id INT AUTO_INCREMENT PRIMARY KEY,
    mobile VARCHAR(15) NOT NULL,
    otp_hash VARCHAR(255) NOT NULL,
    expires_at DATETIME NOT NULL,
    is_verified TINYINT(1) DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Security tip: Store OTP as a hash, not plain text.


Step 2: Configuration (config.php)

<?php
define('TEXTLK_API_KEY', 'YOUR_TEXTLK_API_KEY');
define('TEXTLK_SENDER_ID', 'TEXTLK');
define('TEXTLK_API_URL', 'https://app.text.lk/api/v3/sms/send');
define('OTP_EXPIRY_MINUTES', 5);

Step 3: Database Connection (db.php)

<?php
$conn = new mysqli("localhost", "db_user", "db_pass", "db_name");

if ($conn->connect_error) {
    die("Database connection failed");
}

Step 4: Text.lk SMS Sender (textlk.php)

<?php
function sendSMS($mobile, $message) {
    $payload = [
        "api_key" => TEXTLK_API_KEY,
        "sender_id" => TEXTLK_SENDER_ID,
        "to" => $mobile,
        "message" => $message
    ];

    $ch = curl_init(TEXTLK_API_URL);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);

    $response = curl_exec($ch);
    curl_close($ch);

    return $response;
}

Step 5: Generate & Send OTP (send_otp.php)

<?php
require 'config.php';
require 'db.php';
require 'textlk.php';

$mobile = $_POST['mobile'];

// Generate OTP
$otp = rand(100000, 999999);
$otpHash = password_hash($otp, PASSWORD_DEFAULT);
$expiresAt = date('Y-m-d H:i:s', strtotime('+'.OTP_EXPIRY_MINUTES.' minutes'));

// Save OTP
$stmt = $conn->prepare("
    INSERT INTO otp_verifications (mobile, otp_hash, expires_at)
    VALUES (?, ?, ?)
");
$stmt->bind_param("sss", $mobile, $otpHash, $expiresAt);
$stmt->execute();

// Send SMS
$message = "Your OTP code is $otp. Valid for 5 minutes.";
sendSMS($mobile, $message);

echo json_encode(["status" => "success", "message" => "OTP sent"]);

Step 6: Verify OTP (verify_otp.php)

<?php
require 'db.php';

$mobile = $_POST['mobile'];
$otp = $_POST['otp'];

$stmt = $conn->prepare("
    SELECT id, otp_hash, expires_at
    FROM otp_verifications
    WHERE mobile = ? AND is_verified = 0
    ORDER BY id DESC LIMIT 1
");
$stmt->bind_param("s", $mobile);
$stmt->execute();
$result = $stmt->get_result();

if ($row = $result->fetch_assoc()) {
    if (strtotime($row['expires_at']) < time()) {
        echo json_encode(["status" => "error", "message" => "OTP expired"]);
        exit;
    }

    if (password_verify($otp, $row['otp_hash'])) {
        $update = $conn->prepare("UPDATE otp_verifications SET is_verified = 1 WHERE id = ?");
        $update->bind_param("i", $row['id']);
        $update->execute();

        echo json_encode(["status" => "success", "message" => "OTP verified"]);
    } else {
        echo json_encode(["status" => "error", "message" => "Invalid OTP"]);
    }
} else {
    echo json_encode(["status" => "error", "message" => "OTP not found"]);
}

Step 7: Frontend (Simple Example)

OTP Request (index.php)

<form method="post" action="send_otp.php">
    <input type="text" name="mobile" placeholder="07XXXXXXXX" required>
    <button type="submit">Send OTP</button>
</form>

OTP Verify (verify.php)

<form method="post" action="verify_otp.php">
    <input type="text" name="mobile" required>
    <input type="text" name="otp" placeholder="Enter OTP" required>
    <button type="submit">Verify</button>
</form>

Security Best Practices

✔ OTP expiry (5 minutes max)
✔ Hash OTP in database
✔ Limit OTP requests per number
✔ Prevent brute force attempts
✔ Use HTTPS always
✔ Delete old OTP records via cron


Optional: Auto Cleanup (Cron Job)

DELETE FROM otp_verifications
WHERE expires_at < NOW();

Run every hour via cron.


🎯 Use Cases

  • User registration
  • Login verification
  • Password reset
  • Transaction confirmation
  • Admin action confirmation

🚀 Production Enhancements

  • Redis for OTP storage (high traffic)
  • Rate-limit OTP requests
  • Device fingerprinting
  • Webhook-based delivery reports from Text.lk

🏁 Conclusion

You now have a secure, scalable OTP system using PHP, MySQL, and Text.lk SMS that’s suitable for:

  • SaaS platforms
  • Banking & fintech
  • Sri Lanka–based applications

Leave a Reply

Your email address will not be published. Required fields are marked *