Как узнать, используете ли вы 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

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

  • $_ SERVER [ 'HTTPS_KEYSIZE']
  • $_ SERVER [ 'HTTPS_SECRETKEYSIZE']
  • $_ SERVER [ 'HTTPS_SERVER_ISSUER']
  • $_ SERVER [ 'HTTPS_SERVER_SUBJECT']

    if($_SERVER['HTTPS_KEYSIZE'] != NULL){/*do foobar*/}
    

Ответ 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;
}