PluginProbe
SocketLabs / trunk
SocketLabs vtrunk
trunk 1.2.1 1.2.2
socketlabs / includes / class-socketlabs-mailer.php

class-socketlabs-mailer.php in SocketLabs trunk, at includes/class-socketlabs-mailer.php

397 lines 15.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * SocketLabs mailing manager.
4 *
5 * @link http://socketlabs.com
6 * @since 1.0.0
7 *
8 * @package Socketlabs
9 * @subpackage Socketlabs/includes
10 */
11
12 /**
13 * SocketLabs mailing manager.
14 *
15 * This class will assemble the SocketLabs api message, and send the message.
16 *
17 * @since 1.0.0
18 * @package Socketlabs
19 * @subpackage Socketlabs/includes
20 * @author SocketLabs Dev Team <support@socketlabs.com>
21 */
22 class Socketlabs_Mailer{
23
24 const contact_regex = '/([^"]*)["]?\s*<(.*)>.*$/';
25
26 private $api_url;
27 private $content_type = "text/plain";
28
29 private $api_message = array(
30 "To"=> array(),
31 "From"=> null,
32 "Subject"=> null,
33 "TextBody"=> null,
34 "HtmlBody"=> null,
35 "ApiTemplate"=> null,
36 "MailingId"=> "wordpress",
37 "MessageId"=> null,
38 "Charset"=> null,
39 "ReplyTo"=>null,
40 "Cc"=> array(),
41 "Bcc"=>array(),
42 "CustomHeaders"=> array(),
43 "Attachments"=> array()
44 );
45
46 public $message;
47
48 /**
49 * @since 1.0.0
50 * @access private
51 * @param string|array $to A single or collection of recipients.
52 * @param string $subject The subject of the email.
53 * @param string $message The email message (or body).
54 * @param string|array $headers A single header or a collection of headers.
55 * @param array $attachments A collection of attachments.
56 */
57 function __construct ($to, $subject, $message, $headers, $attachments){
58 $this->api_url = defined("SOCKETLABS_INJECTION_URL") ? SOCKETLABS_INJECTION_URL : "https://inject.socketlabs.com/api/v1/email";
59
60 /**
61 * Filters the wp_mail() arguments.
62 *
63 * @since 1.0.0
64 *
65 * @param array $args A compacted array of wp_mail() arguments, including the "to" email,
66 * subject, message, headers, and attachments values.
67 */
68 $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );
69
70 if ( isset( $atts['to'] ) ) {
71 $to = $atts['to'];
72 if(is_string($to)){
73 $to = explode( ',', $to );
74 }
75 if(is_array($to)){
76 foreach ($to as $recipient){
77 $recipient = trim($recipient);
78 if($recipient != ""){
79 $this->api_message["To"][] = (object)array("EmailAddress"=> $recipient);
80 }
81 }
82 }
83 }
84
85 if ( isset( $atts['subject'] ) ) {
86 $this->api_message["Subject"] = $atts['subject'];
87 }
88
89 if ( isset( $atts['message'] ) ) {
90 $this->message = $atts['message'];
91 }
92
93 if ( isset( $atts['attachments'] ) ) {
94 $attachments = $atts['attachments'];
95 }
96 if ( ! is_array( $attachments ) ) {
97 $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
98 }
99 if ( ! empty( $attachments ) ) {
100 foreach ( $attachments as $attachment ) {
101 try {
102 $this->addAttachment( $attachment );
103 } catch ( Exception $e ) {
104 continue;
105 }
106 }
107 }
108
109 $headers = $atts['headers'];
110 if ( empty( $headers ) ) {
111 $headers = array();
112 } else {
113 if ( ! is_array( $headers ) ) {
114 // Explode the headers out, so this function can take both
115 // string headers and an array of headers.
116 $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
117 } else {
118 $tempheaders = $headers;
119 }
120 $headers = array();
121 // If it's actually got contents
122 if ( ! empty( $tempheaders ) ) {
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 // Explode them out
133 list( $name, $content ) = explode( ':', trim( $header ), 2 );
134
135 // Cleanup crew
136 $name = trim( $name );
137 $content = trim( $content );
138
139 switch ( strtolower( $name ) ) {
140 // Mainly for legacy -- process a From: header if it's there
141 case 'from':
142 $contact_match;
143 preg_match(self::contact_regex, $content, $contact_match);
144
145 if(isset($contact_match[2])){
146 $this->apply_from(isset($contact_match[1]) ? $contact_match[1] : "", $contact_match[2]);
147 }
148 elseif ( '' !== trim( $content ) ) {
149 $this->apply_from("", trim( $content ));
150 }
151
152 break;
153 case 'content-type':
154 if ( strpos( $content, ';' ) !== false ) {
155 list( $type, $charset_content ) = explode( ';', $content );
156 $this->content_type = trim( $type );
157 if ( false !== stripos( $charset_content, 'charset=' ) ) {
158 $this->api_message["Charset"] = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) );
159 } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) {
160 $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) );
161 $this->api_message["Charset"] = apply_filters( 'wp_mail_charset', "" );
162 }
163
164 // Avoid setting an empty $content_type.
165 } elseif ( '' !== trim( $content ) ) {
166 $this->api_message["Charset"] = apply_filters( 'wp_mail_charset', trim( $content ) );
167 }
168 break;
169 case 'cc':
170 $cc = explode( ',', $content );
171 foreach ($cc as $recipient){
172 $this->api_message["Cc"][] = $this->create_contact($recipient);
173 }
174 break;
175 case 'bcc':
176 $bcc = explode( ',', $content );
177 foreach ($bcc as $recipient){
178 $this->api_message["Bcc"][] = $this->create_contact($recipient);
179 }
180 break;
181 case 'reply-to':
182 $this->api_message["ReplyTo"] = $this->create_contact($content);
183 break;
184 default:
185 // Add it to our grand headers array
186 $this->api_message["CustomHeaders"][] = (object)array(
187 "Name" => $name,
188 "Value" => trim( $content ),
189 );
190 break;
191 }
192 }
193 }
194 }
195
196 $this->create_message();
197 }
198
199
200 /**
201 * A helper function that applies from information to the $api_message
202 *
203 * @since 1.0.0
204 * @access private
205 * @param string $from_name From address friendly name
206 * @param string $from_email From email address
207 * @return void
208 */
209 private function apply_from($from_name, $from_email){
210
211 /**
212 * Filters the name to associate with the "from" email address.
213 *
214 * @since 1.0.0
215 *
216 * @param string $from_name Name associated with the "from" email address.
217 */
218 $from_name_filtered = apply_filters( 'wp_mail_from_name', $from_name );
219
220 /**
221 * Filters the email address to send from.
222 *
223 * @since 1.0.0
224 *
225 * @param string $from_email Email address to send from.
226 */
227 $from_email_filtered = apply_filters( 'wp_mail_from', $from_email );
228
229 $from = array();
230 if($from_name_filtered || $from_name){
231 $from["FriendlyName"] = $from_name_filtered ? $from_name_filtered : $from_name;
232 }
233 $from["EmailAddress"] = $from_email_filtered ? $from_email_filtered : $from_email;
234
235 $this->api_message["From"] = (object)$from;
236
237 }
238
239 /**
240 * A helper function that is creates a contact suitable for the api message
241 *
242 * @since 1.0.0
243 * @access private
244 * @param string $header Any single header item
245 * @return void
246 */
247 private function create_contact($value){
248 $contact_match;
249 preg_match(self::contact_regex, $value, $contact_match);
250 if( preg_match(self::contact_regex, $value, $contact_match) && isset($contact_match[2])){
251 return (object)array(
252 "FriendlyName" => isset($contact_match[1]) ? $contact_match[1] : null,
253 "EmailAddress" => $contact_match[2]
254 );
255 }
256 return (object)array(
257 "FriendlyName" => null,
258 "EmailAddress" => $value
259 );
260 }
261
262 /**
263 * A helper function that is assembles the api message
264 *
265 * @since 1.0.0
266 * @return void
267 */
268 private function create_message(){
269
270 /**
271 * Filters the wp_mail() content type.
272 *
273 * @since 1.0.0
274 *
275 * @param string $content_type Default wp_mail() content type.
276 */
277 $this->content_type = apply_filters( 'wp_mail_content_type', $this->content_type );
278
279 // Set whether it's plain text, depending on $content_type
280 if ( 'text/plain' == $this->content_type ){
281 $this->api_message["TextBody"] = $this->message;
282 $this->api_message["HtmlBody"] = null;
283 }
284 else{
285 $this->api_message["TextBody"] = null;
286 $this->api_message["HtmlBody"] = $this->message;
287 }
288
289
290 /* If we don't have an email from the input headers default to wordpress@$sitename
291 * Some hosts will block outgoing mail from this address if it doesn't exist but
292 * there's no easy alternative. Defaulting to admin_email might appear to be another
293 * option but some hosts may refuse to relay mail from an unknown domain. See
294 * https://core.trac.wordpress.org/ticket/5007.
295 */
296
297 if ($this->api_message["From"] == null) {
298 $from_name = 'WordPress';
299 $sitename = 'localhost';
300
301 // Check if SERVER_NAME is set
302 if (isset($_SERVER['SERVER_NAME'])) {
303
304 // Set sitename to SERVER_NAME
305 $sitename = $_SERVER['SERVER_NAME'];
306
307 // Make it lowercase
308 $sitename = strtolower($sitename);
309
310 // Get rid of www. if it exists
311 if (substr($sitename, 0, 4) == 'www.') {
312 $sitename = substr($sitename, 4);
313 }
314 }
315
316 $from_email = 'wordpress@' . $sitename;
317
318 $this->apply_from($from_name, $from_email);
319 }
320 }
321
322
323 /**
324 * Add an attachment from a path on the filesystem.
325 * Never use a user-supplied path to a file!
326 * Returns false if the file could not be found or read.
327 * @since 1.0.7
328 * @param string $path Path to the attachment.
329 * @param string $name Overrides the attachment name.
330 * @param string $type File extension (MIME) type.
331 * @return boolean
332 */
333 private function addAttachment($path, $name = '', $type = '')
334 {
335 try {
336 if (!@is_file($path)) {
337 throw new Exception("Cannot open file: " . $path);
338 }
339 // If a MIME type is not specified, try to work it out from the file name
340 if ($type == '') {
341 $type = Socketlabs_IO::filenameToType($path);
342 }
343 $filename = basename($path);
344 if ($name == '') {
345 $name = $filename;
346 }
347 $this->api_message["Attachments"][] = (object)array(
348 "Name" => $name,
349 "Content" => Socketlabs_IO::encodeFile($path),
350 "ContentType" => $type
351 );
352 } catch (Exception $exc) {
353 return false;
354 }
355 return true;
356 }
357
358 /**
359 * Send the assembled email message
360 * collection.
361 *
362 * @since 1.0.0
363 * @return object
364 */
365 public function send(){
366 $apiKey = Socketlabs::get_api_key();
367 $serverId = Socketlabs::get_server_id();
368
369 $headers = array(
370 'Content-Type' => 'application/json',
371 'Accept' => 'application/json'
372 );
373
374 // If apiKey is 61 characters, use Bearer token in Authorization header
375 if (strlen($apiKey) === 61) {
376 $headers['Authorization'] = 'Bearer ' . $apiKey;
377 $payload = (object) array(
378 "ServerId" => $serverId,
379 "Messages"=> array($this->api_message)
380 );
381 } else {
382 $payload = (object) array(
383 "ServerId" => $serverId,
384 "ApiKey"=> $apiKey,
385 "Messages"=> array($this->api_message)
386 );
387 }
388
389 return wp_remote_post( $this->api_url, array(
390 'method' => 'POST',
391 'body' => json_encode($payload),
392 'headers' => $headers
393 ));
394 }
395 }
396 ?>
397