Как узнать, используете ли вы HTTPS без $_SERVER ['HTTPS']
Я видел много обучающих онлайн, в которых говорится, что вам нужно проверить $_SERVER['HTTPS']
, если соединение с сервером защищено HTTPS. Моя проблема в том, что на некоторых серверах, которые я использую, $_SERVER['HTTPS']
является переменной undefined, которая приводит к ошибке. Есть ли другая переменная, которую я могу проверить, которая всегда должна быть определена?
Чтобы быть ясным, в настоящее время я использую этот код для разрешения, если это HTTPS-соединение:
if(isset($_SERVER['HTTPS'])) {
if ($_SERVER['HTTPS'] == "on") {
$secure_connection = true;
}
}
Ответы
Ответ 1
Это всегда должно работать, даже когда $_SERVER['HTTPS']
не определено:
function isSecure() {
return
(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| $_SERVER['SERVER_PORT'] == 443;
}
Код совместим с IIS.
Из документации по PHP.net и комментариев пользователей :
1) Установите непустое значение, если скрипт запрашивался по протоколу HTTPS.
2) Обратите внимание, что при использовании ISAPI с IIS значение будет "выключено", если запрос не был сделан через протокол HTTPS. (О том же поведении сообщалось для IIS7, выполняющего PHP как приложение Fast-CGI).
Кроме того, серверы Apache 1.x (и неработающие установки) могут не определять $_SERVER['HTTPS']
даже при безопасном подключении. Хотя это и не гарантировано, соединения через порт 443, согласно соглашению, скорее всего, используют безопасные сокеты, поэтому необходима дополнительная проверка порта.
Дополнительное примечание: если есть балансировщик нагрузки между клиентом и вашим сервером, этот код проверяет не соединение между клиентом и балансировщиком нагрузки, а соединение между балансировщиком нагрузки и вашим сервером. Чтобы протестировать предыдущее соединение, вы должны протестировать, используя заголовок HTTP_X_FORWARDED_PROTO
, но сделать это гораздо сложнее; см. последние комментарии ниже этого ответа.
Ответ 2
Мое решение (поскольку стандартные условия [$ _SERVER ['HTTPS'] == 'on'] не работают на серверах за балансировщиком нагрузки):
$isSecure = false;
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
$isSecure = true;
}
elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
$isSecure = true;
}
$REQUEST_PROTOCOL = $isSecure ? 'https' : 'http';
HTTP_X_FORWARDED_PROTO: фактический стандарт для идентификации исходного протокола HTTP-запроса, поскольку обратный прокси (балансировщик нагрузки) может связываться с веб-сервером с использованием HTTP, даже если запрос на обратный прокси-сервер является HTTPS
http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Common_non-standard_request_headers
Ответ 3
Chacha в соответствии с документацией PHP: "Задайте непустое значение, если запрос script был запрошен через протокол HTTPS". Таким образом, оператор if будет возвращать false во многих случаях, когда HTTPS действительно включен. Вы хотите убедиться, что $_SERVER['HTTPS']
существует и не является пустым. В случаях, когда HTTPS неправильно настроен для заданного сервера, вы можете попробовать проверить, есть ли $_SERVER['SERVER_PORT'] == 443
.
Но обратите внимание, что некоторые серверы также будут устанавливать $_SERVER['HTTPS']
на непустое значение, поэтому обязательно проверьте эту переменную.
Ссылка: Документация для $_SERVER
и $HTTP_SERVER_VARS
[устарела]
Ответ 4
Это также работает, когда $_SERVER['HTTPS']
не определен
if( (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443 ){
//enable secure connection
}
Ответ 5
У меня только что была проблема, когда я запускал сервер с помощью Apache mod_ssl, но phpinfo() и var_dump ($ _SERVER) показали, что PHP все еще думает, что я на порту 80.
Вот мой способ обхода любого, у кого есть такая же проблема....
<VirtualHost *:443>
SetEnv HTTPS on
DocumentRoot /var/www/vhost/scratch/content
ServerName scratch.example.com
</VirtualHost>
Стоит отметить строку SetEnv. После этого на месте и после перезапуска вы должны иметь переменную окружения HTTPS, о которой вы всегда мечтали
Ответ 6
Если вы используете Apache, вы всегда можете рассчитывать на
$_SERVER["REQUEST_SCHEME"]
чтобы проверить схему запрашиваемого URL. Но, как упоминалось в других ответах, разумно проверять другие параметры, прежде чем считать, что SSL действительно используется.
Ответ 7
Превращение моей функции из чтения всех предыдущих сообщений:
public static function isHttps()
{
if (array_key_exists("HTTPS", $_SERVER) && 'on' === $_SERVER["HTTPS"]) {
return true;
}
if (array_key_exists("SERVER_PORT", $_SERVER) && 443 === (int)$_SERVER["SERVER_PORT"]) {
return true;
}
if (array_key_exists("HTTP_X_FORWARDED_SSL", $_SERVER) && 'on' === $_SERVER["HTTP_X_FORWARDED_SSL"]) {
return true;
}
if (array_key_exists("HTTP_X_FORWARDED_PROTO", $_SERVER) && 'https' === $_SERVER["HTTP_X_FORWARDED_PROTO"]) {
return true;
}
return false;
}
Ответ 8
РЕАЛЬНЫЙ ответ: готов к копированию в скрипт [config]
/* configuration settings; X=edit may 10th '11 */
$pv_sslport=443; /* for it might be different, as also Gabriel Sosa stated */
$pv_serverport=80; /* X */
$pv_servername="mysite.com"; /* X */
/* X appended after correction by Michael Kopinsky */
if(!isset($_SERVER["SERVER_NAME"]) || !$_SERVER["SERVER_NAME"]) {
if(!isset($_ENV["SERVER_NAME"])) {
getenv("SERVER_NAME");
// Set to env server_name
$_SERVER["SERVER_NAME"]=$_ENV["SERVER_NAME"];
}
}
if(!$_SERVER["SERVER_NAME"]) (
/* X server name still empty? ... you might set $_SERVER["SERVER_NAME"]=$pv_servername; */
}
if(!isset($_SERVER["SERVER_PORT"]) || !$_SERVER["SERVER_PORT"]) {
if(!isset($_ENV["SERVER_PORT"])) {
getenv("SERVER_PORT");
$_SERVER["SERVER_PORT"]=$_ENV["SERVER_PORT"];
}
}
if(!$_SERVER["SERVER_PORT"]) (
/* X server port still empty? ... you might set $_SERVER["SERVER_PORT"]=$pv_serverport; */
}
$pv_URIprotocol = isset($_SERVER["HTTPS"]) ? (($_SERVER["HTTPS"]==="on" || $_SERVER["HTTPS"]===1 || $_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://") : (($_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://");
$pv_URIprotocol
теперь корректен и готов к использованию; Пример $site=$pv_URIprotocol.$_SERVER["SERVER_NAME"]
. Естественно, что строка также может быть заменена TRUE и FALSE. PV означает PortalPress Variable, поскольку это прямая копия-паста, которая всегда будет работать. Эта часть может использоваться в сценарии производства.
Ответ 9
Я не думаю, что добавление порта - хорошая идея - особенно когда у вас много серверов с разными сборками. это просто добавляет еще одну вещь, которую нужно помнить, чтобы ее изменить. глядя на документ. Думаю, последняя линия кайзеров неплоха, так что:
if(!empty($_SERVER["HTTPS"]))
if($_SERVER["HTTPS"]!=="off")
return 1; //https
else
return 0; //http
else
return 0; //http
кажется вполне достаточно.
Ответ 10
Единственным надежным методом является метод, описанный Игорем М.
$pv_URIprotocol = isset($_SERVER["HTTPS"]) ? (($_SERVER["HTTPS"]==="on" || $_SERVER["HTTPS"]===1 || $_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://") : (($_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://");
Рассмотрим следующее:
Вы используете nginx с fastcgi, по умолчанию (debian, ubuntu) fastgi_params содержат директиву:
fastcgi_param HTTPS $https;
если вы НЕ используете SSL, он переводится как пустое значение, а не 'off', а не 0
и вы обречены.
http://unpec.blogspot.cz/2013/01/nette-nginx-php-fpm-redirect.html
Ответ 11
Я нахожу эти параметры приемлемыми, а также, скорее всего, не имеют ложных срабатываний при переключении веб-серверов.
Ответ 12
Самый короткий путь, который я использую:
$secure_connection = !empty($_SERVER['HTTPS']);
Если используется https, то $secure_connection истинно.
Ответ 13
Вы можете проверить $_SERVER['SERVER_PORT']
, поскольку SSL обычно работает на порту 443, но это не является надежным.
Ответ 14
Что вы думаете об этом?
if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')
$scheme = 'https';
else
$scheme = 'http';
Ответ 15
На моем сервере (Ubuntu 14.10, Apache 2.4, php 5.5) переменная $_SERVER['HTTPS']
не устанавливается, когда PHP скрипт загружается через https. Я не знаю, что не так. Но следующие строки в файле .htaccess
исправить эту проблему:
RewriteEngine on
RewriteCond %{HTTPS} =on [NC]
RewriteRule .* - [E=HTTPS:on,NE]
Ответ 16
Вот многократно используемая функция, которую я использовал некоторое время. НТН.
Примечание. Значение HTTPS_PORT (которое является пользовательской константой в моем коде) может варьироваться в зависимости от вашего окружения, например, оно может быть 443 или 81.
/**
* Determine if this is a secure HTTPS connection
*
* @return bool True if it is a secure HTTPS connection, otherwise false.
*/
function isSSL()
{
if (isset($_SERVER['HTTPS'])) {
if ($_SERVER['HTTPS'] == 1) {
return true;
} elseif ($_SERVER['HTTPS'] == 'on') {
return true;
}
} elseif ($_SERVER['SERVER_PORT'] == HTTPS_PORT) {
return true;
}
return false;
}
Ответ 17
только для интереса, хром канарейка в данный момент посылает
HTTPS : 1
на сервере и в зависимости от того, как настроен сервер, может означать, что вы вернетесь к следующему
HTTPS : 1, on
Это нарушило наше приложение, потому что мы тестировали if on, чего, очевидно, нет.
На данный момент кажется, что это только хром канарейка, но стоит отметить, что вещи у канарейки обычно попадают в "нормальный" хром через некоторое время.
Ответ 18
Если вы используете nginx в качестве системы балансировки, проверьте $_SERVER ['HTTP_HTTPS'] == 1 другие проверки будут сбой для ssl.
Ответ 19
$secure_connection = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || (!empty($_SERVER['HTTP_HTTPS']) && $_SERVER['HTTP_HTTPS'] != 'off') || $_SERVER['REQUEST_SCHEME'] == 'https' || $_SERVER['SERVER_PORT'] == 443) ? true : false;
Код проверяет все возможное и работает также на веб-сервере IIS. Chrome, так как v44 не устанавливает заголовок HTTP: 1, поэтому проверка HTTP_HTTPS в порядке. Если этот код не соответствует https, это означает, что ваш веб-сервер или прокси-сервер плохо настроены. Apache сам устанавливает флаг HTTPS правильно, но может возникнуть проблема при использовании прокси-сервера (например, nginx). Вы должны установить некоторый заголовок в виртуальном хосте nginx https
proxy_set_header X-HTTPS 1;
и используйте некоторый модуль Apache, чтобы правильно установить флаг HTTPS, ища X-HTTPS из прокси. Найдите mod_fakessl, mod_rpaf и т.д.
Ответ 20
Если вы используете балансировщик нагрузки Incapsula, вам нужно использовать IRule для создания настраиваемого заголовка для вашего сервера. Я создал заголовок HTTP_X_FORWARDED_PROTO, который равен либо "http", если для порта установлено значение 80 и "https", если оно равно 443.
Ответ 21
Я бы добавил глобальный фильтр, чтобы гарантировать, что все, что я проверю, правильно,
function isSSL() {
$https = filter_input(INPUT_SERVER, 'HTTPS');
$port = filter_input(INPUT_SERVER, 'SERVER_PORT');
if ($https) {
if ($https == 1) {
return true;
} elseif ($https == 'on') {
return true;
}
} elseif ($port == '443') {
return true;
}
return false;
}
Ответ 22
У меня есть еще один шаг вперед и определить, поддерживает ли сайт, с которым я подключаюсь, SSL (один проект запрашивает у пользователя их URL-адрес, и нам нужно проверить, что они установили наш пакет API на сайте http или https).
Здесь функция, которую я использую, - в основном, просто вызывайте URL через cURL, чтобы увидеть, работает ли https!
function hasSSL($url)
{
// take the URL down to the domain name
$domain = parse_url($url, PHP_URL_HOST);
$ch = curl_init('https://' . $domain);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD'); //its a HEAD
curl_setopt($ch, CURLOPT_NOBODY, true); // no body
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // in case of redirects
curl_setopt($ch, CURLOPT_VERBOSE, 0); //turn on if debugging
curl_setopt($ch, CURLOPT_HEADER, 1); //head only wanted
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // we dont want to wait forever
curl_exec($ch);
$header = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($header === 200) {
return true;
}
return false;
}
Это самый надежный способ, который я нашел, чтобы не только узнать, используете ли вы https (как задает вопрос), но если вы МОЖЕТЕ (или даже ДОЛЖНЫ) использовать https.
ПРИМЕЧАНИЕ: возможно (хотя и не очень вероятно...), что на сайте могут быть разные страницы http и https (поэтому, если вам говорят использовать http, возможно, вам не нужно менять..) Подавляющее большинство сайтов одинаковы и, вероятно, должны перенаправить вас сами, но эта дополнительная проверка имеет смысл (конечно, как я уже сказал, в проекте, где пользователь вводит информацию своего сайта, и вы хотите убедиться на стороне сервера)
Ответ 23
Вот как я нахожу решение этого
$https = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') === 0 ||
!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0;
return ($https) ? 'https://' : 'http://';
Ответ 24
Я использовал основное предложение здесь и был раздражен "Уведомлением PHP" в журналах, когда HTTPS не был установлен. Вы можете избежать этого, используя объединяющий нуль оператор "??":
if( ($_SERVER['HTTPS'] ?? 'off') == 'off' ) {
// redirect
}
(Примечание: недоступно до php v7)
Ответ 25
Как и сообщение hobodave: "Задайте непустое значение, если запрос script был запрошен через протокол HTTPS".
if (!empty($_SERVER['HTTPS']))
{
$secure_connection = true;
}