You are here

hosting_alias.module in Hosting 6.2

Allow sites to have domain aliases that they can be accessed with.

File

alias/hosting_alias.module
View source
<?php

/**
 * @file
 *   Allow sites to have domain aliases that they can be accessed with.
 */

/**
 * An alias of this type is a custom, user generated one.
 */
define('HOSTING_ALIAS_CUSTOM', 0);

/**
 * An alias of this type is an automatically generated one.
 *
 * @see hosting_alias_automatic_aliases()
 */
define('HOSTING_ALIAS_AUTOMATIC', 1);

/**
 * Implementation of hook_menu().
 */
function hosting_alias_menu() {
  $items['admin/hosting/aliases'] = array(
    'title' => 'Site aliases',
    'description' => 'Configure aliases for hosted sites',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'hosting_alias_settings',
    ),
    'access arguments' => array(
      'administer hosting aliases',
    ),
    'type' => MENU_LOCAL_TASK,
  );
  $items['hosting_alias/js'] = array(
    'title' => 'Javascript Alias Form',
    'page callback' => 'hosting_alias_form_js',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implementation of hook_help().
 */
function hosting_alias_help($path, $arg) {
  switch ($path) {
    case 'admin/hosting/aliases':
      $output = t('Site aliases allow you to let sites be available through multiple domain addresses.<br /> The most common use of this functionality is to provide automatic aliasing for www.mysite.com and mysite.com variants of the domain name.<br /> ');
      $output .= t('This module will also allow you to provide a "temporary url" that sites will always be accessible from, in case of DNS problems.<br />');
      $output .= t('Settings made here do not take effect automatically for existing sites.<br />');
      break;
  }
  return $output;
}

/**
 * Implementation of hook_form_alter().
 *
 * Add a textbox to site node forms with a newline
 * separated list of aliases to the site
 */
function hosting_alias_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'site_node_form') {
    $form['#validate'][] = 'hosting_alias_site_form_validate';
    return hosting_alias_form_data($form, $form_state);
  }
}

/**
 * Validation handler for site form.
 *
 * Makes sure aliases are not more than HOSTING_MAX_ALIAS_LENGTH characters.
 */
function hosting_alias_site_form_validate($form, &$form_state) {
  $aliases = $form_state['values']['aliases'];
  foreach ($aliases as $key => $alias) {
    $length = strlen(trim($alias));
    if ($length > HOSTING_MAX_ALIAS_LENGTH) {
      $long = $length - HOSTING_MAX_ALIAS_LENGTH;
      form_set_error("aliases_wrapper][aliases][{$key}", t('The alias @alias is @long character(s) too long. Please shorten.', array(
        '@alias' => $alias,
        '@long' => $long,
      )));
    }
  }
}

/**
 * Alter the node form for a site to add the aliases and redirection items.
 *
 * @param $form
 *   The form to alter, should come from hook_form_alter().
 */
function hosting_alias_form_data(&$form, &$form_state) {
  if (user_access('create site aliases')) {

    // List the automatic aliasses first.
    $automatic_aliases = hosting_alias_get_aliases($form['#node'], HOSTING_ALIAS_AUTOMATIC);
    if (sizeof($automatic_aliases)) {
      foreach ($automatic_aliases as $link) {
        $links[] = l($link, "http://{$link}");
      }
      $form['aliases_automatic'] = array(
        '#type' => 'item',
        '#title' => t('Automatic domain aliases'),
        '#value' => implode(', ', $links),
        '#weight' => 10,
      );
    }

    // Add a wrapper for the aliases and more button.
    $form['aliases_wrapper'] = array(
      '#tree' => FALSE,
      '#title' => t('Domain Aliases'),
      '#type' => 'fieldset',
      '#prefix' => '<div class="clear-block" id="hosting-aliases-wrapper">',
      '#suffix' => '</div>',
    );
    $form['aliases_wrapper']['aliases'] = array(
      '#prefix' => '<div id="hosting-aliases">',
      '#suffix' => '</div>',
      '#tree' => TRUE,
    );

    // Get the list of existing aliases, either from form_state or the node.
    if (isset($form_state['aliases'])) {
      $aliases = array_filter($form_state['aliases']);
    }
    elseif (isset($form['#node']->aliases)) {
      $aliases = array_filter($form['#node']->aliases);
    }
    else {
      $aliases = array();
    }

    // Figure out the alias count
    if (isset($form_state['alias_count'])) {
      $alias_count = $form_state['alias_count'] + 1;
    }
    else {
      $alias_count = max(1, empty($aliases) ? 1 : count($aliases) + 1);
    }

    // Add alias textfields
    for ($delta = 0; $delta < $alias_count; $delta++) {
      $form['aliases_wrapper']['aliases'][$delta] = array(
        '#type' => 'textfield',
        '#default_value' => $aliases[$delta],
      );
    }

    // "Add Alias" button
    $form['aliases_wrapper']['add_alias'] = array(
      '#type' => 'submit',
      '#value' => t('Add an alias'),
      '#description' => t("Click here to add another alias."),
      '#weight' => 1,
      '#submit' => array(
        'hosting_alias_add_alias_submit',
      ),
      // If no javascript action.
      '#ahah' => array(
        'path' => 'hosting_alias/js',
        'wrapper' => 'hosting-aliases-wrapper',
        'method' => 'replace',
        'effect' => 'fade',
      ),
    );

    // Redirection Domain
    $options = array();
    $options[0] = t('No redirection');
    if (isset($form['#node']->title)) {
      $options[$form['#node']->title] = $form['#node']->title;
    }
    if (!empty($aliases)) {
      $options += array_combine($aliases, $aliases);
    }
    if (!empty($automatic_aliases)) {
      $options += array_combine($automatic_aliases, $automatic_aliases);
    }
    $default = isset($form_state['values']['redirection']) ? $form_state['values']['redirection'] : $form['#node']->redirection;
    $form['aliases_wrapper']['redirection'] = array(
      '#type' => 'select',
      '#title' => t('Redirect all domain aliases to'),
      '#options' => $options,
      '#default_value' => $default,
      '#weight' => -1,
    );
    return $form;
  }
}

/**
 * Callback to handle "Add Alias" button
 */
function hosting_alias_add_alias_submit($form, &$form_state) {

  // Set the form to rebuild and run submit handlers.
  node_form_submit_build_node($form, $form_state);

  // Make the changes we want to the form state.
  if ($form_state['values']['add_alias']) {
    $form_state['values']['aliases'] = array_filter($form_state['values']['aliases']);
    $form_state['alias_count'] = max(count($form_state['values']['aliases']), 1);
  }
}

/**
 * AHAH callback for additional alias form fields.
 *
 * Copied from poll_choice_js()
 */
function hosting_alias_form_js() {
  include_once 'modules/node/node.pages.inc';
  $form_state = array(
    'storage' => NULL,
    'submitted' => FALSE,
  );
  $form_build_id = $_POST['form_build_id'];

  // Get the form from the cache.
  $form = form_get_cache($form_build_id, $form_state);
  $args = $form['#parameters'];
  $form_id = array_shift($args);

  // We will run some of the submit handlers so we need to disable redirecting.
  $form['#redirect'] = FALSE;

  // We need to process the form, prepare for that by setting a few internals
  // variables.
  $form['#post'] = $_POST;
  $form['#programmed'] = FALSE;
  $form_state['post'] = $_POST;

  // Build, validate and if possible, submit the form.
  drupal_process_form($form_id, $form, $form_state);

  // This call recreates the form relying solely on the form_state that the
  // drupal_process_form set up.
  $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);

  // Render the new output.
  $alias_form = $form['aliases_wrapper'];
  unset($alias_form['#prefix'], $alias_form['#suffix']);

  // Prevent duplicate wrappers.
  $output = theme('status_messages') . drupal_render($alias_form);
  drupal_json(array(
    'status' => TRUE,
    'data' => $output,
  ));
}

/**
 * Retrieve a list of aliases for a site.
 *
 * @param $node
 *   The site to get the aliases for.
 * @param $type
 *   Restrict the type of aliases returned, defaults to returning all aliases. Should be one of:
 *   - HOSTING_ALIAS_CUSTOM
 *   - HOSTING_ALIAS_AUTOMATIC
 * @return
 *   An array of aliases for the given site.
 */
function hosting_alias_get_aliases($node, $type = null) {
  if (!$node->vid) {
    return array();
  }
  $alias = array();
  $query = "SELECT alias FROM {hosting_site_alias} WHERE vid=%d";
  $args[] = $node->vid;
  if (!is_null($type)) {
    $query .= " AND automatic=%d";
    $args[] = $type;
  }
  $query .= ' ORDER BY alias ASC';
  $result = db_query($query, $args);
  while ($obj = db_fetch_object($result)) {
    $alias[] = $obj->alias;
  }
  if (sizeof($alias)) {
    return $alias;
  }
  return array();
}

/**
 * Save stored aliases for a new site.
 *
 * @param $node
 *   The node of the site containing the aliases to save.
 */
function hosting_alias_insert($node) {
  $automatic = hosting_alias_automatic_aliases(strtolower(trim($node->title)));
  if ($node->aliases || sizeof($automatic)) {
    $aliases = is_array($node->aliases) ? $node->aliases : explode("\n", str_replace(",", "\n", $node->aliases));
    if (is_array($aliases)) {
      foreach ($aliases as $alias) {
        if (($alias = trim($alias)) && !in_array($alias, $automatic)) {
          db_query("INSERT INTO {hosting_site_alias} (vid, nid, alias, automatic, redirection) VALUES (%d, %d, '%s', %d, '%s')", $node->vid, $node->nid, $alias, HOSTING_ALIAS_CUSTOM, $node->redirection);
        }
      }
    }
    if (sizeof($automatic)) {
      foreach ($automatic as $alias) {
        if (($alias = trim($alias)) && _hosting_valid_fqdn_wildcard($alias)) {
          db_query("INSERT INTO {hosting_site_alias} (vid, nid, alias, automatic, redirection) VALUES (%d, %d, '%s', %d, '%s')", $node->vid, $node->nid, $alias, HOSTING_ALIAS_AUTOMATIC, $node->redirection);
        }
      }
    }
  }
}

/**
 * Update stored aliases for an existing site.
 *
 * @param $node
 *   The node of the site containing the aliases to save.
 */
function hosting_alias_update($node) {

  // We need to wipe clean existing aliases if we are not making a new revision
  if (empty($node->revision)) {
    hosting_alias_delete_revision($node);
  }
  hosting_alias_insert($node);
}

/**
 * Remove the stored aliases for and existing site.
 *
 * @param $node
 *   The site node.
 */
function hosting_alias_delete($node) {
  db_query("DELETE FROM {hosting_site_alias} WHERE nid=%d", $node->nid);
}

/**
 * Remove the stored aliases for and existing site for a specific version.
 *
 * @param $node
 *   The site node.
 */
function hosting_alias_delete_revision($node) {
  db_query("DELETE FROM {hosting_site_alias} WHERE nid=%d and vid=%d", $node->nid, $node->vid);
}

/**
 * Implementation of hook_nodeapi().
 *
 * For most of the $op's we pass of to a help function that does the heavy
 * lifting.
 */
function hosting_alias_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  if ($node->type == 'site') {
    switch ($op) {
      case 'insert':
        hosting_alias_insert($node);
        break;
      case 'update':
        hosting_alias_update($node);
        break;
      case 'delete':
        hosting_alias_delete($node);
        break;
      case 'delete revision':
        hosting_alias_delete_revision($node);
        break;
      case 'validate':
        $aliases = $node->aliases;
        foreach ($aliases as $alias) {
          if (!module_exists('hosting_subdirs')) {
            hosting_alias_validate_alias($node, $alias);
          }
        }

        // Make sure chosen redirect is still an alias
        if ($node->redirection != 0 && !in_array($node->redirection, $aliases) && !($node->redirection == $node->title)) {
          form_set_error('redirection', t('The domain name @alias is not an alias for this site.', array(
            '@alias' => $node->redirection,
          )));
        }
        break;
      case 'load':

        // XXX: this returns only the first redirection status. it
        // works since they are all set to the same in hook_insert(),
        // but we should return an associative alias => redirection
        // array instead
        $additions['redirection'] = db_result(db_query("SELECT redirection FROM {hosting_site_alias} WHERE vid=%d", $node->vid));

        // Only retrieves custom aliases, as they are all that can be modified.
        $additions['aliases'] = hosting_alias_get_aliases($node, HOSTING_ALIAS_CUSTOM);
        return $additions;
        break;
      case 'view':
        $aliases = hosting_alias_get_aliases($node);
        if (sizeof($aliases)) {
          foreach ($aliases as $link) {
            $links[] = l($link, "http://{$link}");
          }
          $node->content['info']['aliases'] = array(
            '#type' => 'item',
            '#title' => t('Domain aliases'),
            '#value' => implode(', ', $links),
            '#weight' => 10,
          );
          $redirection = db_result(db_query("SELECT redirection FROM {hosting_site_alias} WHERE vid=%d", $node->vid));
          $node->content['info']['redirection'] = array(
            '#type' => 'item',
            '#title' => t('Redirection Target'),
            '#value' => !empty($redirection) ? l($redirection, "http://{$redirection}") : t('None'),
            '#weight' => 10,
          );
        }
        break;
    }
  }
}

/**
 * Ensure that an alias is valid, and not already in use.
 *
 * @param object $site
 *   A Hosting site node.
 * @param string $alias
 *   An alias to have point to the site.
 */
function hosting_alias_validate_alias($site, $alias) {
  if ($alias = trim($alias)) {
    if (!hosting_domain_allowed($alias, array(
      'nid' => $site->nid,
    )) || $alias == $site->title) {
      form_set_error('aliases', t('The domain name @alias is already in use', array(
        '@alias' => $alias,
      )));
    }
    if (!_hosting_valid_fqdn_wildcard($alias)) {
      form_set_error('aliases', t('The domain name @alias is not a valid url', array(
        '@alias' => $alias,
      )));
    }
  }
}

/**
 * Ensure that an alias is valid for subdir site.
 *
 * @param object $site
 *   A Hosting site node.
 * @param string $alias
 *   An alias to have point to the site.
 */
function hosting_alias_validate_subdir($site, $alias) {
  if ($alias = trim($alias)) {
    if (!hosting_alias_allow_domain($alias, array(
      'nid' => $site->nid,
    )) || $alias == $site->title) {
      form_set_error('aliases', t('The domain name @alias is already in use', array(
        '@alias' => $alias,
      )));
    }
    if (!_hosting_valid_fqdn_subdir($alias)) {
      form_set_error('aliases', t('The domain name @alias is not a valid subdir url', array(
        '@alias' => $alias,
      )));
    }
  }
}

/**
 * Implementation of hook_perm().
 */
function hosting_alias_perm() {
  return array(
    'create site aliases',
    'administer hosting aliases',
  );
}

/**
 * Configuration form for site aliases.
 *
 * @see hosting_alias_menu()
 */
function hosting_alias_settings() {
  $form['hosting_alias_subdomain'] = array(
    '#type' => 'textfield',
    '#title' => t('Domain used for automatic subdomain hosting'),
    '#description' => t('To be able to provide a temporary url for your sites, you need to have configured a wild card dns entry<br /> resolving all calls to subdomains of your chosen domain, to point at your web server.'),
    '#default_value' => variable_get('hosting_alias_subdomain', ''),
  );
  $form['hosting_alias_automatic_www'] = array(
    '#type' => 'checkbox',
    '#title' => t('Generate www.domain.com alias automatically'),
    '#description' => t('If a domain name does not start with www., automatically create an alias for www.domain?'),
    '#default_value' => variable_get('hosting_alias_automatic_www', FALSE),
  );
  $form['hosting_alias_automatic_no_www'] = array(
    '#type' => 'checkbox',
    '#title' => t('Generate domain.com alias automatically'),
    '#description' => t('If a domain name starts with www., automatically create an alias for domain.com?'),
    '#default_value' => variable_get('hosting_alias_automatic_no_www', FALSE),
  );
  $form['hosting_alias_redirection'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use redirects instead of aliases by default'),
    '#description' => t('Instead of serving the primary domain under a symlinked site alias, this module can also redirect the user to the primary domain from an alias. This setting can be controlled per site. Setting this option here will make redirection the default behavior for site aliases.'),
    '#default_value' => variable_get('hosting_alias_redirection', FALSE),
  );
  return system_settings_form($form);
}

/**
 * Generate a default set of aliases for the site based on the global options.
 */
function hosting_alias_automatic_aliases($url) {
  $alias = array();
  if ($sub = variable_get('hosting_alias_subdomain', FALSE)) {
    if (!preg_match("/\\.{$sub}\$/", $url)) {
      $alias[] = str_replace(array(
        '-',
        '.',
      ), array(
        '--',
        '-',
      ), $url) . "." . trim($sub, ".");
    }
  }
  if (!preg_match('/^www\\./', $url) && variable_get('hosting_alias_automatic_www', FALSE)) {
    $alias[] = "www." . $url;
  }
  elseif (preg_match('/^www\\./', $url) && variable_get('hosting_alias_automatic_no_www', FALSE)) {
    $alias[] = str_replace("www.", "", $url);
  }
  return $alias;
}

/**
 * Implementation of hook_allow_domain().
 *
 * This function will check the existing aliases and the automatically
 * generated aliases to ensure that this url has not been used before
 */
function hosting_alias_allow_domain($url, $params = array()) {
  $query = "SELECT COUNT(n.nid) FROM {node} n \n      LEFT JOIN {hosting_site} h ON h.nid=n.nid \n      LEFT JOIN {hosting_site_alias} a  ON n.vid = a.vid \n    WHERE \n      type='site' AND alias='%s' AND h.status <> %d";
  $args[] = $url;
  $args[] = HOSTING_SITE_DELETED;
  if (isset($params['nid'])) {
    $query .= ' AND n.nid <> %d';
    $args[] = $params['nid'];
  }
  $result = !db_result(db_query($query, $args));
  return $result;
}

Functions

Namesort descending Description
hosting_alias_add_alias_submit Callback to handle "Add Alias" button
hosting_alias_allow_domain Implementation of hook_allow_domain().
hosting_alias_automatic_aliases Generate a default set of aliases for the site based on the global options.
hosting_alias_delete Remove the stored aliases for and existing site.
hosting_alias_delete_revision Remove the stored aliases for and existing site for a specific version.
hosting_alias_form_alter Implementation of hook_form_alter().
hosting_alias_form_data Alter the node form for a site to add the aliases and redirection items.
hosting_alias_form_js AHAH callback for additional alias form fields.
hosting_alias_get_aliases Retrieve a list of aliases for a site.
hosting_alias_help Implementation of hook_help().
hosting_alias_insert Save stored aliases for a new site.
hosting_alias_menu Implementation of hook_menu().
hosting_alias_nodeapi Implementation of hook_nodeapi().
hosting_alias_perm Implementation of hook_perm().
hosting_alias_settings Configuration form for site aliases.
hosting_alias_site_form_validate Validation handler for site form.
hosting_alias_update Update stored aliases for an existing site.
hosting_alias_validate_alias Ensure that an alias is valid, and not already in use.
hosting_alias_validate_subdir Ensure that an alias is valid for subdir site.

Constants

Namesort descending Description
HOSTING_ALIAS_AUTOMATIC An alias of this type is an automatically generated one.
HOSTING_ALIAS_CUSTOM An alias of this type is a custom, user generated one.