首页 文章

PHP中的HTTP_HOST和SERVER_NAME有什么区别?

提问于
浏览
494

你什么时候考虑使用一个而不是为什么?

9 回答

  • 4

    取决于我想要找到的东西 . SERVER_NAME是服务器的主机名,而HTTP_HOST是客户端连接的虚拟主机 .

  • 2

    由于balusC表示SERVER_NAME不可靠,可以在apache配置中更改,服务器名称配置服务器和防火墙可以在您和服务器之间 .

    以下功能始终返回真实主机(用户没有端口的类型主机,它几乎可靠:

    function getRealHost(){
       list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
       return $realHost;
    }
    
  • 2

    HTTP_HOST 是从HTTP request header获得的,这是客户端实际用作请求的"target host"的内容 . SERVER_NAME 在服务器配置中定义 . 使用哪一个取决于您需要它 . 您现在应该意识到,这是一个客户端控制的值,因此在业务逻辑中可能不可靠,另一个是服务器控制的值更可靠 . 但是,您需要确保相关的Web服务器已正确配置 SERVER_NAME . 以Apache HTTPD为例,这里是its documentation的摘录:

    如果未指定ServerName,则服务器会尝试通过对IP地址执行反向查找来推断主机名 . 如果ServerName中未指定端口,则服务器将使用传入请求中的端口 . 为获得最佳可靠性和可预测性,应使用ServerName指令指定显式主机名和端口 .


    Update :在检查了包含bobince's answer链接的the answer of Pekka on your question之后,PHP将始终返回 SERVER_NAMEHTTP_HOST 的值,这与几年前我自己的PHP 4.x Apache HTTPD 1.2.x经验不符,我吹了一些灰尘来自我在Windows XP上的当前XAMPP环境(带有PHP 5.2.8的Apache HTTPD 2.2.1)启动它,创建了一个打印这两个值的PHP页面,使用URLConnection创建了一个Java测试应用程序来修改 Host Headers ,测试告诉我确实(错误地)这种情况 .

    在首先怀疑PHP并挖掘了一些有关该主题的PHP bug reports之后,我了解到问题的根源在于使用的Web服务器,当请求 SERVER_NAME 时它错误地返回了HTTP Host 标头 . 所以我使用various keywords挖掘了Apache HTTPD bug reports关于这个主题,我终于找到了related bug . 从Apache HTTPD 1.3开始引入了这种行为 . 您需要在 httpd.confServerName<VirtualHost> 条目中将UseCanonicalName指令设置为 on (同时检查the document底部的警告!) .

    <VirtualHost *>
        ServerName example.com
        UseCanonicalName on
    </VirtualHost>
    

    这对我有用 .

    总结一下, SERVER_NAME 更可靠,但你在服务器配置上是 dependent

  • 0

    正如我在this answer中提到的,如果服务器在80以外的端口上运行(在开发/内联网机器上可能是常见的),则 HTTP_HOST 包含端口,而 SERVER_NAME 则不包含端口 .

    $_SERVER['HTTP_HOST'] == 'localhost:8080'
    $_SERVER['SERVER_NAME'] == 'localhost'
    

    (至少这是我在基于Apache端口的虚拟主机中注意到的)

    请注意, HTTP_HOST 在HTTPS上运行时不包含 :443 (除非您测试了're running on a non-standard port, which I haven') .

    正如其他人所指出的,这两者在使用IPv6时也有所不同:

    $_SERVER['HTTP_HOST'] == '[::1]'
    $_SERVER['SERVER_NAME'] == '::1'
    
  • 736

    HTTP_HOST 是客户端发送的目标主机 . 它可以由用户自由操作 . 向您的网站发送请求 HTTP_HOSTwww.stackoverflow.com 值是没问题的 .

    SERVER_NAME 来自服务器的 VirtualHost 定义,因此被认为更可靠 . 但是,它也可以在与Web服务器设置方式相关的某些条件下从外部进行操作:请参阅此This SO question,其中涉及两种变体的安全性方面 .

    你不应该依赖它们是安全的 . 也就是说,使用什么取决于你想做什么 . 如果要确定运行脚本的域,只要来自恶意用户的无效值不会破坏任何内容,就可以安全地使用 HTTP_HOST .

  • 61

    我花了一段时间才明白“ SERVER_NAME 更可靠”的含义 . 我使用共享服务器,但无法访问虚拟主机指令 . 所以,我在 .htaccess 中使用mod_rewrite将不同的 HTTP_HOST 映射到不同的目录 . 在这种情况下,它是有意义的 HTTP_HOST .

    如果使用基于名称的虚拟主机,则情况类似:虚拟主机中的 ServerName 指令只是说明将哪个主机名映射到此虚拟主机 . 最重要的是,在这两种情况下,客户端在请求期间提供的主机名( HTTP_HOST )必须与服务器中的名称匹配,该名称本身也映射到目录 . 映射是使用虚拟主机指令还是使用htaccess mod_rewrite规则完成,这里是次要的 . 在这些情况下, HTTP_HOST 将与 SERVER_NAME 相同 . 我很高兴Apache以这种方式配置 .

    However, the situation is different with IP-based virtual hosts. In this case and only in this case, SERVER_NAME and HTTP_HOST can be different, because now the client selects the server by the IP, not by the name. 实际上,可能存在特殊配置,这很重要 .

    所以,从现在开始,我将使用 SERVER_NAME ,以防我的代码移植到这些特殊配置中 .

  • 47

    假设有一个简单的设置(CentOS 7,Apache 2.4.x和PHP 5.6.20)和只有一个网站(不假设虚拟主机)......

    在PHP意义上, $_SERVER['SERVER_NAME'] 是PHP在 $_SERVER 超全局中注册的元素,基于您在httpd.conf中的Apache配置( **ServerName** 指令和 UseCanonicalName On )(无论是来自包含的虚拟主机配置文件,等等......) . HTTP_HOST 派生自HTTP host 标头 . 将此视为用户输入 . 使用前过滤并验证 .

    以下是我使用 $_SERVER['SERVER_NAME'] 作为比较基础的示例 . 以下方法来自我命名为 ServerValidatorValidator 的子项)的具体子类 . ServerValidator 在使用它们之前检查$ _SERVER中的六个或七个元素 .

    在确定HTTP请求是否为POST时,我使用此方法 .

    public function isPOST()
    {
        return (($this->requestMethod === 'POST')    &&  // Ignore
                $this->hasTokenTimeLeft()            &&  // Ignore
                $this->hasSameGETandPOSTIdentities() &&  // Ingore
                ($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
    }
    

    调用此方法时,将发生相关$ _SERVER元素的所有过滤和验证(并设置相关属性) .

    线......

    ($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')
    

    ...检查 $_SERVER['HTTP_HOST'] 值(最终从请求的 host HTTP标头派生)是否匹配 $_SERVER['SERVER_NAME'] .

    现在,我正在使用superglobal讲话来解释我的例子,但那仅仅是因为有些人对于filter_input_array()不熟悉 INPUT_GETINPUT_POSTINPUT_SERVER .

    最重要的是,除非满足所有四个条件,否则我不会在我的服务器上处理POST请求 . 因此,就POST请求而言,未能提供HTTP host 标头(先前已经过测试)会严格违反 HTTP 1.0 浏览器 . 此外,请求的主机必须匹配httpd.conf中 ServerName 的值,并且,通过扩展, $_SERVER 超全局中的 $_SERVER('SERVER_NAME') 的值 . 再次,我将使用 INPUT_SERVER 与PHP过滤器功能,但你 grab 了我的漂移 .

    请记住,Apache经常在标准重定向中使用 ServerName (例如,从URL中删除尾部斜杠:示例,http://www.foo.com变为http://www.foo.com/),即使您没有使用URL重写 .

    我使用 $_SERVER['SERVER_NAME'] 作为标准,而不是 $_SERVER['HTTP_HOST'] . 在这个问题上有很多来回 . $_SERVER['HTTP_HOST'] 可能为空,因此这不应该是创建代码约定的基础,例如上面的我的公共方法 . 但是,仅仅因为两者都可以设定并不能保证它们是平等的 . 测试是确定的最佳方式(牢记Apache版本和PHP版本) .

  • 25

    请注意,如果要使用IPv6,可能需要使用 HTTP_HOST 而不是 SERVER_NAME . 如果输入 http://[::1]/ ,则环境变量将如下所示:

    HTTP_HOST = [::1]
    SERVER_NAME = ::1
    

    这意味着,如果你做一个mod_rewrite,你可能会得到一个令人讨厌的结果 . SSL重定向的示例:

    # SERVER_NAME will NOT work - Redirection to https://::1/
    RewriteRule .* https://%{SERVER_NAME}/
    
    # HTTP_HOST will work - Redirection to https://[::1]/
    RewriteRule .* https://%{HTTP_HOST}/
    

    仅在您没有主机名的情况下访问服务器时才适用 .

  • 5

    如果你想通过server.php检查或者你想用以下内容调用它:

    <?php
    
    phpinfo(INFO_VARIABLES);
    
    ?>
    

    要么

    <?php
    
    header("Content-type: text/plain");
    
    print_r($_SERVER);
    
    ?>
    

    然后使用您网站的所有有效网址访问它,并查看差异 .

相关问题