Monday, October 12, 2009

redirect(), Header(), #cakephp, #cake, #opensource

This is our PHP redirect() function, it has been tested with PHP versions >= 4.2.0. Seen a lot of requests for this on various mailing lists so we thought we'd share.
We've added support for different HTTP/1.1 3XX status codes. Each of the response codes tell the requesting User-Agent how to respond as described below.
In the W3C specification it's stated that the server should also give some content back for the User-Agent to render if it does not obey the redirect. This redirect function will output some pretty HTML if the headers have already been sent following the W3C intentions.
301 Moved Permanently - Forget the old page existed
302 Found - Use the same method (GET/POST) to request the specified page.
303 See Other - Use GET to request the specified page. Use this to redirct after a POST.
307 Temporary Redirect - Good for response to POST.
Usage example
// Do stuff here before sending headers
redirect('/')
redirect("/my/page")
redirect("http://www.foo.bar/page.htm",303)
redirect("./index.php",307)
?>
The redirect function itself
You may copy and paste this code freely where you need to, please give us credit it if you use it
// func: redirect($to,$code=307)
// spec: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
function redirect($to,$code=301)
{
$location = null;
$sn = $_SERVER['SCRIPT_NAME'];
$cp = dirname($sn);
if (substr($to,0,4)=='http') $location = $to; // Absolute URL
else
{
$schema = $_SERVER['SERVER_PORT']=='443'?'https':'http';
$host = strlen($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:$_SERVER['SERVER_NAME'];
if (substr($to,0,1)=='/') $location = "$schema://$host$to";
elseif (substr($to,0,1)=='.') // Relative Path
{
$location = "$schema://$host/";
$pu = parse_url($to);
$cd = dirname($_SERVER['SCRIPT_FILENAME']).'/';
$np = realpath($cd.$pu['path']);
$np = str_replace($_SERVER['DOCUMENT_ROOT'],'',$np);
$location.= $np;
if ((isset($pu['query'])) && (strlen($pu['query'])>0)) $location.= '?'.$pu['query'];
}
}

$hs = headers_sent();
if ($hs==false)
{
if ($code==301) header("301 Moved Permanently HTTP/1.1"); // Convert to GET
elseif ($code==302) header("302 Found HTTP/1.1"); // Conform re-POST
elseif ($code==303) header("303 See Other HTTP/1.1"); // dont cache, always use GET
elseif ($code==304) header("304 Not Modified HTTP/1.1"); // use cache
elseif ($code==305) header("305 Use Proxy HTTP/1.1");
elseif ($code==306) header("306 Not Used HTTP/1.1");
elseif ($code==307) header("307 Temporary Redirect HTTP/1.1");
else trigger_error("Unhandled redirect() HTTP Code: $code",E_USER_ERROR);
header("Location: $location");
header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
}
elseif (($hs==true) || ($code==302) || ($code==303))
{
// todo: draw some javascript to redirect
$cover_div_style = 'background-color: #ccc; height: 100%; left: 0px; position: absolute; top: 0px; width: 100%;';
echo "
\n";
$link_div_style = 'background-color: #fff; border: 2px solid #f00; left: 0px; margin: 5px; padding: 3px; ';
$link_div_style.= 'position: absolute; text-align: center; top: 0px; width: 95%; z-index: 99;';
echo "
\n";
echo "

Please See: ".htmlspecialchars($location)."

\n";
echo "
\n
\n";
}
exit(0);
}

3 comments:

  1. Maybe a good article but no code formatting makes it unreadable... I just looked at it and didn't bother reading it.

    ReplyDelete
  2. @anonymous: Wow, you're a real asset to the programming community. While Shahgeb has put a lot of effort in painstakingly describing how to deal with several redirect scenarios, you dismiss it by complaining about the form it's presented in.
    There's a saying in the Netherlands to describe just this: it's like throwing pearls to swines.

    ReplyDelete
  3. @guys

    I can understand your feeling. I wrote it once when I was not good programmer. Hope so will not disappoint you any more when next time you people get chance to ready my post.

    I have stopped to write post until I am not capable of. thanks for being patience :)

    ReplyDelete