Drupal - How can a module detect when the "access denied" page is output?
You can set which pages are displayed when 403 & 404 errors occurs (admin/settings/error-reporting).
I guess you can add a new page in your hook_menu()
, then set this page as the 403 error callback. When your custom menu callback is hit, you know you're outputting the "access denied" page!
I do this in Boost 7.x. It's not pretty, but it does get the job done.
- hook_page_delivery_callback_alter()
- boost_page_delivery_callback_alter()
- boost_deliver_html_page()
function boost_page_delivery_callback_alter(&$callback, $set = FALSE) {
if ($callback == 'drupal_deliver_html_page') {
$callback = 'boost_deliver_html_page';
}
}
function boost_deliver_html_page($page_callback_result) {
global $_boost;
// Menu status constants are integers; page content is a string or array.
if (is_int($page_callback_result)) {
// @todo: Break these up into separate functions?
switch ($page_callback_result) {
// …
case MENU_ACCESS_DENIED:
// 403 page.
$_boost['menu_item']['status'] = 403;
break;
// …
}
// …
}
// …
}
In Drupal 7, the function that returns the already set HTTP headers is drupal_get_http_header(), which requires the HTTP header name as parameter. Looking at authorize_access_denied_page(), and drupal_fast_404() code makes clear which values to pass to that function.
// authorize_access_denied_page()
drupal_add_http_header('Status', '403 Forbidden');
watchdog('access denied', 'authorize.php', NULL, WATCHDOG_WARNING);
drupal_set_title('Access denied');
return t('You are not allowed to access this page.');
// drupal_fast_404()
if ($fast_paths && preg_match($fast_paths, $_GET['q'])) {
drupal_add_http_header('Status', '404 Not Found');
$fast_404_html = variable_get('404_fast_html', '<html xmlns="http://www.w3.org/1999/xhtml"><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>');
// Replace @path in the variable with the page path.
print strtr($fast_404_html, array('@path' => check_plain(request_uri())));
exit;
}
When the "Status" header starts with 403, then Drupal output an access denied page.
Make sure the call to drupal_get_http_header('Status')
happens late. Calling during hook_init()
is too soon, but calling it during hook_page_alter()
(or any theme preprocess hook) will have the updated header information.