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

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

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

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

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

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

Куда меня завели мои исследования:

  1. Apache.
    In my opinion Apache has a very quirky approach, since it sets the REDIRECT_SCRIPT_URI header for rewrote URLs, but not for the ones that are not rewrote.
    E.g.

    http://host/ana/are/mere
    would be re-wrote to index.php so the aforementioned header would be present, but
    http://host/
    wouldn't be re-wrote.

  2. Lighttpd.
    Lighttpd с fast-cgi ведет себя нормально, устанавливая заголовок REDIRECT_URI, если для текущего хоста включена перезапись URL. Это надежно.

  3. Cherokee.
    Ну, для Cherokee нет способа, который я обнаружил, так как он использует (на мой взгляд) более сложный метод получения перезаписи URL. (т. е. это называется внутренним перенаправлением, и процесс fcgi не знает, что запрос был перенаправлен)

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


person Marius Or.    schedule 05.07.2009    source источник


Ответы (5)


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

person merkuro    schedule 05.07.2009

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

  1. Настроить перенаправление

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

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

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


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

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

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

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

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

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

person Jasper    schedule 25.12.2012
comment
Хорошее решение. Если бы это было реализовано правильно, это было бы независимым от используемого веб-сервера. - person Luke Mills; 28.12.2012

PHP имеет специфические для сервера функции для серверов 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 - реализовать, а затем протестировать его в сценарии. Я считаю, что это единственный способ получить хороший результат.

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

person Al.    schedule 10.08.2009
comment
Да, спасибо за ответ. Я совершенно забыл о специфических функциях Apache. - person Marius Or.; 10.08.2009
comment
Отличное решение для Apache. Я думал в том же направлении. - person Prathik Rajendran M; 30.12.2012

Вы можете программно проверить наличие 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.

Существует не так много последовательных методов, которые будут работать на всех комбинациях платформ. Но поскольку результат непротиворечив, вы можете проверить это. Настройте специальное перенаправление и пусть скрипт использует cURL PHP или file_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');

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

person Jordan Mack    schedule 28.12.2012
comment
apache_get_modules() не работает, если вы используете PHP как CGI. - person Salman A; 31.12.2012

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

Просто поместите что-то вроде следующего в ваш файл .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) 
person Hugo Delsing    schedule 28.12.2012
comment
Также сделайте запрос HEAD. hakre.wordpress.com/2011/09/17 /head-first-with-php-streams, также содержит ссылки на связанные вопросы - person hakre; 28.12.2012
comment
Обновлено. Я не уверен, что sscanf быстрее/лучше, поэтому я не менял его. - person Hugo Delsing; 28.12.2012