Ticket #29513: wpmail.29513-2.diff
File wpmail.29513-2.diff, 21.1 KB (added by , 10 years ago) |
---|
-
new file src/wp-includes/class-wpmailer-factory.php
diff --git a/src/wp-includes/class-wpmailer-factory.php b/src/wp-includes/class-wpmailer-factory.php new file mode 100644 index 0000000..d61ec0f
- + 1 <?php 2 3 /** 4 * Creates a WPMailer instance, and sets the default values of 5 * the content type, charset and from name/email. 6 * 7 * @see WPMailer 8 * @see wp_mail() 9 */ 10 class WPMailerFactory { 11 12 static function getMailer(){ 13 14 require_once ABSPATH . WPINC . '/class-phpmailer.php'; 15 require_once ABSPATH . WPINC . '/class-wpmailer.php'; 16 require_once ABSPATH . WPINC . '/class-smtp.php'; 17 18 $wpmailer = new WPMailer( true ); 19 $wpmailer = self::reset( $wpmailer ); 20 21 return $wpmailer; 22 } 23 24 static function reset( $wpmailer ){ 25 26 $wpmailer->ClearAllRecipients(); 27 $wpmailer->ClearAttachments(); 28 $wpmailer->ClearCustomHeaders(); 29 $wpmailer->ClearReplyTos(); 30 31 $sitename = strtolower( $_SERVER['SERVER_NAME'] ); 32 if ( substr( $sitename, 0, 4 ) == 'www.' ) { 33 $sitename = substr( $sitename, 4 ); 34 } 35 36 $wpmailer->ContentType = 'text/plain'; 37 $wpmailer->CharSet = get_bloginfo( 'charset' ); 38 $wpmailer->FromName = 'WordPress'; 39 $wpmailer->From = 'wordpress@' . $sitename; 40 41 return $wpmailer; 42 } 43 44 } 45 ?> -
new file src/wp-includes/class-wpmailer.php
diff --git a/src/wp-includes/class-wpmailer.php b/src/wp-includes/class-wpmailer.php new file mode 100644 index 0000000..49a4797
- + 1 <?php 2 /** 3 * Email creation and transport class. (A child class of PHPMailer) 4 * 5 * This class adds a few 'helper' methods to the PHPMailer class and 6 * overrides the send method to trigger e-mail related filters. 7 * 8 */ 9 class WPMailer extends PHPMailer{ 10 11 /** 12 * Adds the passed e-mails as recipients 13 * 14 * @param string|array $recipients Array or comma-separated list of email addresses to send message. 15 */ 16 function setRecipients( $recipients ){ 17 18 //Set destination addresses 19 if ( !is_array( $recipients ) ){ 20 $recipients = explode( ',', $recipients ); 21 } 22 23 foreach ( (array) $recipients as $recipient ) { 24 try { 25 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>" 26 $recipient_name = ''; 27 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) { 28 if ( count( $matches ) == 3 ) { 29 $recipient_name = $matches[1]; 30 $recipient = $matches[2]; 31 } 32 } 33 $this->AddAddress( $recipient, $recipient_name); 34 } catch ( phpmailerException $e ) { 35 continue; 36 } 37 } 38 39 } 40 41 /** 42 * Adds the passed e-mails as "carbon-copy" recipients. 43 * 44 * @param array $cc Array of email addresses to attach as CC recipients. 45 * Each recipient can be an e-mail or of the format "Foo <bar@baz.com>" 46 */ 47 function addCcs( $cc ){ 48 49 foreach ( (array) $cc as $recipient ) { 50 try { 51 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>" 52 $recipient_name = ''; 53 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) { 54 if ( count( $matches ) == 3 ) { 55 $recipient_name = $matches[1]; 56 $recipient = $matches[2]; 57 } 58 } 59 $this->AddCc( $recipient, $recipient_name ); 60 } catch ( phpmailerException $e ) { 61 continue; 62 } 63 } 64 65 } 66 67 /** 68 * Adds the passed e-mails as "blind carbon-copy" recipients. 69 * 70 * @param array $bcc Array of email addresses to attach as BCC recipients. 71 * Each recipient can be an e-mail or of the format "Foo <bar@baz.com>" 72 */ 73 function addBccs( $bcc ){ 74 75 foreach ( (array) $bcc as $recipient) { 76 try { 77 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>" 78 $recipient_name = ''; 79 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) { 80 if ( count( $matches ) == 3 ) { 81 $recipient_name = $matches[1]; 82 $recipient = $matches[2]; 83 } 84 } 85 $this->AddBcc( $recipient, $recipient_name ); 86 } catch ( phpmailerException $e ) { 87 continue; 88 } 89 } 90 91 } 92 93 /** 94 * Adds the provided headers to the e-mail. 95 * 96 * Will set the content type, charset and CC/BCC recipients where appropriate 97 * 98 * @param string|array $headers Additional headers. 99 */ 100 function setHeaders( $headers = array() ){ 101 102 $tempheaders = array(); 103 104 // Headers 105 if ( $headers ){ 106 if ( !is_array( $headers ) ) { 107 // Explode the headers out, so this function can take both 108 // string headers and an array of headers. 109 $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) ); 110 } else { 111 $tempheaders = $headers; 112 } 113 } 114 115 if ( empty( $tempheaders ) ) { 116 return; 117 } 118 119 $headers = array(); 120 $cc = array(); 121 $bcc = array(); 122 123 // Iterate through the raw headers 124 foreach ( (array) $tempheaders as $header ) { 125 if ( strpos($header, ':') === false ) { 126 if ( false !== stripos( $header, 'boundary=' ) ) { 127 $parts = preg_split('/boundary=/i', trim( $header ) ); 128 $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) ); 129 } 130 continue; 131 } 132 133 // Explode them out 134 list( $name, $content ) = explode( ':', trim( $header ), 2 ); 135 136 // Cleanup crew 137 $name = trim( $name ); 138 $content = trim( $content ); 139 140 switch ( strtolower( $name ) ): 141 // Mainly for legacy -- process a From: header if it's there 142 case 'from': 143 144 $bracket_pos = strpos( $content, '<' ); 145 if ( $bracket_pos !== false ) { 146 147 // Text before the bracketed email is the "From" name. 148 if ( $bracket_pos > 0 ) { 149 $from_name = substr( $content, 0, $bracket_pos - 1 ); 150 $from_name = str_replace( '"', '', $from_name ); 151 $this->FromName = trim( $from_name ); 152 } 153 $from_email = substr( $content, $bracket_pos + 1 ); 154 $from_email = str_replace( '>', '', $from_email ); 155 $this->From = trim( $from_email ); 156 157 // Avoid setting an empty $from_email. 158 } elseif ( '' !== trim( $content ) ) { 159 $this->From = trim( $content ); 160 } 161 break; 162 163 case 'content-type': 164 165 if ( strpos( $content, ';' ) !== false ) { 166 167 list( $type, $charset_content ) = explode( ';', $content ); 168 $this->ContentType = trim( $type ); 169 170 if ( false !== stripos( $charset_content, 'charset=' ) ) { 171 $this->CharSet = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) ); 172 } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) { 173 $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) ); 174 $charset = ''; 175 } 176 177 // Avoid setting an empty $content_type. 178 } elseif ( '' !== trim( $content ) ) { 179 $this->ContentType = trim( $content ); 180 } 181 182 if ( false !== stripos( $this->ContentType, 'multipart' ) && ! empty( $boundary ) ){ 183 $this->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $this->ContentType, $boundary ) ); 184 } 185 break; 186 187 case 'cc': 188 $cc = array_merge( (array) $cc, explode( ',', $content ) ); 189 break; 190 191 case 'bcc': 192 $bcc = array_merge( (array) $bcc, explode( ',', $content ) ); 193 break; 194 195 default: 196 // Add it to our grand headers array 197 $this->AddCustomHeader( sprintf( '%1$s: %2$s', trim( $name ), trim( $content ) ) ); 198 break; 199 endswitch; 200 } 201 202 $this->addCcs( $cc ); 203 $this->addBccs( $bcc ); 204 } 205 206 207 /** 208 * Helper function for adding attachments. 209 * 210 * @param string|array $attachments Files to attach. 211 */ 212 function addAttachments( $attachments ){ 213 214 if ( !is_array($attachments) ) 215 $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) ); 216 217 218 foreach ( (array) $attachments as $attachment ) { 219 try { 220 $this->AddAttachment( $attachment ); 221 } catch ( phpmailerException $e ) { 222 continue; 223 } 224 } 225 } 226 227 /** 228 * Pre-send routine, for "last minute" filtering of e-mail properties. 229 * 230 * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from 231 * creating a from address like 'Name <email@address.com>' when both are set. If 232 * just 'wp_mail_from' is set, then just the email address will be used with no 233 * name. 234 * 235 * The default content type is 'text/plain' which does not allow using HTML. 236 * However, you can set the content type of the email by using the 237 * 'wp_mail_content_type' filter. 238 * 239 * The default charset is based on the charset used on the blog. The charset can 240 * be set using the 'wp_mail_charset' filter. 241 * 242 * @see PHPMailer::preSend(); 243 * @param string|array $attachments Files to attach. 244 */ 245 function preSend(){ 246 247 /** 248 * Filter the email address to send from. 249 * 250 * @since 2.2.0 251 * 252 * @param string $from_email Email address to send from. 253 */ 254 $this->From = apply_filters( 'wp_mail_from', $this->From ); 255 256 /** 257 * Filter the name to associate with the "from" email address. 258 * 259 * @since 2.3.0 260 * 261 * @param string $from_name Name associated with the "from" email address. 262 */ 263 $this->FromName = apply_filters( 'wp_mail_from_name', $this->FromName ); 264 265 // Set to use PHP's mail() 266 $this->IsMail(); 267 268 /** 269 * Filter the wp_mail() content type. 270 * 271 * @since 2.3.0 272 * 273 * @param string $content_type Default wp_mail() content type. 274 */ 275 $this->ContentType = apply_filters( 'wp_mail_content_type', $this->ContentType ); 276 277 // Set whether it's plaintext, depending on $content_type 278 if ( 'text/html' == $this->ContentType ){ 279 $this->IsHTML( true ); 280 } 281 282 /** 283 * Filter the default wp_mail() charset. 284 * 285 * @since 2.3.0 286 * 287 * @param string $charset Default email charset. 288 */ 289 $this->CharSet = apply_filters( 'wp_mail_charset', $this->CharSet ); 290 291 /** 292 * Fires after PHPMailer is initialized. 293 * 294 * @since 2.2.0 295 * 296 * @param PHPMailer &$this The PHPMailer instance, passed by reference. 297 */ 298 do_action_ref_array( 'phpmailer_init', array( &$this ) ); 299 300 return parent::preSend(); 301 302 } 303 304 305 } -
src/wp-includes/pluggable.php
diff --git a/src/wp-includes/pluggable.php b/src/wp-includes/pluggable.php index 4c2cc01..98a5c82 100644
a b if ( !function_exists( 'wp_mail' ) ) : 198 198 * email successfully. It just only means that the method used was able to 199 199 * process the request without any errors. 200 200 * 201 * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from202 * creating a from address like 'Name <email@address.com>' when both are set. If203 * just 'wp_mail_from' is set, then just the email address will be used with no204 * name.205 *206 * The default content type is 'text/plain' which does not allow using HTML.207 * However, you can set the content type of the email by using the208 * 'wp_mail_content_type' filter.209 *210 * The default charset is based on the charset used on the blog. The charset can211 * be set using the 'wp_mail_charset' filter.212 *213 201 * @since 1.2.1 214 202 * 215 * @uses PHPMailer203 * @uses WPMailer 216 204 * 217 205 * @param string|array $to Array or comma-separated list of email addresses to send message. 218 206 * @param string $subject Email subject … … function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() 233 221 * subject, message, headers, and attachments values. 234 222 */ 235 223 $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) ); 236 224 237 225 if ( isset( $atts['to'] ) ) { 238 226 $to = $atts['to']; 239 227 } … … function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() 253 241 if ( isset( $atts['attachments'] ) ) { 254 242 $attachments = $atts['attachments']; 255 243 } 244 256 245 257 if ( ! is_array( $attachments ) ) {258 $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );259 }260 246 global $phpmailer; 261 247 262 248 // (Re)create it, if it's gone missing 263 if ( ! ( $phpmailer instanceof PHPMailer ) ) { 264 require_once ABSPATH . WPINC . '/class-phpmailer.php'; 265 require_once ABSPATH . WPINC . '/class-smtp.php'; 266 $phpmailer = new PHPMailer( true ); 267 } 268 269 // Headers 270 if ( empty( $headers ) ) { 271 $headers = array(); 272 } else { 273 if ( !is_array( $headers ) ) { 274 // Explode the headers out, so this function can take both 275 // string headers and an array of headers. 276 $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) ); 277 } else { 278 $tempheaders = $headers; 279 } 280 $headers = array(); 281 $cc = array(); 282 $bcc = array(); 283 284 // If it's actually got contents 285 if ( !empty( $tempheaders ) ) { 286 // Iterate through the raw headers 287 foreach ( (array) $tempheaders as $header ) { 288 if ( strpos($header, ':') === false ) { 289 if ( false !== stripos( $header, 'boundary=' ) ) { 290 $parts = preg_split('/boundary=/i', trim( $header ) ); 291 $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) ); 292 } 293 continue; 294 } 295 // Explode them out 296 list( $name, $content ) = explode( ':', trim( $header ), 2 ); 297 298 // Cleanup crew 299 $name = trim( $name ); 300 $content = trim( $content ); 301 302 switch ( strtolower( $name ) ) { 303 // Mainly for legacy -- process a From: header if it's there 304 case 'from': 305 $bracket_pos = strpos( $content, '<' ); 306 if ( $bracket_pos !== false ) { 307 // Text before the bracketed email is the "From" name. 308 if ( $bracket_pos > 0 ) { 309 $from_name = substr( $content, 0, $bracket_pos - 1 ); 310 $from_name = str_replace( '"', '', $from_name ); 311 $from_name = trim( $from_name ); 312 } 313 314 $from_email = substr( $content, $bracket_pos + 1 ); 315 $from_email = str_replace( '>', '', $from_email ); 316 $from_email = trim( $from_email ); 317 318 // Avoid setting an empty $from_email. 319 } elseif ( '' !== trim( $content ) ) { 320 $from_email = trim( $content ); 321 } 322 break; 323 case 'content-type': 324 if ( strpos( $content, ';' ) !== false ) { 325 list( $type, $charset_content ) = explode( ';', $content ); 326 $content_type = trim( $type ); 327 if ( false !== stripos( $charset_content, 'charset=' ) ) { 328 $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) ); 329 } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) { 330 $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) ); 331 $charset = ''; 332 } 333 334 // Avoid setting an empty $content_type. 335 } elseif ( '' !== trim( $content ) ) { 336 $content_type = trim( $content ); 337 } 338 break; 339 case 'cc': 340 $cc = array_merge( (array) $cc, explode( ',', $content ) ); 341 break; 342 case 'bcc': 343 $bcc = array_merge( (array) $bcc, explode( ',', $content ) ); 344 break; 345 default: 346 // Add it to our grand headers array 347 $headers[trim( $name )] = trim( $content ); 348 break; 349 } 350 } 351 } 352 } 353 354 // Empty out the values that may be set 355 $phpmailer->ClearAllRecipients(); 356 $phpmailer->ClearAttachments(); 357 $phpmailer->ClearCustomHeaders(); 358 $phpmailer->ClearReplyTos(); 359 360 // From email and name 361 // If we don't have a name from the input headers 362 if ( !isset( $from_name ) ) 363 $from_name = 'WordPress'; 364 365 /* If we don't have an email from the input headers default to wordpress@$sitename 366 * Some hosts will block outgoing mail from this address if it doesn't exist but 367 * there's no easy alternative. Defaulting to admin_email might appear to be another 368 * option but some hosts may refuse to relay mail from an unknown domain. See 369 * https://core.trac.wordpress.org/ticket/5007. 370 */ 371 372 if ( !isset( $from_email ) ) { 373 // Get the site domain and get rid of www. 374 $sitename = strtolower( $_SERVER['SERVER_NAME'] ); 375 if ( substr( $sitename, 0, 4 ) == 'www.' ) { 376 $sitename = substr( $sitename, 4 ); 377 } 378 379 $from_email = 'wordpress@' . $sitename; 380 } 381 382 /** 383 * Filter the email address to send from. 384 * 385 * @since 2.2.0 386 * 387 * @param string $from_email Email address to send from. 388 */ 389 $phpmailer->From = apply_filters( 'wp_mail_from', $from_email ); 390 391 /** 392 * Filter the name to associate with the "from" email address. 393 * 394 * @since 2.3.0 395 * 396 * @param string $from_name Name associated with the "from" email address. 397 */ 398 $phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name ); 399 249 if ( !is_object( $phpmailer ) || !is_a( $phpmailer, 'WPMailer' ) ) { 250 $phpmailer = WPMailerFactory::getMailer(); 251 }else{ 252 $phpmailer = WPMailerFactory::reset( $phpmailer ); 253 } 254 400 255 // Set destination addresses 401 if ( !is_array( $to ) ) 402 $to = explode( ',', $to ); 403 404 foreach ( (array) $to as $recipient ) { 405 try { 406 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>" 407 $recipient_name = ''; 408 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) { 409 if ( count( $matches ) == 3 ) { 410 $recipient_name = $matches[1]; 411 $recipient = $matches[2]; 412 } 413 } 414 $phpmailer->AddAddress( $recipient, $recipient_name); 415 } catch ( phpmailerException $e ) { 416 continue; 417 } 418 } 256 $phpmailer->setRecipients( $to ); 419 257 420 258 // Set mail's subject and body 421 259 $phpmailer->Subject = $subject; 422 260 $phpmailer->Body = $message; 423 261 424 // Add any CC and BCC recipients425 if ( !empty( $cc ) ) {426 foreach ( (array) $cc as $recipient ) {427 try {428 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"429 $recipient_name = '';430 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {431 if ( count( $matches ) == 3 ) {432 $recipient_name = $matches[1];433 $recipient = $matches[2];434 }435 }436 $phpmailer->AddCc( $recipient, $recipient_name );437 } catch ( phpmailerException $e ) {438 continue;439 }440 }441 }442 443 if ( !empty( $bcc ) ) {444 foreach ( (array) $bcc as $recipient) {445 try {446 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"447 $recipient_name = '';448 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {449 if ( count( $matches ) == 3 ) {450 $recipient_name = $matches[1];451 $recipient = $matches[2];452 }453 }454 $phpmailer->AddBcc( $recipient, $recipient_name );455 } catch ( phpmailerException $e ) {456 continue;457 }458 }459 }460 461 // Set to use PHP's mail()462 $phpmailer->IsMail();463 464 // Set Content-Type and charset465 // If we don't have a content-type from the input headers466 if ( !isset( $content_type ) )467 $content_type = 'text/plain';468 469 /**470 * Filter the wp_mail() content type.471 *472 * @since 2.3.0473 *474 * @param string $content_type Default wp_mail() content type.475 */476 $content_type = apply_filters( 'wp_mail_content_type', $content_type );477 478 $phpmailer->ContentType = $content_type;479 480 // Set whether it's plaintext, depending on $content_type481 if ( 'text/html' == $content_type )482 $phpmailer->IsHTML( true );483 484 // If we don't have a charset from the input headers485 if ( !isset( $charset ) )486 $charset = get_bloginfo( 'charset' );487 488 // Set the content-type and charset489 490 /**491 * Filter the default wp_mail() charset.492 *493 * @since 2.3.0494 *495 * @param string $charset Default email charset.496 */497 $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );498 499 262 // Set custom headers 500 263 if ( !empty( $headers ) ) { 501 foreach( (array) $headers as $name => $content ) { 502 $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) ); 503 } 504 505 if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) ) 506 $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) ); 264 $phpmailer->setHeaders( $headers ); 507 265 } 508 266 267 //Set attachments 509 268 if ( !empty( $attachments ) ) { 510 foreach ( $attachments as $attachment ) { 511 try { 512 $phpmailer->AddAttachment($attachment); 513 } catch ( phpmailerException $e ) { 514 continue; 515 } 516 } 269 $phpmailer->AddAttachments( $attachments ); 517 270 } 518 519 /** 520 * Fires after PHPMailer is initialized. 521 * 522 * @since 2.2.0 523 * 524 * @param PHPMailer &$phpmailer The PHPMailer instance, passed by reference. 525 */ 526 do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) ); 527 271 528 272 // Send! 529 273 try { 530 274 return $phpmailer->Send(); 531 275 } catch ( phpmailerException $e ) { 532 276 return false; 533 277 } 278 534 279 } 535 280 endif; 536 281 -
src/wp-settings.php
diff --git a/src/wp-settings.php b/src/wp-settings.php index f90ff11..70349a5 100644
a b require( ABSPATH . WPINC . '/widgets.php' ); 153 153 require( ABSPATH . WPINC . '/nav-menu.php' ); 154 154 require( ABSPATH . WPINC . '/nav-menu-template.php' ); 155 155 require( ABSPATH . WPINC . '/admin-bar.php' ); 156 require( ABSPATH . WPINC . '/class-wpmailer-factory.php' ); 156 157 157 158 // Load multisite-specific files. 158 159 if ( is_multisite() ) { -
tests/phpunit/includes/mock-mailer.php
diff --git a/tests/phpunit/includes/mock-mailer.php b/tests/phpunit/includes/mock-mailer.php index a0ff65d..af128b1 100644
a b 1 1 <?php 2 2 require_once( ABSPATH . '/wp-includes/class-phpmailer.php' ); 3 require_once( ABSPATH . '/wp-includes/class-wpmailer.php' ); 3 4 4 class MockPHPMailer extends PHPMailer {5 class MockPHPMailer extends WPMailer { 5 6 var $mock_sent = array(); 6 7 7 8 /**