我在网上看到过很多教程,说你需要检查$_SERVER['HTTPS'],如果服务器连接是HTTPS安全的。我的问题是,在我使用的一些服务器上,$_SERVER['HTTPS']是一个未定义的变量,导致错误。是否有另一个变量我可以检查,总是应该定义?
只是为了清楚一点,我目前正在使用这段代码来解决它是否是一个HTTPS连接:
if(isset($_SERVER['HTTPS'])) {
if ($_SERVER['HTTPS'] == "on") {
$secure_connection = true;
}
}
这应该总是工作,即使$_SERVER['HTTPS']是未定义的:
function isSecure() {
return
(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| $_SERVER['SERVER_PORT'] == 443;
}
该代码与IIS兼容。
根据PHP.net文档和用户评论:
如果通过HTTPS协议查询脚本,请设置为非空值。
注意,当ISAPI与IIS一起使用时,如果请求不是通过HTTPS协议发出的,则该值将为“off”。(同样的行为也被报道为IIS7将PHP作为Fast-CGI应用程序运行)。
还有Apache 1。x服务器(和损坏的安装)可能没有定义$_SERVER['HTTPS'],即使安全连接。尽管不能保证,但按照惯例,端口443上的连接可能使用安全套接字,因此需要进行额外的端口检查。
另外注意:如果在客户端和服务器之间有一个负载均衡器,这段代码不会测试客户端和负载均衡器之间的连接,而是测试负载均衡器和服务器之间的连接。要测试前一个连接,你必须使用HTTP_X_FORWARDED_PROTO头进行测试,但这要复杂得多;请看这个答案下面的最新评论。
唯一可靠的方法是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://");
考虑以下:
你在使用nginx的fastcgi,默认情况下(debian, ubuntu) fastgi_params包含指令:
快进HTTPS $ 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
$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等。
我有机会进一步确定我要连接的网站是否具有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,也许你不需要改变..)绝大多数网站都是一样的,可能需要重新路由你自己,但这个额外的检查是有用处的(当然,就像我说的,在用户输入他们的网站信息的项目中,你想从服务器端确保)
我知道这个答案有点晚了,但我把一堆答案结合起来,做了一个适用于所有用例的简单函数。
试试这个:
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,共享主机提供商等。
享受。