PHP & MySQL

Simple Chat Application - PHP, MySQL & AJAX

Build a real-time chat application with PHP, MySQL, and AJAX. Covers user registration, message storage, long-polling, and XSS prevention.

Architecture Overview

A simple chat system requires three components: a database to store messages, a PHP backend to handle sending and retrieving messages, and a JavaScript frontend to display messages and poll for updates.

Database Schema

CREATE TABLE chat_messages (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    message TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE chat_users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    last_active TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

PHP Backend - Send Message

<?php
// send.php
header('Content-Type: application/json');

$pdo = new PDO('mysql:host=localhost;dbname=chat', 'user', 'pass', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

$username = trim($_POST['username'] ?? '');
$message = trim($_POST['message'] ?? '');

if (strlen($username) < 2 || strlen($message) < 1) {
    echo json_encode(['error' => 'Invalid input']);
    exit;
}

// Sanitize - prevent XSS
$username = htmlspecialchars($username, ENT_QUOTES, 'UTF-8');
$message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');

$stmt = $pdo->prepare(
    "INSERT INTO chat_messages (username, message) VALUES (?, ?)"
);
$stmt->execute([$username, $message]);

echo json_encode(['status' => 'ok', 'id' => $pdo->lastInsertId()]);

PHP Backend - Fetch Messages

<?php
// fetch.php
header('Content-Type: application/json');

$pdo = new PDO('mysql:host=localhost;dbname=chat', 'user', 'pass');

$lastId = (int) ($_GET['after'] ?? 0);

$stmt = $pdo->prepare(
    "SELECT id, username, message, created_at
     FROM chat_messages
     WHERE id > ?
     ORDER BY id ASC
     LIMIT 50"
);
$stmt->execute([$lastId]);
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);

echo json_encode($messages);

JavaScript Frontend - Polling

let lastId = 0;

async function fetchMessages() {
  const res = await fetch(`fetch.php?after=${lastId}`);
  const messages = await res.json();

  messages.forEach(msg => {
    lastId = msg.id;
    appendMessage(msg.username, msg.message, msg.created_at);
  });
}

function appendMessage(user, text, time) {
  const div = document.createElement('div');
  div.className = 'message';
  div.innerHTML = `
    <strong>${user}</strong>
    <span class="time">${new Date(time).toLocaleTimeString()}</span>
    <p>${text}</p>`;
  document.getElementById('messages').appendChild(div);
  div.scrollIntoView({ behavior: 'smooth' });
}

// Send message
document.getElementById('chatForm').addEventListener('submit', async (e) => {
  e.preventDefault();
  const form = new FormData(e.target);
  await fetch('send.php', { method: 'POST', body: form });
  e.target.querySelector('[name="message"]').value = '';
  fetchMessages();
});

// Poll every 2 seconds
setInterval(fetchMessages, 2000);
fetchMessages();

Security Checklist

ThreatPrevention
XSS (script injection)htmlspecialchars() on all user input
SQL injectionPrepared statements (PDO/MySQLi)
Spam / floodingRate limiting (e.g., max 1 msg/sec per user)
CSRFCSRF tokens on form submission
Message size abuseValidate max length server-side

Modern Alternatives

For production chat applications, consider WebSockets (using Ratchet for PHP or Socket.io for Node.js) instead of AJAX polling. WebSockets provide true real-time communication without the overhead of repeated HTTP requests. For managed solutions, services like Pusher, Ably, or Firebase Realtime Database handle the infrastructure for you.

Last updated: 2026 • Browse all courses