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
| Threat | Prevention |
|---|---|
| XSS (script injection) | htmlspecialchars() on all user input |
| SQL injection | Prepared statements (PDO/MySQLi) |
| Spam / flooding | Rate limiting (e.g., max 1 msg/sec per user) |
| CSRF | CSRF tokens on form submission |
| Message size abuse | Validate 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