234

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!

5
  • 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. Commented Dec 21, 2010 at 19:34
  • Yes, that would be awesome, but I don't know how to do it. Commented Dec 21, 2010 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. Commented Dec 21, 2010 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'].'/'); Commented Jan 26, 2013 at 23:58
  • May I suggest this? stackoverflow.com/questions/6768793/get-the-full-url-in-php Commented Apr 16, 2014 at 14:45

19 Answers 19

112

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://';
}
Sign up to request clarification or add additional context in comments.

4 Comments

This is the solution that works if using a proxy (like in my case CloudFlare)
This is correct - you shouldn't assume https just because you're using port 443.
This work fine with normal links as well as with CDN, thanks
Would it be of benefit to apply the PHP strtolower() Function to the portion of the above code ($_SERVER['HTTPS'])== 'on') so that it read strtolower($_SERVER['HTTPS']) == 'on' and therefore allowing for instances where the value returned from $_SERVER['HTTPS'] is On or ON?
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"]

12 Comments

This dont work with "https" stackoverflow.com/questions/16825243/…
@wormhit it mainly depends on how your webserver is configured though
Any reason why you use stripos instead of strpos?
$_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?
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.
|
75

It is not automatic. Your top function looks ok.

3 Comments

worth noting that it IS automatic if you just leave off the protocol.. ie //mysqite.com instead of https://mysitecom
@Pamblam, // works great unless your link is in an email :)
Or in an xhr request
30

short way

$scheme = $_SERVER['REQUEST_SCHEME'] . '://';

2 Comments

REQUEST_SCHEME is not reliable
REQUEST_SCHEME is not available until Apache 2.4.
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;
}

Comments

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.

2 Comments

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.
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.
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

Comments

7

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

1 Comment

no link to the source.. let me reference at least this
6

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?

1 Comment

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?
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://"

Comments

3

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

$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';

4 Comments

Some web servers do not support $_SERVER["HTTPS"] and therefore your code may return http:// even if it should be https://
If the server doesn't support, https, why would the code still return https?
My server supports https but the $_SERVER["HTTPS"] variable is never defined.
I'm confused by your 2 comments. It's probably better if you create a new answer that covers those special cases. Thanks and good luck!
3
$protocal = 'http';
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || $_SERVER['HTTPS'] == 'on') {$protocal = 'https';}


echo $protocal;

Comments

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. :)

1 Comment

Not every server has this $_SERVER['HTTPS']
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

Comments

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

Comments

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

Comments

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://';

Comments

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.

Comments

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

Comments