email_required.module 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. <?php
  2. /**
  3. * Implements hook_menu().
  4. */
  5. function email_required_menu() {
  6. $items = array();
  7. $items['email/verify'] = array(
  8. 'title' => 'Email verifications',
  9. 'description' => 'Form to submit for email verification',
  10. 'page callback' => 'drupal_get_form',
  11. 'page arguments' => array('email_required_verification_form'),
  12. 'access callback' => 'email_required_verification_form_access',
  13. 'file' => 'email_required.pages.inc',
  14. 'type' => MENU_CALLBACK,
  15. );
  16. $items['email/verify/%user/%'] = array(
  17. 'title' => 'Email verification',
  18. 'description' => 'Path to verify your email address',
  19. 'page callback' => 'email_required_verification_page',
  20. 'page arguments' => array(2, 3),
  21. 'access callback' => 'email_required_verification_page_access',
  22. 'access arguments' => array(2, 3),
  23. 'file' => 'email_required.pages.inc',
  24. 'type' => MENU_CALLBACK,
  25. );
  26. $items['admin/config/people/email-required'] = array(
  27. 'title' => 'Email verification',
  28. 'description' => 'Configure when users will need to verify their email address',
  29. 'page callback' => 'drupal_get_form',
  30. 'page arguments' => array('email_required_admin_settings'),
  31. 'access arguments' => array('administer email required'),
  32. 'file' => 'email_required.admin.inc',
  33. 'type' => MENU_NORMAL_ITEM,
  34. );
  35. return $items;
  36. }
  37. /**
  38. * Implements hook_init().
  39. */
  40. function email_required_init() {
  41. // If authenticated
  42. if (user_is_logged_in()) {
  43. // See if we have paths to enforce a required email
  44. if ($paths = variable_get('email_required_paths', NULL)) {
  45. // Determine the current path
  46. $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
  47. // See if we have a match
  48. if (drupal_match_path($path, $paths)) {
  49. // See if the user has to validate their email
  50. if (!email_required_user_is_validated()) {
  51. // See if we can capture the referred page
  52. $options = array();
  53. if (isset($_SERVER['HTTP_REFERER']) && $referer = $_SERVER['HTTP_REFERER']) {
  54. $referer = str_replace(url('<front>', array('absolute' => TRUE)), '', $referer);
  55. $options['query'] = array('destination' => $referer);
  56. }
  57. // Redirect to the verify form
  58. drupal_goto('email/verify', $options);
  59. }
  60. }
  61. }
  62. }
  63. }
  64. /**
  65. * Implements hook_mail().
  66. */
  67. function email_required_mail($key, &$message, $params) {
  68. global $user;
  69. // Get email text
  70. $text = _email_required_email_text();
  71. // Inject a verification link
  72. $text['body'] = str_replace('!link', email_required_generate_link($user, TRUE), $text['body']);
  73. // Attach to the message, and replace tokens
  74. $message['subject'] = token_replace($text['subject'], array('user' => $user));
  75. $message['body'] = array(token_replace($text['body'], array('user' => $user)));
  76. }
  77. /**
  78. * Implements hook_permission().
  79. */
  80. function email_required_permission() {
  81. return array(
  82. 'administer email required' => array(
  83. 'title' => t('Administer email required'),
  84. 'description' => t('Configure the settings for this module.'),
  85. ),
  86. 'bypass email required' => array(
  87. 'title' => t('Bypass email verification'),
  88. 'description' => t('These users will not have to verify their email. Anonyous users will never have to.'),
  89. ),
  90. );
  91. }
  92. /**
  93. * Implements hook_user_presave().
  94. */
  95. function email_required_user_presave(&$edit, $account, $category) {
  96. // See if the user exists yet
  97. if ($account->uid) {
  98. // See if the email address has changed
  99. if (strtolower($edit['mail']) != strtolower($account->mail)) {
  100. // Mark this user as no longer having a verified email address
  101. email_required_delete_hash($account);
  102. }
  103. }
  104. }
  105. /**
  106. * Generate a URL to verify an email address
  107. *
  108. * @param $user
  109. * A user object or uid
  110. * @param $absolute
  111. * TRUE if the link should be absolute.
  112. * @return
  113. * A link to verify an email address, or FALSE if one cannot be made.
  114. */
  115. function email_required_generate_link($user = NULL, $absolute = FALSE) {
  116. // Get the uid
  117. $uid = _email_required_get_uid($user);
  118. // Get the hash string
  119. if ($hash = email_required_load_hash($user, TRUE)) {
  120. // Provide the link
  121. return url("email/verify/{$uid}/{$hash->hash}", array('absolute' => $absolute));
  122. }
  123. return FALSE;
  124. }
  125. /**
  126. * Delete a hash entry for a given user
  127. *
  128. * @param $user
  129. * A user object or uid
  130. */
  131. function email_required_delete_hash($user = NULL) {
  132. // Delete the hash entry
  133. db_delete('email_required')
  134. ->condition('uid', _email_required_get_uid($user))
  135. ->execute();
  136. }
  137. /**
  138. * Create a hash entry for a given user
  139. *
  140. * This will delete any existing entries so call with caution
  141. *
  142. * @param $user
  143. * A user object
  144. * @return
  145. * A hash object
  146. */
  147. function email_required_create_hash($user = NULL) {
  148. if (!$user) {
  149. global $user;
  150. }
  151. // Create the hash object
  152. $hash = array(
  153. 'uid' => _email_required_get_uid($user),
  154. 'hash' => _email_required_hash($user),
  155. 'created' => REQUEST_TIME,
  156. 'verified' => 0,
  157. );
  158. // Delete any existing hashes for this user
  159. email_required_delete_hash($user);
  160. // Insert it
  161. db_insert('email_required')
  162. ->fields($hash)
  163. ->execute();
  164. return $hash;
  165. }
  166. /**
  167. * Validate a user's hash
  168. *
  169. * @param $user
  170. * A user object or uid
  171. */
  172. function email_required_validate_hash($user = NULL) {
  173. // Delete the hash entry
  174. db_update('email_required')
  175. ->fields(array('verified' => REQUEST_TIME))
  176. ->condition('uid', _email_required_get_uid($user))
  177. ->execute();
  178. }
  179. /**
  180. * Get a user's hash object
  181. *
  182. * @param $user
  183. * A user object or uid
  184. * @param $reset
  185. * TRUE if the static cache should be skipped, otherwise FALSE.
  186. * @return
  187. * A hash object
  188. */
  189. function email_required_load_hash($user = NULL, $reset = FALSE) {
  190. static $hashes = array();
  191. // Determine the uid
  192. $uid = _email_required_get_uid($user);
  193. // Check the cache
  194. if ($reset || !isset($hashes[$uid])) {
  195. // Fetch the hash entry
  196. $hashes[$uid] =
  197. db_select('email_required', 'e')
  198. ->fields('e', array('uid', 'hash', 'created', 'verified'))
  199. ->condition('uid', $uid)
  200. ->execute()
  201. ->fetchObject();
  202. }
  203. return $hashes[$uid];
  204. }
  205. /**
  206. * Determine if a given user has validated their email
  207. *
  208. * @param $user
  209. * A user object or uid
  210. * @param $admin
  211. * TRUE if users with adequate permissions will be considered
  212. * validated regardless
  213. * @return
  214. * TRUE if the user is validated, otherwise FALSE.
  215. */
  216. function email_required_user_is_validated($user = NULL, $admin = TRUE) {
  217. static $validated = array();
  218. // Determine the uid
  219. $uid = _email_required_get_uid($user);
  220. // Generate a cache key
  221. $key = $uid . ($admin ? ':admins' : '');
  222. // Check the cache
  223. if (!isset($validated[$key])) {
  224. // Assume false
  225. $validated[$key] = FALSE;
  226. // Check higher permissions first, if desired
  227. if ($admin && (user_access('administer email required') || user_access('bypass email required'))) {
  228. $validated[$key] = TRUE;
  229. }
  230. // Load the hash to check
  231. else if ($hash = email_required_load_hash($user)) {
  232. if ($hash->verified) {
  233. $validated[$key] = TRUE;
  234. }
  235. }
  236. // Allow modules to alter this
  237. drupal_alter('email_required_validated', $user, $admin, $validated[$key]);
  238. }
  239. return $validated[$key];
  240. }
  241. /**
  242. * Access callback for the verification form
  243. */
  244. function email_required_verification_form_access() {
  245. global $user;
  246. // No anonymous allowed
  247. if (!$user->uid) {
  248. return FALSE;
  249. }
  250. return email_required_user_is_validated($user) ? FALSE : TRUE;
  251. }
  252. /**
  253. * Access callback for the verification page
  254. *
  255. * @param $account
  256. * A user object specified in the link
  257. * @param $string
  258. * The hash string on the URL
  259. */
  260. function email_required_verification_page_access($account, $string) {
  261. global $user;
  262. // If the user is logged in, they can only verify themselves
  263. if ($user->uid && ($account->uid != $user->uid)) {
  264. return FALSE;
  265. }
  266. // We'll check for the existance of a hash, and the validity of it
  267. // in the page callback, because we don't want a 403 if the hash
  268. // has been purged
  269. return TRUE;
  270. }
  271. /**
  272. * Wrapper for user_pass_rehash()
  273. *
  274. * Generate a a hash that will be used in the verification URL
  275. *
  276. * @param $user
  277. * A user object or ID
  278. * @return
  279. * A hash
  280. */
  281. function _email_required_hash($user) {
  282. return user_pass_rehash($user->pass, REQUEST_TIME, $user->name);
  283. }
  284. /**
  285. * Helper function to determine the user id to use
  286. *
  287. * @param $user
  288. * A user object, or user ID, or NULL if you want to use
  289. * the current user.
  290. * @return
  291. * A user ID
  292. */
  293. function _email_required_get_uid($user = NULL) {
  294. if (!$user) {
  295. global $user;
  296. }
  297. return is_object($user) ? $user->uid : $user;
  298. }
  299. /**
  300. * Helper function to return email strings
  301. *
  302. * @return
  303. * An array containing the 'subject' and 'body for the
  304. * verification email
  305. */
  306. function _email_required_email_text() {
  307. // Load the defaults
  308. $text = array(
  309. 'subject' => variable_get('email_required_subject', NULL),
  310. 'body' => variable_get('email_required_body', NULL),
  311. );
  312. // See if we need a subject
  313. if (!$text['subject']) {
  314. $text['subject'] = '[[site:name]] ' . t('Verify your email address');
  315. }
  316. // See if we need a body
  317. if (!$text['body']) {
  318. $text['body'] = '[user:name],' . "\n\n";
  319. $text['body'] .= t('You have requested to have your email address validated at !sitename.', array('!sitename' => '[site:name]')) . "\n\n";
  320. $text['body'] .= t('Click the link below to validate your email address:') . "\n\n";
  321. $text['body'] .= '!link' . "\n\n";
  322. $text['body'] .= t('You will never have to validate your email address again, unless you change it.') . "\n\n";
  323. $text['body'] .= '- [site:name]';
  324. }
  325. return $text;
  326. }