Chapter 9: Handling Forms and User Input
Introduction: A Modern Approach to Forms
Handling user input is one of the most critical responsibilities of any web application and one of the biggest security risks. In our unified application, we use a modern, AJAX-driven approach for all form submissions. Instead of a traditional page reload, the user's browser sends the form data to the server in the background. The server validates the data and returns a structured JSON response, which our client-side JavaScript then uses to either display specific field errors or show a success message.
The HTML Form Structure
The foundation of our system is a standard, semantic HTML form. The key to making it work with our system is the inclusion of specific id
and data-*
attributes that our client-side JavaScript can easily target.
<form id="contactForm" method="post" action="/contact/submit">
<h2>Contact Us</h2>
<div id="contactFormResult"></div>
<div class="form-group">
<label for="name">Your Name:</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Your Email:</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message:</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<div class="form-group">
<button type="submit" data-action="submitContactForm">Send Message</button>
</div>
</form>
There are two critical elements here: the form id (contactForm) and the button's data-action attribute (submitContactForm), which our JavaScript uses as specific hooks.
The formValidator: Our Central Validation Engine
All form submissions are first routed to a dedicated validation service before any model logic is executed. This service, implemented as a reusable fieldChecker trait, is the single gatekeeper for all incoming user data. Its job is to take the raw $_POST array and a set of rules, and produce one of two outcomes: a clean, sanitised array of validated data on success, or a JSON response detailing specific field errors on failure.
Conceptual Code PHP
<?php
// A conceptual look at how the validator is called.
$rules = [
'name' => ['required' => true, 'type' => 'string', 'maxLength' => 100],
'email' => ['required' => true, 'type' => 'email'],
'message' => ['required' => true, 'type' => 'string', 'maxLength' => 5000]
];
// The validator trait is used here.
$validatedData = $this->fieldChecker->validate($_POST, $rules);
if ($validatedData['isValid']) {
// If valid, include the processing model.
require_once 'models/xhr/contactRequest.php';
} else {
// If invalid, the fieldChecker has already sent the JSON error response.
exit();
}
The Client-Side Interaction (JavaScript)
Our JavaScript intercepts the form's submit event, sends the data to the server in the background using the fetch() API, and then intelligently handles the JSON response.
Conceptual Code
// A simplified example of the core fetch logic
document.addEventListener('click', function(event) {
const button = event.target.closest('[data-action="submitContactForm"]');
if (button) {
event.preventDefault(); // Stop the default form submission
const form = button.closest('form');
const formData = new FormData(form);
fetch(form.action, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.cmd === 'fe') { // 'fe' = field errors
// Logic to display errors next to each field
} else if (data.cmd === 'pcr') { // 'pcr' = popup, close, reset
// Logic to show a success modal and reset the form
}
});
}
});
The AJAX Processing Model
This is the final link in the chain. This script is only ever executed if the formValidator has already approved the incoming data. Its job is to take the clean data, perform the final business logic, and return a structured JSON response.
The Code (contactRequest.php)
PHP
<?php // models/xhr/contactRequest.php // The script has access to the pre-validated '$fieldValues' array. $params = "'{$fieldValues['name']}', '{$fieldValues['email']}', '{$fieldValues['message']}'"; $db->sp('contactFormInsert', $params); // Build a JSON command for the client-side JavaScript. $response = [ 'cmd' => 'pcr', 'modalContent' => '<h2>Thank You!</h2><p>Your message has been sent.</p>', 'form' => '#contactForm' ]; header('Content-Type: application/json'); echo json_encode($response);
Conclusion: A Secure and Reusable Pattern
By combining a simple HTML structure, a centralised validation engine, and a modern AJAX-driven submission process, we have created a robust and user-friendly system for handling all user input. The separation of concerns is clear: the HTML defines the fields, the JavaScript handles the client-side interaction, the formValidator ensures data integrity, and the models perform the final business logic.