HOWTO · PHP

在 PHP 中获取当前完整的 URL

本教程介绍了如何在 PHP 中获取当前的 URL。

本页内容

要查看或构造当前 PHP 请求的 URL,请组合请求的协议、主机和 URI。这适用于根据查询参数呈现页面或记录请求地址。构造出的 URL 只是数据;将其用于重定向时,仍须单独判断哪些目标地址是允许的。

根据请求数据构造当前 URL

PHP 不会提供一个始终代表完整当前 URL 的单一 $_SERVER 值。服务器会提供各项请求信息,应用程序再组合所需部分。对于常见的网页请求,协议为 http 或 https,主机可能包含端口,而请求 URI 包含路径和查询字符串。

从 $_SERVER 读取协议、主机和请求 URI

$_SERVER 是由网页服务器和运行环境填充的超全局数组。$_SERVER['HTTP_HOST'] 提供请求中的主机,而 $_SERVER['REQUEST_URI'] 通常提供路径和查询字符串。两者单独都不是完整的 URL。主机值源自传入的请求,因此应将其视为不可信输入:在将它用于安全敏感的输出(例如重定向或电子邮件中的绝对链接)之前,应先根据已知主机列表进行验证。

处理 HTTPS 和代理环境中的请求

当 PHP 直接通过 TLS 收到请求时,$_SERVER['HTTPS'] 通常会设置为 on 等非空值。选择协议前请检查该值;不要假设所有服务器的设置方式都相同。$_SERVER['REQUEST_SCHEME'] 也可能可用,但它是否存在以及具体含义取决于服务器配置。

在反向代理部署中,浏览器可能通过 HTTPS 连接,而代理通过 HTTP 连接到 PHP。在这种情况下,直接 HTTPS 值可能只反映代理与 PHP 之间的连接。只有当应用程序位于经过明确配置的可信代理之后,并且该代理会移除或替换客户端提供的同名副本时,转发的协议标头才可能有用。不要信任任意请求中的转发标头。应在代理和应用程序层配置这种信任,或者使用服务器能够可靠提供的协议。

包含路径和查询字符串

$_SERVER['REQUEST_URI'] 通常包含类似 /products.php?category=books&page=2 的值;将其附加到 URL 后,可以保留路径和查询字符串。它不包含协议或主机。查询字符串可能包含私人或敏感值,因此请考虑是否应将其写入日志、输出到页面或放入电子邮件 URL 中。若未考虑应用程序的路由和部署配置,不要将请求 URI 视为规范 URL。

选择方法并验证结果

对于由网页服务器直接处理的普通请求,请明确组合服务器提供的值。以下独立示例使用有代表性的请求值,以便清楚展示组合方式。本写作阶段尚未执行此示例:

本节中的代码以及显示的标签或输出仍为英文。

<?php
$_SERVER = [
    'HTTPS' => 'on',
    'HTTP_HOST' => 'shop.example.test',
    'REQUEST_URI' => '/products.php?category=books&page=2',
];

$isHttps = isset($_SERVER['HTTPS'])
    && $_SERVER['HTTPS'] !== ''
    && strtolower((string) $_SERVER['HTTPS']) !== 'off';
$scheme = $isHttps ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'];
$requestUri = $_SERVER['REQUEST_URI'];
$currentUrl = $scheme . '://' . $host . $requestUri;

echo $currentUrl, PHP_EOL;

最终字符串由协议、主机和请求 URI 组合而成。在应用程序中,请使用实际的请求值,并确认网页服务器及任何可信代理如何填充这些值。将结果用于重定向前,请先验证主机;构造当前 URL 并不会使任意重定向目标变得安全。