如何以编程方式查找Web服务器实例是否支持url重写

时间:2009-07-05 13:28:18

标签: php url-rewriting

我想问的是,是否有办法找出网络服务器实例是否启用了网址重写。我需要这个,以便能够实例化正确类型的URL处理程序。

从理论上讲,如果你启用了它,你可以提前知道它,并且可以使用一些东西来配置它。但是,我希望能够在运行时自动检测此设置。

网址重写规则非常简单:

^/(.*)$ => /bootstrap.php

这可以保证REQUEST_URI中存在相关字符串,但不会污染_GET数组。

到目前为止,我的研究工作在哪里:

  1. 的Apache。
    在我看来,Apache有一个非常古怪的方法,因为它为重写URL设置REDIRECT_SCRIPT_URI标题,但不为那些没有重写的标题设置。 例如。

    http://host/ana/are/mere
    将被重写为index.php,因此前面的标题会出现,但
    http://host/
    不会被重写。

  2. Lighttpd的。
    具有fast-cgi的Lighttpd表现良好,如果为当前主机启用了URL Rewrite,则设置REDIRECT_URI标头。这很可靠。

  3. 切诺基。
    好吧,对于切诺基来说,我找不到任何方法,因为它使用(在我看来)一种更复杂的方法来获取URL重写。 (即,它被称为内部重定向 - 并且fcgi进程不知道请求被重定向)

  4. 此外,我还没有测试过其他http服务器,如nginx,所以如果有人对此事有一些意见,我很乐意听到。

5 个答案:

答案 0 :(得分:14)

不是最优雅的解决方案,但您可以创建一个目录,插入.htaccess和一个小的php文件,并尝试使用curl / file_get_contents()从您的实际代码中打开它:

的.htaccess

RewriteEngine on
RewriteRule ^(.*?)$ index.php?myparam=$1

的index.php

<?php
//open with file_get_contents("http://yoursite/directory/test")
if($_GET['myparam']){die("active");}
?>

虽然在安装过程中这可能是可以接受的,但出于性能原因,这不应该用于您网站上的每个请求!将信息保存在某处(sqlite / textfile)。

<强>更新

特定于Apache,但apache_get_modules() / phpinfo()与array_search / strpos结合使用可能对您有所帮助。

答案 1 :(得分:9)

下面已经提到了,但我相信以下方法对这个问题是一个相当防水的解决方案:

  1. 设置重定向

  2. 通过重写的网址

  3. 申请网页
  4. 如果请求返回有问题的页面,则表示您已正确设置重定向,如果获得HTTP 404响应,则表明它无法正常工作。

  5. 基本上,这个想法适用于任何重定向方法。它已经被提及了,但是值得重申,这些技巧增加了相当多的开销,只能执行一次(安装或从设置面板),然后保存在设置中。


    一些实现细节,选择以及我对此解决方案的了解:

    我记得Drupal在安装过程中做了这样的检查,所以我查看了他们是如何做到的。他们在安装页面上的javascript做了一个ajax请求(同步,以防止与数据库的并发问题)。这需要用户安装软件才能打开javascript,但我认为这不是一个无理要求。

    但是,我确实认为使用php来请求页面可能是一个更清洁的解决方案。除了不需要javascript要求之外,它还需要来回传输更少的数据,并且不需要将操作的逻辑分布在多个文件上。我不知道这两种方法是否还有其他(dis)优势,但这应该让你去,让你自己探索其他选择。

    还有另一种选择:是在测试环境中还是在普通站点上进行测试。 Drupal所做的事情就是让重定向始终打开(例如在apache的情况下,让重定向的.htaccess文件只是Drupal下载的一部分)但是只有在重定向打开时才写入花哨的url设置。这样做的缺点是需要更多的工作来检测使用哪种类型的重定向,但仍然可以(例如,您可以在特定的测试页面或甚至每个页面上添加显示重定向引擎的GET变量,或者您可以重定向到设置$redirectionEngine然后包含真实索引的页面。虽然除了在apache上使用mod_rewrite之外我没有太多的重定向经验,但我相信这应该适用于几乎每个重定向引擎。

    此处的另一个选择是使用测试环境。基本上,我们的想法是创建一个文件夹并为其设置重定向,或者删除对文件系统写访问的需要,而是拥有一个文件夹(或每个重定向引擎的文件夹)。这有一些缺点:你仍然需要写访问权来设置主站点的重定向(虽然可能不是所有的重定向引擎,我真的不知道你们如何正确设置它们 - 但对于apache你需要写访问权限如果要打开重定向),机器人可能更容易通过访问测试来检测您正在使用的软件及其使用的版本(除非您在测试后删除测试文件夹)并且您需要能够仅重写网站的一部分(这对于任何重定向引擎都是有意义的,但我并不是盲目地假设这个功能)。然而,这确实带来了以下优点:更容易找出正在使用的重写引擎或基本上重定向的任何其他方面。可能还有其他我不知道的优点,所以我只是给出选项,让你自己选择你的方法。

    有一些选项留给用户,我相信这可以帮助您以您喜欢的方式设置系统。

答案 2 :(得分:6)

PHP有server-specific functions用于Apache,IIS和NSAPI服务器。我只有Apache,但是merkuro建议按预期工作:

<?php
  if (in_array('mod_rewrite',@apache_get_modules()))
    echo 'mod_rewrite enabled';
  else
    echo 'mod_rewrite not enabled';
?>

由于PHP服务器特定的功能未覆盖您要测试的所有服务器,因此这可能不是最佳解决方案。

我建议merkuro的第一个答案 - 然后在脚本中进行测试。我相信这是获得好成绩的唯一途径。

希望有所帮助!

答案 3 :(得分:2)

如果服务器是Apache,则可以通过PHP中的apache_get_modules()函数以编程方式检查是否存在mod_rewrite:

$modules = apache_get_modules();
echo in_array('mod_rewrite', $modules) ? 'mod_rewrite detected' : 'mod_rewrite not detected';

这可以作为第一步使用,但它无论如何都不是完全证明方法。仅仅因为加载mod_rewrite并不意味着它可用于您的环境。如果您使用的服务器不是Apache,这也无济于事。

没有很多一致的方法适用于所有平台组合。但由于结果是一致的,您可以测试它。设置一个特殊的重定向,并让脚本使用PHP的cURLfile_get_contents()来检查测试URL。如果重定向成功,您将获得预期的内容,并且您可以轻松地进行测试。

这是一个基本的.htaccess我设置将ajax重定向到ajax.php:

RewriteEngine On
RewriteRule ajax ajax.php [L]

以下PHP脚本将尝试获取ajax的内容。真正的脚本名称是ajax.php。如果重定向失败,那么它将无法获得预期的内容。

error_reporting(E_ALL | E_STRICT);

$url = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['REQUEST_URI']).'/ajax';
$result = json_decode(@file_get_contents($url));

echo ($result === "foobar") ? 'mod_rewrite test was successful' : 'mod_rewrite test failed'; 

最后,这是脚本的最后一部分,ajax.php。这将在重定向成功时返回预期的响应:

echo json_encode('foobar');

我设置了live example of this test,我也提供了full sources

答案 4 :(得分:1)

正如所有的awnser已经提到的那样,实际测试它是确保它有效的唯一方法。但实际上我没有实际重定向到实际的页面并等待它加载,我只是检查标题。 在我看来,这很快就足以在运行时在常规站点上使用。如果它真的需要高性能,那么当然缓存它会更好。

只需在.htaccess文件中添加以下内容

即可
RewriteEngine on
RewriteRule ^/redir/My/Super/Special/Hidden/Url/To/Test/$   /redir/longload.php  [L,R=307]

然后你可以使用以下php代码来检查是否启用了mod_rewrite。

<?php
function HasModRewrite() {
  $s = empty($_SERVER["HTTPS"]) ? '' : ($_SERVER["HTTPS"] == "on") ? "s" : "";
  $sp = strtolower($_SERVER["SERVER_PROTOCOL"]);
  $protocol = substr($sp, 0, strpos($sp, "/")) . $s;
  $port = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]);


  $options['http'] = array(
    'method' => "HEAD", 
    'follow_location' => 0,
    'ignore_errors' => 1,
    'timeout' => 0.2
  );

  $context = stream_context_create($options);

  $body = file_get_contents($protocol . "://" . $_SERVER['SERVER_NAME'] . $port .'/redir/My/Super/Special/Hidden/Url/To/Test/', NULL, $context);
  if (!empty($http_response_header))
  {
    return substr_count($http_response_header[0], ' 307')>0;
  }

  return false;      
}


$st = microtime();
$x = HasModRewrite();
$t = microtime()-$st;

echo 'Loaded in: '.$t.'<hr>';

var_dump($x);
?>

输出:

Loaded in: 0.002657
---------------------
bool(true)