Является ли $_SERVER['REQUEST_SCHEME'] надежным?
Недавно я искал способ правильно определить протокол, по которому на сервер был передан URL-запрос.
Я смотрел сквозь parse_url()
и хотя $_SERVER
суперглобальная переменная, и нашел это:
<?php
header('Content-Type: text/plain');
print_r($_SERVER);
?>
Выход:
[REQUEST_SCHEME] => http
Однако я не смог найти его на php.net или в Google. Хотя я смог найти этот вопрос. Q # 1: если $_SERVER['REQUEST_SCHEME']
не было документировано, то, вероятно, это ненадежно, или ему можно доверять?
Я использую VC9 PHP 5.4.14 TS
под окнами для разработки. Но мое производство находится под Ubuntu. Q # 2: Это свойство также доступно в Ubuntu Linux?
7 ответов
Трудно доказать, что это надежно, но легко доказать, что это ненадежно (если бы я только мог привести случай, который не работает). И я могу доказать, что это ненадежно, потому что он не работает с IIS 7.0 + PHP 5.3
REQUEST_SCHEME
Переменная среды задокументирована на странице Apache mod_rewrite. Тем не менее, он не стал доступен до Apache 2.4.
У меня только Apache 2.2, поэтому я создал переменную окружения. Я добавил следующее в начало моего файла.htaccess.
RewriteEngine on
# Set REQUEST_SCHEME (standard environment variable in Apache 2.4)
RewriteCond %{HTTPS} off
RewriteRule .* - [E=REQUEST_SCHEME:http]
RewriteCond %{HTTPS} on
RewriteRule .* - [E=REQUEST_SCHEME:https]
Теперь я могу использовать
%{ENV:REQUEST_SCHEME}
в других переписать условия и правила$_SERVER['REQUEST_SCHEME']
в моем коде PHP
Мне не нужно делать дополнительные беспорядочные условные проверки везде, и мой PHP-код является совместимым с прямой пересылкой. Когда Apache обновлен, я могу изменить свой файл.htaccess.
Я не знаю, как бы вы применили это к среде Windows. Это, вероятно, не очень хорошее решение для распределенного кода, но оно хорошо подходит для моих нужд.
Поскольку эта переменная доступна не во всех версиях сервера, она не является надежной проверкой только ее. Вместо этого вы можете изменить свой PHP-код для проверки еще двух переменных среды сервера, которые также могут указывать на использование https, как показано ниже:
if ( (! empty($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] == 'https') ||
(! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ||
(! empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443') ) {
$server_request_scheme = 'https';
} else {
$server_request_scheme = 'http';
}
Как заметил toxalot, REQUEST_SCHEME является нативной переменной веб-сервера Apache начиная с его версии 2.4. В Apache 2.2 его нет (см. Серверные переменные Apache 2.2), а в Microsoft IIs 8.5 его также нет (см. Серверные переменные IIS 8.5). Естественно, если переменная не установлена сервером, PHP не будет включать ее в свой глобальный массив $_SERVER.
К счастью, для совместимости с кодами, основанными исключительно на проверке REQUEST_SCHEME, вы можете создать эту переменную в Apache 2.2, отредактировав все ваши файлы конфигурации хоста (httpd.conf, ssl.conf, 000-default.conf, vhosts.conf), добавив следующие строки:
# FOR HOSTS LISTENING AT PORT 80
SetEnvIf Request_Protocol ^HTTP/ REQUEST_SCHEME=http
# FOR HOSTS LISTENING AT PORT 443
SetEnvIf Request_Protocol ^HTTP/ REQUEST_SCHEME=https
Приведенный выше код предполагает использование одного виртуального хоста для каждого протокола (наилучшая практика в Apache - см. То и то).
Я тоже не мог найти ссылку на REQUEST_SCHEME
, но если вы хотите определить, был ли запрос сделан http:
или же https:
тогда вы можете использовать $_SERVER['HTTPS']
, которое устанавливается в непустое значение, если запрос был сделан https:
, Это задокументировано на сайте PHP здесь
В новой версии Nginx, установлен по умолчанию fastcgi_param REQUEST_SCHEME $scheme
,
Это значение зависит от вашего веб-сервера. Если вы используете nginx (v1.10), в файле /etc/nginx/fastcgi_params
Вы можете увидеть следующие строки:
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
Как правило, этого значения по умолчанию достаточно. Но возможно, что это не сработает, вы можете форсировать эти значения в вашем vhost:
include fastcgi_params;
fastcgi_param REQUEST_SCHEME https;
fastcgi_param HTTPS On;
Если вы используете Apache, вы можете посмотреть ответ toxalot
Интересно посмотреть, как WordPress решает эту проблему с помощью функции is_ssl(), которая использует переменную $_SERVER,
function is_ssl() {
if ( isset( $_SERVER['HTTPS'] ) ) {
if ( 'on' == strtolower( $_SERVER['HTTPS'] ) ) {
return true;
}
if ( '1' == $_SERVER['HTTPS'] ) {
return true;
}
} elseif ( isset( $_SERVER['SERVER_PORT'] ) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
return true;
}
return false;
}
Я использую это и думаю, что это лучший способ получить текущую схему
/**
* Is Secure?
* Determines if the application is accessed via an encrypted
* (HTTPS) connection.
*
* @return bool
*/
public static function isSecure()
{
if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') {
return true;
} elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https') {
return true;
} elseif (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') {
return true;
} elseif (isset($_SERVER['SERVER_PORT']) && intval($_SERVER['SERVER_PORT']) === 443) {
return true;
}
return false;
}
Определите эту функцию и проверьте ssl-соединение сервера, чтобы получить текущую схему
$scheme = isSecure() ? 'https' : 'http';
Усовершенствование предложения токсалота для пользователей CloudFlare:
RewriteEngine on
RewriteCond %{HTTPS} !on [OR]
RewriteCond %{HTTP:CF-Visitor} '"scheme":"http"'
RewriteRule .* - [E=REQUEST_SCHEME:http]
RewriteCond %{HTTPS} on [OR]
RewriteCond %{HTTP:CF-Visitor} '"scheme":"https"'
RewriteRule .* - [E=REQUEST_SCHEME:https]