Ticket #29513: refactor-wp-mail.diff
File refactor-wp-mail.diff, 20.7 KB (added by , 10 years ago) |
---|
-
new file src/wp-includes/class-wpmailer-factory.php
diff --git src/wp-includes/class-wpmailer-factory.php src/wp-includes/class-wpmailer-factory.php new file mode 100644 index 0000000..c42ba04
- + 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 20 $sitename = strtolower( $_SERVER['SERVER_NAME'] ); 21 if ( substr( $sitename, 0, 4 ) == 'www.' ) { 22 $sitename = substr( $sitename, 4 ); 23 } 24 25 $wpmailer->ContentType = 'text/plain'; 26 $wpmailer->CharSet = get_bloginfo( 'charset' ); 27 $wpmailer->FromName = 'WordPress'; 28 $wpmailer->From = 'wordpress@' . $sitename; 29 30 return $wpmailer; 31 } 32 33 } 34 ?> 35 No newline at end of file -
new file src/wp-includes/class-wpmailer.php
diff --git src/wp-includes/class-wpmailer.php src/wp-includes/class-wpmailer.php new file mode 100644 index 0000000..fb2e808
- + 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 if ( strpos($content, '<' ) !== false ) { 144 // So... making my life hard again? 145 $from_name = substr( $content, 0, strpos( $content, '<' ) - 1 ); 146 $from_name = str_replace( '"', '', $from_name ); 147 $from_name = trim( $from_name ); 148 149 $from_email = substr( $content, strpos( $content, '<' ) + 1 ); 150 $from_email = str_replace( '>', '', $from_email ); 151 $from_email = trim( $from_email ); 152 153 $this->FromName = $from_name; 154 155 } else { 156 $from_email = trim( $content ); 157 } 158 159 $this->From = $from_email; 160 break; 161 162 case 'content-type': 163 if ( strpos( $content, ';' ) !== false ) { 164 165 list( $type, $charset ) = explode( ';', $content ); 166 $content_type = trim( $type ); 167 168 if ( false !== stripos( $charset, 'charset=' ) ) { 169 $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset ) ); 170 } elseif ( false !== stripos( $charset, 'boundary=' ) ) { 171 $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset ) ); 172 $charset = ''; 173 } 174 175 } else { 176 $content_type = trim( $content ); 177 } 178 179 $this->CharSet = $charset; 180 $this->ContentType = $content_type; 181 182 if ( false !== stripos( $content_type, 'multipart' ) && ! empty( $boundary ) ){ 183 $this->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $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 } 306 No newline at end of file -
src/wp-includes/pluggable.php
diff --git src/wp-includes/pluggable.php src/wp-includes/pluggable.php index 872da82..2a063af 100644
if ( !function_exists( 'wp_mail' ) ) : 199 199 * email successfully. It just only means that the method used was able to 200 200 * process the request without any errors. 201 201 * 202 * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from203 * creating a from address like 'Name <email@address.com>' when both are set. If204 * just 'wp_mail_from' is set, then just the email address will be used with no205 * name.206 *207 * The default content type is 'text/plain' which does not allow using HTML.208 * However, you can set the content type of the email by using the209 * 'wp_mail_content_type' filter.210 *211 * The default charset is based on the charset used on the blog. The charset can212 * be set using the 'wp_mail_charset' filter.213 *214 202 * @since 1.2.1 215 203 * 216 * @uses PHPMailer204 * @uses WPMailer 217 205 * 218 206 * @param string|array $to Array or comma-separated list of email addresses to send message. 219 207 * @param string $subject Email subject … … function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() 234 222 * subject, message, headers, and attachments values. 235 223 */ 236 224 $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) ); 237 225 238 226 if ( isset( $atts['to'] ) ) { 239 227 $to = $atts['to']; 240 228 } … … function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() 254 242 if ( isset( $atts['attachments'] ) ) { 255 243 $attachments = $atts['attachments']; 256 244 } 245 257 246 258 if ( ! is_array( $attachments ) ) {259 $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );260 }261 247 global $phpmailer; 262 248 263 249 // (Re)create it, if it's gone missing 264 if ( !is_object( $phpmailer ) || !is_a( $phpmailer, 'PHPMailer' ) ) { 265 require_once ABSPATH . WPINC . '/class-phpmailer.php'; 266 require_once ABSPATH . WPINC . '/class-smtp.php'; 267 $phpmailer = new PHPMailer( true ); 268 } 269 270 // Headers 271 if ( empty( $headers ) ) { 272 $headers = array(); 273 } else { 274 if ( !is_array( $headers ) ) { 275 // Explode the headers out, so this function can take both 276 // string headers and an array of headers. 277 $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) ); 278 } else { 279 $tempheaders = $headers; 280 } 281 $headers = array(); 282 $cc = array(); 283 $bcc = array(); 284 285 // If it's actually got contents 286 if ( !empty( $tempheaders ) ) { 287 // Iterate through the raw headers 288 foreach ( (array) $tempheaders as $header ) { 289 if ( strpos($header, ':') === false ) { 290 if ( false !== stripos( $header, 'boundary=' ) ) { 291 $parts = preg_split('/boundary=/i', trim( $header ) ); 292 $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) ); 293 } 294 continue; 295 } 296 // Explode them out 297 list( $name, $content ) = explode( ':', trim( $header ), 2 ); 298 299 // Cleanup crew 300 $name = trim( $name ); 301 $content = trim( $content ); 302 303 switch ( strtolower( $name ) ) { 304 // Mainly for legacy -- process a From: header if it's there 305 case 'from': 306 if ( strpos($content, '<' ) !== false ) { 307 // So... making my life hard again? 308 $from_name = substr( $content, 0, strpos( $content, '<' ) - 1 ); 309 $from_name = str_replace( '"', '', $from_name ); 310 $from_name = trim( $from_name ); 311 312 $from_email = substr( $content, strpos( $content, '<' ) + 1 ); 313 $from_email = str_replace( '>', '', $from_email ); 314 $from_email = trim( $from_email ); 315 } else { 316 $from_email = trim( $content ); 317 } 318 break; 319 case 'content-type': 320 if ( strpos( $content, ';' ) !== false ) { 321 list( $type, $charset ) = explode( ';', $content ); 322 $content_type = trim( $type ); 323 if ( false !== stripos( $charset, 'charset=' ) ) { 324 $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset ) ); 325 } elseif ( false !== stripos( $charset, 'boundary=' ) ) { 326 $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset ) ); 327 $charset = ''; 328 } 329 } else { 330 $content_type = trim( $content ); 331 } 332 break; 333 case 'cc': 334 $cc = array_merge( (array) $cc, explode( ',', $content ) ); 335 break; 336 case 'bcc': 337 $bcc = array_merge( (array) $bcc, explode( ',', $content ) ); 338 break; 339 default: 340 // Add it to our grand headers array 341 $headers[trim( $name )] = trim( $content ); 342 break; 343 } 344 } 345 } 346 } 347 348 // Empty out the values that may be set 349 $phpmailer->ClearAllRecipients(); 350 $phpmailer->ClearAttachments(); 351 $phpmailer->ClearCustomHeaders(); 352 $phpmailer->ClearReplyTos(); 353 354 // From email and name 355 // If we don't have a name from the input headers 356 if ( !isset( $from_name ) ) 357 $from_name = 'WordPress'; 358 359 /* If we don't have an email from the input headers default to wordpress@$sitename 360 * Some hosts will block outgoing mail from this address if it doesn't exist but 361 * there's no easy alternative. Defaulting to admin_email might appear to be another 362 * option but some hosts may refuse to relay mail from an unknown domain. See 363 * http://trac.wordpress.org/ticket/5007. 364 */ 365 366 if ( !isset( $from_email ) ) { 367 // Get the site domain and get rid of www. 368 $sitename = strtolower( $_SERVER['SERVER_NAME'] ); 369 if ( substr( $sitename, 0, 4 ) == 'www.' ) { 370 $sitename = substr( $sitename, 4 ); 371 } 372 373 $from_email = 'wordpress@' . $sitename; 374 } 375 376 /** 377 * Filter the email address to send from. 378 * 379 * @since 2.2.0 380 * 381 * @param string $from_email Email address to send from. 382 */ 383 $phpmailer->From = apply_filters( 'wp_mail_from', $from_email ); 384 385 /** 386 * Filter the name to associate with the "from" email address. 387 * 388 * @since 2.3.0 389 * 390 * @param string $from_name Name associated with the "from" email address. 391 */ 392 $phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name ); 393 250 if ( !is_object( $phpmailer ) || !is_a( $phpmailer, 'WPMailer' ) ) { 251 //require_once ABSPATH . WPINC . '/class-phpmailer.php'; 252 //require_once ABSPATH . WPINC . '/class-smtp.php'; 253 $phpmailer = WPMailerFactory::getMailer(); 254 }else{ 255 256 $phpmailer->ClearAllRecipients(); 257 $phpmailer->ClearAttachments(); 258 $phpmailer->ClearCustomHeaders(); 259 $phpmailer->ClearReplyTos(); 260 261 } 262 263 264 265 394 266 // Set destination addresses 395 if ( !is_array( $to ) ) 396 $to = explode( ',', $to ); 397 398 foreach ( (array) $to as $recipient ) { 399 try { 400 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>" 401 $recipient_name = ''; 402 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) { 403 if ( count( $matches ) == 3 ) { 404 $recipient_name = $matches[1]; 405 $recipient = $matches[2]; 406 } 407 } 408 $phpmailer->AddAddress( $recipient, $recipient_name); 409 } catch ( phpmailerException $e ) { 410 continue; 411 } 412 } 267 $phpmailer->setRecipients( $to ); 413 268 414 269 // Set mail's subject and body 415 270 $phpmailer->Subject = $subject; 416 271 $phpmailer->Body = $message; 417 272 418 // Add any CC and BCC recipients419 if ( !empty( $cc ) ) {420 foreach ( (array) $cc as $recipient ) {421 try {422 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"423 $recipient_name = '';424 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {425 if ( count( $matches ) == 3 ) {426 $recipient_name = $matches[1];427 $recipient = $matches[2];428 }429 }430 $phpmailer->AddCc( $recipient, $recipient_name );431 } catch ( phpmailerException $e ) {432 continue;433 }434 }435 }436 437 if ( !empty( $bcc ) ) {438 foreach ( (array) $bcc as $recipient) {439 try {440 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"441 $recipient_name = '';442 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {443 if ( count( $matches ) == 3 ) {444 $recipient_name = $matches[1];445 $recipient = $matches[2];446 }447 }448 $phpmailer->AddBcc( $recipient, $recipient_name );449 } catch ( phpmailerException $e ) {450 continue;451 }452 }453 }454 455 // Set to use PHP's mail()456 $phpmailer->IsMail();457 458 // Set Content-Type and charset459 // If we don't have a content-type from the input headers460 if ( !isset( $content_type ) )461 $content_type = 'text/plain';462 463 /**464 * Filter the wp_mail() content type.465 *466 * @since 2.3.0467 *468 * @param string $content_type Default wp_mail() content type.469 */470 $content_type = apply_filters( 'wp_mail_content_type', $content_type );471 472 $phpmailer->ContentType = $content_type;473 474 // Set whether it's plaintext, depending on $content_type475 if ( 'text/html' == $content_type )476 $phpmailer->IsHTML( true );477 478 // If we don't have a charset from the input headers479 if ( !isset( $charset ) )480 $charset = get_bloginfo( 'charset' );481 482 // Set the content-type and charset483 484 /**485 * Filter the default wp_mail() charset.486 *487 * @since 2.3.0488 *489 * @param string $charset Default email charset.490 */491 $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );492 493 273 // Set custom headers 494 274 if ( !empty( $headers ) ) { 495 foreach( (array) $headers as $name => $content ) { 496 $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) ); 497 } 498 499 if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) ) 500 $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) ); 275 $phpmailer->setHeaders( $headers ); 501 276 } 502 277 278 //Set attachments 503 279 if ( !empty( $attachments ) ) { 504 foreach ( $attachments as $attachment ) { 505 try { 506 $phpmailer->AddAttachment($attachment); 507 } catch ( phpmailerException $e ) { 508 continue; 509 } 510 } 280 $phpmailer->AddAttachments( $attachments ); 511 281 } 512 513 /** 514 * Fires after PHPMailer is initialized. 515 * 516 * @since 2.2.0 517 * 518 * @param PHPMailer &$phpmailer The PHPMailer instance, passed by reference. 519 */ 520 do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) ); 521 282 522 283 // Send! 523 284 try { 524 285 return $phpmailer->Send(); 525 286 } catch ( phpmailerException $e ) { 526 287 return false; 527 288 } 289 528 290 } 529 291 endif; 530 292 -
src/wp-settings.php
diff --git src/wp-settings.php src/wp-settings.php index 9795971..37cd533 100644
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 tests/phpunit/includes/mock-mailer.php tests/phpunit/includes/mock-mailer.php index a0ff65d..af128b1 100644
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 /**