Packages

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • NMail
  • NMailMimePart
  • NSendmailMailer
  • NSmtpMailer

Interfaces

  • IMailer

Exceptions

  • NSmtpException
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  * @package Nette\Mail
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * MIME message part.
 17:  *
 18:  * @author     David Grudl
 19:  *
 20:  * @property-read array $headers
 21:  * @property-write $contentType
 22:  * @property   string $encoding
 23:  * @property   mixed $body
 24:  * @package Nette\Mail
 25:  */
 26: class NMailMimePart extends NObject
 27: {
 28:     /** encoding */
 29:     const ENCODING_BASE64 = 'base64',
 30:         ENCODING_7BIT = '7bit',
 31:         ENCODING_8BIT = '8bit',
 32:         ENCODING_QUOTED_PRINTABLE = 'quoted-printable';
 33: 
 34:     /** @internal */
 35:     const EOL = "\r\n";
 36:     const LINE_LENGTH = 76;
 37: 
 38:     /** @var array */
 39:     private $headers = array();
 40: 
 41:     /** @var array */
 42:     private $parts = array();
 43: 
 44:     /** @var string */
 45:     private $body;
 46: 
 47: 
 48:     /**
 49:      * Sets a header.
 50:      * @param  string
 51:      * @param  string|array  value or pair email => name
 52:      * @param  bool
 53:      * @return self
 54:      */
 55:     public function setHeader($name, $value, $append = FALSE)
 56:     {
 57:         if (!$name || preg_match('#[^a-z0-9-]#i', $name)) {
 58:             throw new InvalidArgumentException("Header name must be non-empty alphanumeric string, '$name' given.");
 59:         }
 60: 
 61:         if ($value == NULL) { // intentionally ==
 62:             if (!$append) {
 63:                 unset($this->headers[$name]);
 64:             }
 65: 
 66:         } elseif (is_array($value)) { // email
 67:             $tmp = & $this->headers[$name];
 68:             if (!$append || !is_array($tmp)) {
 69:                 $tmp = array();
 70:             }
 71: 
 72:             foreach ($value as $email => $recipient) {
 73:                 if ($recipient !== NULL && !NStrings::checkEncoding($recipient)) {
 74:                     NValidators::assert($recipient, 'unicode', "header '$name'");
 75:                 }
 76:                 if (preg_match('#[\r\n]#', $recipient)) {
 77:                     throw new InvalidArgumentException("Name must not contain line separator.");
 78:                 }
 79:                 NValidators::assert($email, 'email', "header '$name'");
 80:                 $tmp[$email] = $recipient;
 81:             }
 82: 
 83:         } else {
 84:             $value = (string) $value;
 85:             if (!NStrings::checkEncoding($value)) {
 86:                 throw new InvalidArgumentException("Header is not valid UTF-8 string.");
 87:             }
 88:             $this->headers[$name] = preg_replace('#[\r\n]+#', ' ', $value);
 89:         }
 90:         return $this;
 91:     }
 92: 
 93: 
 94:     /**
 95:      * Returns a header.
 96:      * @param  string
 97:      * @return mixed
 98:      */
 99:     public function getHeader($name)
100:     {
101:         return isset($this->headers[$name]) ? $this->headers[$name] : NULL;
102:     }
103: 
104: 
105:     /**
106:      * Removes a header.
107:      * @param  string
108:      * @return self
109:      */
110:     public function clearHeader($name)
111:     {
112:         unset($this->headers[$name]);
113:         return $this;
114:     }
115: 
116: 
117:     /**
118:      * Returns an encoded header.
119:      * @param  string
120:      * @param  string
121:      * @return string
122:      */
123:     public function getEncodedHeader($name)
124:     {
125:         $offset = strlen($name) + 2; // colon + space
126: 
127:         if (!isset($this->headers[$name])) {
128:             return NULL;
129: 
130:         } elseif (is_array($this->headers[$name])) {
131:             $s = '';
132:             foreach ($this->headers[$name] as $email => $name) {
133:                 if ($name != NULL) { // intentionally ==
134:                     $s .= self::encodeHeader($name, $offset, strpbrk($name, '.,;<@>()[]"=?'));
135:                     $email = " <$email>";
136:                 }
137:                 $email .= ',';
138:                 if ($s !== '' && $offset + strlen($email) > self::LINE_LENGTH) {
139:                     $s .= self::EOL . "\t";
140:                     $offset = 1;
141:                 }
142:                 $s .= $email;
143:                 $offset += strlen($email);
144:             }
145:             return substr($s, 0, -1); // last comma
146: 
147:         } elseif (preg_match('#^(\S+; (?:file)?name=)"(.*)"\z#', $this->headers[$name], $m)) { // Content-Disposition
148:             $offset += strlen($m[1]);
149:             return $m[1] . '"' . self::encodeHeader($m[2], $offset) . '"';
150: 
151:         } else {
152:             return self::encodeHeader($this->headers[$name], $offset);
153:         }
154:     }
155: 
156: 
157:     /**
158:      * Returns all headers.
159:      * @return array
160:      */
161:     public function getHeaders()
162:     {
163:         return $this->headers;
164:     }
165: 
166: 
167:     /**
168:      * Sets Content-Type header.
169:      * @param  string
170:      * @param  string
171:      * @return self
172:      */
173:     public function setContentType($contentType, $charset = NULL)
174:     {
175:         $this->setHeader('Content-Type', $contentType . ($charset ? "; charset=$charset" : ''));
176:         return $this;
177:     }
178: 
179: 
180:     /**
181:      * Sets Content-Transfer-Encoding header.
182:      * @param  string
183:      * @return self
184:      */
185:     public function setEncoding($encoding)
186:     {
187:         $this->setHeader('Content-Transfer-Encoding', $encoding);
188:         return $this;
189:     }
190: 
191: 
192:     /**
193:      * Returns Content-Transfer-Encoding header.
194:      * @return string
195:      */
196:     public function getEncoding()
197:     {
198:         return $this->getHeader('Content-Transfer-Encoding');
199:     }
200: 
201: 
202:     /**
203:      * Adds or creates new multipart.
204:      * @return NMailMimePart
205:      */
206:     public function addPart(NMailMimePart $part = NULL)
207:     {
208:         return $this->parts[] = $part === NULL ? new self : $part;
209:     }
210: 
211: 
212:     /**
213:      * Sets textual body.
214:      * @return self
215:      */
216:     public function setBody($body)
217:     {
218:         $this->body = $body;
219:         return $this;
220:     }
221: 
222: 
223:     /**
224:      * Gets textual body.
225:      * @return mixed
226:      */
227:     public function getBody()
228:     {
229:         return $this->body;
230:     }
231: 
232: 
233:     /********************* building ****************d*g**/
234: 
235: 
236:     /**
237:      * Returns encoded message.
238:      * @return string
239:      */
240:     public function generateMessage()
241:     {
242:         $output = '';
243:         $boundary = '--------' . NStrings::random();
244: 
245:         foreach ($this->headers as $name => $value) {
246:             $output .= $name . ': ' . $this->getEncodedHeader($name);
247:             if ($this->parts && $name === 'Content-Type') {
248:                 $output .= ';' . self::EOL . "\tboundary=\"$boundary\"";
249:             }
250:             $output .= self::EOL;
251:         }
252:         $output .= self::EOL;
253: 
254:         $body = (string) $this->body;
255:         if ($body !== '') {
256:             switch ($this->getEncoding()) {
257:                 case self::ENCODING_QUOTED_PRINTABLE:
258:                     $output .= function_exists('quoted_printable_encode') ? quoted_printable_encode($body) : self::encodeQuotedPrintable($body);
259:                     break;
260: 
261:                 case self::ENCODING_BASE64:
262:                     $output .= rtrim(chunk_split(base64_encode($body), self::LINE_LENGTH, self::EOL));
263:                     break;
264: 
265:                 case self::ENCODING_7BIT:
266:                     $body = preg_replace('#[\x80-\xFF]+#', '', $body);
267:                     // break intentionally omitted
268: 
269:                 case self::ENCODING_8BIT:
270:                     $body = str_replace(array("\x00", "\r"), '', $body);
271:                     $body = str_replace("\n", self::EOL, $body);
272:                     $output .= $body;
273:                     break;
274: 
275:                 default:
276:                     throw new InvalidStateException('Unknown encoding.');
277:             }
278:         }
279: 
280:         if ($this->parts) {
281:             if (substr($output, -strlen(self::EOL)) !== self::EOL) {
282:                 $output .= self::EOL;
283:             }
284:             foreach ($this->parts as $part) {
285:                 $output .= '--' . $boundary . self::EOL . $part->generateMessage() . self::EOL;
286:             }
287:             $output .= '--' . $boundary.'--';
288:         }
289: 
290:         return $output;
291:     }
292: 
293: 
294:     /********************* QuotedPrintable helpers ****************d*g**/
295: 
296: 
297:     /**
298:      * Converts a 8 bit header to a string.
299:      * @param  string
300:      * @param  int
301:      * @param  bool
302:      * @return string
303:      */
304:     private static function encodeHeader($s, & $offset = 0, $force = FALSE)
305:     {
306:         $o = '';
307:         if ($offset >= 55) { // maximum for iconv_mime_encode
308:             $o = self::EOL . "\t";
309:             $offset = 1;
310:         }
311: 
312:         if (!$force && strspn($s, "!\"#$%&\'()*+,-./0123456789:;<>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^`abcdefghijklmnopqrstuvwxyz{|}=? _\r\n\t") === strlen($s)
313:             && ($offset + strlen($s) <= self::LINE_LENGTH)
314:         ) {
315:             $offset += strlen($s);
316:             return $o . $s;
317:         }
318: 
319:         $o .= str_replace("\n ", "\n\t", substr(iconv_mime_encode(str_repeat(' ', $offset), $s, array(
320:             'scheme' => 'B', // Q is broken
321:             'input-charset' => 'UTF-8',
322:             'output-charset' => 'UTF-8',
323:         )), $offset + 2));
324: 
325:         $offset = strlen($o) - strrpos($o, "\n");
326:         return $o;
327:     }
328: 
329: 
330:     /**
331:      * Converts a 8 bit string to a quoted-printable string.
332:      * @param  string
333:      * @return string
334:      */public static function encodeQuotedPrintable($s)
335:     {
336:         $range = '!"#$%&\'()*+,-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}'; // \x21-\x7E without \x3D
337:         $pos = 0;
338:         $len = 0;
339:         $o = '';
340:         $size = strlen($s);
341:         while ($pos < $size) {
342:             if ($l = strspn($s, $range, $pos)) {
343:                 while ($len + $l > self::LINE_LENGTH - 1) { // 1 = length of suffix =
344:                     $lx = self::LINE_LENGTH - $len - 1;
345:                     $o .= substr($s, $pos, $lx) . '=' . self::EOL;
346:                     $pos += $lx;
347:                     $l -= $lx;
348:                     $len = 0;
349:                 }
350:                 $o .= substr($s, $pos, $l);
351:                 $len += $l;
352:                 $pos += $l;
353: 
354:             } else {
355:                 $len += 3;
356:                 if ($len > self::LINE_LENGTH - 1) {
357:                     $o .= '=' . self::EOL;
358:                     $len = 3;
359:                 }
360:                 $o .= '=' . strtoupper(bin2hex($s[$pos]));
361:                 $pos++;
362:             }
363:         }
364:         return rtrim($o, '=' . self::EOL);
365:     }
366: 
367: }
368: 
Nette Framework 2.0.13 (for PHP 5.2, prefixed) API API documentation generated by ApiGen 2.8.0