Home » Php » Is $_SERVER['REQUEST_SCHEME'] reliable?

Is $_SERVER['REQUEST_SCHEME'] reliable?

Posted by: admin November 29, 2017 Leave a comment

Questions:

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?

Answers:

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

Questions:
Answers:

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.

Questions:
Answers:

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

Questions:
Answers:

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

Questions:
Answers:

As this variable is not available in all server versions, certainly it is not reliable only testing 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 toxalot said, REQUEST_SCHEME is a native variable of Apache since version 2.4 (Apache 2.2 does not have it). And, if the variable is not set by the server, PHP will not include it in its global array $_SERVER.

Fortunately, for compatibility with codes based exclusevily on REQUEST_SCHEME check, 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

Questions:
Answers:

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]

Questions:
Answers:

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