$_SERVER['REQUEST_SCHEME'] 可靠吗?
Posted
技术标签:
【中文标题】$_SERVER[\'REQUEST_SCHEME\'] 可靠吗?【英文标题】:Is $_SERVER['REQUEST_SCHEME'] reliable?$_SERVER['REQUEST_SCHEME'] 可靠吗? 【发布时间】:2013-08-03 04:58:16 【问题描述】:我最近正在寻找一种方法来正确确定协议,根据该协议将 url 请求提供给服务器。
我查看了parse_url()
和$_SERVER
超全局变量,发现了这个:
<?php
header('Content-Type: text/plain');
print_r($_SERVER);
输出:
[REQUEST_SCHEME] => http
但是,我无法在 php.net 或 Google 上找到它。不过,我能够找到this 的问题。 Q#1:如果$_SERVER['REQUEST_SCHEME']
没有记录在案,那么它可能不可靠,或者可以信任?
我在 windows 下使用VC9 PHP 5.4.14 TS
进行开发。但是我的制作是在ubuntu下的。 Q#2: 这个属性在 ubuntu linux 下也可用吗?
【问题讨论】:
【参考方案1】:由于此变量并非在所有 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 自 2.4 版以来是 Apache Web 服务器的本机变量。 Apache 2.2 没有它(参见Apache 2.2 server variables),Microsoft IIs 8.5 也没有它(参见IIS 8.5 Server Variables)。当然,如果服务器没有设置变量,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 的最佳实践 - 请参阅 this 和 that)。
【讨论】:
在未定义REQUEST_SCHEME
环境变量时假设$server_request_scheme = 'http'
似乎不是一个好主意。此外,对于SetEnvIf Request_Protocol
,这不适用于监听两个端口的虚拟主机。
嗨@xhienne。关于 PHP 代码:其背后的想法不是强制定义 Web 服务器中自然存在的变量:相反,这里的目的是修复可能出现在不存在此环境变量的服务器中的问题!在这种情况下,您有一个定义的请求方案,但服务器不会“明确地”通知您(我的意思是,精确的字符串为“http”或“https”)。因此,当您想要的信息以另一个变量和不同的形式出现时,代码只是一个翻译器。
嗨,aldemarcalazans。对不起,我想,由于它的长度,我错过了你的 if 语句中的其他条件,只看到了 REQUEST_SCHEME 的测试。实际上,您的 PHP 代码看起来还不错。如果您不介意,您可以将那个长条件拆分为多行。谢谢。
完成:条件拆分。
在反向代理后面使用 Apache/2.4.25 (Debian) 和 php_fpm(https 在到达 apache 之前发生)我只是无法将 REQUEST_SCHEME 更改为 https - 似乎有其他东西迫使它回到 http(我可以看到它改变了订单变量显示在phpinfo()
但值保持 http【参考方案2】:
我正在使用它,我认为这是获取当前方案的最佳方式
/**
* 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';
【讨论】:
$_SERVER['SERVER_PROTOCOL']
包含类似于 HTTP/1.1
的内容,与您要比较的内容无关。
@cherouvim 返回Web服务器协议及其版本,我们可以通过这种方式检测url方案。是什么让您认为这个答案无关紧要?
服务器协议可以是HTTP/1.0
、HTTP/1.1
、HTTP 2.0
等,和https
相关的字符串比较如何?
@cherouvim 是的,可能是 https 的...我之前的答案适用于 Apache Web 服务器,但感谢您让我更新这篇文章,现在我编辑了生产就绪代码的答案,它的 codeigniter检查安全连接的实现。在上述方法中,所有可能性和网络服务器都被考虑在内,看起来非常可靠。希望有用
你完全改变了代码。您之前尝试从协议版本中扣除方案,这是不可行的。【参考方案3】:
看看 WordPress 如何通过使用 $_SERVER 变量的 is_ssl() 函数解决这个问题很有趣,
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;
【讨论】:
【参考方案4】:此值取决于您的网络服务器。如果您使用 nginx (v1.10),在文件 /etc/nginx/fastcgi_params
中您可以看到以下几行:
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
一般来说,这个默认值就足够了。 但它可能不起作用,您可以在您的虚拟主机中强制使用此值:
include fastcgi_params;
fastcgi_param REQUEST_SCHEME https;
fastcgi_param HTTPS On;
如果你使用 Apache,可以看看 toxalot 的回答
【讨论】:
【参考方案5】:加强 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]
【讨论】:
我应该补充一点,该标头是 JSON,从技术上讲,他们可以在冒号后添加空格并破坏该配置的逻辑,但我当然知道 Apache 不允许解析 JSON,而 Cloudflare 工作人员是可能知道人们在 JSON 中进行字符串匹配。有关 Cloudflare 特殊标头的更多信息:support.cloudflare.com/hc/en-us/articles/…【参考方案6】:在新版本的Nginx中,默认设置fastcgi_param REQUEST_SCHEME $scheme
。
【讨论】:
【参考方案7】:REQUEST_SCHEME
环境变量记录在 Apache mod_rewrite page 上。但是,它直到 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 环境中。对于分布式代码,这可能不是一个好的解决方案,但它可以很好地满足我的需求。
【讨论】:
【参考方案8】:很难证明它可靠,但证明它不可靠很容易(如果我能提供一个它不起作用的案例)。而且我可以证明它不可靠,因为它不适用于 IIS 7.0 + PHP 5.3
【讨论】:
谢谢。我使用PHP 5.4.17
制作的作品也没有显示。
Zend Server CE on Windows 也没有!
只是为了让谷歌知道:lighttpd
和 PHP 5.5.9
上也缺少它。
它也不适用于 Apache 2.2,在其“默认”配置中。
并且在反向代理后面(使用 apache 2.4 作为后端)似乎无法将其设置为 https【参考方案9】:
我也找不到对REQUEST_SCHEME
的引用,但如果您要确定请求是由http:
还是https:
提出的,那么您可以使用$_SERVER['HTTPS']
,它已设置如果https:
发出请求,则为非空值。它记录在 PHP 网站 here
【讨论】:
在某些情况下,$_SERvER['HTTPS']
给出非空值 (off
),表示未使用 HTTPS。在答案中链接的页面上了解更多信息。
@F-3000 感谢您的来信。这非常有用。
isset($_SERVER['HTTPS']) && 'on' === $_SERVER['HTTPS']
似乎是确定 https:// 的最安全方法以上是关于$_SERVER['REQUEST_SCHEME'] 可靠吗?的主要内容,如果未能解决你的问题,请参考以下文章
PHP:$_SERVER 变量:$_SERVER['HTTP_HOST'] vs $_SERVER['SERVER_NAME'] [重复]
__FILE__ $_SERVER['PHP_SELF'] $_SERVER['SCRIPT_NAME'] $_SERVER['SCRIPT_FILEN