vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php line 600

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