
Live Chat Button on Modern Computer Keyboard. (v5)
Okay, here’s a comprehensive guide on building a real-time website chat script using PHP, HTML, CSS, JavaScript, and MySQL. This outlines the core components and logic involved.
Project Structure:
We will create a basic directory structure for clarity:
root/
css/
style.css
js/
script.js
php/
db_connect.php
get_messages.php
send_message.php
login.php
logout.php
register.php
online_users.php
index.php
1. Database Setup (MySQL):
First, you’ll need a database to store user information and chat messages. Create a database (e.g., chat_db
) and the following tables:
users
table:
CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, -- Store hashed passwords last_active TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
messages
table:
CREATE TABLE messages ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, message TEXT NOT NULL, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) );
2. Database Connection (php/db_connect.php
):
This file establishes a connection to your MySQL database.
<?php $servername = "localhost"; // Or your server address $username = "your_username"; $password = "your_password"; $dbname = "chat_db"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } //Set default time zone date_default_timezone_set('UTC'); ?>
Important: Replace "your_username"
, "your_password"
, and "chat_db"
with your actual database credentials. Never hardcode sensitive information like database credentials directly into public-facing code in a production environment. Use environment variables or configuration files.
3. User Authentication (Login, Registration, Logout):
php/register.php
:
<?php require_once 'db_connect.php'; if ($_SERVER["REQUEST_METHOD"] == "POST") { $username = $_POST["username"]; $password = $_POST["password"];// Basic validation (add more robust validation) if (empty($username) || empty($password)) { echo json_encode(['status' => 'error', 'message' => 'Username and password are required.']); exit; } // Check if username already exists $check_sql = "SELECT id FROM users WHERE username = ?"; $check_stmt = $conn->prepare($check_sql); $check_stmt->bind_param("s", $username); $check_stmt->execute(); $check_stmt->store_result(); if ($check_stmt->num_rows > 0) { echo json_encode(['status' => 'error', 'message' => 'Username already exists.']); $check_stmt->close(); exit; } $check_stmt->close(); // Hash the password $hashed_password = password_hash($password, PASSWORD_DEFAULT); // Insert the user into the database $sql = "INSERT INTO users (username, password) VALUES (?, ?)"; $stmt = $conn->prepare($sql); $stmt->bind_param("ss", $username, $hashed_password); if ($stmt->execute()) { echo json_encode(['status' => 'success', 'message' => 'Registration successful.']); } else { echo json_encode(['status' => 'error', 'message' => 'Registration failed: ' . $conn->error]); } $stmt->close(); $conn->close(); } else { echo json_encode(['status' => 'error', 'message' => 'Invalid request.']); } ?>
php/login.php
:
<?php require_once 'db_connect.php'; session_start(); // Start the session if ($_SERVER["REQUEST_METHOD"] == "POST") { $username = $_POST["username"]; $password = $_POST["password"];if (empty($username) || empty($password)) { echo json_encode(['status' => 'error', 'message' => 'Username and password are required.']); exit; } $sql = "SELECT id, password FROM users WHERE username = ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("s", $username); $stmt->execute(); $stmt->store_result(); if ($stmt->num_rows == 1) { $stmt->bind_result($user_id, $hashed_password); $stmt->fetch(); if (password_verify($password, $hashed_password)) { // Password is correct $_SESSION["user_id"] = $user_id; // Store user ID in session //Update last_active timestamp $update_sql = "UPDATE users SET last_active = CURRENT_TIMESTAMP WHERE id = ?"; $update_stmt = $conn->prepare($update_sql); $update_stmt->bind_param("i", $user_id); $update_stmt->execute(); $update_stmt->close(); echo json_encode(['status' => 'success', 'message' => 'Login successful.']); } else { echo json_encode(['status' => 'error', 'message' => 'Invalid username or password.']); } } else { echo json_encode(['status' => 'error', 'message' => 'Invalid username or password.']); } $stmt->close(); $conn->close(); } else { echo json_encode(['status' => 'error', 'message' => 'Invalid request.']); } ?>
php/logout.php
:
<?php session_start(); session_unset(); session_destroy(); echo json_encode(['status' => 'success', 'message' => 'Logged out.']); exit; ?>
index.php
(HTML – Login/Registration Form):
<!DOCTYPE html> <html> <head> <title>Chat</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <div id="login-register-container"> <div id="login-form"> <h2>Login</h2> <input type="text" id="login-username" placeholder="Username"><br> <input type="password" id="login-password" placeholder="Password"><br> <button id="login-button">Login</button> <p id="login-message"></p> </div> <div id="register-form"> <h2>Register</h2> <input type="text" id="register-username" placeholder="Username"><br> <input type="password" id="register-password" placeholder="Password"><br> <button id="register-button">Register</button> <p id="register-message"></p> </div> </div> <div id="chat-container" style="display:none;"> <div id="chat-messages"></div> <input type="text" id="message-input" placeholder="Type your message..."> <button id="send-button">Send</button> <button id="logout-button">Logout</button> <div id="online-users"></div> </div> <script src="js/script.js"></script> </body> </html>
4. Chat Functionality (Sending, Retrieving, Displaying Messages):
php/send_message.php
:
<?php session_start(); require_once 'db_connect.php'; if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_SESSION["user_id"])) { $user_id = $_SESSION["user_id"]; $message = $_POST["message"];if (empty($message)) { echo json_encode(['status' => 'error', 'message' => 'Message cannot be empty.']); exit; } $sql = "INSERT INTO messages (user_id, message) VALUES (?, ?)"; $stmt = $conn->prepare($sql); $stmt->bind_param("is", $user_id, $message); if ($stmt->execute()) { echo json_encode(['status' => 'success', 'message' => 'Message sent.']); } else { echo json_encode(['status' => 'error', 'message' => 'Failed to send message: ' . $conn->error]); } $stmt->close(); $conn->close(); } else { echo json_encode(['status' => 'error', 'message' => 'Invalid request.']); } ?>
php/get_messages.php
:
<?php require_once 'db_connect.php'; $last_message_id = isset($_GET['last_message_id']) ? intval($_GET['last_message_id']) : 0; $sql = "SELECT messages.id, messages.message, messages.timestamp, users.username FROM messages INNER JOIN users ON messages.user_id = users.id WHERE messages.id > ? ORDER BY messages.timestamp ASC"; $stmt = $conn->prepare($sql); $stmt->bind_param('i', $last_message_id); $stmt->execute(); $result = $stmt->get_result(); $messages = array(); while ($row = $result->fetch_assoc()) { $messages[] = $row; } echo json_encode($messages); $stmt->close(); $conn->close(); ?>
php/online_users.php
:
<?php require_once 'db_connect.php'; // Set inactivity threshold (e.g., 5 minutes = 300 seconds) $inactivity_threshold = 300; // Calculate the timestamp for inactive users $inactive_timestamp = date('Y-m-d H:i:s', time() - $inactivity_threshold); // Query to get online users (last_active within the threshold) $sql = "SELECT id, username FROM users WHERE last_active >= ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("s", $inactive_timestamp); // Binding as string because it it's a datetime $stmt->execute(); $result = $stmt->get_result(); $online_users = array(); while ($row = $result->fetch_assoc()) { $online_users[] = $row; } echo json_encode($online_users); $stmt->close(); $conn->close(); ?>
5. JavaScript (js/script.js
): This file handles the client-side logic, including AJAX requests to your PHP scripts.
document.addEventListener('DOMContentLoaded', function() { let loginForm = document.getElementById('login-form'); let registerForm = document.getElementById('register-form'); let chatContainer = document.getElementById('chat-container'); let loginButton = document.getElementById('login-button'); let registerButton = document.getElementById('register-button'); let logoutButton = document.getElementById('logout-button'); let sendMessageButton = document.getElementById('send-button'); let loginMessage = document.getElementById('login-message'); let registerMessage = document.getElementById('register-message'); let chatMessages = document.getElementById('chat-messages'); let messageInput = document.getElementById('message-input'); let onlineUsersDiv = document.getElementById('online-users'); let lastMessageId = 0; // Keep track of the last message ID // ---- Authentication Functions ---- function login(username, password) { fetch('php/login.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `username=${username}&password=${password}` }) .then(response => response.json()) .then(data => { if (data.status === 'success') { loginForm.style.display = 'none'; registerForm.style.display = 'none'; chatContainer.style.display = 'block'; loginMessage.textContent = ''; //Start fetching messages and online users lastMessageId = 0; // Reset when logging in loadMessages(); loadOnlineUsers(); //Start periodic updates setInterval(loadMessages, 2000); // Refresh messages every 2 seconds setInterval(loadOnlineUsers, 15000); // Refresh online users every 15 seconds. } else { loginMessage.textContent = data.message; } }) .catch(error => { console.error('Login error:', error); loginMessage.textContent = 'Login failed.'; }); } function register(username, password) { fetch('php/register.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `username=${username}&password=${password}` }) .then(response => response.json()) .then(data => { registerMessage.textContent = data.message; }) .catch(error => { console.error('Registration error: ', error); registerMessage.textContent = 'Registration failed.'; }); } function logout() { fetch('php/logout.php') .then(response => response.json()) .then(data => { if (data.status === 'success') { chatContainer.style.display = 'none'; loginForm.style.display = 'block'; registerForm.style.display = 'block'; chatMessages.innerHTML = ''; // Clear messages onlineUsersDiv.innerHTML = ''; //Clear online users } }) .catch(error => console.error('Logout error:', error)); } // ---- Chat Functions ---- function sendMessage(message) { fetch('php/send_message.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `message=${message}` }) .then(response => response.json()) .then(data => { if (data.status === 'success') { messageInput.value = ''; // Clear the input //loadMessages(); //Refresh messages - No need with automatic loading } else { console.error('Send message error: ', data.message); } }) .catch(error => console.error('Send message error:', error)); } function loadMessages() { fetch(`php/get_messages.php?last_message_id=${lastMessageId}`) .then(response => response.json()) .then(data => { if (data.length > 0) { data.forEach(message => { const messageDiv = document.createElement('div'); messageDiv.classList.add('message'); messageDiv.innerHTML = `<strong>${message.username}:</strong> ${message.message} <span class="timestamp">(${message.timestamp})</span>`; // Include timestamp chatMessages.appendChild(messageDiv); lastMessageId = message.id; //Update the last ID }); // Scroll to the bottom of chat chatMessages.scrollTop = chatMessages.scrollHeight; } }) .catch(error => console.error('Load messages error:', error)); } function loadOnlineUsers() { fetch('php/online_users.php') .then(response => response.json()) .then(data => { onlineUsersDiv.innerHTML = '<h3>Online Users:</h3>'; //Clear previous list if(data.length > 0) { let userList = '<ul>'; data.forEach(user => { userList += `<li>${user.username}</li>` }); userList += '</ul>'; onlineUsersDiv.innerHTML += userList; } else { onlineUsersDiv.innerHTML += '<p>No users online.</p>'; } }) .catch(error => console.error('Load online users error: ', error)); } // ---- Event Listeners ---- loginButton.addEventListener('click', function() { login(document.getElementById('login-username').value, document.getElementById('login-password').value); }); registerButton.addEventListener('click', function() { register(document.getElementById('register-username').value, document.getElementById('register-password').value); }); logoutButton.addEventListener('click', logout); sendMessageButton.addEventListener('click', function() { sendMessage(messageInput.value); }); messageInput.addEventListener('keydown', function(event) { if (event.key === 'Enter') { sendMessage(messageInput.value); } }); });
6. CSS (css/style.css
):
Provide styling to make the chat interface visually appealing. Here’s a basic example:
body { font-family: sans-serif; margin: 0; padding: 0; background-color: #f4f4f4; } #login-register-container { width: 400px; margin: 50px auto; background-color: #fff; padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } #login-form, #register-form { margin-bottom: 20px; } h2 { text-align: center; color: #333; } input[type="text"], input[type="password"] { width: 90%; padding: 10px; margin-bottom: 10px; border: 1px solid #ddd; border-radius: 4px; } button { background-color: #5cb85c; color: white; padding: 10px 15px; border: none; border-radius: 4px; cursor: pointer; width: 100%; } button:hover { background-color: #449d44; } #chat-container { width: 600px; margin: 50px auto; background-color: #fff; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); padding: 20px; } #chat-messages { height: 300px; overflow-y: scroll; padding: 10px; border: 1px solid #ddd; margin-bottom: 10px; } #chat-messages .message { margin-bottom: 5px; padding: 5px; border-bottom: 1px solid #eee; } #chat-messages .message .timestamp { font-size: 0.8em; color: #888; margin-left: 5px; } #message-input { width: 75%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; margin-right: 10px; } #send-button, #logout-button{ width: 20%; } #online-users { margin-top: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; } #online-users ul { list-style-type: none; padding: 0; } #online-users li { margin-bottom: 5px; }
Key Considerations and Improvements:
- Security: Input sanitization and output encoding are crucial to prevent XSS vulnerabilities. Always sanitize user input before using it in database queries or displaying it on the page. Use prepared statements to prevent SQL injection.
- Password Hashing: Always use
password_hash()
to securely store passwords andpassword_verify()
to compare them. - Error Handling: Implement comprehensive error handling (try-catch blocks, logging) to catch and report unexpected issues.
- Scalability: For high-traffic applications, consider using a more scalable solution for real-time communication, such as WebSockets (e.g., using Ratchet, Swoole or similar) or a cloud-based real-time messaging service (e.g., Pusher, Ably). Polling, as used in this example, can become inefficient with many users.
- User Interface: Enhance the UI with features like typing indicators, message delivery confirmations, message editing, and user avatars.
- Message Persistence: Implement message history and retrieval when a user logs back in.
- Real-time Updates: Implement real-time updates to messages by using techniques such as long-polling or WebSockets to push updates instead of polling.
- AJAX Error Handling: The JavaScript code should include more robust error handling for AJAX requests. Display appropriate error messages to the user if a request fails.
- Input Validation: Add client-side and server-side validation for user input to prevent invalid data from being submitted.
- Session Management: Implement secure session management to prevent session hijacking. Use
session_regenerate_id()
periodically. - Code Organization: Consider using a PHP framework (e.g., Laravel, Symfony) to structure your code more effectively and take advantage of built-in features.
- Cross-Site Request Forgery (CSRF) Protection: Implement CSRF protection to prevent malicious attacks that can execute unwanted actions on behalf of an authenticated user.
- Data Sanitization: Always sanitize user input on the server-side to prevent Cross-Site Scripting (XSS) attacks. Use functions like
htmlspecialchars()
orstrip_tags()
to escape special characters.
This detailed walkthrough provides a foundation for building a real-time website chat script. Remember to adapt and expand upon it based on your specific requirements. Remember to address the “Key Considerations and Improvements” points to create a secure, efficient, and user-friendly chat application.