domain.module

Tracking 5.x-1.x branch
  1. drupal
    1. 5 contributions/domain/domain.module
    2. 6 contributions/domain/domain.module

Core module functions for the Domain Access suite.

Functions & methods

NameDescription
domain_adminRouter function to call various administration tasks
domain_apiHelper function for passing hook_domainload() by reference.
domain_batch_validateValidate handler for hook_domainbatch()
domain_blockImplement hook_block()
domain_check_schemeEnsure that the scheme value has not been hacked.
domain_cronImplement hook_cron()
domain_db_rewrite_sqlImplement hook_db_rewrite_sql().
domain_defaultAssigns the default settings to domain 0, the root domain.
domain_disableImplement hook_disable()
domain_disablingSimple function to make sure we don't respond with grants when disabling ourselves.
domain_domainbatchImplement hook_domainbatch()
domain_domaininstallImplement hook_domaininstall()
domain_domainloadImplement hook_domainload()
domain_domainsReturn all active domains (including the default) as an array.
domain_domainupdateImplement hook_domainupdate()
domain_enableUpon enabling this module, store the default view grant in the {node_access} table.
domain_enablingWrites the default grants when the module is first enabled.
domain_form_alterImplement hook_form_alter()
domain_form_sitename_submitUpdate the default domain's sitename.
domain_get_pathDetermine an absolute path for a domain
domain_get_uriDetermine an absolute path to the current page
domain_gotoDetermine if we must switch the active domain.
domain_grant_allActivate the hidden grant for searches.
domain_initImplement hook_init()
domain_lookupRuns a lookup against the {domain} table. One of the two values must be present
domain_menuImplement hook_menu()
domain_nodeapiImplement hook_nodeapi().
domain_node_access_explainImplement hook_node_access_explain for devel.module
domain_node_access_recordsImplement hook_node_access_records()
domain_node_grantsImplement hook_node_grants.
domain_permImplement hook_perm()
domain_set_default_grantEnsure that the 'domain_all' grant is present.
domain_simpletestImplement hook_simpletest()
domain_unique_domainValidate the domain against existing domains.
domain_userImplement hook_user()
domain_validateValidates a domain string.
domain_valid_domainValidate the domain against all correctable errors.
domain_warning_checkSets a message to the site admin.
_domain_id_sortHelper sort function
_domain_name_sortHelper sort function
_domain_rid_sortHelper sort function
_domain_rname_sortHelper sort function
_domain_rurl_sortHelper sort function
_domain_url_sortHelper sort function
_domain_write_recordsStore node_access records in the {domain_access{} table.

Constants

NameDescription
DOMAIN_EDITOR_RULEDefines how to handle editor permissions when installing the module. You may alter this variable before installing the module. See README.txt.
DOMAIN_INSTALL_RULEDefines how to handle access permissions when installing the module. You may alter this variable before installing the module. See README.txt.
DOMAIN_SITE_GRANTDefines whether to show affiliated content on all domains.. You may alter this variable before installing the module. See README.txt.

File

View source
  1. <?php
  2. /**
  3. * @defgroup domain Domain Access: A subdomain-based access control system
  4. *
  5. * The core Domain Access module.
  6. */
  7. /**
  8. * @file
  9. * Core module functions for the Domain Access suite.
  10. * @ingroup domain
  11. */
  12. /**
  13. * Defines how to handle access permissions when installing the module.
  14. * You may alter this variable before installing the module. See README.txt.
  15. */
  16. define('DOMAIN_INSTALL_RULE', TRUE);
  17. /**
  18. * Defines how to handle editor permissions when installing the module.
  19. * You may alter this variable before installing the module. See README.txt.
  20. */
  21. define('DOMAIN_EDITOR_RULE', FALSE);
  22. /**
  23. * Defines whether to show affiliated content on all domains..
  24. * You may alter this variable before installing the module. See README.txt.
  25. */
  26. define('DOMAIN_SITE_GRANT', TRUE);
  27. /**
  28. * Implement hook_init()
  29. *
  30. * Inititalizes a global $_domain variable and set it based on the
  31. * third-level domain used to access the page.
  32. */
  33. function domain_init() {
  34. global $_domain, $conf;
  35. $_domain = array();
  36. // We lower case this, since EXAMPLE.com == example.com.
  37. $_subdomain = strtolower(rtrim($_SERVER['HTTP_HOST']));
  38. // Strip the www. off the subdomain, if required by the module settings.
  39. $raw_domain = $_subdomain;
  40. if (variable_get('domain_www', 0)) {
  41. $_subdomain = str_replace('www.', '', $_subdomain);
  42. }
  43. // Lookup the active domain against our allowed hosts record.
  44. $data = db_fetch_array(db_query("SELECT domain_id FROM {domain} WHERE subdomain = '%s'", $_subdomain));
  45. // Get the domain data.
  46. $_domain = domain_lookup($data['domain_id']);
  47. // If return is -1, then the DNS didn't match anything, so use defaults.
  48. if ($_domain == -1) {
  49. $_domain = domain_default();
  50. // If the request was not for the primary domain, send the user there.
  51. // See http://drupal.org/node/293453 and http://drupal.org/node/321071.
  52. if (variable_get('domain_redirect_wildcards', TRUE) && !empty($_domain['subdomain']) && $_subdomain != $_domain['subdomain']) {
  53. $request = domain_get_uri($_domain);
  54. if (variable_get('domain_redirect_alert', TRUE)) {
  55. drupal_set_message(t('You have followed an incorrect link to this website. Please update your links and bookmarks to <a href="!url">!url</a>.', array('!url' => $request)));
  56. }
  57. drupal_goto($request);
  58. }
  59. }
  60. // If we stripped the www. send the user to the proper domain. This should only
  61. // happen once, on an inbound link or typed URL, so the overhead is acceptable.
  62. if ($raw_domain != $_subdomain) {
  63. drupal_goto(domain_get_uri($_domain));
  64. }
  65. // For Domain User, we check the validity of accounts, so the 'valid' flag must be TRUE.
  66. // If this check fails, we send users to the default site homepage.
  67. if (!$_domain['valid'] && !user_access('administer domains')) {
  68. $_domain = domain_default();
  69. drupal_goto($_domain['path']);
  70. }
  71. // Set the site name to the domain-specific name.
  72. $conf['site_name'] = $_domain['sitename'];
  73. }
  74. /**
  75. * Implement hook_menu()
  76. */
  77. function domain_menu($may_cache) {
  78. $items = array();
  79. $admin = user_access('administer domains');
  80. if ($may_cache) {
  81. $items[] = array(
  82. 'title' => t('Domains'),
  83. 'path' => 'admin/build/domain',
  84. 'access' => $admin,
  85. 'callback' => 'domain_admin',
  86. 'callback arguments' => array('view'),
  87. 'description' => t('Settings for the Domain Access module.'),
  88. );
  89. $items[] = array(
  90. 'title' => t('Domain list'),
  91. 'path' => 'admin/build/domain/view',
  92. 'access' => $admin,
  93. 'type' => MENU_DEFAULT_LOCAL_TASK,
  94. 'callback' => 'domain_admin',
  95. 'callback arguments' => array('view'),
  96. 'weight' => -10,
  97. );
  98. $items[] = array(
  99. 'title' => t('Settings'),
  100. 'path' => 'admin/build/domain/settings',
  101. 'access' => $admin,
  102. 'type' => MENU_LOCAL_TASK,
  103. 'callback' => 'domain_admin',
  104. 'callback arguments' => array('configure'),
  105. 'weight' => -8,
  106. );
  107. $items[] = array(
  108. 'title' => t('Create domain record'),
  109. 'path' => 'admin/build/domain/create',
  110. 'access' => $admin,
  111. 'type' => MENU_LOCAL_TASK,
  112. 'callback' => 'domain_admin',
  113. 'callback arguments' => array('create'),
  114. 'weight' => -4,
  115. );
  116. $items[] = array(
  117. 'title' => t('Node settings'),
  118. 'path' => 'admin/build/domain/advanced',
  119. 'access' => $admin,
  120. 'type' => MENU_LOCAL_TASK,
  121. 'callback' => 'domain_admin',
  122. 'callback arguments' => array('advanced'),
  123. 'weight' => -2,
  124. );
  125. // Register the batch actions as menu callbacks
  126. $batch = module_invoke_all('domainbatch');
  127. if (!empty($batch)) {
  128. $items[] = array(
  129. 'title' => t('Batch updating'),
  130. 'path' => 'admin/build/domain/batch',
  131. 'access' => $admin,
  132. 'type' => MENU_LOCAL_TASK,
  133. 'callback' => 'domain_admin',
  134. 'callback arguments' => array('batch'),
  135. 'weight' => 0,
  136. );
  137. // Get the submenu items
  138. foreach ($batch as $key => $value) {
  139. $items[] = array(
  140. 'title' => $value['#form']['#title'],
  141. 'path' => 'admin/build/domain/batch/'. $key,
  142. 'access' => isset($value['#permission']) ? user_access($value['#permission']) : $admin,
  143. 'type' => MENU_CALLBACK,
  144. 'callback' => 'domain_admin',
  145. 'callback arguments' => array('batch', $key),
  146. 'weight' => $value['#weight'],
  147. );
  148. }
  149. }
  150. }
  151. else {
  152. $items[] = array(
  153. 'title' => t('Edit domain record'),
  154. 'path' => 'admin/build/domain/edit',
  155. 'access' => $admin,
  156. 'type' => MENU_CALLBACK,
  157. 'callback' => 'domain_admin',
  158. 'callback arguments' => array('edit', arg(4)),
  159. );
  160. $items[] = array(
  161. 'title' => t('Delete domain record'),
  162. 'path' => 'admin/build/domain/delete',
  163. 'access' => $admin,
  164. 'type' => MENU_CALLBACK,
  165. 'callback' => 'domain_admin',
  166. 'callback arguments' => array('delete', arg(4)),
  167. );
  168. // Make sure that our default grant is set at all times.
  169. if (arg(0) == 'admin') {
  170. domain_set_default_grant();
  171. }
  172. }
  173. return $items;
  174. }
  175. /**
  176. * Implement hook_perm()
  177. */
  178. function domain_perm() {
  179. $perms = array('administer domains', 'assign domain editors', 'edit domain nodes', 'set domain access', 'view domain publishing');
  180. return $perms;
  181. }
  182. /**
  183. * Implement hook_block()
  184. *
  185. * A nifty little domain-switcher block, useful during debugging.
  186. */
  187. function domain_block($op = 'list', $delta = 0, $edit = array()) {
  188. global $_domain, $base_url;
  189. $blocks = array();
  190. switch ($op) {
  191. case 'list':
  192. $blocks[0] = array(
  193. 'info' => t('Domain switcher'),
  194. );
  195. $blocks[1] = array(
  196. 'info' => t('Domain access information'),
  197. );
  198. return $blocks;
  199. break;
  200. case 'view':
  201. switch ($delta) {
  202. case 0:
  203. $block['subject'] = t('Domain switcher');
  204. $items = array();
  205. $domains = domain_domains();
  206. $msg = FALSE;
  207. foreach ($domains as $domain) {
  208. if ($domain['valid']) {
  209. $title = $domain['sitename'];
  210. $allow = TRUE;
  211. }
  212. else {
  213. $title = $domain['sitename'] .' *';
  214. $allow = FALSE;
  215. if (user_access('administer domains')) {
  216. $msg = TRUE;
  217. $allow = TRUE;
  218. }
  219. }
  220. if ($allow) {
  221. $items[] = l($title, domain_get_uri($domain));
  222. }
  223. }
  224. $block['content'] = theme('item_list', $items);
  225. if ($msg) {
  226. $block['content'] .= t('<em>* Inactive domain.</em>');
  227. }
  228. break;
  229. case 1:
  230. $block['content'] = '';
  231. if (arg(0) == 'node' && is_numeric(arg(1))) {
  232. $block['subject'] = t('Domain access information');
  233. $this_node = node_load(arg(1));
  234. $output = '';
  235. if (!empty($this_node->subdomains)) {
  236. $items = array();
  237. foreach($this_node->subdomains as $name) {
  238. $items[] = check_plain($name);
  239. }
  240. $output .= theme('item_list', $items, t('Subdomains'));
  241. }
  242. if (!empty($this_node->editors)) {
  243. $items = array();
  244. foreach($this_node->editors as $name) {
  245. $items[] = check_plain($name);
  246. }
  247. $output .= theme('item_list', $items, t('Editors'));
  248. }
  249. if (isset($this_node->domain_source)) {
  250. $this_domain = domain_lookup($this_node->domain_source);
  251. $output .= theme('item_list', array(check_plain($this_domain['sitename'])), t('Source domain'));
  252. }
  253. if (empty($output)) {
  254. $output = t('This node is not assigned to a domain.');
  255. }
  256. $block['content'] = '<p>'. t('%node is published with the following Domain Access rules:', array('%node' => $this_node->title)) .'</p>'. $output;
  257. }
  258. return $block;
  259. break;
  260. }
  261. return $block;
  262. break;
  263. }
  264. }
  265. /**
  266. * Implement hook_user()
  267. *
  268. * Attached domain_id records to all registering users. These
  269. * are used to determine which 'domain_editor' group that users
  270. * with the 'edit domain nodes' permission are in.
  271. */
  272. function domain_user($op, &$edit, &$account, $category = NULL) {
  273. switch ($op) {
  274. case 'form':
  275. case 'register':
  276. if (is_null($category) || $category == 'account') {
  277. global $_domain;
  278. $result = db_query("SELECT domain_id, subdomain, sitename, scheme FROM {domain}");
  279. $options = array();
  280. // By default, the requesting domain is assigned.
  281. if (empty($account->domain_user)) {
  282. ($_domain['domain_id'] == 0) ? $default = array(-1) : $default = array($_domain['domain_id']);
  283. }
  284. else {
  285. $default = $account->domain_user;
  286. }
  287. $options[-1] = variable_get('domain_sitename', variable_get('site_name', 'Drupal'));
  288. while ($data = db_fetch_array($result)) {
  289. $options[$data['domain_id']] = check_plain($data['sitename']);
  290. }
  291. if (user_access('assign domain editors')) {
  292. $form['domain_user'] = array(
  293. '#type' => 'fieldset',
  294. '#title' => t('Domain access'),
  295. '#collapsible' => TRUE,
  296. '#collapsed' => FALSE,
  297. '#weight' => 1
  298. );
  299. $form['domain_user']['domain_user'] = array(
  300. '#type' => 'checkboxes',
  301. '#options' => $options,
  302. '#title' => t('Domain access setttings'),
  303. '#description' => t('Select the affiliates that this user belongs to. Used to grant editing permissions for users with the "edit domain nodes" permission.'),
  304. '#default_value' => $default
  305. );
  306. }
  307. else {
  308. $form['domain_user'] = array(
  309. '#type' => 'value',
  310. '#value' => $default
  311. );
  312. }
  313. return $form;
  314. }
  315. break;
  316. case 'validate':
  317. return array('domain_user' => $edit['domain_user']);
  318. break;
  319. case 'insert':
  320. case 'update':
  321. // If our field element is missing, do nothing.
  322. if (!isset($edit['domain_user'])) {
  323. return;
  324. }
  325. break;
  326. case 'view':
  327. if (user_access('assign domain editors') && !empty($account->domain_user)) {
  328. $output = '<ul>';
  329. foreach ($account->domain_user as $id) {
  330. if (abs($id) > 0) {
  331. if ($id > 0) {
  332. $domain = domain_lookup($id);
  333. $output .= '<li>'. check_plain($domain['sitename']) .'</li>';
  334. }
  335. else {
  336. $output .= '<li>'. check_plain(variable_get('domain_sitename', variable_get('site_name', 'Drupal'))) .'</li>';
  337. }
  338. }
  339. }
  340. $output .= '</ul>';
  341. $items['domain'] = array(
  342. 'title' => t('Domain settings'),
  343. 'value' => $output,
  344. 'class' => 'status',
  345. );
  346. return array(t('Domain status') => $items);
  347. }
  348. break;
  349. }
  350. }
  351. /**
  352. * Implement hook_cron()
  353. *
  354. * This function invokes hook_domaincron() and allows
  355. * Domain Access modules to run functions for all active affiliates.
  356. */
  357. function domain_cron() {
  358. global $_domain;
  359. // Check to see if this function is needed at all.
  360. $modules = module_implements('domaincron');
  361. if (!empty($modules)) {
  362. // Store the current $_domain global.
  363. $_temp = $_domain;
  364. // Get the domain list.
  365. $domains = domain_domains();
  366. // Run the hook for each active domain.
  367. foreach ($domains as $domain) {
  368. // Set the domain-specific variables
  369. if (function_exists('_domain_conf_load')) {
  370. _domain_conf_load($domain);
  371. }
  372. // Set the global table prefix
  373. if (function_exists('_domain_prefix_load')) {
  374. _domain_prefix_load($domain);
  375. }
  376. // Set the global to the current $domain.
  377. $_domain = $domain;
  378. foreach ($modules as $module) {
  379. module_invoke($module, 'domaincron', $domain);
  380. }
  381. }
  382. // Set the $_domain global back.
  383. $_domain = $_temp;
  384. }
  385. }
  386. /**
  387. * Router function to call various administration tasks
  388. *
  389. * @param $action
  390. * The function to be performed.
  391. * @param $id
  392. * The domain_id of the record to be acted upon.
  393. */
  394. function domain_admin($action, $id = NULL) {
  395. include_once('domain_admin.inc');
  396. $func = 'domain_'. $action;
  397. return $func($id);
  398. }
  399. /**
  400. * Runs a lookup against the {domain} table. One of the two values must be present
  401. *
  402. * This function also calls hook_domainload(), which lets module developers overwrite
  403. * or add to the $domain array.
  404. *
  405. * @param $domain_id
  406. * The domain_id taken from {domain}. Optional.
  407. * @param $subdomain
  408. * The string representation of a {domain} entry. Optional.
  409. * @param $reset
  410. * A boolean flag to clear the static variable if necessary.
  411. * @return
  412. * An array containing the requested row from the {domain} table, plus the
  413. * elements added by hook_domainload(). Returns -1 on failure.
  414. */
  415. function domain_lookup($domain_id = NULL, $subdomain = NULL, $reset = FALSE) {
  416. static $domains;
  417. // If both are NULL, no lookup can be run.
  418. if (is_null($domain_id) && is_null($subdomain)) {
  419. return -1;
  420. }
  421. // Create a unique key so we can static cache all requests.
  422. $key = $domain_id . $subdomain;
  423. // Run the lookup, if needed.
  424. if (!isset($domains[$key]) || $reset) {
  425. if ($subdomain) {
  426. $domain = db_fetch_array(db_query("SELECT domain_id, subdomain, sitename, scheme, valid FROM {domain} WHERE subdomain = '%s'", $subdomain));
  427. }
  428. else if ($domain_id == 0) {
  429. $domain = domain_default();
  430. }
  431. else {
  432. $domain = db_fetch_array(db_query("SELECT domain_id, subdomain, sitename, scheme, valid FROM {domain} WHERE domain_id = %d", $domain_id));
  433. }
  434. // Did we get a valid result?
  435. if (isset($domain['domain_id'])) {
  436. // Let Domain Access module extensions act to override the defaults.
  437. $domains[$key] = domain_api($domain);
  438. }
  439. else {
  440. $domains[$key] = -1;
  441. }
  442. }
  443. return $domains[$key];
  444. }
  445. /**
  446. * Assigns the default settings to domain 0, the root domain.
  447. *
  448. * This value is used throughout the modules, so needed abstraction.
  449. *
  450. * @param $reset
  451. * A boolean flag indicating whether to reset the static array or not.
  452. */
  453. function domain_default($reset = FALSE) {
  454. static $default;
  455. if (empty($default) || $reset) {
  456. $default['domain_id'] = 0;
  457. $default['sitename'] = variable_get('domain_sitename', variable_get('site_name', 'Drupal'));
  458. $default['subdomain'] = variable_get('domain_root', '');
  459. $default['scheme'] = variable_get('domain_scheme', 'http');
  460. // Set the valid flag.
  461. $default['valid'] = TRUE;
  462. // Let submodules overwrite the defaults, if they wish.
  463. $default = domain_api($default);
  464. }
  465. return $default;
  466. }
  467. /**
  468. * Return all active domains (including the default) as an array.
  469. *
  470. * @param $reset
  471. * A boolean flag indicating whether to reset the static array or not.
  472. * @return
  473. * An array of all active domains, with the domain_id as the key.
  474. */
  475. function domain_domains($reset = FALSE) {
  476. static $domains;
  477. if (empty($domains) || $reset) {
  478. $domains = array();
  479. $domains[] = domain_default($reset);
  480. // Query the db for active domain records.
  481. $result = db_query("SELECT domain_id FROM {domain}");
  482. while ($data = db_fetch_array($result)) {
  483. $domain = domain_lookup($data['domain_id'], NULL, TRUE);
  484. $domains[$domain['domain_id']] = $domain;
  485. }
  486. }
  487. $sort = variable_get('domain_sort', 'id');
  488. uasort($domains, '_domain_'. $sort .'_sort');
  489. return $domains;
  490. }
  491. /**
  492. * Helper sort function
  493. */
  494. function _domain_id_sort($a, $b) {
  495. return ($a['domain_id'] < $b['domain_id']) ? -1 : 1;
  496. }
  497. /**
  498. * Helper sort function
  499. */
  500. function _domain_name_sort($a, $b) {
  501. return strcmp($a['sitename'], $b['sitename']);
  502. }
  503. /**
  504. * Helper sort function
  505. */
  506. function _domain_url_sort($a, $b) {
  507. return strcmp($a['subdomain'], $b['subdomain']);
  508. }
  509. /**
  510. * Helper sort function
  511. */
  512. function _domain_rid_sort($a, $b) {
  513. return ($a['domain_id'] > $b['domain_id']) ? -1 : 1;
  514. }
  515. /**
  516. * Helper sort function
  517. */
  518. function _domain_rname_sort($a, $b) {
  519. return strcmp($b['sitename'], $a['sitename']);
  520. }
  521. /**
  522. * Helper sort function
  523. */
  524. function _domain_rurl_sort($a, $b) {
  525. return strcmp($a['subdomain'], $b['subdomain']);
  526. }
  527. /**
  528. * Helper function for passing hook_domainload() by reference.
  529. *
  530. * @param $domain
  531. * The domain array defined by domain_lookup().
  532. * @return
  533. * The $domain array, modified by reference by hook_domainload() implementations.
  534. */
  535. function domain_api($domain) {
  536. static $_modules;
  537. if (!isset($_modules)) {
  538. $_modules = module_implements('domainload');
  539. }
  540. if (!empty($_modules)) {
  541. foreach ($_modules as $module) {
  542. // Cannot use module_invoke_all() since these are passed by reference.
  543. $function = $module .'_domainload';
  544. $function($domain);
  545. }
  546. }
  547. return $domain;
  548. }
  549. /**
  550. * Implement hook_domainload()
  551. *
  552. * Adds the home page 'path' and 'site_grant' boolean.
  553. */
  554. function domain_domainload(&$domain) {
  555. // Get the path to the home page for this domain.
  556. $domain['path'] = domain_get_path($domain);
  557. // Grant access to all affiliates.
  558. $domain['site_grant'] = DOMAIN_SITE_GRANT;
  559. }
  560. /**
  561. * Determine an absolute path for a domain
  562. *
  563. * @param $domain
  564. * The currently active $domain array, provided by domain_lookup().
  565. */
  566. function domain_get_path($domain) {
  567. global $base_url;
  568. if (empty($base_url)) {
  569. return domain_check_scheme($domain['scheme']) .'://'. $domain['subdomain'];
  570. }
  571. $_url = parse_url($base_url);
  572. // PHP 5 does not return an empty path element.
  573. if (!isset($_url['path'])) {
  574. $_url['path'] = '/';
  575. }
  576. // We need a trailing slash at the end of the path
  577. if (substr($_url['path'], -1) != '/') {
  578. $_url['path'] .= '/';
  579. }
  580. $path = domain_check_scheme($domain['scheme']) .'://'. $domain['subdomain'] . $_url['path'];
  581. return $path;
  582. }
  583. /**
  584. * Determine an absolute path to the current page
  585. */
  586. function domain_get_uri($domain) {
  587. $path = domain_check_scheme($domain['scheme']) .'://'. $domain['subdomain'] . request_uri();
  588. return $path;
  589. }
  590. /**
  591. * Ensure that the scheme value has not been hacked.
  592. *
  593. * Note that Domain Access only supports HTTP and HTTPS.
  594. * Other protocols will be removed.
  595. *
  596. * @param $scheme
  597. * The request protocol for the requested domain.
  598. * @return
  599. * Either 'http' or 'https'.
  600. */
  601. function domain_check_scheme($scheme) {
  602. if ($scheme != 'https') {
  603. $scheme = 'http';
  604. }
  605. return $scheme;
  606. }
  607. /**
  608. * Determine if we must switch the active domain.
  609. *
  610. * This function will execute a drupal_goto() to pop users to the correct
  611. * domain.
  612. *
  613. * @param $domain
  614. * The currently active $domain array, provided by domain_lookup().
  615. */
  616. function domain_goto($domain) {
  617. global $_domain;
  618. // We must be on the proper domain, see http://drupal.org/node/186153.
  619. if ($domain != -1 && $_domain['domain_id'] != $domain['domain_id']) {
  620. $path = domain_get_uri($domain);
  621. drupal_goto($path);
  622. }
  623. }
  624. /**
  625. * Implement hook_nodeapi().
  626. *
  627. * This function is used to provide debugging information and to prep values from
  628. * the {domain_access} table when editing nodes. Since not all users can see the
  629. * domain access editing checkboxes, we pass some node_access values as hidden elements.
  630. */
  631. function domain_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  632. switch ($op) {
  633. case 'prepare':
  634. case 'load':
  635. // Append the domain grants to the node for editing.
  636. $node->domains = array();
  637. $node->editors = array();
  638. $node->domain_site = FALSE;
  639. $result = db_query("SELECT gid, realm FROM {domain_access} WHERE nid = %d AND (realm = '%s' OR realm = '%s' OR realm = '%s')", $node->nid, 'domain_id', 'domain_site', 'domain_editor');
  640. while ($data = db_fetch_object($result)) {
  641. // Transform the 0 to -1, since {domain_access} is unsigned.
  642. ($data->gid == 0) ? $gid = -1 : $gid = $data->gid;
  643. if ($data->realm == 'domain_id') {
  644. $node->domains[$gid] = $gid;
  645. if ($gid > 0) {
  646. $domain = domain_lookup($gid);
  647. $node->subdomains[] = $domain['sitename'];
  648. }
  649. else {
  650. $node->subdomains[] = variable_get('domain_sitename', variable_get('site_name', 'Drupal'));
  651. }
  652. }
  653. else if ($data->realm == 'domain_site') {
  654. $node->domain_site = TRUE;
  655. $node->subdomains[] = t('All affiliates');
  656. }
  657. else if ($data->realm == 'domain_editor') {
  658. $node->domain_editor = TRUE;
  659. if ($gid > 0) {
  660. $domain = domain_lookup($gid);
  661. $node->editors[] = $domain['sitename'];
  662. }
  663. else {
  664. $node->editors[] = variable_get('domain_sitename', variable_get('site_name', 'Drupal'));
  665. }
  666. }
  667. }
  668. break;
  669. case 'view':
  670. // Search module casts both $a3 and $a4 as FALSE, not NULL.
  671. // We check that to hide this data from search and other nodeapi
  672. // calls that are neither a teaser nor a page view.
  673. if ($a3 !== FALSE || $a4 !== FALSE) {
  674. $output = '';
  675. $debug = variable_get('domain_debug', 0);
  676. if ($debug && user_access('set domain access')) {
  677. if (!empty($node->subdomains)) {
  678. $output .= '<p><b>Subdomains</b></p><ul>';
  679. foreach ($node->subdomains as $name) {
  680. $output .= '<li>'. check_plain($name) .'</li>';
  681. }
  682. $output .= '</ul>';
  683. $node->content['subdomains'] = array('#value' => $output, '#weight' => 20);
  684. }
  685. if (!empty($node->editors)) {
  686. $output = '<p><b>Editors</b></p><ul>';
  687. foreach ($node->editors as $name) {
  688. $output .= '<li>'. check_plain($name) .'</li>';
  689. }
  690. $output .= '</ul>';
  691. $node->content['editors'] = array('#value' => $output, '#weight' => 21);
  692. }
  693. if (empty($output)) {
  694. $node->content['domain'] = array('#value' => t('This node is not assigned to a domain.'), '#weight' => 22);
  695. }
  696. }
  697. }
  698. break;
  699. case 'insert':
  700. case 'update':
  701. // Store these records in our own table as well.
  702. $grants = domain_node_access_records($node);
  703. _domain_write_records($node->nid, $grants);
  704. break;
  705. case 'delete':
  706. // Remove records from the {domain_access} table.
  707. db_query("DELETE FROM {domain_access} WHERE nid = %d", $node->nid);
  708. break;
  709. }
  710. }
  711. /**
  712. * Implement hook_node_grants.
  713. *
  714. * Informs the node access system what permissions the user has. By design
  715. * all users are in the realm defined by the currently active domain_id.
  716. */
  717. function domain_node_grants($account, $op) {
  718. global $_domain;
  719. // Do we need to use complex rules?
  720. $rules = variable_get('domain_access_rules', FALSE);
  721. // By design, all users can see content sent to all affiliates,
  722. // but the $_domain['site_grant'] can be set to FALSE.
  723. if ($op == 'view') {
  724. if ($_domain['site_grant']) {
  725. $grants['domain_site'][] = 0;
  726. if ($rules) {
  727. $grants['domain_site']['group'] = 'domain';
  728. }
  729. }
  730. // Grant based on active subdomain.
  731. $grants['domain_id'][] = $_domain['domain_id'];
  732. if ($rules) {
  733. $grants['domain_id']['group'] = 'domain';
  734. }
  735. // In special cases, we grant the ability to view all nodes. That is,
  736. // we simply get out of the way of other node_access rules.
  737. // We do this with the universal 'domain_all' grant.
  738. if ($op == 'view' && domain_grant_all()) {
  739. // If no other node access modules are present, return our grant.
  740. // Otherwise, we just step out of the way.
  741. if ($rules) {
  742. return array();
  743. }
  744. else {
  745. return array('domain_all' => array(0));
  746. }
  747. }
  748. }
  749. else {
  750. // Special permissions for editors
  751. $editors = variable_get('domain_editors', DOMAIN_EDITOR_RULE);
  752. if ($editors && user_access('edit domain nodes', $account)) {
  753. if (!empty($account->domain_user)) {
  754. foreach ($account->domain_user as $id) {
  755. if (abs($id) > 0) {
  756. if ($id > 0) {
  757. $grants['domain_editor'][] = $id;
  758. }
  759. else {
  760. $grants['domain_editor'][] = 0;
  761. }
  762. // Advanced rules let us access check unpublished nodes for editing.
  763. if ($rules) {
  764. $grants['domain_editor']['check'] = TRUE;
  765. }
  766. }
  767. }
  768. }
  769. }
  770. }
  771. // Let Domain Access module extensions act to override the defaults.
  772. static $_modules;
  773. if (!isset($_modules)) {
  774. $_modules = module_implements('domaingrants');
  775. }
  776. if (!empty($_modules)) {
  777. foreach ($_modules as $module) {
  778. // Cannot use module_invoke_all() since these are passed by reference.
  779. $function = $module .'_domaingrants';
  780. $function($grants, $account, $op);
  781. }
  782. }
  783. return $grants;
  784. }
  785. /**
  786. * Implement hook_node_access_records()
  787. *
  788. * Set permissions for a node to be written to the database. By design
  789. * if no options are selected, the node is assigned to the main site.
  790. */
  791. function domain_node_access_records($node) {
  792. if (domain_disabling()) {
  793. return;
  794. }
  795. // Define the $grants array.
  796. $grants = array();
  797. // If the form is hidden, we are passed the 'domains_raw' variable.
  798. // We need to append unique values from this variable to the existing
  799. // stored values. See the logic for 'view domain publshing' in domain_form_alter().
  800. if (is_array($node->domains_raw)) {
  801. if (!isset($node->domains)) {
  802. $node->domains = array();
  803. }
  804. foreach ($node->domains_raw as $value) {
  805. // Only add this if it is not present already.
  806. if (!in_array($value, $node->domains)) {
  807. $node->domains[$value] = $value;
  808. }
  809. }
  810. }
  811. // If set, grant access to the core site, otherwise
  812. // The grant must be explicitly given to a domain.
  813. if ($node->domain_site) {
  814. $grants[] = array(
  815. 'realm' => 'domain_site',
  816. 'gid' => 0,
  817. 'grant_view' => TRUE,
  818. 'grant_update' => FALSE,
  819. 'grant_delete' => FALSE,
  820. 'priority' => 0, // If this value is > 0, then other grants will not be recorded
  821. );
  822. }
  823. // Special permissions for editors, if activated.
  824. $editors = variable_get('domain_editors', DOMAIN_EDITOR_RULE);
  825. if (!empty($node->domains)) {
  826. foreach ($node->domains as $key => $value) {
  827. // We can't use a 0 value in an $options list, so convert -1 to 0.
  828. if (abs($value) > 0) {
  829. ($key == -1) ? $key = 0 : $key = $key;
  830. $grants[] = array(
  831. 'realm' => 'domain_id',
  832. 'gid' => $key,
  833. 'grant_view' => TRUE,
  834. 'grant_update' => FALSE,
  835. 'grant_delete' => FALSE,
  836. 'priority' => 0,
  837. );
  838. if ($editors) {
  839. $grants[] = array(
  840. 'realm' => 'domain_editor',
  841. 'gid' => $key,
  842. 'grant_view' => FALSE,
  843. 'grant_update' => TRUE,
  844. 'grant_delete' => TRUE,
  845. 'priority' => 0,
  846. );
  847. }
  848. }
  849. }
  850. }
  851. // At least one option must be present, and it is the default site
  852. // this prevents null values in the form.
  853. // If we are enabling the module for the first time, we set the
  854. // default domain of all existing nodes to the root domain.
  855. if (empty($grants)) {
  856. $grants[] = array(
  857. 'realm' => 'domain_id',
  858. 'gid' => 0,
  859. 'grant_view' => TRUE,
  860. 'grant_update' => FALSE,
  861. 'grant_delete' => FALSE,
  862. 'priority' => 0,
  863. );
  864. if ($editors) {
  865. $grants[] = array(
  866. 'realm' => 'domain_editor',
  867. 'gid' => 0,
  868. 'grant_view' => FALSE,
  869. 'grant_update' => TRUE,
  870. 'grant_delete' => TRUE,
  871. 'priority' => 0,
  872. );
  873. }
  874. }
  875. // Let Domain Access module extensions act to override the defaults.
  876. static $_modules;
  877. if (!isset($_modules)) {
  878. $_modules = module_implements('domainrecords');
  879. }
  880. if (!empty($_modules)) {
  881. foreach ($_modules as $module) {
  882. // Cannot use module_invoke_all() since these are passed by reference.
  883. $function = $module .'_domainrecords';
  884. $function($grants, $node);
  885. }
  886. }
  887. return $grants;
  888. }
  889. /**
  890. * Store node_access records in the {domain_access{} table.
  891. *
  892. * @param $nid
  893. * The node id being acted upon.
  894. * @param $grants
  895. * The grants passed by hook_node_access_records().
  896. */
  897. function _domain_write_records($nid, $grants = array()) {
  898. if ($nid > 0 && !empty($grants)) {
  899. db_query("DELETE FROM {domain_access} WHERE nid = %d", $nid);
  900. foreach ($grants as $grant) {
  901. db_query("INSERT INTO {domain_access} (nid, gid, realm) VALUES (%d, %d, '%s')", $nid, $grant['gid'], $grant['realm']);
  902. }
  903. }
  904. }
  905. /**
  906. * Upon enabling this module, store the default view grant
  907. * in the {node_access} table.
  908. * @see domain_grant_all()
  909. */
  910. function domain_enable() {
  911. domain_enabling(TRUE);
  912. // Thanks to the new way that batch processing of node grants is handled, we have to
  913. // manually define our records if none are present.
  914. $count = db_result(db_query("SELECT COUNT(*) FROM {domain_access}"));
  915. if ($count == 0) {
  916. $rule = variable_get('domain_behavior', DOMAIN_INSTALL_RULE);
  917. $edit = variable_get('domain_editors', DOMAIN_EDITOR_RULE);
  918. $site = DOMAIN_SITE_GRANT;
  919. $nids = db_query("SELECT nid FROM {node}");
  920. while ($nid = db_fetch_object($nids)) {
  921. if (!empty($site)) {
  922. db_query("INSERT INTO {domain_access} (nid, gid, realm) VALUES (%d, %d, '%s')", $nid->nid, 0, 'domain_site');
  923. }
  924. if (!empty($rule)) {
  925. // By design, all nodes are assigned to the master domain.
  926. db_query("INSERT INTO {domain_access} (nid, gid, realm) VALUES (%d, %d, '%s')", $nid->nid, 0, 'domain_id');
  927. // Editor rules only apply is nodes are assigned to a domain.
  928. if (!empty($edit)) {
  929. variable_set('domain_editors', TRUE);
  930. db_query("INSERT INTO {domain_access} (nid, gid, realm) VALUES (%d, %d, '%s')", $nid->nid, 0, 'domain_editor');
  931. }
  932. }
  933. }
  934. }
  935. // Rebuild the node access table with our rules.
  936. node_access_rebuild();
  937. // Set the default 'domain_all' grant for special pages.
  938. domain_set_default_grant();
  939. }
  940. /**
  941. * Ensure that the 'domain_all' grant is present.
  942. */
  943. function domain_set_default_grant() {
  944. $check = db_result(db_query("SELECT COUNT(nid) FROM {node_access} WHERE realm = 'domain_all' AND gid = 0"));
  945. if (!$check) {
  946. db_query("INSERT INTO {node_access} VALUES (0, 0, 'domain_all', 1, 0, 0)");
  947. }
  948. }
  949. /**
  950. * Writes the default grants when the module is first enabled.
  951. */
  952. function domain_enabling($set = NULL) {
  953. static $enabling = FALSE;
  954. if ($set !== NULL) {
  955. $enabling = $set;
  956. }
  957. return $enabling;
  958. }
  959. /**
  960. * Implement hook_disable()
  961. */
  962. function domain_disable() {
  963. domain_disabling(TRUE);
  964. // Rebuild the node access table. Other modules have to fend for themselves here.
  965. node_access_rebuild();
  966. // If {node_access} just contains the 'all' grant, then reset it to default.
  967. $result = db_result(db_query("SELECT COUNT(realm) FROM {node_access} WHERE realm <> 'all'"));
  968. if ($result == 0) {
  969. db_query("DELETE FROM {node_access}");
  970. db_query("INSERT INTO {node_access} VALUES (0, 0, 'all', 1, 0, 0)");
  971. }
  972. }
  973. /**
  974. * Simple function to make sure we don't respond with grants when disabling ourselves.
  975. */
  976. function domain_disabling($set = NULL) {
  977. static $disabling = FALSE;
  978. if ($set !== NULL) {
  979. $disabling = $set;
  980. }
  981. return $disabling;
  982. }
  983. /**
  984. * Implement hook_form_alter()
  985. *
  986. * This function is crucial, as it appends our node access elements to the node edit form.
  987. * For users without the "set domain access" permission, this happens silently.
  988. */
  989. function domain_form_alter($form_id, &$form) {
  990. // There are forms that we never want to alter, and they are passed here.
  991. $forms = module_invoke_all('domainignore');
  992. if (in_array($form_id, $forms)) {
  993. return;
  994. }
  995. // Set a message if we are on an admin page.
  996. domain_warning_check($form_id);
  997. // If SEO is turned on, then form actions need to be absolute paths
  998. // to the currently active domain. See http://drupal.org/node/196217.
  999. $seo = variable_get('domain_seo', 0);
  1000. if ($seo && isset($form['#action'])) {
  1001. global $_domain;
  1002. $action = parse_url($form['#action']);
  1003. if ($action['query']) {
  1004. $action['path'] .= '?';
  1005. }
  1006. // We cannot reset this if it has already been set by another module.
  1007. // See http://drupal.org/node/306551
  1008. if (empty($action['host'])) {
  1009. $form['#action'] = check_url($_domain['scheme'] .'://'. $_domain['subdomain'] . $action['path'] . $action['query']);
  1010. }
  1011. }
  1012. // Save our settings for the default domain.
  1013. if ($form_id == 'system_site_information_settings' && arg(2) != 'domain') {
  1014. $form['#submit']['domain_form_sitename_submit'] = array();
  1015. }
  1016. // Apply to all node editing forms, but make sure we are not on the CCK field configuration form.
  1017. if ($form['#id'] == 'node-form' && !$form['#node']->cck_dummy_node_form) {
  1018. global $_domain, $user;
  1019. // By default, the requesting domain is assigned.
  1020. $default = array($_domain['domain_id']);
  1021. // How is core content handled for this site?
  1022. $behavior = variable_get('domain_behavior', DOMAIN_INSTALL_RULE);
  1023. if ($_domain['domain_id'] == 0) {
  1024. $default[] = -1;
  1025. }
  1026. // Some options will be passed as hidden values, we need to run some checks on those.
  1027. if ($form['#node']->nid) {
  1028. $raw = $form['#node']->domains;
  1029. }
  1030. else {
  1031. $raw = $default;
  1032. }
  1033. $options = array();
  1034. foreach (domain_domains() as $data) {
  1035. // Cannot pass zero in checkboxes.
  1036. ($data['domain_id'] == 0) ? $key = -1 : $key = $data['domain_id'];
  1037. // The domain must be valid.
  1038. if ($data['valid'] || user_access('administer domains')) {
  1039. $options[$key] = check_plain($data['sitename']);
  1040. }
  1041. }
  1042. // If the user is a site admin, show the form, otherwise pass it silently.
  1043. if (user_access('set domain access')) {
  1044. $form['domain'] = array(
  1045. '#type' => 'fieldset',
  1046. '#title' => t('Domain access options'),
  1047. '#collapsible' => TRUE,
  1048. '#collapsed' => FALSE
  1049. );
  1050. $form['domain']['domain_site'] = array(
  1051. '#type' => 'checkbox',
  1052. '#prefix' => t('<p><b>Publishing options:</b>'),
  1053. '#suffix' => '</p>',
  1054. '#title' => t('Send to all affiliates'),
  1055. '#required' => FALSE,
  1056. '#description' => t('Select if this content can be shown to all affiliates. This setting will override the options below.'),
  1057. '#default_value' => (isset($form['#node']->nid)) ? $form['#node']->domain_site : variable_get('domain_node_'. $form['#node']->type, $behavior),
  1058. );
  1059. $form['domain']['domains'] = array(
  1060. '#type' => 'checkboxes',
  1061. '#title' => t('Publish to'),
  1062. '#options' => $options,
  1063. '#required' => TRUE,
  1064. '#description' => t('Select which affiliates can access this content.'),
  1065. '#default_value' => (isset($form['#node']->nid)) ? $form['#node']->domains : $default,
  1066. );
  1067. }
  1068. // If the user has limited permissions, show that form or obey the settings.
  1069. else {
  1070. if (user_access('view domain publishing')) {
  1071. $action = variable_get('domain_options', 0);
  1072. $user_domains = array();
  1073. $default_options = array();
  1074. if (!isset($user->domain_user)) {
  1075. $user->domain_user = array();
  1076. }
  1077. foreach ($user->domain_user as $key => $value) {
  1078. if (abs($value) > 0) {
  1079. $user_domains[] = $value;
  1080. }
  1081. }
  1082. $first_domain = current($user_domains);
  1083. $user_options = array();
  1084. foreach ($options as $key => $value) {
  1085. if (in_array($key, $user_domains)) {
  1086. $user_options[$key] = $value;
  1087. }
  1088. }
  1089. // Raw data checks for published nodes.
  1090. foreach ($raw as $key => $value) {
  1091. if (in_array($value, $user_domains)) {
  1092. $default_options[] = $value;
  1093. }
  1094. // This is only used in case 3, below. It means that some options
  1095. // are present that the user cannot access but that must be preserved.
  1096. else {
  1097. $raw_options[] = $value;
  1098. }
  1099. }
  1100. // Act on the behavior desired by the site admin.
  1101. switch ($action) {
  1102. // 1 == go to the default domain.
  1103. case 1:
  1104. $root = domain_default();
  1105. if ($root['domain_id'] != $_domain['domain_id']) {
  1106. domain_goto($root);
  1107. }
  1108. break;
  1109. // 2 == go to the user's assigned domain.
  1110. case 2:
  1111. $domain = domain_lookup($first_domain);
  1112. // If the domain is invalid, go to the primary domain.
  1113. if ($domain == -1 || $domain['valid'] == 0) {
  1114. domain_goto(domain_default());
  1115. }
  1116. else if ($domain['domain_id'] != $_domain['domain_id']) {
  1117. domain_goto($domain);
  1118. }
  1119. break;
  1120. // 3 == show checkboxes of available domains.
  1121. case 3:
  1122. // If the user has no available domains, then they cannot post.
  1123. if (empty($user_options)) {
  1124. $form = array();
  1125. return drupal_access_denied();
  1126. }
  1127. $form['domain'] = array(
  1128. '#type' => 'fieldset',
  1129. '#title' => t('Affiliate publishing options'),
  1130. '#collapsible' => TRUE,
  1131. '#collapsed' => FALSE
  1132. );
  1133. // We must preserve publishing options that the user cannot access, but only for
  1134. // existing nodes.
  1135. if ($form['#node']->nid) {
  1136. $raw = $raw_options;
  1137. }
  1138. else {
  1139. $raw = array();
  1140. }
  1141. // If the raw options are being passed, then no input is technically required.
  1142. (empty($raw)) ? $required = TRUE : $required = FALSE;
  1143. $form['domain']['domains'] = array(
  1144. '#type' => 'checkboxes',
  1145. '#title' => t('Publish to'),
  1146. '#options' => $user_options,
  1147. '#required' => $required,
  1148. '#description' => t('Select which affiliates can access this content.'),
  1149. '#default_value' => (isset($form['#node']->nid)) ? $form['#node']->domains : $default_options,
  1150. );
  1151. // Show the options that cannot be changed.
  1152. $list = array();
  1153. if ($form['#node']->domain_site) {
  1154. $list[]['data'] = t('All affiliates');
  1155. }
  1156. if (!empty($raw)) {
  1157. foreach ($raw as $did) {
  1158. ($did == -1) ? $id = 0 : $id = $did;
  1159. $raw_domains = domain_lookup($id);
  1160. $list[]['data'] = check_plain($raw_domains['sitename']);
  1161. }
  1162. }
  1163. if (!empty($list)) {
  1164. $form['domain']['domains_notes'] = array(
  1165. '#value' => '<label><b>'. t('Publishing status:') .'</b></label>'. theme('item_list', $list) .'<div class="description">'. t('This content has also been published to these affiliates.') .'</div>',
  1166. );
  1167. }
  1168. break;
  1169. }
  1170. }
  1171. // These form elements are hidden from non-privileged users, by design.
  1172. $form['domain_site'] = array(
  1173. '#type' => 'value',
  1174. '#value' => (isset($form['#node']->nid)) ? $form['#node']->domain_site : variable_get('domain_node_'. $form['#node']->type, $behavior),
  1175. );
  1176. // Domains that have been assigned and cannot be changed.
  1177. $form['domains_raw'] = array(
  1178. '#type' => 'value',
  1179. '#value' => $raw,
  1180. );
  1181. }
  1182. // THIS SECTION BREAKS CCK if we don't check for cck_dummy_node_form! See http://drupal.org/node/186624
  1183. // and note the !$form['#node']->cck_dummy_node_form in the IF check at the top of the function.
  1184. // Some editors cannot administer nodes, so we have to add these form elements.
  1185. if (variable_get('domain_editors', DOMAIN_EDITOR_RULE) == 1 && user_access('edit domain nodes')) {
  1186. $access = variable_get('domain_form_elements', array('options', 'delete', 'comment_settings', 'path'));
  1187. foreach ($access as $item) {
  1188. $form[$item]['#access'] = TRUE;
  1189. }
  1190. }
  1191. }
  1192. }
  1193. /**
  1194. * Update the default domain's sitename.
  1195. */
  1196. function domain_form_sitename_submit($form_id, $form_values) {
  1197. variable_set('domain_sitename', $form_values['site_name']);
  1198. drupal_set_message(t('Primary domain settings updated.'));
  1199. }
  1200. /**
  1201. * Activate the hidden grant for searches.
  1202. *
  1203. * @param $reset
  1204. * A boolean flag indicating whether to reset the static variable or not.
  1205. * @return
  1206. * TRUE or FALSE, depending on whether the grants should be executed for this page.
  1207. */
  1208. function domain_grant_all($reset= FALSE) {
  1209. static $grant;
  1210. if (!isset($grant) || $reset) {
  1211. $grant = FALSE;
  1212. // Search is the easy case, so we check it first.
  1213. if (variable_get('domain_search', 0) && arg(0) == 'search') {
  1214. $grant = TRUE;
  1215. }
  1216. // On cron runs, we normally have to disable Domain Access. See http://drupal.org/node/197488.
  1217. if (!$grant && variable_get('domain_cron_rule', 1)) {
  1218. $ref = explode('/', request_uri());
  1219. $script = array_pop($ref);
  1220. if ($script == 'cron.php') {
  1221. $grant = TRUE;
  1222. }
  1223. }
  1224. if (!$grant) {
  1225. // We check the paths registered by the special pages setting.
  1226. $pages = variable_get('domain_grant_all', "user/*/track");
  1227. $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($pages, '/')) .')$/';
  1228. // Compare with the internal and path alias (if any).
  1229. $page_match = preg_match($regexp, $_GET['q']);
  1230. if (!$page_match) {
  1231. $path = drupal_get_path_alias($_GET['q']);
  1232. if ($path != $_GET['q']) {
  1233. $page_match = preg_match($regexp, $path);
  1234. }
  1235. }
  1236. if ($page_match) {
  1237. $grant = TRUE;
  1238. }
  1239. }
  1240. }
  1241. return $grant;
  1242. }
  1243. /**
  1244. * Implement hook_domaininstall()
  1245. */
  1246. function domain_domaininstall() {
  1247. // Check to see if the hook_url_alter() patch is installed.
  1248. if (url('domain_access_test_path') != url('domain_access_path_test')) {
  1249. drupal_set_message(t('The <em>custom_url_rewrite_outbound()</em> patch is not installed. Some features are not available. See the Patches to Drupal Core section of <a href="!url">INSTALL.txt</a>', array('!url' => base_path() . drupal_get_path('module', 'domain') .'/INSTALL.txt')));
  1250. }
  1251. }
  1252. /**
  1253. * Implement hook_domainupdate()
  1254. */
  1255. function domain_domainupdate($op, $domain = array(), $edit = array()) {
  1256. switch ($op) {
  1257. case 'delete':
  1258. if ($domain != -1) {
  1259. // Remove domain-specific entries from the {node_access} table and clear the cache.
  1260. db_query("DELETE FROM {node_access} WHERE realm = 'domain_id' AND gid = %d", $domain['domain_id']);
  1261. db_query("DELETE FROM {node_access} WHERE realm = 'domain_editor' AND gid = %d", $domain['domain_id']);
  1262. db_query("DELETE FROM {domain_access} WHERE realm = 'domain_id' AND gid = %d", $domain['domain_id']);
  1263. db_query("DELETE FROM {domain_access} WHERE realm = 'domain_editor' AND gid = %d", $domain['domain_id']);
  1264. }
  1265. break;
  1266. }
  1267. // In all cases, we need to force a menu rebuild, which also clears the cache.
  1268. menu_rebuild();
  1269. }
  1270. /**
  1271. * Implement hook_domainbatch()
  1272. */
  1273. function domain_domainbatch() {
  1274. // Change all the domain names at once.
  1275. $batch = array();
  1276. $batch['subdomain'] = array(
  1277. '#form' => array(
  1278. '#title' => t('Domains'),
  1279. '#type' => 'textfield',
  1280. '#size' => 40,
  1281. '#maxlength' => 80,
  1282. '#description' => t('Enter the host value of the domain. No http:// or slashes.'),
  1283. '#required' => TRUE,
  1284. ),
  1285. '#domain_action' => 'domain',
  1286. '#meta_description' => t('Edit all domain values.'),
  1287. '#variable' => 'domain_root',
  1288. '#validate' => 'domain_batch_validate',
  1289. '#data_type' => 'string',
  1290. '#weight' => -10,
  1291. );
  1292. //Change all the sitenames at once.
  1293. $batch['sitename'] = array(
  1294. '#form' => array(
  1295. '#title' => t('Site names'),
  1296. '#type' => 'textfield',
  1297. '#size' => 40,
  1298. '#maxlength' => 80,
  1299. '#description' => t('The site name to display for this domain.'),
  1300. '#required' => TRUE,
  1301. ),
  1302. '#domain_action' => 'domain',
  1303. '#meta_description' => t('Edit all domain site names.'),
  1304. '#variable' => 'domain_sitename',
  1305. '#validate' => 'domain_batch_validate',
  1306. '#data_type' => 'string',
  1307. '#weight' => -10,
  1308. );
  1309. // Change all the schemes at once.
  1310. $batch['scheme'] = array(
  1311. '#form' => array(
  1312. '#title' => t('URL schemes'),
  1313. '#type' => 'radios',
  1314. '#options' => array('http' => 'http://', 'https' => 'https://'),
  1315. '#description' => t('The URL scheme for accessing this domain.')
  1316. ),
  1317. '#domain_action' => 'domain',
  1318. '#meta_description' => t('Edit all domain URL schemes.'),
  1319. '#system_default' => variable_get('domain_scheme', 'http://'),
  1320. '#variable' => 'domain_scheme',
  1321. '#data_type' => 'string',
  1322. '#weight' => -10,
  1323. );
  1324. // Change all the valid flags at once.
  1325. $batch['valid'] = array(
  1326. '#form' => array(
  1327. '#title' => t('Valid domains'),
  1328. '#type' => 'radios',
  1329. '#options' => array(1 => t('Active'), 0 => t('Inactive')),
  1330. '#description' => t('Allows users to access this domain.')
  1331. ),
  1332. '#domain_action' => 'domain',
  1333. '#meta_description' => t('Edit all domain status flags.'),
  1334. '#system_default' => 1,
  1335. '#data_type' => 'integer',
  1336. '#weight' => -10,
  1337. );
  1338. return $batch;
  1339. }
  1340. /**
  1341. * Validate handler for hook_domainbatch()
  1342. */
  1343. function domain_batch_validate($form_values) {
  1344. $case = $form_values['variable'];
  1345. $batch = $form_values['domain_batch'];
  1346. switch ($case) {
  1347. case 'domain_root':
  1348. foreach ($batch as $key => $value) {
  1349. $subdomain = strtolower(urlencode($value));
  1350. $check = db_result(db_query("SELECT COUNT(domain_id) FROM {domain} WHERE subdomain = '%s' AND domain_id <> %d", $value, $key));
  1351. if ($check > 0 || ($key > 0 && $value == variable_get('domain_root', ''))) {
  1352. form_set_error('domain_batch', t('Each domain value must be unique.'));
  1353. }
  1354. }
  1355. break;
  1356. case 'domain_sitename':
  1357. foreach ($batch as $key => $value) {
  1358. $check = db_result(db_query("SELECT COUNT(domain_id) FROM {domain} WHERE sitename = '%s' AND domain_id <> %d", $value, $key));
  1359. if ($check > 0 || ($key > 0 && $value == variable_get('domain_sitename', 'Drupal'))) {
  1360. form_set_error('domain_batch', t('Each site name value must be unique.'));
  1361. }
  1362. }
  1363. break;
  1364. }
  1365. # exit;
  1366. }
  1367. /**
  1368. * Implement hook_simpletest()
  1369. */
  1370. function domain_simpletest() {
  1371. $module_name = 'domain';
  1372. $dir = drupal_get_path('module', $module_name) .'/tests';
  1373. $tests = file_scan_directory($dir, '\.test$');
  1374. return array_keys($tests);
  1375. }
  1376. /**
  1377. * Sets a message to the site admin.
  1378. *
  1379. * If our module changes $conf settings, they may be reflected
  1380. * on admin pages when we don't want them to be.
  1381. */
  1382. function domain_warning_check($form_id) {
  1383. static $_warning;
  1384. // If $_POST is set, we are submitting the form and should not set a message.
  1385. if (!$_POST && empty($_warning)) {
  1386. global $_domain;
  1387. // Add the list of forms
  1388. $forms = array();
  1389. $forms = module_invoke_all('domainwarnings');
  1390. if (arg(2) != 'domain' && in_array($form_id, $forms)) {
  1391. $default = domain_default();
  1392. if ($_domain['domain_id'] != $default['domain_id']) {
  1393. $_path = domain_get_uri($default);
  1394. drupal_set_message(t('You are viewing #this. This form may need to be entered from <a href="!url">!domain</a>', array('#this' => $_domain['subdomain'], '!url' => $_path, '!domain' => $default['subdomain'])));
  1395. }
  1396. }
  1397. $_warning = TRUE;
  1398. }
  1399. }
  1400. /**
  1401. * Implement hook_db_rewrite_sql().
  1402. *
  1403. * If enabled, force admins to use Domain Access rules.
  1404. */
  1405. function domain_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
  1406. global $_domain;
  1407. $admin_force = variable_get('domain_force_admin', FALSE);
  1408. // In any of the following cases, do not enforce any rules.
  1409. if (!$admin_force || $primary_field != 'nid' || !user_access('administer nodes') || domain_grant_all()) {
  1410. return;
  1411. }
  1412. $domain_id = (int) $_domain['domain_id'];
  1413. $return = array(
  1414. 'join' => "INNER JOIN {domain_access} da_admin ON $primary_table.nid = da_admin.nid",
  1415. 'where' => "(da_admin.gid = 0 AND da_admin.realm = 'domain_site') OR (da_admin.gid = $domain_id AND da_admin.realm = 'domain_id')",
  1416. );
  1417. return $return;
  1418. }
  1419. /**
  1420. * Implement hook_node_access_explain for devel.module
  1421. */
  1422. function domain_node_access_explain($row) {
  1423. global $_domain;
  1424. $active = $_domain['subdomain'];
  1425. $domain = domain_lookup($row->gid);
  1426. $return = t('Domain Access -- ');
  1427. switch ($row->realm) {
  1428. case 'domain_all':
  1429. if (domain_grant_all() == TRUE) {
  1430. $return .= t('True: Allows content from all domains to be shown.');
  1431. }
  1432. else {
  1433. $return .= t('False: Only allows content from the active domain (%domain) or from all affiliates.', array('%domain' => $active));
  1434. }
  1435. break;
  1436. case 'domain_site':
  1437. $return .= t('Viewable on all affiliate sites.');
  1438. break;
  1439. case 'domain_id':
  1440. $return .= t('Viewable on %domain.', array('%domain' => $domain['subdomain']));
  1441. break;
  1442. case 'domain_editor':
  1443. $return .= t('Editable by %domain editors.', array('%domain' => $domain['subdomain']));
  1444. break;
  1445. default:
  1446. // This is not our grant, do not return anything.
  1447. $return = NULL;
  1448. break;
  1449. }
  1450. return $return;
  1451. }
  1452. /**
  1453. * Validates a domain string.
  1454. * @param string $subdomain
  1455. * The string to check for domain validity
  1456. * @return array
  1457. * List of error messages or empty array.
  1458. */
  1459. function domain_validate($subdomain) {
  1460. $error_list = array();
  1461. // Validate the domains format generically for now.
  1462. $error = domain_valid_domain($subdomain);
  1463. if (!empty($error)) {
  1464. $error_list[] = $error;
  1465. }
  1466. // Make sure domain is unique
  1467. if (!domain_unique_domain($subdomain)) {
  1468. $error_list[] = t('The domain value must be unique.');
  1469. }
  1470. return $error_list;
  1471. }
  1472. /**
  1473. * Validate the domain against all correctable errors.
  1474. *
  1475. * Note that we decided not to check for valid TLDs here.
  1476. *
  1477. * @param $subdomain
  1478. * Domain string to check.
  1479. * @return string
  1480. * Empty if valid, error message on invalid.
  1481. */
  1482. function domain_valid_domain($subdomain) {
  1483. $error_list = array();
  1484. // Check for at least one dot.
  1485. if (substr_count($subdomain, '.') == 0) {
  1486. $error_list[] = t('At least one dot (.) is required.');
  1487. }
  1488. // Check for one colon only.
  1489. if (substr_count($subdomain, ':') > 1) {
  1490. $error_list[] = t('Only one colon (:) is allowed.');
  1491. }
  1492. // If a colon, make sure it is only followed by numbers.
  1493. else if (substr_count($subdomain, ':') == 1) {
  1494. $parts = explode(':', $subdomain);
  1495. $port = (int) $parts[1];
  1496. if (strcmp($port, $parts[1])) {
  1497. $error_list[] = t('The port protocol must be an integer.');
  1498. }
  1499. }
  1500. // The domain cannot begin or end with a period.
  1501. if (substr($subdomain, 0, 1) == '.') {
  1502. $error_list[] = t('The domain must not begin with a dot (.)');
  1503. }
  1504. // The domain cannot begin or end with a period.
  1505. if (substr($subdomain, -1) == '.') {
  1506. $error_list[] = t('The domain must not end with a dot (.)');
  1507. }
  1508. // Check for valid characters
  1509. $pattern = '/^[a-z0-9\.\-:]*$/i';
  1510. if (!preg_match($pattern, $subdomain)) {
  1511. $error_list[] = t('Only alphanumeric characters, dashes, and a colon are allowed.');
  1512. }
  1513. if (!empty($error_list)) {
  1514. return t('The domain string is invalid:') . theme('item_list', $error_list);
  1515. }
  1516. }
  1517. /**
  1518. * Validate the domain against existing domains.
  1519. *
  1520. * @param $subdomain
  1521. * Domain string to check
  1522. * @return bool
  1523. * TRUE if unique; FALSE if duplicate.
  1524. */
  1525. function domain_unique_domain($subdomain) {
  1526. $count = db_result(db_query("SELECT COUNT(domain_id) FROM {domain} WHERE subdomain = '%s'", $subdomain));
  1527. return !(bool) $count;
  1528. }

Related topics