You are here

function _linkchecker_status_handling in Link checker 5.2

Same name and namespace in other branches
  1. 6.2 linkchecker.module \_linkchecker_status_handling()
  2. 7 linkchecker.module \_linkchecker_status_handling()

Status code handling.

Parameters

$link: An object containing the url, lid and fail_count.

$response: An object containing the HTTP request headers, response code, headers, data and redirect status.

1 call to _linkchecker_status_handling()
linkchecker_cron in ./linkchecker.module
Implementation of hook_cron().

File

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

Code

function _linkchecker_status_handling($link, $response) {
  $useragent = variable_get('linkchecker_check_useragent', 'Drupal (+http://drupal.org/)');
  $ignore_response_codes = preg_split('/(\\r\\n?|\\n)/', variable_get('linkchecker_ignore_response_codes', "200\n302\n304\n401\n403"));

  // FIXME: drupal_http_request() may not provide an UTF8 encoded error message
  // what results in a database UPDATE failure. See http://drupal.org/node/371495
  // for more information. ISO-8859-1 as source encoding may be wrong, but WFM.
  if (!empty($response->error) && !drupal_validate_utf8($response->error)) {
    $response->error = drupal_convert_to_utf8($response->error, 'ISO-8859-1');
  }

  // Prevent E_ALL warnings for non-existing $response->error.
  if (!isset($response->error)) {
    $response->error = '';
  }
  switch ($response->code) {
    case 200:
    case 304:
      db_query("UPDATE {linkchecker_links} SET code = %d, error = '%s', fail_count = %d, last_checked = %d WHERE lid = %d", $response->code, $response->error, 0, time(), $link->lid);

      //watchdog('linkchecker', t('Checked %link successfully.', array('%link' => $link->url)));
      break;
    case 301:
      db_query("UPDATE {linkchecker_links} SET code = %d, error = '%s', fail_count = fail_count+1, last_checked = %d WHERE lid = %d", $response->code, $response->error, time(), $link->lid);

      // A HTTP status code of 301 tells us an existing link have changed to
      // a new link. The remote site owner was so kind to provide us the new
      // link and if we trust this change we are able to replace the old link
      // with the new one without any hand work.
      $auto_repair_301 = variable_get('linkchecker_action_status_code_301', 0);
      if ($auto_repair_301 && $auto_repair_301 <= $link->fail_count + 1 && $response->redirect_code == 200 && valid_url($response->redirect_url, TRUE)) {

        // NODES: Autorepair all nodes having this outdated link.
        $res = db_query("SELECT * FROM {linkchecker_nodes} WHERE lid = %d", $link->lid);
        while ($row = db_fetch_object($res)) {
          $node = node_load(array(
            'nid' => $row->nid,
          ));

          // Create array of node fields to scan (for e.g. $node->title, $node->links_weblink_url).
          $text_items = array();
          $text_items[] = 'title';
          $text_items[] = 'body';
          $text_items[] = 'teaser';

          // Update 'weblink' nodes from 'links' module package.
          if (module_exists('links_weblink') && $node->type == 'weblink' && isset($node->links_weblink_url)) {
            $text_items[] = 'links_weblink_url';
          }

          // Update 'weblinks' nodes from 'weblinks' module.
          if (module_exists('weblinks') && $node->type == 'weblinks' && isset($node->url)) {
            $text_items[] = 'url';
          }

          // Now replace the outdated link with the permanently moved one in all node fields.
          foreach ($text_items as $text_item) {
            _linkchecker_link_replace($node->{$text_item}, $link->url, $response->redirect_url);
          }

          // Search for CCK-fields of types 'link' and 'text'.
          if (module_exists('content')) {
            $fields = content_fields(NULL, $node->type);
            foreach ($fields as $field) {
              if (isset($node->{$field['field_name']})) {
                if (module_exists('link') && $field['type'] == 'link') {
                  foreach ($node->{$field}['field_name'] as $delta => $item) {
                    _linkchecker_link_replace($node->{$field['field_name']}[$delta]['url'], $link->url, $response->redirect_url);
                  }
                }
                elseif (module_exists('text') && $field['type'] == 'text') {
                  foreach ($node->{$field}['field_name'] as $delta => $item) {
                    _linkchecker_link_replace($node->{$field['field_name']}[$delta]['value'], $link->url, $response->redirect_url);
                  }
                }
              }
            }
          }

          // Always use the default revision setting. See node_form().
          $node_options = variable_get('node_options_' . $node->type, array(
            'status',
            'promote',
          ));
          $node->revision = in_array('revision', $node_options);

          // Generate a log message for the node_revisions table, visible on the node's revisions tab.
          $log_message = t('Changed permanently moved link in %node from %src to %dst.', array(
            '%node' => url('node/' . $row->nid),
            '%src' => $link->url,
            '%dst' => $response->redirect_url,
          ));
          $node->log = $log_message;

          // Save changed node and update the node link list.
          node_save($node);
          watchdog('linkchecker', $log_message);
        }

        // COMMENTS: Autorepair all comments having this outdated link.
        if (module_exists('comment')) {
          $res = db_query("SELECT * FROM {linkchecker_comments} WHERE lid = %d", $link->lid);
          while ($row = db_fetch_object($res)) {
            $comment = _linkchecker_comment_load($row->cid);

            // Create array of comment fields to scan (for e.g. $comment->subject, $comment->comment).
            $text_items = array();
            $text_items[] = 'subject';
            $text_items[] = 'comment';

            // Now replace the outdated link with the permanently moved one in all comment fields.
            foreach ($text_items as $text_item) {
              _linkchecker_link_replace($comment[$text_item], $link->url, $response->redirect_url);
            }

            // Save changed comment and update the comment link list.
            comment_save($comment);
            watchdog('linkchecker', t('Changed permanently moved link in comment %comment from %src to %dst.', array(
              '%comment' => $comment['cid'],
              '%src' => $link->url,
              '%dst' => $response->redirect_url,
            )));
          }
        }

        // BOXES: Autorepair all boxes having this outdated link.
        $res = db_query("SELECT * FROM {linkchecker_boxes} WHERE lid = %d", $link->lid);
        while ($row = db_fetch_object($res)) {
          $box = block_box_get($row->bid);

          // Create array of box fields to scan.
          $text_items = array();
          $text_items[] = 'info';
          $text_items[] = 'title';
          $text_items[] = 'body';

          // Now replace the outdated link with the permanently moved one in all box fields.
          foreach ($text_items as $text_item) {
            _linkchecker_link_replace($box[$text_item], $link->url, $response->redirect_url);
          }

          // Save changed node and update the node link list.
          block_box_save($box, $row->bid);

          // There is no hook that fires on block_box_save(), therefore do it programmatically.
          _linkchecker_add_box_links($box, $row->bid);
          watchdog('linkchecker', t('Changed permanently moved link in box %bid from %src to %dst.', array(
            '%bid' => $row->bid,
            '%src' => $link->url,
            '%dst' => $response->redirect_url,
          )));
        }
      }
      else {
        watchdog('linkchecker', t('Link %link has changed and needs to be updated.', array(
          '%link' => $link->url,
        )), WATCHDOG_NOTICE, l(t('Broken links'), 'admin/logs/linkchecker'));
      }
      break;
    case 404:
      db_query("UPDATE {linkchecker_links} SET code = %d, error = '%s', fail_count = fail_count+1, last_checked = %d WHERE lid = %d", $response->code, $response->error, time(), $link->lid);
      watchdog('linkchecker', t('Broken link %link has been found.', array(
        '%link' => $link->url,
      )), WATCHDOG_NOTICE, l(t('Broken links'), 'admin/logs/linkchecker'));

      // If unpublishing limit is reached, unpublish all nodes having this link.
      $linkchecker_action_status_code_404 = variable_get('linkchecker_action_status_code_404', 0);
      if ($linkchecker_action_status_code_404 && $linkchecker_action_status_code_404 <= $link->fail_count + 1) {
        _linkchecker_unpublish_nodes($link->lid);
      }
      break;
    case 405:

      // Special error handling if method is not allowed. Switch link checking to GET method and try again.
      $response = drupal_http_request($link->url, array(
        'User-Agent' => 'User-Agent: ' . $useragent,
      ), 'GET', NULL, 0);
      if ($response->code == 200) {
        db_query("UPDATE {linkchecker_links} SET code = %d, error = '%s', fail_count = %d, last_checked = %d, method = '%s' WHERE lid = %d", $response->code, $response->error, 0, time(), 'GET', $link->lid);
      }
      else {
        db_query("UPDATE {linkchecker_links} SET code = %d, error = '%s', fail_count = fail_count+1, last_checked = %d, method = '%s' WHERE lid = %d", $response->code, $response->error, time(), 'GET', $link->lid);
      }
      watchdog('linkchecker', t('Method HEAD is not allowed for link %link. Method has been changed to GET.', array(
        '%link' => $link->url,
      )), WATCHDOG_NOTICE, l(t('Broken links'), 'admin/logs/linkchecker'));
      break;
    default:

      // Don't treat ignored response codes as errors.
      if (in_array($response->code, $ignore_response_codes)) {
        db_query("UPDATE {linkchecker_links} SET code = %d, error = '%s', fail_count = %d, last_checked = %d WHERE lid = %d", $response->code, $response->error, 0, time(), $link->lid);

        //watchdog('linkchecker', t('Unhandled link error %link has been found.', array('%link' => $link->url)), WATCHDOG_ERROR, l(t('Broken links'), 'admin/logs/linkchecker'));
      }
      else {
        db_query("UPDATE {linkchecker_links} SET code = %d, error = '%s', fail_count = fail_count+1, last_checked = %d WHERE lid = %d", $response->code, $response->error, time(), $link->lid);

        //watchdog('linkchecker', t('Unhandled link error %link has been found.', array('%link' => $link->url)), WATCHDOG_ERROR, l(t('Broken links'), 'admin/logs/linkchecker'));
      }
  }
}