Live stream set for 2025-11-05 at 14:00:00 Eastern
Ask questions in the live chat about any programming or lifestyle topic.
This livestream will be on YouTube or you can watch below.
PHP Validation, Santization, and Storage
Every developer knows the challenge: you need to collect user data via a form, and that data must be both valid and securely stored.
In the browser, you can use powerful HTML5 Regular Expressions for instant user feedback (If you missed that, see: HTML5 Regular Expressions).
But here is the most important truth in web security: You must never trust client-side validation.
Any user can bypass client-side checks with ease. The real defense happens on the server. This guide shows you how to build a robust PHP endpoint that handles the process, from re-validating the data to securely storing it in a MariaDB database and notifying the administrator.
1. The Goal: Strict Input Rules
We are building the PHP backend for a registration form that enforces these rules:
| Field | Client-Side Rule (HTML5 Regex) | Server-Side Enforcement (PHP) |
|---|---|---|
| Username | 4-16 lowercase letters/numbers | preg_match() |
| Password | Min 8 chars, must include upper, lower, and number | password_hash() |
2. The Database Blueprint: Creating the Users Table
Our PHP script connects to MariaDB (or MySQL) and ensures the necessary users table exists. We use CREATE TABLE IF NOT EXISTS to ensure the script works even on a fresh setup.
-- SQL executed by the PHP script to ensure the table is ready
CREATE TABLE IF NOT EXISTS users (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(16) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL, -- Long field for secure hash
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
3. The Secure PHP Backend Code (process_form.php)
This script contains the entire logic: input handling, security checks, database communication, and admin email notification. Remember to update the configuration variables (lines 3-6) before testing!
// --- 1. CONFIGURATION SECTION (CRITICAL: UPDATE THESE VALUES) ---
$servername = "localhost";
$db_username = "your_db_user"; // Your MariaDB/MySQL Username
$db_password = "your_db_password"; // Your MariaDB/MySQL Password
$dbname = "user_db"; // The name of your database (MUST EXIST)
$admin_email_recipient = "admin@yourwebsite.com"; // For new user notification
// Initialize error and success variables
$usernameError = '';
$passwordError = '';
$response = ['success' => false, 'message' => ''];
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// Retrieve and trim inputs
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
// --- 2. Validation Checks (Matching your form rules) ---
// Validate Username (4-16 lowercase letters/numbers)
if (empty($username)) {
$usernameError = "Username is required.";
} elseif (strlen($username) < 4 || strlen(trim($username)) > 16) {
$usernameError = "Username must be between 4 and 16 characters.";
} elseif (!preg_match("/^[a-z0-9]+$/", $username)) {
$usernameError = "Username must contain only lowercase letters and numbers.";
}
// Validate Password (Min 8 chars, incl. upper, lower, and number)
if (empty($password)) {
$passwordError = "Password is required.";
} elseif (strlen($password) < 8) {
$passwordError = "Password must be at least 8 characters long.";
} elseif (!preg_match("/[A-Z]/", $password) || !preg_match("/[a-z]/", $password) || !preg_match("/[0-9]/", $password)) {
$passwordError = "Password must include at least one uppercase letter, one lowercase letter, and one number.";
}
// --- 3. Database Connection and Preparation ---
if (empty($usernameError) && empty($passwordError)) {
$conn = new mysqli($servername, $db_username, $db_password, $dbname);
if ($conn->connect_error) {
$response['message'] = "â Server Error: Database connection failed. Check credentials/server.";
} else {
// **DATABASE PREP: CREATE TABLE IF NOT EXISTS**
$table_sql = "
CREATE TABLE IF NOT EXISTS users (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(16) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
if ($conn->query($table_sql) === FALSE) {
error_log("MariaDB Table Creation Error: " . $conn->error);
}
// --- 4. User Registration and Data Storage ---
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
$sql = "INSERT INTO users (username, password_hash) VALUES (?, ?)";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $username, $hashed_password);
if ($stmt->execute()) {
$response['success'] = true;
$response['message'] = " Success! User registered and stored securely.";
// --- 5. Admin Notification ---
$subject = "NEW User Registration Alert";
$message_body = "A new user has registered:\nUsername: " . $username . "\nTime: " . date("Y-m-d H:i:s");
$headers = "From: webmaster@yourdomain.com\r\n";
if (!mail($admin_email_recipient, $subject, $message_body, $headers)) {
error_log("Failed to send admin email for user: " . $username);
}
} else {
if ($conn->errno === 1062) {
$response['message'] = "â Username '{$username}' is already taken. Please choose another.";
} else {
$response['message'] = "â Database error during registration.";
error_log("MariaDB Error: " . $stmt->error);
}
}
$stmt->close();
$conn->close();
}
} else {
$errors = array_filter([$usernameError, $passwordError]);
$response['message'] = "Validation Failed: " . implode(' ', $errors);
}
} else {
$response['message'] = "Invalid request method.";
}
// Simple redirect on success or show error
if ($response['success']) {
header("Location: success_page.html");
exit();
} else {
echo "<h1>Registration Status</h1>";
echo "<p style='color: red;'>" . $response['message'] . "</p>";
}
4. Security Deep Dive: Three Critical Steps
The value of this PHP endpoint is in its security implementation, making it a professional-grade handler.
A. Reinforcing Validation with preg_match
PHP re-validates the input using preg_match() to enforce the length and character rules. This catch-all validation prevents improperly formatted data from ever reaching your database or crashing your application.
B. Password Hashing (The Non-Negotiable Step)
The line $hashed_password = password_hash($password, PASSWORD_DEFAULT); is the most important security measure here.
- NEVER store a raw password!
password_hash()converts the user’s password into an irreversible hash. If an attacker breaches your database, they only get the hash, not the actual password. - Verification: Later, when a user logs in, you use the PHP function
password_verify()to check the raw password against the stored hash.
C. Preventing SQL Injection with Prepared Statements
The mysqli::prepare() and bind_param() methods are essential. They separate the SQL command from the user-provided data (? placeholders). This guarantees that malicious code entered into the form cannot be executed against your database.
Screenshots and Screencast



Further Learning and Support
If you’re excited by the power of connecting HTML forms to a secure database, you’re ready to dive deeper into PHP.
I offer comprehensive resources to help you master these essential web development skills:
- Book: Get the foundational knowledge you need with my book, “Learning PHP” available on Amazon: https://www.amazon.com/Learning-PHP-Programming-Edward-Ojambo-ebook/dp/B0D442PR8T
- Course: Enroll in my comprehensive “Learning PHP” course today to accelerate your mastery: https://ojamboshop.com/product/learning-php
I am also available for one-on-one programming tutorials and services for updating or migrating existing PHP applications to modern, secure standards.
- Click here to get in touch for personalized help: https://ojambo.com/contact
Disclosure: Some of the links above are referral (affiliate) links. I may earn a commission if you purchase through them - at no extra cost to you.