'unconfirmed', 'to_email' => is_array( $to ) ? implode( ', ', array_map( 'strval', $to ) ) : (string) $to, 'from_email' => self::sender_of( $from ), 'subject' => isset( $atts['subject'] ) ? (string) $atts['subject'] : '', 'body' => $store_content && isset( $atts['message'] ) && is_string( $atts['message'] ) ? MailRedactor::redact( $atts['message'] ) : '', 'headers' => $headers, 'attachments' => array_values( array_filter( array_map( static function ( $path ) { return is_string( $path ) ? wp_basename( $path ) : ''; }, (array) $files ) ) ), 'error' => '', ); } /** * Headers as wp_mail() accepts them, a string or an array, reduced to the few worth keeping. * * @param string|string[] $headers Raw headers. * @return array Lower-case name => value, in KEPT_HEADERS order, plus 'from'. */ public static function parse_headers( $headers ) { $lines = is_array( $headers ) ? $headers : explode( "\n", str_replace( "\r\n", "\n", (string) $headers ) ); $found = array(); foreach ( $lines as $line ) { if ( ! is_string( $line ) || false === strpos( $line, ':' ) ) { continue; } list( $name, $value ) = explode( ':', $line, 2 ); $name = strtolower( trim( $name ) ); $value = trim( $value ); if ( 'from' !== $name && ! in_array( $name, self::KEPT_HEADERS, true ) ) { continue; } // Cc and Bcc may legitimately repeat. $found[ $name ] = isset( $found[ $name ] ) ? $found[ $name ] . ', ' . $value : $value; } $kept = array(); foreach ( self::KEPT_HEADERS as $name ) { if ( isset( $found[ $name ] ) ) { $kept[ $name ] = substr( $found[ $name ], 0, 500 ); } } if ( isset( $found['from'] ) ) { $kept['from'] = $found['from']; } return $kept; } /** * A From header value as the From column keeps it: '"Shop, Inc." ' becomes * 'Shop, Inc. ', a bare address stays bare. * * @param string $from A From header value. * @return string */ public static function sender_of( $from ) { if ( preg_match( '/^(.*)<([^>]+)>/', (string) $from, $match ) ) { return self::mailbox( $match[1], $match[2] ); } return trim( (string) $from ); } /** * A name and an address as one "Name
" string, or the address alone when there is * no name. The name is kept in the same column as the address rather than a column of its * own; everything that needs the bare address -- the privacy tools, search -- splits on the * angle brackets or matches inside the string already. * * @param string $name Display name, possibly quoted. * @param string $address Email address. * @return string */ public static function mailbox( $name, $address ) { $name = trim( str_replace( array( '<', '>' ), '', (string) $name ), " \t\"" ); $address = trim( (string) $address ); return '' === $name ? $address : $name . ' <' . $address . '>'; } }