SimpleMimeEntity.php 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. <?php
  2. /*
  3. * This file is part of SwiftMailer.
  4. * (c) 2004-2009 Chris Corbyn
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * A MIME entity, in a multipart message.
  11. * @package Swift
  12. * @subpackage Mime
  13. * @author Chris Corbyn
  14. */
  15. class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
  16. {
  17. /** A collection of Headers for this mime entity */
  18. private $_headers;
  19. /** The body as a string, or a stream */
  20. private $_body;
  21. /** The encoder that encodes the body into a streamable format */
  22. private $_encoder;
  23. /** The grammar to use for id validation */
  24. private $_grammar;
  25. /** A mime bounary, if any is used */
  26. private $_boundary;
  27. /** Mime types to be used based on the nesting level */
  28. private $_compositeRanges = array(
  29. 'multipart/mixed' => array(self::LEVEL_TOP, self::LEVEL_MIXED),
  30. 'multipart/alternative' => array(self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE),
  31. 'multipart/related' => array(self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED)
  32. );
  33. /** A set of filter rules to define what level an entity should be nested at */
  34. private $_compoundLevelFilters = array();
  35. /** The nesting level of this entity */
  36. private $_nestingLevel = self::LEVEL_ALTERNATIVE;
  37. /** A KeyCache instance used during encoding and streaming */
  38. private $_cache;
  39. /** Direct descendants of this entity */
  40. private $_immediateChildren = array();
  41. /** All descendants of this entity */
  42. private $_children = array();
  43. /** The maximum line length of the body of this entity */
  44. private $_maxLineLength = 78;
  45. /** The order in which alternative mime types should appear */
  46. private $_alternativePartOrder = array(
  47. 'text/plain' => 1,
  48. 'text/html' => 2,
  49. 'multipart/related' => 3
  50. );
  51. /** The CID of this entity */
  52. private $_id;
  53. /** The key used for accessing the cache */
  54. private $_cacheKey;
  55. protected $_userContentType;
  56. /**
  57. * Create a new SimpleMimeEntity with $headers, $encoder and $cache.
  58. * @param Swift_Mime_HeaderSet $headers
  59. * @param Swift_Mime_ContentEncoder $encoder
  60. * @param Swift_KeyCache $cache
  61. * @param Swift_Mime_Grammar $grammar
  62. */
  63. public function __construct(Swift_Mime_HeaderSet $headers,
  64. Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache,
  65. Swift_Mime_Grammar $grammar)
  66. {
  67. $this->_cacheKey = uniqid();
  68. $this->_cache = $cache;
  69. $this->_headers = $headers;
  70. $this->_grammar = $grammar;
  71. $this->setEncoder($encoder);
  72. $this->_headers->defineOrdering(
  73. array('Content-Type', 'Content-Transfer-Encoding')
  74. );
  75. // This array specifies that, when the entire MIME document contains
  76. // $compoundLevel, then for each child within $level, if its Content-Type
  77. // is $contentType then it should be treated as if it's level is
  78. // $neededLevel instead. I tried to write that unambiguously! :-\
  79. // Data Structure:
  80. // array (
  81. // $compoundLevel => array(
  82. // $level => array(
  83. // $contentType => $neededLevel
  84. // )
  85. // )
  86. // )
  87. $this->_compoundLevelFilters = array(
  88. (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => array(
  89. self::LEVEL_ALTERNATIVE => array(
  90. 'text/plain' => self::LEVEL_ALTERNATIVE,
  91. 'text/html' => self::LEVEL_RELATED
  92. )
  93. )
  94. );
  95. $this->_id = $this->getRandomId();
  96. }
  97. /**
  98. * Generate a new Content-ID or Message-ID for this MIME entity.
  99. * @return string
  100. */
  101. public function generateId()
  102. {
  103. $this->setId($this->getRandomId());
  104. return $this->_id;
  105. }
  106. /**
  107. * Get the {@link Swift_Mime_HeaderSet} for this entity.
  108. * @return Swift_Mime_HeaderSet
  109. */
  110. public function getHeaders()
  111. {
  112. return $this->_headers;
  113. }
  114. /**
  115. * Get the nesting level of this entity.
  116. * @return int
  117. * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE
  118. */
  119. public function getNestingLevel()
  120. {
  121. return $this->_nestingLevel;
  122. }
  123. /**
  124. * Get the Content-type of this entity.
  125. * @return string
  126. */
  127. public function getContentType()
  128. {
  129. return $this->_getHeaderFieldModel('Content-Type');
  130. }
  131. /**
  132. * Set the Content-type of this entity.
  133. * @param string $type
  134. */
  135. public function setContentType($type)
  136. {
  137. $this->_setContentTypeInHeaders($type);
  138. // Keep track of the value so that if the content-type changes automatically
  139. // due to added child entities, it can be restored if they are later removed
  140. $this->_userContentType = $type;
  141. return $this;
  142. }
  143. /**
  144. * Get the CID of this entity.
  145. * The CID will only be present in headers if a Content-ID header is present.
  146. * @return string
  147. */
  148. public function getId()
  149. {
  150. return $this->_headers->has($this->_getIdField())
  151. ? current((array) $this->_getHeaderFieldModel($this->_getIdField()))
  152. : $this->_id;
  153. }
  154. /**
  155. * Set the CID of this entity.
  156. * @param string $id
  157. */
  158. public function setId($id)
  159. {
  160. if (!$this->_setHeaderFieldModel($this->_getIdField(), $id))
  161. {
  162. $this->_headers->addIdHeader($this->_getIdField(), $id);
  163. }
  164. $this->_id = $id;
  165. return $this;
  166. }
  167. /**
  168. * Get the description of this entity.
  169. * This value comes from the Content-Description header if set.
  170. * @return string
  171. */
  172. public function getDescription()
  173. {
  174. return $this->_getHeaderFieldModel('Content-Description');
  175. }
  176. /**
  177. * Set the description of this entity.
  178. * This method sets a value in the Content-ID header.
  179. * @param string $description
  180. */
  181. public function setDescription($description)
  182. {
  183. if (!$this->_setHeaderFieldModel('Content-Description', $description))
  184. {
  185. $this->_headers->addTextHeader('Content-Description', $description);
  186. }
  187. return $this;
  188. }
  189. /**
  190. * Get the maximum line length of the body of this entity.
  191. * @return int
  192. */
  193. public function getMaxLineLength()
  194. {
  195. return $this->_maxLineLength;
  196. }
  197. /**
  198. * Set the maximum line length of lines in this body.
  199. * Though not enforced by the library, lines should not exceed 1000 chars.
  200. * @param int $length
  201. */
  202. public function setMaxLineLength($length)
  203. {
  204. $this->_maxLineLength = $length;
  205. return $this;
  206. }
  207. /**
  208. * Get all children added to this entity.
  209. * @return array of Swift_Mime_Entity
  210. */
  211. public function getChildren()
  212. {
  213. return $this->_children;
  214. }
  215. /**
  216. * Set all children of this entity.
  217. * @param array $children Swiift_Mime_Entity instances
  218. * @param int $compoundLevel For internal use only
  219. */
  220. public function setChildren(array $children, $compoundLevel = null)
  221. {
  222. //TODO: Try to refactor this logic
  223. $compoundLevel = isset($compoundLevel)
  224. ? $compoundLevel
  225. : $this->_getCompoundLevel($children)
  226. ;
  227. $immediateChildren = array();
  228. $grandchildren = array();
  229. $newContentType = $this->_userContentType;
  230. foreach ($children as $child)
  231. {
  232. $level = $this->_getNeededChildLevel($child, $compoundLevel);
  233. if (empty($immediateChildren)) //first iteration
  234. {
  235. $immediateChildren = array($child);
  236. }
  237. else
  238. {
  239. $nextLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel);
  240. if ($nextLevel == $level)
  241. {
  242. $immediateChildren[] = $child;
  243. }
  244. elseif ($level < $nextLevel)
  245. {
  246. //Re-assign immediateChildren to grandchilden
  247. $grandchildren = array_merge($grandchildren, $immediateChildren);
  248. //Set new children
  249. $immediateChildren = array($child);
  250. }
  251. else
  252. {
  253. $grandchildren[] = $child;
  254. }
  255. }
  256. }
  257. if (!empty($immediateChildren))
  258. {
  259. $lowestLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel);
  260. //Determine which composite media type is needed to accomodate the
  261. // immediate children
  262. foreach ($this->_compositeRanges as $mediaType => $range)
  263. {
  264. if ($lowestLevel > $range[0]
  265. && $lowestLevel <= $range[1])
  266. {
  267. $newContentType = $mediaType;
  268. break;
  269. }
  270. }
  271. //Put any grandchildren in a subpart
  272. if (!empty($grandchildren))
  273. {
  274. $subentity = $this->_createChild();
  275. $subentity->_setNestingLevel($lowestLevel);
  276. $subentity->setChildren($grandchildren, $compoundLevel);
  277. array_unshift($immediateChildren, $subentity);
  278. }
  279. }
  280. $this->_immediateChildren = $immediateChildren;
  281. $this->_children = $children;
  282. $this->_setContentTypeInHeaders($newContentType);
  283. $this->_fixHeaders();
  284. $this->_sortChildren();
  285. return $this;
  286. }
  287. /**
  288. * Get the body of this entity as a string.
  289. * @return string
  290. */
  291. public function getBody()
  292. {
  293. return ($this->_body instanceof Swift_OutputByteStream)
  294. ? $this->_readStream($this->_body)
  295. : $this->_body;
  296. }
  297. /**
  298. * Set the body of this entity, either as a string, or as an instance of
  299. * {@link Swift_OutputByteStream}.
  300. * @param mixed $body
  301. * @param string $contentType optional
  302. */
  303. public function setBody($body, $contentType = null)
  304. {
  305. if ($body !== $this->_body)
  306. {
  307. $this->_clearCache();
  308. }
  309. $this->_body = $body;
  310. if (isset($contentType))
  311. {
  312. $this->setContentType($contentType);
  313. }
  314. return $this;
  315. }
  316. /**
  317. * Get the encoder used for the body of this entity.
  318. * @return Swift_Mime_ContentEncoder
  319. */
  320. public function getEncoder()
  321. {
  322. return $this->_encoder;
  323. }
  324. /**
  325. * Set the encoder used for the body of this entity.
  326. * @param Swift_Mime_ContentEncoder $encoder
  327. */
  328. public function setEncoder(Swift_Mime_ContentEncoder $encoder)
  329. {
  330. if ($encoder !== $this->_encoder)
  331. {
  332. $this->_clearCache();
  333. }
  334. $this->_encoder = $encoder;
  335. $this->_setEncoding($encoder->getName());
  336. $this->_notifyEncoderChanged($encoder);
  337. return $this;
  338. }
  339. /**
  340. * Get the boundary used to separate children in this entity.
  341. * @return string
  342. */
  343. public function getBoundary()
  344. {
  345. if (!isset($this->_boundary))
  346. {
  347. $this->_boundary = '_=_swift_v4_' . time() . uniqid() . '_=_';
  348. }
  349. return $this->_boundary;
  350. }
  351. /**
  352. * Set the boundary used to separate children in this entity.
  353. * @param string $boundary
  354. * @throws Swift_RfcComplianceException
  355. */
  356. public function setBoundary($boundary)
  357. {
  358. $this->_assertValidBoundary($boundary);
  359. $this->_boundary = $boundary;
  360. return $this;
  361. }
  362. /**
  363. * Receive notification that the charset of this entity, or a parent entity
  364. * has changed.
  365. * @param string $charset
  366. */
  367. public function charsetChanged($charset)
  368. {
  369. $this->_notifyCharsetChanged($charset);
  370. }
  371. /**
  372. * Receive notification that the encoder of this entity or a parent entity
  373. * has changed.
  374. * @param Swift_Mime_ContentEncoder $encoder
  375. */
  376. public function encoderChanged(Swift_Mime_ContentEncoder $encoder)
  377. {
  378. $this->_notifyEncoderChanged($encoder);
  379. }
  380. /**
  381. * Get this entire entity as a string.
  382. * @return string
  383. */
  384. public function toString()
  385. {
  386. $string = $this->_headers->toString();
  387. if (isset($this->_body) && empty($this->_immediateChildren))
  388. {
  389. if ($this->_cache->hasKey($this->_cacheKey, 'body'))
  390. {
  391. $body = $this->_cache->getString($this->_cacheKey, 'body');
  392. }
  393. else
  394. {
  395. $body = "\r\n" . $this->_encoder->encodeString($this->getBody(), 0,
  396. $this->getMaxLineLength()
  397. );
  398. $this->_cache->setString($this->_cacheKey, 'body', $body,
  399. Swift_KeyCache::MODE_WRITE
  400. );
  401. }
  402. $string .= $body;
  403. }
  404. if (!empty($this->_immediateChildren))
  405. {
  406. foreach ($this->_immediateChildren as $child)
  407. {
  408. $string .= "\r\n\r\n--" . $this->getBoundary() . "\r\n";
  409. $string .= $child->toString();
  410. }
  411. $string .= "\r\n\r\n--" . $this->getBoundary() . "--\r\n";
  412. }
  413. return $string;
  414. }
  415. /**
  416. * Returns a string representation of this object.
  417. *
  418. * @return string
  419. *
  420. * @see toString()
  421. */
  422. public function __toString()
  423. {
  424. return $this->toString();
  425. }
  426. /**
  427. * Write this entire entity to a {@link Swift_InputByteStream}.
  428. * @param Swift_InputByteStream
  429. */
  430. public function toByteStream(Swift_InputByteStream $is)
  431. {
  432. $is->write($this->_headers->toString());
  433. $is->commit();
  434. if (empty($this->_immediateChildren))
  435. {
  436. if (isset($this->_body))
  437. {
  438. if ($this->_cache->hasKey($this->_cacheKey, 'body'))
  439. {
  440. $this->_cache->exportToByteStream($this->_cacheKey, 'body', $is);
  441. }
  442. else
  443. {
  444. $cacheIs = $this->_cache->getInputByteStream($this->_cacheKey, 'body');
  445. if ($cacheIs)
  446. {
  447. $is->bind($cacheIs);
  448. }
  449. $is->write("\r\n");
  450. if ($this->_body instanceof Swift_OutputByteStream)
  451. {
  452. $this->_body->setReadPointer(0);
  453. $this->_encoder->encodeByteStream($this->_body, $is, 0,
  454. $this->getMaxLineLength()
  455. );
  456. }
  457. else
  458. {
  459. $is->write($this->_encoder->encodeString(
  460. $this->getBody(), 0, $this->getMaxLineLength()
  461. ));
  462. }
  463. if ($cacheIs)
  464. {
  465. $is->unbind($cacheIs);
  466. }
  467. }
  468. }
  469. }
  470. if (!empty($this->_immediateChildren))
  471. {
  472. foreach ($this->_immediateChildren as $child)
  473. {
  474. $is->write("\r\n\r\n--" . $this->getBoundary() . "\r\n");
  475. $child->toByteStream($is);
  476. }
  477. $is->write("\r\n\r\n--" . $this->getBoundary() . "--\r\n");
  478. }
  479. }
  480. // -- Protected methods
  481. /**
  482. * Get the name of the header that provides the ID of this entity */
  483. protected function _getIdField()
  484. {
  485. return 'Content-ID';
  486. }
  487. /**
  488. * Get the model data (usually an array or a string) for $field.
  489. */
  490. protected function _getHeaderFieldModel($field)
  491. {
  492. if ($this->_headers->has($field))
  493. {
  494. return $this->_headers->get($field)->getFieldBodyModel();
  495. }
  496. }
  497. /**
  498. * Set the model data for $field.
  499. */
  500. protected function _setHeaderFieldModel($field, $model)
  501. {
  502. if ($this->_headers->has($field))
  503. {
  504. $this->_headers->get($field)->setFieldBodyModel($model);
  505. return true;
  506. }
  507. else
  508. {
  509. return false;
  510. }
  511. }
  512. /**
  513. * Get the parameter value of $parameter on $field header.
  514. */
  515. protected function _getHeaderParameter($field, $parameter)
  516. {
  517. if ($this->_headers->has($field))
  518. {
  519. return $this->_headers->get($field)->getParameter($parameter);
  520. }
  521. }
  522. /**
  523. * Set the parameter value of $parameter on $field header.
  524. */
  525. protected function _setHeaderParameter($field, $parameter, $value)
  526. {
  527. if ($this->_headers->has($field))
  528. {
  529. $this->_headers->get($field)->setParameter($parameter, $value);
  530. return true;
  531. }
  532. else
  533. {
  534. return false;
  535. }
  536. }
  537. /**
  538. * Re-evaluate what content type and encoding should be used on this entity.
  539. */
  540. protected function _fixHeaders()
  541. {
  542. if (count($this->_immediateChildren))
  543. {
  544. $this->_setHeaderParameter('Content-Type', 'boundary',
  545. $this->getBoundary()
  546. );
  547. $this->_headers->remove('Content-Transfer-Encoding');
  548. }
  549. else
  550. {
  551. $this->_setHeaderParameter('Content-Type', 'boundary', null);
  552. $this->_setEncoding($this->_encoder->getName());
  553. }
  554. }
  555. /**
  556. * Get the KeyCache used in this entity.
  557. */
  558. protected function _getCache()
  559. {
  560. return $this->_cache;
  561. }
  562. /**
  563. * Get the grammar used for validation.
  564. * @return Swift_Mime_Grammar
  565. */
  566. protected function _getGrammar()
  567. {
  568. return $this->_grammar;
  569. }
  570. /**
  571. * Empty the KeyCache for this entity.
  572. */
  573. protected function _clearCache()
  574. {
  575. $this->_cache->clearKey($this->_cacheKey, 'body');
  576. }
  577. /**
  578. * Returns a random Content-ID or Message-ID.
  579. * @return string
  580. */
  581. protected function getRandomId()
  582. {
  583. $idLeft = time() . '.' . uniqid();
  584. $idRight = !empty($_SERVER['SERVER_NAME'])
  585. ? $_SERVER['SERVER_NAME']
  586. : 'swift.generated';
  587. $id = $idLeft . '@' . $idRight;
  588. try
  589. {
  590. $this->_assertValidId($id);
  591. }
  592. catch (Swift_RfcComplianceException $e)
  593. {
  594. $id = $idLeft . '@swift.generated';
  595. }
  596. return $id;
  597. }
  598. // -- Private methods
  599. private function _readStream(Swift_OutputByteStream $os)
  600. {
  601. $string = '';
  602. while (false !== $bytes = $os->read(8192))
  603. {
  604. $string .= $bytes;
  605. }
  606. return $string;
  607. }
  608. private function _setEncoding($encoding)
  609. {
  610. if (!$this->_setHeaderFieldModel('Content-Transfer-Encoding', $encoding))
  611. {
  612. $this->_headers->addTextHeader('Content-Transfer-Encoding', $encoding);
  613. }
  614. }
  615. private function _assertValidBoundary($boundary)
  616. {
  617. if (!preg_match(
  618. '/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di',
  619. $boundary))
  620. {
  621. throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.');
  622. }
  623. }
  624. private function _setContentTypeInHeaders($type)
  625. {
  626. if (!$this->_setHeaderFieldModel('Content-Type', $type))
  627. {
  628. $this->_headers->addParameterizedHeader('Content-Type', $type);
  629. }
  630. }
  631. private function _setNestingLevel($level)
  632. {
  633. $this->_nestingLevel = $level;
  634. }
  635. private function _getCompoundLevel($children)
  636. {
  637. $level = 0;
  638. foreach ($children as $child)
  639. {
  640. $level |= $child->getNestingLevel();
  641. }
  642. return $level;
  643. }
  644. private function _getNeededChildLevel($child, $compoundLevel)
  645. {
  646. $filter = array();
  647. foreach ($this->_compoundLevelFilters as $bitmask => $rules)
  648. {
  649. if (($compoundLevel & $bitmask) === $bitmask)
  650. {
  651. $filter = $rules + $filter;
  652. }
  653. }
  654. $realLevel = $child->getNestingLevel();
  655. $lowercaseType = strtolower($child->getContentType());
  656. if (isset($filter[$realLevel])
  657. && isset($filter[$realLevel][$lowercaseType]))
  658. {
  659. return $filter[$realLevel][$lowercaseType];
  660. }
  661. else
  662. {
  663. return $realLevel;
  664. }
  665. }
  666. private function _createChild()
  667. {
  668. return new self($this->_headers->newInstance(),
  669. $this->_encoder, $this->_cache, $this->_grammar);
  670. }
  671. private function _notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder)
  672. {
  673. foreach ($this->_immediateChildren as $child)
  674. {
  675. $child->encoderChanged($encoder);
  676. }
  677. }
  678. private function _notifyCharsetChanged($charset)
  679. {
  680. $this->_encoder->charsetChanged($charset);
  681. $this->_headers->charsetChanged($charset);
  682. foreach ($this->_immediateChildren as $child)
  683. {
  684. $child->charsetChanged($charset);
  685. }
  686. }
  687. private function _sortChildren()
  688. {
  689. $shouldSort = false;
  690. foreach ($this->_immediateChildren as $child)
  691. {
  692. //NOTE: This include alternative parts moved into a related part
  693. if ($child->getNestingLevel() == self::LEVEL_ALTERNATIVE)
  694. {
  695. $shouldSort = true;
  696. break;
  697. }
  698. }
  699. //Sort in order of preference, if there is one
  700. if ($shouldSort)
  701. {
  702. usort($this->_immediateChildren, array($this, '_childSortAlgorithm'));
  703. }
  704. }
  705. private function _childSortAlgorithm($a, $b)
  706. {
  707. $typePrefs = array();
  708. $types = array(
  709. strtolower($a->getContentType()),
  710. strtolower($b->getContentType())
  711. );
  712. foreach ($types as $type)
  713. {
  714. $typePrefs[] = (array_key_exists($type, $this->_alternativePartOrder))
  715. ? $this->_alternativePartOrder[$type]
  716. : (max($this->_alternativePartOrder) + 1);
  717. }
  718. return ($typePrefs[0] >= $typePrefs[1]) ? 1 : -1;
  719. }
  720. // -- Destructor
  721. /**
  722. * Empties it's own contents from the cache.
  723. */
  724. public function __destruct()
  725. {
  726. $this->_cache->clearAll($this->_cacheKey);
  727. }
  728. /**
  729. * Throws an Exception if the id passed does not comply with RFC 2822.
  730. * @param string $id
  731. * @throws Swift_RfcComplianceException
  732. */
  733. private function _assertValidId($id)
  734. {
  735. if (!preg_match(
  736. '/^' . $this->_grammar->getDefinition('id-left') . '@' .
  737. $this->_grammar->getDefinition('id-right') . '$/D',
  738. $id
  739. ))
  740. {
  741. throw new Swift_RfcComplianceException(
  742. 'Invalid ID given <' . $id . '>'
  743. );
  744. }
  745. }
  746. }