227

I've written a little function to establish the current site url protocol but I don't have SSL and don't know how to test if it works under https. Can you tell me if this is correct?

function siteURL()
{
    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
    $domainName = $_SERVER['HTTP_HOST'].'/';
    return $protocol.$domainName;
}
define( 'SITE_URL', siteURL() );

Is it necessary to do it like above or can I just do it like?:

function siteURL()
{
    $protocol = 'http://';
    $domainName = $_SERVER['HTTP_HOST'].'/'
    return $protocol.$domainName;
}
define( 'SITE_URL', siteURL() );

Under SSL, doesn't the server automatically convert the url to https even if the anchor tag url is using http? Is it necessary to check for the protocol?

Thank you!

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    Wouldn't it be a better option for you to install a local web server and throw a self signed SSL certificate on it? That way you can test it for yourself. – Frazell Thomas Dec 21 '10 at 19:34
  • Yes, that would be awesome, but I don't know how to do it. –  Dec 21 '10 at 19:35
  • 4
    While this doesn't answer your question, a better solution to your problem (though I can't be sure without knowing more) might be to use [Protocol Relative URLs](http://paulirish.com/2010/the-protocol-relative-url/). – Reese Moore Dec 21 '10 at 19:46
  • Just a quick question...how come you're doing a function if it's not dynamic. It's not like you feed it any vars to change the url. Why not define a constant? That's what I did. $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://"; define('SITE_URL', $protocol.$_SERVER['HTTP_HOST'].'/'); – HTMLGuy Jan 26 '13 at 23:58
  • May I suggest this? http://stackoverflow.com/questions/6768793/get-the-full-url-in-php – Timo Huovinen Apr 16 '14 at 14:45

19 Answers19

102

This works for me

if (isset($_SERVER['HTTPS']) &&
    ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
    isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
    $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
  $protocol = 'https://';
}
else {
  $protocol = 'http://';
}
Rid Iculous
  • 3,696
  • 3
  • 23
  • 28
91

I know it's late, although there is a much more convenient way to solve this kind of problem! The other solutions are quite messy; this is how I would do it:

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

...or even without condition if you prefer:

$protocol = strtolower(substr($_SERVER["SERVER_PROTOCOL"],0,strpos( $_SERVER["SERVER_PROTOCOL"],'/'))).'://';

Have a look at $_SERVER["SERVER_PROTOCOL"]

ashleedawg
  • 20,365
  • 9
  • 72
  • 105
ivoputzer
  • 6,427
  • 1
  • 25
  • 43
  • 28
    This dont work with "https" http://stackoverflow.com/questions/16825243/why-is-phps-server-protocol-showing-http-1-1-even-when-using-https – wormhit Aug 07 '14 at 12:57
  • @wormhit it mainly depends on how your webserver is configured though – ivoputzer Aug 07 '14 at 14:18
  • Any reason why you use `stripos` instead of `strpos`? – Fred Dec 03 '14 at 14:37
  • @Fred it's just to prevent webserver configuration flaws! in most cases though going `strpos` is absolutely fine `strpos($_SERVER['SERVER_PROTOCOL'],'HTTPS')` – ivoputzer Dec 03 '14 at 15:09
  • Note that `stripos` is slower than `strpos`. I am not aware of any configuration where it might say 'https' in lowercase. – Fred Dec 04 '14 at 11:15
  • I did find one - once, and that's the reason why i went that way! If you really want to dig into performance however `isset($_SERVER['SERVER_PROTOCOL'][4]) && 'S' === $_SERVER['SERVER_PROTOCOL'][4]` might be even faster than `strpos`. To me it just depends on how many times you need to execute the procedure; I might edit the answer adding a hi-performance version ;) – ivoputzer Dec 04 '14 at 11:51
  • 18
    `$_SERVER['SERVER_PROTOCOL']` is made to store `HTTP/1.0` or `HTTP/1.1` depending on the protocol version, what sort of HTTP server configuration do you talk about, storing `https` information on this string coming from the http query? – regilero Feb 03 '15 at 14:48
  • @ejectamenta - Checking if $_SERVER['HTTPS'] is set is insufficient. According to http://php.net/manual/en/reserved.variables.server.php, there's a case where it will be set to 'off'. I'm down voting the answer as incorrect. – KenB Aug 16 '16 at 13:51
  • " Note that when using ISAPI with IIS, the value will be off if the request was not made through the HTTPS protocol" so it doesn't work for Windows servers, but if you are using a UNIX server then it is sufficient – ejectamenta Aug 17 '16 at 18:11
  • Or even shorter: `$protocol = strtolower(strstr($_SERVER['SERVER_PROTOCOL'], '/', TRUE))` – Joe Black May 06 '17 at 14:41
  • 6
    Doesn't work in my case! $_SERVER['SERVER_PROTOCOL'] contains "HTTP" (without any "S") while the protocol is https. Checking $_SERVER['HTTPS'] is more appropriate. – Simon Hi Nov 24 '17 at 14:08
  • This answer is outdated, now that SERVER_PROTOCOL can be [SERVER_PROTOCOL] => HTTP/2.0. More robust option is in answer from Rid Iculous (which is, BTW, a ridiculous username ;-) – zmippie Dec 20 '20 at 09:53
75

It is not automatic. Your top function looks ok.

profitphp
  • 8,104
  • 2
  • 28
  • 21
29

short way

$scheme = $_SERVER['REQUEST_SCHEME'] . '://';
softcod.com
  • 554
  • 5
  • 8
28

Some changes:

function siteURL() {
  $protocol = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || 
    $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
  $domainName = $_SERVER['HTTP_HOST'];
  return $protocol.$domainName;
}
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Anoop K
  • 281
  • 3
  • 3
7

Because testing port number is not a good practice according to me, my solution is:

define('HTTPS', isset($_SERVER['HTTPS']) && filter_var($_SERVER['HTTPS'], FILTER_VALIDATE_BOOLEAN));

The HTTPSconstant returns TRUE if $_SERVER['HTTPS'] is set and equals to "1", "true", "on" or "yes". Returns FALSE otherwise.

alex
  • 5,661
  • 6
  • 33
  • 54
  • This is probably the best answer. Lots of these answers will will only in a percentage of situations. For example, people are just checking if $_SERVER['HTTPS'] is set. Many frameworks set this variable as false or 'off' etc, therefore checking if it's simply set will not work. – Daniel Dewhurst Jan 03 '17 at 14:48
  • 1
    While this works under most situations, there have been times where there was a configuration SNAFU and $_SERVER['HTTPS'] was actually set to "off". Your code would still regard that as "passing" the test, so should be amended to allow for that particular setting. – Dave Morton May 23 '17 at 14:20
7

For any system except IIS this is quite enough to define site self URL:

$siteURL='http'.(empty($_SERVER['HTTPS'])?'':'s').'://'.$_SERVER['HTTP_HOST'].'/';

or

$siteURL='http'.(empty($_SERVER['HTTPS'])?'':'s').'://'.$_SERVER['SERVER_NAME'].'/';

depends on what you exactly want: HTTP_HOST vs. SERVER_NAME

Community
  • 1
  • 1
5

Use this server variable to get the protocol details:

 $scheme = $_SERVER['REQUEST_SCHEME'] . '://';
 echo $scheme; //it gives http:// or https://

Note that this server variable is unreliable. For more information take a look at: Is $_SERVER['REQUEST_SCHEME'] reliable?

Community
  • 1
  • 1
shashik493
  • 790
  • 1
  • 10
  • 12
  • Can you add some more information to your post, and not only the code? For example explain why this is an answer to the question? – ndsmyter Jul 08 '15 at 09:42
5

In case of proxy the SERVER_PORT may not give the correct value so this is what worked for me -

$protocol = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443 || $_SERVER['HTTP_X_FORWARDED_PORT'] == 443) ? "https://" : "http://"
Harshit
  • 711
  • 1
  • 9
  • 29
5

Extracted from CodeIgniter :

if ( ! function_exists('is_https'))
{
    /**
     * Is HTTPS?
     *
     * Determines if the application is accessed via an encrypted
     * (HTTPS) connection.
     *
     * @return  bool
     */
    function is_https()
    {
        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;
        }

        return FALSE;
    }
}
Guillaume
  • 443
  • 5
  • 11
3
$protocal = 'http';
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || $_SERVER['HTTPS'] == 'on') {$protocal = 'https';}


echo $protocal;
Saurabh Chandra Patel
  • 12,712
  • 6
  • 88
  • 78
3

I know this is an old question but I came across this today since I needed to test for this in my site. It seems the answers above are needlessly complicated. To establish the site protocol, all you have to do is test $_SERVER['HTTPS']

If the protocol is using HTTPS, then $_SERVER['HTTPS'] will return 'on'. If not, the variable will remain empty. For example:

test if HTTPS is being used. If it is, the echo will return '$SSL_test: on'. If not HTTPS, '$SSL_test' will remain empty.

$SSL_test = $_SERVER['HTTPS'];

echo '<p>$SSL_test: '.$SSL_test.'</p>';
    
if($SSL_test == true) {
    echo 'You\'re using SSL';
} else {
    echo 'You\'re not using SSL';
} 

You can use the above to easily and cleanly test for HTTPS and implement accordingly. :)

Shahzad Barkati
  • 2,532
  • 6
  • 25
  • 33
Rob Stocki
  • 156
  • 1
  • 9
2

made a function using the Rid Iculous's answer which worked on my system.

function site_protocol() {
    if(isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&  $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')  return $protocol = 'https://'; else return $protocol = 'http://';
}

Hope it helps

miyuru
  • 1,141
  • 11
  • 19
2

I've tested the most voted answer and it didn't work for me, I ended up using:

$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
Community
  • 1
  • 1
Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
2

Here is how I do it ... it is a shorthand if else version of Rid Iculous's answer ...

$protocol = isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] === 'on' || $_SERVER['HTTPS'] === 1) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ? 'https' : 'http';
Scotty G
  • 374
  • 2
  • 6
1

I think the complete func should look like :

function siteURL()
{
    $protocol =  "http://";
    if (
        //straight
        isset($_SERVER['HTTPS']) && in_array($_SERVER['HTTPS'], ['on', 1])
        ||
        //proxy forwarding
        isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'
    ) {
        $protocol = 'https://';
    }

    $domainName = $_SERVER['HTTP_HOST'];
    return $protocol . $domainName;
}

Notes:

  • you should look also for HTTP_X_FORWARDED_PROTO (e.g. if proxy server)
  • relying on 443 port is not safe (https could be served on different port)
  • REQUEST_SCHEME not reliable
koalaok
  • 5,075
  • 11
  • 47
  • 91
1

Also late to the party, but here is a much shorter version of Rid Iculous's answer using the Null Coalescing Operator:

$is_ssl = in_array($_SERVER['HTTPS'] ?? '', ['on', 1]) ||
          ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') == 'https';
$protocol = $is_ssl ? 'https://' : 'http://';

Or:

$protocol = in_array($_SERVER['HTTPS'] ?? '', ['on', 1]) ||
            ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') == 'https' ?
            'https://' : 'http://';
Aranxo
  • 677
  • 4
  • 15
0

it's the best solution of https or http use this :

<?php
$protocol = '//';  
$site_url = $protocol.$_SERVER["HTTP_HOST"];
?>

But can't display https or http, so it only use to link your site content like image, etc.

if want to redirect your site in https, add this code in .htaccess file :

<IfModule mod_rewrite.c>
 RewriteCond %{HTTP:CF-Visitor} '"scheme":"http"'
 RewriteRule ^(.*)$ https://www.your-domain.com$1 [L]
</IfModule>

Change www.your-domain.com with your dowmain name.

0

I know I'm a bit late to this party, but if you much prefer not using $_SERVER as it's strongly discouraged, and even deactivated on some PHP frameworks; and you have an apache web server, you can use it's native command thusly: -

$protocol = apache_getenv('HTTPS') ? 'https:' : 'http:';
Jon
  • 812
  • 2
  • 11
  • 18