You are here

function _linkchecker_link_node_ids in Link checker 6.2

Same name and namespace in other branches
  1. 7 linkchecker.module \_linkchecker_link_node_ids()

Returns IDs of nodes that contain a link which the current user may be allowed to view.

Important note: For performance reasons, this function is not always guaranteed to return the exact list of node IDs that the current user is allowed to view. It will, however, always return an empty array if the user does not have access to view *any* such nodes, thereby meeting the security goals of _linkchecker_link_access() and other places that call it.

In the case where a user has access to some of the nodes that contain the link, this function may return some node IDs that the user does not have access to. Therefore, use caution with its results.

Parameters

$link: An object representing the link to check.

$node_author_account: (optional) If a user account object is provided, the returned nodes will additionally be restricted to only those owned by this account. Otherwise, nodes owned by any user account may be returned.

Return value

An array of node IDs that contain the provided link and that the current user may be allowed to view.

2 calls to _linkchecker_link_node_ids()
_linkchecker_link_access in ./linkchecker.module
Determines if the current user has access to view a link.
_linkchecker_report_page in includes/linkchecker.pages.inc

File

./linkchecker.module, line 174
This module periodically check links in given node types, blocks, cck fields, etc.

Code

function _linkchecker_link_node_ids($link, $node_author_account = NULL) {
  static $fields_with_node_links = array();

  // Exit if all node types are disabled or if the user cannot access content,
  // there is no need to check further.
  $linkchecker_scan_nodetypes = array_filter(variable_get('linkchecker_scan_nodetypes', array()));
  if (empty($linkchecker_scan_nodetypes) || !user_access('access content')) {
    return array();
  }

  // Disable language negotiation temporarily, re-enable it later.
  if (module_exists('i18n')) {
    i18n_selection_mode('off');
  }

  // Get a list of nodes containing the link, using db_rewrite_sql() to allow
  // node access modules to exclude nodes that the current user does not have
  // access to view.
  if (!empty($node_author_account)) {
    $nodes = db_query(db_rewrite_sql('SELECT n.nid
      FROM {node} n
      INNER JOIN {linkchecker_nodes} ln ON ln.nid = n.nid
      INNER JOIN {node_revisions} r ON r.vid = n.vid
      WHERE ln.lid = %d AND (n.uid = %d OR r.uid = %d)'), $link->lid, $node_author_account->uid, $node_author_account->uid);
  }
  else {
    $nodes = db_query(db_rewrite_sql('SELECT n.nid
      FROM {node} n
      INNER JOIN {linkchecker_nodes} ln ON ln.nid = n.nid
      WHERE ln.lid = %d'), $link->lid);
  }

  // Re-enable language negotiation.
  if (module_exists('i18n')) {
    i18n_selection_mode('reset');
  }

  // Check if the current user has access to view the link in each node.
  // However, for performance reasons, as soon as we find one node where that
  // is the case, stop checking and return the remainder of the list.
  $nids = array();
  $access_allowed = FALSE;
  while ($node = db_fetch_object($nodes)) {
    if ($access_allowed) {
      $nids[] = $node->nid;
      continue;
    }
    $node = node_load($node->nid);

    // We must check whether the link is currently part of the node; if not, we
    // do not want to return it (and it is not safe to, since we cannot know if
    // it contained access restrictions for the current user at the point which
    // it was originally extracted by the Link checker module).
    if (!isset($fields_with_node_links[$node->nid])) {
      $fields_with_node_links[$node->nid] = _linkchecker_extract_node_links($node, TRUE);
    }
    if (empty($fields_with_node_links[$node->nid][$link->url])) {
      continue;
    }

    // If the link only appears in CCK fields and a field access module is
    // being used, we must check that the current user has access to view at
    // least one field that contains the link; if they don't, we should not
    // return the node.
    $fields = $fields_with_node_links[$node->nid][$link->url];
    if (!in_array('node', $fields) && module_exists('content') && module_implements('field_access')) {
      $fields_with_access = array();
      foreach (content_fields(NULL, $node->type) as $field) {

        // Only check link and text fields, since those are the only types we
        // extract links from.
        if (($field['type'] == 'link' || $field['type'] == 'text') && content_access('view', $field, NULL, $node)) {
          $fields_with_access[] = $field['field_name'];
        }
      }
      if (!array_intersect($fields, $fields_with_access)) {
        continue;
      }
    }
    $nids[] = $node->nid;
    $access_allowed = TRUE;
  }
  return $nids;
}