PHP Form Required
What Is a Required Field? In simple terms: A required field is a form field the user must fill in before the form can be accepted — such as a name, an email address, or the "I accept the terms" checkb
What Is a Required Field?
In simple terms: A required field is a form field the user must fill in before the form can be accepted — such as a name, an email address, or the "I accept the terms" checkbox.
Technically: Checking a required field means verifying that the submitted value is present and not blank. What counts as "blank" depends on the field type: a text field containing only spaces, an unchecked checkbox (which is not submitted at all), a select left on its placeholder option, or a checkbox group with nothing selected.
Why Required Checks Need Care
The obvious approach — empty($_POST['name']) — has a serious flaw, and different field types behave differently when left empty. Getting this right avoids two kinds of bugs: rejecting valid input (such as the value 0) and accepting meaningless input (such as a name made only of spaces).
What Browsers Send for Empty Fields
| Field | User Leaves It Empty | What PHP Receives |
|---|---|---|
| Text, email, textarea | Empty box | '' (empty string) |
| Text with only spaces | " " | ' ' (not empty!) |
| Checkbox | Unchecked | Key missing from $_POST |
| Radio group | Nothing selected | Key missing |
| Select | Placeholder option chosen | The placeholder's value, usually '' |
Multiple select / checkbox group (name[]) | Nothing selected | Key missing |
| File input | No file chosen | $_FILES[...]['error'] === UPLOAD_ERR_NO_FILE |
A complete required check must handle missing keys, whitespace-only strings, and arrays.
Why empty() Is the Wrong Tool
empty($x) is true for missing values and for every falsy value, including the string '0':
<?php
$submissions = [
'missing' => null,
'empty string' => '',
'only spaces' => ' ',
'zero' => '0',
'name' => 'Asha',
];
foreach ($submissions as $label => $value) {
printf("%-13s empty(): %-5s trim check: %s\n",
$label,
var_export(empty($value), true),
var_export($value === null || trim($value) === '', true)
);
}
Output
missing empty(): true trim check: true
empty string empty(): true trim check: true
only spaces empty(): false trim check: true
zero empty(): true trim check: false
name empty(): false trim check: false
empty() gets two cases wrong:
'0'counts as empty, so a user whose answer is "0" (number of children, apartment floor, a quantity) is told the field is required.' 'counts as filled, so a name consisting only of spaces is accepted.
The trim check treats exactly the right values as blank.
A Reliable Required Check
<?php
function isFilled(mixed $value): bool
{
if (is_array($value)) {
return $value !== [];
}
return is_string($value) && trim($value) !== '';
}
$tests = [
'missing' => null,
'empty string' => '',
'only spaces' => ' ',
'zero' => '0',
'text' => 'Asha',
'empty array' => [],
'checked items' => ['php'],
];
foreach ($tests as $label => $value) {
echo str_pad($label, 14) . (isFilled($value) ? 'filled' : 'blank') . "\n";
}
Output
missing blank
empty string blank
only spaces blank
zero filled
text filled
empty array blank
checked items filled
- Strings are trimmed before checking, so whitespace-only input is blank and
'0'is filled. - Arrays (from
name[]fields) are filled when at least one item was selected. - Anything else —
nullfor a missing key, or an unexpected type — is blank.
Use it as isFilled($_POST['name'] ?? null).
Required Checkboxes, Radios, and Selects
"Accept the Terms" Checkbox
<label><input type="checkbox" name="terms" value="yes"> I accept the terms</label>
$acceptedTerms = ($_POST['terms'] ?? null) === 'yes';
An unchecked checkbox is not sent, so ?? null provides the default. Comparing with the exact expected value rejects anything else.
Required Radio Group
<label><input type="radio" name="plan" value="free"> Free</label>
<label><input type="radio" name="plan" value="pro"> Pro</label>
$plan = $_POST['plan'] ?? null;
$planIsValid = in_array($plan, ['free', 'pro'], true);
A required radio group is valid only when one of the allowed values is present. This one check covers both "nothing selected" and "a manipulated value".
Required Select With a Placeholder
<select name="city">
<option value="">-- Choose a city --</option>
<option value="MAA">Chennai</option>
<option value="IXM">Madurai</option>
</select>
The placeholder has an empty value, so the required check is again an allow-list check: the submitted value must be one of the real options (MAA, IXM). See Checkbox, Radio and Select Inputs.
Conditionally Required Fields
Some fields are required only in certain situations — for example, a company name and GSTIN for business accounts:
<?php
function isFilled(mixed $value): bool
{
return is_array($value) ? $value !== [] : is_string($value) && trim($value) !== '';
}
function checkRequired(array $input): array
{
$errors = [];
if (!isFilled($input['name'] ?? null)) {
$errors['name'] = 'Please enter your name.';
}
$accountType = $input['account_type'] ?? null;
if (!in_array($accountType, ['personal', 'business'], true)) {
$errors['account_type'] = 'Choose an account type.';
}
if ($accountType === 'business') {
if (!isFilled($input['company'] ?? null)) {
$errors['company'] = 'Company name is required for business accounts.';
}
if (!isFilled($input['gstin'] ?? null)) {
$errors['gstin'] = 'GSTIN is required for business accounts.';
}
}
if (($input['terms'] ?? null) !== 'yes') {
$errors['terms'] = 'You must accept the terms.';
}
return $errors;
}
print_r(checkRequired(['name' => 'Asha', 'account_type' => 'personal', 'terms' => 'yes']));
print_r(checkRequired(['name' => ' ', 'account_type' => 'business', 'company' => '']));
Output
Array
(
)
Array
(
[name] => Please enter your name.
[company] => Company name is required for business accounts.
[gstin] => GSTIN is required for business accounts.
[terms] => You must accept the terms.
)
How It Works
- The personal account passes: company and GSTIN are not checked because they are not required for personal accounts.
- For the business account, the whitespace-only name, the empty company, the missing GSTIN, and the missing terms checkbox are all reported together.
- The account type itself is required and restricted to allowed values in one check.
On the HTML side, JavaScript can show or hide the business fields, but the server must still decide what is required based on the submitted account type.
Marking Required Fields in HTML
<?php
$errors = ['name' => 'Please enter your name.'];
$name = '';
?>
<label for="name">Name <span aria-hidden="true">*</span></label>
<input id="name" name="name" required
value="<?= htmlspecialchars($name) ?>"
<?= isset($errors['name']) ? 'aria-invalid="true" aria-describedby="name-error"' : '' ?>>
<?php if (isset($errors['name'])): ?>
<p id="name-error" class="error"><?= htmlspecialchars($errors['name']) ?></p>
<?php endif; ?>
Output (HTML)
<label for="name">Name <span aria-hidden="true">*</span></label>
<input id="name" name="name" required
value=""
aria-invalid="true" aria-describedby="name-error">
<p id="name-error" class="error">Please enter your name.</p>
- The
requiredattribute gives users immediate feedback in the browser. - An asterisk marks required fields visually;
aria-hiddenstops screen readers from announcing it, becauserequiredalready conveys the information. aria-invalidandaria-describedbyconnect the error message to the field for assistive technologies.
Common Mistakes
Using empty() for Required Checks
Effect: '0' is rejected, and whitespace-only input is accepted.
Fix: Trim strings and compare with ''.
Forgetting That Unchecked Fields Are Missing
Effect: "Undefined array key" warnings.
Fix: Use ?? null for checkboxes, radios, and multi-selects.
Accepting Any Non-Empty Value for Choices
Effect: Manipulated values pass the required check.
Fix: Required choices must be in an allow-list.
Relying Only on the required Attribute
Effect: Direct requests bypass it.
Fix: Repeat every required check on the server.
Showing Only the First Missing Field
Effect: Users must submit several times.
Fix: Collect and display all errors at once.
Best Practices
- Treat missing keys, empty strings, and whitespace-only strings as blank; treat
'0'as filled. - Check required choices with allow-lists.
- Handle conditionally required fields on the server based on submitted values.
- Mark required fields clearly and connect error messages to fields accessibly.
- Use the
requiredattribute for convenience, never as the only check.
Official reference: https://www.php.net/manual/en/function.empty.php