0

My custom error handler module is somewhat based on the customerror module, but instead of returning markup, my menu callback function redirects based on the original path. It registers error paths as follows:

function my_customerror_menu() {
  $items = array();

  $items['my_customerror/%'] = array(
    'title callback' => FALSE,
    'access callback' => TRUE,
    'page callback' => 'my_customerror_page',
    'page arguments' => array(1),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

'access callback' => TRUE should make it accessible to all users. I can use the path my_customerror/404 for example in the site settings and it is recognized as a valid path. This works fine in a local instance and on the Pantheon development site, but once I pushed it to the Pantheon test environment, my_customerror/404 is not invoked on 404 - Drupal uses the default error response. Unless I am logged in, then it works in Test as well.

But the path my_customerror/404 works regardless when I type it in manually and does what it should. Somehow Drupal erroneously thinks that this path is not accessible to anonymous users.

What could be causing this?

Here is a simplified version of the callback function that shows what it does:

function my_customerror_page($code) {
  $dest = variable_get('my_customerror_' . $code . '_default', '');
  switch ($code) {
    [conditional stuff]
    default:
      header('Status: 301 Moved Permanently', false, 301);
      header("Location: " . $dest);
      break;
  }
  return "";
}

Don't ask why I use header() and not drupal_goto() ....

Just bringing something into the problem description that I already mentioned in a comment. When the Devel module is turned on and anonymous users are given permission to see developer output, it starts working! But this is not a solution, I obviously can't do this in the Live environment.

8
  • What does the callback return for anonymous users? Is it an integer?
    – Jaypan
    Commented Jun 12, 2020 at 14:03
  • @Jaypan it returns an empty string in all cases and adds a redirect to the response.
    – cdonner
    Commented Jun 12, 2020 at 14:05
  • D7 doesn't have the Response class to which redirects can be added. Can you please show your code?
    – Jaypan
    Commented Jun 12, 2020 at 14:11
  • @jaypan - added the essential parts of the callback, leaving out all the conditional stuff.
    – cdonner
    Commented Jun 12, 2020 at 14:17
  • So, weirdly enough, when I turned on Devel and gave anonymous users permission to access debug output, the error page started to be used .... I obviously can't keep Devel enabled, so I will play some more with what exactly breaks/fixes it.
    – cdonner
    Commented Jun 12, 2020 at 14:47

2 Answers 2

1

You're doing a switch(), but with only a default for the switch and no options, it means the switch is unnecessary. Drupal also provides the drupal_goto() function, which handles both redirects, as well as cancelling killing the script so the redirect can proceed. Your code can be simplified to:

function my_customerror_page($code) {
  $dest = variable_get('my_customerror_' . $code . '_default', '');
  drupal_goto($dest);
}

Or if you're really set on using header() to set headers for whatever reason, you just need to add drupal_exit() after your call to header().

5
  • I added a placeholder to the code snippet that makes it more obvious why the switch is there. Granted, it is not relevant for the question or answer and I could have removed it. drupal_goto does its own path validation, does not work with external URLs, and I just could not get it working with the query string that I need. It did not work for me.
    – cdonner
    Commented Jun 12, 2020 at 16:05
  • And thank you for looking into this with me! Much appreciated.
    – cdonner
    Commented Jun 12, 2020 at 16:07
  • Oh, and I am not sure calling drupal_exit is the right thing to do here - doesn't this stop the request pipeline? Isn't it better to allow the callback to return and complete in an orderly fashion?
    – cdonner
    Commented Jun 12, 2020 at 16:13
  • That's what drupal_exit() does. If you don't call it, the rest of the Drupal process runs through before your redirect happens. drupal_exit() shuts down the necessary bits, without running the unnecessary bits.
    – Jaypan
    Commented Jun 12, 2020 at 16:14
  • I did more testing with a lot of permutations of all the variable elements here. Using drupal_exit() does not change anything, so I can't accept your answer. Not setting the response code with header() was the thing that ultimately resolved this, if we want to call it that. It remains a mystery to me why it would matter.
    – cdonner
    Commented Jun 12, 2020 at 17:55
-1

Two subtle changes to the callback function appear to have resolved this. It is working now:

  1. returning something other than an empty string
  2. using drupal_add_http_header() to set the response code instead of the low level PHP function.

As in:

function my_customerror_page($code) {
  $dest = variable_get('my_customerror_' . $code . '_default', '');
  drupal_add_http_header('Status', '301 Moved Permanently');
  header("Location: " . $dest);
  return "redirecting ....";
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.