Real-Time Domain Availability Checker in PHP (AJAX + WHOIS + DNS)
A modern PHP-based domain search tool with AJAX, DNS checks, and WHOIS fallback. Get instant domain availability results and smart suggestions in a fast, elegant UI.
Suggested:
Learn how to create a real-time PHP chat app using MySQL and JavaScript with user login, typing status, chat history deletion, and a modern, responsive UI.
In this tutorial, you’ll learn how to build a real-time chat application using PHP, MySQL, and JavaScript from scratch. We’ll create a modern, user-friendly chat system featuring secure authentication, live typing indicators, message history management, and a clean, responsive UI. Using AJAX for real-time updates and TailwindCSS-style design, this project is perfect for anyone who wants to level up their PHP skills and build practical, production-ready applications.
Table of contents [Show]
Features: Landing Page, Registration/Login, Typing Indicator, Delete + History, Prettier UI
chat-app/
│
├── chat.php
├── check_typing_status.php
├── config.php
├── db.sql
├── delete_message.php
├── fetch_messages.php
├── index.php
├── login.php
├── logout.php
├── register.php
├── send_message.php
├── style.css
└── typing_status.php<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chat App - Connect Instantly</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
background: #f4f7fb;
color: #2c3e50;
line-height: 1.6;
}
header {
background: #ffffff;
padding: 20px 40px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
display: flex;
justify-content: space-between;
align-items: center;
}
header h1 {
font-size: 24px;
color: #3498db;
}
nav a {
margin-left: 20px;
text-decoration: none;
color: #2c3e50;
font-weight: 500;
}
.hero {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100px 20px;
text-align: center;
background: linear-gradient(135deg, #3498db 20%, #9b59b6 100%);
color: white;
}
.hero h2 {
font-size: 42px;
max-width: 600px;
margin-bottom: 20px;
}
.hero p {
font-size: 18px;
max-width: 500px;
margin-bottom: 30px;
}
.hero .cta {
display: flex;
gap: 15px;
}
.hero .cta a {
padding: 12px 24px;
background: white;
color: #3498db;
font-weight: 600;
text-decoration: none;
border-radius: 6px;
transition: 0.3s;
}
.hero .cta a:hover {
background: #ecf0f1;
}
.preview {
padding: 60px 20px;
text-align: center;
}
.preview h3 {
font-size: 28px;
margin-bottom: 20px;
}
.chat-ui-sample {
max-width: 600px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.05);
padding: 20px;
text-align: left;
}
.message {
margin-bottom: 15px;
}
.message .sender {
font-weight: 600;
color: #3498db;
}
.footer {
text-align: center;
padding: 20px;
color: #95a5a6;
font-size: 14px;
}
</style>
</head>
<body>
<header>
<h1>Chat App</h1>
<!-- <nav>
<a href="#">Login</a>
<a href="#">Sign Up</a>
<a href="#">Docs</a>
</nav> -->
</header>
<section class="hero">
<h2>Fast, Secure, and Fun Messaging</h2>
<p>Chatter lets you connect instantly with friends and colleagues through real-time messaging, voice, and media sharing.</p>
<div class="cta">
<a href="register.php">Register</a>
<a href="login.php">Login</a>
</div>
</section>
<section class="preview">
<h3>See How It Works</h3>
<div class="chat-ui-sample">
<div class="message">
<div class="sender">Alice</div>
<div class="text">Hey Bob, are we meeting at 3 PM?</div>
</div>
<div class="message">
<div class="sender">Bob</div>
<div class="text">Yes! Don’t forget the slides 😄</div>
</div>
</div>
</section>
<footer class="footer">
© 2025 Chat App. All rights reserved.
</footer>
</body>
</html>
<?php
require 'config.php';
// Initialize error message
$error = '';
// CSRF Token Generation
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// CSRF Token Validation
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
$error = "Invalid CSRF token.";
} else {
$username = trim($_POST['username']);
$password = $_POST['password'];
// Validate username (3-20 characters, alphanumeric + underscore)
if (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {
$error = "Username must be 3-20 characters and contain only letters, numbers, and underscores.";
}
// Validate password length
elseif (strlen($password) < 6) {
$error = "Password must be at least 6 characters long.";
}
else {
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
$stmt = $conn->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$stmt->bind_param("ss", $username, $hashedPassword);
if ($stmt->execute()) {
header("Location: login.php");
exit();
} else {
$error = "Username already taken or database error.";
}
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Register</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.login-container {
background-color: white;
padding: 20px 30px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
width: 300px;
}
.login-container h2 {
text-align: center;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input {
width: 100%;
padding: 8px;
box-sizing: border-box;
}
.login-button {
width: 100%;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.login-button:hover {
background-color: #45a049;
}
.text-danger {
color: red;
font-size: 0.9em;
text-align: center;
}
.text-link {
text-align: center;
margin-top: 10px;
font-size: 0.9em;
}
</style>
</head>
<body>
<div class="login-container">
<h2>Register</h2>
<form method="post">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($_SESSION['csrf_token']); ?>">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" placeholder="Username" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit" class="login-button">Register</button>
<p class="text-danger"><?php echo htmlspecialchars($error); ?></p>
</form>
<p class="text-link">Already have an account? <a href="login.php">Login Here</a>.</p>
</div>
</body>
</html>
<?php
require 'config.php';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $conn->prepare("SELECT id, password FROM users WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($user_id, $hashed_password);
if ($stmt->num_rows > 0 && $stmt->fetch() && password_verify($password, $hashed_password)) {
$_SESSION['user_id'] = $user_id;
$_SESSION['username'] = $username;
header("Location: chat.php");
} else {
$error = "Invalid login";
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login Form</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.login-container {
background-color: white;
padding: 20px 30px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
width: 300px;
}
.login-container h2 {
text-align: center;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input {
width: 100%;
padding: 8px;
box-sizing: border-box;
}
.login-button {
width: 100%;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.login-button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<div class="login-container">
<h2>Login</h2>
<form method="post">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" placeholder="Username" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit" class="login-button">Login</button>
<p class="text-danger"><?php echo $error ?? ''; ?></p>
</form>
<p>Don't have an account? <a href="register.php">Register here</a>.</p>
</div>
</body>
</html>
<?php
require 'config.php';
if (!isset($_SESSION['user_id'])) {
header("Location: index.php");
exit();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Messaging Template with Usernames</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
background: #f1f1f1;
margin: 0;
padding: 0;
}
.chat-container {
max-width: 600px;
margin: 50px auto;
background: #fff;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
padding: 20px;
}
</style>
</head>
<body>
<div class="chat-container">
<h3>Welcome, <?php echo $_SESSION['username']; ?>!</h3>
<a href="logout.php" class="btn btn-danger">Logout</a>
<div id="chat-box" class="border p-3 mb-3" style="height: 400px; overflow-y: scroll;"></div>
<form id="chat-form">
<input type="text" id="message" class="form-control mb-2" placeholder="Enter message" required>
<button class="btn btn-success">Send</button>
</form>
</div>
</body>
</html>
<script>
$(document).ready(function () {
let typingTimer;
let isTyping = false;
function setTypingStatus(status) {
if (isTyping !== status) {
isTyping = status;
$.post("typing_status.php", { typing: status ? 1 : "" });
}
}
function loadMessages() {
$.get("fetch_messages.php", function (data) {
$('#chat-box').html(data);
// Auto-scroll removed
});
}
// Initial load and polling
loadMessages();
setInterval(loadMessages, 1000);
// Handle message sending
$('#chat-form').on('submit', function (e) {
e.preventDefault();
setTypingStatus(false);
$.post("send_message.php", { message: $('#message').val() }, function () {
$('#message').val('');
loadMessages();
});
});
// Handle typing indicator
$('#message').on('input', function () {
setTypingStatus(true);
clearTimeout(typingTimer);
typingTimer = setTimeout(() => {
setTypingStatus(false);
}, 3000);
});
// Handle message deletion
$(document).on('click', '.delete-btn', function () {
if (confirm('Are you sure you want to delete this message?')) {
const messageId = $(this).data('id');
$.post('delete_message.php', { message_id: messageId }, function () {
loadMessages();
});
}
});
});
</script><?php
session_start();
session_destroy();
header("Location: index.php");
exit();
?>
<?php
require 'config.php';
if (isset($_SESSION['user_id']) && isset($_POST['message'])) {
$msg = htmlspecialchars(trim($_POST['message']));
$stmt = $conn->prepare("INSERT INTO messages (user_id, message) VALUES (?, ?)");
$stmt->bind_param("is", $_SESSION['user_id'], $msg);
$stmt->execute();
}
?>
<?php
require 'config.php';
echo '<style>
/* General Styles */
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
background-color: #f1f1f1;
color: #333;
padding: 20px;
}
/* Message container styling */
.message-container {
font-family: Arial, sans-serif;
margin-bottom: 20px;
padding: 15px;
border-radius: 12px;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
background-color: #ffffff;
transition: all 0.3s ease;
}
.message-container:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
}
.message-author {
font-weight: bold;
color: #4a90e2;
font-size: 16px;
}
.message-body {
margin-top: 8px;
font-size: 15px;
color: #555;
}
.message-body.deleted {
font-style: italic;
color: #999;
}
.message-time {
font-size: 12px;
color: #777;
margin-top: 5px;
}
/* Styling for message delete button */
.btn-danger {
background-color: #ff4757;
border: none;
color: white;
padding: 6px 12px;
border-radius: 5px;
cursor: pointer;
font-size: 12px;
margin-top: 5px;
transition: background-color 0.3s ease;
}
.btn-danger:hover {
background-color: #e84118;
}
.btn-danger:focus {
outline: none;
}
/* Align message based on user */
.message-container.mine {
background-color: #e0f7fa;
align-self: flex-end;
}
.message-container.mine .message-author {
color: #00bcd4;
}
.message-container.mine .message-time {
color: #00bcd4;
}
/* Typing indicator */
.typing-indicator {
font-style: italic;
color: #aaa;
margin-top: 10px;
font-size: 14px;
}
/* Styling for the chat container */
.chat-container {
display: flex;
flex-direction: column;
max-width: 600px;
margin: 0 auto;
}
/* Mobile responsiveness */
@media (max-width: 600px) {
.message-container {
padding: 12px;
}
.message-author {
font-size: 14px;
}
.message-body {
font-size: 13px;
}
.typing-indicator {
font-size: 13px;
}
}
</style>';
echo '<div class="chat-container">';
$query = "SELECT m.id, m.message, m.deleted, m.created_at, m.user_id, u.username
FROM messages m
JOIN users u ON m.user_id = u.id
ORDER BY m.created_at ASC";
$result = $conn->query($query);
while ($row = $result->fetch_assoc()) {
$isMine = $row['user_id'] == $_SESSION['user_id'];
// Add 'mine' class for self-messages to align them to the right
$messageClass = $isMine ? 'mine' : '';
echo "<div class='message-container $messageClass'>";
echo "<p class='message-author'>" . htmlspecialchars($row['username']) . ":</p>";
if ($row['deleted']) {
echo "<p class='message-body deleted'>Message deleted</p>";
} else {
echo "<p class='message-body'>" . htmlspecialchars($row['message']) . "</p>";
}
echo "<p class='message-time'>(" . htmlspecialchars($row['created_at']) . ")</p>";
// Show delete button if the message belongs to the current user and is not deleted
if ($isMine && !$row['deleted']) {
echo "<form method='POST' action='delete_message.php' style='display:inline'>
<input type='hidden' name='message_id' value='{$row['id']}'>
<button type='submit' class='btn-danger' onclick=\"return confirm('Delete this message?');\">Delete</button>
</form>";
}
echo "</div>";
}
// Typing indicator
$typing_query = "SELECT username FROM users WHERE is_typing = 1 AND id != {$_SESSION['user_id']}";
$typing_result = $conn->query($typing_query);
if ($typing_result->num_rows > 0) {
$typing_users = [];
while ($row = $typing_result->fetch_assoc()) {
$typing_users[] = $row['username'];
}
echo "<p class='typing-indicator'>" . implode(', ', $typing_users) . " is typing...</p>";
}
echo '</div>';
?>
<?php
require 'config.php';
session_start();
if (!isset($_SESSION['user_id'])) {
exit('Unauthorized');
}
$userId = (int)$_SESSION['user_id'];
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message_id'])) {
$messageId = (int)$_POST['message_id'];
// Verify that the message belongs to the user
$check = $conn->prepare("SELECT id FROM messages WHERE id = ? AND user_id = ?");
$check->bind_param("ii", $messageId, $userId);
$check->execute();
$result = $check->get_result();
if ($result && $result->num_rows > 0) {
// Soft delete (mark as deleted)
$delete = $conn->prepare("UPDATE messages SET deleted = 1 WHERE id = ?");
$delete->bind_param("i", $messageId);
$delete->execute();
}
}
header("Location: chat.php"); // Replace with your actual chat page
exit;
<?php
require 'db.php';
$response = ['typing' => false];
if (isset($_SESSION['user_id']) && isset($_SESSION['typing_status']) && $_SESSION['typing_status']) {
$response['typing'] = true;
}
echo json_encode($response);
?>
<?php
require 'config.php';
if (isset($_SESSION['user_id'])) {
$user_id = $_SESSION['user_id'];
$is_typing = isset($_POST['typing']) && $_POST['typing'] == 1 ? 1 : 0;
$stmt = $conn->prepare("UPDATE users SET is_typing = ?, last_typed_at = NOW() WHERE id = ?");
$stmt = $conn->prepare("UPDATE users SET is_typing = ? WHERE id = ?");
$stmt->bind_param("ii", $is_typing, $user_id);
$stmt->execute();
}
?>
CREATE TABLE `messages` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`message` text NOT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`deleted` tinyint(1) DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
`is_typing` tinyint(1) DEFAULT 0,
`last_typed_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
ALTER TABLE `messages`
ADD PRIMARY KEY (`id`),
ADD KEY `user_id` (`user_id`);
ALTER TABLE `users`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `username` (`username`);
ALTER TABLE `messages`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `users`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `messages`
ADD CONSTRAINT `messages_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
COMMIT;<?php
$host = "localhost";
$user = "root";
$pass = "";
$dbname = "chat_app";
$conn = new mysqli($host, $user, $pass, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
session_start();
?>
/* General */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #f2f2f2;
padding: 20px;
margin: 0;
}
h3 {
margin-bottom: 20px;
color: #333;
}
/* Chat container */
#chat-box {
background: #fff;
border: 1px solid #ccc;
border-radius: 10px;
padding: 15px;
height: 300px;
overflow-y: scroll;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
/* Chat message style */
#chat-box p {
background: #e9f0fa;
border-radius: 8px;
padding: 10px;
margin: 10px 0;
max-width: 75%;
position: relative;
clear: both;
}
#chat-box p strong {
color: #007bff;
display: block;
margin-bottom: 5px;
}
#chat-box p:nth-child(even) {
background: #dfe8f1;
margin-left: auto;
}
/* Typing indicator */
#typing-indicator {
font-style: italic;
color: #777;
padding: 5px 0;
margin-top: 10px;
animation: blink 1s infinite;
}
@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
/* Form styling */
form {
margin-top: 15px;
display: flex;
flex-direction: row;
gap: 10px;
}
#message {
flex: 1;
padding: 10px;
border: 1px solid #ccc;
border-radius: 20px;
outline: none;
font-size: 14px;
background-color: #fff;
}
button {
padding: 10px 20px;
background-color: #007bff;
border: none;
color: #fff;
font-weight: bold;
border-radius: 20px;
cursor: pointer;
transition: background 0.3s ease;
}
button:hover {
background-color: #0056b3;
}
/* Auth forms */
input[type="text"],
input[type="password"] {
padding: 10px;
width: 250px;
margin-bottom: 10px;
border: 1px solid #bbb;
border-radius: 5px;
}
.auth-form {
background-color: #fff;
padding: 20px;
margin: 30px auto;
max-width: 400px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.auth-form h2 {
text-align: center;
color: #333;
}
/* style.css */
.message-container {
font-family: Arial, sans-serif;
margin-bottom: 15px;
padding: 10px;
background-color: #f9f9f9;
border-radius: 5px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.message-container p {
margin: 0;
}
.message-author {
font-weight: bold;
color: #333;
}
.message-body {
margin-top: 5px;
font-size: 14px;
color: #555;
}
.message-body.deleted {
font-style: italic;
color: #888;
}
.message-time {
font-size: 12px;
color: #999;
}
.btn-danger {
background-color: #d9534f;
border: none;
color: white;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
font-size: 12px;
}
.btn-danger:hover {
background-color: #c9302c;
}
.typing-indicator {
font-style: italic;
color: #aaa;
margin-top: 10px;
}

With just PHP, MySQL, and JavaScript, you’ve successfully built a functional real-time chat application packed with essential features. From live typing indicators to message deletion and chat history management, this project shows how powerful a well-structured PHP backend combined with AJAX and a clean UI.
A modern PHP-based domain search tool with AJAX, DNS checks, and WHOIS fallback. Get instant domain availability results and smart suggestions in a fast, elegant UI.
Learn how to build an advanced AJAX contact form with PHP that sends email without page reload. Includes modern UI design, form validation, and secure email handling using PHP's mail() function.
Learn how to remove .php, .html, and .htm extensions from URLs using .htaccess. Create clean, SEO-friendly URLs on Apache servers with our step-by-step guide.