$_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.0HTTP/1.1HTTP 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 也没有! 只是为了让谷歌知道:lighttpdPHP 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']) &amp;&amp; '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

PHP_$_SERVER_说明详解

$_SERVER

PHP $_SERVER 常用命令

PHP $_SERVER详解