我最近正在寻找一种方法来正确确定协议,根据该协议向服务器提供 url 请求。
我观察了parse_url()
,虽然$_SERVER
超全局变量,发现了这个:
<?php
header('Content-Type: text/plain');
print_r($_SERVER);
输出:
[REQUEST_SCHEME] => http
但是,我无法在 php.net 或谷歌上找到它。不过,我能够找到这个问题。问#1:如果没有记录$_SERVER['REQUEST_SCHEME']
,那么它可能不可靠,或者它可以信任?
我正在使用 Windows 下的VC9 PHP 5.4.14 TS
进行开发。但我的生产是在 ubuntu 下进行的。问#2:此属性在 ubuntu Linux 下也可用吗?
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环境中。对于分布式代码来说,这可能不是一个很好的解决方案,但它非常适合我的需求。
很难证明它是可靠的,但很容易证明它不可靠(如果我能提供一个它不起作用的情况(。我可以证明它是不可靠的,因为它不适用于IIS 7.0 + PHP 5.3
由于此变量并非在所有 Web 服务器版本中都可用,因此仅对其进行测试并不可靠。相反,您可以更改 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是ApacheWeb服务器自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
.
此值取决于您的 Web 服务器。如果您使用 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';
增强 toxalot 对 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]