使用 PHP 进行表单验证
在本文中,我们将使用 HTML 和 PHP 构建并验证一个小型 Web 表单。 表单是使用 HTML 创建的,表单内容的验证和处理是使用 PHP 完成的。 本文的目的是向您介绍一些基本的 HTML 表单元素以及如何在 PHP 脚本中访问它们的数据。
我们将创建的表单包含许多输入:文本字段、单选按钮、多选项选择列表、复选框和提交按钮。 这些输入将被验证以确保用户为每个输入提供了一个值。
如果一个或多个字段为空,表单将再次显示。 然而,这一次,空字段旁边将显示错误字符串“Missing”。 如果没有字段为空,则将以简单的方式显示提供的值。
您可以在 GitHub 上找到本文的代码。
HTML 表单
让我们创建 HTML 表单。 该表格的目的是让虚构的公司“The World of Fruit”对其客户进行水果调查。 该表单捕获三件事:
- 用户的详细信息(姓名、地址和电子邮件地址) 用户的水果消费偏好(他们每天吃的水果量,以及他们最喜欢的水果) 如果用户想要免费的小册子
文本字段
姓名、地址和电子邮件字段将使用 label
和 input
像这样的元素:
<label for="name">Name</label>
<div>
<input type="text" name="name" id="name" value="">
</div>
<label for="address">Address</label>
<div>
<input type="text" name="address" id="address" value="">
</div>
<label for="email">Email</label>
<div>
<input type="text" name="email" id="email" value="">
</div>
HTML 输入元素有几个属性。 环境 type
到 text
将它们定义为接受文本的单行输入字段。 这 name
属性用于指定字段的名称,并用于在 PHP 处理期间访问元素。 ID 属性将输入与其关联的标签相关联(通过标签的 for
属性),这使得表单更易于访问。
单选按钮
单选按钮存储用户每天吃多少水果。
<label>
<input type="radio" name="howMany" value="zero"> 0
</label>
<label>
<input type="radio" name="howMany" value="one"> 1
</label>
<label>
<input type="radio" name="howMany" value="two"> 2
</label>
<label>
<input type="radio" name="howMany" value="twoplus"> More than 2
</label>
环境 type
到 radio
将输入呈现为单选按钮。 请注意每个按钮是如何分配相同名称的。 这将单选按钮视为一个组,允许用户选择 0、1 或 2。 value
每个按钮的属性不同,以提供用户可以选择的不同值。 因为这里的输入被包装在标签中,所以 for
和 id
不需要属性。
选择列表
select 元素存储用户选择的最喜欢的水果:
<label for="favoriteFruit">My favorite fruit</label>
<div>
<select name="favoriteFruit[]" id="favoriteFruit" size="4" multiple="">
<option value="apple">Apple</option>
<option value="banana">Banana</option>
<option value="plum">Plum</option>
<option value="pomegranate">Pomegranate</option>
<option value="strawberry">Strawberry</option>
<option value="watermelon">Watermelon</option>
</select>
</div>
这 name
attribute 是一个数组(由名称后的方括号定义),因为允许多项选择(由于存在 multiple
属性)。 没有 multiple
属性,只能选择一个选项。
这 value
每个选项元素的属性是将提交给服务器的值,以及开始和结束之间的文本 option
tag 是用户将在选择菜单中看到的值。 每个 option
元素必须具有不同的值。
复选框
<label for="brochure">Would you like a brochure?</label>
<div>
<input type="checkbox" name="brochure" id="brochure" value="Yes">
</div>
复选框元素用于让用户选择是否需要小册子。 如果选中该框,其值将设置为“是”。 否则,它将有效地设置为“否”。
提交按钮
<div>
<input type="submit" name="submit" value="Submit">
</div>
最后但并非最不重要的是提交按钮。 它的价值 value
元素显示为按钮的文本。 单击它提交表单。
表单元素
<form method="POST"
action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
接下来是 form
元素。 虽然 HTML 表单支持许多属性,但只需要设置两个属性: action
和 method
. method
确定表单内容的提交方式。 action
定义提交表单时将表单内容发送到哪里。
环境 action
到 POST
表示表单的内容作为 HTTP 请求正文的一部分发送。 这些值可以通过 PHP 在 PHP 中检索 $_POST
超全球的。 替代方案 POST
是 GET
,它将表单的值作为 URL 的一部分传递。 使用 GET 发送的值可以在 PHP 中通过 $_GET
超全球的。
方法之间的主要区别 POST
和 GET
是知名度。 Web 上有很多关于在它们之间进行选择的文章,但我的建议是在使用表单时坚持使用 POST,除非您有充分的理由在可查看的 URL 中传递用户数据。
在上面的例子中, action
设置为传递值的结果 $_SERVER["PHP_SELF"]
,这是当前正在执行的脚本的名称,对 PHP 的 htmlspecialchars()
方法。 此方法用于将特定的 HTML 字符转换为其 HTML 实体名称。 例如, >
将转换为 >
.
这做了两件事:
- 如果用户提交 HTML 标记,它可以防止表单被破坏。 它是一种防止 XSS(跨站点脚本)攻击的方法,攻击者将使用它来尝试利用 Web 应用程序中的漏洞。 要了解其他常见漏洞,请查看 OWASP Top 10。
注意:在实际应用中,您可能会使用超过 htmlspecialchars
清理表单输入,例如像 laminas-filter 这样的第三方库。
使用 $_SERVER["PHP_SELF"]
如果您希望您的表单回发到生成它的同一脚本,则比简单地硬编码一个位置更可取,因为如果您更改脚本的名称,则不必更新代码。
在我们结束对表单的讨论之前,使用 HTML 表单时要记住以下三点:
- 所有的表单控件都必须包含在
form
标签。 文本和表单控件的对齐可以通过多种方式实现。 CSS 是首选,尤其是现在所有新的布局工具都可用,包括 Flexbox 和 Grid。 (请不要使用表格进行布局,因为表单元素不是表格数据!)为了额外的可访问性,值得研究 fieldset
用于对表单元素进行分组的元素。
表单处理
现在您已经在 HTML 中定义了表单,让我们研究处理表单的代码。 在我们这样做之前,请注意表单可以处于两种状态之一:
- 首次加载页面时会加载一个空白表单。 如果表单验证失败,则加载表单。 在这种状态下,用户填写的字段将包含提供的值。 其他字段将为空,旁边会显示错误消息。
验证表单内容
提交表单时,以下条目将存储在 $_POST
数组(或 $_GET
数组取决于表单的 method
属性)。 左侧列中的值取自控件的 name
属性,并且我还标记了该字段是否是用于验证目的的必填字段。
字段类型必填或可选名称单值变量必填地址单值变量必填电子邮件单值变量必填howMany单值变量必填-必须选择一个最喜欢的水果数组必填-必须选择一个小册子单值变量可选
如果用户不遵守这些规则,将显示一条错误消息。 任何已经完成的字段都将保持不变,允许用户简单地调整他们的输入并重新提交表单,而无需重新输入数据。
在继续之前,我们在本文的代码中执行的验证非常简单。 通常,您会执行更复杂的验证,例如:
- 某些字段是否不超过一定长度 电子邮件地址是否符合电子邮件地址规范 如果开始日期格式正确且在某个日期之前或之后
为此,您可能会使用第三方库,例如 laminas-validator 或 Symfony 验证组件,但是,这超出了本文的范围。
让我们看看验证表单所需的 PHP,它位于页面顶部,在表单的 HTML 之前:
<?php
$errors = [];
$fields = ['name', 'address', 'email', 'howMany', 'favoriteFruit', 'brochure'];
$optionalFields = ['brochure'];
$values = [];
if ($_SERVER["REQUEST_METHOD"] == "POST") {
foreach ($fields as $field) {
if (empty($_POST[$field]) && !in_array($field, $optionalFields)) {
$errors[] = $field;
} else {
$values[$field] = $_POST[$field];
}
}
代码初始化了三个数组:
$errors
:最初为空,这存储验证失败的表单字段$fields
:这存储了所有要处理的字段名称$optionalFields
:这存储可选的字段名称$values
: 最初为空,这是一个关联数组,将包含提供的字段及其值
之后,它检查用于提交表单的方法是否设置为 POST
. 如果是,它遍历数组中的值并检查是否 $_POST
superglobal 包含相关的字段名称。 如果是,并且该字段有值,则该字段及其值存储在 $values
大批。 但是,如果该字段为空,并且不在 $optionalFields
数组,它被添加到 $errors
大批。
在此处的示例中,我们正在检查 $_POST
数组,因为表单的方法设置为 POST
. 如果 method
被设置为 GET
,代码将更新以检查 $_GET
超全球代替。
在检查提交是否有错误之后,如果没有记录错误,代码会以一种相当基本的方式打印出用户提交的值:
if (empty($errors)) {
foreach ($fields as $field) {
if ($field === "favoriteFruit") {
printf("%s: %s<br />", $field, var_export($_POST[$field], TRUE));
} else {
printf("%s: %s<br />", $field, $_POST[$field]);
}
};
exit;
}
}
运行此代码后,将呈现页面的 HTML。 鉴于我们将使用用户提供的值再次呈现表单,我们需要稍微更新一下表单。 具体来说,需要将一些 PHP 代码合并到每个元素的 HTML 中。
对于输入字段,我们将更新它们以设置它们的值,如以下示例所示,该示例填充名称字段的值:
<input type="text"
name="name"
value="<?php echo htmlspecialchars($values['name']);?>">
htmlspecialchars()
在这里使用的原因与之前使用的原因相同 PHP_SELF
– 防止 XSS 攻击。 如果未提供值,则将在输入字段后添加以下 HTML 以显示错误消息:
<?php if (in_array('name', $errors)): ?>
<span class="error">Missing</span>
<?php endif; ?>
类的使用 error
提供使用 CSS 设置错误消息样式的钩子:
.error {
color: #FF0000;
}
扩展表单的可用性
稍加努力,您还可以记住用户从单选按钮做出的选择并选择:
<input type="radio" name="howMany"
<?php if (isset($howMany) && $howMany == "zero") echo "checked"; ?>
value="zero"> 0
<input type="radio" name="howMany"
<?php if (isset($howMany) && $howMany == "one") echo "checked"; ?>
value="one"> 1
<input type="radio" name="howMany"
<?php if (isset($howMany) && $howMany == "two") echo "checked"; ?>
value="two"> 2
<input type="radio" name="howMany"
<?php if (isset($howMany) && $howMany == "twoplus") echo "checked"; ?>
value="twoplus"> More than 2
添加了代码以检查与单选按钮关联的变量是否已在验证部分中定义。 如果是这样, checked
作为元素的 HTML 的一部分输出。
现在来解决选择菜单。 实际上,将代码重组为循环比盲目添加代码以手动检查每个选项更好。 该循环可以动态生成选项的 HTML,并且可以将选项是否已被选中的检查合并到其中:
<select name="favoriteFruit[]" size="4" multiple="">
<?php
$options = ["apple", "banana", "plum", "pomegranate", "strawberry",...