PHP 入门可以从处理一份报名数据开始:读取字段,验证类型和范围,再把结果安全地显示出来。你可能已经学会变量赋值,却一接表单就不知道该相信哪个值。浏览器发来的数据不是已经整理好的业务对象,缺字段、空字符串和意外数组都可能出现。

本文用一个报名处理函数串起变量、关联数组和表单校验,再提供命令行自测与网页入口。示例面向 PHP 8.x,先在本地练习目录运行,不连接数据库。页面只返回确认结果,没有保存报名记录,也没有实现真实业务中的身份认证与重复提交处理。
一、先定义一份报名数据应该是什么
本例需要姓名和年龄两个字段。姓名必须是非空字符串,去掉首尾空白后最多九十个字节;年龄必须是十六到六十五之间的整数形式字符串。这里的长度按字节计算,中文字符通常占多个字节,因此它不是“最多九十个汉字”。
关联数组像带字段名称的表格行:name 对应姓名,age 对应年龄。读取不存在的键时要考虑缺省情况,但缺省值只能帮助程序继续判断,不能直接替用户做出业务决定。例如年龄缺失时,不应默认设成十八岁并接受报名。
可以从 PHP 教程 补充变量与数组基础。理解超全局变量之后,再使用 $_POST;它提供请求数据的入口,不代表数据已经可信。
二、把校验写成独立函数
新建 registration.php。先检查字段是不是字符串,再调用 trim 和过滤函数,避免请求把字段构造成数组时引发类型错误。
<?php
declare(strict_types=1);
function register(array $data): array {
$name = $data['name'] ?? null;
$ageText = $data['age'] ?? null;
if (!is_string($name) || !is_string($ageText)) {
throw new InvalidArgumentException('姓名和年龄必须是文本字段');
}
$name = trim($name);
if ($name === '' || strlen($name) > 90) {
throw new InvalidArgumentException('姓名为空或长度超出限制');
}
$age = filter_var($ageText, FILTER_VALIDATE_INT, [
'options' => ['min_range' => 16, 'max_range' => 65]
]);
if ($age === false) {
throw new InvalidArgumentException('年龄必须是16到65之间的整数');
}
return ['name' => $name, 'age' => $age];
}
成功返回时,姓名是处理过的字符串,年龄是整数;失败时抛出明确异常。把这层逻辑独立出来,命令行和网页请求就可以复用同一套规则,不会出现两套年龄范围互相冲突。
filter_var 校验失败返回 false,因此用严格比较判断。不要用“如果没有值就默认一”这样的简写覆盖错误。另一个常见误解是先转整数再验证:某些不完整数字文本经过强制转换后会变成一个数字,原始格式错误就丢失了。
三、先在命令行验证数组输入
新建 test_registration.php,与函数文件放在同一目录。用 php test_registration.php 运行,成功时打印完成信息,失败则抛异常并使程序退出。
<?php
declare(strict_types=1);
require __DIR__ . '/registration.php';
$valid = register(['name' => ' 编程狮练习 ', 'age' => '18']);
if ($valid !== ['name' => '编程狮练习', 'age' => 18]) {
throw new RuntimeException('正常输入结果不符');
}
$cases = [
['name' => '', 'age' => '18'],
['name' => '学员', 'age' => '15'],
['name' => '学员', 'age' => '66'],
['name' => '学员', 'age' => '18abc'],
['name' => ['学员'], 'age' => '18'],
['name' => '学员']
];
foreach ($cases as $case) {
$rejected = false;
try { register($case); }
catch (InvalidArgumentException $error) { $rejected = true; }
if (!$rejected) throw new RuntimeException('非法输入未被拒绝');
}
echo "正常输入与6组非法输入检查通过\n";
这组测试特意包括边界外年龄、含字母的数字文本和数组姓名。它验证的是用户可能提交的具体形状,不是只测试函数能否被调用一次。还应自己补十六和六十五两个端点,确认允许范围确实包含它们。
常用数组与类型判断可对照 PHP 速查手册。注意本测试不用 assert 作为唯一失败判据,而是明确抛出异常,避免运行配置导致断言未执行。
四、再接上表单,区分校验与输出转义
新建 index.php。浏览器端的 required、min 和 max 是操作提示;服务端仍调用 register 进行真实校验。返回结果使用 htmlspecialchars 进入 HTML 文本位置,避免姓名被解释为标签。
<?php
declare(strict_types=1);
require __DIR__ . '/registration.php';
$message = '';
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
try {
$record = register($_POST);
$message = '已校验:' . $record['name'] . ',年龄 ' . $record['age'];
} catch (InvalidArgumentException $error) {
http_response_code(422);
$message = $error->getMessage();
}
}
?>
<!doctype html>
<html lang="zh-CN">
<meta charset="utf-8">
<title>编程狮 PHP 表单练习</title>
<form method="post">
<label>姓名 <input name="name" required></label>
<label>年龄 <input name="age" type="number" min="16" max="65" required></label>
<button type="submit">校验资料</button>
</form>
<p><?= htmlspecialchars($message, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') ?></p>
</html>
在练习目录启动 php -S 127.0.0.1:8080,然后访问本机八零八零端口。PHP 内置服务用于本地开发验证,不应按这个命令直接搭建公网正式站点。
校验和转义承担不同职责。校验判断数据是否符合业务;转义保证数据在特定输出位置被当作文字。姓名通过非空检查,不意味着它适合原样写入 HTML。相反,转义过的年龄字符串也不代表年龄合法。
| 输入或动作 | 应有结果 | 对应责任 |
|---|---|---|
| 正常姓名、十八岁 | 显示校验结果 | 业务处理 |
| 缺少年龄 | 返回字段错误 | 服务端校验 |
| 姓名含尖括号 | 按文字显示 | HTML 输出转义 |
| 想真正保存报名 | 需要另写存储流程 | 当前示例范围外 |
如果下一步接数据库,应使用参数化查询,而不是把转义后的 HTML 字符串拼进 SQL。不同输出上下文有不同规则,htmlspecialchars 不是万能安全函数。异常页面也不应向用户展示数据库口令或本地文件路径。

总结
网页入口用 __DIR__ 定位函数文件,是为了避免启动服务器的位置改变后,相对路径指向另一处。同样,命令行测试直接传数组,能把业务校验与请求解析分开。命令行通过而网页失败时,应检查请求方法和字段名称;两边都失败时,再回到校验函数和用例本身定位。
本例对空姓名拒绝,但没有实现“真实姓名识别”。产品是否允许昵称、连字符或其他字符,应由需求决定。也不要为了过滤尖括号直接删掉所有特殊字符:输入内容是否合法与它怎样进入页面,是两套规则。业务层保留需要的信息,展示层按上下文处理,才不会一边修安全问题一边损坏正常数据。
PHP 入门的这三个知识点可以组成完整链路:变量读取字段,关联数组组织数据,校验函数把不确定输入变成明确结果。网页入口负责请求和展示,业务函数负责规则,两者分开后更容易测试。
你可以先增加一个学习方向字段,规定允许值集合,再给正常值与未知值各写一个测试。等规则稳定后再考虑数据库保存、身份认证和防重复提交。不要因为页面出现“校验成功”,就把它描述成一个已经能接受真实报名的系统。
延伸学习
- PHP 数组遍历实践 可作为理解数组逐项处理的补充资料。
- PHP 零基础入门课程 适合继续练习语法与页面交互。
- PHP 异常处理说明 可帮助区分业务拒绝与程序故障。
常见问题
Q:浏览器已经限制年龄,服务端为什么还检查?
因为请求可以不经过这个表单发出。浏览器限制帮助正常用户减少误填,服务端检查负责验证实际收到的数据,两者不能互相替代。
Q:strlen 为什么不是按汉字个数计数?
它统计字节长度,UTF-8 字符可能占多个字节。如果产品要求按字符数量限制,应选择相应多字节函数并确认扩展可用。
Q:转义应该在保存前还是展示前做?
通常应根据输出位置在展示时处理。存储层保留适当验证后的业务值,避免同一份数据在不同展示上下文中被重复转义或错误解释。
技术依据:PHP htmlspecialchars 文档。

免费 AI IDE



