服务器与大带宽专家 · 持牌IDC/CDN/ISP服务商
简米科技官网JIANMI TECH
资讯 2026-10-21 简米科技 5,645 字 14 分钟阅读

PHP如何获取本地域名完整路径?php怎么获取域名路径代码

导读PHP获取本地域名与完整路径,本质就是读$_SERVER:协议看HTTPS或HTTP_X_FORWARDED_PROTO,域名看HTTP_HOST(自带端口)或SERVER_NAME(不带端口),路径看REQUEST_URI和DOCUMENT_ROOT,把这几段拼起来就是完整URL,php获取当前域名和完整的u……

PHP获取本地域名与完整路径,本质就是读$_SERVER:协议看HTTPS或HTTP_X_FORWARDED_PROTO,域名看HTTP_HOST(自带端口)或SERVER_NAME(不带端口),路径看REQUEST_URI和DOCUMENT_ROOT,把这几段拼起来就是完整URL。

php获取当前域名和完整的url方法

在PHP里拿域名,绕不开超全局数组$_SERVER,它由Web服务器(Apache、Nginx、Caddy)在转发请求时填充,所以不同环境下字段的完整度并不一样,理解每个字段的来源,比记住一段拼接代码更重要。

三个关键变量分别负责什么

  • $_SERVER['HTTP_HOST']:来自请求头Host,格式是域名:端口,例如shop.test:8080,它反映用户浏览器实际访问的地址。
  • $_SERVER['SERVER_NAME']:来自服务器配置文件里的ServerName指令,通常只有域名,没有端口,虚拟主机多站点场景下,它可能和用户访问的域名不一致。
  • $_SERVER['REQUEST_URI']:浏览器请求的路径加查询串,例如/index.php?id=3,不含域名。

据PHP官方文档说明,$_SERVER中的值由Web服务器提供,不能保证在所有服务器上都存在,所以取用前必须做存在性判断。

拼接完整URL的通用写法

<?php
function currentUrl(): string
{
    // 1. 判断协议,兼容反向代理
    $https = $_SERVER['HTTPS'] ?? '';
    $proto = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '';
    $scheme = ($https === 'on' || $https === '1' || $proto === 'https') ? 'https' : 'http';
    // 2. 取主机,优先 Host 头
    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
    // 3. 取路径
    $uri = $_SERVER['REQUEST_URI'] ?? '/';
    return $scheme . '://' . $host . $uri;
}
echo currentUrl(); // 输出 https://shop.test:8080/index.php?id=3

这段代码有两个细节:一是HTTP_HOST自带端口,拼接时不要再手工加和端口号,否则会出现8080:8080;二是$_SERVER['HTTPS']在部分服务器上会被设为off而不是空值,所以判断时用严格比较更稳。

只想要域名,不要路径

$host = $_SERVER['HTTP_HOST'] ?? 'localhost';           // 带端口
$domain = explode(':', $host)[0];                        // 去掉端口
$domain = preg_replace('/^www\./i', '', $domain);        // 去掉 www

在需要写Cookie作用域、生成邮件链接、做跨域白名单时,通常只需要裸域名。parse_url()也可以,但传给它的是完整URL,多一步拼接,不如直接处理HTTP_HOST来得直接。

php获取本地域名和项目路径的区别

初学者常把这两个概念混在一起,写出来的代码在本地能跑,上服务器就报错,业内共识认为,域名属于"访问层",路径属于"文件层",它们来自不同的数据源,不能互相推导。

域名是浏览器地址栏里的东西

本地开发时,这个"域名"可能是三种形态:

  • localhost或0.0.1,配合php -S localhost:8000或XAMPP默认端口;
  • 配置了虚拟主机的自定义后缀,比如phpstudy里的shop.test、Laragon里的app.test;
  • Docker环境下的容器服务名,如web、php-fpm,从宿主机访问时又变成localhost:映射端口。

这三种情况下HTTP_HOST都能正确反映用户访问入口,但SERVER_NAME未必跟着变,尤其在Docker里,容器内SERVER_NAME可能还是localhost。

路径是文件在磁盘上的位置

获取项目根目录,常用三种方式,差异明显:

写法 适用场景
__DIR__ 当前文件所在目录的绝对路径 引入配置、类文件,最稳定
$_SERVER['DOCUMENT_ROOT'] 站点根目录 需要拼静态资源物理路径
getcwd() 进程当前工作目录 CLI脚本,会被chdir()改变

__DIR__是编译期常量,不受运行目录影响,写require __DIR__ . '/config.php'几乎不会出错,而DOCUMENT_ROOT在Nginx+PHP-FPM下有时会是空值,取用前要加判断。

URL路径要用另一套变量

想要网站根URL,用$_SERVER['SCRIPT_NAME']去掉文件名部分:

$basePath = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])), '/');
// 子目录部署返回 /shop,根目录部署返回空字符串

这一步在项目部署到/shop这类子目录时特别关键,否则生成的静态资源链接会全部404。

本地开发环境php获取域名端口失败怎么办

这是高频场景:命令行跑脚本,$_SERVER['HTTP_HOST']压根不存在,直接报"未定义索引"警告,PHP 7.0以后可以用做兜底,但更重要的是给一个合理默认值。

先判断当前运行模式

function baseUrl(): string
{
    if (PHP_SAPI === 'cli') {
        return 'http://localhost';   // CLI 下没有域名概念
    }
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
    return $scheme . '://' . $host;
}

PHP_SAPI能直接区分cli、fpm-fcgi、apache2handler,比猜测某个$_SERVER键是否存在更可靠。

Docker 与端口映射的坑

容器内HTTP_HOST是localhost:80,宿主机映射到8080,用户实际访问的是localhost:8080,如果代码用HTTP_HOST生成回调地址,就会漏掉映射端口,解决办法是在docker-compose.yml里给容器加环境变量,比如APP_URL=http://localhost:8080,代码优先读它,读不到再走$_SERVER兜底,这套写法不依赖任何付费组件,纯原生PHP即可实现,适合预算有限的小型内网项目参考。

反向代理下拿到的是内网地址

在华东、华北不少机房的Nginx反向代理后面,PHP-FPM收到的REMOTE_ADDR是代理机内网IP,协议也常显示为http,这时要读代理透传的头:

$realIp = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
$protocol = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? 'http';

前提是代理层确实配置了这两条头,否则读到的是空值,据工信部相关机房建设规范提及的分层架构,七层代理透传已是常规做法,但具体头字段名由运维配置决定,需要和部署方确认。

安全与兼容:几个容易忽略的细节

第一,HTTP_HOST来自客户端请求头,可以被伪造,把它直接拼进邮件链接或写进日志,存在被注入恶意域名的风险,输出前用preg_match('/^[a-zA-Z0-9\.\-]+(:\d+)?$/', $host)过滤一次,成本极低。

第二,做重定向跳转时,优先使用配置文件里的固定域名,而不是动态读取,业内专家指出,开放重定向漏洞中有相当一部分源于动态拼接主机名。

第三,Windows开发机下__DIR__返回反斜杠,拼接URL前必须str_replace('\\', '/', ...),否则http://localhostC:\www这类畸形地址会直接暴露在页面上。

第四,$_SERVER['SERVER_PORT']能拿到端口,但反向代理下返回的是容器端口,不如直接信任HTTP_HOST里携带的端口。

一套可复用的封装

class UrlHelper
{
    public static function host(): string
    {
        $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
        return preg_match('/^[a-zA-Z0-9\.\-]+(:\d+)?$/', $host) ? $host : 'localhost';
    }
    public static function baseUrl(): string
    {
        $https = $_SERVER['HTTPS'] ?? '';
        $proto = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '';
        $scheme = ($https === 'on' || $https === '1' || $proto === 'https') ? 'https' : 'http';
        return $scheme . '://' . self::host();
    }
    public static function root(): string
    {
        return dirname(__DIR__);   // 按实际层级调整
    }
}

调用UrlHelper::baseUrl()拿到https://shop.test:8080,UrlHelper::root()拿到项目绝对路径,两个需求一次覆盖。

PHP获取域名靠请求头变量,获取路径靠魔术常量和服务器变量,两者分开处理,再各自加兜底和过滤,代码才能在本地、测试、生产三种环境里稳定运行。

PHP获取域名与完整路径常见问答

Q1:HTTP_HOST 和 SERVER_NAME 到底该用哪个?

生成访问链接用HTTP_HOST,它带端口、跟随用户实际访问入口,更符合预期,做日志标记或服务器内部判断用SERVER_NAME,它不受请求头篡改影响,两者都不存在时统一回退到localhost。

Q2:本地用 localhost 访问,生成的回调地址也是 localhost,怎么在测试环境改成真实域名?

在项目配置里定义APP_URL常量,通过.env文件区分环境,代码里优先读配置,读不到再走$_SERVER兜底,这样本地是http://localhost:8000,测试环境是https://test.example.com,同一份代码不用改。

Q3:获取到的域名是内网IP而不是域名,问题出在哪?

多数情况是请求没有经过带Host头的七层代理,或者代理未透传X-Forwarded-Host,检查Nginx配置里是否写了proxy_set_header Host $host;,缺少这一行时,PHP-FPM收到的HTTP_HOST就是上游地址。

分享本文
本文为 简米科技官网 原创,已由运维技术专家审核。转载请注明来源:原文链接
售前咨询 服务热线 售后 邮箱