angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

Date.php (20551B)


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