【问题标题】:How to get real host or server name in PHP如何在 PHP 中获取真实的主机名或服务器名
【发布时间】:2011-01-09 08:44:29
【问题描述】:

如何在 PHP 中不使用 $_SERVER['SERVER_NAME'] 来获取真实主机名?还有其他更可靠的方法吗?

我创建了一个从域路径获取主机名的函数。

我想避免使用 $_SERVER['SERVER_NAME'] 变量,因为它可以通过在 HTTP 请求中发送修改后的标头来伪造。

这是我当前的实现(如果路径中包含实际域名,则此方法有效。例如:/vhosts/website.com/public_html):

function getServerName() {
 $path = realpath(__FILE__);
 $url = array();
 preg_match_all("/\/[a-z0-9-]+(\.[a-z0-9-]+)+/i", $path, $url);
 // 4 is minimum requirement for the address (e.g: http://www.in.tv)
 if (strlen($url[0][0]) > 4) {
  $result = str_replace("/", "", $url[0][0]);
  return $result;
 }
 else
  return false;
}

谢谢!

【问题讨论】:

  • 更可能他不知道如何正确表达他的问题。帮助新手并解释他在提供的环境和 HTTP 协议中误解了什么而不是投票否决他的问题会很好。
  • 你知道的,很好。我会解决这个问题。问题是他说的一半我听不懂,只能推断他在说什么。我只能假设'PATH' 的意思是'SCRIPT_PATH',我不知道他是在谈论'HTTP_HOST' 还是'SERVER_NAME'。似乎很难相信他可以写一个脚本,却不知道他使用了哪些变量。
  • @Chacha102 是的,我知道,我一遍又一遍地从我的同事那里听到同样的问题...... ;-) 我刚刚发布了一个更长的答案,希望下一个“信息寻求者”可以更多很容易找到它。永不放弃? ;-)
  • 嗯,nvm。我不会主要编辑它,因为他不知道他在说什么变量,因此我无法可靠地解决这个问题。
  • @minnur 请修正您原来的问题...($_SERVER 的哈希索引似乎不正确)

标签: php


【解决方案1】:

如果您想要客户端无法设置的服务器名称,请使用$_SERVER['SERVER_NAME']。它由服务器自己设置但也可以在某些情况下使用错误来伪造,正如 Gumbo 指出并在 cmets 中链接到的那样。

【讨论】:

  • 事实上它可以被客户端操纵(见shiflett.org/blog/2006/mar/server-name-versus-http-host)。
  • @Gumbo:这是一个错误。它是否仍然存在,我不知道(那个博客条目已经快 4 年了)
  • @R. Bemrose:它是仍然存在(PHP 5.3.0)。
  • @Gumbo:很高兴知道!我会把它添加到我的答案中。
  • 有些事情永远不会改变...... ;-) 但我不知道这是否真的是一个错误。也许这种行为是故意的。
【解决方案2】:

我想你说的是

$_SERVER['HTTP_HOST'];

其中,给定 HTTP 前缀意味着它来自 HTTP 标头。

您可能想使用:

$_SERVER['SERVER_NAME']

由服务器定义,不能通过请求更改?

【讨论】:

    【解决方案3】:

    这将获得服务器端的主机名,但如果您在商业主机上运行(而不是自己托管),我认为这不会有那么有用。

    $host = php_uname( 'n' );
    

    如果您使用的是 Apache,您应该做的是让您的服务器/站点只响应某些名称(否则应该有一个没有多大作用的默认值)。您可以使用 ServerName 和 ServerAlias 指令。

    【讨论】:

    • 如果您只使用主机名白名单,您将永远不会被注入
    【解决方案4】:

    编辑:正如 Gumbo 所指出的,原始海报可能意味着 HTTP_HOST 而不是 HOST_NAME。否则,我的答案是完全错误的。

    HTTP_HOST 变量反映访问者用于访问站点的域名。如果与文件路径无关!它的值方便地存储在 $_SERVER['HTTP_HOST'] 中。有没有其他方法可以得到它?当然,通常有几种方法可以做事。例如,当 PHP 作为 Apache 模块运行时,这是有效的。

    <?php
    
    $request_headers = apache_request_headers();
    echo $request_headers['Host'];
    
    ?>
    

    问题是:为什么有人想做这样的事情?为什么要使用最终从同一个地方获取相同数据的古怪解决方法来替换可靠的标准方法?

    您担心 HTTP 请求会更改 $_SERVER['HTTP_HOST']。当然是:这就是它的来源。浏览器必须指定它想要访问的站点(这是基于名称的虚拟主机的基础),如果它发送一个流氓值,那么它就不会到达该站点。

    【讨论】:

    • 没有$_SERVER['HOST_NAME'];这是$_SERVER['HTTP_HOST']。
    • OP 主机可能遇到的主要问题是,它是一个托管的标准 apache/plesk/whatever 安装,无论发送哪个主机名(如果不匹配),它总是响应第一个虚拟主机任何虚拟主机。如果请求标头中的 http 主机与预期不匹配,则解决此问题的正确方法是返回 404。否则,您将不会做出任何更好的事情(从某种意义上说,您正在尝试修复/预防)。
    【解决方案5】:

    当然$_SERVER['HTTP_HOST']可以被客户端修改——因为实际上它是由客户端发送的。这是 http 协议的一部分。如果您想获取在 apache 的 vhost 配置中定义的主服务器名称,或者您可以按照其他人的建议访问 $_SERVER['SERVER_NAME'] 的任何名称。

    我建议从服务器的文件路径(存储在__FILE__)中提取域名是不明智的,因为它可能使您的应用程序不可重定位(它将不再与存储位置无关)。

    您可以通过使用var_dump($_SERVER) 将数组转储到脚本中来查看数组的内容,但请记住,并非所有 Web 服务器和所有 Web 服务器设置都暴露相同的环境。这在 web 服务器文档中有记录,我认为它部分记录在 php 在线文档中。

    更新/重要通知:正如其他人指出的那样,如果 apache 配置为 UseCanonicalName off,$_SERVER['SERVER_NAME'] 的内容可能会被欺骗(如果您使用例如 Plesk,这可能是默认设置基于托管)。所以实际上使用__FILE__ 可以解决这个问题(如果您的文档根目录包含主机名)。第一种方法的更大问题是它可以用来将任何类型的东西注入你的应用程序(SQL、JavaScript),因为 php 程序员通常认为SERVER_NAME 不是用户输入,因此不会对其进行清理。

    【讨论】:

    • 感谢您的回答!我将使用 $path = realpath(FILE);
    【解决方案6】:

    你没有。这就是 $_SERVER 变量的目的。如果要从路径中获取HOST_NAME,必须先从$_SERVER['HTTP_HOST']中获取PATH

    【讨论】:

    • 谢谢大家。这就是我想知道的。
    猜你喜欢
    • 2016-03-24
    • 1970-01-01
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-30
    • 2014-09-11
    • 2017-03-17
    相关资源
    最近更新 更多