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