hosting_alias.module

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

Functions

Namesort descending Description
hosting_alias_add_alias_callback Ajax callback for returning multiple alias fields.
hosting_alias_add_alias_submit Callback to handle "Add Alias" button.
hosting_alias_allow_domain Implements 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_data Alter the node form for a site to add the aliases and redirection items.
hosting_alias_form_site_node_form_alter Implements hook_form_alter().
hosting_alias_get_aliases Retrieve a list of aliases for a site.
hosting_alias_help Implements hook_help().
hosting_alias_insert Save stored aliases for a new site.
hosting_alias_menu Implements hook_menu().
hosting_alias_node_delete Implements hook_node_delete().
hosting_alias_node_insert Implements hook_node_insert().
hosting_alias_node_load Implements hook_node_load().
hosting_alias_node_revision_delete Implements hook_node_revision_delete().
hosting_alias_node_update Implements hook_node_update().
hosting_alias_node_view Implements hook_node_view().
hosting_alias_permission Implements hook_permission().
hosting_alias_settings Configuration form for site aliases.
hosting_alias_settings_validate Validation handler for hosting_alias_settings form.
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.

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.

File

alias/hosting_alias.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * Allow sites to have domain aliases that they can be accessed with.
  5. */
  6. /**
  7. * An alias of this type is a custom, user generated one.
  8. */
  9. define('HOSTING_ALIAS_CUSTOM', 0);
  10. /**
  11. * An alias of this type is an automatically generated one.
  12. *
  13. * @see hosting_alias_automatic_aliases()
  14. */
  15. define('HOSTING_ALIAS_AUTOMATIC', 1);
  16. /**
  17. * Implements hook_menu().
  18. */
  19. function hosting_alias_menu() {
  20. $items['admin/hosting/aliases'] = array(
  21. 'title' => 'Site aliases',
  22. 'description' => 'Configure aliases for hosted sites',
  23. 'page callback' => 'drupal_get_form',
  24. 'page arguments' => array('hosting_alias_settings'),
  25. 'access arguments' => array('administer hosting aliases'),
  26. 'type' => MENU_LOCAL_TASK,
  27. );
  28. $items['hosting_alias/js'] = array(
  29. 'title' => 'Javascript Alias Form',
  30. 'page callback' => 'hosting_alias_form_js',
  31. 'access arguments' => array('access content'),
  32. 'type' => MENU_CALLBACK,
  33. );
  34. return $items;
  35. }
  36. /**
  37. * Implements hook_help().
  38. */
  39. function hosting_alias_help($path, $arg) {
  40. switch ($path) {
  41. case 'admin/hosting/aliases':
  42. $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 />');
  43. $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 />');
  44. $output .= t('Settings made here do not take effect automatically for existing sites.<br />');
  45. return $output;
  46. }
  47. }
  48. /**
  49. * Implements hook_form_alter().
  50. *
  51. * Add a textbox to site node forms with a newline
  52. * separated list of aliases to the site
  53. */
  54. function hosting_alias_form_site_node_form_alter(&$form, &$form_state) {
  55. if (user_access('create site aliases')) {
  56. $form['#validate'][] = 'hosting_alias_site_form_validate';
  57. return hosting_alias_form_data($form, $form_state);
  58. }
  59. }
  60. /**
  61. * Validation handler for site form.
  62. *
  63. * Makes sure aliases are not more than HOSTING_MAX_ALIAS_LENGTH characters.
  64. */
  65. function hosting_alias_site_form_validate($form, &$form_state) {
  66. $aliases = $form_state['values']['aliases'] = array_filter($form_state['values']['aliases']);
  67. foreach ($aliases as $key => $alias) {
  68. hosting_alias_validate_alias($form_state['node'], $alias, $key);
  69. }
  70. }
  71. /**
  72. * Alter the node form for a site to add the aliases and redirection items.
  73. *
  74. * @param array $form
  75. * The form to alter, should come from hook_form_alter().
  76. * @param array $form_state
  77. * A keyed array containing the current state of the form.
  78. */
  79. function hosting_alias_form_data(&$form, &$form_state) {
  80. // List the automatic aliasses first.
  81. $automatic_aliases = hosting_alias_get_aliases($form['#node'], HOSTING_ALIAS_AUTOMATIC);
  82. if (count($automatic_aliases)) {
  83. foreach ($automatic_aliases as $link) {
  84. $links[] = l($link, "http://$link");
  85. }
  86. $form['aliases_automatic'] = array(
  87. '#type' => 'item',
  88. '#title' => t('Automatic domain aliases'),
  89. '#markup' => implode(', ', $links),
  90. '#weight' => 10,
  91. );
  92. }
  93. // Add a wrapper for the aliases and more button.
  94. $form['aliases_wrapper'] = array(
  95. '#tree' => FALSE,
  96. '#title' => t('Domain Aliases'),
  97. '#type' => 'fieldset',
  98. '#prefix' => '<div class="clear-block" id="hosting-aliases-wrapper">',
  99. '#suffix' => '</div>',
  100. );
  101. $form['aliases_wrapper']['aliases'] = array(
  102. '#prefix' => '<div id="hosting-aliases">',
  103. '#suffix' => '</div>',
  104. '#tree' => TRUE,
  105. // '#theme' => 'hosting_alias_form',
  106. );
  107. // Get the list of existing aliases, either from form_state or the node.
  108. if (isset($form_state['input']['aliases'])) {
  109. $aliases = array_filter($form_state['input']['aliases']);
  110. }
  111. elseif (isset($form['#node']->aliases)) {
  112. $aliases = array_filter($form['#node']->aliases);
  113. }
  114. else {
  115. $aliases = array();
  116. }
  117. // Add alias textfields.
  118. for ($delta = 0; $delta <= count($aliases); $delta++) {
  119. $form['aliases_wrapper']['aliases'][$delta] = array(
  120. '#type' => 'textfield',
  121. '#default_value' => isset($aliases[$delta]) ? $aliases[$delta] : '',
  122. );
  123. }
  124. // "Add Alias" button.
  125. $form['aliases_wrapper']['add_alias'] = array(
  126. '#type' => 'submit',
  127. '#value' => t('Add an alias'),
  128. '#description' => t("Click here to add another alias."),
  129. '#weight' => 1,
  130. '#submit' => array('hosting_alias_add_alias_submit'),
  131. '#ajax' => array(
  132. 'callback' => 'hosting_alias_add_alias_callback',
  133. 'wrapper' => 'hosting-aliases-wrapper',
  134. 'method' => 'replace',
  135. 'effect' => 'fade',
  136. ),
  137. );
  138. // Redirection Domain.
  139. $options = array();
  140. $options[0] = t('No redirection');
  141. if (isset($form['#node']->title)) {
  142. $options[$form['#node']->title] = $form['#node']->title;
  143. }
  144. if (!empty($aliases)) {
  145. $options += array_combine($aliases, $aliases);
  146. }
  147. if (!empty($automatic_aliases)) {
  148. $options += array_combine($automatic_aliases, $automatic_aliases);
  149. }
  150. $default = isset($form['#node']->redirection) ? $form['#node']->redirection : '';
  151. $form['aliases_wrapper']['redirection'] = array(
  152. '#type' => 'select',
  153. '#title' => t('Redirect all domain aliases to'),
  154. '#options' => $options,
  155. '#default_value' => $default,
  156. '#weight' => -1,
  157. );
  158. return $form;
  159. }
  160. /**
  161. * Callback to handle "Add Alias" button.
  162. */
  163. function hosting_alias_add_alias_submit($form, &$form_state) {
  164. $form_state['rebuild'] = TRUE;
  165. }
  166. /**
  167. * Ajax callback for returning multiple alias fields.
  168. */
  169. function hosting_alias_add_alias_callback($form, $form_state) {
  170. return $form['aliases_wrapper'];
  171. }
  172. /**
  173. * Retrieve a list of aliases for a site.
  174. *
  175. * @param Object $node
  176. * The site to get the aliases for.
  177. * @param int $type
  178. * Restrict the type of aliases returned, defaults to returning all aliases.
  179. * Should be one of:
  180. * - HOSTING_ALIAS_CUSTOM
  181. * - HOSTING_ALIAS_AUTOMATIC
  182. *
  183. * @return array
  184. * An array of aliases for the given site.
  185. */
  186. function hosting_alias_get_aliases($node, $type = NULL) {
  187. if (empty($node->vid)) {
  188. return array();
  189. }
  190. $alias = array();
  191. $query = db_select('hosting_site_alias')
  192. ->addTag('hosting_alias_get_aliases')
  193. ->fields('hosting_site_alias', array('alias'))
  194. ->condition('vid', $node->vid)
  195. ->orderBy('alias', 'ASC');
  196. if (!is_null($type)) {
  197. $query->condition('automatic', $type);
  198. }
  199. $result = $query->execute();
  200. foreach ($result as $obj) {
  201. $alias[] = $obj->alias;
  202. }
  203. if (count($alias)) {
  204. return $alias;
  205. }
  206. return array();
  207. }
  208. /**
  209. * Save stored aliases for a new site.
  210. *
  211. * @param Object $node
  212. * The node of the site containing the aliases to save.
  213. */
  214. function hosting_alias_insert($node) {
  215. $automatic = hosting_alias_automatic_aliases(strtolower(trim($node->title)));
  216. if (!empty($node->aliases) || count($automatic)) {
  217. $aliases = (is_array($node->aliases)) ? $node->aliases : explode("\n", str_replace(",", "\n", $node->aliases));
  218. if (is_array($aliases)) {
  219. foreach ($aliases as $alias) {
  220. if (($alias = trim($alias)) && !in_array($alias, $automatic)) {
  221. $id = db_insert('hosting_site_alias')
  222. ->fields(array(
  223. 'vid' => $node->vid,
  224. 'nid' => $node->nid,
  225. 'alias' => $alias,
  226. 'automatic' => HOSTING_ALIAS_CUSTOM,
  227. 'redirection' => isset($node->redirection) ? $node->redirection : 0,
  228. ))
  229. ->execute();
  230. }
  231. }
  232. }
  233. if (count($automatic)) {
  234. foreach ($automatic as $alias) {
  235. if (($alias = trim($alias)) && _hosting_valid_fqdn_wildcard($alias)) {
  236. $id = db_insert('hosting_site_alias')
  237. ->fields(array(
  238. 'vid' => $node->vid,
  239. 'nid' => $node->nid,
  240. 'alias' => $alias,
  241. 'automatic' => HOSTING_ALIAS_AUTOMATIC,
  242. 'redirection' => isset($node->redirection) ? $node->redirection : 0,
  243. ))
  244. ->execute();
  245. }
  246. }
  247. }
  248. }
  249. }
  250. /**
  251. * Update stored aliases for an existing site.
  252. *
  253. * @param Object $node
  254. * The node of the site containing the aliases to save.
  255. */
  256. function hosting_alias_update($node) {
  257. // We need to wipe clean existing aliases if we are not making a new revision.
  258. if (empty($node->revision)) {
  259. hosting_alias_delete_revision($node);
  260. }
  261. hosting_alias_insert($node);
  262. }
  263. /**
  264. * Remove the stored aliases for and existing site.
  265. *
  266. * @param Object $node
  267. * The site node.
  268. */
  269. function hosting_alias_delete($node) {
  270. db_delete('hosting_site_alias')
  271. ->condition('nid', $node->nid)
  272. ->execute();
  273. }
  274. /**
  275. * Remove the stored aliases for and existing site for a specific version.
  276. *
  277. * @param Object $node
  278. * The site node.
  279. */
  280. function hosting_alias_delete_revision($node) {
  281. db_delete('hosting_site_alias')
  282. ->condition('nid', $node->nid)
  283. ->condition('vid', $node->vid)
  284. ->execute();
  285. }
  286. /**
  287. * Implements hook_node_insert().
  288. */
  289. function hosting_alias_node_insert($node) {
  290. if ($node->type == 'site') {
  291. hosting_alias_insert($node);
  292. }
  293. }
  294. /**
  295. * Implements hook_node_update().
  296. */
  297. function hosting_alias_node_update($node) {
  298. if ($node->type == 'site') {
  299. hosting_alias_update($node);
  300. }
  301. }
  302. /**
  303. * Implements hook_node_delete().
  304. */
  305. function hosting_alias_node_delete($node) {
  306. if ($node->type == 'site') {
  307. hosting_alias_delete($node);
  308. }
  309. }
  310. /**
  311. * Implements hook_node_revision_delete().
  312. */
  313. function hosting_alias_node_revision_delete($node) {
  314. if ($node->type == 'site') {
  315. hosting_alias_delete_revision($node);
  316. }
  317. }
  318. /**
  319. * Ensure that an alias is valid, and not already in use.
  320. *
  321. * @param object $site
  322. * A Hosting site node.
  323. * @param string $alias
  324. * An alias to have point to the site.
  325. * @param string $key
  326. * The array index of this alias, to set any error on the proper sub-field.
  327. */
  328. function hosting_alias_validate_alias($site, $alias, $key) {
  329. if ($alias = trim($alias)) {
  330. $params = isset($site->nid) ? array('nid' => $site->nid) : array();
  331. if (!hosting_domain_allowed($alias, $params) || $alias == $site->title) {
  332. form_set_error("aliases][$key", t('The domain name @alias is already in use', array('@alias' => $alias)));
  333. }
  334. if (!_hosting_valid_fqdn_wildcard($alias)) {
  335. form_set_error("aliases][$key", t('The domain name @alias is not a valid url', array('@alias' => $alias)));
  336. }
  337. $length = strlen($alias);
  338. if ($length > HOSTING_MAX_ALIAS_LENGTH) {
  339. $long = $length - HOSTING_MAX_ALIAS_LENGTH;
  340. form_set_error("aliases][$key", t('The domain name @alias is @long character(s) too long. Please shorten.', array('@alias' => $alias, '@long' => $long)));
  341. }
  342. }
  343. }
  344. /**
  345. * Implements hook_node_load().
  346. */
  347. function hosting_alias_node_load($nodes, $types) {
  348. foreach ($nodes as $nid => &$node) {
  349. if ($node->type == 'site') {
  350. // XXX: this returns only the first redirection status. it
  351. // works since they are all set to the same in hook_insert(),
  352. // but we should return an associative alias => redirection
  353. // array instead.
  354. $nodes[$nid]->redirection = db_query("SELECT redirection FROM {hosting_site_alias} WHERE vid = :vid", array(':vid' => $node->vid))->fetchField();
  355. // Only retrieves custom aliases, as they are all that can be modified.
  356. $nodes[$nid]->aliases = hosting_alias_get_aliases($node, HOSTING_ALIAS_CUSTOM);
  357. $nodes[$nid]->aliases_automatic = hosting_alias_get_aliases($node, HOSTING_ALIAS_AUTOMATIC);
  358. }
  359. }
  360. }
  361. /**
  362. * Implements hook_node_view().
  363. */
  364. function hosting_alias_node_view($node, $view_mode, $langcode) {
  365. if ($node->type == 'site') {
  366. if (count($node->aliases)) {
  367. foreach ($node->aliases as $link) {
  368. $links[] = l($link, "http://$link");
  369. }
  370. $node->content['info']['aliases'] = array(
  371. '#type' => 'item',
  372. '#title' => t('Domain aliases'),
  373. '#markup' => implode(', ', $links),
  374. '#weight' => 10,
  375. );
  376. $redirection = db_query("SELECT redirection FROM {hosting_site_alias} WHERE vid = :vid", array(':vid' => $node->vid))->fetchAssoc();
  377. $node->content['info']['redirection'] = array(
  378. '#type' => 'item',
  379. '#title' => t('Redirection'),
  380. '#markup' => $redirection['redirection'] ? t('Yes') : t('No'),
  381. '#weight' => 12,
  382. );
  383. }
  384. // List the automatic aliasses.
  385. if (count($node->aliases_automatic)) {
  386. $links = array();
  387. foreach ($node->aliases_automatic as $link) {
  388. $links[] = l($link, "http://$link");
  389. }
  390. $node->content['info']['aliases_automatic'] = array(
  391. '#type' => 'item',
  392. '#title' => t('Auto aliases'),
  393. '#markup' => implode(', ', $links),
  394. '#weight' => 11,
  395. );
  396. }
  397. }
  398. }
  399. /**
  400. * Implements hook_permission().
  401. */
  402. function hosting_alias_permission() {
  403. return array(
  404. 'create site aliases' => array(
  405. 'title' => t('create site aliases'),
  406. ),
  407. 'administer hosting aliases' => array(
  408. 'title' => t('administer hosting aliases'),
  409. ),
  410. );
  411. }
  412. /**
  413. * Configuration form for site aliases.
  414. *
  415. * @see hosting_alias_menu()
  416. */
  417. function hosting_alias_settings($form, &$form_state) {
  418. $form['hosting_alias_subdomain'] = array(
  419. '#type' => 'textfield',
  420. '#title' => t('Domain used for automatic subdomain hosting'),
  421. '#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.'),
  422. '#default_value' => variable_get('hosting_alias_subdomain', ''),
  423. );
  424. $form['hosting_alias_automatic_www'] = array(
  425. '#type' => 'checkbox',
  426. '#title' => t('Generate www.domain.com alias automatically'),
  427. '#description' => t('If a domain name does not start with www., automatically create an alias for www.domain?'),
  428. '#default_value' => variable_get('hosting_alias_automatic_www', FALSE),
  429. );
  430. $form['hosting_alias_automatic_no_www'] = array(
  431. '#type' => 'checkbox',
  432. '#title' => t('Generate domain.com alias automatically'),
  433. '#description' => t('If a domain name starts with www., automatically create an alias for domain.com?'),
  434. '#default_value' => variable_get('hosting_alias_automatic_no_www', FALSE),
  435. );
  436. $form['hosting_alias_redirection'] = array(
  437. '#type' => 'checkbox',
  438. '#title' => t('Use redirects instead of aliases by default'),
  439. '#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.'),
  440. '#default_value' => variable_get('hosting_alias_redirection', FALSE),
  441. );
  442. $form['#submit'][] = 'hosting_alias_settings_validate';
  443. return system_settings_form($form);
  444. }
  445. /**
  446. * Validation handler for hosting_alias_settings form.
  447. */
  448. function hosting_alias_settings_validate($form, $form_state) {
  449. if (!valid_url($form_state['values']['hosting_alias_subdomain'])) {
  450. form_set_error('hosting_alias_subdomain', t('The provided domain is invalid.'));
  451. }
  452. }
  453. /**
  454. * Generate a default set of aliases for the site based on the global options.
  455. */
  456. function hosting_alias_automatic_aliases($url) {
  457. $alias = array();
  458. if ($sub = variable_get('hosting_alias_subdomain', FALSE)) {
  459. if (!preg_match("/\." . preg_quote($sub, '/') . "$/", $url)) {
  460. $alias[] = str_replace(array('-', '.'), array('--', '-'), $url) . "." . trim($sub, ".");
  461. }
  462. }
  463. if (!preg_match('/^www\./', $url) && variable_get('hosting_alias_automatic_www', FALSE)) {
  464. $alias[] = "www." . $url;
  465. }
  466. elseif (preg_match('/^www\./', $url) && variable_get('hosting_alias_automatic_no_www', FALSE)) {
  467. $alias[] = str_replace("www.", "", $url);
  468. }
  469. return $alias;
  470. }
  471. /**
  472. * Implements hook_allow_domain().
  473. *
  474. * This function will check the existing aliases and the automatically
  475. * generated aliases to ensure that this url has not been used before
  476. */
  477. function hosting_alias_allow_domain($url, $params = array()) {
  478. $query = db_select('node', 'n')
  479. ->fields('n', array('nid'))
  480. ->condition('n.type', 'site');
  481. $query->leftJoin('hosting_site', 'h', 'h.nid = n.nid');
  482. $query->condition('h.status', HOSTING_SITE_DELETED, '<>');
  483. $query->leftJoin('hosting_site_alias', 'a', 'n.vid = a.vid');
  484. $query->condition('a.alias', $url);
  485. // For existing sites, don't match the site's current aliases.
  486. if (isset($params['nid'])) {
  487. $query->condition('n.nid', $params['nid'], '<>');
  488. }
  489. return !$query->countQuery()->execute()->fetchField();
  490. }