如何找出如果你'正在使用HTTPS没有$_SERVER[' https:// ']

我在网上看到过很多教程,说你需要检查$_SERVER['HTTPS'],如果服务器连接是HTTPS安全的。我的问题是,在我使用的一些服务器上,$_SERVER['HTTPS']是一个未定义的变量,会导致错误。是否有另一个变量我可以检查,总是应该定义?

只是为了清楚一点,我目前正在使用这段代码来解决它是否是一个HTTPS连接:

if(isset($_SERVER['HTTPS'])) {
if ($_SERVER['HTTPS'] == "on") {
$secure_connection = true;
}
}
283020 次浏览

你可以检查$_SERVER['SERVER_PORT'],因为SSL通常运行在端口443上,但这不是万无一失的。

Chacha,根据PHP文档:“如果通过HTTPS协议查询脚本,则设置为非空值。”你的if语句在很多HTTPS打开的情况下会返回false。你需要验证$_SERVER['HTTPS']是否存在且非空。在没有为给定服务器正确设置HTTPS的情况下,您可以尝试检查$_SERVER['SERVER_PORT'] == 443. conf是否正确。

但请注意,一些服务器也会将$_SERVER['HTTPS']设置为非空值,所以一定要检查这个变量。

参考:__ABC0和$HTTP_SERVER_VARS的文档[已弃用]

根据hobodave的帖子:“如果通过HTTPS协议查询脚本,则设置为非空值。”

if (!empty($_SERVER['HTTPS']))
{
$secure_connection = true;
}

即使$_SERVER['HTTPS']未定义,这也应该始终有效:

function isSecure() {
return
(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| $_SERVER['SERVER_PORT'] == 443;
}

该代码与IIS兼容。

PHP.net文档和用户注释:

  1. 如果通过HTTPS协议查询,请设置为非空值。

  2. 注意,当ISAPI与IIS一起使用时,该值将是"off"如果请求不是通过HTTPS协议发出的。(同样的行为也被报道为IIS7将PHP作为Fast-CGI应用程序运行)。

还有Apache 1。x服务器(和损坏的安装)可能没有定义$_SERVER['HTTPS'],即使安全连接。虽然不保证,但端口443上的连接通过公约很可能使用安全套接字,因此需要进行额外的端口检查。

另外注意:如果在客户端和服务器之间有一个负载均衡器,这段代码不会测试客户端和负载均衡器之间的连接,而是测试负载均衡器和服务器之间的连接。要测试前一个连接,你必须使用HTTP_X_FORWARDED_PROTO头进行测试,但这要复杂得多;参见答案下面的最新评论

真正的答案:准备复制粘贴到一个[配置]脚本

/* 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变量,因为它是一个总是工作的直接复制粘贴。可以在产品脚本中使用此片段。

我刚刚有一个问题,我正在使用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环境变量

我不认为添加一个端口是一个好主意——特别是当你有很多不同版本的服务器时。这只是增加了一个要记住改变的东西。看医生的,我认为最后一行kaisers很好,所以:

if(!empty($_SERVER["HTTPS"]))
if($_SERVER["HTTPS"]!=="off")
return 1; //https
else
return 0; //http
else
return 0; //http

看起来很完美。

唯一可靠的方法是Igor M。

$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://");
< p >考虑以下: 你正在使用nginx的fastcgi,默认情况下(debian, ubuntu) fastgi_params包含指令:

fastcgi_param HTTPS

如果你没有使用SSL,它将被转换为空值,而不是'off',而不是0

http://unpec.blogspot.cz/2013/01/nette-nginx-php-fpm-redirect.html

我的解决方案(因为标准条件[$_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与web服务器通信,即使对反向代理的请求是HTTPS http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Common_non-standard_request_headers < / p >

我发现这些参数也是可以接受的,而且在切换web服务器时更可能不会出现误报。

  1. $ _SERVER(“HTTPS_KEYSIZE”)
  2. $ _SERVER(“HTTPS_SECRETKEYSIZE”)
  3. $ _SERVER(“HTTPS_SERVER_ISSUER”)
  4. < p > $ _SERVER(“HTTPS_SERVER_SUBJECT”)

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

我使用的最短方法:

$secure_connection = !empty($_SERVER['HTTPS']);

如果使用https,则$secure_connection为真。

这是一个我已经使用了一段时间的可重用函数。HTH。

注意: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;
}

你觉得这个怎么样?

if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')
$scheme = 'https';
else
$scheme = 'http';

在我的服务器(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]

只是出于兴趣,铬金丝雀目前发送

HTTPS : 1

发送到服务器,这取决于服务器的配置方式,可能意味着您将返回以下内容

HTTPS : 1, on
这破坏了我们的应用程序,因为我们正在测试是否打开,显然它不是。 目前,只有铬金丝雀似乎可以做到这一点,但值得注意的是,金丝雀的东西通常会在“正常”铬上降落

如果你使用nginx作为负载均衡系统检查$_SERVER['HTTP_HTTPS'] == 1其他检查将失败ssl。

这在$_SERVER['HTTPS']未定义时也适用

if( (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443 ){
//enable secure connection
}

如果你正在使用Apache,你可以一直依赖它

$_SERVER["REQUEST_SCHEME"]

验证所请求URL的方案。但是,正如在其他回答中提到的,在假设真的使用SSL之前,验证其他参数是谨慎的。

如果您正在使用Incapsula的负载均衡器,则需要使用IRule为您的服务器生成自定义报头。我创建了一个HTTP_X_FORWARDED_PROTO头,等于“http”,如果端口设置为80和“https”,如果它等于443。

$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 web服务器上工作。Chrome自v44不设置头HTTP: 1,所以检查HTTP_HTTPS是OK的。如果这段代码不匹配https,这意味着您的web服务器或代理服务器配置不佳。Apache本身设置HTTPS标志正确,但当你使用代理(例如nginx)时可能会有问题。你必须在nginx https虚拟主机中设置一些头文件

proxy_set_header   X-HTTPS 1;

并使用一些Apache模块通过从代理中查找X-HTTPS来正确设置HTTPS标志。搜索mod_fakessl, mod_rpaf等。

我会添加一个全局过滤器,以确保我检查的所有内容都是正确的;

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;
}

从阅读之前的所有帖子中创建自己的函数:

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;
}

我有机会进一步确定我要连接的网站是否具有SSL能力(一个项目要求用户提供他们的URL,我们需要验证他们已经在http或https网站上安装了我们的API包)。

这是我使用的函数-基本上,只是通过cURL调用URL,看看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,也许你不需要改变..)绝大多数网站都是一样的,可能需要重新路由你自己,但这个额外的检查是有用处的(当然,就像我说的,在用户输入他们的网站信息的项目中,你想从服务器端确保)

这就是我解决这个问题的方法

$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://';

我使用了这里的主要建议,当没有设置HTTPS时,日志中的“PHP通知”让我很恼火。你可以通过使用空合并操作符 "??":

if( ($_SERVER['HTTPS'] ?? 'off') == 'off' ) {
// redirect
}

(注意:在php v7之前不可用)

如果你不能控制web服务器&不知道已经设置了哪些变量,上传这个PHP来找出:

<?php
echo "<br>1 ".$_SERVER["HTTPS"];
echo "<br>2 ".$_SERVER["SERVER_PORT"];
echo "<br>3 ".$_SERVER["HTTP_X_FORWARDED_PROTO"];
echo "<br>4 ".$_SERVER["HTTP_X_FORWARDED_SSL"];
echo "<br>5 ".$_SERVER["HTTP_HTTPS"];
echo "<br>6 ".$_SERVER["REQUEST_SCHEME"];
?>


<html>
<body>
<br>
Just cruising
</body>
</html>

我知道这个答案有点晚了,但我把一堆答案结合起来,做了一个适用于所有用例的简单函数。

试试这个:

function is_ssl(){
if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO']=="https"){ return true; }
elseif(isset($_SERVER['HTTPS'])){ return true; }
elseif($_SERVER['SERVER_PORT'] == 443){ return true; }
else{ return false; }
}

然后使用if,例如:

if(is_ssl()){
// WHAT TO DO IF IT IS SSL / HTTPS
}else{
// WHAT TO DO IF IT IS NOT SSL / HTTPS
}

此代码适用于Cloudflare,共享主机提供商等。

享受。

我的系统使用cloudflare。我必须访问$_SERVER['HTTP_CF_VISITOR']值。

$isSsl = false;
if (isset($_SERVER['HTTP_CF_VISITOR'])) {
$cfDecode = json_decode($_SERVER['HTTP_CF_VISITOR']);
if (!empty($cfDecode) && !empty($cfDecode->scheme) && $cfDecode->scheme == 'https') {
$isSsl = true;
}
}
var_dump($isSsl);