University of Oregon

PHP redirects if the headers have already been sent.

I ran in to a situation with some inherited code today.
The developer wanted to redirect users to a course listing page if they landed on a date/time listing that couldn’t be found.
See this code below; they check for an empty $dateTime var and create a log message before attempting to redirect the user.

if (empty($dateTime)) {
  $logger->err('DateTime with the id of '.$_REQUEST['dt_id'].' cannot be located.');
  Header( 'Location: course_list.php'); // Go back to the course list

Unfortunately the headers had already been sent to the browser and the Header function call was ignored and the user only saw a partially loaded web page with no body content.

In the past I had implemented a fall-back with a meta and js redirect but I thought that could be improved upon.
Stack Overflow had some nice responses to a previous question and one of them included Redirect function that checked if the headers were already sent: headers_sent().
I liked that. So I added my fall back to that function.

Next I swapped that Header function call with the Redirect function call:

if (empty($dateTime)) {
  $logger->err('DateTime with the id of '.$_REQUEST['dt_id'].' cannot be located.');
  Redirect('course_list.php'); // Go back to the course list

Problem solved.

Here’s the function (note: it’s wrapped in a function_exists() call to make sure I don’t declare this twice at any point):

  function Redirect($url, $code = 302) //from
    #echo 'redirecting';
    if (strncmp('cli', PHP_SAPI, 3) !== 0)
      #echo 'cli';
      if (headers_sent() !== true)
        if (strlen(session_id()) > 0) // if using sessions
            session_regenerate_id(true); // avoids session fixation attacks
            session_write_close(); // avoids having sessions lock other requests
        if (strncmp('cgi', PHP_SAPI, 3) === 0)
            header(sprintf('Status: %03u', $code), true, $code);
      header('Location: ' . $url, true, (preg_match('~^30[1237]$~', $code) > 0) ? $code : 302);
      } else { //headers have already been sent. Use Meta refresh with js location.href fallback
        <em>This page has moved.</em><br />
        If you are not redirected automatically please follow this link: <a href=\"<?php echo $url; ?>"><?php echo $url; ?></a>.
        <meta http-equiv="Refresh" content="1;
        URL=<?php echo $url; ?>">
        <script language=javascript>
        setTimeout("location.href='<?php echo $url; ?>'",1);
      }//end if headers_sent


Redirect an entire Drupal site – .htaccess

I’ve migrated several Drupal sites to new servers lately and since some of those sites were in development they didn’t have a proper cName. So I’ve been using a .htaccess redirect to channel all traffic from the old site to the new ones.
Here’s an example of the new .htaccess file I placed in the /hr_diac directory on my old server:
##Redirect everything that pointed to /hr_diac to$1

RewriteEngine on
RewriteCond %{REQUEST_URI} /hr_diac [nc]
RewriteRule ^(.*)$$1 [r=301,nc]

To clarify; I completely replaced the drupal .htaccess file with this file.
It’s pretty simple but it works.

Handle sites/default/files redirect in Drupal 6 with Custom Errors module

When I’ve migrated sites into Aegir recently, I find that the users have many links in the content hard-coded to files in the default directory.
While it is possible to use the Scanner search & replace module to ferret those out. It’s not always thorough enough. For example, it doesn’t search and replace menu link urls, or content in blocks, views, headers, footers or custom fields. You can specify custom fields and locations to search but that’s another bag of worms that fraught with issues.
So I wanted to find a simple way to catch any hard coded links that I missed.
Enter the Custom Error module.

I’ve been using it to provide a populated search form on the 404 ‘Not found’ page as well as a site map but I also have a few custom redirects in there so adding an option for sites/default/files was simple.

Here’s the code: (more…)