name); } /** * Implementation of hook_uninstall(). */ function linkchecker_uninstall() { drupal_uninstall_schema('linkchecker'); variable_del('linkchecker_action_status_code_301'); variable_del('linkchecker_action_status_code_404'); variable_del('linkchecker_check_connections_max'); variable_del('linkchecker_check_library'); variable_del('linkchecker_check_links_interval'); variable_del('linkchecker_check_useragent'); variable_del('linkchecker_cleanup_links_last'); variable_del('linkchecker_disable_link_check_for_urls'); variable_del('linkchecker_extract_from_a'); variable_del('linkchecker_extract_from_audio'); variable_del('linkchecker_extract_from_embed'); variable_del('linkchecker_extract_from_iframe'); variable_del('linkchecker_extract_from_img'); variable_del('linkchecker_extract_from_object'); variable_del('linkchecker_extract_from_source'); variable_del('linkchecker_extract_from_video'); variable_del('linkchecker_filter_blacklist'); variable_del('linkchecker_fqdn_only'); variable_del('linkchecker_ignore_response_codes'); variable_del('linkchecker_impersonate_user'); variable_del('linkchecker_scan_blocks'); variable_del('linkchecker_scan_comments'); variable_del('linkchecker_scan_nodetypes'); } /** * Implementation of hook_schema(). */ function linkchecker_schema() { $schema['linkchecker_links'] = array( 'description' => 'Stores all links.', 'fields' => array( 'lid' => array( 'type' => 'serial', 'not null' => TRUE, 'description' => 'Primary Key: Unique link ID.', ), 'urlhash' => array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'description' => 'The indexable md5 hash of the {linkchecker_links}.url.', ), 'url' => array( 'type' => 'text', 'not null' => TRUE, 'description' => 'The full qualified link.', ), 'method' => array( 'type' => 'varchar', 'length' => 4, 'default' => 'HEAD', 'not null' => TRUE, 'description' => 'The method for checking links (HEAD, GET, POST).', ), 'code' => array( 'type' => 'int', 'not null' => TRUE, 'default' => -1, 'description' => 'HTTP status code from link checking.', ), 'error' => array( 'type' => 'text', 'not null' => FALSE, 'description' => 'The error message received from the remote server while doing link checking.', ), 'fail_count' => array( 'type' => 'int', 'not null' => TRUE, 'default' => 0, 'description' => 'Fail count of unsuccessful link checks. No flapping detection. (Successful = 0, Unsuccessful = fail_count+1).', ), 'last_checked' => array( 'type' => 'int', 'not null' => TRUE, 'default' => 0, 'description' => 'Timestamp of the last link check.', ), 'status' => array( 'type' => 'int', 'not null' => TRUE, 'default' => 1, 'description' => 'Boolean indicating if a link should be checked or not.', ), ), 'primary key' => array('lid'), 'unique keys' => array('urlhash' => array('urlhash')), 'indexes' => array( 'method' => array('method'), 'code' => array('code'), 'fail_count' => array('fail_count'), 'last_checked' => array('last_checked'), 'status' => array('status'), ), ); $schema['linkchecker_boxes'] = array( 'description' => 'Stores all link references for boxes.', 'fields' => array( 'bid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {boxes}.bid.', ), 'lid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {linkchecker_links}.lid.', ), ), 'primary key' => array('bid', 'lid'), 'indexes' => array('lid' => array('lid')), ); $schema['linkchecker_nodes'] = array( 'description' => 'Stores all link references for nodes.', 'fields' => array( 'nid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {node}.nid.', ), 'lid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {linkchecker_links}.lid.', ), ), 'primary key' => array('nid', 'lid'), 'indexes' => array('lid' => array('lid')), ); $schema['linkchecker_comments'] = array( 'description' => 'Stores all link references for comments.', 'fields' => array( 'cid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {comments}.cid.', ), 'lid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {linkchecker_links}.lid.', ), ), 'primary key' => array('cid', 'lid'), 'indexes' => array('lid' => array('lid')), ); return $schema; } /** * Implementation of hook_requirements(). */ function linkchecker_requirements($phase) { $requirements = array(); $t = get_t(); switch ($phase) { case 'install' : // MySQL version with subselect support is required. $version = db_version(); if (in_array($GLOBALS['db_type'], array('mysql', 'mysqli')) && version_compare($version, LINKCHECKER_MINIMUM_MYSQL) < 0) { $requirements['linkchecker_minimum_mysql'] = array( 'title' => $t('MySQL database'), 'value' => $version, 'severity' => REQUIREMENT_ERROR, 'description' => $t('Your MySQL Server is too old. Link Checker requires at least MySQL %version.', array('%version' => LINKCHECKER_MINIMUM_MYSQL)), ); } break; } return $requirements; } /** * Upgrade module to new D5 schema. */ function linkchecker_update_5200() { $ret = array(); // Module functions are required. Make sure the module is loaded. drupal_load('module', 'linkchecker'); // Remove obsolete tables no longer required. db_drop_table($ret, 'linkchecker_tasks'); db_drop_table($ret, 'linkchecker_results'); // Create new tables. $schema['linkchecker_links'] = array( 'description' => 'Stores all links.', 'fields' => array( 'lid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique link ID.', ), 'token' => array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'description' => 'The indexable md5 hash of the {linkchecker_links}.url.', ), 'url' => array( 'type' => 'text', 'not null' => TRUE, 'description' => 'The full qualified link URL.', ), 'method' => array( 'type' => 'varchar', 'length' => 4, 'default' => 'HEAD', 'not null' => TRUE, 'description' => 'The method for checking links (HEAD, GET, POST).', ), 'code' => array( 'type' => 'int', 'not null' => TRUE, 'default' => 0, 'description' => 'HTTP status code from link checking.', ), 'error' => array( 'type' => 'text', 'not null' => FALSE, 'description' => 'The error message received from the remote server while doing link checking.', ), 'fail_count' => array( 'type' => 'int', 'not null' => TRUE, 'default' => 0, 'description' => 'Fail count of unsuccessful link checks. No flapping detection. (Successful = 0, Unsuccessful = fail_count+1).', ), 'last_checked' => array( 'type' => 'int', 'not null' => TRUE, 'default' => 0, 'description' => 'Timestamp of the last link check.', ), ), 'primary key' => array('lid'), 'unique keys' => array('token' => array('token')), ); $schema['linkchecker_boxes'] = array( 'description' => 'Stores all link references for boxes.', 'fields' => array( 'bid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {boxes}.bid.', ), 'lid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {linkchecker_links}.lid.', ), ), 'primary key' => array('bid', 'lid'), ); $schema['linkchecker_nodes'] = array( 'description' => 'Stores all link references for nodes.', 'fields' => array( 'nid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {node}.nid.', ), 'lid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {linkchecker_links}.lid.', ), ), 'primary key' => array('nid', 'lid'), ); // Create schema. db_create_table($ret, 'linkchecker_links', $schema['linkchecker_links']); db_create_table($ret, 'linkchecker_boxes', $schema['linkchecker_boxes']); db_create_table($ret, 'linkchecker_nodes', $schema['linkchecker_nodes']); // Upgrade settings. Could be less code, but is easier to follow. $ignore_response_codes = preg_split('/(\r\n?|\n)/', variable_get('linkchecker_ignore_responses', "200\n304\n401\n403")); // Filter all invalid responds codes and outdated error messages out. $ignore_response_codes = array_filter($ignore_response_codes, '_linkchecker_isvalid_response_code'); // Make sure we have status code 200 and 304 in the ignore list. $ignore_response_codes = array_merge(array('200', '304'), $ignore_response_codes); $ignore_response_codes = array_unique($ignore_response_codes); variable_set('linkchecker_ignore_response_codes', implode("\n", $ignore_response_codes)); $ret[] = array('success' => TRUE, 'query' => 'Ignored response codes have been upgraded to '. implode(",", $ignore_response_codes)); // Remove obsolete settings. variable_del('linkchecker_ignore_responses'); variable_del('linkchecker_rebuild'); variable_del('linkchecker_maxtime'); variable_del('linkchecker_socket_timeout'); variable_del('linkchecker_max_links_per_node'); variable_del('linkchecker_remove_after'); variable_del('linkchecker_give_up'); return $ret; } /** * Upgrade module to new D6 schema. */ function linkchecker_update_6200() { $ret = array(); db_change_field($ret, 'linkchecker_links', 'lid', 'lid', array('type' => 'serial', 'not null' => TRUE)); // Upgrade line break converter from D5 filter/2 to D6 filter/1. $linkchecker_filter_blacklist = variable_get('linkchecker_filter_blacklist', array()); if (!empty($linkchecker_filter_blacklist) && $linkchecker_filter_blacklist['filter/2']) { $linkchecker_filter_blacklist['filter/2'] = 0; $linkchecker_filter_blacklist['filter/1'] = 'filter/1'; variable_set('linkchecker_filter_blacklist', $linkchecker_filter_blacklist); $ret[] = array('success' => TRUE, 'query' => 'Upgraded the default exclusion of line break converter filter from D5 filter/2 to D6 filter/1.'); } return $ret; } /** * Install linkchecker_comments table. */ function linkchecker_update_6201() { $ret = array(); // Create new tables. $schema['linkchecker_comments'] = array( 'description' => 'Stores all link references for comments.', 'fields' => array( 'cid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {comments}.cid.', ), 'lid' => array( 'type' => 'int', 'not null' => TRUE, 'description' => 'Primary Key: Unique {linkchecker_links}.lid.', ), ), 'primary key' => array('cid', 'lid'), ); // Table may be created in 5201 by 5.x-2.x. if (!db_table_exists('linkchecker_comments')) { db_create_table($ret, 'linkchecker_comments', $schema['linkchecker_comments']); } return $ret; } /** * Remove unnecessary elements from custom submit buttons. */ function linkchecker_update_6202() { $ret = array(); variable_del('linkchecker_analyze'); variable_del('linkchecker_clear_analyze'); return $ret; } /** * Make fields unsigned. */ function linkchecker_update_6204() { $ret = array(); // Make linkchecker_links.lid unsigned. db_change_field($ret, 'linkchecker_links', 'lid', 'lid', array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE)); if ($GLOBALS['db_type'] == 'pgsql') { db_add_primary_key($ret, 'linkchecker_links', array('lid')); } // Make linkchecker_boxes.bid and linkchecker_boxes.lid unsigned. db_drop_primary_key($ret, 'linkchecker_boxes'); db_change_field($ret, 'linkchecker_boxes', 'bid', 'bid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE)); db_change_field($ret, 'linkchecker_boxes', 'lid', 'lid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE)); db_add_primary_key($ret, 'linkchecker_boxes', array('bid', 'lid')); // Make linkchecker_comments.cid and linkchecker_comments.lid unsigned. db_drop_primary_key($ret, 'linkchecker_comments'); db_change_field($ret, 'linkchecker_comments', 'cid', 'cid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE)); db_change_field($ret, 'linkchecker_comments', 'lid', 'lid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE)); db_add_primary_key($ret, 'linkchecker_comments', array('cid', 'lid')); // Make linkchecker_nodes.nid and linkchecker_nodes.lid unsigned. db_drop_primary_key($ret, 'linkchecker_nodes'); db_change_field($ret, 'linkchecker_nodes', 'nid', 'nid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE)); db_change_field($ret, 'linkchecker_nodes', 'lid', 'lid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE)); db_add_primary_key($ret, 'linkchecker_nodes', array('nid', 'lid')); return $ret; } /** * Remove any references to nodes that are not published and also remove their comments references. */ function linkchecker_update_6205() { $ret = array(); $ret[] = update_sql("DELETE FROM {linkchecker_nodes} WHERE nid IN (SELECT nid FROM {node} WHERE status = 0)"); $ret[] = update_sql("DELETE FROM {linkchecker_comments} WHERE cid IN (SELECT c.cid FROM {node} n INNER JOIN {comments} c ON c.nid = n.nid WHERE n.status = 0)"); return $ret; } /** * Add status column to links table. */ function linkchecker_update_6206() { $ret = array(); // Add the column only if not exists. Column may been added in D5 (5207). if (!db_column_exists('linkchecker_links', 'status')) { db_add_field($ret, 'linkchecker_links', 'status', array('type' => 'int', 'not null' => TRUE, 'default' => 1)); } return $ret; } /** * Remove obsolete variable. */ function linkchecker_update_6207() { $ret = array(); variable_del('linkchecker_cleanup_links_interval'); return $ret; } /** * Change default value for linkchecker_links.code to -1. * * fsockopen may return 0 as an indication that the error occurred before * the connect() call. This is most likely due to a problem initializing the * socket. */ function linkchecker_update_6208() { $ret = array(); db_change_field($ret, 'linkchecker_links', 'code', 'code', array('type' => 'int', 'not null' => TRUE, 'default' => -1)); return $ret; } /** * Update the permissions table, to reflect changes to hook_perm. */ function linkchecker_update_6209() { $ret = array(); $res = db_query('SELECT rid, perm FROM {permission}'); $perms = array(); while ($p = db_fetch_object($res)) { $perm = $p->perm; $perm = preg_replace('/access linkchecker/', 'access broken links report', $perm); $perms[$p->rid] = $perm; } foreach ($perms as $rid => $renamed_permission) { db_query("UPDATE {permission} SET perm = '%s' WHERE rid = %d", $renamed_permission, $rid); $ret[] = array('success' => TRUE, 'query' => 'UPDATE {permission} SET perm = ' . check_plain($renamed_permission) . ' WHERE rid = '. $rid); } return $ret; } /** * Add status code 302 to the default list of ignored response codes. */ function linkchecker_update_6210() { $ret = array(); $ignore_response_codes = preg_split('/(\r\n?|\n)/', variable_get('linkchecker_ignore_response_codes', "200\n302\n304\n401\n403")); if (!in_array('302', $ignore_response_codes)) { $ignore_response_codes[] = '302'; sort($ignore_response_codes); variable_set('linkchecker_ignore_response_codes', implode("\n", $ignore_response_codes)); $ret[] = array('success' => TRUE, 'query' => 'Added the status code 302 to the list of ignored response codes.'); } else { $ret[] = array('success' => TRUE, 'query' => 'No action taken. The status code 302 was already on the list of ignored response codes.'); } return $ret; } /** * Remove obsolete variable. */ function linkchecker_update_6211() { $ret = array(); variable_del('linkchecker_pathfilter_support'); $ret[] = array('success' => TRUE, 'query' => 'Removed obsolete linkchecker_pathfilter_support variable.'); return $ret; } /** * Change unique key and column name 'token' into 'urlhash'. */ function linkchecker_update_6212() { $ret = array(); db_drop_unique_key($ret, 'linkchecker_links', 'token'); db_change_field($ret, 'linkchecker_links', 'token', 'urlhash', array('type' => 'varchar', 'length' => 32, 'not null' => TRUE)); db_add_unique_key($ret, 'linkchecker_links', 'urlhash', array('urlhash')); return $ret; } /** * Add RFC documenation domains back if they have been removed. */ function linkchecker_update_6213() { $ret = array(); $linkchecker_disable_link_check_for_urls = array_filter(preg_split('/(\r\n?|\n)/', variable_get('linkchecker_disable_link_check_for_urls', LINKCHECKER_RESERVED_DOCUMENTATION_DOMAINS))); variable_set('linkchecker_disable_link_check_for_urls', implode("\n", array_unique(array_merge(explode("\n", LINKCHECKER_RESERVED_DOCUMENTATION_DOMAINS), $linkchecker_disable_link_check_for_urls)))); $ret[] = array('success' => TRUE, 'query' => 'Added RFC documenation domains back if they have been removed.'); return $ret; } /** * #1321378: Improve performance of queries. */ function linkchecker_update_6214() { $ret = array(); db_add_index($ret, 'linkchecker_boxes', 'lid', array('lid')); db_add_index($ret, 'linkchecker_comments', 'lid', array('lid')); db_add_index($ret, 'linkchecker_nodes', 'lid', array('lid')); return $ret; } /** * Add status code 206 to the default list of ignored response codes. */ function linkchecker_update_6215() { $ret = array(); $ignore_response_codes = preg_split('/(\r\n?|\n)/', variable_get('linkchecker_ignore_response_codes', "200\n206\n302\n304\n401\n403")); if (!in_array('206', $ignore_response_codes)) { $ignore_response_codes[] = '206'; sort($ignore_response_codes); variable_set('linkchecker_ignore_response_codes', implode("\n", $ignore_response_codes)); $ret[] = array('success' => TRUE, 'query' => 'Added the status code 206 to the list of ignored response codes.'); } else { $ret[] = array('success' => TRUE, 'query' => 'No action taken. The status code 206 was already on the list of ignored response codes.'); } return $ret; } /** * #965720: Add indexes to improve performance of views queries. */ function linkchecker_update_6216() { $ret = array(); db_add_index($ret, 'linkchecker_links', 'method', array('method')); db_add_index($ret, 'linkchecker_links', 'code', array('code')); db_add_index($ret, 'linkchecker_links', 'fail_count', array('fail_count')); db_add_index($ret, 'linkchecker_links', 'last_checked', array('last_checked')); db_add_index($ret, 'linkchecker_links', 'status', array('status')); return $ret; } /** * #1450672: Set user 1 as default user to impersonate content updates. */ function linkchecker_update_6217() { $ret = array(); $linkchecker_default_impersonate_user = user_load(1); variable_set('linkchecker_impersonate_user', $linkchecker_default_impersonate_user->name); $ret[] = array('success' => TRUE, 'query' => 'Set user 1 as default user to impersonate content updates.'); return $ret; } /** * Removed obsolete linkchecker_check_links_max variable. */ function linkchecker_update_6218() { $ret = array(); variable_del('linkchecker_check_links_max'); $ret[] = array('success' => TRUE, 'query' => 'Removed obsolete linkchecker_check_links_max variable.'); return $ret; } /** * Upgrade outdated HTTP user agents. */ function linkchecker_update_6219() { $ret = array(); $linkchecker_check_useragent = variable_get('linkchecker_check_useragent', 'Drupal (+http://drupal.org/)'); $useragent_upgrade = array( 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1;)' => 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0;)' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0', 'Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5' => 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0', ); if (isset($useragent_upgrade[$linkchecker_check_useragent])) { variable_set('linkchecker_check_useragent', $useragent_upgrade[$linkchecker_check_useragent]); $ret[] = array('success' => TRUE, 'query' => 'Upgraded outdated HTTP user agent.'); } else { $ret[] = array('success' => TRUE, 'query' => 'User agent already up to date.'); } return $ret; }