Weird behavior in IE/Firefox regarding $_SERVER['QUERY_STRING'] - php

In an php-based application I've been coding, I have the following small block of code:
if (isset($_SERVER['QUERY_STRING'])) {
header("Location: " . $_SERVER['QUERY_STRING']);
}
In my application, I use framesets and frames. This code is present in the main content area frame, and upon execution in IE, creates an infinite loop which kills the browser unless I manually stop loading.
The purpose of this code is to detect if there is a query string appended to the url, and if so, redirect to that query string. I've primarily been developing using chrome and and firefox, and today decided to test it in IE9. I have not tested it in any previous versions, but so far this behavior only occurs in IE, and I'm frankly stumped on why such is happening. I've searched for similar questions here and on the internet, but so far no dice.
Edit
As I noted with an earlier edit, I am using framesets and frames to control the interface. The left-hand frame, a side bar, contains links with a base target of the main 'content' area frame. The content of the content area frame contains javascript that appends a query string to the parent window's url, so that when the index page is visited(with the query string present), it will redirect the content frame to that specific page.
This works perfectly fine in Chrome. Not IE(or firefox, which I just discovered as of this edit). Ie instead redirects to the index page, the page containing the frameset, and it does this forever, creating sidebar after sidebar.

Try the following:
session_start();
if ( !isset($_SESSION['Redirect'] ) && isset( $_SERVER['QUERY_STRING'] ) ) {
$_SESSION['Redirect'] = true;
header( "Location: " . $_SERVER['QUERY_STRING'] );
}

I don't know if this can be your problem at all, but as per HTTP/1.1, redirection requires the full absolute path including the hostname. So perhaps try this:
<?php
/* Redirect to a different page in the current directory that was requested */
$host = $_SERVER['HTTP_HOST'];
$uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
$extra = $_SERVER['QUERY_STRING'];
header("Location: http://$host$uri/$extra");
exit;
?>
Or another suggestion is to avoid using the full querystring (like ?thispage.php), but to use a GET parameter instead (like ?path=thispage.php).
<?php
/* Redirect to a different page in the current directory that was requested */
$host = $_SERVER['HTTP_HOST'];
$uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
$extra = $_GET['page'];
header("Location: http://$host$uri/$extra");
exit;
?>

I kind of hate myself for not thinking of this sooner, given how horribly simple it is. All I did, was check if $_SERVER['QUERY_STRING'] was empty, as so:
if (isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != '') {
header("Location: " . $_SERVER['QUERY_STRING']);
}
And that solved the problem of the index page creating infinite nested framesets and frames.

Related

Get Referer URL and FOLDER name in PHP

I have several folders on my domain, within each folder contains an index.php file that checks to see if the database connection passes or fails, if it fails, the page is redirected to a top level file (outside of all folders) called offline.php. This part works great. The basic format I'm using to redirect if the db is offline is:
if ( !$dbconnect ) {
header("Location: https://www.test.com/offline.php");
}
Then, within the offline.php page, I need to check to see which folder brought the user to the offline.php page, and display a unique message to the user - based on the folder that brought them to the offline.php page.
For example:
test.com/test1/index.php redirects to offline.php, the message would say 'test1 brought you to this page'
test.com/test2/index.php redirects to offline.php, the message would say 'test2 brought you to this page'.
In multiple browsers I've tried the following code, which always results in 'unknown uri':
$url = 'https://' . $_SERVER['HTTP_REFERER'] ;
if ( strpos($url,'test') !== false ) {
echo 'test';
} elseif ( strpos($url,'test1') !== false ) {
echo 'test1';
} elseif ( strpos($url,'test2') !== false ) {
echo 'test2';
} else {
echo 'unknown uri';
}
Suggestions?
EDIT
Due to the unreliable nature of HTTP_REFERER I've decided to put all of the conditions within the index.php page and forget about the offline.php page. A HUGE thank you to everyone who offered suggestions!
Why would you use redirects at all? They are heavy on the server, slow and just plain old unnecessary. Use a switch statement and have 1 controlling page instead of multiple folders and pages.
If you use the following code on your offline.php page, you can see all of the $_SERVER variables available (referring URL is in there)
echo '<pre>',print_r($_SERVER),'</pre>';
From there, you can take $_SERVER['HTTP_REFERER'] use a select case, or if then statement and accomplish your goal.
Based on some of your questions in the comments and people pointing out the use of $_SERVER['HTTP_REFERER'] being unreliable, you could do something like this instead.
On your index.php page with the dbconnect check, you could modify it to be something like this. header("Location: https://www.test.com/offline.php?org=".urlencode($_SERVER['REQUEST_URI']));
Then, on the offline.php,
$page = urldecode($_GET['org']);
$org = explode('/',$page);
echo $org[1] to get the first value after the slash, $org[2] would get the next value etc..

PHP redirect to HTTPS if page is

I need a PHP if/else statement that if the sign-in.php or register.php page is access over HTTP I would like to redirect to HTTPS else if any other page is accessed over HTTPS redirect to HTTP plus have any query string appended for example if a user tries to access a restricted page (http://domain.com/my-account.php) the site redirects the user to http://domain.com/sign-in.php?redirect=my-account however, I would like the page to redirect to https://domain.com/sign-in.php?redirect=my-account.
I know I could simply change the header redirects to include https instead of http but users may type http://domain.com/sign-in.php?redirect=my-account so just need to ensure if this happens sign in (or others) happen over https.
Any help is appreciated
Here You go.
//force the page to use ssl
if ($_SERVER["SERVER_PORT"] != 443) {
$redir = "Location: https://" . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header($redir);
exit();
}
$_SERVER, It is an array containing information such as headers, paths, and script locations.
You can check against $_SERVER, specifically 'SERVER_PROTOCOL'
http://php.net/manual/en/reserved.variables.server.php
There should be a part of your code that is always run on every page. In an MVC it would be in your base controller. Other designs may include an init.php file on every page.
In this file have a whitelist of pages that require HTTPS.
$requires_https = array(
'sign-in.php' => TRUE,
'register.php' => TRUE
);
Then you need to determine which page was requested.
$url_info = pathinfo($_SERVER['REQUEST_URI']);
$page = $url_info['filename'];
Next check if you are on HTTP or HTTPS
$is_secure = ! empty($_SERVER['HTTPS']);
Finally you can do the checking:
if (isset($requires_https[$page]) AND ! $is_secure)
header('Location: https://www.yoursite.com/' . $page);
elseif ( ! isset($requires_https[$page]) AND $is_secure)
header('Location: http://www.yoursite.com/' . $page);
This could definitely be improved upon in the last part by using a custom redirect function and a site_url function that takes in the option of being secure or not and builds the proper URL.
It is worth mentioning that it generally doesn't matter if someone is left surfing in HTTPS. In fact most of Google's services are in HTTPS and with better internet connections surfing will eventually all be done in HTTPS. It is only important to make sure the pages that should be secure are secure, not make sure that pages that don't need to be secure aren't.
if ($_SERVER['SERVER_PORT'] != 443) {
header("HTTP/1.1 301 Moved Permanently");
header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
exit();
}
Using part of an init class / script -
You can run code to check if this page should require SSL prior, but this is the actual code to force redirect to SSL (and REQUEST_URI provides any dirs, etc.. to get the correct path).
Using on a single page (i.e. sign-in and register) -
This will redirect the user to this page in SSL (put this code near the top).
The 301 Moved Permanently will also prevent any negative SEO.
(A more) complete method: (includes the query string)
To determine if on https:
$secure = (!empty(filter_input(INPUT_SERVER, 'HTTPS')) &&
filter_input(INPUT_SERVER, 'HTTPS') !== 'off') ||
filter_input(INPUT_SERVER, 'SERVER_PORT') == 443;
as per https://stackoverflow.com/a/2886224
Then to redirect and include the query string:
if($secure){
header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
}
Using REQUEST_URI instead of PHP_SELF will include the query parameters (things after the ? in the URL).
And as always filter your user input (including these) with filter_input() or the like.

php / expression engine - redirect all URLs from one URL segment to another URL segment

I have an expression engine site that I recently redid and, while the titles of each article or page on the site did not change, the routes to them did. So, for example, where before I had:
site.com/site/code_single/name-of-page
I now have
site.com/main/code-item/name-of-page
How would I set up a redirect (either with expression engine tags or with PHP / .htaccess) so that all URLS matching site/code_single got redirected to their corresponding titles in site/main/code-item?
A single line of .htaccess really is the simplest solution here I think.
RedirectMatch ^/site/code_single/(.+)$ /main/code-item/$1 [L,R=301]
if you need a php solution you could call this function before any other code is executed(at the top of your main index.php.
I use this to reroute codeigniter urls without keeping duplicate urls alive what would happen if you use the routes.php
For those wondering why? Google loves 301 redirects and hates double content. Codeigniter has a nifty feature to make your own "routes" so you can use your own url where you need it. The problem is, the original "unwanted/ugly" url still is accessible and if google finds this out, your page takes a nosedive in seo ranking.
Having found that out I tried to uncover any sort of 301 redirect function in codeigniter only to hit a brick wall everytime, and .htaccess redirects failed time over time(and i'm not the only one, stackoverflow is full with it)
So that is why I decided to write this, with keeping speed in mind so as little "fancy manipulation" as possible to get the job done.
You'll have to add these lines at the very top of your first index.php file of codeigniter
require ('myobjects_x.php');
redirecttoHTTPS();
I have called the below file myobjects_x.php and saved it in my base directory where the first index.php file of codeigniter is.
/* Codeigniter 301 reroute script written by Michael Dibbets
* Copyright 2012 by Michael Dibbets
* http://www.facebook.com/michael.dibbets - mdibbets[at]outlook.com
* Licenced under the MIT license http://opensource.org/licenses/MIT
*/
function redirectToHTTPS()
{
// remove this if you don't need to redirect everyone to https
if($_SERVER['HTTPS']!=="on")
{
$redirect= "https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
header( "Status: 301 Moved Permanently" );
header("Location: $redirect");
exit(0);
}
// get the request url
$uri = urldecode($_SERVER['REQUEST_URI']);
// check for unwanted trailing slashes.
// if they exist redirect our visitor.
// we want urls without trailing slashes so we don't need to to check the same url twice
if($uri !== '/')
{
$slash = substr($uri, strlen($uri)-1, 1);
if($slash === '/')
{
$uri = substr($uri, 0, strlen($uri)-1);
$redirect= "https://".$_SERVER['HTTP_HOST'].''.$uri;
header( "Status: 301 Moved Permanently" );
header("Location: $redirect");
exit(0);
}
}
// if we have double slashes in our url for whatever reason replace them with single slashes
if(strpos($uri,'//') !== false)
{
$uri = str_replace('//','/',$uri);
$redirect= "https://".$_SERVER['HTTP_HOST'].''.$uri;
header( "Status: 301 Moved Permanently" );
header("Location: $redirect");
exit(0);
}
$urilistcount = 0;
//Just keep copy pasting this. In the orig you do the url without domain to check.
// The code checks the begin of the url, and if it matches it'll append anything that was
// behind the part you wanted to check. for example
// $urilist[$urilistcount]['orig'] = '/pressrelease/82/something';
// $urilist[$urilistcount]['good'] = 'http://www.domain.com/hereweare';
// $urilistcount++;
// will cause /pressrelease/82/something/we-have-something-to-say to reroute to
// http://www.domain.com/hereweare/we-have-something-to-say
//
// So make sure that your "top level" that's likely to match to a lot of sub pages
// is placed last in the array, and that the sub pages you want different reroute urls for route first
// When an route is encountered, processing stops at that point.
// Copy paste from here and add below it
$urilist[$urilistcount]['orig'] = '/pressrelease/82/something';
$urilist[$urilistcount]['good'] = 'https://www.domain.com/media/pressrelease/31/somewhereinteresting-with-an-title-in-url-for-seo';
$urilistcount++;
// End copy and paste
for($c=0;$c < $urilistcount;$c++)
{
if(strpos($uri,$urilist[$c]['orig'])===0)
{
$tmpx = strlen($urilist[$c]['orig']);
$tmpy = strlen($urilist[$c]['good']);
if($tmpx != $tmpy)
{
$tmpz = substr($uri,$tmpx);
// special check to replace dashes to underscores
// only when this word appears in the string to append.
if(strpos($tmpz,'/iamadash-')===0)
{
$tmpz = str_replace('-','_',$tmpz);
}
// add the extra variables to the good url.
$urilist[$c]['good'] .= $tmpz;
}
header("Status: 301 Moved Permanently" );
header("Location: " . $urilist[$c]['good']);
exit(0);
}
}
unset($urilist);
}
// filter out bad urls character/strings that cause codeigniter to break
function CIsafeurl($string)
{
return str_replace(array('&','‘','’ ','&','=','+','*','%','’',';','\'','!',',',':',' ','(',')','[',']','?','--','/'),array('-','','','-','','','','','','','','','','','-','','','','','','-','-'),$string);
}
Thanks - think I found a good solution online that involves having EE dynamically generate a list of URLs for 301 redirect:
http://www.blue-dreamer.co.uk/blog/entry/expressionengine-301-redirects-made-easier/
There's an add-on called Detour Pro that allows you to create 301 and 302 redirects within a simple admin panel in EE (it even provides metrics on each redirect you establish). It's worth a look if you have a lot of them to manage and want to avoid doing it in htaccess - particularly if not all of redirects have been mapped out and you need the client (within reason) to be able to create such redirects themselves.

PHP skipping script and click anchor tag

I have a form. After the form is filled out and the user clicks the submit button the user is taken to a thank you page. On the thank you page is a link (anchor tag) for the user to get to her home page. It works fine 19 out of 20 times.
The problem is, sometimes php skips the thank you page and goes directly to the home page. How is this possible? How is php clicking the link? I've gone over the code and it's completely correct. There is no javascript, just html and css.
Like I said, it doesn't do it every time and I guess it's not a bid deal I'd just like to understand what's going on. I'm using a simple header redirect like so
$url = "thanks/";
header("Location: $url");
exit();
What do you guys think is going? Is there any way to stop it?
Thanks
The RFC for the Location header requires a single absolute URI. This is also pointed out in the PHP manual in the notes section:
HTTP/1.1 requires an absolute URI as argument to » Location: including
the scheme, hostname and absolute path, but some clients accept
relative URIs. You can usually use $_SERVER['HTTP_HOST'],
$_SERVER['PHP_SELF'] and dirname() to make an absolute URI from a
relative one yourself
The problem may be to do with the fact that you're passing non standard headers to the browser. Browsers interpret the malformed header string differently and don't always behave as expected. Again as demonstrated in the PHP manual you should create an absolute URI, not an absolute or relative path before passing it to the header() function.
/* Redirect to a different page in the current directory that was requested */
$host = $_SERVER['HTTP_HOST'];
$uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
$extra = 'mypage.php';
header("Location: http://$host$uri/$extra");
exit;

Help on changing the page language without changing the current page (PHP)

langauage web. I set 3 links, Français... (href=changeLanguage.php?lang=fr,es,en)
changLanguage.php
session_start();
if(isset($_SESSION['bckTo']) && isset($_GET['lang'])){
$lang = preg_replace('/[^a-z]/','',trim($_GET['lang']));
#TODO
#More vlidation ...
$full_url = $_SESSION['bckTo'];
$full_url = str_replace(array('&lang=en','&lang=es','&lang=fr'),'',$full_url);
header('Location: '.$full_url.'&lang='.$lang.'');
}
$_SESSION['bckTo'] save the current URL for example: mysite.com/index.php?id=x&n_d=y
The problem is, the header translate the URL to: mysite.com/index.php?id=x&n_d=y&lang=en.
Any idea will be appreciate
Why not just set the language in session instead of via GET? Then you just have to put a link to change the language and and then redirect to the page. This would probably be best, given that you are already using sessions.
Example:
English
On the changeLanguage:
//code up here
if (isset($_SESSION['bckTo') && isset($_GET['lang'])) {
// $lang code here
$_SESSION['lang'] = $lang;
header('Location: ' . $_SESSION['bckTo']);
}
Then you would just need to change your language checking / displaying code to check the session variable rather than the GET (on the actual pages).
Running html_entity_decode will convert those HTML entities back into ampersands.
http://us2.php.net/manual/en/function.html-entity-decode.php

Categories