blocked_ips_expire.module in Blocked IPs Expire 7
Hooks, callbacks and helper functions for the blocked_ips_expire module.
File
blocked_ips_expire.moduleView source
<?php
/**
* @file
* Hooks, callbacks and helper functions for the blocked_ips_expire module.
*/
/* Hooks. */
/**
* Implements hook_menu().
*/
function blocked_ips_expire_menu() {
$items = array();
// The blocked IPs expire preference page.
$items['admin/config/people/blocked_ips_expire'] = array(
'title' => 'Blocked IPs expiry',
'description' => 'Manage how long IP addresses get blocked for by default.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'_blocked_ips_expire_preferences',
),
'access arguments' => array(
'block IP addresses',
),
'file' => 'blocked_ips_expire.admin.inc',
);
// A default local task, which happens to be the blocked IPs expire preference
// page.
$items['admin/config/people/blocked_ips_expire/config'] = array(
'title' => 'Config',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -2,
);
// Assign expiry times to IP addresses in bulk.
$items['admin/config/people/blocked_ips_expire/bulk_assign'] = array(
'title' => 'Bulk-assign expiry times',
'description' => 'Add expiry times to blocked IP addresses without them.',
'type' => MENU_LOCAL_TASK,
'weight' => -1,
'page callback' => 'drupal_get_form',
'page arguments' => array(
'_blocked_ips_expire_bulk_assign',
),
'access arguments' => array(
'block IP addresses',
),
'file' => 'blocked_ips_expire.bulk_assign.inc',
);
return $items;
}
/**
* Implements hook_cron_queue_info().
*/
function blocked_ips_expire_cron_queue_info() {
$queues = array();
// A queue to delete blocked IP addresses whose expiry dates have passed upon
// cron run.
$queues['blocked_ips_expire_cron_delete'] = array(
'worker callback' => '_blocked_ips_expire_cron_delete',
'time' => 60,
);
return $queues;
}
/**
* Implements hook_cron().
*/
function blocked_ips_expire_cron() {
$expired_ips = _blocked_ips_expire_get_expired();
// If there are IPs to delete, queue them for deletion.
if (count($expired_ips) > 0) {
$queue = DrupalQueue::get('blocked_ips_expire_cron_delete');
foreach ($expired_ips as $expired_ip_entry) {
$queue
->createItem($expired_ip_entry);
}
}
}
/**
* Implements hook_blocked_ips_expire_deleting().
*/
function blocked_ips_expire_blocked_ips_expire_deleting($ip_info) {
// Log that a blocked IP address has been removed.
watchdog('blocked_ips_expire', 'The IP address @ip expired on @expiry_date and has been unblocked.', array(
'@ip' => $ip_info->ip,
'@expiry_date' => format_date($ip_info->expiry_date),
));
}
/* Alter functions. */
/**
* Implements hook_page_alter().
*/
function blocked_ips_expire_page_alter(&$page) {
// On the list of blocked IP addresses, add an expiry date column.
if (isset($page['content']['system_main']['system_ip_blocking_form'])) {
$page['content']['system_main']['system_ip_blocking_table']['#header'][] = t('Expiry dates');
foreach ($page['content']['system_main']['system_ip_blocking_table']['#rows'] as &$row) {
$ip = _blocked_ips_expire_get_one_by_ip($row[0]);
if ($ip) {
$row[] = format_date($ip->expiry_date);
}
else {
$row[] = t('Not set');
}
}
}
}
/**
* Implements hook_form_alter().
*/
function blocked_ips_expire_form_alter(&$form, &$form_state, $form_id) {
// Add a control to let a user enter an expiry date when they're blocking an
// IP address.
if ($form_id === 'system_ip_blocking_form') {
$form['#submit'][] = '_blocked_ips_expire_system_ip_blocking_form';
$default_duration = variable_get('blocked_ips_expire_default_time', '+2 years');
$default_expiry_date = new DateTime($default_duration);
$form['expiry_date'] = array(
'#type' => 'date',
'#title' => t('Expiry date'),
'#default_value' => array(
'year' => $default_expiry_date
->format('Y'),
'month' => $default_expiry_date
->format('n'),
'day' => $default_expiry_date
->format('j'),
),
'#description' => t('Defaults to the current default, %interval.', array(
'%interval' => $default_duration,
)),
'#required' => TRUE,
);
}
}
/**
* Implements hook_help().
*/
function blocked_ips_expire_help($path, $arg) {
$result = db_query("SELECT COUNT(ip) FROM {blocked_ips}");
$number_of_rows = $result
->fetchField();
switch ($path) {
case 'admin/config/people/ip-blocking':
return '<h3>' . t("The total number of blocked IPs is: @number_of_rows", array(
'@number_of_rows' => $number_of_rows,
)) . '</h3>';
}
}
/* Callbacks. */
/**
* Delete an IP address entry.
*/
function _blocked_ips_expire_cron_delete($expired_ip_entry) {
if (!empty($expired_ip_entry)) {
// Let other modules act on this event.
module_invoke_all('blocked_ips_expire_deleting', $expired_ip_entry);
// Now delete the IP address.
_blocked_ips_expire_delete_ip($expired_ip_entry->iid);
}
}
/* Batch API callbacks. */
/**
* Implements callback_batch_operation().
*/
function _blocked_ips_expire_bulk_assign_batch_operation($new_date = '', $iid = '', &$context = array()) {
// Set context for the finished message.
if (!isset($context['results']['date'])) {
$context['results']['date'] = $new_date;
}
// Set the expiry date for this ip.
db_merge('blocked_ips_expire')
->key(array(
'iid' => $iid,
))
->fields(array(
'expiry_date' => $new_date,
))
->execute();
}
/**
* Implements callback_batch_finished().
*/
function _blocked_ips_expire_bulk_assign_batch_finished($success, $results, $operations) {
// Yay! Write the results in a message and in the log.
if ($success) {
$message = format_plural(count($results), 'Assigned the date @date to 1 IP address.', 'Assigned the date @date to @count IP addresses.', array(
'@date' => format_date($results['date']),
));
drupal_set_message($message);
watchdog('blocked_ips_expire', $message, array(), WATCHDOG_INFO);
}
else {
$error_operation = reset($operations);
$message = t('An error occurred while processing %error_operation with arguments: @arguments', array(
'%error_operation' => $error_operation[0],
'@arguments' => print_r($error_operation[1], TRUE),
));
drupal_set_message($message, 'error');
}
// Either way, redirect to the bulk assignment page, which should be empty.
drupal_goto('admin/config/people/blocked_ips_expire/bulk_assign');
}
/* Form callbacks. */
/**
* Form submission handler for system_ip_blocking_form().
*
* @see blocked_ips_expire_form_alter
*/
function _blocked_ips_expire_system_ip_blocking_form($form, &$form_state) {
$expiry_date = new DateTime();
$expiry_date
->setDate($form_state['values']['expiry_date']['year'], $form_state['values']['expiry_date']['month'], $form_state['values']['expiry_date']['day']);
_blocked_ips_expire_add_ip($form_state['values']['ip'], $expiry_date
->format('U'));
}
/* Form element validation handlers. */
/**
* Form element validation handler for strtotime()-compatible strings.
*
* @see https://php.net/manual/function.strtotime.php
*/
function _blocked_ips_expire_element_validate_strtotime($element, &$form_state) {
if (strtotime($element['#value']) === FALSE) {
form_error($element, t("%name must be in a format that <a href='@strtotime'>PHP's strtotime function</a> can interpret.", array(
'%name' => $element['#title'],
'@strtotime' => 'https://php.net/manual/function.strtotime.php',
)));
}
}
/**
* Form element validation handler for strings that parse as dates.
*/
function _blocked_ips_expire_element_validate_strtotime_or_empty($element, &$form_state) {
if (!empty($element['#value']) && strtotime($element['#value']) === FALSE) {
form_error($element, t('%name must be a date.', array(
'%name' => $element['#title'],
)));
}
}
/* Helper functions. */
/**
* Returns IP addresses whose expiry dates have passed.
*
* @param bool $is_count_query
* Whether this is a count query, or a regular one.
*
* @return array|int
* If (bool) $is_count_query === TRUE, then returns the number of blocked IP
* addresses without expiry dates (an int). Otherwise, returns an array of
* IIDs mapped to objects with the following properties:
* - 'iid': The IID of the IP address.
* - 'ip': The IP address.
* - 'expiry_date': The date the IP address expired.
*/
function _blocked_ips_expire_get_expired($is_count_query = FALSE) {
$expired = array();
// Query for IP addresses whose expiry dates have passed.
$query = db_select('blocked_ips', 'bi');
$query
->join('blocked_ips_expire', 'bie', 'bi.iid = bie.iid');
$query
->addField('bi', 'iid');
$query
->addField('bi', 'ip');
$query
->addField('bie', 'expiry_date');
$query
->condition('expiry_date', strtotime('now'), '<');
// If this is a count query, return the count.
if ((bool) $is_count_query) {
return (int) $query
->countQuery()
->execute()
->fetchField();
}
// If we get here, it was a regular query: return the results.
$result = $query
->execute();
$expired = $result
->fetchAllAssoc('iid');
return $expired;
}
/**
* Returns IP addresses that have not been assigned expiry dates.
*
* @param bool $is_count_query
* Whether this is a count query, or a regular one.
*
* @return array|int
* If (bool) $is_count_query === TRUE, then returns the number of blocked IP
* addresses without expiry dates (an int). Otherwise, returns an array of
* IIDs mapped to objects with the following properties:
* - 'iid': The IID of the IP address.
* - 'ip': The IP address.
* - 'expiry_date': The date the IP address expired.
*/
function _blocked_ips_expire_get_unassigned($is_count_query = FALSE) {
$unassigned = array();
// Query for IP addresses without expiry dates.
$query = db_select('blocked_ips', 'bi');
$query
->leftJoin('blocked_ips_expire', 'bie', 'bi.iid = bie.iid');
$query
->addField('bi', 'iid');
$query
->addField('bi', 'ip');
$query
->addField('bie', 'expiry_date');
$query
->isNull('bie.expiry_date');
// If this is a count query, return the count.
if ((bool) $is_count_query) {
return (int) $query
->countQuery()
->execute()
->fetchField();
}
// If we get here, it was a regular query: return the results.
$result = $query
->execute();
$unassigned = $result
->fetchAllAssoc('iid');
return $unassigned;
}
/**
* Blocks an IP address and gives it an expiry date.
*
* @param string $ip
* The IP address to block.
* @param string $expiry_date
* The date that the block should expire (i.e.: the date that the IP address
* should be unblocked).
*
* @return int
* The IID of the IP address that was added.
*/
function _blocked_ips_expire_add_ip($ip, $expiry_date) {
if (empty($ip)) {
$ip = ip_address();
}
// Remove spaces around $ip before adding it to database, so it operates the
// same as system_ip_blocking_form_submit().
$ip = trim((string) $ip);
// Check for duplicate IP addresses. There is no constraint on the table, so
// checking for duplicates must be done manually.
$duplicate_ip_query = db_select('blocked_ips', 'bi');
$duplicate_ip_query
->addField('bi', 'iid');
$duplicate_ip_query
->condition('bi.ip', $ip);
$iid = $duplicate_ip_query
->execute()
->fetchField();
// If there was no duplicate IP address, add it to the database.
if (empty($iid)) {
$iid = db_insert('blocked_ips')
->fields(array(
'ip' => (string) $ip,
))
->execute();
}
// Add expiry date to the expiry table.
db_merge('blocked_ips_expire')
->key(array(
'iid' => $iid,
))
->fields(array(
'expiry_date' => (int) $expiry_date,
))
->execute();
return $iid;
}
/**
* Gets information about an IP address, given an IID.
*
* @param int $iid
* The IID of the IP address.
*
* @return object|bool
* Returns FALSE if an IP address with the given IID was not found, or an
* object with the following properties:
* - 'iid': The IID of the IP address.
* - 'ip': The IP address.
* - 'expiry_date': The date the IP address expired.
*/
function _blocked_ips_expire_get_one($iid) {
$query = db_select('blocked_ips', 'bi');
$query
->join('blocked_ips_expire', 'bie', 'bi.iid = bie.iid');
$query
->addField('bi', 'iid');
$query
->addField('bi', 'ip');
$query
->addField('bie', 'expiry_date');
$query
->condition('bi.iid', (int) $iid);
$result = $query
->execute();
return $result
->fetchObject();
}
/**
* Gets information about an IP address, given an IP address.
*
* @param string $ip
* The IP address to look up.
*
* @return object|bool
* Returns FALSE if the given IP address was not found, or an object with the
* following properties:
* - 'iid': The IID of the IP address.
* - 'ip': The IP address.
* - 'expiry_date': The date the IP address expired.
*/
function _blocked_ips_expire_get_one_by_ip($ip) {
$query = db_select('blocked_ips', 'bi');
$query
->join('blocked_ips_expire', 'bie', 'bi.iid = bie.iid');
$query
->addField('bi', 'iid');
$query
->addField('bi', 'ip');
$query
->addField('bie', 'expiry_date');
$query
->condition('bi.ip', $ip);
$result = $query
->execute();
return $result
->fetchObject();
}
/**
* Deletes an IP address from the database.
*
* @param int $iid
* The IID of the IP address.
*/
function _blocked_ips_expire_delete_ip($iid) {
// Delete the entries from both tables.
db_delete('blocked_ips_expire')
->condition('iid', (int) $iid)
->execute();
db_delete('blocked_ips')
->condition('iid', (int) $iid)
->execute();
}