[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/simplepie/simplepie/library/SimplePie/Parse/ -> Date.php (source)

   1  <?php
   2  /**
   3   * SimplePie
   4   *
   5   * A PHP-Based RSS and Atom Feed Framework.
   6   * Takes the hard work out of managing a complete RSS/Atom solution.
   7   *
   8   * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
   9   * All rights reserved.
  10   *
  11   * Redistribution and use in source and binary forms, with or without modification, are
  12   * permitted provided that the following conditions are met:
  13   *
  14   *     * Redistributions of source code must retain the above copyright notice, this list of
  15   *       conditions and the following disclaimer.
  16   *
  17   *     * Redistributions in binary form must reproduce the above copyright notice, this list
  18   *       of conditions and the following disclaimer in the documentation and/or other materials
  19   *       provided with the distribution.
  20   *
  21   *     * Neither the name of the SimplePie Team nor the names of its contributors may be used
  22   *       to endorse or promote products derived from this software without specific prior
  23   *       written permission.
  24   *
  25   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  26   * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  27   * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
  28   * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  30   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  31   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  32   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33   * POSSIBILITY OF SUCH DAMAGE.
  34   *
  35   * @package SimplePie
  36   * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  37   * @author Ryan Parman
  38   * @author Geoffrey Sneddon
  39   * @author Ryan McCue
  40   * @link http://simplepie.org/ SimplePie
  41   * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  42   */
  43  
  44  
  45  /**
  46   * Date Parser
  47   *
  48   * @package SimplePie
  49   * @subpackage Parsing
  50   */
  51  class SimplePie_Parse_Date
  52  {
  53      /**
  54       * Input data
  55       *
  56       * @access protected
  57       * @var string
  58       */
  59      var $date;
  60  
  61      /**
  62       * List of days, calendar day name => ordinal day number in the week
  63       *
  64       * @access protected
  65       * @var array
  66       */
  67      var $day = array(
  68          // English
  69          'mon' => 1,
  70          'monday' => 1,
  71          'tue' => 2,
  72          'tuesday' => 2,
  73          'wed' => 3,
  74          'wednesday' => 3,
  75          'thu' => 4,
  76          'thursday' => 4,
  77          'fri' => 5,
  78          'friday' => 5,
  79          'sat' => 6,
  80          'saturday' => 6,
  81          'sun' => 7,
  82          'sunday' => 7,
  83          // Dutch
  84          'maandag' => 1,
  85          'dinsdag' => 2,
  86          'woensdag' => 3,
  87          'donderdag' => 4,
  88          'vrijdag' => 5,
  89          'zaterdag' => 6,
  90          'zondag' => 7,
  91          // French
  92          'lundi' => 1,
  93          'mardi' => 2,
  94          'mercredi' => 3,
  95          'jeudi' => 4,
  96          'vendredi' => 5,
  97          'samedi' => 6,
  98          'dimanche' => 7,
  99          // German
 100          'montag' => 1,
 101          'dienstag' => 2,
 102          'mittwoch' => 3,
 103          'donnerstag' => 4,
 104          'freitag' => 5,
 105          'samstag' => 6,
 106          'sonnabend' => 6,
 107          'sonntag' => 7,
 108          // Italian
 109          'lunedì' => 1,
 110          'martedì' => 2,
 111          'mercoledì' => 3,
 112          'giovedì' => 4,
 113          'venerdì' => 5,
 114          'sabato' => 6,
 115          'domenica' => 7,
 116          // Spanish
 117          'lunes' => 1,
 118          'martes' => 2,
 119          'miércoles' => 3,
 120          'jueves' => 4,
 121          'viernes' => 5,
 122          'sábado' => 6,
 123          'domingo' => 7,
 124          // Finnish
 125          'maanantai' => 1,
 126          'tiistai' => 2,
 127          'keskiviikko' => 3,
 128          'torstai' => 4,
 129          'perjantai' => 5,
 130          'lauantai' => 6,
 131          'sunnuntai' => 7,
 132          // Hungarian
 133          'hétfő' => 1,
 134          'kedd' => 2,
 135          'szerda' => 3,
 136          'csütörtok' => 4,
 137          'péntek' => 5,
 138          'szombat' => 6,
 139          'vasárnap' => 7,
 140          // Greek
 141          'Δευ' => 1,
 142          'Τρι' => 2,
 143          'Τετ' => 3,
 144          'Πεμ' => 4,
 145          'Παρ' => 5,
 146          'Σαβ' => 6,
 147          'Κυρ' => 7,
 148          // Russian
 149          'Пн.' => 1,
 150          'Вт.' => 2,
 151          'Ср.' => 3,
 152          'Чт.' => 4,
 153          'Пт.' => 5,
 154          'Сб.' => 6,
 155          'Вс.' => 7,
 156      );
 157  
 158      /**
 159       * List of months, calendar month name => calendar month number
 160       *
 161       * @access protected
 162       * @var array
 163       */
 164      var $month = array(
 165          // English
 166          'jan' => 1,
 167          'january' => 1,
 168          'feb' => 2,
 169          'february' => 2,
 170          'mar' => 3,
 171          'march' => 3,
 172          'apr' => 4,
 173          'april' => 4,
 174          'may' => 5,
 175          // No long form of May
 176          'jun' => 6,
 177          'june' => 6,
 178          'jul' => 7,
 179          'july' => 7,
 180          'aug' => 8,
 181          'august' => 8,
 182          'sep' => 9,
 183          'september' => 9,
 184          'oct' => 10,
 185          'october' => 10,
 186          'nov' => 11,
 187          'november' => 11,
 188          'dec' => 12,
 189          'december' => 12,
 190          // Dutch
 191          'januari' => 1,
 192          'februari' => 2,
 193          'maart' => 3,
 194          'april' => 4,
 195          'mei' => 5,
 196          'juni' => 6,
 197          'juli' => 7,
 198          'augustus' => 8,
 199          'september' => 9,
 200          'oktober' => 10,
 201          'november' => 11,
 202          'december' => 12,
 203          // French
 204          'janvier' => 1,
 205          'février' => 2,
 206          'mars' => 3,
 207          'avril' => 4,
 208          'mai' => 5,
 209          'juin' => 6,
 210          'juillet' => 7,
 211          'août' => 8,
 212          'septembre' => 9,
 213          'octobre' => 10,
 214          'novembre' => 11,
 215          'décembre' => 12,
 216          // German
 217          'januar' => 1,
 218          'februar' => 2,
 219          'märz' => 3,
 220          'april' => 4,
 221          'mai' => 5,
 222          'juni' => 6,
 223          'juli' => 7,
 224          'august' => 8,
 225          'september' => 9,
 226          'oktober' => 10,
 227          'november' => 11,
 228          'dezember' => 12,
 229          // Italian
 230          'gennaio' => 1,
 231          'febbraio' => 2,
 232          'marzo' => 3,
 233          'aprile' => 4,
 234          'maggio' => 5,
 235          'giugno' => 6,
 236          'luglio' => 7,
 237          'agosto' => 8,
 238          'settembre' => 9,
 239          'ottobre' => 10,
 240          'novembre' => 11,
 241          'dicembre' => 12,
 242          // Spanish
 243          'enero' => 1,
 244          'febrero' => 2,
 245          'marzo' => 3,
 246          'abril' => 4,
 247          'mayo' => 5,
 248          'junio' => 6,
 249          'julio' => 7,
 250          'agosto' => 8,
 251          'septiembre' => 9,
 252          'setiembre' => 9,
 253          'octubre' => 10,
 254          'noviembre' => 11,
 255          'diciembre' => 12,
 256          // Finnish
 257          'tammikuu' => 1,
 258          'helmikuu' => 2,
 259          'maaliskuu' => 3,
 260          'huhtikuu' => 4,
 261          'toukokuu' => 5,
 262          'kesäkuu' => 6,
 263          'heinäkuu' => 7,
 264          'elokuu' => 8,
 265          'suuskuu' => 9,
 266          'lokakuu' => 10,
 267          'marras' => 11,
 268          'joulukuu' => 12,
 269          // Hungarian
 270          'január' => 1,
 271          'február' => 2,
 272          'március' => 3,
 273          'április' => 4,
 274          'május' => 5,
 275          'június' => 6,
 276          'július' => 7,
 277          'augusztus' => 8,
 278          'szeptember' => 9,
 279          'október' => 10,
 280          'november' => 11,
 281          'december' => 12,
 282          // Greek
 283          'Ιαν' => 1,
 284          'Φεβ' => 2,
 285          'Μάώ' => 3,
 286          'Μαώ' => 3,
 287          'Απρ' => 4,
 288          'Μάι' => 5,
 289          'Μαϊ' => 5,
 290          'Μαι' => 5,
 291          'Ιούν' => 6,
 292          'Ιον' => 6,
 293          'Ιούλ' => 7,
 294          'Ιολ' => 7,
 295          'Αύγ' => 8,
 296          'Αυγ' => 8,
 297          'Σεπ' => 9,
 298          'Οκτ' => 10,
 299          'Νοέ' => 11,
 300          'Δεκ' => 12,        
 301          // Russian
 302          'Янв' => 1,
 303          'января' => 1,
 304          'Фев' => 2,
 305          'февраля' => 2,
 306          'Мар' => 3,
 307          'марта' => 3,
 308          'Апр' => 4,
 309          'апреля' => 4,
 310          'Май' => 5,
 311          'мая' => 5,
 312          'Июн' => 6,
 313          'июня' => 6,
 314          'Июл' => 7,
 315          'июля' => 7,
 316          'Авг' => 8,
 317          'августа' => 8,
 318          'Сен' => 9,
 319          'сентября' => 9,
 320          'Окт' => 10,
 321          'октября' => 10,
 322          'Ноя' => 11,
 323          'ноября' => 11,
 324          'Дек' => 12,
 325          'декабря' => 12,
 326  
 327      );
 328  
 329      /**
 330       * List of timezones, abbreviation => offset from UTC
 331       *
 332       * @access protected
 333       * @var array
 334       */
 335      var $timezone = array(
 336          'ACDT' => 37800,
 337          'ACIT' => 28800,
 338          'ACST' => 34200,
 339          'ACT' => -18000,
 340          'ACWDT' => 35100,
 341          'ACWST' => 31500,
 342          'AEDT' => 39600,
 343          'AEST' => 36000,
 344          'AFT' => 16200,
 345          'AKDT' => -28800,
 346          'AKST' => -32400,
 347          'AMDT' => 18000,
 348          'AMT' => -14400,
 349          'ANAST' => 46800,
 350          'ANAT' => 43200,
 351          'ART' => -10800,
 352          'AZOST' => -3600,
 353          'AZST' => 18000,
 354          'AZT' => 14400,
 355          'BIOT' => 21600,
 356          'BIT' => -43200,
 357          'BOT' => -14400,
 358          'BRST' => -7200,
 359          'BRT' => -10800,
 360          'BST' => 3600,
 361          'BTT' => 21600,
 362          'CAST' => 18000,
 363          'CAT' => 7200,
 364          'CCT' => 23400,
 365          'CDT' => -18000,
 366          'CEDT' => 7200,
 367          'CEST' => 7200,
 368          'CET' => 3600,
 369          'CGST' => -7200,
 370          'CGT' => -10800,
 371          'CHADT' => 49500,
 372          'CHAST' => 45900,
 373          'CIST' => -28800,
 374          'CKT' => -36000,
 375          'CLDT' => -10800,
 376          'CLST' => -14400,
 377          'COT' => -18000,
 378          'CST' => -21600,
 379          'CVT' => -3600,
 380          'CXT' => 25200,
 381          'DAVT' => 25200,
 382          'DTAT' => 36000,
 383          'EADT' => -18000,
 384          'EAST' => -21600,
 385          'EAT' => 10800,
 386          'ECT' => -18000,
 387          'EDT' => -14400,
 388          'EEST' => 10800,
 389          'EET' => 7200,
 390          'EGT' => -3600,
 391          'EKST' => 21600,
 392          'EST' => -18000,
 393          'FJT' => 43200,
 394          'FKDT' => -10800,
 395          'FKST' => -14400,
 396          'FNT' => -7200,
 397          'GALT' => -21600,
 398          'GEDT' => 14400,
 399          'GEST' => 10800,
 400          'GFT' => -10800,
 401          'GILT' => 43200,
 402          'GIT' => -32400,
 403          'GST' => 14400,
 404          'GST' => -7200,
 405          'GYT' => -14400,
 406          'HAA' => -10800,
 407          'HAC' => -18000,
 408          'HADT' => -32400,
 409          'HAE' => -14400,
 410          'HAP' => -25200,
 411          'HAR' => -21600,
 412          'HAST' => -36000,
 413          'HAT' => -9000,
 414          'HAY' => -28800,
 415          'HKST' => 28800,
 416          'HMT' => 18000,
 417          'HNA' => -14400,
 418          'HNC' => -21600,
 419          'HNE' => -18000,
 420          'HNP' => -28800,
 421          'HNR' => -25200,
 422          'HNT' => -12600,
 423          'HNY' => -32400,
 424          'IRDT' => 16200,
 425          'IRKST' => 32400,
 426          'IRKT' => 28800,
 427          'IRST' => 12600,
 428          'JFDT' => -10800,
 429          'JFST' => -14400,
 430          'JST' => 32400,
 431          'KGST' => 21600,
 432          'KGT' => 18000,
 433          'KOST' => 39600,
 434          'KOVST' => 28800,
 435          'KOVT' => 25200,
 436          'KRAST' => 28800,
 437          'KRAT' => 25200,
 438          'KST' => 32400,
 439          'LHDT' => 39600,
 440          'LHST' => 37800,
 441          'LINT' => 50400,
 442          'LKT' => 21600,
 443          'MAGST' => 43200,
 444          'MAGT' => 39600,
 445          'MAWT' => 21600,
 446          'MDT' => -21600,
 447          'MESZ' => 7200,
 448          'MEZ' => 3600,
 449          'MHT' => 43200,
 450          'MIT' => -34200,
 451          'MNST' => 32400,
 452          'MSDT' => 14400,
 453          'MSST' => 10800,
 454          'MST' => -25200,
 455          'MUT' => 14400,
 456          'MVT' => 18000,
 457          'MYT' => 28800,
 458          'NCT' => 39600,
 459          'NDT' => -9000,
 460          'NFT' => 41400,
 461          'NMIT' => 36000,
 462          'NOVST' => 25200,
 463          'NOVT' => 21600,
 464          'NPT' => 20700,
 465          'NRT' => 43200,
 466          'NST' => -12600,
 467          'NUT' => -39600,
 468          'NZDT' => 46800,
 469          'NZST' => 43200,
 470          'OMSST' => 25200,
 471          'OMST' => 21600,
 472          'PDT' => -25200,
 473          'PET' => -18000,
 474          'PETST' => 46800,
 475          'PETT' => 43200,
 476          'PGT' => 36000,
 477          'PHOT' => 46800,
 478          'PHT' => 28800,
 479          'PKT' => 18000,
 480          'PMDT' => -7200,
 481          'PMST' => -10800,
 482          'PONT' => 39600,
 483          'PST' => -28800,
 484          'PWT' => 32400,
 485          'PYST' => -10800,
 486          'PYT' => -14400,
 487          'RET' => 14400,
 488          'ROTT' => -10800,
 489          'SAMST' => 18000,
 490          'SAMT' => 14400,
 491          'SAST' => 7200,
 492          'SBT' => 39600,
 493          'SCDT' => 46800,
 494          'SCST' => 43200,
 495          'SCT' => 14400,
 496          'SEST' => 3600,
 497          'SGT' => 28800,
 498          'SIT' => 28800,
 499          'SRT' => -10800,
 500          'SST' => -39600,
 501          'SYST' => 10800,
 502          'SYT' => 7200,
 503          'TFT' => 18000,
 504          'THAT' => -36000,
 505          'TJT' => 18000,
 506          'TKT' => -36000,
 507          'TMT' => 18000,
 508          'TOT' => 46800,
 509          'TPT' => 32400,
 510          'TRUT' => 36000,
 511          'TVT' => 43200,
 512          'TWT' => 28800,
 513          'UYST' => -7200,
 514          'UYT' => -10800,
 515          'UZT' => 18000,
 516          'VET' => -14400,
 517          'VLAST' => 39600,
 518          'VLAT' => 36000,
 519          'VOST' => 21600,
 520          'VUT' => 39600,
 521          'WAST' => 7200,
 522          'WAT' => 3600,
 523          'WDT' => 32400,
 524          'WEST' => 3600,
 525          'WFT' => 43200,
 526          'WIB' => 25200,
 527          'WIT' => 32400,
 528          'WITA' => 28800,
 529          'WKST' => 18000,
 530          'WST' => 28800,
 531          'YAKST' => 36000,
 532          'YAKT' => 32400,
 533          'YAPT' => 36000,
 534          'YEKST' => 21600,
 535          'YEKT' => 18000,
 536      );
 537  
 538      /**
 539       * Cached PCRE for SimplePie_Parse_Date::$day
 540       *
 541       * @access protected
 542       * @var string
 543       */
 544      var $day_pcre;
 545  
 546      /**
 547       * Cached PCRE for SimplePie_Parse_Date::$month
 548       *
 549       * @access protected
 550       * @var string
 551       */
 552      var $month_pcre;
 553  
 554      /**
 555       * Array of user-added callback methods
 556       *
 557       * @access private
 558       * @var array
 559       */
 560      var $built_in = array();
 561  
 562      /**
 563       * Array of user-added callback methods
 564       *
 565       * @access private
 566       * @var array
 567       */
 568      var $user = array();
 569  
 570      /**
 571       * Create new SimplePie_Parse_Date object, and set self::day_pcre,
 572       * self::month_pcre, and self::built_in
 573       *
 574       * @access private
 575       */
 576  	public function __construct()
 577      {
 578          $this->day_pcre = '(' . implode('|', array_keys($this->day)) . ')';
 579          $this->month_pcre = '(' . implode('|', array_keys($this->month)) . ')';
 580  
 581          static $cache;
 582          if (!isset($cache[get_class($this)]))
 583          {
 584              $all_methods = get_class_methods($this);
 585  
 586              foreach ($all_methods as $method)
 587              {
 588                  if (strtolower(substr($method, 0, 5)) === 'date_')
 589                  {
 590                      $cache[get_class($this)][] = $method;
 591                  }
 592              }
 593          }
 594  
 595          foreach ($cache[get_class($this)] as $method)
 596          {
 597              $this->built_in[] = $method;
 598          }
 599      }
 600  
 601      /**
 602       * Get the object
 603       *
 604       * @access public
 605       */
 606  	public static function get()
 607      {
 608          static $object;
 609          if (!$object)
 610          {
 611              $object = new SimplePie_Parse_Date;
 612          }
 613          return $object;
 614      }
 615  
 616      /**
 617       * Parse a date
 618       *
 619       * @final
 620       * @access public
 621       * @param string $date Date to parse
 622       * @return int Timestamp corresponding to date string, or false on failure
 623       */
 624  	public function parse($date)
 625      {
 626          foreach ($this->user as $method)
 627          {
 628              if (($returned = call_user_func($method, $date)) !== false)
 629              {
 630                  return $returned;
 631              }
 632          }
 633  
 634          foreach ($this->built_in as $method)
 635          {
 636              if (($returned = call_user_func(array($this, $method), $date)) !== false)
 637              {
 638                  return $returned;
 639              }
 640          }
 641  
 642          return false;
 643      }
 644  
 645      /**
 646       * Add a callback method to parse a date
 647       *
 648       * @final
 649       * @access public
 650       * @param callback $callback
 651       */
 652  	public function add_callback($callback)
 653      {
 654          if (is_callable($callback))
 655          {
 656              $this->user[] = $callback;
 657          }
 658          else
 659          {
 660              trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
 661          }
 662      }
 663  
 664      /**
 665       * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
 666       * well as allowing any of upper or lower case "T", horizontal tabs, or
 667       * spaces to be used as the time separator (including more than one))
 668       *
 669       * @access protected
 670       * @return int Timestamp
 671       */
 672  	public function date_w3cdtf($date)
 673      {
 674          static $pcre;
 675          if (!$pcre)
 676          {
 677              $year = '([0-9]{4})';
 678              $month = $day = $hour = $minute = $second = '([0-9]{2})';
 679              $decimal = '([0-9]*)';
 680              $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
 681              $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
 682          }
 683          if (preg_match($pcre, $date, $match))
 684          {
 685              /*
 686              Capturing subpatterns:
 687              1: Year
 688              2: Month
 689              3: Day
 690              4: Hour
 691              5: Minute
 692              6: Second
 693              7: Decimal fraction of a second
 694              8: Zulu
 695              9: Timezone ±
 696              10: Timezone hours
 697              11: Timezone minutes
 698              */
 699  
 700              // Fill in empty matches
 701              for ($i = count($match); $i <= 3; $i++)
 702              {
 703                  $match[$i] = '1';
 704              }
 705  
 706              for ($i = count($match); $i <= 7; $i++)
 707              {
 708                  $match[$i] = '0';
 709              }
 710  
 711              // Numeric timezone
 712              if (isset($match[9]) && $match[9] !== '')
 713              {
 714                  $timezone = $match[10] * 3600;
 715                  $timezone += $match[11] * 60;
 716                  if ($match[9] === '-')
 717                  {
 718                      $timezone = 0 - $timezone;
 719                  }
 720              }
 721              else
 722              {
 723                  $timezone = 0;
 724              }
 725  
 726              // Convert the number of seconds to an integer, taking decimals into account
 727              $second = round((int)$match[6] + (int)$match[7] / (10 ** strlen($match[7])));
 728  
 729              return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
 730          }
 731  
 732          return false;
 733      }
 734  
 735      /**
 736       * Remove RFC822 comments
 737       *
 738       * @access protected
 739       * @param string $data Data to strip comments from
 740       * @return string Comment stripped string
 741       */
 742  	public function remove_rfc2822_comments($string)
 743      {
 744          $string = (string) $string;
 745          $position = 0;
 746          $length = strlen($string);
 747          $depth = 0;
 748  
 749          $output = '';
 750  
 751          while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
 752          {
 753              $output .= substr($string, $position, $pos - $position);
 754              $position = $pos + 1;
 755              if ($pos === 0 || $string[$pos - 1] !== '\\')
 756              {
 757                  $depth++;
 758                  while ($depth && $position < $length)
 759                  {
 760                      $position += strcspn($string, '()', $position);
 761                      if ($string[$position - 1] === '\\')
 762                      {
 763                          $position++;
 764                          continue;
 765                      }
 766                      elseif (isset($string[$position]))
 767                      {
 768                          switch ($string[$position])
 769                          {
 770                              case '(':
 771                                  $depth++;
 772                                  break;
 773  
 774                              case ')':
 775                                  $depth--;
 776                                  break;
 777                          }
 778                          $position++;
 779                      }
 780                      else
 781                      {
 782                          break;
 783                      }
 784                  }
 785              }
 786              else
 787              {
 788                  $output .= '(';
 789              }
 790          }
 791          $output .= substr($string, $position);
 792  
 793          return $output;
 794      }
 795  
 796      /**
 797       * Parse RFC2822's date format
 798       *
 799       * @access protected
 800       * @return int Timestamp
 801       */
 802  	public function date_rfc2822($date)
 803      {
 804          static $pcre;
 805          if (!$pcre)
 806          {
 807              $wsp = '[\x09\x20]';
 808              $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
 809              $optional_fws = $fws . '?';
 810              $day_name = $this->day_pcre;
 811              $month = $this->month_pcre;
 812              $day = '([0-9]{1,2})';
 813              $hour = $minute = $second = '([0-9]{2})';
 814              $year = '([0-9]{2,4})';
 815              $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
 816              $character_zone = '([A-Z]{1,5})';
 817              $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
 818              $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
 819          }
 820          if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
 821          {
 822              /*
 823              Capturing subpatterns:
 824              1: Day name
 825              2: Day
 826              3: Month
 827              4: Year
 828              5: Hour
 829              6: Minute
 830              7: Second
 831              8: Timezone ±
 832              9: Timezone hours
 833              10: Timezone minutes
 834              11: Alphabetic timezone
 835              */
 836  
 837              // Find the month number
 838              $month = $this->month[strtolower($match[3])];
 839  
 840              // Numeric timezone
 841              if ($match[8] !== '')
 842              {
 843                  $timezone = $match[9] * 3600;
 844                  $timezone += $match[10] * 60;
 845                  if ($match[8] === '-')
 846                  {
 847                      $timezone = 0 - $timezone;
 848                  }
 849              }
 850              // Character timezone
 851              elseif (isset($this->timezone[strtoupper($match[11])]))
 852              {
 853                  $timezone = $this->timezone[strtoupper($match[11])];
 854              }
 855              // Assume everything else to be -0000
 856              else
 857              {
 858                  $timezone = 0;
 859              }
 860  
 861              // Deal with 2/3 digit years
 862              if ($match[4] < 50)
 863              {
 864                  $match[4] += 2000;
 865              }
 866              elseif ($match[4] < 1000)
 867              {
 868                  $match[4] += 1900;
 869              }
 870  
 871              // Second is optional, if it is empty set it to zero
 872              if ($match[7] !== '')
 873              {
 874                  $second = $match[7];
 875              }
 876              else
 877              {
 878                  $second = 0;
 879              }
 880  
 881              return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
 882          }
 883  
 884          return false;
 885      }
 886  
 887      /**
 888       * Parse RFC850's date format
 889       *
 890       * @access protected
 891       * @return int Timestamp
 892       */
 893  	public function date_rfc850($date)
 894      {
 895          static $pcre;
 896          if (!$pcre)
 897          {
 898              $space = '[\x09\x20]+';
 899              $day_name = $this->day_pcre;
 900              $month = $this->month_pcre;
 901              $day = '([0-9]{1,2})';
 902              $year = $hour = $minute = $second = '([0-9]{2})';
 903              $zone = '([A-Z]{1,5})';
 904              $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
 905          }
 906          if (preg_match($pcre, $date, $match))
 907          {
 908              /*
 909              Capturing subpatterns:
 910              1: Day name
 911              2: Day
 912              3: Month
 913              4: Year
 914              5: Hour
 915              6: Minute
 916              7: Second
 917              8: Timezone
 918              */
 919  
 920              // Month
 921              $month = $this->month[strtolower($match[3])];
 922  
 923              // Character timezone
 924              if (isset($this->timezone[strtoupper($match[8])]))
 925              {
 926                  $timezone = $this->timezone[strtoupper($match[8])];
 927              }
 928              // Assume everything else to be -0000
 929              else
 930              {
 931                  $timezone = 0;
 932              }
 933  
 934              // Deal with 2 digit year
 935              if ($match[4] < 50)
 936              {
 937                  $match[4] += 2000;
 938              }
 939              else
 940              {
 941                  $match[4] += 1900;
 942              }
 943  
 944              return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
 945          }
 946  
 947          return false;
 948      }
 949  
 950      /**
 951       * Parse C99's asctime()'s date format
 952       *
 953       * @access protected
 954       * @return int Timestamp
 955       */
 956  	public function date_asctime($date)
 957      {
 958          static $pcre;
 959          if (!$pcre)
 960          {
 961              $space = '[\x09\x20]+';
 962              $wday_name = $this->day_pcre;
 963              $mon_name = $this->month_pcre;
 964              $day = '([0-9]{1,2})';
 965              $hour = $sec = $min = '([0-9]{2})';
 966              $year = '([0-9]{4})';
 967              $terminator = '\x0A?\x00?';
 968              $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
 969          }
 970          if (preg_match($pcre, $date, $match))
 971          {
 972              /*
 973              Capturing subpatterns:
 974              1: Day name
 975              2: Month
 976              3: Day
 977              4: Hour
 978              5: Minute
 979              6: Second
 980              7: Year
 981              */
 982  
 983              $month = $this->month[strtolower($match[2])];
 984              return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
 985          }
 986  
 987          return false;
 988      }
 989  
 990      /**
 991       * Parse dates using strtotime()
 992       *
 993       * @access protected
 994       * @return int Timestamp
 995       */
 996  	public function date_strtotime($date)
 997      {
 998          $strtotime = strtotime($date);
 999          if ($strtotime === -1 || $strtotime === false)
1000          {
1001              return false;
1002          }
1003  
1004          return $strtotime;
1005      }
1006  }