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