Page 1 of 1

Need help with || and redirection

Posted: Tue Nov 27, 2012 1:14 pm
by dharmeshb
I have this code which is not working for the user roles "LeagueAdmin" and "TeamAdmin", but works fine for "WebAdmin" and "Viewer". If I login as a "LeagueAdmin" or "TeamAdmin" I get redirected to index.php, where for test purposes I echoed the roles to make sure the user role is correctly read. It does read the roles accurately. Any idea why it is not working? Even more baffling is why is the code redirecting me to index.php.

Code: Select all

if($_SESSION['UserRole'] === 'WebAdmin'
         || $_SESSION['UserRole'] === 'LeagueAdmin'
         || $_SESSION['UserRole'] === 'TeamAdmin'){
         header('Location: dashboard.php');
         exit();
     }
     elseif ($_SESSION['UserRole'] === "Viewer") {
       header('Location: viewer.php');
       exit();
}

Re: Need help with || and redirection

Posted: Tue Nov 27, 2012 2:15 pm
by Eric!
That should work provided your values are of the same type, case and don't contain any extra bits like white spaces. It might contain binary data as well which cause === to fail too. Since we can't see the contents of your variables it's hard to say why it isn't working the way you expect. However if you test it by defining the value you'll see it works. So something is going on with the variable value before your script tests it.

Typically I use a binary safe string comparison function like strcasecmp or strcmp instead of relying on === or ==.

If it is redirecting to index.php, then it is falling outside of your if/then tests to somewhere else in your code.

Re: Need help with || and redirection

Posted: Tue Nov 27, 2012 7:15 pm
by Benjamin
Header redirects should contain an absolute path, not a relative path.

Re: Need help with || and redirection

Posted: Tue Nov 27, 2012 10:02 pm
by Christopher
Yes, I think it needs to be:

Code: Select all

header('Location: http://www.mysite.com/dashboard.php');

Re: Need help with || and redirection

Posted: Tue Nov 27, 2012 10:27 pm
by Eric!
I've wondered about that. From what I understand there was a bug in the spec and UA's are expected to resolve relative paths based on the request uri. I've tested relative paths with IE9 and various FF versions with out any redirect issues. However I'm not sure I've ever checked if the apache mod_asis was modifying them.

Edit: I just did another quick check of the actual headers and with http/1.1 and the relative uri's are handled fine by ff.

Re: Need help with || and redirection

Posted: Tue Nov 27, 2012 10:53 pm
by Benjamin
Although the specifications don't really say you shouldn't use relative URI's, they kind of do. Most browsers do support this though.

But my interpretation of the HTTP/1.1 specifications lead me to believe that the full URI should be specified in the redirect. A full URI also conveys the protocol in addition to being accurate regardless of whether you are in a sub directory of the website or not.
http://www.w3.org/Addressing/URL/4_3_Partial.html wrote:Partial (relative) form
Within a object whose URI is well defined, the URI of another object may be given in abbreviated form, where parts of the two URIs are the same. This allows objects within a group to refer to each other without requiring the space for a complete reference, and it incidentally allows the group of objects to be moved without changing any references. It must be emphasized that when a reference is passed in anything other than a well controlled context, the full form must always be used.
A header redirect is never in a "well controlled context" because the base URI is specified in HTML, not the header. Therefore the browser would never know what the base URI was when it receives a relative URI. It can certainly guess, but not with 100% accuracy.
http://www.ietf.org/rfc/rfc2616.txt wrote:10.3.2 301 Moved Permanently

The requested resource has been assigned a new permanent URI and any
future references to this resource SHOULD use one of the returned
URIs. Clients with link editing capabilities ought to automatically
re-link references to the Request-URI to one or more of the new
references returned by the server, where possible. This response is
cacheable unless indicated otherwise.

The new permanent URI SHOULD be given by the Location field in the
response. Unless the request method was HEAD, the entity of the
response SHOULD contain a short hypertext note with a hyperlink to
the new URI(s).

If the 301 status code is received in response to a request other
than GET or HEAD, the user agent MUST NOT automatically redirect the
request unless it can be confirmed by the user, since this might
change the conditions under which the request was issued.

Note: When automatically redirecting a POST request after
receiving a 301 status code, some existing HTTP/1.0 user agents
will erroneously change it into a GET request.
The specifications are calling it a "permanent URI". It doesn't explicitly state absolute, but I am interpreting it that way.

Re: Need help with || and redirection

Posted: Tue Nov 27, 2012 11:02 pm
by Eric!
I'm probably missing the nuances of what you're pointing out. I was thinking the UA knows the base from the request-uri that generates the redirect. Wouldn't that be a well controlled context (i.e. the header)?

It will be interesting to see if dharmeshb's problem is fixed with an absolute URI. But it seems odd that a relative URI would end up at index.php. I guess the UA might choke and fall back to index.html and the server comes back with another redirect to index.php.

Re: Need help with || and redirection

Posted: Tue Nov 27, 2012 11:18 pm
by Benjamin
Well the base URI can be specified in the <head> of an html document. But the header redirect is sent prior to that, if any HTML is even sent at all.

Also, consider that the same code could send a header redirect regardless of whether you are at the site root (e.g. index.php) or a subdirectory (e.g. categories/1/blue/). In other words, should "Location: newpage.php" be redirected to newpage.php or categories/1/blue/newpage.php?

Finally, even the protocol could be different than the current one in use.

These are the reasons why I believe it's not possible for the base URI to be in a "well controlled context" (when it's not absolute and when it's sent in a header) because the UA can only base it's decision on the current URI, which may or may not be accurate (relative to the actual destination) or subject to change.

Sorry, this is a bit abstract. Based on my experience I'd never count on a relative URI in a redirect to be failsafe.

Re: Need help with || and redirection

Posted: Tue Nov 27, 2012 11:31 pm
by Benjamin
I rewrote your code so that it's organized and utilizes decomposition. I removed the convoluted IF conditionals and replaced it with a switch which is more appropriate. Further I added exception handling which will allow you to handle errors easily based on specific events. Now you should be able to read the code easily and also modify it easily as well. This is untested.

Code: Select all

define('BASE_HREF', 'http://somedomain.com');

function redirect($request) {
    $location = BASE_HREF . "/" . ltrim($request, '/');
    header("HTTP/1.1 301 Moved Permanently");
    header("Location: $location");
    echo "<html><head><title>Moved Permanently</title></head><body><p>The resource you requested has moved to <a href=\"$location\">$location</a>.</p></body></html>";
    exit();
}

try {
    if (empty($_SESSION['UserRole'])) {
        throw new Exception('');
    }

    switch($_SESSION['UserRole']) {
        case 'WebAdmin':
        case 'LeagueAdmin':
        case 'TeamAdmin':
            redirect('dashboard.php');
            break;
        case 'Viewer':
            redirect('viewer.php');
            break;
        default:
            throw new Exception('');
    }
} catch (Exception $e) {
    redirect('login.php');
}

Re: Need help with || and redirection

Posted: Wed Nov 28, 2012 8:53 am
by Eric!
Thanks for taking the time to share your knowledge on this. I should say that I think using an absolute path is the best practice so there's no confusion. At the same time, I would love to learn which UA the OP is using if that does turn out to be the cause of his trouble.

I've had a hard time following what's really going on with rfc2616 because I've read many interpretations of how relative uri's are supposed to be handled. So a while ago I did an experiment where I recorded successful redirects using a relative paths and counted the UA's that didn't show up. Out of the different user agents all of them followed the relative link correctly. I wish I still had the info but it's gone now. I did double check the apache mod_asis wasn't modifying the headers.

I also experimented with the sub-directory issue and found ua's I played with tend to treat them like file systems. If the relative uri has a leading / then it takes the base from the request-uri and appends the relative uri. If the leading / is missing it takes the full request uri (minus the file) and appends the new relative uri. This of course might not work on the same on all ua's....

I've never tried switching protocols between a redirect, but I've been trying to think of a scenario where the request-uri wouldn't reflect the right base in that case. I'm afraid my imagination is a bit limited on this. It seems that if you wanted to switch protocols the server would have to provide an absolute uri by definition.

Re: Need help with || and redirection

Posted: Thu Nov 29, 2012 8:31 am
by dharmeshb
As a complete beginner.. I have no idea what UA is..

However, I figured the cause after digging around after Eric's reply. I thought I had looked at every page before posting my issue. Looks like I missed the obvious.. When I reviewed my dashboard.php, it was redirecting as expected, since the only roles it was checking were "WebAdmin" and "Viewer", anything except those two would be redirected to index.php.

I like the Switch case.. :) I'll try switching (no pun intended :)) my complex IFs

Re: Need help with || and redirection

Posted: Thu Nov 29, 2012 10:19 pm
by Eric!
Sorry, we got a little carried away, but it was a good discussion. And if you look at Benjamin's code there are several things to learn from there like exceptions, and some header lines to make your redirect more complete.

A UA is short for User Agent like a browser, but it could be anything connecting to the web and requesting data.