diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index c26ec86..658fda0 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($ip) !== FALSE; } return $denied; } diff --git a/core/modules/statistics/statistics.admin.inc b/core/modules/statistics/statistics.admin.inc index 6606b8b..1fc7214 100644 --- a/core/modules/statistics/statistics.admin.inc +++ b/core/modules/statistics/statistics.admin.inc @@ -100,8 +100,10 @@ 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'); + $blocked_ips = is_array($blocked_ips) ? $blocked_ips : array(); $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 +111,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 +127,12 @@ 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)); + if (in_array($account->hostname, $blocked_ips)) { + $ban_link = l(t('unblock IP address'), "admin/config/people/ip-blocking/delete/$account->hostname", array('query' => $destination)); + } + else { + $ban_link = 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..2d75e8a 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($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/' . $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/system.admin.inc b/core/modules/system/system.admin.inc index 978b0f4..e98508b 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 $ip) { + $rows[] = array( + $ip, + // Use a substring of the key - it is prefixed with 'ip_'. + l(t('delete'), 'admin/config/people/ip-blocking/delete/' . $ip), + ); + } } $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($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_' . system_convert_config_ip_address($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' => $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_' . system_convert_config_ip_address($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 905d11d..b6a3e84 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1762,6 +1762,21 @@ function system_update_8005() { } /** + * Migrates the entries from blocked_ips into a configuration file. + */ +function system_update_8006() { + $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_' . system_convert_config_ip_address($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 fd571ce..93aa90d 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1705,16 +1705,27 @@ 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 its value prefixed + * with 'ip_' as key, and '.' replaced with '_'. The prefix is necessary + * because XML tags cannot start with numbers, and '.' is not a valid character + * in XML tag names. * - * @return - * The blocked IP address from the database as an array. + * @param string $ip + * The blocked IP address to retrieve. + * + * @return string|false + * 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($ip) { + // We can't use '.' in XML element names, so we replace it with '_'. + $escaped_ip = system_convert_config_ip_address($ip); + $blocked_ips = config('system.blocked_ips')->get('blocked_ips'); + if (empty($blocked_ips) || !isset($blocked_ips['ip_' . $escaped_ip])) { + return FALSE; + } + return $blocked_ips['ip_' . $escaped_ip]; } /** @@ -4020,3 +4031,16 @@ function system_admin_paths() { ); return $paths; } + +/** + * Helper function to convert . to _ to allow ips to be stored in XML. + * + * @param string $ip + * String ip address that needs to be converted. + * + * @return string + * A string with periods converted to underscores. + */ +function system_convert_config_ip_address($ip) { + return str_replace('.', '_', $ip); +} diff --git a/core/modules/system/system.test b/core/modules/system/system.test index 9287d16..894c8c5 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($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($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 4f3fab8..2e43e1e 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