You are here

key.module in Key 7

Same filename and directory in other branches
  1. 8 key.module
  2. 7.3 key.module
  3. 7.2 key.module

Provides the ability to manage keys, which can be used by other modules.

File

key.module
View source
<?php

/**
 * @file
 * Provides the ability to manage keys, which can be used by other modules.
 */
define('KEY_STATUS_VALID', 1);
define('KEY_STATUS_NOT_VALID', 0);

/**
 * Implements hook_permission().
 */
function key_permission() {
  return array(
    'administer keys' => array(
      'title' => t('Administer keys'),
      'description' => 'Create, edit, and delete keys.',
    ),
  );
}

/**
 * Implements hook_ctools_plugin_directory().
 *
 * Tell CTools where to find plugins for this module.
 */
function key_ctools_plugin_directory($module, $plugin) {
  if ($module == 'key' && !empty($plugin)) {
    return "plugins/{$plugin}";
  }
}

/**
 * Implements hook_ctools_plugin_type().
 *
 * Tell CTools about plugins the module uses.
 */
function key_ctools_plugin_type() {
  $plugins['key_provider'] = array(
    'cache' => TRUE,
    'cache table' => 'cache',
    'process' => '_key_provider_plugin_process',
    'defaults' => array(
      'title' => '',
      'description' => '',
      'key get callback' => NULL,
      'key set callback' => NULL,
      'dependency callback' => NULL,
      'dependency errors' => NULL,
      'settings form' => NULL,
      'key form' => NULL,
      'instructions' => NULL,
      'status callback' => NULL,
    ),
  );
  $plugins['key_integration'] = array(
    'cache' => TRUE,
    'cache table' => 'cache',
    'process' => '_key_integration_plugin_process',
    'defaults' => array(
      'title' => '',
      'description' => '',
      'type' => NULL,
      'enabled' => FALSE,
      'locked' => FALSE,
      'settings' => array(),
      'enable callback' => NULL,
      'disable callback' => NULL,
    ),
  );
  $plugins['key_type'] = array(
    'cache' => TRUE,
    'cache table' => 'cache',
    'defaults' => array(
      'title' => '',
      'description' => '',
    ),
  );
  return $plugins;
}

/**
 * Implements hook_element_info().
 */
function key_element_info() {
  $type['key'] = array(
    '#input' => TRUE,
    '#size' => 0,
    '#multiple' => FALSE,
    '#process' => array(
      '_key_element_expand',
      'form_process_select',
      'ajax_process_form',
    ),
    '#theme' => 'select',
    '#theme_wrappers' => array(
      'form_element',
    ),
    '#options' => array(),
    // Allow filtering of the list of key configurations.
    // See _key_filter_configs().
    '#filters' => array(),
    '#key_description' => TRUE,
  );
  return $type;
}

/**
 * Process function to expand the key element.
 */
function _key_element_expand($element) {
  $element['#options'] = key_get_configs_as_options();
  if (!empty($element['#filters'])) {
    $element['#options'] = _key_configs_filter($element['#options'], $element['#filters']);
  }

  // Prefix the default description with a information about keys.
  if ($element['#key_description']) {
    $key_description = t('Choose an available key to use.');
    if (module_exists('key_ui')) {
      $key_description .= ' ' . t('If your key is not listed, <a href="@url">create a new key</a>.', array(
        '@url' => '/' . KEY_MENU_PATH,
      ));
    }
    else {
      $key_description .= ' ' . t('If your key is not listed, enable the Keys UI module and create a new key.');
    }
    $element['#description'] = $key_description . ' ' . $element['#description'];
  }
  return $element;
}

/**
 * Filter an array of key configurations.
 */
function _key_configs_filter($configs, $filters) {
  $target_configs = array();
  foreach (key_get_configs() as $config) {
    $include = TRUE;
    if (!empty($filters['type'])) {
      $include &= in_array($config['type'], (array) $filters['type']);
    }
    if (!empty($filters['provider'])) {
      $include &= in_array($config['provider'], (array) $filters['provider']);
    }
    if ($include) {
      $target_configs[$config['name']] = TRUE;
    }
  }
  $configs = array_intersect_key($configs, $target_configs);
  return $configs;
}

/**
 * Gets information about all key providers.
 *
 * @param bool $all
 *   A flag indicating whether to include plugins with unmet dependencies.
 * @param bool $reset
 *   A flag indicating whether to clear the plugin cache. Otherwise, stale
 *   data may be returned if plugin properties have changed.
 *
 * @return array
 *   Information about all key providers.
 */
function key_get_providers($all = TRUE, $reset = FALSE) {
  if ($reset) {
    _key_clear_plugin_cache('key_provider');
  }
  ctools_include('plugins');
  $providers = ctools_get_plugins('key', 'key_provider');
  return $all ? $providers : array_filter($providers, '_key_plugin_is_valid');
}

/**
 * Gets all key providers as options, for use in forms.
 *
 * @param bool $all
 *   A flag indicating whether to include plugins with unmet dependencies.
 * @param bool $reset
 *   A flag indicating whether to clear the plugin cache. Otherwise, stale
 *   data may be returned if plugin properties have changed.
 *
 * @return array
 *   An array of key providers, with names for keys and labels for values.
 */
function key_get_providers_as_options($all = TRUE, $reset = FALSE) {
  $providers = key_get_providers($all, $reset);
  $options = array();
  foreach ($providers as $name => $provider) {
    $options[$name] = $provider['title'];
  }
  return $options;
}

/**
 * Gets information about a specific key provider.
 *
 * @param string $provider
 *   The name of the key provider to get.
 * @param bool $reset
 *   A flag indicating whether to clear the plugin cache. Otherwise, stale
 *   data may be returned if plugin properties have changed.
 *
 * @return array
 *   A key provider.
 */
function key_get_provider($provider, $reset = FALSE) {
  ctools_include('plugins');
  return ctools_get_plugins('key', 'key_provider', $provider);
}

/**
 * Gets information about all key types.
 *
 * @param bool $all
 *   A flag indicating whether to include plugins with unmet dependencies.
 * @param bool $reset
 *   A flag indicating whether to clear the plugin cache. Otherwise, stale
 *   data may be returned if plugin properties have changed.
 *
 * @return array
 *   Information about all key types.
 */
function key_get_types($all = TRUE, $reset = FALSE) {
  if ($reset) {
    _key_clear_plugin_cache('key_type');
  }
  ctools_include('plugins');
  $types = ctools_get_plugins('key', 'key_type');
  return $all ? $types : array_filter($types, '_key_plugin_is_valid');
}

/**
 * Gets all key types as options, for use in forms.
 *
 * @param bool $all
 *   A flag indicating whether to include plugins with unmet dependencies.
 * @param bool $reset
 *   A flag indicating whether to clear the plugin cache. Otherwise, stale
 *   data may be returned if plugin properties have changed.
 *
 * @return array
 *   An array of types, with names for keys and labels for values.
 */
function key_get_types_as_options($all = TRUE, $reset = FALSE) {
  $providers = key_get_types($all, $reset);
  $options = array();
  foreach ($providers as $name => $provider) {
    $options[$name] = $provider['title'];
  }
  return $options;
}

/**
 * Gets information about a specific key type.
 *
 * @param string $type
 *   The name of the type to get.
 * @param bool $reset
 *   A flag indicating whether to clear the plugin cache. Otherwise, stale
 *   data may be returned if plugin properties have changed.
 *
 * @return array
 *   A key type.
 */
function key_get_type($type, $reset = FALSE) {
  ctools_include('plugins');
  return ctools_get_plugins('key', 'key_type', $type);
}

/**
 * Gets information about all key configurations.
 *
 * @param bool $reset
 *   A flag to force the configurations to be retrieved from the database.
 *
 * @return array
 *   An array of configurations.
 */
function key_get_configs($reset = FALSE) {
  $configs =& drupal_static(__FUNCTION__);
  if (!isset($configs) || $reset) {
    $configs = db_query("SELECT * FROM {key_config} ORDER BY label ASC")
      ->fetchAllAssoc('name', PDO::FETCH_ASSOC);

    // Unserialize provider_settings field.
    foreach ($configs as $name => $config) {
      if (!empty($config['provider_settings'])) {
        $provider_settings = unserialize($config['provider_settings']);
        $configs[$name]['provider_settings'] = $provider_settings;
      }
    }
  }
  return $configs;
}

/**
 * Gets all key configurations as options, for use in forms.
 *
 * @param bool $reset
 *   A flag to force the configurations to be retrieved from the database.
 *
 * @return array
 *   An array of configurations, with names for keys and labels for values.
 */
function key_get_configs_as_options($reset = FALSE) {
  $options =& drupal_static(__FUNCTION__);
  if (!isset($options) || $reset) {
    $configs = key_get_configs($reset);
    $options = array();
    foreach ($configs as $name => $config) {
      $options[$name] = $config['label'];
    }
  }
  return $options;
}

/**
 * Gets information about a specific key configuration.
 *
 * @param string $name
 *   The machine name of the configuration to get.
 * @param bool $reset
 *   A flag to force the configuration to be retrieved from the database.
 *
 * @return array
 *   A key configuration.
 */
function key_get_config($name, $reset = FALSE) {
  $configs =& drupal_static(__FUNCTION__);
  if (!isset($configs) || $reset) {
    $configs = key_get_configs($reset);
  }
  if (array_key_exists($name, $configs)) {
    $config = $configs[$name];
  }
  else {
    $config = NULL;
  }
  return $config;
}

/**
 * Save a key configuration.
 *
 * @param array $fields
 *   The fields of the configuration to save.
 * @param array $key
 *   The key to save, if desired and allowed for the chosen key provider.
 * @param array $overwrite
 *   FALSE if a new configuration should be created, instead of overwriting
 *   an existing one with the same name.
 * @param bool $messages
 *   TRUE if messages should be displayed.
 */
function key_save_config($fields, $key = FALSE, $overwrite = TRUE, $messages = TRUE) {

  // Load the key provider.
  $provider = key_get_provider($fields['provider']);

  // If the configuration should not be overwritten, create a new one
  // and make sure that certain fields are unique.
  if (!$overwrite) {
    $configs = key_get_configs();

    // Make sure the configuration name is unique.
    $counter = 2;
    $base_name = $fields['name'];
    while (key_get_config($fields['name'])) {
      $fields['name'] = "{$base_name}_{$counter}";
      $counter++;
    }

    // Make sure the configuration label is unique.
    $counter = 2;
    $base_label = $fields['label'];
    $config_labels = array();
    foreach ($configs as $index => $config) {
      $config_labels[] = $config['label'];
    }
    while (in_array($fields['label'], $config_labels)) {
      $fields['label'] = "{$base_label} {$counter}";
      $counter++;
    }

    // If the key provider is variable and the key is defined,
    // make sure the variable name is unique.
    if ($fields['provider'] == 'variable' && isset($key)) {
      $counter = 2;
      $base_variable_name = $fields['provider_settings']['variable_name'];
      $config_variable_names = array();
      foreach ($configs as $index => $config) {
        if ($config['provider'] == 'variable') {
          $config_variable_names[] = $config['provider_settings']['variable_name'];
        }
      }
      while (in_array($fields['provider_settings']['variable_name'], $config_variable_names)) {
        $fields['provider_settings']['variable_name'] = "{$base_variable_name}_{$counter}";
        $counter++;
      }
    }
    foreach ($configs as $index => $config) {

      // Change the configuration label to be unique.
      while (key_get_config($fields['name'])) {
        $fields['name'] = "{$base_name}_{$counter}";
        $counter++;
      }
    }
  }

  // Serialize any field that is an array.
  foreach ($fields as $index => $field) {
    if (is_array($field)) {
      $fields[$index] = serialize($field);
    }
  }

  // If the created field is empty, set it to the request time.
  if (empty($fields['created'])) {
    $fields['created'] = REQUEST_TIME;
  }

  // If the changed field is empty, set it to the request time.
  if (empty($fields['changed'])) {
    $fields['changed'] = REQUEST_TIME;
  }

  // Save the configuration.
  $merge_status = db_merge('key_config')
    ->key(array(
    'name' => $fields['name'],
  ))
    ->fields($fields)
    ->execute();

  // Display message and log to watchdog.
  if ($messages) {
    $t_args = array(
      '%label' => $fields['label'],
    );
    switch ($merge_status) {
      case MergeQuery::STATUS_INSERT:
        drupal_set_message(t('The key %label has been added.', $t_args));
        watchdog('key', 'Added key %label.', $t_args, WATCHDOG_NOTICE, l(t('view'), KEY_MENU_PATH . '/list'));
        break;
      case MergeQuery::STATUS_UPDATE:
        drupal_set_message(t('The key %label has been updated.', $t_args));
        watchdog('key', 'Updated key %label.', $t_args, WATCHDOG_NOTICE, l(t('view'), KEY_MENU_PATH . '/list'));
        break;
    }
  }

  // Load the configuration to make sure it was saved.
  $key_config = key_get_config($fields['name'], TRUE);
  if (empty($key_config)) {
    return NULL;
  }

  // Set the key if the key provider supports it and a key was defined.
  if (isset($key) && ($key_set_callback = ctools_plugin_get_function($provider, 'key set callback'))) {
    call_user_func($key_set_callback, $key_config['provider_settings'], $key);
  }

  // Return the saved configuration.
  return $key_config;
}

/**
 * Gets information about key integrations.
 *
 * @param string $status
 *   An enabled status by which to filter the results.
 * @param string $type
 *   An integration type by which to filter the results.
 * @param bool $reset
 *   A flag to force a reset of the integration data.
 *
 * @return array
 *   An array of integrations.
 */
function key_get_integrations($status = NULL, $type = NULL, $reset = FALSE) {
  $integrations =& drupal_static(__FUNCTION__);
  if ($reset) {
    _key_clear_plugin_cache('key_integration');
  }
  if (!isset($integrations) || $reset) {
    ctools_include('plugins');
    $integrations = ctools_get_plugins('key', 'key_integration');
  }

  // If no filtering should occur, return all integrations.
  if (!$status && !$type) {
    return $integrations;
  }
  $filtered_integrations = $integrations;

  // Filter integrations by status and/or type.
  foreach ($integrations as $name => $integration) {
    if ($status == 'enabled' && !$integration['enabled']) {
      unset($filtered_integrations[$name]);
      continue;
    }
    if ($status == 'disabled' && $integration['enabled']) {
      unset($filtered_integrations[$name]);
      continue;
    }
    if (isset($type) && $integration['type'] != $type) {
      unset($filtered_integrations[$name]);
      continue;
    }
  }
  return $filtered_integrations;
}

/**
 * Gets all key integrations as options, for use in forms.
 *
 * @param string $status
 *   An enabled status by which to filter the results.
 * @param string $type
 *   An integration type by which to filter the results.
 * @param bool $reset
 *   A flag to force a reset of the integration data.
 *
 * @return array
 *   An array of integrations, with names for keys and labels for values.
 */
function key_get_integrations_as_options($status = NULL, $type = NULL, $reset = FALSE) {
  $integrations = key_get_integrations($status, $type, $reset);
  $options = array();
  foreach ($integrations as $name => $integration) {
    $options[$name] = $integration['title'];
  }
  return $options;
}

/**
 * Gets information about a specific key integration.
 *
 * @param string $name
 *   The machine name of the integration to get.
 * @param bool $reset
 *   A flag to force a reset of the integration data.
 *
 * @return array
 *   A key integration.
 */
function key_get_integration($name, $reset = FALSE) {
  $integrations = key_get_integrations(NULL, NULL, $reset);
  if (array_key_exists($name, $integrations)) {
    $integration = $integrations[$name];
  }
  else {
    $integration = NULL;
  }
  return $integration;
}

/**
 * Checks if a specific key integration is enabled.
 */
function key_integration_is_enabled($name, $reset = FALSE) {
  $integration = key_get_integration($name, $reset);
  return $integration['enabled'];
}

/**
 * Gets information about key integration settings.
 *
 * @param string $name
 *   The name of an integration to retrieve.
 * @param bool $reset
 *   A flag to force the settings to be retrieved from the database.
 *
 * @return array
 *   An array of integration settings.
 */
function key_get_integration_settings($name = NULL, $reset = FALSE) {
  $rows =& drupal_static(__FUNCTION__);
  if (!isset($rows) || $reset) {
    $rows = db_query("SELECT * FROM {key_integration} ORDER BY name ASC")
      ->fetchAllAssoc('name', PDO::FETCH_ASSOC);

    // Unserialize settings field.
    foreach ($rows as $index => $row) {
      if (!empty($row['settings'])) {
        $settings = unserialize($row['settings']);
        $rows[$index]['settings'] = $settings;
      }
    }
  }
  if ($name) {
    return isset($rows[$name]) ? $rows[$name] : NULL;
  }
  else {
    return $rows;
  }
}

/**
 * Save settings for a key integration.
 *
 * @param array $fields
 *   The fields of the integration to save.
 */
function key_save_integration_settings($fields) {

  // Load the integration.
  $integration = key_get_integration($fields['name']);

  // If the integration is locked, make sure no db record exists.
  if ($integration['locked']) {
    $num_deleted = db_delete('key_integration')
      ->condition('name', $fields['name'])
      ->execute();
    return;
  }

  // Serialize any field that is an array.
  foreach ($fields as $index => $field) {
    if (is_array($field)) {
      $fields[$index] = serialize($field);
    }
  }

  // Save the integration.
  $merge_status = db_merge('key_integration')
    ->key(array(
    'name' => $fields['name'],
  ))
    ->fields($fields)
    ->execute();
}

/**
 * Get a key using a key configuration.
 *
 * @param string $config_name
 *   The configuration name of the key to retrieve.
 *
 * @return string
 *   The key.
 */
function key_get_key($config_name) {
  $keys =& drupal_static(__FUNCTION__);

  // If the key already exists, return it.
  if (isset($keys[$config_name])) {
    return $keys[$config_name];
  }
  $config = key_get_config($config_name);
  $provider = key_get_provider($config['provider']);

  // Get the function to retrieve the key.
  $key_function = ctools_plugin_get_function($provider, 'key get callback');

  // If there are any settings, use them.
  $provider_settings = isset($config['provider_settings']) ? $config['provider_settings'] : array();

  // Retrieve the key.
  $key = call_user_func($key_function, $provider_settings);

  // Store the key, in case it's needed again.
  $keys[$config_name] = $key;
  return $key;
}

/**
 * Helper function to clear key plugin caches.
 */
function _key_clear_plugin_cache($type = NULL) {
  if ($type) {
    cache_clear_all("plugins:key:{$type}", 'cache');
  }
  else {
    cache_clear_all('plugins:key:', 'cache', TRUE);
  }
}

/**
 * Callback function to process key provider plugins.
 */
function _key_provider_plugin_process(&$plugin, $info) {

  // Check dependencies and attach any errors to the plugin.
  if ($dependency_function = ctools_plugin_get_function($plugin, 'dependency callback')) {
    $plugin['dependency errors'] = call_user_func($dependency_function);
  }
}

/**
 * Determine if a key provider plugin is valid.
 *
 * @param array $plugin
 *   The plugin to check.
 *
 * @return bool
 *   Whether or not the plugin is valid.
 */
function _key_plugin_is_valid($plugin) {
  if (empty($plugin['dependency errors'])) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

/**
 * Callback function to process key integration plugins.
 */
function _key_integration_plugin_process(&$plugin, $info) {
  $integrations = db_query("SELECT * FROM {key_integration} ORDER BY name ASC")
    ->fetchAllAssoc('name', PDO::FETCH_ASSOC);
  $name = $plugin['name'];
  if (array_key_exists($name, $integrations)) {
    if (isset($integrations[$name]['enabled'])) {
      $plugin['enabled'] = $integrations[$name]['enabled'];
    }
  }
}

/**
 * Implements hook_features_api().
 *
 * Define the components that we want to make exportable, in this case
 * key configurations and integrations.
 */
function key_features_api() {
  return array(
    'key_config' => array(
      'name' => 'Keys',
      'file' => drupal_get_path('module', 'key') . '/includes/key_config.features.inc',
      'default_hook' => 'key_default_configs',
      'feature_source' => TRUE,
    ),
    'key_integration' => array(
      'name' => 'Key Integration',
      'file' => drupal_get_path('module', 'key') . '/includes/key_integration.features.inc',
      'default_hook' => 'key_default_integrations',
      'feature_source' => TRUE,
    ),
  );
}

Functions

Namesort descending Description
key_ctools_plugin_directory Implements hook_ctools_plugin_directory().
key_ctools_plugin_type Implements hook_ctools_plugin_type().
key_element_info Implements hook_element_info().
key_features_api Implements hook_features_api().
key_get_config Gets information about a specific key configuration.
key_get_configs Gets information about all key configurations.
key_get_configs_as_options Gets all key configurations as options, for use in forms.
key_get_integration Gets information about a specific key integration.
key_get_integrations Gets information about key integrations.
key_get_integrations_as_options Gets all key integrations as options, for use in forms.
key_get_integration_settings Gets information about key integration settings.
key_get_key Get a key using a key configuration.
key_get_provider Gets information about a specific key provider.
key_get_providers Gets information about all key providers.
key_get_providers_as_options Gets all key providers as options, for use in forms.
key_get_type Gets information about a specific key type.
key_get_types Gets information about all key types.
key_get_types_as_options Gets all key types as options, for use in forms.
key_integration_is_enabled Checks if a specific key integration is enabled.
key_permission Implements hook_permission().
key_save_config Save a key configuration.
key_save_integration_settings Save settings for a key integration.
_key_clear_plugin_cache Helper function to clear key plugin caches.
_key_configs_filter Filter an array of key configurations.
_key_element_expand Process function to expand the key element.
_key_integration_plugin_process Callback function to process key integration plugins.
_key_plugin_is_valid Determine if a key provider plugin is valid.
_key_provider_plugin_process Callback function to process key provider plugins.

Constants

Namesort descending Description
KEY_STATUS_NOT_VALID
KEY_STATUS_VALID @file Provides the ability to manage keys, which can be used by other modules.