Elgg  Version 1.12
notification.php
Go to the documentation of this file.
1 <?php
61 function elgg_register_notification_event($object_type, $object_subtype, array $actions = array()) {
62  _elgg_services()->notifications->registerEvent($object_type, $object_subtype, $actions);
63 }
64 
73 function elgg_unregister_notification_event($object_type, $object_subtype) {
74  return _elgg_services()->notifications->unregisterEvent($object_type, $object_subtype);
75 }
76 
90  _elgg_services()->notifications->registerMethod($name);
91 }
92 
102  return _elgg_services()->notifications->unregisterMethod($name);
103 }
104 
114 function elgg_add_subscription($user_guid, $method, $target_guid) {
115  $methods = _elgg_services()->notifications->getMethods();
116  $db = _elgg_services()->db;
117  $subs = new \Elgg\Notifications\SubscriptionsService($db, $methods);
118  return $subs->addSubscription($user_guid, $method, $target_guid);
119 }
120 
130 function elgg_remove_subscription($user_guid, $method, $target_guid) {
131  $methods = _elgg_services()->notifications->getMethods();
132  $db = _elgg_services()->db;
133  $subs = new \Elgg\Notifications\SubscriptionsService($db, $methods);
134  return $subs->removeSubscription($user_guid, $method, $target_guid);
135 }
136 
152  $methods = _elgg_services()->notifications->getMethods();
153  $db = _elgg_services()->db;
154  $subs = new \Elgg\Notifications\SubscriptionsService($db, $methods);
155  return $subs->getSubscriptionsForContainer($container_guid);
156 }
157 
174  _elgg_services()->notifications->enqueueEvent($action, $type, $object);
175 }
176 
181  // calculate when we should stop
182  // @todo make configurable?
183  $stop_time = time() + 45;
184  _elgg_services()->notifications->processQueue($stop_time);
185 }
186 
198 
199  if ($result === true) {
200  // assume someone else already sent the message
201  return;
202  }
203 
204  /* @var \Elgg\Notifications\Notification $message */
205  $message = $params['notification'];
206 
207  $sender = $message->getSender();
208  $recipient = $message->getRecipient();
209 
210  if (!$sender) {
211  return false;
212  }
213 
214  if (!$recipient || !$recipient->email) {
215  return false;
216  }
217 
218  $to = $recipient->email;
219 
221  // If there's an email address, use it - but only if it's not from a user.
222  if (!($sender instanceof \ElggUser) && $sender->email) {
223  $from = $sender->email;
224  } else if ($site->email) {
225  $from = $site->email;
226  } else {
227  // If all else fails, use the domain of the site.
228  $from = 'noreply@' . $site->getDomain();
229  }
230 
231  return elgg_send_email($from, $to, $message->subject, $message->body, $params);
232 }
233 
249 
250  if (!is_array($returnvalue) || !is_array($returnvalue['params'])) {
251  // another hook handler returned a non-array, let's not override it
252  return;
253  }
254 
255  $hostname = parse_url(elgg_get_site_url(), PHP_URL_HOST);
256  $url_path = parse_url(elgg_get_site_url(), PHP_URL_PATH);
257 
258  $mt = microtime(true);
259 
260  $returnvalue['headers']['Message-ID'] = "<{$url_path}.default.{$mt}@{$hostname}>";
261 
262  return $returnvalue;
263 }
275 function _elgg_notifications_smtp_thread_headers($hook, $type, $returnvalue, $params) {
276 
277  if (!is_array($returnvalue) || !is_array($returnvalue['params'])) {
278  // another hook handler returned a non-array, let's not override it
279  return;
280  }
281 
282  $notificationParams = elgg_extract('params', $returnvalue, array());
284  $notification = elgg_extract('notification', $notificationParams);
285 
286  if (!($notification instanceof \Elgg\Notifications\Notification)) {
287  return $returnvalue;
288  }
289 
290  $hostname = parse_url(elgg_get_site_url(), PHP_URL_HOST);
291  $urlPath = parse_url(elgg_get_site_url(), PHP_URL_PATH);
292 
293  $object = elgg_extract('object', $notification->params);
295  $event = elgg_extract('event', $notification->params);
296 
297  if (($object instanceof \ElggEntity) && ($event instanceof \Elgg\Notifications\Event)) {
298  if ($event->getAction() === 'create') {
299  // create event happens once per entity and we need to guarantee message id uniqueness
300  // and at the same time have thread message id that we don't need to store
301  $messageId = "<{$urlPath}.entity.{$object->guid}@{$hostname}>";
302  } else {
303  $mt = microtime(true);
304  $messageId = "<{$urlPath}.entity.{$object->guid}.$mt@{$hostname}>";
305  }
306  $returnvalue['headers']["Message-ID"] = $messageId;
307  $container = $object->getContainerEntity();
308 
309  // let's just thread comments by default
310  if (($container instanceof \ElggEntity) && ($object instanceof \ElggComment)) {
311 
312  $threadMessageId = "<{$urlPath}.entity.{$container->guid}@{$hostname}>";
313  $returnvalue['headers']['In-Reply-To'] = $threadMessageId;
314  $returnvalue['headers']['References'] = $threadMessageId;
315  }
316  }
317 
318  return $returnvalue;
319 }
320 
325  elgg_register_plugin_hook_handler('cron', 'minute', '_elgg_notifications_cron', 100);
326  elgg_register_event_handler('all', 'all', '_elgg_enqueue_notification_event');
327 
328  // add email notifications
330  elgg_register_plugin_hook_handler('send', 'notification:email', '_elgg_send_email_notification');
331  elgg_register_plugin_hook_handler('email', 'system', '_elgg_notifications_smtp_default_message_id_header', 1);
332  elgg_register_plugin_hook_handler('email', 'system', '_elgg_notifications_smtp_thread_headers');
333 
334  // add ability to set personal notification method
335  elgg_extend_view('forms/account/settings', 'core/settings/account/notifications');
336  elgg_register_plugin_hook_handler('usersettings:save', 'user', '_elgg_save_notification_user_settings');
337 }
338 
354 function _elgg_notify_user($to, $from, $subject, $message, array $params = null, $methods_override = "") {
355 
356  $notify_service = _elgg_services()->notifications;
357 
358  // Sanitise
359  if (!is_array($to)) {
360  $to = array((int)$to);
361  }
362  $from = (int)$from;
363  //$subject = sanitise_string($subject);
364 
365  // Get notification methods
366  if (($methods_override) && (!is_array($methods_override))) {
367  $methods_override = array($methods_override);
368  }
369 
370  $result = array();
371 
372  foreach ($to as $guid) {
373  // Results for a user are...
374  $result[$guid] = array();
375 
376  if ($guid) { // Is the guid > 0?
377  // Are we overriding delivery?
378  $methods = $methods_override;
379  if (!$methods) {
380  $tmp = get_user_notification_settings($guid);
381  $methods = array();
382  // $tmp may be false. don't cast
383  if (is_object($tmp)) {
384  foreach ($tmp as $k => $v) {
385  // Add method if method is turned on for user!
386  if ($v) {
387  $methods[] = $k;
388  }
389  }
390  }
391  }
392 
393  if ($methods) {
394  // Deliver
395  foreach ($methods as $method) {
396 
397  $handler = $notify_service->getDeprecatedHandler($method);
398  /* @var callable $handler */
399  if (!$handler || !is_callable($handler)) {
400  elgg_log("No handler registered for the method $method", 'WARNING');
401  continue;
402  }
403 
404  elgg_log("Sending message to $guid using $method");
405 
406  // Trigger handler and retrieve result.
407  try {
408  $result[$guid][$method] = call_user_func($handler,
409  $from ? get_entity($from) : null,
410  get_entity($guid),
411  $subject,
412  $message,
413  $params
414  );
415  } catch (Exception $e) {
416  error_log($e->getMessage());
417  }
418  }
419  }
420  }
421  }
422 
423  return $result;
424 }
425 
426 
476 function notify_user($to, $from, $subject, $message, array $params = array(), $methods_override = "") {
477 
478  if (!is_array($to)) {
479  $to = array((int)$to);
480  }
481  $from = (int)$from;
482  $from = get_entity($from) ? $from : elgg_get_site_entity()->guid;
483  $sender = get_entity($from);
484  $summary = elgg_extract('summary', $params, '');
485 
486  // Get notification methods
487  if (($methods_override) && (!is_array($methods_override))) {
488  $methods_override = array($methods_override);
489  }
490 
491  $result = array();
492 
493  $available_methods = _elgg_services()->notifications->getMethods();
494  if (!$available_methods) {
495  // There are no notifications methods to use
496  return $result;
497  }
498 
499  // temporary backward compatibility for 1.8 and earlier notifications
500  $event = null;
501  if (isset($params['object']) && isset($params['action'])) {
502  $event = new \Elgg\Notifications\Event($params['object'], $params['action'], $sender);
503  }
504  $params['event'] = $event;
505 
506  foreach ($to as $guid) {
507  // Results for a user are...
508  $result[$guid] = array();
509 
510  if ($guid) { // Is the guid > 0?
511  // Are we overriding delivery?
512  $methods = $methods_override;
513  if (!$methods) {
514  $tmp = (array)get_user_notification_settings($guid);
515  $methods = array();
516  foreach ($tmp as $k => $v) {
517  // Add method if method is turned on for user!
518  if ($v) {
519  $methods[] = $k;
520  }
521  }
522  }
523 
524  if ($methods) {
525  // Deliver
526  foreach ($methods as $method) {
527  if (!in_array($method, $available_methods)) {
528  // This method was available the last time the user saved their
529  // notification settings. It's however currently disabled.
530  continue;
531  }
532 
533  if (_elgg_services()->hooks->hasHandler('send', "notification:$method")) {
534  // 1.9 style notification handler
535  $recipient = get_entity($guid);
536  if (!$recipient) {
537  continue;
538  }
539  $language = $recipient->language;
540  $notification = new \Elgg\Notifications\Notification($sender, $recipient, $language, $subject, $message, $summary, $params);
541  $params['notification'] = $notification;
542  $result[$guid][$method] = _elgg_services()->hooks->trigger('send', "notification:$method", $params, false);
543  } else {
544  $result[$guid][$method] = _elgg_notify_user($guid, $from, $subject, $message, $params, array($method));
545  }
546  }
547  }
548  }
549  }
550 
551  return $result;
552 }
553 
562  $user_guid = (int)$user_guid;
563 
564  if ($user_guid == 0) {
566  }
567 
568  // @todo: there should be a better way now that metadata is cached. E.g. just query for MD names, then
569  // query user object directly
570  $all_metadata = elgg_get_metadata(array(
571  'guid' => $user_guid,
572  'limit' => 0
573  ));
574  if ($all_metadata) {
575  $prefix = "notification:method:";
576  $return = new \stdClass;
577 
578  foreach ($all_metadata as $meta) {
579  $name = substr($meta->name, strlen($prefix));
580  $value = $meta->value;
581 
582  if (strpos($meta->name, $prefix) === 0) {
583  $return->$name = $value;
584  }
585  }
586 
587  return $return;
588  }
589 
590  return false;
591 }
592 
603  $user_guid = (int)$user_guid;
605 
607  if (!$user) {
609  }
610 
611  if (($user) && ($user instanceof \ElggUser)) {
612  $prefix = "notification:method:$method";
613  $user->$prefix = $value;
614  $user->save();
615 
616  return true;
617  }
618 
619  return false;
620 }
621 
635 function elgg_send_email($from, $to, $subject, $body, array $params = null) {
636  global $CONFIG;
637 
638  if (!$from) {
639  $msg = "Missing a required parameter, '" . 'from' . "'";
640  throw new \NotificationException($msg);
641  }
642 
643  if (!$to) {
644  $msg = "Missing a required parameter, '" . 'to' . "'";
645  throw new \NotificationException($msg);
646  }
647 
648  $headers = array(
649  "Content-Type" => "text/plain; charset=UTF-8; format=flowed",
650  "MIME-Version" => "1.0",
651  "Content-Transfer-Encoding" => "8bit",
652  );
653 
654  // return true/false to stop elgg_send_email() from sending
655  $mail_params = array(
656  'to' => $to,
657  'from' => $from,
658  'subject' => $subject,
659  'body' => $body,
660  'headers' => $headers,
661  'params' => $params,
662  );
663 
664  // $mail_params is passed as both params and return value. The former is for backwards
665  // compatibility. The latter is so handlers can now alter the contents/headers of
666  // the email by returning the array
667  $result = elgg_trigger_plugin_hook('email', 'system', $mail_params, $mail_params);
668  if (is_array($result)) {
669  foreach (array('to', 'from', 'subject', 'body', 'headers') as $key) {
670  if (isset($result[$key])) {
671  ${$key} = $result[$key];
672  }
673  }
674  } elseif ($result !== null) {
675  return $result;
676  }
677 
678  $header_eol = "\r\n";
679  if (isset($CONFIG->broken_mta) && $CONFIG->broken_mta) {
680  // Allow non-RFC 2822 mail headers to support some broken MTAs
681  $header_eol = "\n";
682  }
683 
684  // Windows is somewhat broken, so we use just address for to and from
685  if (strtolower(substr(PHP_OS, 0, 3)) == 'win') {
686  // strip name from to and from
687  if (strpos($to, '<')) {
688  preg_match('/<(.*)>/', $to, $matches);
689  $to = $matches[1];
690  }
691  if (strpos($from, '<')) {
692  preg_match('/<(.*)>/', $from, $matches);
693  $from = $matches[1];
694  }
695  }
696 
697  // make sure From is set
698  if (empty($headers['From'])) {
699  $headers['From'] = $from;
700  }
701 
702  // stringify headers
703  $headers_string = '';
704  foreach ($headers as $key => $value) {
705  $headers_string .= "$key: $value{$header_eol}";
706  }
707 
708  // Sanitise subject by stripping line endings
709  $subject = preg_replace("/(\r\n|\r|\n)/", " ", $subject);
710  // this is because Elgg encodes everything and matches what is done with body
711  $subject = html_entity_decode($subject, ENT_QUOTES, 'UTF-8'); // Decode any html entities
712  if (is_callable('mb_encode_mimeheader')) {
713  $subject = mb_encode_mimeheader($subject, "UTF-8", "B");
714  }
715 
716  // Format message
717  $body = html_entity_decode($body, ENT_QUOTES, 'UTF-8'); // Decode any html entities
718  $body = elgg_strip_tags($body); // Strip tags from message
719  $body = preg_replace("/(\r\n|\r)/", "\n", $body); // Convert to unix line endings in body
720  $body = preg_replace("/^From/", ">From", $body); // Change lines starting with From to >From
721  $body = wordwrap($body);
722 
723  return mail($to, $subject, $body, $headers_string);
724 }
725 
733  $method = get_input('method');
734 
735  $current_settings = get_user_notification_settings();
736 
737  $result = false;
738  foreach ($method as $k => $v) {
739  // check if setting has changed and skip if not
740  if ($current_settings->$k == ($v == 'yes')) {
741  continue;
742  }
743 
744  $result = set_user_notification_setting(elgg_get_logged_in_user_guid(), $k, ($v == 'yes') ? true : false);
745 
746  if (!$result) {
747  register_error(elgg_echo('notifications:usersettings:save:fail'));
748  }
749  }
750 
751  if ($result) {
752  system_message(elgg_echo('notifications:usersettings:save:ok'));
753  }
754 }
755 
759 function _elgg_notifications_test($hook, $type, $tests) {
760  global $CONFIG;
761  $tests[] = "{$CONFIG->path}engine/tests/ElggCoreDatabaseQueueTest.php";
762  return $tests;
763 }
764 
765 return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
766  $events->registerHandler('init', 'system', '_elgg_notifications_init');
767 
768  $hooks->registerHandler('unit_test', 'system', '_elgg_notifications_test');
769 };
elgg_get_site_entity($site_guid=0)
Get an entity (default is current site)
Definition: sites.php:18
get_input($variable, $default=null, $filter_result=true)
Get some input from variables passed submitted through GET or POST.
Definition: input.php:27
elgg_register_notification_method($name)
Register a delivery method for notifications.
$subject
Definition: exceptions.php:25
if($guid==elgg_get_logged_in_user_guid()) $name
Definition: delete.php:21
$method
Definition: form.php:25
$e
Definition: metadata.php:12
$object
Definition: upgrade.php:12
elgg_strip_tags($string, $allowable_tags=null)
Strip tags and offer plugins the chance.
Definition: output.php:521
_elgg_notifications_cron()
private
$headers
Definition: default.php:14
elgg_unregister_notification_event($object_type, $object_subtype)
Unregister a notification event.
_elgg_enqueue_notification_event($action, $type, $object)
Queue a notification event for later handling.
$value
Definition: longtext.php:26
$return
Definition: opendd.php:15
$guid
Removes an admin notice.
elgg parse_url
Parse a URL into its parts.
Definition: elgglib.js:421
elgg_register_plugin_hook_handler($hook, $type, $callback, $priority=500)
Definition: elgglib.php:717
elgg_remove_subscription($user_guid, $method, $target_guid)
Unsubscribe a user to notifications about a target entity.
$action
$actions
Definition: user_hover.php:12
$summary
Definition: full.php:21
$params
Definition: login.php:72
elgg_get_subscriptions_for_container($container_guid)
Get the subscriptions for the content created inside this container.
_elgg_notifications_init()
private
_elgg_save_notification_user_settings()
Save personal notification settings - input comes from request.
elgg_unregister_notification_method($name)
Unregister a delivery method for notifications.
Save menu items.
if($entity) $container
Definition: access.php:62
elgg_echo($message_key, $args=array(), $language="")
Given a message key, returns an appropriately translated full-text string.
Definition: languages.php:21
$key
Definition: summary.php:34
$language
Definition: useradd.php:20
_elgg_services()
Definition: autoloader.php:14
global $CONFIG
sanitise_string($string)
Wrapper function for alternate English spelling (.
Definition: database.php:150
elgg_extend_view($view, $view_extension, $priority=501, $viewtype= '')
Extends a view with another view.
Definition: views.php:387
$user
Definition: ban.php:13
_elgg_notifications_smtp_default_message_id_header($hook, $type, $returnvalue, $params)
Adds default Message-ID header to all e-mails.
set_user_notification_setting($user_guid, $method, $value)
Set a user notification pref.
elgg_trigger_plugin_hook($hook, $type, $params=null, $returnvalue=null)
Definition: elgglib.php:790
elgg global
Pointer to the global context.
Definition: elgglib.js:12
elgg_get_site_url($site_guid=0)
Get the URL for the current (or specified) site.
$type
Definition: add.php:8
elgg_extract($key, $array, $default=null, $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:1271
elgg system_message
Wrapper function for system_messages.
Definition: elgglib.js:373
elgg_register_event_handler($event, $object_type, $callback, $priority=500)
Definition: elgglib.php:533
elgg_log($message, $level= 'NOTICE')
Display or log a message.
Definition: elgglib.php:958
_elgg_send_email_notification($hook, $type, $result, $params)
Send an email notification.
_elgg_notifications_test($hook, $type, $tests)
private
elgg_add_subscription($user_guid, $method, $target_guid)
Subscribe a user to notifications about a target entity.
elgg_register_notification_event($object_type, $object_subtype, array $actions=array())
Register a notification event.
elgg register_error
Wrapper function for system_messages.
Definition: elgglib.js:382
elgg_get_metadata(array $options=array())
Returns metadata.
Definition: metadata.php:143
notify_user($to, $from, $subject, $message, array $params=array(), $methods_override="")
Notify a user via their preferences.
elgg_get_logged_in_user_entity()
Return the current logged in user, or null if no user is logged in.
Definition: sessions.php:32
$container_guid
$handler
Definition: add.php:10
$user_guid
Avatar remove action.
Definition: remove.php:6
get_user_notification_settings($user_guid=0)
Get the notification settings for a given user.
elgg_send_email($from, $to, $subject, $body, array $params=null)
Send an email to any email address.
elgg_get_logged_in_user_guid()
Return the current logged in user by guid.
Definition: sessions.php:42
_elgg_notify_user($to, $from, $subject, $message, array $params=null, $methods_override="")
Notify a user via their preferences.
get_entity($guid)
Loads and returns an entity object from a guid.
Definition: entities.php:382