Go to the documentation of this file.
39 if ( is_object( $address ) && $address instanceof
User ) {
40 $this->address = $address->getEmail();
41 $this->
name = $address->getName();
42 $this->realName = $address->getRealName();
44 $this->address = strval( $address );
46 $this->realName = strval( $realName );
55 # PHP's mail() implementation under Windows is somewhat shite, and
56 # can't handle "Joe Bloggs <joe@bloggs.com>" format email addresses,
57 # so don't bother generating them
58 if ( $this->address ) {
60 global $wgEnotifUseRealName;
61 $name = ( $wgEnotifUseRealName && $this->realName ) ? $this->realName : $this->
name;
63 if ( strpos( $quoted,
'.' ) !==
false || strpos( $quoted,
',' ) !==
false ) {
64 $quoted =
'"' . $quoted .
'"';
66 return "$quoted <{$this->address}>";
68 return $this->address;
96 protected static function sendWithPear( $mailer, $dest, $headers, $body ) {
97 $mailResult = $mailer->send( $dest, $headers, $body );
99 # Based on the result return an error string,
100 if ( PEAR::isError( $mailResult ) ) {
101 wfDebug(
"PEAR::Mail failed: " . $mailResult->getMessage() .
"\n" );
125 $strings[] =
"$name: $value";
127 return implode( $endl, $strings );
136 global $wgSMTP, $wgServer;
138 $msgid = uniqid(
wfWikiID() .
".",
true );
139 if ( is_array( $wgSMTP ) && isset( $wgSMTP[
'IDHost'] ) && $wgSMTP[
'IDHost'] ) {
140 $domain = $wgSMTP[
'IDHost'];
143 $domain = $url[
'host'];
145 return "<$msgid@$domain>";
163 public static function send( $to,
$from, $subject, $body, $replyto =
null, $contentType =
'text/plain; charset=UTF-8' ) {
164 global $wgSMTP, $wgEnotifMaxRecips, $wgAdditionalMailParams, $wgAllowHTMLEmail;
166 if ( !is_array( $to ) ) {
177 !is_array( $body ) &&
178 strlen( $body ) >= $minBodyLen
183 isset( $body[
'text'] ) &&
184 isset( $body[
'html'] ) &&
185 strlen( $body[
'text'] ) >= $minBodyLen &&
186 strlen( $body[
'html'] ) >= $minBodyLen
193 if ( !$wgAllowHTMLEmail && is_array( $body ) ) {
195 $body = $body[
'text'];
198 wfDebug( __METHOD__ .
': sending mail to ' . implode(
', ', $to ) .
"\n" );
200 # Make sure we have at least one address
201 $has_address =
false;
202 foreach ( $to
as $u ) {
208 if ( !$has_address ) {
212 # Forge email headers
213 # -------------------
217 # DO NOT add To: or Subject: headers at this step. They need to be
218 # handled differently depending upon the mailer we are going to use.
221 # PHP mail() first argument is the mail receiver. The argument is
222 # used as a recipient destination and as a To header.
224 # PEAR mailer has a recipient argument which is only used to
225 # send the mail. If no To header is given, PEAR will set it to
226 # to 'undisclosed-recipients:'.
228 # NOTE: To: is for presentation, the actual recipient is specified
229 # by the mailer using the Rcpt-To: header.
232 # PHP mail() second argument to pass the subject, passing a Subject
233 # as an additional header will result in a duplicate header.
235 # PEAR mailer should be passed a Subject header.
239 $headers[
'From'] =
$from->toString();
240 $headers[
'Return-Path'] =
$from->address;
243 $headers[
'Reply-To'] = $replyto->toString();
248 $headers[
'X-Mailer'] =
'MediaWiki mailer';
250 # Line endings need to be different on Unix and Windows due to
251 # the bug described at http://trac.wordpress.org/ticket/2603
258 if ( is_array( $body ) ) {
260 wfDebug(
"Assembling multipart mime email\n" );
261 if ( !stream_resolve_include_path(
'Mail/mime.php' ) ) {
262 wfDebug(
"PEAR Mail_Mime package is not installed. Falling back to text email.\n" );
264 $body = $body[
'text'];
266 require_once
'Mail/mime.php';
268 $body[
'text'] = str_replace(
"\n",
"\r\n", $body[
'text'] );
269 $body[
'html'] = str_replace(
"\n",
"\r\n", $body[
'html'] );
271 $mime =
new Mail_mime(
array(
'eol' => $endl,
'text_charset' =>
'UTF-8',
'html_charset' =>
'UTF-8' ) );
272 $mime->setTXTBody( $body[
'text'] );
273 $mime->setHTMLBody( $body[
'html'] );
274 $body =
$mime->get();
275 $headers =
$mime->headers( $headers );
278 if (
$mime ===
null ) {
281 $body = str_replace(
"\n",
"\r\n", $body );
283 $headers[
'MIME-Version'] =
'1.0';
284 $headers[
'Content-type'] = ( is_null( $contentType ) ?
285 'text/plain; charset=UTF-8' : $contentType );
286 $headers[
'Content-transfer-encoding'] =
'8bit';
290 if (
$ret ===
false ) {
293 } elseif (
$ret !==
true ) {
298 if ( is_array( $wgSMTP ) ) {
303 if ( !stream_resolve_include_path(
'Mail.php' ) ) {
304 throw new MWException(
'PEAR mail package is not installed' );
306 require_once
'Mail.php';
311 $mail_object =& Mail::factory(
'smtp', $wgSMTP );
312 if ( PEAR::isError( $mail_object ) ) {
313 wfDebug(
"PEAR::Mail factory failed: " . $mail_object->getMessage() .
"\n" );
318 wfDebug(
"Sending mail via PEAR::Mail\n" );
322 # When sending only to one recipient, shows it its email using To:
323 if ( count( $to ) == 1 ) {
324 $headers[
'To'] = $to[0]->toString();
327 # Split jobs since SMTP servers tends to limit the maximum
328 # number of possible recipients.
329 $chunks = array_chunk( $to, $wgEnotifMaxRecips );
330 foreach ( $chunks
as $chunk ) {
332 # FIXME : some chunks might be sent while others are not!
333 if ( !$status->isOK() ) {
344 if ( count( $to ) > 1 ) {
345 $headers[
'To'] =
'undisclosed-recipients:;';
349 wfDebug(
"Sending mail via internal mail() function\n" );
351 self::$mErrorString =
'';
352 $html_errors = ini_get(
'html_errors' );
353 ini_set(
'html_errors',
'0' );
354 set_error_handler(
'UserMailer::errorHandler' );
359 foreach ( $to
as $recip ) {
361 $sent =
mail( $recip, self::quotedPrintable( $subject ), $body, $headers );
363 $sent =
mail( $recip, self::quotedPrintable( $subject ), $body, $headers, $wgAdditionalMailParams );
366 }
catch ( Exception
$e ) {
367 restore_error_handler();
371 restore_error_handler();
372 ini_set(
'html_errors', $html_errors );
374 if ( self::$mErrorString ) {
375 wfDebug(
"Error sending mail: " . self::$mErrorString .
"\n" );
377 } elseif ( ! $sent ) {
379 wfDebug(
"Unknown error sending mail\n" );
394 self::$mErrorString = preg_replace(
'/^mail\(\)(\s*\[.*?\])?: /',
'', $string );
403 return strtr( $val,
array(
"\r" =>
'',
"\n" =>
'' ) );
415 $phrase = str_replace(
'"',
'', $phrase );
416 return '"' . $phrase .
'"';
431 # Probably incomplete; see RFC 2045
432 if ( empty( $charset ) ) {
435 $charset = strtoupper( $charset );
436 $charset = str_replace(
'ISO-8859',
'ISO8859', $charset );
438 $illegal =
'\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff=';
439 $replace = $illegal .
'\t ?_';
440 if ( !preg_match(
"/[$illegal]/", $string ) ) {
443 $out =
"=?$charset?Q?";
444 $out .= preg_replace_callback(
"/([$replace])/",
445 array( __CLASS__,
'quotedPrintableCallback' ), $string );
451 return sprintf(
"=%02X", ord(
$matches[1] ) );
505 global $wgEnotifUseJobQ, $wgEnotifWatchlist, $wgShowUpdatedMarker, $wgEnotifMinorEdits,
506 $wgUsersNotifiedOnAllChanges, $wgEnotifUserTalk;
514 if ( $wgEnotifWatchlist || $wgShowUpdatedMarker ) {
516 $res = $dbw->select(
array(
'watchlist' ),
519 'wl_user != ' . intval(
$editor->getID() ),
522 'wl_notificationtimestamp IS NULL',
525 foreach (
$res as $row ) {
526 $watchers[] = intval( $row->wl_user );
531 $dbw->onTransactionIdle(
534 $dbw->update(
'watchlist',
536 'wl_notificationtimestamp' => $dbw->timestamp(
$timestamp )
538 'wl_user' => $watchers,
553 if ( !count( $watchers ) && !count( $wgUsersNotifiedOnAllChanges ) ) {
567 if ( $wgEnotifUseJobQ ) {
570 'editorID' =>
$editor->getID(),
575 'watchers' => $watchers,
603 # we use $wgPasswordSender as sender's address
604 global $wgEnotifWatchlist;
605 global $wgEnotifMinorEdits, $wgEnotifUserTalk;
609 # The following code is only run, if several conditions are met:
610 # 1. EmailNotification for pages (other than user_talk pages) must be enabled
611 # 2. minor edits (changes) are only regarded if the global flag indicates so
621 $this->composed_common =
false;
624 $formattedPageStatus =
array(
'deleted',
'created',
'moved',
'restored',
'changed' );
626 wfRunHooks(
'UpdateUserMailerFormattedPageStatus',
array( &$formattedPageStatus ) );
627 if ( !in_array( $this->pageStatus, $formattedPageStatus ) ) {
629 throw new MWException(
'Not a valid page status!' );
639 $userTalkId = $targetUser->getId();
642 if ( $wgEnotifWatchlist ) {
645 foreach ( $userArray
as $watchingUser ) {
646 if ( $watchingUser->getOption(
'enotifwatchlistpages' )
647 && ( !
$minorEdit || $watchingUser->getOption(
'enotifminoredits' ) )
648 && $watchingUser->isEmailConfirmed()
649 && $watchingUser->getID() != $userTalkId
652 $this->
compose( $watchingUser );
659 global $wgUsersNotifiedOnAllChanges;
660 foreach ( $wgUsersNotifiedOnAllChanges
as $name ) {
683 if ( $wgEnotifUserTalk && $isUserTalkPage ) {
686 if ( !$targetUser || $targetUser->isAnon() ) {
687 wfDebug( __METHOD__ .
": user talk page edited, but user does not exist\n" );
689 wfDebug( __METHOD__ .
": user edited their own talk page, no notification sent\n" );
690 } elseif ( $targetUser->getOption(
'enotifusertalkpages' )
691 && ( !
$minorEdit || $targetUser->getOption(
'enotifminoredits' ) )
693 if ( !$targetUser->isEmailConfirmed() ) {
694 wfDebug( __METHOD__ .
": talk page owner doesn't have validated email\n" );
696 wfDebug( __METHOD__ .
": talk page update notification is aborted for this user\n" );
698 wfDebug( __METHOD__ .
": sending talk page update notification\n" );
702 wfDebug( __METHOD__ .
": talk page owner doesn't want notifications\n" );
712 global $wgPasswordSender, $wgNoReplyAddress;
713 global $wgEnotifFromEditor, $wgEnotifRevealEditorAddress;
714 global $wgEnotifImpersonal, $wgEnotifUseRealName;
716 $this->composed_common =
true;
718 # You as the WikiAdmin and Sysops can make use of plenty of
719 # named variables when composing your notification emails while
720 # simply editing the Meta pages
723 $postTransformKeys =
array();
724 $pageTitleUrl = $this->
title->getCanonicalURL();
725 $pageTitle = $this->
title->getPrefixedText();
727 if ( $this->oldid ) {
730 $this->
title->getCanonicalURL(
array(
'diff' =>
'next',
'oldid' => $this->oldid ) ) )
731 ->inContentLanguage()->text();
733 if ( !$wgEnotifImpersonal ) {
737 $this->
title->getCanonicalURL(
array(
'diff' =>
'0',
'oldid' => $this->oldid ) ) )
738 ->inContentLanguage()->text();
742 $keys[
'$CHANGEDORCREATED'] =
wfMessage(
'changed' )->inContentLanguage()->text();
744 # clear $OLDID placeholder in the message template
745 $keys[
'$OLDID'] =
'';
746 $keys[
'$NEWPAGE'] =
'';
748 $keys[
'$CHANGEDORCREATED'] =
wfMessage(
'created' )->inContentLanguage()->text();
751 $keys[
'$PAGETITLE'] = $this->
title->getPrefixedText();
752 $keys[
'$PAGETITLE_URL'] = $this->
title->getCanonicalURL();
753 $keys[
'$PAGEMINOREDIT'] = $this->minorEdit ?
754 wfMessage(
'minoredit' )->inContentLanguage()->text() :
'';
755 $keys[
'$UNWATCHURL'] = $this->
title->getCanonicalURL(
'action=unwatch' );
757 if ( $this->editor->isAnon() ) {
758 # real anon (user:xxx.xxx.xxx.xxx)
759 $keys[
'$PAGEEDITOR'] =
wfMessage(
'enotif_anon_editor', $this->editor->getName() )
760 ->inContentLanguage()->text();
761 $keys[
'$PAGEEDITOR_EMAIL'] =
wfMessage(
'noemailtitle' )->inContentLanguage()->text();
764 $keys[
'$PAGEEDITOR'] = $wgEnotifUseRealName ? $this->editor->getRealName() : $this->editor->getName();
766 $keys[
'$PAGEEDITOR_EMAIL'] = $emailPage->getCanonicalURL();
769 $keys[
'$PAGEEDITOR_WIKI'] = $this->editor->getUserPage()->getCanonicalURL();
772 # Replace this after transforming the message, bug 35019
773 $postTransformKeys[
'$PAGESUMMARY'] = $this->summary ==
'' ?
' - ' :
$this->summary;
780 $this->subject =
wfMessage(
'enotif_subject_' . $this->pageStatus )->inContentLanguage()
781 ->params( $pageTitle,
$keys[
'$PAGEEDITOR'] )->text();
786 $keys[
'$PAGEINTRO'] =
wfMessage(
'enotif_body_intro_' . $this->pageStatus )
787 ->inContentLanguage()->params( $pageTitle,
$keys[
'$PAGEEDITOR'], $pageTitleUrl )
793 $this->body = wordwrap( strtr(
$body, $postTransformKeys ), 72 );
795 # Reveal the page editor's address as REPLY-TO address only if
796 # the user has not opted-out and the option is enabled at the
797 # global configuration level.
798 $adminAddress =
new MailAddress( $wgPasswordSender,
800 if ( $wgEnotifRevealEditorAddress
801 && ( $this->editor->getEmail() !=
'' )
802 && $this->editor->getOption(
'enotifrevealaddr' )
805 if ( $wgEnotifFromEditor ) {
806 $this->
from = $editorAddress;
808 $this->
from = $adminAddress;
809 $this->replyto = $editorAddress;
812 $this->
from = $adminAddress;
813 $this->replyto =
new MailAddress( $wgNoReplyAddress );
825 global $wgEnotifImpersonal;
827 if ( !$this->composed_common ) {
831 if ( $wgEnotifImpersonal ) {
842 global $wgEnotifImpersonal;
843 if ( $wgEnotifImpersonal ) {
864 # $PAGEEDITDATE is the time and date of the page change
865 # expressed in terms of individual local time of the notification
866 # recipient, i.e. watching user
868 array(
'$WATCHINGUSERNAME',
871 array( $wgEnotifUseRealName ? $watchingUser->getRealName() : $watchingUser->getName(),
872 $wgContLang->userDate( $this->timestamp, $watchingUser ),
873 $wgContLang->userTime( $this->timestamp, $watchingUser ) ),
888 if ( empty( $addresses ) ) {
893 array(
'$WATCHINGUSERNAME',
897 $wgContLang->date( $this->timestamp,
false,
false ),
898 $wgContLang->time( $this->timestamp,
false,
false ) ),
static send( $to, $from, $subject, $body, $replyto=null, $contentType='text/plain;charset=UTF-8')
This function will perform a direct (authenticated) login to a SMTP Server to use for mail relaying i...
static sanitizeHeaderValue( $val)
Strips bad characters from a header value to prevent PHP mail header injection attacks.
globals txt Globals are evil The original MediaWiki code relied on globals for processing context far too often MediaWiki development since then has been a story of slowly moving context out of global variables and into objects Storing processing context in object member variables allows those objects to be reused in a much more flexible way Consider the elegance of
composeCommonMailtext()
Generate the generic "this page has been changed" e-mail text.
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
getId()
Get the user's ID.
usually copyright or history_copyright This message must be in HTML not wikitext $subpages will be ignored and the rest of subPageSubtitle() will run. 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink' whether MediaWiki currently thinks this is a CSS JS page Hooks may change this value to override the return value of Title::isCssOrJsPage(). 'TitleIsAlwaysKnown' whether MediaWiki currently thinks this page is known isMovable() always returns false. $title whether MediaWiki currently thinks this page is movable Hooks may change this value to override the return value of Title::isMovable(). 'TitleIsWikitextPage' whether MediaWiki currently thinks this is a wikitext page Hooks may change this value to override the return value of Title::isWikitextPage() 'TitleMove' use UploadVerification and UploadVerifyFile instead where the first element is the message key and the remaining elements are used as parameters to the message based on mime etc Preferred in most cases over UploadVerification object with all info about the upload string $mime
static quotedPrintable( $string, $charset='')
Converts a string into quoted-printable format.
notifyOnPageChange( $editor, $title, $timestamp, $summary, $minorEdit, $oldid=false, $pageStatus='changed')
Send emails corresponding to the user $editor editing the page $title.
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
sendMails()
Send any queued mails.
wfProfileIn( $functionname)
Begin profiling of a function.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
wfSuppressWarnings( $end=false)
Reference-counted warning suppression.
static newGood( $value=null)
Factory function for good results.
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the content language as $wgContLang
static sendWithPear( $mailer, $dest, $headers, $body)
Send mail using a PEAR mailer.
static errorHandler( $code, $string)
Set the mail error message in self::$mErrorString.
toString()
Return formatted and quoted address to insert into SMTP headers.
static getSafeTitleFor( $name, $subpage=false)
Get a localised Title object for a page name with a possibly unvalidated subpage.
Stores a single person's name and email address.
to move a page</td >< td > &*You are moving the page across *A non empty talk page already exists under the new or *You uncheck the box below In those you will have to move or merge the page manually if desired</td >< td > be sure to &You are responsible for making sure that links continue to point where they are supposed to go Note that the page will &a page at the new title
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
getDBkey()
Get the main part with underscores.
wfRestoreWarnings()
Restore error level to previous value.
getNamespace()
Get the namespace index, i.e.
wfProfileOut( $functionname='missing')
Stop profiling of a function.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form externallinks including delete and has completed for all link tables default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "<
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
when a variable name is used in a it is silently declared as a new masking the global
static arrayToHeaderString( $headers, $endl="\n")
Creates a single string from an associative array.
compose( $user)
Compose a mail to a given user and either queue it for sending, or send it now, depending on settings...
static singleton()
Get the signleton instance of this class.
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
Allows to change the fields on the form that will be generated $name
if(!defined( 'MEDIAWIKI')) if(!isset( $wgVersion)) $matches
Collection of static functions for sending mail.
__construct( $address, $name=null, $realName=null)
actuallyNotifyOnPageChange( $editor, $title, $timestamp, $summary, $minorEdit, $oldid, $watchers, $pageStatus='changed')
Immediate version of notifyOnPageChange().
wfIsWindows()
Check if the operating system is Windows.
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
wfIniGetBool( $setting)
Safety wrapper around ini_get() for boolean settings.
static makeMsgId()
Create a value suitable for the MessageId Header.
Represents a title within MediaWiki.
canSendUserTalkEmail( $editor, $title, $minorEdit)
if(count( $args)< 1) $job
sendImpersonal( $addresses)
Same as sendPersonalised but does impersonal mail suitable for bulk mailing.
static singleton( $wiki=false)
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
sendPersonalised( $watchingUser)
Does the per-user customizations to a notification e-mail (name, timestamp in proper timezone,...
Please log in again after you receive it</td >< td > s a saved copy from
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at name
static quotedPrintableCallback( $matches)
This module processes the email notifications when the current page is changed.
static rfc822Phrase( $phrase)
Converts a string into a valid RFC 822 "phrase", such as is used for the sender name.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Job for email notification mails.
static getLocalInstance( $ts=false)
Get a timestamp instance in the server local timezone ($wgLocaltimezone)
getName()
Get the user name, or the IP of an anonymous user.
getText()
Get the text form (spaces not underscores) of the main part.
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
isAllowed( $action='')
Internal mechanics of testing a permission.
static newFatal( $message)
Factory function for fatal errors.