diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 4967991..db5cd49 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -1756,7 +1756,7 @@ function drupal_is_denied($ip) { // database and also in this case it's quite likely that the user relies // on higher performance solutions like a firewall. elseif (class_exists('Database', FALSE)) { - $denied = (bool)db_query("SELECT 1 FROM {blocked_ips} WHERE ip = :ip", array(':ip' => $ip))->fetchField(); + $denied = (blocked_ip_load(md5($ip)) !== FALSE); } return $denied; } diff --git a/core/modules/statistics/statistics.admin.inc b/core/modules/statistics/statistics.admin.inc index 6606b8b..976a0dd 100644 --- a/core/modules/statistics/statistics.admin.inc +++ b/core/modules/statistics/statistics.admin.inc @@ -100,8 +100,9 @@ function statistics_top_visitors() { array('data' => t('Total page generation time'), 'field' => 'total'), array('data' => user_access('block IP addresses') ? t('Operations') : '', 'colspan' => 2), ); + + $blocked_ips = config('system.blocked_ips')->get('blocked_ips'); $query = db_select('accesslog', 'a', array('target' => 'slave'))->extend('PagerDefault')->extend('TableSort'); - $query->leftJoin('blocked_ips', 'bl', 'a.hostname = bl.ip'); $query->leftJoin('users', 'u', 'a.uid = u.uid'); $query->addExpression('COUNT(a.uid)', 'hits'); @@ -109,11 +110,9 @@ function statistics_top_visitors() { $query ->fields('a', array('uid', 'hostname')) ->fields('u', array('name')) - ->fields('bl', array('iid')) ->groupBy('a.hostname') ->groupBy('a.uid') ->groupBy('u.name') - ->groupBy('bl.iid') ->limit(30) ->orderByHeader($header); @@ -127,7 +126,7 @@ function statistics_top_visitors() { $rows = array(); $destination = drupal_get_destination(); foreach ($result as $account) { - $ban_link = $account->iid ? l(t('unblock IP address'), "admin/config/people/ip-blocking/delete/$account->iid", array('query' => $destination)) : l(t('block IP address'), "admin/config/people/ip-blocking/$account->hostname", array('query' => $destination)); + $ban_link = in_array($account->hostname, $blocked_ips) ? l(t('unblock IP address'), 'admin/config/people/ip-blocking/delete/' . md5($account->hostname), array('query' => $destination)) : l(t('block IP address'), "admin/config/people/ip-blocking/$account->hostname", array('query' => $destination)); $rows[] = array($account->hits, ($account->uid ? theme('username', array('account' => $account)) : $account->hostname), format_interval(round($account->total / 1000)), (user_access('block IP addresses') && !$account->uid) ? $ban_link : ''); } diff --git a/core/modules/statistics/statistics.test b/core/modules/statistics/statistics.test index 62cec24..50f2af3 100644 --- a/core/modules/statistics/statistics.test +++ b/core/modules/statistics/statistics.test @@ -275,7 +275,8 @@ class StatisticsBlockVisitorsTestCase extends StatisticsTestCase { $edit = array(); $edit['ip'] = $test_ip_address; $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); - $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $edit['ip']))->fetchField(); + + $ip = blocked_ip_load(md5($edit['ip'])); $this->assertNotEqual($ip, FALSE, t('IP address found in database')); $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $edit['ip'])), t('IP address was blocked.')); @@ -287,8 +288,7 @@ class StatisticsBlockVisitorsTestCase extends StatisticsTestCase { // Unblock the IP address. $this->clickLink('unblock IP address'); $this->assertRaw(t('Are you sure you want to delete %ip?', array('%ip' => $test_ip_address)), t('IP address deletion confirmation found.')); - $edit = array(); - $this->drupalPost('admin/config/people/ip-blocking/delete/1', NULL, t('Delete')); + $this->drupalPost('admin/config/people/ip-blocking/delete/' . md5($test_ip_address), NULL, t('Delete')); $this->assertRaw(t('The IP address %ip was deleted.', array('%ip' => $test_ip_address)), t('IP address deleted.')); } } diff --git a/core/modules/system/config/system.blocked_ips.xml b/core/modules/system/config/system.blocked_ips.xml new file mode 100644 index 0000000..2c72080 --- /dev/null +++ b/core/modules/system/config/system.blocked_ips.xml @@ -0,0 +1,4 @@ + + + + diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 978b0f4..9a8f7e1 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -1359,12 +1359,15 @@ function system_modules_uninstall_submit($form, &$form_state) { function system_ip_blocking($default_ip = '') { $rows = array(); $header = array(t('Blocked IP addresses'), t('Operations')); - $result = db_query('SELECT * FROM {blocked_ips}'); - foreach ($result as $ip) { - $rows[] = array( - $ip->ip, - l(t('delete'), "admin/config/people/ip-blocking/delete/$ip->iid"), - ); + $blocked_ips = config('system.blocked_ips')->get('blocked_ips'); + if (is_array($blocked_ips)) { + foreach ($blocked_ips as $hash => $ip) { + $rows[] = array( + $ip, + // Use a substring of the key - it is prefixed with 'ip_'. + l(t('delete'), 'admin/config/people/ip-blocking/delete/' . substr($hash, 3)), + ); + } } $build['system_ip_blocking_form'] = drupal_get_form('system_ip_blocking_form', $default_ip); @@ -1407,7 +1410,8 @@ function system_ip_blocking_form($form, $form_state, $default_ip) { function system_ip_blocking_form_validate($form, &$form_state) { $ip = trim($form_state['values']['ip']); - if (db_query("SELECT * FROM {blocked_ips} WHERE ip = :ip", array(':ip' => $ip))->fetchField()) { + $loaded_ip = blocked_ip_load(md5($ip)); + if ($loaded_ip !== FALSE) { form_set_error('ip', t('This IP address is already blocked.')); } elseif ($ip == ip_address()) { @@ -1420,9 +1424,9 @@ function system_ip_blocking_form_validate($form, &$form_state) { function system_ip_blocking_form_submit($form, &$form_state) { $ip = trim($form_state['values']['ip']); - db_insert('blocked_ips') - ->fields(array('ip' => $ip)) - ->execute(); + $config = config('system.blocked_ips'); + $config->set('blocked_ips.ip_' . md5($ip), $ip); + $config->save(); drupal_set_message(t('The IP address %ip has been blocked.', array('%ip' => $ip))); $form_state['redirect'] = 'admin/config/people/ip-blocking'; return; @@ -1433,24 +1437,24 @@ function system_ip_blocking_form_submit($form, &$form_state) { * * @see system_ip_blocking_delete_submit() */ -function system_ip_blocking_delete($form, &$form_state, $iid) { +function system_ip_blocking_delete($form, &$form_state, $ip) { $form['blocked_ip'] = array( '#type' => 'value', - '#value' => $iid, + '#value' => md5($ip), ); - return confirm_form($form, t('Are you sure you want to delete %ip?', array('%ip' => $iid['ip'])), 'admin/config/people/ip-blocking', t('This action cannot be undone.'), t('Delete'), t('Cancel')); + return confirm_form($form, t('Are you sure you want to delete %ip?', array('%ip' => $ip)), 'admin/config/people/ip-blocking', t('This action cannot be undone.'), t('Delete'), t('Cancel')); } /** * Process system_ip_blocking_delete form submissions. */ function system_ip_blocking_delete_submit($form, &$form_state) { - $blocked_ip = $form_state['values']['blocked_ip']; - db_delete('blocked_ips') - ->condition('iid', $blocked_ip['iid']) - ->execute(); - watchdog('user', 'Deleted %ip', array('%ip' => $blocked_ip['ip'])); - drupal_set_message(t('The IP address %ip was deleted.', array('%ip' => $blocked_ip['ip']))); + $ip = blocked_ip_load($form_state['values']['blocked_ip']); + $config = config('system.blocked_ips'); + $config->clear('blocked_ips.ip_' . $form_state['values']['blocked_ip']); + $config->save(); + watchdog('user', 'Deleted %ip', array('%ip' => $ip)); + drupal_set_message(t('The IP address %ip was deleted.', array('%ip' => $ip))); $form_state['redirect'] = 'admin/config/people/ip-blocking'; } diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 14d4853..80cb293 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1761,6 +1761,21 @@ function system_update_8004() { } /** + * Migrates the entries from blocked_ips into a configuration file. + */ +function system_update_8005() { + $results = db_query("SELECT ip FROM {blocked_ips}")->fetchAll(); + if (!empty($results)) { + $config = config('system.blocked_ips'); + foreach ($results as $row) { + $config->set('blocked_ips.ip_' . md5($row->ip), $row->ip); + } + $config->save(); + } + db_drop_table('blocked_ips'); +} + +/** * @} End of "defgroup updates-7.x-to-8.x" * The next series of updates should start at 9000. */ diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 94fd3e0..4fd5879 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1705,16 +1705,24 @@ function system_stream_wrappers() { } /** - * Retrieve a blocked IP address from the database. + * Retrieves a blocked IP address. * - * @param $iid integer - * The ID of the blocked IP address to retrieve. + * An IP address is stored in the configuration file with a hash of its value + * prefixed with 'ip_' as key. The prefix is necessary because XML tags cannot + * start with numbers and hashes sometimes do start with a number. + * + * @param $hash string + * An md5 sum of the blocked IP address to retrieve. * * @return - * The blocked IP address from the database as an array. + * The blocked IP address or FALSE if the IP address is not blocked. */ -function blocked_ip_load($iid) { - return db_query("SELECT * FROM {blocked_ips} WHERE iid = :iid", array(':iid' => $iid))->fetchAssoc(); +function blocked_ip_load($hash) { + $blocked_ips = config('system.blocked_ips')->get('blocked_ips'); + if (empty($blocked_ips) || !isset($blocked_ips['ip_' . $hash])) { + return FALSE; + } + return $blocked_ips['ip_' . $hash]; } /** diff --git a/core/modules/system/system.test b/core/modules/system/system.test index 9287d16..41d7277 100644 --- a/core/modules/system/system.test +++ b/core/modules/system/system.test @@ -673,13 +673,12 @@ class IPAddressBlockingTestCase extends DrupalWebTestCase { */ function testIPAddressValidation() { $this->drupalGet('admin/config/people/ip-blocking'); - // Block a valid IP address. $edit = array(); $edit['ip'] = '192.168.1.1'; $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); - $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $edit['ip']))->fetchField(); - $this->assertTrue($ip, t('IP address found in database.')); + $ip = blocked_ip_load(md5($edit['ip'])); + $this->assertNotEqual($ip, FALSE, 'IP address found in config file.'); $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $edit['ip'])), t('IP address was blocked.')); // Try to block an IP address that's already blocked. @@ -709,8 +708,8 @@ class IPAddressBlockingTestCase extends DrupalWebTestCase { // Pass an IP address as a URL parameter and submit it. $submit_ip = '1.2.3.4'; $this->drupalPost('admin/config/people/ip-blocking/' . $submit_ip, NULL, t('Add')); - $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->fetchField(); - $this->assertTrue($ip, t('IP address found in database')); + $ip = blocked_ip_load(md5($submit_ip)); + $this->assertNotEqual($ip, FALSE, 'IP address found in config file.'); $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $submit_ip)), t('IP address was blocked.')); // Submit your own IP address. This fails, although it works when testing manually. diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 7531a98..8181ac6 100755 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -465,7 +465,7 @@ ini_set('session.cookie_lifetime', 2000000); * IP blocking: * * To bypass database queries for denied IP addresses, use this setting. - * Drupal queries the {blocked_ips} table by default on every page request + * Drupal looks up the IPs in a config file named system.blocked_ips.xml * for both authenticated and anonymous users. This allows the system to * block IP addresses from within the administrative interface and before any * modules are loaded. However on high traffic websites you may want to avoid