Namespaces

  • 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

  • Message
  • MimePart
  • SendmailMailer
  • SmtpMailer

Interfaces

  • IMailer

Exceptions

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