Overview

Packages

  • Jyxo_Beholder
  • Jyxo_Charset
  • Jyxo_Color
  • Jyxo_Css
  • Jyxo_ErrorHandling
  • Jyxo_FirePhp
  • Jyxo_Gettext
    • Parser
  • Jyxo_Html
  • Jyxo_Input
    • Chain
    • Filter
    • Validator
  • Jyxo_Mail
    • Email
    • Parser
    • Sender
  • Jyxo_Rpc
    • Json
    • Xml
  • Jyxo_Shell
  • Jyxo_SpamFilter
  • Jyxo_Spl
  • Jyxo_String
  • Jyxo_Svn
  • Jyxo_Time
  • Jyxo_Timer
  • Jyxo_Webdav
  • Jyxo_XmlReader
  • PHP

Classes

  • Jyxo_Mail_Sender
  • Jyxo_Mail_Sender_Result
  • Jyxo_Mail_Sender_Smtp

Exceptions

  • Jyxo_Mail_Sender_CreateException
  • Jyxo_Mail_Sender_Exception
  • Jyxo_Mail_Sender_RecipientUnknownException
  • Jyxo_Mail_Sender_SmtpException
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * Jyxo PHP Library
  5:  *
  6:  * LICENSE
  7:  *
  8:  * This source file is subject to the new BSD license that is bundled
  9:  * with this package in the file license.txt.
 10:  * It is also available through the world-wide-web at this URL:
 11:  * https://github.com/jyxo/php/blob/master/license.txt
 12:  */
 13: 
 14: /**
 15:  * Class for sending emails.
 16:  * Based on PhpMailer class (C) Copyright 2001-2003  Brent R. Matzelle
 17:  *
 18:  * @category Jyxo
 19:  * @package Jyxo_Mail
 20:  * @subpackage Sender
 21:  * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
 22:  * @license https://github.com/jyxo/php/blob/master/license.txt
 23:  * @author Jaroslav HanslĂ­k
 24:  */
 25: class Jyxo_Mail_Sender
 26: {
 27:     /**
 28:      * Send using the internal mail() function.
 29:      *
 30:      * @var string
 31:      */
 32:     const MODE_MAIL = 'mail';
 33: 
 34:     /**
 35:      * Send using a SMTP server.
 36:      *
 37:      * @var string
 38:      */
 39:     const MODE_SMTP = 'smtp';
 40: 
 41:     /**
 42:      * No sending.
 43:      * Useful if we actually don't want to send the message but just generate it.
 44:      *
 45:      * @var string
 46:      */
 47:     const MODE_NONE = 'none';
 48: 
 49:     /**
 50:      * Maximum line length.
 51:      *
 52:      * @var integer
 53:      */
 54:     const LINE_LENGTH = 74;
 55: 
 56:     /**
 57:      * Line ending.
 58:      *
 59:      * @var string
 60:      */
 61:     const LINE_END = "\n";
 62: 
 63:     /**
 64:      * Simple mail type.
 65:      *
 66:      * @var string
 67:      */
 68:     const TYPE_SIMPLE = 'simple';
 69: 
 70:     /**
 71:      * Email with a HTML and plaintext part.
 72:      *
 73:      * @var string
 74:      */
 75:     const TYPE_ALTERNATIVE = 'alternative';
 76: 
 77:     /**
 78:      * Email with a HTML and plaintext part and attachments.
 79:      *
 80:      * @var string
 81:      */
 82:     const TYPE_ALTERNATIVE_ATTACHMENTS = 'alternative_attachments';
 83: 
 84:     /**
 85:      * Email with attachments.
 86:      *
 87:      * @var string
 88:      */
 89:     const TYPE_ATTACHMENTS = 'attachments';
 90: 
 91:     /**
 92:      * Charset.
 93:      *
 94:      * @var string
 95:      */
 96:     private $charset = 'iso-8859-2';
 97: 
 98:     /**
 99:      * Hostname.
100:      *
101:      * @var string
102:      */
103:     private $hostname = '';
104: 
105:     /**
106:      * X-Mailer header value.
107:      *
108:      * @var string
109:      */
110:     private $xmailer = '';
111: 
112:     /**
113:      * Mail encoding (8bit, 7bit, binary, base64, quoted-printable).
114:      *
115:      * @var string
116:      */
117:     private $encoding = Jyxo_Mail_Encoding::QUOTED_PRINTABLE;
118: 
119:     /**
120:      * Email instance to be sent.
121:      *
122:      * @var Jyxo_Mail_Email
123:      */
124:     private $email = null;
125: 
126:     /**
127:      * SMTP server.
128:      *
129:      * @var string
130:      */
131:     private $smtpHost = 'localhost';
132: 
133:     /**
134:      * SMTP port.
135:      *
136:      * @var integer
137:      */
138:     private $smtpPort = 25;
139: 
140:     /**
141:      * SMTP HELO value.
142:      *
143:      * @var string
144:      */
145:     private $smtpHelo = '';
146: 
147:     /**
148:      * SMTP username.
149:      *
150:      * @var string
151:      */
152:     private $smtpUser = '';
153: 
154:     /**
155:      * SMTP password.
156:      *
157:      * @var string
158:      */
159:     private $smtpPsw = '';
160: 
161:     /**
162:      * SMTP connection timeout.
163:      *
164:      * @var string
165:      */
166:     private $smtpTimeout = 5;
167: 
168:     /**
169:      * Sending result.
170:      *
171:      * @var Jyxo_Mail_Sender_Result
172:      */
173:     private $result = null;
174: 
175:     /**
176:      * Generated boundaries of mail parts.
177:      *
178:      * @var array
179:      */
180:     private $boundary = array();
181: 
182:     /**
183:      * Sending mode.
184:      *
185:      * @var integer
186:      */
187:     private $mode = self::MODE_MAIL;
188: 
189:     /**
190:      * Email type.
191:      *
192:      * @var string
193:      */
194:     private $type = self::TYPE_SIMPLE;
195: 
196:     /**
197:      * Generated email headers.
198:      *
199:      * @var array
200:      */
201:     private $createdHeader = array();
202: 
203:     /**
204:      * Generated email body.
205:      *
206:      * @var string
207:      */
208:     private $createdBody = '';
209: 
210:     /**
211:      * Returns charset.
212:      *
213:      * @return string
214:      */
215:     public function getCharset()
216:     {
217:         return $this->charset;
218:     }
219: 
220:     /**
221:      * Sets charset.
222:      *
223:      * @param string $charset Final charset
224:      * @return Jyxo_Mail_Sender
225:      */
226:     public function setCharset($charset)
227:     {
228:         $this->charset = (string) $charset;
229: 
230:         return $this;
231:     }
232: 
233:     /**
234:      * Returns hostname.
235:      *
236:      * @return string
237:      */
238:     public function getHostname()
239:     {
240:         if (empty($this->hostname)) {
241:             $this->hostname = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
242:         }
243: 
244:         return $this->hostname;
245:     }
246: 
247:     /**
248:      * Sets hostname.
249:      *
250:      * @param string $hostname Hostname
251:      * @return Jyxo_Mail_Sender
252:      */
253:     public function setHostname($hostname)
254:     {
255:         $this->hostname = (string) $hostname;
256: 
257:         return $this;
258:     }
259: 
260:     /**
261:      * Returns X-Mailer header value.
262:      *
263:      * @return string
264:      */
265:     public function getXmailer()
266:     {
267:         return $this->xmailer;
268:     }
269: 
270:     /**
271:      * Sets X-Mailer header value.
272:      *
273:      * @param string $xmailer X-Mailer header value
274:      * @return Jyxo_Mail_Sender
275:      */
276:     public function setXmailer($xmailer)
277:     {
278:         $this->xmailer = (string) $xmailer;
279: 
280:         return $this;
281:     }
282: 
283:     /**
284:      * Returns encoding.
285:      *
286:      * @return string
287:      */
288:     public function getEncoding()
289:     {
290:         return $this->encoding;
291:     }
292: 
293:     /**
294:      * Sets encoding.
295:      *
296:      * @param string $encoding Encoding
297:      * @return Jyxo_Mail_Sender
298:      * @throws InvalidArgumentException If an incompatible encoding was provided
299:      */
300:     public function setEncoding($encoding)
301:     {
302:         if (!Jyxo_Mail_Encoding::isCompatible($encoding)) {
303:             throw new InvalidArgumentException(sprintf('Incompatible encoding %s.', $encoding));
304:         }
305: 
306:         $this->encoding = (string) $encoding;
307: 
308:         return $this;
309:     }
310: 
311:     /**
312:      * Returns the email to be sent.
313:      *
314:      * @return Jyxo_Mail_Email
315:      */
316:     public function getEmail()
317:     {
318:         return $this->email;
319:     }
320: 
321:     /**
322:      * Sets the email to be sent.
323:      *
324:      * @param Jyxo_Mail_Email $email Email instance
325:      * @return Jyxo_Mail_Sender
326:      */
327:     public function setEmail(Jyxo_Mail_Email $email)
328:     {
329:         $this->email = $email;
330: 
331:         return $this;
332:     }
333: 
334:     /**
335:      * Sets SMTP parameters.
336:      *
337:      * @param string $host Hostname
338:      * @param integer $port Port
339:      * @param string $helo HELO value
340:      * @param string $user Username
341:      * @param string $password Password
342:      * @param integer $timeout Connection timeout
343:      * @return Jyxo_Mail_Sender
344:      */
345:     public function setSmtp($host, $port = 25, $helo = '', $user = '', $password = '', $timeout = 5)
346:     {
347:         $this->smtpHost = (string) $host;
348:         $this->smtpPort = (int) $port;
349:         $this->smtpHelo = !empty($helo) ? (string) $helo : $this->getHostname();
350:         $this->smtpUser = (string) $user;
351:         $this->smtpPsw = (string) $password;
352:         $this->smtpTimeout = (int) $timeout;
353: 
354:         return $this;
355:     }
356: 
357:     /**
358:      * Sends an email using the given mode.
359:      *
360:      * @param string $mode Sending mode
361:      * @return Jyxo_Mail_Sender_Result
362:      * @throws InvalidArgumentException If an unknown mode was requested
363:      * @throws Jyxo_Mail_Sender_Exception On error
364:      * @throws Jyxo_Mail_Sender_CreateException If a required setting is missing
365:      */
366:     public function send($mode)
367:     {
368:         // Sending modes
369:         static $modes = array(
370:             self::MODE_SMTP => true,
371:             self::MODE_MAIL => true,
372:             self::MODE_NONE => true
373:         );
374:         if (!isset($modes[$mode])) {
375:             throw new InvalidArgumentException(sprintf('Unknown sending mode %s.', $mode));
376:         }
377:         $this->mode = (string) $mode;
378: 
379:         // Check of required parameters
380:         if (null === $this->email->from) {
381:             throw new Jyxo_Mail_Sender_CreateException('No sender was set.');
382:         }
383:         if ((count($this->email->to) + count($this->email->cc) + count($this->email->bcc)) < 1) {
384:             throw new Jyxo_Mail_Sender_CreateException('No recipient was set.');
385:         }
386: 
387:         // Creates a result
388:         $this->result = new Jyxo_Mail_Sender_Result();
389: 
390:         // Creates an email
391:         $this->create();
392:         $body = trim($this->createdBody);
393:         if (empty($body)) {
394:             throw new Jyxo_Mail_Sender_CreateException('No body was created.');
395:         }
396: 
397:         // Choose the appropriate sending method
398:         switch ($this->mode) {
399:             case self::MODE_SMTP:
400:                 $this->sendBySmtp();
401:                 break;
402:             case self::MODE_MAIL:
403:                 $this->sendByMail();
404:                 break;
405:             case self::MODE_NONE:
406:                 // Break missing intentionally
407:             default:
408:                 // No sending
409:                 break;
410:         }
411: 
412:         // Save the generated source code to the result
413:         $this->result->source = $this->getHeader() . $this->createdBody;
414: 
415:         // Flush of created email
416:         $this->createdHeader = array();
417:         $this->createdBody = '';
418: 
419:         return $this->result;
420:     }
421: 
422:     /**
423:      * Sends an email using the mail() function.
424:      *
425:      * @throws Jyxo_Mail_Sender_Exception On error
426:      */
427:     private function sendByMail()
428:     {
429:         $recipients = '';
430:         $iterator = new ArrayIterator($this->email->to);
431:         while ($iterator->valid()) {
432:             $recipients .= $this->formatAddress($iterator->current());
433: 
434:             $iterator->next();
435:             if ($iterator->valid()) {
436:                 $recipients .= ', ';
437:             }
438:         }
439: 
440:         $subject = $this->changeCharset($this->clearHeaderValue($this->email->subject));
441: 
442:         if (!mail($recipients, $this->encodeHeader($subject), $this->createdBody, $this->getHeader(array('To', 'Subject')))) {
443:             throw new Jyxo_Mail_Sender_Exception('Could not send the message.');
444:         }
445:     }
446: 
447:     /**
448:      * Sends an email using a SMTP server.
449:      *
450:      * @throws Jyxo_Mail_Sender_Exception On error
451:      */
452:     private function sendBySmtp()
453:     {
454:         if (!class_exists('Jyxo_Mail_Sender_Smtp')) {
455:             throw new Jyxo_Mail_Sender_Exception('Could not sent the message. Required class Jyxo_Mail_Sender_Smtp is missing.');
456:         }
457: 
458:         try {
459:             $smtp = new Jyxo_Mail_Sender_Smtp($this->smtpHost, $this->smtpPort, $this->smtpHelo, $this->smtpTimeout);
460:             $smtp->connect();
461:             if (!empty($this->smtpUser)) {
462:                 $smtp->auth($this->smtpUser, $this->smtpPsw);
463:             }
464: 
465:             // Sender
466:             $smtp->from($this->email->from->email);
467: 
468:             // Recipients
469:             $unknownRecipients = array();
470:             foreach (array_merge($this->email->to, $this->email->cc, $this->email->bcc) as $recipient) {
471:                 try {
472:                     $smtp->recipient($recipient->email);
473:                 } catch (Jyxo_Mail_Sender_SmtpException $e) {
474:                     $unknownRecipients[] = $recipient->email;
475:                 }
476:             }
477:             if (!empty($unknownRecipients)) {
478:                 throw new Jyxo_Mail_Sender_RecipientUnknownException('Unknown email recipients.', 0, $unknownRecipients);
479:             }
480: 
481:             // Data
482:             $smtp->data($this->getHeader(), $this->createdBody);
483:             $smtp->disconnect();
484:         } catch (Jyxo_Mail_Sender_RecipientUnknownException $e) {
485:             $smtp->disconnect();
486:             throw $e;
487:         } catch (Jyxo_Mail_Sender_SmtpException $e) {
488:             $smtp->disconnect();
489:             throw new Jyxo_Mail_Sender_Exception('Cannot send email: ' . $e->getMessage());
490:         }
491:     }
492: 
493:     /**
494:      * Creates an email.
495:      */
496:     private function create()
497:     {
498:         $uniqueId = md5(uniqid(time()));
499:         $hostname = $this->clearHeaderValue($this->getHostname());
500: 
501:         // Unique email Id
502:         $this->result->messageId = $uniqueId . '@' . $hostname;
503: 
504:         // Sending time
505:         $this->result->datetime = Jyxo_Time_Time::now();
506: 
507:         // Parts boundaries
508:         $this->boundary = array(
509:             1 => '====b1' . $uniqueId . '====' . $hostname . '====',
510:             2 => '====b2' . $uniqueId . '====' . $hostname . '===='
511:         );
512: 
513:         // Determine the message type
514:         if (!empty($this->email->attachments)) {
515:             // Are there any attachments?
516:             if (!empty($this->email->body->alternative)) {
517:                 // There is an alternative content
518:                 $this->type = self::TYPE_ALTERNATIVE_ATTACHMENTS;
519:             } else {
520:                 // No alternative content
521:                 $this->type = self::TYPE_ATTACHMENTS;
522:             }
523:         } else {
524:             // No attachments
525:             if (!empty($this->email->body->alternative)) {
526:                 // There is an alternative content
527:                 $this->type = self::TYPE_ALTERNATIVE;
528:             } else {
529:                 // No alternative content
530:                 $this->type = self::TYPE_SIMPLE;
531:             }
532:         }
533: 
534:         // Creates header and body
535:         $this->createHeader();
536:         $this->createBody();
537:     }
538: 
539:     /**
540:      * Creates header.
541:      */
542:     private function createHeader()
543:     {
544:         $this->addHeaderLine('Date', $this->result->datetime->email);
545:         $this->addHeaderLine('Return-Path', '<' . $this->clearHeaderValue($this->email->from->email) . '>');
546: 
547:         $this->addHeaderLine('From', $this->formatAddress($this->email->from));
548:         $this->addHeaderLine('Subject', $this->encodeHeader($this->changeCharset($this->clearHeaderValue($this->email->subject))));
549: 
550:         if (!empty($this->email->to)) {
551:             $this->addHeaderLine('To', $this->formatAddressList($this->email->to));
552:         } elseif (empty($this->email->cc)) {
553:             // Only blind carbon copy recipients
554:             $this->addHeaderLine('To', 'undisclosed-recipients:;');
555:         }
556: 
557:         if (!empty($this->email->cc)) {
558:             $this->addHeaderLine('Cc', $this->formatAddressList($this->email->cc));
559:         }
560:         if (!empty($this->email->bcc)) {
561:             $this->addHeaderLine('Bcc', $this->formatAddressList($this->email->bcc));
562:         }
563:         if (!empty($this->email->replyTo)) {
564:             $this->addHeaderLine('Reply-To', $this->formatAddressList($this->email->replyTo));
565:         }
566: 
567:         if (!empty($this->email->confirmReadingTo)) {
568:             $this->addHeaderLine('Disposition-Notification-To', $this->formatAddress($this->email->confirmReadingTo));
569:         }
570: 
571:         if (!empty($this->email->priority)) {
572:             $this->addHeaderLine('X-Priority', $this->email->priority);
573:         }
574: 
575:         $this->addHeaderLine('Message-ID', '<' . $this->result->messageId . '>');
576: 
577:         if (!empty($this->email->inReplyTo)) {
578:             $this->addHeaderLine('In-Reply-To', '<' . $this->clearHeaderValue($this->email->inReplyTo) . '>');
579:         }
580:         if (!empty($this->email->references)) {
581:             $references = $this->email->references;
582:             foreach ($references as $key => $reference) {
583:                 $references[$key] = $this->clearHeaderValue($reference);
584:             }
585:             $this->addHeaderLine('References', '<' . implode('> <', $references) . '>');
586:         }
587: 
588:         if (!empty($this->xmailer)) {
589:             $this->addHeaderLine('X-Mailer', $this->changeCharset($this->clearHeaderValue($this->xmailer)));
590:         }
591: 
592:         $this->addHeaderLine('MIME-Version', '1.0');
593: 
594:         // Custom headers
595:         foreach ($this->email->headers as $header) {
596:             $this->addHeaderLine($this->changeCharset($this->clearHeaderValue($header->name)), $this->encodeHeader($this->clearHeaderValue($header->value)));
597:         }
598: 
599:         switch ($this->type) {
600:             case self::TYPE_ATTACHMENTS:
601:                 // Break missing intentionally
602:             case self::TYPE_ALTERNATIVE_ATTACHMENTS:
603:                 $subtype = $this->email->hasInlineAttachments() ? 'related' : 'mixed';
604:                 $this->addHeaderLine('Content-Type', 'multipart/' . $subtype . ';' . self::LINE_END . ' boundary="' . $this->boundary[1] . '"');
605:                 break;
606:             case self::TYPE_ALTERNATIVE:
607:                 $this->addHeaderLine('Content-Type', 'multipart/alternative;' . self::LINE_END . ' boundary="' . $this->boundary[1] . '"');
608:                 break;
609:             case self::TYPE_SIMPLE:
610:                 // Break missing intentionally
611:             default:
612:                 $contentType = $this->email->body->isHtml() ? 'text/html' : 'text/plain';
613: 
614:                 $this->addHeaderLine('Content-Type', $contentType . '; charset="' . $this->clearHeaderValue($this->charset) . '"');
615:                 $this->addHeaderLine('Content-Transfer-Encoding', $this->encoding);
616:                 break;
617:         }
618:     }
619: 
620:     /**
621:      * Creates body.
622:      */
623:     private function createBody()
624:     {
625:         switch ($this->type) {
626:             case self::TYPE_ATTACHMENTS:
627:                 $contentType = $this->email->body->isHtml() ? 'text/html' : 'text/plain';
628: 
629:                 $this->createdBody .= $this->getBoundaryStart($this->boundary[1], $contentType, $this->charset, $this->encoding) . self::LINE_END;
630:                 $this->createdBody .= $this->encodeString($this->changeCharset($this->email->body->main), $this->encoding) . self::LINE_END;
631: 
632:                 $this->createdBody .= $this->attachAll();
633:                 break;
634:             case self::TYPE_ALTERNATIVE_ATTACHMENTS:
635:                 $this->createdBody .= '--' . $this->boundary[1] . self::LINE_END;
636:                 $this->createdBody .= 'Content-Type: multipart/alternative;' . self::LINE_END . ' boundary="' . $this->boundary[2] . '"' . self::LINE_END . self::LINE_END;
637:                 $this->createdBody .= $this->getBoundaryStart($this->boundary[2], 'text/plain', $this->charset, $this->encoding) . self::LINE_END;
638:                 $this->createdBody .= $this->encodeString($this->changeCharset($this->email->body->alternative), $this->encoding) . self::LINE_END;
639:                 $this->createdBody .= $this->getBoundaryStart($this->boundary[2], 'text/html', $this->charset, $this->encoding) . self::LINE_END;
640:                 $this->createdBody .= $this->encodeString($this->changeCharset($this->email->body->main), $this->encoding) . self::LINE_END;
641:                 $this->createdBody .= $this->getBoundaryEnd($this->boundary[2]) . self::LINE_END;
642: 
643:                 $this->createdBody .= $this->attachAll();
644:                 break;
645:             case self::TYPE_ALTERNATIVE:
646:                 $this->createdBody .= $this->getBoundaryStart($this->boundary[1], 'text/plain', $this->charset, $this->encoding) . self::LINE_END;
647:                 $this->createdBody .= $this->encodeString($this->changeCharset($this->email->body->alternative), $this->encoding) . self::LINE_END;
648:                 $this->createdBody .= $this->getBoundaryStart($this->boundary[1], 'text/html', $this->charset, $this->encoding) . self::LINE_END;
649:                 $this->createdBody .= $this->encodeString($this->changeCharset($this->email->body->main), $this->encoding) . self::LINE_END;
650:                 $this->createdBody .= $this->getBoundaryEnd($this->boundary[1]);
651:                 break;
652:             case self::TYPE_SIMPLE:
653:                 // Break missing intentionally
654:             default:
655:                 $this->createdBody = $this->encodeString($this->changeCharset($this->email->body->main), $this->encoding);
656:                 break;
657:         }
658:     }
659: 
660:     /**
661:      * Adds all attachments to the email.
662:      *
663:      * @return string
664:      */
665:     private function attachAll()
666:     {
667:         $mime = array();
668: 
669:         foreach ($this->email->attachments as $attachment) {
670:             $encoding = !empty($attachment->encoding) ? $attachment->encoding : Jyxo_Mail_Encoding::BASE64;
671:             $name = $this->changeCharset($this->clearHeaderValue($attachment->name));
672: 
673:             $mime[] = '--' . $this->boundary[1] . self::LINE_END;
674:             $mime[] = 'Content-Type: ' . $this->clearHeaderValue($attachment->mimeType) . ';' . self::LINE_END;
675:             $mime[] = ' name="' .  $this->encodeHeader($name) . '"' . self::LINE_END;
676:             $mime[] = 'Content-Transfer-Encoding: ' . $encoding . self::LINE_END;
677: 
678:             if ($attachment->isInline()) {
679:                 $mime[] = 'Content-ID: <' . $this->clearHeaderValue($attachment->cid) . '>' . self::LINE_END;
680:             }
681: 
682:             $mime[] = 'Content-Disposition: ' . $attachment->disposition . ';' . self::LINE_END;
683:             $mime[] = ' filename="' . $this->encodeHeader($name) . '"' . self::LINE_END . self::LINE_END;
684: 
685:             // Just fix line endings in case of encoded attachments, encode otherwise
686:             $mime[] = !empty($attachment->encoding)
687:                 ? Jyxo_String::fixLineEnding($attachment->content, self::LINE_END)
688:                 : $this->encodeString($attachment->content, $encoding);
689:             $mime[] = self::LINE_END . self::LINE_END;
690:         }
691: 
692:         $mime[] = '--' . $this->boundary[1] . '--' . self::LINE_END;
693: 
694:         return implode('', $mime);
695:     }
696: 
697:     /**
698:      * Returns headers except given lines.
699:      * Various sending methods need some headers removed, because they add them on their own.
700:      *
701:      * @param array $except Headers to be removed
702:      * @return string
703:      */
704:     private function getHeader(array $except = array())
705:     {
706:         $header = '';
707:         foreach ($this->createdHeader as $headerLine) {
708:             if (!in_array($headerLine['name'], $except)) {
709:                 $header .= $headerLine['name'] . ': ' . $headerLine['value'] . self::LINE_END;
710:             }
711:         }
712: 
713:         return $header . self::LINE_END;
714:     }
715: 
716:     /**
717:      * Formats an email address.
718:      *
719:      * @param Jyxo_Mail_Email_Address $address Address
720:      * @return string
721:      */
722:     private function formatAddress(Jyxo_Mail_Email_Address $address)
723:     {
724:         $name = $this->changeCharset($this->clearHeaderValue($address->name));
725:         $email = $this->clearHeaderValue($address->email);
726: 
727:         // No name is set
728:         if ((empty($name)) || ($name === $email)) {
729:             return $email;
730:         }
731: 
732:         if (preg_match('~[\200-\377]~', $name)) {
733:             // High ascii
734:             $name = $this->encodeHeader($name);
735:         } elseif (preg_match('~[^\w\s!#\$%&\'*+/=?^_`{|}\~-]~', $name)) {
736:             // Dangerous characters
737:             $name = '"' . $name . '"';
738:         }
739: 
740:         return $name . ' <' . $email . '>';
741:     }
742: 
743:     /**
744:      * Formats a list of addresses.
745:      *
746:      * @param array $addressList Array of addresses
747:      * @return string
748:      */
749:     private function formatAddressList(array $addressList)
750:     {
751:         $formated = '';
752:         while ($address = current($addressList)) {
753:             $formated .= $this->formatAddress($address);
754: 
755:             if (false !== next($addressList)) {
756:                 $formated .= ', ';
757:             }
758:         }
759:         return $formated;
760:     }
761: 
762:     /**
763:      * Adds a header line.
764:      *
765:      * @param string $name Header name
766:      * @param string $value Header value
767:      */
768:     private function addHeaderLine($name, $value)
769:     {
770:         $this->createdHeader[] = array(
771:             'name' => $name,
772:             'value' => trim($value)
773:         );
774:     }
775: 
776:     /**
777:      * Encodes headers.
778:      *
779:      * @param string $string Header definition
780:      * @return string
781:      */
782:     private function encodeHeader($string)
783:     {
784:         // There might be dangerous characters in the string
785:         $count = preg_match_all('~[^\040-\176]~', $string, $matches);
786:         if (0 === $count) {
787:             return $string;
788:         }
789: 
790:         // 7 is =? + ? + Q/B + ? + ?=
791:         $maxlen = 75 - 7 - strlen($this->charset);
792: 
793:         // Uses encoding with shorter output
794:         /*
795:         if (mb_strlen($string, $this->charset) / 3 < $count) {
796:             $encoding = 'B';
797:             $maxlen -= $maxlen % 4;
798:             $encoded = $this->encodeString($string, Jyxo_Mail_Encoding::BASE64, $maxlen);
799:         } else {
800:             $encoding = 'Q';
801:             $encoded = $this->encodeString($string, Jyxo_Mail_Encoding::QUOTED_PRINTABLE);
802:             $encoded = str_replace(array('?', ' '), array('=3F', '=20'), $encoded);
803:         }
804:         */
805: 
806:         // We have to use base64 always, because Thunderbird has problems with quoted-printable
807:         $encoding = 'B';
808:         $maxlen -= $maxlen % 4;
809:         $encoded = $this->encodeString($string, Jyxo_Mail_Encoding::BASE64, $maxlen);
810: 
811:         // Splitting to multiple lines
812:         $encoded = trim(preg_replace('~^(.*)$~m', ' =?' . $this->clearHeaderValue($this->charset) . '?' . $encoding . '?\1?=', $encoded));
813: 
814:         return $encoded;
815:     }
816: 
817:     /**
818:      * Encodes a string using the given encoding.
819:      *
820:      * @param string $string Input string
821:      * @param string $encoding Encoding
822:      * @param integer $lineLength Line length
823:      * @return string
824:      */
825:     private function encodeString($string, $encoding, $lineLength = self::LINE_LENGTH)
826:     {
827:         return Jyxo_Mail_Encoding::encode($string, $encoding, $lineLength, self::LINE_END);
828:     }
829: 
830:     /**
831:      * Returns a beginning of an email part.
832:      *
833:      * @param string $boundary Boundary
834:      * @param string $contentType Mime-type
835:      * @param string $charset Charset
836:      * @param string $encoding Encoding
837:      * @return string
838:      */
839:     private function getBoundaryStart($boundary, $contentType, $charset, $encoding)
840:     {
841:         $start = '--' . $boundary . self::LINE_END;
842:         $start .= 'Content-Type: ' . $contentType . '; charset="' . $this->clearHeaderValue($charset) . '"' . self::LINE_END;
843:         $start .= 'Content-Transfer-Encoding: ' . $encoding . self::LINE_END;
844: 
845:         return $start;
846:     }
847: 
848:     /**
849:      * Returns an end of an email part.
850:      *
851:      * @param string $boundary Boundary
852:      * @return string
853:      */
854:     private function getBoundaryEnd($boundary)
855:     {
856:         return self::LINE_END . '--' . $boundary . '--' . self::LINE_END;
857:     }
858: 
859:     /**
860:      * Clears headers from line endings.
861:      *
862:      * @param string $string Headers definition
863:      * @return string
864:      */
865:     private function clearHeaderValue($string)
866:     {
867:         return strtr(trim($string), "\r\n\t", '   ');
868:     }
869: 
870:     /**
871:      * Converts a string from UTF-8 into the email encoding.
872:      *
873:      * @param string $string Input string
874:      * @return string
875:      */
876:     private function changeCharset($string)
877:     {
878:         if ('utf-8' !== $this->charset) {
879:             // Triggers a notice on an invalid character
880:             $string = @iconv('utf-8', $this->charset . '//TRANSLIT', $string);
881:         }
882: 
883:         return $string;
884:     }
885: }
886: 
Jyxo PHP Library API documentation generated by ApiGen 2.3.0