I'm trying to prevent certain pages on my site from being accessed through HTTPS, and (for whatever reason) I want to do it through PHP and not through a .htaccess.
Here's the code I'm using:
if ( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ) {
header("HTTP/1.1 301 Moved Permanently");
header("Location: http://mydomain.com");
}
But for some odd reason, I'm stuck in an infinite loop, and can't get it to work. When I check the response headers in firebug, I see that the location header is set to https://mydomain.com instead of http://mydomain.com, which is causing the infinite loop.
EDIT: Accessing http://mydomain.com directly does work.
Also note: this works if I send'em to a different page, but not if I send them to the same page. So if I run the above code in mydomain.com/somePage.php, and then try accessing it through https://mydomain.com/somePage.php, it'll properly redirect to (non-SSL-ed) homepage. Only when I redirect them to the same page with a different protocol does it ignore the protocol.
What am I doing wrong?
It turns out there was nothing wrong with my code. The server was just setup in a way that was messing with my headers. I'm using engineHosting.com, and I have to say: they were very helpful. After a lot of back & forth with them, here's what they sent me:
We were able to get to the bottom of this and may have it (sic) fixed the issue but the fix in and of itself my cause other issues. Let me explain.
Our architecture is not typical of most web hosts. Your account is actually hosted by twin firewalls, twin intrusion prevention systems, twin load balancers also performing the role of SSL hardware-based acceleration, fronting two apache web nodes, and a massive mysql server backend.
The problem was with how we were doing the SSL acceleration inside the load balancers. We have had a number of clients that wanted to detect when a user was accessing a page that was only meant to be used with https, but never the reverse of wanting to detect when a user was on a page that should be redirected to regular http. Because of this, we had an option enabled on our load balancers called "http wan optimized compression SSL Sites Only" which also rewrites an outbound location header to be https when the requesting url was already https enabled. This is useful when you may have a lot of links to assets on the same URL served dynamically but accidentally wrote the link as http. So this is actually a feature, not a bug (and yes I too dislike that phrase).
To work around your particular use case, we changed the SSL profile for your domain to be "http compression for normal/non-ssl" virtual server setups. You have likely not run into this issue using single server web solutions in the past. The unfortunate consequence of operating in this mode is that the other use case of doing 30x redirects at the server level for redirecting users from http to https may have issues depending on how the redirects are implemented. To be safe, you should validate the methods you will be using in your live site and let me know if you run into any problems.
Not completely sure, but here's a couple things I note:
If your .htaccess or server config it set to insist on HTTPS, you won't be able to get around that at the php level.
you left off the trailing slash on http://mydomain.com which creates an implied redirect. Try it with the full actual path in the location -- http://mydomain.com/index.html or http://mydomain.com/index.php for example.
I have a self-hosted server running an HTTPS site. I did a few quick tests, and your code works exactly as expected. Here's my code (verbatim, with only the domain changed):
redir.php
<?php
if ( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ) {
header("HTTP/1.1 301 Moved Permanently");
header("Location: http://mydomain.com/redir.php");
exit;
}
if ( !isset($_SERVER['HTTPS']) || !$_SERVER['HTTPS'])
{
echo "IT'S WORKING!";
}
?>
I would definitely say - as Jared Farrish said in his chat - that it's an issue with the host. Something in their server configuration is forcing the redirect back to HTTPS. I don't think it's a PHP bug. My server is running PHP 5.3.5 with Apache 2.2.17.
Related
We have a client that hosts their IIS web server on AWS. When navigating to a particular PHP web application on this server, it works when there is a slash on the end, but not when it is absent.
this works:
https://example.com.au/application/
However, if one were to enter this into the address bar:
https://example.com.au/application
it redirects to the equivalent http address with a slash on the end:
http://example.com.au/application/
http is disabled via the firewall, so the result is an error.
Here is the request details in Chrome debugger
So my question is, what does my client need to check to ensure this redirect does not occur? or that instead of redirecting to HTTP, it redirects to HTTPS?
Additional info:
This same issue does not seem to occur with .NET web applications. Eg 'https://example.com.au/dotnetapp' will not redirect to 'http://example.com.au/dotnetapp/'.
There are no rules configured in "URL rewrite"
IIS logs show requests when the HTTPS url is triggered, but not the HTTP one.
Edit: This seems to be due to browser caching. After disabling browser caching, i can see the 301 entry in the log files.
'index.php' is set as a default document
One possible reason is that the PHP project doesn't know that the secure connection is active and so it's redirecting the page to the http version when adding the slash.
PHP application can detect the secure connection by the $_SERVER['SERVER_PORT'], $_SERVER['REQUEST_SCHEME']. But if the application is behind some reverse proxy (e.g. Varnish or Amazon’s Elastic Load Balancer), the connection to the PHP application is probably not secured. PHP should be informed about the original secure connection with X-Forwarded-* headers.
Please check if the PHP has these variables set:
$_SERVER['HTTP_X_FORWARDED_PROTO']: should be https,
$_SERVER['HTTP_X_FORWARDED_PORT']: should be 443.
Symfony framework
If the application is using the framework, e.g. Symfony, it should be configured to trust the IP of the reverse proxy and to trust also these headers:
# config/packages/framework.yaml
framework:
# ...
# the IP address (or range) of your proxy
trusted_proxies: '192.0.0.1,10.0.0.0/8'
# trust *all* "X-Forwarded-*" headers
trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port']
# or, if your proxy instead uses the "Forwarded" header
trusted_headers: ['forwarded']
See https://symfony.com/doc/current/deployment/proxies.html for more details and https://symfony.com/doc/current/deployment/proxies.html#but-what-if-the-ip-of-my-reverse-proxy-changes-constantly for more detaiils if the IP address of reverse proxy server changes.
Looks like you are setting location header in the 'index.php' file and so browser is redirecting to the http url.
If the index.php has code like below, replace the http to https and to the correct URL
header("location:http://example.com.au/application/");
Updated :
Also check your folder to see if any other files are redirecting.
Please make sure the index.php is listed as the first in the default document list and none of the other files contain redirect code.
You can search for "meta http-equiv="refresh" http tags in all the files in folder to see if they are redirecting.
I need to access http://server.com/folder and get a default index.php file with NO REDIRECT , which means I need Apache to deliver http://server.com/folder/index.php when http://server.com/folder is called with no redirect. How can this be done? I see many solutions but some do not seem to work or perhaps are incomplete while other cause a redirect. The client I want to use is Mopira for Scanning and does not respond to the redirect as I suspect others will not as well.
This is Apache2 running on a local Ubuntu server so i is not a server exposed to the Internet
Alternately if I can force http://server.com/filename to load http://server.com/filename.php with no redirects this would also work but redirects do not work!
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?
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.
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.
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']);
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.
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 :-)
I'm having a strange problem here and can't figure the cause. I have a php-script on an nginx server which triggers a redirect to a different (sub)domain on the same server:
For instance:
foo.domain.com/redirect.php
header("Status:301");
header("location:http://www.domain.com/new_url/");
The result is that I'm getting redirected to:
foo.domain.com/new_url
The domain doesn't change at all although my response headers look fine .
Any ideas?
Ok, I finally found the cause for my troubles. Neither Nginx, nor PHP caused the issues. My webservers are behind a loadbalancer running with Pound.
Pound has a feature to rewrite domains inside header redirects (enabled by default). We now turned this feature off and all redirects finally work as expected!
Check your containing your site in an iframe,
Some hosts can do this if its free hosting, all so some domains setup allows the site to be contained in an iframe witch would cause the properly your describing
I have a script that handles several different redirects on a server with a snippet that looks like follows:
if($url == "http://www.url.com")
{header("Location: https://www.url.com/index.html");}
The script works exactly as intended with one issue - all of the https redirects end up redirecting to http (versus the https as defined).
Does anyone have any ideas what may be going on?
The server you redirect to has a redirect of its own to http.
Nothing you can do about it, unless you are administering that server.
There was something else going on with the server, but it's been a while so I can't remember what it was anymore.