123

I'm working on a shopping cart website and I would like to redirect the user to a HTTPS page when he's entering his billing details and maintain the HTTPS connection for the next pages until he logs out.

What do I need to install on the server (I'm using Apache) in order to do this, and how can this redirect be done from PHP?

Psyche
  • 8,513
  • 20
  • 70
  • 85

5 Answers5

287

Try something like this (should work for Apache and IIS):

if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === "off") {
    $location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: ' . $location);
    exit;
}
Jigarius
  • 394
  • 3
  • 16
Raphael Michel
  • 854
  • 1
  • 9
  • 18
  • 7
    It doesn't work always. I tried using it and there was no 'https' element in the $_SERVER array due to which it was giving error of 'too many redirects'. Would need to use other method. – Usman Zaheer Apr 09 '12 at 16:14
  • I edit the question in a few minutes, maybe this will work for you – Raphael Michel Apr 14 '12 at 22:24
  • 6
    I had to test `if( $_SERVER['HTTPS'] == "off")` to get this code to work. I think it's because I'm on IIS, not Apache like the OP. – Nick Pickering Apr 26 '13 at 19:43
  • 1
    @NicholasPickering Jepp, $_SERVER variables might vary with webservers. – Raphael Michel Apr 27 '13 at 23:40
  • 6
    Note: die() or exit() can be important to put after header redirects to prevent the rest of the page from executing (and possibly sending extra information to the client) (i.e. to hackers or browsers that may not respect the header). – dajon Dec 11 '13 at 07:16
  • 4
    Depending on your server environment/setup you may need to use $_SERVER['HTTP_X_FORWARDED_PROTO'] to check for http/https – David Meister Jan 25 '14 at 10:12
  • I'd also suggest adding `header("HTTP/1.1 301 Moved Permanently");` before the `header("Location: $redirect");` to make that permanent. – Andrew Lott Jan 16 '15 at 11:51
  • PHP's [`empty($var)`](http://php.net/manual/en/function.empty.php) function combines `!isset($var)` and `$var == ""` – vqdave Jun 04 '15 at 17:09
  • 2
    Is this vulnerable to an injection attack? What if `$_SERVER['REQUEST_URI']` contains special characters, like a new line? – Flimm Feb 07 '17 at 18:09
  • It didn't work with me on self-signed certs on localhost so I added the port condition `if((empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off") && $_SERVER['SERVER_PORT'] != HTTPS_PORT)` remember to define the HTTPS_PORT to 443 – Accountant م Dec 14 '17 at 19:30
  • Since I don't want a redirection when developing locally, I enhanced the if-statement: `if((empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off") && ($_SERVER['HTTP_HOST'] !== "localhost" && $_SERVER['HTTP_HOST'] !== "127.0.0.1"))` – scotty86 May 26 '18 at 09:07
  • The reason I am doing this is because my URL redirect code isn't working as expected on ports.conf RewriteRule ^(.*)$ http://%{HTTP_HOST}$1 [redirect=301] – Alvin567 Jun 16 '21 at 12:51
30

This is a good way to do it:

<?php
if (!(isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || 
   $_SERVER['HTTPS'] == 1) ||  
   isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&   
   $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'))
{
   $redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
   header('HTTP/1.1 301 Moved Permanently');
   header('Location: ' . $redirect);
   exit();
}
?>
Matiasg1982
  • 399
  • 3
  • 5
  • 3
    works well the one marked as good will return a redirect too many times at least in Chrome – Thomas J Younsi Aug 30 '17 at 20:55
  • 1
    The condition `!(isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on'` will always be false, since if the last part is true, the first will be false. – Max Aug 27 '18 at 12:52
  • @Max : I don't get what you say. If the second condition is true ($_SERVER['HTTPS'] == 'on') then the first condition will have to be TRUE as well (of course that server variable is set, because it contains a value!) – OMA Sep 24 '18 at 11:11
8

Redirecting from HTTP to HTTPS with PHP on IIS

I was having trouble getting redirection to HTTPS to work on a Windows server which runs version 6 of MS Internet Information Services (IIS). I’m more used to working with Apache on a Linux host so I turned to the Internet for help and this was the highest ranking Stack Overflow question when I searched for “php redirect http to https”. However, the selected answer didn’t work for me.

After some trial and error, I discovered that with IIS, $_SERVER['HTTPS'] is set to off for non-TLS connections. I thought the following code should help any other IIS users who come to this question via search engine.

<?php
if (! isset($_SERVER['HTTPS']) or $_SERVER['HTTPS'] == 'off' ) {
    $redirect_url = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    header("Location: $redirect_url");
    exit();
}
?>

Edit: From another Stack Overflow answer, a simpler solution is to check if($_SERVER["HTTPS"] != "on").

Community
  • 1
  • 1
Anthony Geoghegan
  • 11,533
  • 5
  • 49
  • 56
  • 14
    @JakeSylvestre Fair enough. Given that this question isn't tagged as `apache`, I posted this answer for the benefit of other IIS users (similar to the situation I was in) who may come across this page via search engine. I subscribe to the view that answers are for the benefit of the community as a whole and not just the OP. – Anthony Geoghegan Mar 22 '16 at 23:36
6

You can always use

header('Location: https://www.domain.com/cart_save/');

to redirect to the save URL.

But I would recommend to do it by .htaccess and the Apache rewrite rules.

powtac
  • 40,542
  • 28
  • 115
  • 170
  • 13
    I would always recommend to check $_SERVER['HTTPS'] before redirecting. – Raphael Michel Feb 24 '11 at 15:01
  • $_SERVER['HTTPS'] is not always set, but it is a good idea to check before. Thats why I recommend to do it with an useful rewrite rule in Apache, which only redirects when its not on HTTPS. – powtac Feb 24 '11 at 15:03
  • Although Apache recommends not to use an extra .htaccess file (because it slows down) but to use the rewrite rules inside the *.conf of Apache. – powtac May 15 '13 at 08:27
5

On my AWS beanstalk server, I don't see $_SERVER['HTTPS'] variable. I do see $_SERVER['HTTP_X_FORWARDED_PROTO'] which can be either 'http' or 'https' so if you're hosting on AWS, use this:

if ($_SERVER['HTTP_HOST'] != 'localhost' and $_SERVER['HTTP_X_FORWARDED_PROTO'] != "https") {
    $location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: ' . $location);
    exit;
}
phoenix
  • 1,629
  • 20
  • 11