1

I have implemented hook_node access so that two users cannot view each other's posts if they do not have the right permission (I implemented the permission in hook_permission). I use a comparison with $node->uid as follows:

 function mymodule_node_access( $node, $op, $account)
 {
   global $user;                                                                                                                                                       
   $type = is_string($node) ? $node : $node->type;

   switch($type)
   {
    case "myCustomType":

      if ( ($user->uid != $node->uid) && !user_access("view other's posts"))
       {
              return NODE_ACCESS_DENY;

       }
       break;

   }

}

Everything works fine but I do get the following warning:

Notice: Trying to get property of non-object in mymodule_node_access().

This is caused by this: $node->uid. Drupal complains that $node is a not a stdobject (it seems to actually be string containing the node's type). Yet the code still works which I do not understand why.

What is the proper way to access the node's uid from hook_node_access?

3 Answers 3

4

The $node parameter is

Either a node object or the machine name of the content type on which to perform the access check.

When that hook is invoked with the create op, there's no node object available, so $node is a string.

You're already handling that bit, but you're missing a check on the $op parameter. The reason it's working is because when your function is invoked with the op you're trying to target (probably view), $node is an object and has a uid property.

With your current code, you'll get one of those notices every time someone other than user 1 tries to create a node, because $node is not an object.

Try re-working your code like this:

function mymodule_node_access( $node, $op, $account)
 {
   if ($op == 'create') {
     $type = $node;
     // You can be reasonably sure that $account is the user who's trying to create the node here.
     // You'll probably want to ignore this bit and check $op specifically for the 
     // actions you're looking for; this is just here to show the workflow.
   }
   else {
     if ($node->type == 'myCustomType') {
       // Be sure to use the $account var here, not the global $user object
       if ( ($account->uid != $node->uid) && !user_access("view other's posts", $account)) {
       return NODE_ACCESS_DENY;
     }
   }

   return NODE_ACCESS_IGNORE;
0

You'll find the uid in the $account object with $account->uid.

2
  • I already have the current user's uid using $user->uid. What i need is the current's node uid (the uid of the creator of the node). $account seems to refer to the user currently viewing the node, not the creator of the node.
    – Baba
    Commented Aug 3, 2013 at 17:21
  • Hmm... maybe it bails out when the node hasn't been saved yet. When it's being created node->uid isn't available. Commented Aug 3, 2013 at 17:25
0

The value passed in $node could also be the content type of the node being created; that is why the following line is necessary to get the content type.

$type = is_string($node) ? $node : $node->type;

The reason the code works is that a non initialized variable, or object property, is set to NULL. In your case, the control statement is really executing the following code, when the node is being created.

  if (($user->uid != NULL) && !user_access("view other's posts")) {
    return NODE_ACCESS_DENY;
  }

Since $user->uid is never NULL, that is the reason why the code work the same, even if it raises a PHP warning.

To avoid the warning message, it is enough to execute code similar to the following one.

 function mymodule_node_access( $node, $op, $account) {                                                                                                                                                       
   if (($op == 'view') && ($node->type == "myCustomType") && ($user->uid != $node->uid)) {
     return user_access("view other's posts") ? NODE_ACCESS_ALLOW : NODE_ACCESS_DENY;
   }

   // Returning nothing from this function would have the same effect.
   return NODE_ACCESS_IGNORE;
 }

I changed the code because I think that what you are trying to do is the following:

  • When the content type is myCustomType, the user is viewing a node created by another user, and the user who is watching the node has the view other's posts permission, allow that user to see the node
  • When the content type is myCustomType, the user is viewing a node created by another user, and the user who is watching the node doesn't have the view other's posts permission, don't allow that user to see the node

What your code is doing is:

  • When the content type is myCustomType, the user is viewing/editing/deleting a node created by another user, and the user who is acting on the node doesn't have the view other's posts permission, don't allow that user to do anything on that node the node
  • In the other cases, let the other modules decide about the access permission

What I notice is that:

  • Despite the permission is "view other's posts," it is applied even when the currently logged-in user is doing something else than viewing the node
  • In the case the currently logged-in user has the view other's posts permission and is doing something on the node created by somebody else, it lets other modules decide the user's permission to access the node

If the permission is really about any operation done on a node, then it should be renamed, or the code should use more than one permission. The latter is what the Node module does, since for every content type there are a permission to create a node of that content type, to edit nodes of that content type, and to delete nodes of that content type.

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.