【问题标题】:Get current domain获取当前域
【发布时间】:2012-05-29 20:12:58
【问题描述】:

我的网站在服务器上http://www.myserver.uk.com

在这台服务器上我有两个域:

one.com and two.com

我想使用 PHP 获取当前域,但如果我使用 $_SERVER['HTTP_HOST'],那么它会显示给我

myserver.uk.com

代替:

one.com or two.com

如何获取域,而不是服务器名称?

【问题讨论】:

  • 您只能获取主 URL。这三个中哪一个是主要的?
  • 您的两个域如何将请求“重定向”到您的服务器?
  • @infgeoax 可能是一个框架...
  • 主要是 myserver.uk.com。那么我怎样才能得到当前的域名呢?如果我打开地址为 one.com 的站点,我想获得 one.com 而不是 myserver.uk.com
  • @TonyEvyght 这就是 infgeoax 的重点,我试图让您应该$_SERVER['HTTP_HOST'] 中获得您正在连接的主机名。如果站点one.comtwo.com 使用(i)框架“重定向”,则页面本身仍然来自myserver.uk.com,因此您不会获得真正的域。 one.com 的 HTML 源代码是什么?

标签: php url php-5.2


【解决方案1】:

试试这个:

$_SERVER['SERVER_NAME']

或解析:

$_SERVER['REQUEST_URI']

参考:apache_request_headers()

【讨论】:

  • -1:仅凭这个答案,我不知道我正在查看的不同建议究竟是做什么的。当然,这给了我继续寻找的意义,但就其本身而言,这确实不是一个好的答案......
  • 只需 print_r(apache_request_headers()) 你就会明白所有的:)
  • @SarahLewis HTTP_X_ORIGINAL_HOST 可以被用户修改,不能被信任。这可能并不总是一个问题,但需要注意。
【解决方案2】:

最好的用途是

echo $_SERVER['HTTP_HOST'];

而且可以这样使用:

if (strpos($_SERVER['HTTP_HOST'], 'banana.com') !== false) {
    echo "Yes this is indeed the banana.com domain";
}

下面的代码是在结构化 HTML 输出中查看 $_SERVER 中所有变量的好方法,其中突出显示的关键字在执行后立即停止。因为我有时会忘记自己使用哪一个 - 我认为这可能很不错。

<?php
    // Change banana.com to the domain you were looking for..
    $wordToHighlight = "banana.com";
    $serverVarHighlighted = str_replace( $wordToHighlight, '<span style=\'background-color:#883399; color: #FFFFFF;\'>'. $wordToHighlight .'</span>',  $_SERVER );
    echo "<pre>";
    print_r($serverVarHighlighted);
    echo "</pre>";
    exit();
?>

【讨论】:

    【解决方案3】:

    这样做的唯一安全方式

    检索当前域的唯一有保证的安全方法是将其存储在自己的安全位置。

    大多数框架都会为您存储域,因此您需要查阅特定框架的文档。如果您不使用框架,请考虑将域存储在以下位置之一:

       Secure methods of storing the domain      Used By
    A configuration file   Joomla, Drupal/Symfony
    The database   WordPress
    An environmental variable Laravel
    A service registry   Kubernetes DNS

    以下工作......但它们并不安全

    黑客可以使以下变量输出他们想要的任何域。这可能会导致缓存中毒和难以察觉的网络钓鱼攻击。

    $_SERVER['HTTP_HOST']
    

    这会从open to manipulation by hackers 的请求标头中获取域。与:

    $_SERVER['SERVER_NAME']
    

    如果关闭Apache设置usecanonicalname,这个可以做得更好;在这种情况下,$_SERVER['SERVER_NAME'] 将不再被允许填充任意值并且是安全的。但是,这不是默认设置,也不常见。

    在流行的系统中

    以下是如何在以下框架/系统中获取当前域:

    WordPress

    $urlparts = parse_url(home_url());
    $domain = $urlparts['host'];
    

    如果您在 WordPress 中构建 URL,只需使用 home_urlsite_urlother URL functions 中的任何一个。

    Laravel

    request()->getHost()
    

    request()-&gt;getHost 函数继承自 Symfony,自 2013 年 CVE-2013-4752 修补以来一直是安全的。

    Drupal

    安装程序尚未确保此安全 (issue #2404259)。但是在 Drupal 8 中,您可以在 Trusted Host Settings 关注文档以保护您的 Drupal 安装,之后可以使用以下内容:

    \Drupal::request()->getHost();
    

    其他框架

    随时编辑此答案,以包括如何在您喜欢的框架中获取当前域。这样做时,请附上相关源代码的链接或任何其他有助于我验证框架是否安全运行的链接。


    附录

    利用示例:

    1. 如果僵尸网络持续使用错误的主机头请求页面,则可能发生缓存中毒。然后,生成的 HTML 将包含指向攻击者网站的链接,他们可以在其中对您的用户进行网络钓鱼。一开始恶意链接只会被发回给黑客,但如果黑客做了足够多的请求,页面的恶意版本最终会在你的缓存中分发给其他用户。

    2. 如果您根据主机标头将链接存储在数据库中,则可能发生网络钓鱼攻击。例如,假设您将绝对 URL 存储到论坛上用户的个人资料。通过使用错误的标题,黑客可以让任何点击其个人资料链接的人被发送到钓鱼网站。

    3. 如果黑客在为其他用户填写密码重置表单时使用恶意主机标头,则可能会发生密码重置中毒。然后,该用户将收到一封电子邮件,其中包含指向网络钓鱼站点的密码重置链接。另一种更复杂的形式通过让电子邮件退回并重新发送到黑客的一个 SMTP 服务器(for example CVE-2017-8295.)

      来跳过用户必须做的任何事情
    4. 这里有一些more malicious examples

    其他注意事项和注意事项:

    • usecanonicalname 关闭时,$_SERVER['SERVER_NAME'] 填充了相同的标题$_SERVER['HTTP_HOST'] 无论如何都会使用(加上端口)。这是 Apache 的默认设置。如果您或 DevOps 将其打开,那么您就可以了 - 是的 - 但您是否真的想依赖一个单独的团队,或者三年后的您自己,以保持看起来像次要配置的非-默认值?尽管这样可以确保安全,但我会提醒您不要依赖此设置。
    • 不过,Red Hat 默认会开启 usecanonical [source]。
    • 如果在虚拟主机条目中使用了serverAlias,并且请求了别名域,$_SERVER['SERVER_NAME'] 将不会返回当前域,而是返回 serverName 指令的值。
    • 如果无法解析 serverName,则使用操作系统的 hostname 命令代替 [source]
    • 如果省略主机头,服务器的行为就像使用规范一样 在[source]上。
    • 最后,我刚刚尝试在本地服务器上利用它,但无法欺骗主机标头。我不确定 Apache 是否有解决此问题的更新,或者我是否只是做错了什么。无论如何,在没有使用虚拟主机的环境中,这个标头仍然可以被利用。

    有点咆哮:

         这个问题获得了数十万的浏览量,却没有提及手头的安全问题!不应该这样,但仅仅因为 Stack Overflow 答案很受欢迎,这并不意味着它是安全的。



    【讨论】:

    • 您可能想提一下 home_url 和 site_url 之间的区别。 wordpress.stackexchange.com/a/50605/13
    • wordpress 用户 +1。如果您需要检查是否安装在子目录中很好,但请注意,如果安装在域的根目录中,则未设置 parse_url key:$urlparts['path']。否则 $urlparts['path'] 返回子目录。
    【解决方案4】:

    使用$_SERVER['HTTP_HOST'] 得到我(子域。)maindomain.extension。对我来说,这似乎是最简单的解决方案。

    如果您实际上是通过 iFrame 进行“重定向”,则可以添加一个 GET 参数来说明域。

    <iframe src="myserver.uk.com?domain=one.com"/>
    

    然后您可以设置一个会话变量,在整个应用程序中保留这些数据。

    【讨论】:

    • 最重要的是它包含端口号,这样我之后就不需要连接它了。 bsdnoobz 建议的 phpinfo 可以帮助我找到正确的解决方案。
    【解决方案5】:

    试试$_SERVER['SERVER_NAME']

    提示:创建一个调用函数phpinfo() 的PHP 文件并查看“PHP 变量”部分。那里有一堆我们从未想过的有用变量。

    【讨论】:

    • 您可以随时尝试 print_r-ing $_SERVER 并搜索
    【解决方案6】:

    获取域名:

    $_SERVER['HTTP_HOST'] 
    

    协议域:

    $protocol = strpos(strtolower($_SERVER['SERVER_PROTOCOL']), 'https') === FALSE ? 'http' : 'https';
    $domainLink = $protocol . '://' . $_SERVER['HTTP_HOST'];
    

    协议、域和查询字符串总计:

    $url = $protocol . '://' . $_SERVER['HTTP_HOST'] . '?' . $_SERVER['QUERY_STRING'];
    

    **由于 $_SERVER['SERVER_NAME'] 对于多域托管不可靠!

    【讨论】:

      【解决方案7】:

      我知道这可能不完全是关于这个主题,但根据我的经验,我发现将当前 URL 的 WWW 属性存储在一个变量中很有用。

      另外,请看我下面的评论,看看这是什么意思。

      在确定是否使用“www”来调度 Ajax 调用时,这一点很重要:

      $.ajax("url" : "www.site.com/script.php", ...
      
      $.ajax("url" : "site.com/script.php", ...
      

      在调度 Ajax 调用时,域名必须与浏览器地址栏中的域名匹配,否则控制台中会出现 Uncaught SecurityError

      所以我想出了这个解决方案来解决这个问题:

      <?php
          substr($_SERVER['SERVER_NAME'], 0, 3) == "www" ? $WWW = true : $WWW = false;
      
          if ($WWW) {
              /* We have www.example.com */
          } else {
              /* We have example.com */
          }
      ?>
      

      然后,根据 $WWW 是真还是假,运行正确的 Ajax 调用。

      我知道这听起来可能微不足道,但这是一个很容易被绊倒的常见问题。

      【讨论】:

      • OP 明确要求提供域,而不是 SERVER_NAME
      • 没错,但现在你也不得不担心 www 问题。
      • 为什么?在 JS 中,您可以查看 window.location。在 PHP 中你得到了SERVER_NAME.
      • SERVER_NAME 返回“www.site.com”,即使在地址栏中输入了“site.com”。如果您在整个代码中使用 SERVER_NAME,则不可避免地会遇到 www/no-www 安全问题,尤其是在进行 Ajax 调用时。但要回答您的问题,在高级 PHP 编程中,有时 PHP 需要动态生成对服务器进行 HTTP 调用的代码。如果目标 URL 在页面上包含“www”而没有,则会产生安全错误。
      • 好吧好吧...我读到了,你是对的。所以你的答案可能与某人有关。干得好:)
      【解决方案8】:

      每个人都在使用parse_url 函数,但有时用户可能会以不同的格式传递参数。

      为了解决这个问题,我创建了一个函数。看看这个:

      function fixDomainName($url='')
      {
          $strToLower = strtolower(trim($url));
          $httpPregReplace = preg_replace('/^http:\/\//i', '', $strToLower);
          $httpsPregReplace = preg_replace('/^https:\/\//i', '', $httpPregReplace);
          $wwwPregReplace = preg_replace('/^www\./i', '', $httpsPregReplace);
          $explodeToArray = explode('/', $wwwPregReplace);
          $finalDomainName = trim($explodeToArray[0]);
          return $finalDomainName;
      }
      

      只需传递 URL 并获取域。

      例如,

      echo fixDomainName('https://stackoverflow.com');
      

      将返回:

      stackoverflow.com
      

      在某些情况下:

      echo fixDomainName('stackoverflow.com/questions/id/slug');
      

      它还会返回stackoverflow.com

      【讨论】:

        【解决方案9】:

        试试吧:

        echo apache_request_headers()[3];
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-09
          • 1970-01-01
          • 1970-01-01
          • 2023-04-06
          • 1970-01-01
          相关资源
          最近更新 更多