返回

多域名共享登录及独立 Header/Footer 加载方案 (PHP+Twig)

javascript

不同域名,咋用同一个登录注册,还能加载各自的 Header?

多个域名(domain.com, domain.org, domain.africa, domain.net)共享数据库和部分内容,但每个域名都有自己独立的注册登录表单,更新起来很麻烦。现在把注册登录表单统一了,可咋根据用户当前访问的域名,加载对应的 header 和 footer 呢?

我用的是 PHP + Twig (无框架),在网上找了些方法,但都不太灵光。下面我来捋一捋问题,并给出解决方案。

问题根源:区分域名,条件加载

问题的核心在于:如何准确判断用户当前访问的是哪个域名,然后根据域名,有条件地加载对应的 header 和 footer 文件 。 之前尝试的方法,要么判断不准确(比如 JavaScript 的方法,总是加载第一个匹配项),要么 Twig 模板引擎获取不到正确的 URL 信息。

解决方案:服务器端才是王道!

由于需要准确获取域名信息,并在服务器端处理模板渲染,客户端(Javascript)方案并不可靠。应该直接在 PHP 中获取当前 URL,然后将域名信息传递给 Twig 模板。

方案一:PHP 传递域名信息给 Twig

  1. 原理: 在 PHP 中使用 $_SERVER['HTTP_HOST'] 获取当前请求的主机名(即域名),然后将这个值传递给 Twig 模板。在 Twig 模板中,根据这个值来决定加载哪个 header 文件。

  2. 代码示例 (PHP 部分):

    <?php
    // 获取当前域名
    $currentDomain = $_SERVER['HTTP_HOST'];
    
    // 假设你的 Twig 环境设置好了,名为 $twig
    echo $twig->render('your_template.html', [
        'currentDomain' => $currentDomain
    ]);
    ?>
    
  3. 代码示例 (Twig 部分):

    {% if currentDomain == 'domain.com' %}
        {% include 'domains/domaincom/includes/header.html' %}
    {% elseif currentDomain == 'domain.org' %}
        {% include 'domains/domainorg/includes/header.html' %}
    {% elseif currentDomain == 'domain.africa' %}
        {% include 'domains/domainafrica/includes/header.html' %}
    {% elseif currentDomain == 'domain.net' %}
        {% include 'domains/domainnet/includes/header.html' %}
    {% else %}
        {# 默认的 header,或者啥也不加载 #}
    {% endif %}
    
    {# ... 页面的其他内容 ... #}
    
    {% if currentDomain == 'domain.com' %}
        {% include 'domains/domaincom/includes/footer.html' %}
    {% elseif currentDomain == 'domain.org' %}
        {% include 'domains/domainorg/includes/footer.html' %}
    {% elseif currentDomain == 'domain.africa' %}
        {% include 'domains/domainafrica/includes/footer.html' %}
    {% elseif currentDomain == 'domain.net' %}
        {% include 'domains/domainnet/includes/footer.html' %}
    {% else %}
        {# 默认的 footer,或者啥也不加载 #}
    {% endif %}
    
    
  4. 解释:

    • PHP 代码中, $_SERVER['HTTP_HOST'] 能可靠地获取当前域名。
    • 然后,把获取到的域名通过 $twig->render 传递给 Twig 模板。
    • Twig 模板里, 用 {% if currentDomain == '...' %} 这样的条件判断语句, 来决定包含哪个 header/footer 文件。

方案二:创建域名映射,简化 Twig 逻辑

如果域名和 header/footer 文件的路径有规律,可以创建一个映射关系,让 Twig 模板更简洁。

  1. 原理: 在 PHP 中创建一个数组,将域名映射到对应的 header/footer 文件夹。将这个映射数组传递给 Twig 模板。在 Twig 模板中,通过域名从映射数组中取出对应的文件夹,然后拼接出完整的 header/footer 文件路径。

  2. 代码示例 (PHP 部分):

    <?php
    $currentDomain = $_SERVER['HTTP_HOST'];
    
    // 创建域名到文件夹的映射
    $domainMap = [
        'domain.com' => 'domaincom',
        'domain.org' => 'domainorg',
        'domain.africa' => 'domainafrica',
        'domain.net' => 'domainnet',
    ];
    
    // 获取对应的文件夹名称,如果域名不存在映射,则为空
      $domainFolder = $domainMap[$currentDomain] ?? '';
    
    echo $twig->render('your_template.html', [
        'domainFolder' => $domainFolder,
    ]);
    ?>
    
  3. 代码示例 (Twig 部分):

      {% if domainFolder %}
          {% include 'domains/' ~ domainFolder ~ '/includes/header.html' %}
      {% endif %}
    
      {# ... 页面的其他内容 ... #}
      {% if domainFolder %}
          {% include 'domains/' ~ domainFolder ~ '/includes/footer.html' %}
      {% endif %}
    
    
  4. 解释:

    • PHP 代码中创建了一个 $domainMap 数组。
    • $domainMap[$currentDomain] ?? '' 尝试根据当前域名获取对应的文件夹名称。如果 $currentDomain 不在 $domainMap 中,则返回空字符串。
    • Twig 模板中, 使用 ~ 连接字符串, 拼出完整的 header/footer 文件路径.

方案三: 更进一步,把 header/footer 文件名也放到映射里 (可选)

如果 header/footer 文件名在不同域名下也不一样,还可以把文件名也放到映射数组里。

  1. 原理: 在 PHP 中创建的映射数组,不仅包含文件夹名,还包含 header 和 footer 的文件名。

  2. 代码示例 (PHP 部分):

    <?php
    $currentDomain = $_SERVER['HTTP_HOST'];
    
    $domainMap = [
        'domain.com' => ['folder' => 'domaincom', 'header' => 'header.html', 'footer' => 'footer.html'],
        'domain.org' => ['folder' => 'domainorg', 'header' => 'header_org.html', 'footer' => 'footer_org.html'],
        'domain.africa' => ['folder' => 'domainafrica', 'header' => 'header_africa.html', 'footer' => 'footer_africa.html'],
        'domain.net' => ['folder' => 'domainnet', 'header' => 'header.html', 'footer' => 'special_footer.html'],
    ];
    
     $domainData = $domainMap[$currentDomain] ?? null;
    
    echo $twig->render('your_template.html', [
        'domainData' => $domainData,
    ]);
    ?>
    
  3. 代码示例 (Twig 部分):

    {% if domainData %}
      {% include 'domains/' ~ domainData.folder ~ '/includes/' ~ domainData.header %}
    {% endif %}
    
      {# ... 页面的其他内容 ... #}
     {% if domainData %}
        {% include 'domains/' ~ domainData.folder ~ '/includes/' ~ domainData.footer %}
      {% endif %}
    
    
  4. 解释:

  • $domainMap 数组现在每个域名对应一个包含 folderheaderfooter 键的数组。
  • 在Twig中使用domainData.folder,domainData.header,domainData.footer来拼接路径

安全建议

  • 验证输入: 尽管 $_SERVER['HTTP_HOST'] 相对可靠, 但理论上仍然可以被伪造。如果你需要更高的安全性,可以考虑对 $currentDomain 的值进行白名单验证,只允许已知的域名。
  • 路径安全: 在拼接文件路径时,要确保 $domainFolderdomainData.header`, `domainData.footer`这些变量的值不会导致路径遍历漏洞。一般来说,使用白名单控制这些变量的值是最安全的。避免直接使用用户可控的输入来拼接文件路径。

进阶技巧:封装成 Twig 扩展(可选)

如果你想让代码更优雅,可以将获取域名和选择 header/footer 的逻辑封装成一个 Twig 扩展。这样,在 Twig 模板中就可以使用自定义的函数或过滤器,让模板更简洁。由于这部分内容较为复杂,这里只提供思路,不展开具体代码。主要步骤如下:

  1. 创建一个 PHP 类,实现 Twig 的扩展接口(Twig\Extension\ExtensionInterface 或继承 Twig\Extension\AbstractExtension)。
  2. 在这个类中,定义一个或多个自定义函数或过滤器。这些函数/过滤器负责获取当前域名,并根据域名返回对应的 header/footer 文件路径。
  3. 将这个扩展注册到你的 Twig 环境中。
  4. 在 Twig 模板中,使用你定义的自定义函数或过滤器。

希望以上方案能帮你解决多域名 header/footer 的问题!