<?php练功房

第 5 章 · Web 开发 · 第 5.1 课

PHP 怎么处理网页请求

约 18 分钟

到目前为止我们都在写“普通程序”。PHP 真正的主场是网站:

  1. 浏览器请求 https://example.com/hello.php?name=Tom;
  2. Web 服务器(Nginx、Caddy 等)把请求交给 PHP;
  3. PHP 执行 hello.php,把请求里的数据放进几个超全局变量;
  4. 脚本 echo 出来的内容就是返回给浏览器的网页。
变量里面装的是
$_GET网址 ? 后面的参数
$_POST表单用 POST 提交的数据
$_SERVER请求方法、路径、IP 等信息
$_COOKIE浏览器带来的 cookie
$_SESSION服务器端为这个访客保存的会话数据

练功房里没有真实的网络请求,所以下面的例子会先手动给 $_GET 赋值来模拟一次请求。

永远不要相信用户输入:XSS

用户输入的内容如果原样输出到网页里,攻击者就能塞进一段 <script>,在别人的浏览器里执行,偷走登录状态。这叫 XSS(跨站脚本攻击)。

防御方法很简单:输出到 HTML 之前一律用 htmlspecialchars() 转义,它会把 <、>、"、'、& 变成无害的 HTML 实体。运行下面的代码,再切到“网页预览”对比一下。

表单和校验

HTML 表单用 method="post" 提交时,数据会出现在 $_POST 里。服务器端必须再校验一遍(浏览器端的校验可以被绕过)。filter_var 能校验邮箱、整数、网址等常见格式。

Session:记住“你是谁”

HTTP 请求之间互相不认识。要实现“登录后一直保持登录”,PHP 用 session:session_start() 之后,往 $_SESSION 里存的东西会保存在服务器上,浏览器只拿到一个随机的会话 id(存在 cookie 里),下次请求带回来,PHP 就能找到对应的数据。

这个网站的注册登录就是这么做的。session 需要真实的浏览器请求,练功房里没法演示,看一下写法即可:

<?php
// login.php:密码校验通过后
session_start();
session_regenerate_id(true);   // 换一个新的会话 id,防止会话固定攻击
$_SESSION['user_id'] = 42;

// 其他页面
session_start();
if (!isset($_SESSION['user_id'])) {
    header('Location: /login.php');
    exit;
}
echo "欢迎回来,用户 " . $_SESSION['user_id'];

选择题

把用户输入的内容输出到网页之前,为什么要用 htmlspecialchars?

练习 1

分页参数

列表页每页显示 10 条,页码来自 $_GET['page']。算出这一页显示的是第几条到第几条,输出格式:

显示第 21 到 30 条

要考虑用户乱传的情况:没有 page 参数、page 是 0、负数或者不是数字时,都按第 1 页处理。检查时会换几种请求来测。

练习 2

转义函数

很多项目会写一个短名字的转义函数,模板里用起来方便。写函数 e(string $s): string,返回转义后的字符串,单引号和双引号都要转义。

  • e('<b>') → &lt;b&gt;
  • e('"x"') → &quot;x&quot;
  • e("It's") → It&#039;s