$ _SERVER ['REQUEST_SCHEME']可靠吗?

时间:2013-08-02 03:10:13

标签: php url-parsing

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

我通过parse_url()$_SERVER超全局变量进行了观察,发现了这一点:

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

print_r($_SERVER);
?>

输出:

  

[REQUEST_SCHEME] =&gt; HTTP

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

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

9 个答案:

答案 0 :(得分: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}
  • 我的PHP代码中的
  • $_SERVER['REQUEST_SCHEME']

我不需要在任何地方进行额外的杂乱条件检查,而且我的PHP代码是向前兼容的。当Apache升级时,我可以更改我的.htaccess文件。

我不知道您如何将其应用于Windows环境。这可能不是分布式代码的好解决方案,但它可以很好地满足我的需求。

答案 1 :(得分:33)

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

答案 2 :(得分:8)

由于此变量并非在所有服务器版本中都可用,因此仅对其进行可靠测试。 相反,您可以更改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将不会将其包含在其全局中) array $ _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)。

答案 3 :(得分:7)

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

答案 4 :(得分:5)

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

答案 5 :(得分: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]

答案 6 :(得分: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的答案

答案 7 :(得分:1)

有趣的是,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;
}

答案 8 :(得分:0)

我正在使用它,我认为这是获得当前方案的最佳方法

window.configure(background=SOMECOLOR(e.g:'black'))

定义此功能并检查服务器ssl连接以获取当前方案

    /**
     * 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;
    }