Как узнать программно, если экземпляр веб-сервера поддерживает переписывание URL-адресов

Я хочу спросить, есть ли способ узнать, имеет ли экземпляр веб-сервера включенную перезапись URL. Мне нужно это для того, чтобы создать экземпляр правильного типа обработчика URL.

Теоретически вы знаете заранее, если вы его включили или нет, и можете использовать что-то для его настройки. Однако я хотел бы иметь возможность автоматически обнаруживать этот параметр во время выполнения.

Правило перезаписи URL будет очень простым:

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

Это гарантирует, что соответствующая строка присутствует в REQUEST_URI, но не загрязняет массив _GET.

Где мои исследования заняли меня до сих пор:

  • Apache.
    На мой взгляд, Apache имеет очень причудливый подход, поскольку он устанавливает заголовок REDIRECT_SCRIPT_URI для переписанных URL-адресов, но не для тех, которые не переписаны.
    Например.

     http://host/ana/are/mere
    будет переписана в index.php, поэтому вышеупомянутый заголовок будет присутствовать, но
     http://host/
    не будет перезаписана.
  • Lighttpd.
    Lighttpd с fast-cgi ведет себя нормально, установив заголовок REDIRECT_URI, если URL-адрес Rewrite включен для текущего хоста. Это надежно.

  • Cherokee.
    Что ж, для Cherokee нет метода, который я узнал, поскольку он использует (на мой взгляд) более сложный метод для перезаписи URL-адресов. (I.e., он называется внутренним перенаправлением – и процесс fcgi не знает, что запрос был перенаправлен)

Также я не тестировал другие http-серверы, как nginx, поэтому, если у кого-то есть какой-то вклад в этом вопросе, я бы с удовольствием его услышал.

Ответы

Ответ 1

Не самое элегантное решение, но вы можете создать каталог, вставить файл .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 может быть вам полезен.

Ответ 2

Это уже затронуто ниже, но я считаю, что следующий рецепт является довольно водонепроницаемым решением этой проблемы:

  • Настройте перенаправление

  • Запросить страницу через свой переписанный URL

  • Если запрос возвращает указанную страницу, вы правильно настроили перенаправление, если вы получили ответ HTTP 404, тогда он не работает.

Идея в основном заключается в том, что это работает практически с любым методом перенаправления. Это уже упоминалось, но повторяется, такие трюки добавляют немного накладных расходов и лучше выполняются только один раз (установка или с панели настроек), а затем сохраняются в настройках.


Некоторые детали реализации, выбор, который нужно сделать, и немного о том, как я пришел к этому решению:

Я вспомнил, что Drupal сделал такую ​​проверку во время процесса установки, поэтому я посмотрел, как они это сделали. У них был javascript на странице установки, который выполняет запрос ajax (синхронно, чтобы предотвратить проблемы concurrency с базой данных). Это требует, чтобы пользователь установил программное обеспечение, чтобы включить javascript, но я не думаю, что это необоснованное требование.

Однако, я думаю, что использование php для запроса страницы может быть более чистым решением. Наряду с тем, чтобы не беспокоиться о требовании javascript, ему также требуется меньше данных для отправки туда и обратно и просто не требует, чтобы логика действия распространялась по нескольким файлам. Я не знаю, есть ли другое (dis) преимущество для любого метода, но это должно заставить вас идти и позволить вам самостоятельно исследовать альтернативные варианты.

Существует еще один выбор: тестировать ли в тестовой среде или на обычном сайте. Дело Drupal заключается в том, что перенаправление всегда включается (например, в случае Apache, имеет файл .htaccess, который перенаправляет только часть загрузки Drupal), но только записывает причудливые URL-адреса, если перенаправление включено в настройки. Это имеет недостаток, что требуется больше работы для определения того, какой тип перенаправления используется, но он по-прежнему возможен (например, вы можете добавить переменную GET, отображающую механизм перенаправления либо на определенной тестовой странице, либо даже на каждой странице, либо вы можете перенаправить на страницу, которая устанавливает $redirectionEngine, а затем включает в себя реальный индекс). Хотя у меня нет большого опыта перенаправления, отличного от mod_rewrite на apache, я считаю, что это должно работать практически с каждым движком перенаправления.

Другой вариант здесь - использовать тестовую среду. В основном идея состоит в том, чтобы либо создать папку, либо настроить перенаправление для нее, либо удалить необходимость доступа к файловой системе, а вместо нее создать папку (или папку для каждого механизма перенаправления). Это имеет некоторые недостатки: вам все еще нужен доступ на запись для настройки перенаправления для основного сайта (хотя, возможно, не для всех механизмов перенаправления, я действительно не знаю, как вы все настроили их правильно), но для apache вам потребуется доступ на запись если вы собираетесь включить перенаправление), боту может быть проще определить, какое программное обеспечение и какая версия его вы используете, обратившись к тестам (если вы не удалите тестовые папки после тестирования), и вам нужно будет переписывайте только часть сайта (что имеет смысл для любого механизма перенаправления, чтобы быть возможностью, но я не слепо буду предполагать эту функциональность). Однако это связано с тем, что легче узнать, какой механизм перезаписи используется или в основном любой другой аспект перенаправления. Могут быть и другие преимущества, о которых я не знаю, поэтому я просто даю варианты и позволяю вам самостоятельно выбирать ваш метод.

С некоторыми вариантами, оставленными пользователю, я считаю, что это должно помочь вам настроить систему так, как вам нравится.

Ответ 3

PHP имеет специфические для сервера функции для серверов Apache, IIS и NSAPI. У меня только Apache, но, как предположил Меркуро, это работает как ожидалось:

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

Поскольку функции, специфичные для PHP-сервера, не охватывают все серверы, которые вы хотите протестировать, вероятно, это не лучшее решение.

Я бы порекомендовал первый ответ merkuro - внедряя затем тестирование в script. Я считаю, что это единственный способ получить хороший результат.

Надеюсь, что это поможет!

Ответ 4

Вы можете программно проверить наличие mod_rewrite, если сервер Apache, используя apache_get_modules() в PHP:

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

Это может быть использовано в качестве первого шага, но это не полный метод доказательства любыми способами. Просто потому, что загружен mod_rewrite, это не значит, что он доступен для вашей среды. Это также не помогает, если вы находитесь на сервере, который не является Apache.

Существует не так много последовательных методов, которые будут работать во всех комбинациях платформ. Но поскольку результат согласован, вы можете проверить это. Настройте специальное перенаправление и используйте script PHP cURL или file_get_contents(), чтобы проверить тестовый URL. Если перенаправление было успешным, вы получите ожидаемое содержимое, и вы можете легко протестировать его для этого.

Это базовый .htaccess, который я настраиваю для перенаправления ajax на ajax.php:

RewriteEngine On
RewriteRule ajax ajax.php [L]

Следующий PHP script попытается получить содержимое ajax. Настоящим именем script является 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'; 

Наконец, вот заключительная часть script, ajax.php. Это возвращает ожидаемый ответ при успешном перенаправлении:

echo json_encode('foobar');

Я установил живой пример этого теста, и я также предоставил полные источники.

Ответ 5

Как уже упоминал айнсер, на самом деле тестирование это единственный способ убедиться, что он работает. Но вместо того, чтобы фактически перенаправить на фактическую страницу и ждать ее загрузки, я просто проверил бы заголовок. По-моему, это достаточно быстро, чтобы даже использоваться во время работы на обычном сайте. Если это действительно должно быть высокой производительности, то, конечно, кеширование лучше.

Просто введите в файл .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)