Is $_SERVER['REQUEST_SCHEME'] reliable?

心已入冬 提交于 2019-11-27 12:45:31

问题


I recently was seeking a way to properly determine protocol, under which url request was supplied to the server.

I watched through parse_url() and though $_SERVER superglobal variable, and found this:

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

print_r($_SERVER);
?>

Output:

[REQUEST_SCHEME] => http

However, I was unable to find it on php.net or Google. Though, I was able to find this question. Q#1: If $_SERVER['REQUEST_SCHEME'] wasn't documented, then it is probably unreliable, or it can be trusted?

I'am using VC9 PHP 5.4.14 TS under windows for development. But my production is under ubuntu. Q#2: Is this property also availible under ubuntu linux too?


回答1:


It is hard to prove that it is reliable, but it is easy to prove that it is not reliable (if only I could provide a case which it does not work). And I can prove that it is unreliable because it does not work with IIS 7.0 + PHP 5.3




回答2:


The REQUEST_SCHEME environment variable is documented on the Apache mod_rewrite page. However, it didn't become available until Apache 2.4.

I only have Apache 2.2 so I created an environment variable. I added the following to the top of my .htaccess file.

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]

Now I can use

  • %{ENV:REQUEST_SCHEME} in other rewrite conditions and rules
  • $_SERVER['REQUEST_SCHEME'] in my PHP code

I don't have to do extra messy conditional checks everywhere, and my PHP code is forward compatible. When Apache is upgraded, I can change my .htaccess file.

I don't know how you'd apply this to a Windows environment. This is probably not a good solution for distributed code, but it works well for my needs.




回答3:


As this variable is not available in all server versions, it is not reliable testing only it. Instead, you can change your PHP code to test two more server environment variables, which can also indicate that https is being used, as below:

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';
}

As remarked by toxalot, REQUEST_SCHEME is a native variable of Apache web server since its version 2.4. Apache 2.2 does not have it (see Apache 2.2 server variables) and Microsoft IIs 8.5 does not have it either (see IIS 8.5 Server Variables). Naturally, if a variable is not set by the server, PHP will not include it in its global array $_SERVER.

Fortunately, for compatibility with codes based exclusively on REQUEST_SCHEME checking, you can create this variable in Apache 2.2 editing all your host configuration files (httpd.conf, ssl.conf, 000-default.conf, vhosts.conf), adding the following lines:

# 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

The code above presume the use of one vhost for every protocol (a best practice in Apache - see this and that).




回答4:


I, too, couldn't find a reference to REQUEST_SCHEME, but if you're looking to determine whether a request was made by http: or https: then you can use $_SERVER['HTTPS'], which is set to a non-empty value if a request was made by https:. It's documented on the PHP site here




回答5:


In new version Nginx, set by default fastcgi_param REQUEST_SCHEME $scheme.




回答6:


This value depends on your web-server. If you use nginx (v1.10), in file /etc/nginx/fastcgi_params you can see this following lines :

fastcgi_param  REQUEST_SCHEME     $scheme; 
fastcgi_param  HTTPS              $https if_not_empty;

Generally, this default values are sufficient. But it is possible that it does not work, you can force this values in your vhost :

include fastcgi_params;
fastcgi_param  REQUEST_SCHEME     https; 
fastcgi_param  HTTPS              On;

If you use Apache, you can take a look toxalot's answer




回答7:


Enhancing toxalot's suggestion for CloudFlare users:

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]



回答8:


Its interesting to see how WordPress resolves this issue with its is_ssl() function which makes use of $_SERVER variable,

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



回答9:


I'm using this and i think it's best way to get the current scheme

        $protocol = stripos($_SERVER['SERVER_PROTOCOL'], 'https') === false ? 'http' : 'https';


来源:https://stackoverflow.com/questions/18008135/is-serverrequest-scheme-reliable

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!