[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/horde/framework/Horde/Imap/Client/ -> Ids.php (source)

   1  <?php
   2  /**
   3   * Copyright 2011-2014 Horde LLC (http://www.horde.org/)
   4   *
   5   * See the enclosed file COPYING 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 2011-2014 Horde LLC
  10   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  11   * @package   Imap_Client
  12   */
  13  
  14  /**
  15   * An object that provides a way to identify a list of IMAP indices.
  16   *
  17   * @author    Michael Slusarz <slusarz@horde.org>
  18   * @category  Horde
  19   * @copyright 2011-2014 Horde LLC
  20   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  21   * @package   Imap_Client
  22   *
  23   * @property-read boolean $all  Does this represent an ALL message set?
  24   * @property-read array $ids  The list of IDs.
  25   * @property-read boolean $largest  Does this represent the largest ID in use?
  26   * @property-read string $max  The largest ID (@since 2.20.0).
  27   * @property-read string $min  The smallest ID (@since 2.20.0).
  28   * @property-read string $range_string  Generates a range string consisting of
  29   *                                      all messages between begin and end of
  30   *                                      ID list.
  31   * @property-read boolean $search_res  Does this represent a search result?
  32   * @property-read boolean $sequence  Are these sequence IDs? If false, these
  33   *                                   are UIDs.
  34   * @property-read boolean $special  True if this is a "special" ID
  35   *                                  representation.
  36   * @property-read string $tostring  Return the non-sorted string
  37   *                                  representation.
  38   * @property-read string $tostring_sort  Return the sorted string
  39   *                                       representation.
  40   */
  41  class Horde_Imap_Client_Ids implements Countable, Iterator, Serializable
  42  {
  43      /**
  44       * "Special" representation constants.
  45       */
  46      const ALL = "\01";
  47      const SEARCH_RES = "\02";
  48      const LARGEST = "\03";
  49  
  50      /**
  51       * Allow duplicate IDs?
  52       *
  53       * @var boolean
  54       */
  55      public $duplicates = false;
  56  
  57      /**
  58       * List of IDs.
  59       *
  60       * @var mixed
  61       */
  62      protected $_ids = array();
  63  
  64      /**
  65       * Are IDs message sequence numbers?
  66       *
  67       * @var boolean
  68       */
  69      protected $_sequence = false;
  70  
  71      /**
  72       * Are IDs sorted?
  73       *
  74       * @var boolean
  75       */
  76      protected $_sorted = false;
  77  
  78      /**
  79       * Constructor.
  80       *
  81       * @param mixed $ids         See self::add().
  82       * @param boolean $sequence  Are $ids message sequence numbers?
  83       */
  84      public function __construct($ids = null, $sequence = false)
  85      {
  86          $this->add($ids);
  87          $this->_sequence = $sequence;
  88      }
  89  
  90      /**
  91       */
  92      public function __get($name)
  93      {
  94          switch ($name) {
  95          case 'all':
  96              return ($this->_ids === self::ALL);
  97  
  98          case 'ids':
  99              return is_array($this->_ids)
 100                  ? $this->_ids
 101                  : array();
 102  
 103          case 'largest':
 104              return ($this->_ids === self::LARGEST);
 105  
 106          case 'max':
 107              $this->sort();
 108              return end($this->_ids);
 109  
 110          case 'min':
 111              $this->sort();
 112              return reset($this->_ids);
 113  
 114          case 'range_string':
 115              if (!count($this)) {
 116                  return '';
 117              }
 118  
 119              $min = $this->min;
 120              $max = $this->max;
 121  
 122              return ($min == $max)
 123                  ? $min
 124                  : $min . ':' . $max;
 125  
 126          case 'search_res':
 127              return ($this->_ids === self::SEARCH_RES);
 128  
 129          case 'sequence':
 130              return (bool)$this->_sequence;
 131  
 132          case 'special':
 133              return is_string($this->_ids);
 134  
 135          case 'tostring':
 136          case 'tostring_sort':
 137              if ($this->all) {
 138                  return '1:*';
 139              } elseif ($this->largest) {
 140                  return '*';
 141              } elseif ($this->search_res) {
 142                  return '$';
 143              }
 144              return strval($this->_toSequenceString($name == 'tostring_sort'));
 145          }
 146      }
 147  
 148      /**
 149       */
 150      public function __toString()
 151      {
 152          return $this->tostring;
 153      }
 154  
 155      /**
 156       * Add IDs to the current object.
 157       *
 158       * @param mixed $ids  Either self::ALL, self::SEARCH_RES, self::LARGEST,
 159       *                    Horde_Imap_Client_Ids object, array, or sequence
 160       *                    string.
 161       */
 162      public function add($ids)
 163      {
 164          if (!is_null($ids)) {
 165              if (is_string($ids) &&
 166                  in_array($ids, array(self::ALL, self::SEARCH_RES, self::LARGEST))) {
 167                  $this->_ids = $ids;
 168              } elseif ($add = $this->_resolveIds($ids)) {
 169                  if (is_array($this->_ids) && !empty($this->_ids)) {
 170                      foreach ($add as $val) {
 171                          $this->_ids[] = $val;
 172                      }
 173                  } else {
 174                      $this->_ids = $add;
 175                  }
 176                  if (!$this->duplicates) {
 177                      $this->_ids = (count($this->_ids) > 25000)
 178                          ? array_unique($this->_ids)
 179                          : array_keys(array_flip($this->_ids));
 180                  }
 181              }
 182  
 183              $this->_sorted = (count($this->_ids) === 1);
 184          }
 185      }
 186  
 187      /**
 188       * Removed IDs from the current object.
 189       *
 190       * @since 2.17.0
 191       *
 192       * @param mixed $ids  Either Horde_Imap_Client_Ids object, array, or
 193       *                    sequence string.
 194       */
 195      public function remove($ids)
 196      {
 197          if (!$this->isEmpty() &&
 198              ($remove = $this->_resolveIds($ids))) {
 199              $this->_ids = array_diff($this->_ids, array_unique($remove));
 200          }
 201      }
 202  
 203      /**
 204       * Is this object empty (i.e. does not contain IDs)?
 205       *
 206       * @return boolean  True if object is empty.
 207       */
 208      public function isEmpty()
 209      {
 210          return (is_array($this->_ids) && !count($this->_ids));
 211      }
 212  
 213      /**
 214       * Reverses the order of the IDs.
 215       */
 216      public function reverse()
 217      {
 218          if (is_array($this->_ids)) {
 219              $this->_ids = array_reverse($this->_ids);
 220          }
 221      }
 222  
 223      /**
 224       * Sorts the IDs numerically.
 225       */
 226      public function sort()
 227      {
 228          if (!$this->_sorted && is_array($this->_ids)) {
 229              sort($this->_ids, SORT_NUMERIC);
 230              $this->_sorted = true;
 231          }
 232      }
 233  
 234      /**
 235       * Split the sequence string at an approximate length.
 236       *
 237       * @since 2.7.0
 238       *
 239       * @param integer $length  Length to split.
 240       *
 241       * @return array  A list containing individual sequence strings.
 242       */
 243      public function split($length)
 244      {
 245          $id = new Horde_Stream_Temp();
 246          $id->add($this->tostring_sort, true);
 247  
 248          $out = array();
 249  
 250          do {
 251              $out[] = $id->substring(0, $length) . $id->getToChar(',');
 252          } while (!$id->eof());
 253  
 254          return $out;
 255      }
 256  
 257      /**
 258       * Resolve the $ids input to add() and remove().
 259       *
 260       * @param mixed $ids  Either Horde_Imap_Client_Ids object, array, or
 261       *                    sequence string.
 262       *
 263       * @return array  An array of IDs.
 264       */
 265      protected function _resolveIds($ids)
 266      {
 267          if ($ids instanceof Horde_Imap_Client_Ids) {
 268              return $ids->ids;
 269          } elseif (is_array($ids)) {
 270              return $ids;
 271          } elseif (is_string($ids) || is_integer($ids)) {
 272              return is_numeric($ids)
 273                  ? array($ids)
 274                  : $this->_fromSequenceString($ids);
 275          }
 276  
 277          return array();
 278      }
 279  
 280      /**
 281       * Create an IMAP message sequence string from a list of indices.
 282       *
 283       * Index Format: range_start:range_end,uid,uid2,...
 284       *
 285       * @param boolean $sort  Numerically sort the IDs before creating the
 286       *                       range?
 287       *
 288       * @return string  The IMAP message sequence string.
 289       */
 290      protected function _toSequenceString($sort = true)
 291      {
 292          if (empty($this->_ids)) {
 293              return '';
 294          }
 295  
 296          $in = $this->_ids;
 297  
 298          if ($sort && !$this->_sorted) {
 299              sort($in, SORT_NUMERIC);
 300          }
 301  
 302          $first = $last = array_shift($in);
 303          $i = count($in) - 1;
 304          $out = array();
 305  
 306          reset($in);
 307          while (list($key, $val) = each($in)) {
 308              if (($last + 1) == $val) {
 309                  $last = $val;
 310              }
 311  
 312              if (($i == $key) || ($last != $val)) {
 313                  if ($last == $first) {
 314                      $out[] = $first;
 315                      if ($i == $key) {
 316                          $out[] = $val;
 317                      }
 318                  } else {
 319                      $out[] = $first . ':' . $last;
 320                      if (($i == $key) && ($last != $val)) {
 321                          $out[] = $val;
 322                      }
 323                  }
 324                  $first = $last = $val;
 325              }
 326          }
 327  
 328          return empty($out)
 329              ? $first
 330              : implode(',', $out);
 331      }
 332  
 333      /**
 334       * Parse an IMAP message sequence string into a list of indices.
 335       *
 336       * @see _toSequenceString()
 337       *
 338       * @param string $str  The IMAP message sequence string.
 339       *
 340       * @return array  An array of indices.
 341       */
 342      protected function _fromSequenceString($str)
 343      {
 344          $ids = array();
 345          $str = trim($str);
 346  
 347          if (!strlen($str)) {
 348              return $ids;
 349          }
 350  
 351          $idarray = explode(',', $str);
 352  
 353          reset($idarray);
 354          while (list(,$val) = each($idarray)) {
 355              $range = explode(':', $val);
 356              if (isset($range[1])) {
 357                  for ($i = min($range), $j = max($range); $i <= $j; ++$i) {
 358                      $ids[] = $i;
 359                  }
 360              } else {
 361                  $ids[] = $val;
 362              }
 363          }
 364  
 365          return $ids;
 366      }
 367  
 368      /* Countable methods. */
 369  
 370      /**
 371       */
 372      public function count()
 373      {
 374          return is_array($this->_ids)
 375              ? count($this->_ids)
 376              : 0;
 377      }
 378  
 379      /* Iterator methods. */
 380  
 381      /**
 382       */
 383      public function current()
 384      {
 385          return is_array($this->_ids)
 386              ? current($this->_ids)
 387              : null;
 388      }
 389  
 390      /**
 391       */
 392      public function key()
 393      {
 394          return is_array($this->_ids)
 395              ? key($this->_ids)
 396              : null;
 397      }
 398  
 399      /**
 400       */
 401      public function next()
 402      {
 403          if (is_array($this->_ids)) {
 404              next($this->_ids);
 405          }
 406      }
 407  
 408      /**
 409       */
 410      public function rewind()
 411      {
 412          if (is_array($this->_ids)) {
 413              reset($this->_ids);
 414          }
 415      }
 416  
 417      /**
 418       */
 419      public function valid()
 420      {
 421          return !is_null($this->key());
 422      }
 423  
 424      /* Serializable methods. */
 425  
 426      /**
 427       */
 428      public function serialize()
 429      {
 430          $save = array();
 431  
 432          if ($this->duplicates) {
 433              $save['d'] = 1;
 434          }
 435  
 436          if ($this->_sequence) {
 437              $save['s'] = 1;
 438          }
 439  
 440          if ($this->_sorted) {
 441              $save['is'] = 1;
 442          }
 443  
 444          switch ($this->_ids) {
 445          case self::ALL:
 446              $save['a'] = true;
 447              break;
 448  
 449          case self::LARGEST:
 450              $save['l'] = true;
 451              break;
 452  
 453          case self::SEARCH_RES:
 454              $save['sr'] = true;
 455              break;
 456  
 457          default:
 458              $save['i'] = strval($this);
 459              break;
 460          }
 461  
 462          return serialize($save);
 463      }
 464  
 465      /**
 466       */
 467      public function unserialize($data)
 468      {
 469          $save = @unserialize($data);
 470  
 471          $this->duplicates = !empty($save['d']);
 472          $this->_sequence = !empty($save['s']);
 473          $this->_sorted = !empty($save['is']);
 474  
 475          if (isset($save['a'])) {
 476              $this->_ids = self::ALL;
 477          } elseif (isset($save['l'])) {
 478              $this->_ids = self::LARGEST;
 479          } elseif (isset($save['sr'])) {
 480              $this->_ids = self::SEARCH_RES;
 481          } elseif (isset($save['i'])) {
 482              $this->add($save['i']);
 483          }
 484      }
 485  
 486  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1