PHP 零基础教程

PHP $_REQUEST

$_REQUEST 是一个关联数组,默认情况下,它包含了 $_GET$_POST$_COOKIE 的所有内容。虽然它就像一个接收所有传入数据的“大杂烩”,但在你决定使用它之前,必须清楚了解它的运行机制,以及将不同来源的数据混合在一个变量中所带来的安全隐患。

1. $_REQUEST 的构成

从本质上讲,$_REQUEST 提供了一个统一的接口来获取用户输入。当请求到达你的 PHP 脚本时,PHP 引擎会根据 php.ini 配置文件中的 request_order 指令来填充 $_REQUEST。如果该指令设置为 GP(默认值),那么 $_REQUEST 将包含来自 $_GET$_POST 的数据。

2. 何时使用 $_REQUEST

$_REQUEST 最大的优势就是方便。如果你正在编写一个脚本,并且不在乎输入数据到底来自哪里——无论是来自 URL 参数 (GET) 还是表单提交 (POST)——$_REQUEST 允许你直接获取数据,而无需事先去判断请求的具体方法。

想象一个搜索功能:用户既可以在搜索栏中输入内容触发搜索 (POST),也可以通过点击带有查询参数的分享链接来触发搜索 (GET)。

// 以前你需要同时检查两个来源:
$query = $_POST['search'] ?? $_GET['search'] ?? '';

// 现在你可以直接使用:
$query = $_REQUEST['search'] ?? '';

3. 风险与冲突

$_REQUEST 能够合并数据源,这是它最强大的地方,但同时也是它最大的隐患。

3.1 数据覆盖

PHP 会按照特定的顺序合并这些数组。如果一个 URL 参数和一个表单字段使用了相同的键名(Key),那么在 request_order 配置中排在后面的数据会覆盖前面的数据。如果 request_orderGP(先 GET 后 POST),那么 $_POST 的数据将会覆盖 $_GET 的数据。如果你的应用程序逻辑非常依赖特定传输方式的数据,这可能会导致无法预料的程序行为。

3.2 安全与数据伪造

因为 $_REQUEST 可能包含 $_COOKIE 数据,你将面临意外交互的风险。攻击者可以伪造一个与表单字段同名的 Cookie,从而悄悄覆盖合法的表单数据。过度依赖 $_REQUEST 会掩盖数据的真实来源,使得实施细粒度的安全控制变得更加困难(例如通常严格绑定到 $_POST 请求的 CSRF 防御机制)。

强烈建议: 在生产环境的代码中避免使用 $_REQUEST。明确地使用 $_GET$_POST 可以让你的代码具备“自文档化”的特性,并迫使你认真思考数据传输背后的真实意图。只有当你确实需要无差别地支持多种输入来源时,才考虑使用 $_REQUEST

4. 代码实现对比

为了更清晰地展示控制力和安全性的差异,我们来看看在一个简单的登录场景下的两种不同做法。

4.1 使用明确的超全局变量(推荐做法)

这种做法意图明确且安全。它强制要求登录凭证必须来自于 POST 请求的主体。

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = $_POST['username'] ?? '';
    $password = $_POST['password'] ?? '';
    
    // 处理登录逻辑...
}

4.2 使用 $_REQUEST(安全性较低)

这种做法允许攻击者潜在地通过 URL (GET 方式) 提交登录凭证,这可能会导致这些敏感的账号密码被明文记录在 Web 服务器的访问日志或用户的浏览器历史记录中,非常不安全。

// 这种做法很容易受到意外数据源的攻击
$username = $_REQUEST['username'] ?? '';
$password = $_REQUEST['password'] ?? '';

5. 总结

$_REQUEST 是一个为了方便而设计的包装器,它将来自不同来源的输入合并到了一个地方。虽然它可以减少编写简单脚本时的重复代码,但它引入了数据来源的歧义性,增加了安全审计的复杂性,并制造了键名覆盖冲突的潜在可能。

在开发中,请优先使用 $_POST 来执行修改服务器状态或处理敏感数据的操作,使用 $_GET 来执行单纯的获取数据操作。只有当具体的传输方法对你的业务逻辑完全无关紧要时,才使用 $_REQUEST