Detecting whether your PHP code is running on https or http is useful in a number of situations, particularly if you’re building a URL to set a form action or something similar, but it’s actually not as straightforward as it should be.
If you search on Google or Stack Overflow for advice on how to detect https using PHP, you’ll get a number of different answers. Most if not all of these answers will involve PHP server variables, but they use different ones, so which do you pick?
Here are the common methods…
The ‘HTTPS’ server variable
You would check this variable something like this:
$https = false; if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') { $https = true; }
But this only works on some servers. On others, this server variable is simply absent.
The ‘SERVER_PORT’ server variable
You would check this variable something like the example below:
$https = false; if (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) { $https = true; }
But this only works on some servers. On others (I’m looking at you, Cloudways), $_SERVER[‘SERVER_PORT’] can sometimes return 80, even if the site is running on SSL. If there’s a good reason for that, it escapes me at the moment.
So what to do?
Combining these the WordPress way
WordPress has a core function is_ssl which combines the above two methods so that more different servers are covered and the chances of getting back the correct result are increased. Here it is in its current incarnation:
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; }
This is good so far as it goes, and it definitely increases the chances of getting the right result.
But there’s another case where this may fail – and that is on servers that are operating via a reverse proxy. I’m not going to try and explain what a reverse proxy is (though if you’re using CloudFlare you’re using one), but suffice to say that sometimes the function above will fail, because there’s yet another server variable that you need to check instead…
The ‘HTTP_X_FORWARDED_PROTO’ server variable
Sometimes this will be the only relevant server variable that is present and set, so you need to check for it, which you can do like this:
$https = false; if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && ('https' == $_SERVER['HTTP_X_FORWARDED_PROTO'])) { $https = true; }
So if we combine all three methods described above, we should have a universal https detection method. So, we can create…
One function to rule them all
I make no guarantees but I think this function should cover your behind on a significant majority of web servers out there that are running PHP. Unless you’re using IIS in which case you should just go read the IIS documentation to learn which non-standard method Microsoft has imposed.
function is_definitely_ssl() { if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') { return true; } if (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) { return true; } if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && ('https' == $_SERVER['HTTP_X_FORWARDED_PROTO'])) { return true; } return false; }
I’ve eliminated the ‘else’ structure of the WordPress function, since it’s not needed. The first condition that’s met will drop out of the function with the positive result. I’ve deliberately put the conditions in a certain order, so that the ones I believe are more common will be checked first, thus making the function more efficient.
Add this to your snippets collection, utilities class, or whatever you use to store functions that you can use in many projects.
I’ve actually seen yet another server variable – $_SERVER[‘REQUEST_SCHEME’] – discussed in relation to this topic, but I’ve never seen it available on any server I’ve encountered. So I’m going to assume it’s very unusual and politely ignore it.
If you know of another method in reasonably widespread use that I haven’t covered, please leave a comment below and I’ll amend the article!