source: Dev/branches/cakephp/cake/libs/controller/components/email.php @ 126

Last change on this file since 126 was 126, checked in by fpvanagthoven, 14 years ago

Cakephp branch.

File size: 24.1 KB
Line 
1<?php
2/**
3 * Email Component
4 *
5 * PHP versions 4 and 5
6 *
7 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8 * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
9 *
10 * Licensed under The MIT License
11 * Redistributions of files must retain the above copyright notice.
12 *
13 * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
14 * @link          http://cakephp.org CakePHP(tm) Project
15 * @package       cake
16 * @subpackage    cake.cake.libs.controller.components
17 * @since         CakePHP(tm) v 1.2.0.3467
18 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
19 */
20App::import('Core', 'Multibyte');
21App::import('Core', 'String');
22
23/**
24 * EmailComponent
25 *
26 * This component is used for handling Internet Message Format based
27 * based on the standard outlined in http://www.rfc-editor.org/rfc/rfc2822.txt
28 *
29 * @package       cake
30 * @subpackage    cake.cake.libs.controller.components
31 * @link http://book.cakephp.org/view/1283/Email
32 *
33 */
34class EmailComponent extends Object{
35
36/**
37 * Recipient of the email
38 *
39 * @var string
40 * @access public
41 */
42        var $to = null;
43
44/**
45 * The mail which the email is sent from
46 *
47 * @var string
48 * @access public
49 */
50        var $from = null;
51
52/**
53 * The email the recipient will reply to
54 *
55 * @var string
56 * @access public
57 */
58        var $replyTo = null;
59
60/**
61 * The read receipt email
62 *
63 * @var string
64 * @access public
65 */
66        var $readReceipt = null;
67
68/**
69 * The mail that will be used in case of any errors like
70 * - Remote mailserver down
71 * - Remote user has exceeded his quota
72 * - Unknown user
73 *
74 * @var string
75 * @access public
76 */
77        var $return = null;
78
79/**
80 * Carbon Copy
81 *
82 * List of email's that should receive a copy of the email.
83 * The Recipient WILL be able to see this list
84 *
85 * @var array
86 * @access public
87 */
88        var $cc = array();
89
90/**
91 * Blind Carbon Copy
92 *
93 * List of email's that should receive a copy of the email.
94 * The Recipient WILL NOT be able to see this list
95 *
96 * @var array
97 * @access public
98 */
99        var $bcc = array();
100
101/**
102 * The date to put in the Date: header.  This should be a date
103 * conformant with the RFC2822 standard.  Leave null, to have
104 * today's date generated.
105 *
106 * @var string
107 */
108        var $date = null;
109
110/**
111 * The subject of the email
112 *
113 * @var string
114 * @access public
115 */
116        var $subject = null;
117
118/**
119 * Associative array of a user defined headers
120 * Keys will be prefixed 'X-' as per RFC2822 Section 4.7.5
121 *
122 * @var array
123 * @access public
124 */
125        var $headers = array();
126
127/**
128 * List of additional headers
129 *
130 * These will NOT be used if you are using safemode and mail()
131 *
132 * @var string
133 * @access public
134 */
135        var $additionalParams = null;
136
137/**
138 * Layout for the View
139 *
140 * @var string
141 * @access public
142 */
143        var $layout = 'default';
144
145/**
146 * Template for the view
147 *
148 * @var string
149 * @access public
150 */
151        var $template = null;
152
153/**
154 * as per RFC2822 Section 2.1.1
155 *
156 * @var integer
157 * @access public
158 */
159        var $lineLength = 70;
160
161/**
162 * Line feed character(s) to be used when sending using mail() function
163 * By default PHP_EOL is used.
164 * RFC2822 requires it to be CRLF but some Unix
165 * mail transfer agents replace LF by CRLF automatically
166 * (which leads to doubling CR if CRLF is used).
167 *
168 * @var string
169 * @access public
170 */
171        var $lineFeed = PHP_EOL;
172
173/**
174 * @deprecated see lineLength
175 */
176        var $_lineLength = null;
177
178/**
179 * What format should the email be sent in
180 *
181 * Supported formats:
182 * - text
183 * - html
184 * - both
185 *
186 * @var string
187 * @access public
188 */
189        var $sendAs = 'text';
190
191/**
192 * What method should the email be sent by
193 *
194 * Supported methods:
195 * - mail
196 * - smtp
197 * - debug
198 *
199 * @var string
200 * @access public
201 */
202        var $delivery = 'mail';
203
204/**
205 * charset the email is sent in
206 *
207 * @var string
208 * @access public
209 */
210        var $charset = 'utf-8';
211
212/**
213 * List of files that should be attached to the email.
214 *
215 * Can be both absolute and relative paths
216 *
217 * @var array
218 * @access public
219 */
220        var $attachments = array();
221
222/**
223 * What mailer should EmailComponent identify itself as
224 *
225 * @var string
226 * @access public
227 */
228        var $xMailer = 'CakePHP Email Component';
229
230/**
231 * The list of paths to search if an attachment isnt absolute
232 *
233 * @var array
234 * @access public
235 */
236        var $filePaths = array();
237
238/**
239 * List of options to use for smtp mail method
240 *
241 * Options is:
242 * - port
243 * - host
244 * - timeout
245 * - username
246 * - password
247 * - client
248 *
249 * @var array
250 * @access public
251 * @link http://book.cakephp.org/view/1290/Sending-A-Message-Using-SMTP
252 */
253        var $smtpOptions = array();
254
255/**
256 * Placeholder for any errors that might happen with the
257 * smtp mail methods
258 *
259 * @var string
260 * @access public
261 */
262        var $smtpError = null;
263
264/**
265 * Contains the rendered plain text message if one was sent.
266 *
267 * @var string
268 * @access public
269 */
270        var $textMessage = null;
271
272/**
273 * Contains the rendered HTML message if one was sent.
274 *
275 * @var string
276 * @access public
277 */
278        var $htmlMessage = null;
279
280/**
281 * Whether to generate a Message-ID header for the
282 * e-mail. True to generate a Message-ID, False to let
283 * it be handled by sendmail (or similar) or a string
284 * to completely override the Message-ID.
285 *
286 * If you are sending Email from a shell, be sure to set this value.  As you
287 * could encounter delivery issues if you do not.
288 *
289 * @var mixed
290 * @access public
291 */
292        var $messageId = true;
293
294/**
295 * Temporary store of message header lines
296 *
297 * @var array
298 * @access private
299 */
300        var $__header = array();
301
302/**
303 * If set, boundary to use for multipart mime messages
304 *
305 * @var string
306 * @access private
307 */
308        var $__boundary = null;
309
310/**
311 * Temporary store of message lines
312 *
313 * @var array
314 * @access private
315 */
316        var $__message = array();
317
318/**
319 * Variable that holds SMTP connection
320 *
321 * @var resource
322 * @access private
323 */
324        var $__smtpConnection = null;
325
326/**
327 * Initialize component
328 *
329 * @param object $controller Instantiating controller
330 * @access public
331 */
332        function initialize(&$controller, $settings = array()) {
333                $this->Controller =& $controller;
334                if (Configure::read('App.encoding') !== null) {
335                        $this->charset = Configure::read('App.encoding');
336                }
337                $this->_set($settings);
338        }
339
340/**
341 * Startup component
342 *
343 * @param object $controller Instantiating controller
344 * @access public
345 */
346        function startup(&$controller) {}
347
348/**
349 * Send an email using the specified content, template and layout
350 *
351 * @param mixed $content Either an array of text lines, or a string with contents
352 *  If you are rendering a template this variable will be sent to the templates as `$content`
353 * @param string $template Template to use when sending email
354 * @param string $layout Layout to use to enclose email body
355 * @return boolean Success
356 * @access public
357 */
358        function send($content = null, $template = null, $layout = null) {
359                $this->_createHeader();
360
361                if ($template) {
362                        $this->template = $template;
363                }
364
365                if ($layout) {
366                        $this->layout = $layout;
367                }
368
369                if (is_array($content)) {
370                        $content = implode("\n", $content) . "\n";
371                }
372
373                $this->htmlMessage = $this->textMessage = null;
374                if ($content) {
375                        if ($this->sendAs === 'html') {
376                                $this->htmlMessage = $content;
377                        } elseif ($this->sendAs === 'text') {
378                                $this->textMessage = $content;
379                        } else {
380                                $this->htmlMessage = $this->textMessage = $content;
381                        }
382                }
383
384                if ($this->sendAs === 'text') {
385                        $message = $this->_wrap($content);
386                } else {
387                        $message = $this->_wrap($content, 998);
388                }
389
390                if ($this->template === null) {
391                        $message = $this->_formatMessage($message);
392                } else {
393                        $message = $this->_render($message);
394                }
395
396                $message[] = '';
397                $this->__message = $message;
398
399                if (!empty($this->attachments)) {
400                        $this->_attachFiles();
401                }
402
403                if (!is_null($this->__boundary)) {
404                        $this->__message[] = '';
405                        $this->__message[] = '--' . $this->__boundary . '--';
406                        $this->__message[] = '';
407                }
408
409
410                $_method = '_' . $this->delivery;
411                $sent = $this->$_method();
412
413                $this->__header = array();
414                $this->__message = array();
415
416                return $sent;
417        }
418
419/**
420 * Reset all EmailComponent internal variables to be able to send out a new email.
421 *
422 * @access public
423 * @link http://book.cakephp.org/view/1285/Sending-Multiple-Emails-in-a-loop
424 */
425        function reset() {
426                $this->template = null;
427                $this->to = array();
428                $this->from = null;
429                $this->replyTo = null;
430                $this->return = null;
431                $this->cc = array();
432                $this->bcc = array();
433                $this->subject = null;
434                $this->additionalParams = null;
435                $this->date = null;
436                $this->smtpError = null;
437                $this->attachments = array();
438                $this->htmlMessage = null;
439                $this->textMessage = null;
440                $this->messageId = true;
441                $this->__header = array();
442                $this->__boundary = null;
443                $this->__message = array();
444        }
445
446/**
447 * Render the contents using the current layout and template.
448 *
449 * @param string $content Content to render
450 * @return array Email ready to be sent
451 * @access private
452 */
453        function _render($content) {
454                $viewClass = $this->Controller->view;
455
456                if ($viewClass != 'View') {
457                        list($plugin, $viewClass) = pluginSplit($viewClass);
458                        $viewClass = $viewClass . 'View';
459                        App::import('View', $this->Controller->view);
460                }
461
462                $View = new $viewClass($this->Controller);
463                $View->layout = $this->layout;
464                $msg = array();
465
466                $content = implode("\n", $content);
467
468                if ($this->sendAs === 'both') {
469                        $htmlContent = $content;
470                        if (!empty($this->attachments)) {
471                                $msg[] = '--' . $this->__boundary;
472                                $msg[] = 'Content-Type: multipart/alternative; boundary="alt-' . $this->__boundary . '"';
473                                $msg[] = '';
474                        }
475                        $msg[] = '--alt-' . $this->__boundary;
476                        $msg[] = 'Content-Type: text/plain; charset=' . $this->charset;
477                        $msg[] = 'Content-Transfer-Encoding: 7bit';
478                        $msg[] = '';
479
480                        $content = $View->element('email' . DS . 'text' . DS . $this->template, array('content' => $content), true);
481                        $View->layoutPath = 'email' . DS . 'text';
482                        $content = explode("\n", $this->textMessage = str_replace(array("\r\n", "\r"), "\n", $View->renderLayout($content)));
483
484                        $msg = array_merge($msg, $content);
485
486                        $msg[] = '';
487                        $msg[] = '--alt-' . $this->__boundary;
488                        $msg[] = 'Content-Type: text/html; charset=' . $this->charset;
489                        $msg[] = 'Content-Transfer-Encoding: 7bit';
490                        $msg[] = '';
491
492                        $htmlContent = $View->element('email' . DS . 'html' . DS . $this->template, array('content' => $htmlContent), true);
493                        $View->layoutPath = 'email' . DS . 'html';
494                        $htmlContent = explode("\n", $this->htmlMessage = str_replace(array("\r\n", "\r"), "\n", $View->renderLayout($htmlContent)));
495                        $msg = array_merge($msg, $htmlContent);
496                        $msg[] = '';
497                        $msg[] = '--alt-' . $this->__boundary . '--';
498                        $msg[] = '';
499
500                        ClassRegistry::removeObject('view');
501                        return $msg;
502                }
503
504                if (!empty($this->attachments)) {
505                        if ($this->sendAs === 'html') {
506                                $msg[] = '';
507                                $msg[] = '--' . $this->__boundary;
508                                $msg[] = 'Content-Type: text/html; charset=' . $this->charset;
509                                $msg[] = 'Content-Transfer-Encoding: 7bit';
510                                $msg[] = '';
511                        } else {
512                                $msg[] = '--' . $this->__boundary;
513                                $msg[] = 'Content-Type: text/plain; charset=' . $this->charset;
514                                $msg[] = 'Content-Transfer-Encoding: 7bit';
515                                $msg[] = '';
516                        }
517                }
518
519                $content = $View->element('email' . DS . $this->sendAs . DS . $this->template, array('content' => $content), true);
520                $View->layoutPath = 'email' . DS . $this->sendAs;
521                $content = explode("\n", $rendered = str_replace(array("\r\n", "\r"), "\n", $View->renderLayout($content)));
522
523                if ($this->sendAs === 'html') {
524                        $this->htmlMessage = $rendered;
525                } else {
526                        $this->textMessage = $rendered;
527                }
528
529                $msg = array_merge($msg, $content);
530                ClassRegistry::removeObject('view');
531
532                return $msg;
533        }
534
535/**
536 * Create unique boundary identifier
537 *
538 * @access private
539 */
540        function _createboundary() {
541                $this->__boundary = md5(uniqid(time()));
542        }
543
544/**
545 * Sets headers for the message
546 *
547 * @access public
548 * @param array Associative array containing headers to be set.
549 */
550        function header($headers) {
551                foreach ($headers as $header => $value) {
552                        $this->__header[] = sprintf('%s: %s', trim($header), trim($value));
553                }
554        }
555/**
556 * Create emails headers including (but not limited to) from email address, reply to,
557 * bcc and cc.
558 *
559 * @access private
560 */
561        function _createHeader() {
562        $headers = array();
563
564                if ($this->delivery == 'smtp') {
565                        $headers['To'] = implode(', ', array_map(array($this, '_formatAddress'), (array)$this->to));
566                }
567                $headers['From'] = $this->_formatAddress($this->from);
568
569                if (!empty($this->replyTo)) {
570                        $headers['Reply-To'] = $this->_formatAddress($this->replyTo);
571                }
572                if (!empty($this->return)) {
573                        $headers['Return-Path'] = $this->_formatAddress($this->return);
574                }
575                if (!empty($this->readReceipt)) {
576                        $headers['Disposition-Notification-To'] = $this->_formatAddress($this->readReceipt);
577                }
578
579                if (!empty($this->cc)) {
580                        $headers['Cc'] = implode(', ', array_map(array($this, '_formatAddress'), (array)$this->cc));
581                }
582
583                if (!empty($this->bcc) && $this->delivery != 'smtp') {
584                        $headers['Bcc'] = implode(', ', array_map(array($this, '_formatAddress'), (array)$this->bcc));
585                }
586                if ($this->delivery == 'smtp') {
587                        $headers['Subject'] = $this->_encode($this->subject);
588                }
589
590                if ($this->messageId !== false) {
591                        if ($this->messageId === true) {
592                                $headers['Message-ID'] = '<' . String::uuid() . '@' . env('HTTP_HOST') . '>';
593                        } else {
594                                $headers['Message-ID'] = $this->messageId;
595                        }
596                }
597
598                $date = $this->date;
599                if ($date == false) {
600                        $date = date(DATE_RFC2822);
601                }
602                $headers['Date'] = $date;
603
604                $headers['X-Mailer'] = $this->xMailer;
605
606                if (!empty($this->headers)) {
607                        foreach ($this->headers as $key => $val) {
608                                $headers['X-' . $key] = $val;
609                        }
610                }
611
612                if (!empty($this->attachments)) {
613                        $this->_createBoundary();
614                        $headers['MIME-Version'] = '1.0';
615                        $headers['Content-Type'] = 'multipart/mixed; boundary="' . $this->__boundary . '"';
616                        $headers[] = 'This part of the E-mail should never be seen. If';
617                        $headers[] = 'you are reading this, consider upgrading your e-mail';
618                        $headers[] = 'client to a MIME-compatible client.';
619                } elseif ($this->sendAs === 'text') {
620                        $headers['Content-Type'] = 'text/plain; charset=' . $this->charset;
621                } elseif ($this->sendAs === 'html') {
622                        $headers['Content-Type'] = 'text/html; charset=' . $this->charset;
623                } elseif ($this->sendAs === 'both') {
624                        $headers['Content-Type'] = 'multipart/alternative; boundary="alt-' . $this->__boundary . '"';
625                }
626
627                $headers['Content-Transfer-Encoding'] = '7bit';
628
629        $this->header($headers);
630        }
631
632/**
633 * Format the message by seeing if it has attachments.
634 *
635 * @param string $message Message to format
636 * @access private
637 */
638        function _formatMessage($message) {
639                if (!empty($this->attachments)) {
640                        $prefix = array('--' . $this->__boundary);
641                        if ($this->sendAs === 'text') {
642                                $prefix[] = 'Content-Type: text/plain; charset=' . $this->charset;
643                        } elseif ($this->sendAs === 'html') {
644                                $prefix[] = 'Content-Type: text/html; charset=' . $this->charset;
645                        } elseif ($this->sendAs === 'both') {
646                                $prefix[] = 'Content-Type: multipart/alternative; boundary="alt-' . $this->__boundary . '"';
647                        }
648                        $prefix[] = 'Content-Transfer-Encoding: 7bit';
649                        $prefix[] = '';
650                        $message = array_merge($prefix, $message);
651                }
652                return $message;
653        }
654
655/**
656 * Attach files by adding file contents inside boundaries.
657 *
658 * @access private
659 * @TODO: modify to use the core File class?
660 */
661        function _attachFiles() {
662                $files = array();
663                foreach ($this->attachments as $filename => $attachment) {
664                        $file = $this->_findFiles($attachment);
665                        if (!empty($file)) {
666                                if (is_int($filename)) {
667                                        $filename = basename($file);
668                                }
669                                $files[$filename] = $file;
670                        }
671                }
672
673                foreach ($files as $filename => $file) {
674                        $handle = fopen($file, 'rb');
675                        $data = fread($handle, filesize($file));
676                        $data = chunk_split(base64_encode($data)) ;
677                        fclose($handle);
678
679                        $this->__message[] = '--' . $this->__boundary;
680                        $this->__message[] = 'Content-Type: application/octet-stream';
681                        $this->__message[] = 'Content-Transfer-Encoding: base64';
682                        $this->__message[] = 'Content-Disposition: attachment; filename="' . basename($filename) . '"';
683                        $this->__message[] = '';
684                        $this->__message[] = $data;
685                        $this->__message[] = '';
686                }
687        }
688
689/**
690 * Find the specified attachment in the list of file paths
691 *
692 * @param string $attachment Attachment file name to find
693 * @return string Path to located file
694 * @access private
695 */
696        function _findFiles($attachment) {
697                if (file_exists($attachment)) {
698                        return $attachment;
699                }
700                foreach ($this->filePaths as $path) {
701                        if (file_exists($path . DS . $attachment)) {
702                                $file = $path . DS . $attachment;
703                                return $file;
704                        }
705                }
706                return null;
707        }
708
709/**
710 * Wrap the message using EmailComponent::$lineLength
711 *
712 * @param string $message Message to wrap
713 * @param integer $lineLength Max length of line
714 * @return array Wrapped message
715 * @access protected
716 */
717        function _wrap($message, $lineLength = null) {
718                $message = $this->_strip($message, true);
719                $message = str_replace(array("\r\n","\r"), "\n", $message);
720                $lines = explode("\n", $message);
721                $formatted = array();
722
723                if ($this->_lineLength !== null) {
724                        trigger_error(__('_lineLength cannot be accessed please use lineLength', true), E_USER_WARNING);
725                        $this->lineLength = $this->_lineLength;
726                }
727
728                if (!$lineLength) {
729                        $lineLength = $this->lineLength;
730                }
731
732                foreach ($lines as $line) {
733                        if (substr($line, 0, 1) == '.') {
734                                $line = '.' . $line;
735                        }
736                        $formatted = array_merge($formatted, explode("\n", wordwrap($line, $lineLength, "\n", true)));
737                }
738                $formatted[] = '';
739                return $formatted;
740        }
741
742/**
743 * Encode the specified string using the current charset
744 *
745 * @param string $subject String to encode
746 * @return string Encoded string
747 * @access private
748 */
749        function _encode($subject) {
750                $subject = $this->_strip($subject);
751
752                $nl = "\r\n";
753                if ($this->delivery == 'mail') {
754                        $nl = '';
755                }
756                $internalEncoding = function_exists('mb_internal_encoding');
757                if ($internalEncoding) {
758                        $restore = mb_internal_encoding();
759                        mb_internal_encoding($this->charset);
760                }
761                $return = mb_encode_mimeheader($subject, $this->charset, 'B', $nl);
762                if ($internalEncoding) {
763                        mb_internal_encoding($restore);
764                }
765                return $return;
766        }
767
768/**
769 * Format a string as an email address
770 *
771 * @param string $string String representing an email address
772 * @return string Email address suitable for email headers or smtp pipe
773 * @access private
774 */
775        function _formatAddress($string, $smtp = false) {
776                $hasAlias = preg_match('/((.*))?\s?<(.+)>/', $string, $matches);
777                if ($smtp && $hasAlias) {
778                        return $this->_strip('<' .  $matches[3] . '>');
779                } elseif ($smtp) {
780                        return $this->_strip('<' . $string . '>');
781                }
782
783                if ($hasAlias && !empty($matches[2])) {
784                        return $this->_encode($matches[2]) . $this->_strip(' <' . $matches[3] . '>');
785                }
786                return $this->_strip($string);
787        }
788
789/**
790 * Remove certain elements (such as bcc:, to:, %0a) from given value.
791 * Helps prevent header injection / mainipulation on user content.
792 *
793 * @param string $value Value to strip
794 * @param boolean $message Set to true to indicate main message content
795 * @return string Stripped value
796 * @access private
797 */
798        function _strip($value, $message = false) {
799                $search  = '%0a|%0d|Content-(?:Type|Transfer-Encoding)\:';
800                $search .= '|charset\=|mime-version\:|multipart/mixed|(?:[^a-z]to|b?cc)\:.*';
801
802                if ($message !== true) {
803                        $search .= '|\r|\n';
804                }
805                $search = '#(?:' . $search . ')#i';
806                while (preg_match($search, $value)) {
807                        $value = preg_replace($search, '', $value);
808                }
809                return $value;
810        }
811
812/**
813 * Wrapper for PHP mail function used for sending out emails
814 *
815 * @return bool Success
816 * @access private
817 */
818        function _mail() {
819                $header = implode($this->lineFeed, $this->__header);
820                $message = implode($this->lineFeed, $this->__message);
821                if (is_array($this->to)) {
822                        $to = implode(', ', array_map(array($this, '_formatAddress'), $this->to));
823                } else {
824                        $to = $this->to;
825                }
826                if (ini_get('safe_mode')) {
827                        return @mail($to, $this->_encode($this->subject), $message, $header);
828                }
829                return @mail($to, $this->_encode($this->subject), $message, $header, $this->additionalParams);
830        }
831
832
833/**
834 * Helper method to get socket, overridden in tests
835 *
836 * @param array $config Config data for the socket.
837 * @return void
838 * @access protected
839 */
840        function _getSocket($config) {
841                $this->__smtpConnection =& new CakeSocket($config);
842        }
843
844/**
845 * Sends out email via SMTP
846 *
847 * @return bool Success
848 * @access private
849 */
850        function _smtp() {
851                App::import('Core', array('CakeSocket'));
852
853                $defaults = array(
854                        'host' => 'localhost',
855                        'port' => 25,
856                        'protocol' => 'smtp',
857                        'timeout' => 30
858                );
859                $this->smtpOptions = array_merge($defaults, $this->smtpOptions);
860                $this->_getSocket($this->smtpOptions);
861
862                if (!$this->__smtpConnection->connect()) {
863                        $this->smtpError = $this->__smtpConnection->lastError();
864                        return false;
865                } elseif (!$this->_smtpSend(null, '220')) {
866                        return false;
867                }
868
869                $httpHost = env('HTTP_HOST');
870
871                if (isset($this->smtpOptions['client'])) {
872                        $host = $this->smtpOptions['client'];
873                } elseif (!empty($httpHost)) {
874                        list($host) = explode(':', $httpHost);
875                } else {
876                        $host = 'localhost';
877                }
878
879                if (!$this->_smtpSend("EHLO {$host}", '250') && !$this->_smtpSend("HELO {$host}", '250')) {
880                        return false;
881                }
882
883                if (isset($this->smtpOptions['username']) && isset($this->smtpOptions['password'])) {
884                        $authRequired = $this->_smtpSend('AUTH LOGIN', '334|503');
885                        if ($authRequired == '334') {
886                                if (!$this->_smtpSend(base64_encode($this->smtpOptions['username']), '334')) {
887                                        return false;
888                                }
889                                if (!$this->_smtpSend(base64_encode($this->smtpOptions['password']), '235')) {
890                                        return false;
891                                }
892                        } elseif ($authRequired != '503') {
893                                return false;
894                        }
895                }
896
897                if (!$this->_smtpSend('MAIL FROM: ' . $this->_formatAddress($this->from, true))) {
898                        return false;
899                }
900
901                if (!is_array($this->to)) {
902                        $tos = array_map('trim', explode(',', $this->to));
903                } else {
904                        $tos = $this->to;
905                }
906                foreach ($tos as $to) {
907                        if (!$this->_smtpSend('RCPT TO: ' . $this->_formatAddress($to, true))) {
908                                return false;
909                        }
910                }
911
912                foreach ($this->cc as $cc) {
913                        if (!$this->_smtpSend('RCPT TO: ' . $this->_formatAddress($cc, true))) {
914                                return false;
915                        }
916                }
917                foreach ($this->bcc as $bcc) {
918                        if (!$this->_smtpSend('RCPT TO: ' . $this->_formatAddress($bcc, true))) {
919                                return false;
920                        }
921                }
922
923                if (!$this->_smtpSend('DATA', '354')) {
924                        return false;
925                }
926
927                $header = implode("\r\n", $this->__header);
928                $message = implode("\r\n", $this->__message);
929                if (!$this->_smtpSend($header . "\r\n\r\n" . $message . "\r\n\r\n\r\n.")) {
930                        return false;
931                }
932                $this->_smtpSend('QUIT', false);
933
934                $this->__smtpConnection->disconnect();
935                return true;
936        }
937
938/**
939 * Protected method for sending data to SMTP connection
940 *
941 * @param string $data data to be sent to SMTP server
942 * @param mixed $checkCode code to check for in server response, false to skip
943 * @return bool Success
944 * @access protected
945 */
946        function _smtpSend($data, $checkCode = '250') {
947                if (!is_null($data)) {
948                        $this->__smtpConnection->write($data . "\r\n");
949                }
950                while ($checkCode !== false) {
951                        $response = '';
952                        $startTime = time();
953                        while (substr($response, -2) !== "\r\n" && ((time() - $startTime) < $this->smtpOptions['timeout'])) {
954                                $response .= $this->__smtpConnection->read();
955                        }
956                        if (substr($response, -2) !== "\r\n") {
957                                $this->smtpError = 'timeout';
958                                return false;
959                        }
960                        $response = end(explode("\r\n", rtrim($response, "\r\n")));
961
962                        if (preg_match('/^(' . $checkCode . ')(.)/', $response, $code)) {
963                                if ($code[2] === '-') {
964                                        continue;
965                                }
966                                return $code[1];
967                        }
968                        $this->smtpError = $response;
969                        return false;
970                }
971                return true;
972        }
973
974/**
975 * Set as controller flash message a debug message showing current settings in component
976 *
977 * @return boolean Success
978 * @access private
979 */
980        function _debug() {
981                $nl = "\n";
982                $header = implode($nl, $this->__header);
983                $message = implode($nl, $this->__message);
984                $fm = '<pre>';
985
986                if (is_array($this->to)) {
987                        $to = implode(', ', array_map(array($this, '_formatAddress'), $this->to));
988                } else {
989                        $to = $this->to;
990                }
991                $fm .= sprintf('%s %s%s', 'To:', $to, $nl);
992                $fm .= sprintf('%s %s%s', 'From:', $this->from, $nl);
993                $fm .= sprintf('%s %s%s', 'Subject:', $this->_encode($this->subject), $nl);
994                $fm .= sprintf('%s%3$s%3$s%s', 'Header:', $header, $nl);
995                $fm .= sprintf('%s%3$s%3$s%s', 'Parameters:', $this->additionalParams, $nl);
996                $fm .= sprintf('%s%3$s%3$s%s', 'Message:', $message, $nl);
997                $fm .= '</pre>';
998
999                if (isset($this->Controller->Session)) {
1000                        $this->Controller->Session->setFlash($fm, 'default', null, 'email');
1001                        return true;
1002                }
1003                return $fm;
1004        }
1005}
Note: See TracBrowser for help on using the repository browser.