$ _SERVER ['REQUEST_SCHEME']可靠吗?

问题描述 投票:33回答:8

我最近正在寻找一种方法来正确地确定协议,在该协议下,url请求被提供给服务器。

我通过parse_url()$_SERVER超全球变量观察,发现了这个:

<?php
header('Content-Type: text/plain');

print_r($_SERVER);
?>

输出:

[REQUEST_SCHEME] => http

但是,我无法在php.net或Google上找到它。虽然,我能够找到this问题。问题1:如果没有记录$_SERVER['REQUEST_SCHEME'],那么它可能不可靠,或者它可以被信任?

我在windows下使用VC9 PHP 5.4.14 TS进行开发。但我的生产是在ubuntu下。问题2:这个属性在ubuntu linux下也可用吗?

php url-parsing
8个回答
33
投票

很难证明它是可靠的,但很容易证明它不可靠(如果我能提供一个它不起作用的情况)。我可以证明它不可靠,因为它不适用于IIS 7.0 + PHP 5.3


51
投票

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环境。对于分布式代码而言,这可能不是一个好的解决方案,但它可以很好地满足我的需求。


10
投票

由于此变量在所有服务器版本中都不可用,因此仅对其进行可靠性测试。相反,您可以更改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是Apache Web服务器自2.4版以来的本机变量。 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

上面的代码假定每个协议使用一个vhost(Apache中的最佳实践 - 请参阅thisthat)。


7
投票

我也找不到对REQUEST_SCHEME的引用,但是如果你想确定请求是由http:还是https:做出来的,那么你可以使用$_SERVER['HTTPS'],如果提出请求则设置为非空值通过https:。它记录在PHP网站here


5
投票

在新版本的Nginx中,默认设置为fastcgi_param REQUEST_SCHEME $scheme


2
投票

增强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]

2
投票

此值取决于您的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的答案


1
投票

看看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;
}
© www.soinside.com 2019 - 2024. All rights reserved.