Various PHP questions - php

about this function:
function requireSSL() {
if($_SERVER['SERVER_PORT'] != 443) {
header("HTTP/1.1 301 Moved Permanently");
header("Location: https://" . $_SERVER['HTTP_HOST'] .$_SERVER['REQUEST_URI']);
exit;
}
return false;
}
SSL requires port 443, so in this piece of code if not 443 then forced to use https? and if 443 it would automatically use https I assumed. What's the moved permanently used for?
The code header("Location: .");
What's use of the above, it's nothing more than telling it to stay at the same page. By default it should stay at the same page, isn't it redundant?

SSL requires port 443
Not always. That is the default port. HTTPS can be configured to run on other ports. A better way to check is:
if ( !isset($_SERVER['HTTPS']) || strtolower($_SERVER['HTTPS']) != 'on') {
}
What's the moved permanently used for?
From w3:
The requested resource has been assigned a new permanent URI and any
future references to this resource SHOULD use one of the returned
URIs
In other words, a browser should remember that the requested URI is moved and request the new URI anytime the user requests that old URI again.
By default it should stay at the same page, isn't it redundant?
That's not what the code is doing. It's redirecting to the https version when the user requests the non-https version.

This piece of code is redirecting the client to use https in case it does not use https. 301 tells the client to always use the new location.
The redirection is done via the Location header, and you are only partly right, the page is the same, but the connection is done via https and not http. If the client is already connected via https, the redirect does not occur.

1) HTTP/1.1 301 is for letting the browser and search engines know that the page has moved to https://example.com/thepage.php
2) This code is used for specific pages or sites that require SSL. Example: Shopping carts, banks, logins

HTTPS goes through port 443 by default. This code redirects the user, using the Location-header, to the HTTPS if the user is visiting through plain HTTP.
The 301 instructs the browser to always redirecting HTTP to HTTPS on succeeding requests on that URL.
In psuedo-code it does this:
if (user is NOT visiting through HTTPS)
redirect permanently to the same URL, but then through HTTPS
So no, it's not redundant, for if anyone visits that page using HTTPS, the body of the if-block will not be executed and no redirect takes place.

First of all, the function does what you think.
Let's go through each of those you want to learn more about:
header("HTTP/1.1 301 Moved Permanently");
This sets the HTTP response status code. Code: 301. Message: Moved Permanently. 301 is a permanent redirect, this just tells the browser (HTTP client), next time to use the new address directly instead of the requested one.
The new address is given with a Location: header.
header("Location: .");
This code is just plain wrong code. Don't expect that it works. I assume somebody wanted to redirect to the same page again, but this does not work this way. A Location: needs to be followed by an absolute URL, this is a relative URL and won't work. Absolute URLs always start with http:// or https:// and contain a host-name.

Related

Redirect HTTPS to HTTP in Controller

At the moment the redirect code redirects HTTPS → HTTPS. I tried stopping the page with die($url) to see if the PROTOCOL is HTTP and it was correct. But for some reason when I try PHP header location it redirects back to HTTPS protocol rather than HTTP
So when I use following code in my Zend predispatch method
header('Location: http://www.example.com/blogs/');
it redirects to https://www.example.com/blogs/ (HTTPS PROTOCOL)
whereas when I try
header("Refresh:0; url=http://www.example.com/blogs/");
it works fine. Meaning it redirects to HTTP protocol.
Note: The reason I need to do this inside the controller is that redirects depend on a special flagpole. I cannot do it with Apache config.
I have finally solved this issue.
The problem was the redirection headers were being overridden by the loadbalancer. So there was some sort of policy set that if someone tries to redirect URL from one protocol to another it will not allow that causing the redirect loop that i was experiencing.
The solution in my particular case was another custom header that was needed to be sent which allowed scheme override in the loadbalancer.

302 redirect to non-HTTP protocol

I need to perform a 302 redirect with PHP. I'm trying with header location.
It works well with HTTP. But, the redirect does not work with a custom protocol. For example:
header ('Location: magplus://myaccountview/login/');
How I can fix it?
For some browsers, you will not be able to redirect to a protocol other than HTTP or HTTPS. There is nothing you can do about that specifically.
You can try to change the location in the browser client-side with JavaScript, if that is a possibility for your application. That also won't always work however.

Forcing http/https: How to detect https and which status header to send when redirecting?

I've written a script to force certain sections of the site to be accessed via http or https. We want the user to be redirected to the normal http page in case they land on the https version by accident, and vice versa. So far, so good, but I have 2 questions for you guys.
What is the correct status header to send when switching protocol? I'm currently using this in both cases before redirecting:
header('HTTP/1.1 301 Moved Permanently');
What is the preferred way to detect if we're using https?
// if ($_SERVER['SERVER_PORT'] == 443) /* EDIT: OK, not this? */
if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on'))
Something else? Both?
Replies to comments:
We're using Apache, but if there's a universal solution that would great.
We don't want to use .htaccess because the https required pages are "flagged" as such by the CMS we're using, and that this is a part of. We don't want to "hard-code" the URLs into a file.
The 301 redirect is the proper method. You cannot switch between HTTP and HTTPS mid-stream. The page must be reloaded in the client.
The second method, via $_SERVER['HTTPS'] is the preferred method. Simply ensure that your web server supports it.

PHP - Redirect HTTPS to HTTP - infinite loop

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.

Get full URL in PHP to redirect to SSL

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

Categories