PHP中获取完整URL:快速且无错误的方法

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

如何在PHP中获取完整URL而不抓狂?

\n\n

每位PHP开发者都曾遇到过这样的任务:“如何获取当前页面的完整URL?”看似简单——只需取$_SERVER['HTTP_HOST'],加上$_SERVER['REQUEST_URI']就完成了。但现实总是充满变数。HTTP还是HTTPS?如果端口不标准怎么办?如果网站位于代理之后呢?如果不仅要获取,还要快速、无内存泄漏且具备未来扩展性呢?

\n\n

关于“Get the full URL in PHP”的问题在Stack Overflow上已有数千次浏览和数十个回答。这并非偶然:主题看似简单,但陷阱之多如同春天的水坑。今天,我们不仅要讨论“如何做”,更要探讨如何正确、快速且可靠地完成。开始吧!

\n\n

为什么简单地从$_SERVER复制是邪恶的?

\n\n

初学者经常这样写:

\n\n
$url = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
\n\n

乍一看,似乎可行。但让我们看看问题所在:

\n
    \n
  • 缺少HTTPS。如果网站通过HTTPS运行,你会得到http://——浏览器会因混合内容而报错。
  • \n
  • 端口。如果端口不标准(例如8080),除非使用$_SERVER['SERVER_PORT'],否则端口会丢失。
  • \n
  • 代理和负载均衡器。在反向代理(Nginx、Cloudflare)后面,$_SERVER['HTTP_HOST']可能不是用户实际看到的。
  • \n
  • 安全性。HTTP_HOST的值可能被攻击者篡改(Host header注入)。
  • \n
\n\n

简而言之,从Stack Overflow的第一个答案复制粘贴并非最佳选择。让我们编写一个正确且高性能的函数。

\n\n

标准函数:正确获取完整URL

\n\n

这是一个可靠的函数,考虑了所有主要场景:

\n\n
function getFullUrl(): string {\n    $protocol = 'http';\n    if (\n        (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')\n        || (int)$_SERVER['SERVER_PORT'] === 443\n    ) {\n        $protocol = 'https';\n    }\n\n    // 考虑来自代理的头部(如果信任)\n    $host = $_SERVER['HTTP_HOST'] ?? '';\n    if (empty($host) && !empty($_SERVER['SERVER_NAME'])) {\n        $host = $_SERVER['SERVER_NAME'];\n    }\n\n    // 端口检查\n    $port = (int)$_SERVER['SERVER_PORT'];\n    $portSuffix = '';\n    if (\n        ($protocol === 'http' && $port !== 80)\n        || ($protocol === 'https' && $port !== 443)\n    ) {\n        $portSuffix = ':' . $port;\n    }\n\n    $uri = $_SERVER['REQUEST_URI'] ?? '/';\n\n    return $protocol . '://' . $host . $portSuffix . $uri;\n}
\n\n

这里有什么重要的?

\n
    \n
  • 检查HTTPS——标准方法,在99%的情况下有效。
  • \n
  • 考虑SERVER_PORT——如果网站使用非标准端口,不会丢失。
  • \n
  • 通过SERVER_NAME提供备用方案——以防HTTP_HOST为空。
  • \n
  • 不使用$_SERVER['SCRIPT_URI']——因为它并非处处存在。
  • \n
\n\n

性能优化:当每一毫秒都至关重要时

\n\n

如果你在每个页面或循环中调用此函数,应考虑速度。以下是一些技巧:

\n\n

1. 缓存结果

\n

如果URL在单个请求中不变(实际上不会变),请缓存:

\n\n
function getFullUrlCached(): string {\n    static $url = null;\n    if ($url === null) {\n        $url = getFullUrl(); // 使用我们上面的函数\n    }\n    return $url;\n}
\n\n

静态变量在首次调用后保留值——无需重复计算。

\n\n

2. 避免不必要的操作

\n

不要使用filt

博客

书籍推荐