1

I have some PHP pages that I need to force SSL for. I don't want to do it with mod_rewrite or anything like that, I want to keep all the logic in PHP. Right now I have code that looks like this:

if($_SERVER["HTTPS"] != "on") {
    header("HTTP/1.1 301 Moved Permanently");
    header("Location: https://" . $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"]);
    exit();
}

This does not work however because the server name is generic as I am hosting multiple sites with different domain names. So the SERVER_NAME is "www". The above code will redirect to https://www/index.php which is not valid.

I have tried print_r($_SERVER) to see the variables available to me but none of them give me the full URI request (http://example.com/index.php), and the next closest option I can see instead of SERVER_NAME is SERVER_ADDR which will also not help me, because going to https://127.0.0.1/index.php will go to the default apache site and not to the definition for "example.com" (not to mention that my SSL cert would no longer be valid).

Any suggestions?

bawkstoo
  • 315
  • 2
  • 5
  • 16

5 Answers5

1

If you can't get the host name from any $_SERVER variable, and you don't want to explicitly set it in a config or anything, the only other option I can think of (besides doing it using mod_rewrite, which you stated you don't want to do for whatever reason) is to serve the user a blank page that says, "Please wait while we redirect you to the secure site..." and then handle the redirect using JavaScript to parse the current URL and redirect to the HTTPS version.

Sarah
  • 513
  • 4
  • 11
  • To get the $_SERVER['SERVER_NAME'] and $_SERVER['SERVER_PORT'] to be filled appropriately, you may need to set the option in apache "UseCanonicalName" to "on". http://httpd.apache.org/docs/1.3/mod/core.html#usecanonicalname – Sarah Dec 22 '10 at 18:59
  • Hey this worked! I added UseCononicalName into apache.conf and now SCRIPT_URI shows my full request path as seen from the client! (`http://example.com/index.php` instead of `http://www/index.php` as it used to display). For lack of a PHP-only solution without writing a URL managing system, I think this wins. – bawkstoo Dec 22 '10 at 19:21
1

In the end I had the guy who manages the Apache proxy server to add ProxyPreserveHost On to apache2.conf and this enabled forwarding of HTTP_HOST (and SERVER_NAME) properly to the backend Apache server.

Thank you everyone for your suggestions, I'm sorry the problem ended up being something stupid that wasn't even in the scope of my question. If the Apache server I was working on did not have a proxy in front of it, most of your suggestions would have proven completely accurate.

bawkstoo
  • 315
  • 2
  • 5
  • 16
0

I suspect you want to use the $_SERVER['HTTP_HOST'] setting in place of SERVER_NAME.

header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);

John Parker
  • 54,048
  • 11
  • 129
  • 129
  • HTTP_HOST is giving me the same value as SERVER_NAME ("www"). And SCRIPT_URI shows `"http://www/index.php"` too. – bawkstoo Dec 22 '10 at 18:36
  • Odd. Are you running under Windows or something? (I've used the above on PHP sites for many, many, years.) Also are you using virtualhosts under Apache? – John Parker Dec 22 '10 at 18:37
  • Ubuntu 10.04, apache2-mpm-prefork 2.2.14-5ubuntu8.4, yes using but perhaps not correctly? – bawkstoo Dec 22 '10 at 18:49
  • @bawkstoo - Are you setting the full "ServerName" within your VirtualHost? (I suspect you'll need to do this.) – John Parker Dec 22 '10 at 18:52
  • ServerName in apache2.conf is localhost, and in each definition it it is set to the appropriate domain, but I see none of that in $_SERVER. – bawkstoo Dec 22 '10 at 18:57
  • @bawkstoo Ah... you *might* need to set "ExtendedStatus On" in your main Apache conf file. (Fingers crossed that and a restart will sort it out.) – John Parker Dec 22 '10 at 19:01
  • Didn't change or add anything to $_SERVER :( – bawkstoo Dec 22 '10 at 19:04
  • @bawkstoo. Sorry, I'm outta ideas then. :-( (Presume you can't check this on another server to make sure it isn't some weird install issue?) – John Parker Dec 22 '10 at 19:05
0

If your site URL isn't in $_SERVER I'd guess that you'd have to register it somewhere as a global variable. Each site would then have to register it's own $SITE_URL variable or some such so that you could fill it in with that.

James Alday
  • 873
  • 9
  • 23
0

In my humble opinion you should avoid doing theses absolute url stuff in your application. The right place to do it si behind your application, for several reasons:

  • your application could be used in the same time, via the same apache
    server, with different names
  • your application could be used behind some proxy, rewriting the base url. (But you can try to detect it)

See for a more detailled explanation this link http://www.makina-corpus.org/blog/relativeabsolute-url-and-proxies

So absolute url is bad, should avoid... I would build instead a nice url managment, where the rules would be simple (all /admin or /conn url needs to be on SSL) and let the proxys/web servers/load balancers handle it nicely. But if you really want to make this redirection in your application the used ways are:

  • using a configuration file where the https absolute url and the http abolute url is defined and unique (fine if your site name is unique and your application not done for large usage)
  • detect absolute url from proxy string in HTTP_X_FORWARDED_HOST and/or
    HTTP_HOST (better)

But most admins will say that absolutes url are bad :-)

regilero
  • 29,806
  • 6
  • 60
  • 99
  • I fully agree, I do not enjoy using an absolute URL anywhere to keep my code as portable as possible. This current application is behind a proxy which *can* provide me with the HTTP_X_FORWARDED_HOST header, but it may not always do so (this is why I am avoiding using it, and also any mod_rewrite rules as I do not control those directly on the production server). – bawkstoo Dec 22 '10 at 19:16
  • So you could build your host absolute url by taking the HTTP_HOST or if not empty the last HTTP_X_FORWARDED_HOST. But what will happen if in production the reverse proxy was not configured to handle your app in https but only in http (for example, the https thing is handled byt he reverse proxy and he's querying your app only on http). I think that would make the browser trying to get direct access https to your app (on a DNS which is maybe not public), withou querying the proxy. Having no control on production http/https settings is a nice hell :-) – regilero Dec 22 '10 at 22:31