views:

60

answers:

1

How do you issue a 403 for certain nodes? I tried using drupal_access_denied. While I got an Access Denied message, the watchdog is filled with:

Cannot modify header information - headers already sent

Is that normal? Am I not using drupal_access_denied right?

+3  A: 

Using the suggested hook_nodeapi() is still too late.

If you use the $op = load, you'll likely exhaust your memory because Drupal has already committed to all the normal things it does when it loads a node (including loading it multiple times).

If you use $op = view, you can "fake" it if you do the following:

function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'view':
      drupal_access_denied();
      exit();
      break;
  }
}

But it's not a real 403: it won't be reported as such except in Watchdog, and all the normal stuff will still load and render as if the node was there.

For an easy hack, you could use hook_init():

function mymodule_init() {
  $nodes_403 = array(42, 69, 187);
  if (arg(0) == 'node' && in_array(arg(1), $nodes_403))
    drupal_access_denied();
    exit();
  }
}

But that's bypassing Drupal's built-in permissions system unnecessarily. Instead, you want to take advantage of Drupal's node access rights system to deny access to the node.

If you defined your own content type in the module, you could use hook_access():

function mymodule_access($op, $node, $account) {
  $nodes_403 = array(42, 69, 187);

  if (in_array($node->nid, $nodes_403)) {
    return FALSE;
  }
}

But if you don't define your own custom content types, hook_access() is never invoked. So instead, you need to override the node path's access callback with your own:

function mymodule_menu_alter(&$items) {
  $items['node/%node']['access callback'] = 'mymodule_access';
}

function mymodule_access($op, $node, $account = NULL) {
  $nodes_403 = array(42, 69, 187);

  if ($op == 'view' && in_array($node->nid, $nodes_403)) {
    return FALSE;
  }

  return node_access($op, $node, $account);
}

Because of the hook_menu_alter() implementation, make sure to rebuild your menu system after implementing the above.

Mark Trapp
I was able to get the 'headers' error to go away by doing drupal_access_denied(); break; at each check- but I will look at your method too. Wish this kind of explanation was in the API. http://api.drupal.org/api/function/drupal_access_denied/6
Kevin
@Kevin: the node access API is notoriously badly documented, which doesn't help when it's badly designed to begin with (why can I only use `hook_access()` when I define my own custom content type, and not on all nodes? Or for that matter, on *any* page). Drupal 7 cleaned up the API, so hopefully the documentation gets some love.
Mark Trapp
Yeah- I noticed this was breaking certain cron functions for user 0. I refactored to your method. Also, am I crazy, or does nodeapi view case not work like you'd expect?
Kevin
@Kevin, the `view` operation in `hook_nodeapi()` is the non-node module complement to [`hook_view()`](http://api.drupal.org/api/function/hook_view/6): it's mainly used to add additional fields to `$node->content`, and it's called extremely late in the node building process. By the time it gets called, you've already committed to displaying the node.
Mark Trapp
Gotcha. Used your method. What an odd quirk.
Kevin

related questions