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?
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
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.
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).
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
In new version Nginx, set by default fastcgi_param REQUEST_SCHEME $scheme
.
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
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]
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;
}
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