Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

   1  <?php
   2  /**
   3   * Copyright 2012-2017 Horde LLC (http://www.horde.org/)
   4   *
   5   * See the enclosed file LICENSE for license information (LGPL). If you
   6   * did not receive this file, see http://www.horde.org/licenses/lgpl21.
   7   *
   8   * @category  Horde
   9   * @copyright 2012-2017 Horde LLC
  10   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  11   * @package   Mime
  12   */
  13  
  14  /**
  15   * This class parses a multipart/related MIME part (RFC 2387) to provide
  16   * information on the part contents.
  17   *
  18   * @author    Michael Slusarz <slusarz@horde.org>
  19   * @category  Horde
  20   * @copyright 2012-2017 Horde LLC
  21   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  22   * @package   Mime
  23   */
  24  class Horde_Mime_Related implements IteratorAggregate
  25  {
  26      /**
  27       * Content IDs.
  28       *
  29       * @var array
  30       */
  31      protected $_cids = array();
  32  
  33      /**
  34       * Start ID.
  35       *
  36       * @var string
  37       */
  38      protected $_start;
  39  
  40      /**
  41       * Constructor.
  42       *
  43       * @param Horde_Mime_Part $mime_part  A MIME part object. Must be of
  44       *                                    type multipart/related.
  45       */
  46      public function __construct(Horde_Mime_Part $mime_part)
  47      {
  48          if ($mime_part->getType() != 'multipart/related') {
  49              throw new InvalidArgumentException('MIME part must be of type multipart/related');
  50          }
  51  
  52          $id = null;
  53          $ids = array();
  54          $related_id = $mime_part->getMimeId();
  55  
  56          /* Build a list of parts -> CIDs. */
  57          foreach ($mime_part->partIterator() as $val) {
  58              $part_id = $val->getMimeId();
  59              $ids[] = $part_id;
  60  
  61              if ((strcmp($related_id, $part_id) !== 0) &&
  62                  ($cid = $val->getContentId())) {
  63                  $this->_cids[$part_id] = $cid;
  64              }
  65          }
  66  
  67          /* Look at the 'start' parameter to determine which part to start
  68           * with. If no 'start' parameter, use the first part (RFC 2387
  69           * [3.1]). */
  70          if ($start = $mime_part->getContentTypeParameter('start')) {
  71              $id = $this->cidSearch(trim($start, '<> '));
  72          }
  73  
  74          if (empty($id)) {
  75              reset($ids);
  76              $id = next($ids);
  77          }
  78  
  79          $this->_start = $id;
  80      }
  81  
  82      /**
  83       * Return the start ID.
  84       *
  85       * @return string  The start ID.
  86       */
  87      public function startId()
  88      {
  89          return $this->_start;
  90      }
  91  
  92      /**
  93       * Search for a CID in the related part.
  94       *
  95       * @param string $cid  The CID to search for.
  96       *
  97       * @return string  The MIME ID or false if not found.
  98       */
  99      public function cidSearch($cid)
 100      {
 101          return array_search($cid, $this->_cids);
 102      }
 103  
 104      /**
 105       * Scan for CID strings in HTML data and replace with data returned from
 106       * a callback method.
 107       *
 108       * @param mixed $text         The HTML text (can be Horde_Domhtml object).
 109       * @param callback $callback  Callback method. Receives three arguments:
 110       *                            MIME ID, the attribute name containing the
 111       *                            content ID, and the node object. Expects
 112       *                            return value of URL to display the data.
 113       * @param string $charset     HTML data charset.
 114       *
 115       * @return Horde_Domhtml  A Horde_Domhtml object.
 116       */
 117      public function cidReplace($text, $callback, $charset = 'UTF-8')
 118      {
 119          $dom = ($text instanceof Horde_Domhtml)
 120              ? $text
 121              : new Horde_Domhtml($text, $charset);
 122  
 123          foreach ($dom as $node) {
 124              if ($node instanceof DOMElement) {
 125                  switch (Horde_String::lower($node->tagName)) {
 126                  case 'body':
 127                  case 'td':
 128                      $this->_cidReplace($node, 'background', $callback);
 129                      break;
 130  
 131                  case 'img':
 132                      $this->_cidReplace($node, 'src', $callback);
 133                      break;
 134                  }
 135              }
 136          }
 137  
 138          return $dom;
 139      }
 140  
 141      /**
 142       */
 143      protected function _cidReplace($node, $attribute, $callback)
 144      {
 145          if ($node->hasAttribute($attribute)) {
 146              $val = $node->getAttribute($attribute);
 147              if ((strpos($val, 'cid:') === 0) &&
 148                  ($id = $this->cidSearch(substr($val, 4)))) {
 149                  $node->setAttribute($attribute, call_user_func($callback, $id, $attribute, $node));
 150              }
 151          }
 152      }
 153  
 154      /* IteratorAggregate method. */
 155  
 156      public function getIterator()
 157      {
 158          return new ArrayIterator($this->_cids);
 159      }
 160  
 161  }