Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?phpdeclare(strict_types=1);/*** SimplePie** A PHP-Based RSS and Atom Feed Framework.* Takes the hard work out of managing a complete RSS/Atom solution.** Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors* All rights reserved.** Redistribution and use in source and binary forms, with or without modification, are* permitted provided that the following conditions are met:** * Redistributions of source code must retain the above copyright notice, this list of* conditions and the following disclaimer.** * Redistributions in binary form must reproduce the above copyright notice, this list* of conditions and the following disclaimer in the documentation and/or other materials* provided with the distribution.** * Neither the name of the SimplePie Team nor the names of its contributors may be used* to endorse or promote products derived from this software without specific prior* written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.** @package SimplePie* @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue* @author Ryan Parman* @author Sam Sneddon* @author Ryan McCue* @link http://simplepie.org/ SimplePie* @license http://www.opensource.org/licenses/bsd-license.php BSD License*/namespace SimplePie\Parse;/*** Date Parser** @package SimplePie* @subpackage Parsing*/class Date{/*** Input data** @access protected* @var string*/public $date;/*** List of days, calendar day name => ordinal day number in the week** @access protected* @var array*/public $day = [// English'mon' => 1,'monday' => 1,'tue' => 2,'tuesday' => 2,'wed' => 3,'wednesday' => 3,'thu' => 4,'thursday' => 4,'fri' => 5,'friday' => 5,'sat' => 6,'saturday' => 6,'sun' => 7,'sunday' => 7,// Dutch'maandag' => 1,'dinsdag' => 2,'woensdag' => 3,'donderdag' => 4,'vrijdag' => 5,'zaterdag' => 6,'zondag' => 7,// French'lundi' => 1,'mardi' => 2,'mercredi' => 3,'jeudi' => 4,'vendredi' => 5,'samedi' => 6,'dimanche' => 7,// German'montag' => 1,'mo' => 1,'dienstag' => 2,'di' => 2,'mittwoch' => 3,'mi' => 3,'donnerstag' => 4,'do' => 4,'freitag' => 5,'fr' => 5,'samstag' => 6,'sa' => 6,'sonnabend' => 6,// AFAIK no short form for sonnabend'so' => 7,'sonntag' => 7,// Italian'lunedì' => 1,'martedì' => 2,'mercoledì' => 3,'giovedì' => 4,'venerdì' => 5,'sabato' => 6,'domenica' => 7,// Spanish'lunes' => 1,'martes' => 2,'miércoles' => 3,'jueves' => 4,'viernes' => 5,'sábado' => 6,'domingo' => 7,// Finnish'maanantai' => 1,'tiistai' => 2,'keskiviikko' => 3,'torstai' => 4,'perjantai' => 5,'lauantai' => 6,'sunnuntai' => 7,// Hungarian'hétfő' => 1,'kedd' => 2,'szerda' => 3,'csütörtok' => 4,'péntek' => 5,'szombat' => 6,'vasárnap' => 7,// Greek'Δευ' => 1,'Τρι' => 2,'Τετ' => 3,'Πεμ' => 4,'Παρ' => 5,'Σαβ' => 6,'Κυρ' => 7,// Russian'Пн.' => 1,'Вт.' => 2,'Ср.' => 3,'Чт.' => 4,'Пт.' => 5,'Сб.' => 6,'Вс.' => 7,];/*** List of months, calendar month name => calendar month number** @access protected* @var array*/public $month = [// English'jan' => 1,'january' => 1,'feb' => 2,'february' => 2,'mar' => 3,'march' => 3,'apr' => 4,'april' => 4,'may' => 5,// No long form of May'jun' => 6,'june' => 6,'jul' => 7,'july' => 7,'aug' => 8,'august' => 8,'sep' => 9,'september' => 9,'oct' => 10,'october' => 10,'nov' => 11,'november' => 11,'dec' => 12,'december' => 12,// Dutch'januari' => 1,'februari' => 2,'maart' => 3,'april' => 4,'mei' => 5,'juni' => 6,'juli' => 7,'augustus' => 8,'september' => 9,'oktober' => 10,'november' => 11,'december' => 12,// French'janvier' => 1,'février' => 2,'mars' => 3,'avril' => 4,'mai' => 5,'juin' => 6,'juillet' => 7,'août' => 8,'septembre' => 9,'octobre' => 10,'novembre' => 11,'décembre' => 12,// German'januar' => 1,'jan' => 1,'februar' => 2,'feb' => 2,'märz' => 3,'mär' => 3,'april' => 4,'apr' => 4,'mai' => 5, // no short form for may'juni' => 6,'jun' => 6,'juli' => 7,'jul' => 7,'august' => 8,'aug' => 8,'september' => 9,'sep' => 9,'oktober' => 10,'okt' => 10,'november' => 11,'nov' => 11,'dezember' => 12,'dez' => 12,// Italian'gennaio' => 1,'febbraio' => 2,'marzo' => 3,'aprile' => 4,'maggio' => 5,'giugno' => 6,'luglio' => 7,'agosto' => 8,'settembre' => 9,'ottobre' => 10,'novembre' => 11,'dicembre' => 12,// Spanish'enero' => 1,'febrero' => 2,'marzo' => 3,'abril' => 4,'mayo' => 5,'junio' => 6,'julio' => 7,'agosto' => 8,'septiembre' => 9,'setiembre' => 9,'octubre' => 10,'noviembre' => 11,'diciembre' => 12,// Finnish'tammikuu' => 1,'helmikuu' => 2,'maaliskuu' => 3,'huhtikuu' => 4,'toukokuu' => 5,'kesäkuu' => 6,'heinäkuu' => 7,'elokuu' => 8,'suuskuu' => 9,'lokakuu' => 10,'marras' => 11,'joulukuu' => 12,// Hungarian'január' => 1,'február' => 2,'március' => 3,'április' => 4,'május' => 5,'június' => 6,'július' => 7,'augusztus' => 8,'szeptember' => 9,'október' => 10,'november' => 11,'december' => 12,// Greek'Ιαν' => 1,'Φεβ' => 2,'Μάώ' => 3,'Μαώ' => 3,'Απρ' => 4,'Μάι' => 5,'Μαϊ' => 5,'Μαι' => 5,'Ιούν' => 6,'Ιον' => 6,'Ιούλ' => 7,'Ιολ' => 7,'Αύγ' => 8,'Αυγ' => 8,'Σεπ' => 9,'Οκτ' => 10,'Νοέ' => 11,'Δεκ' => 12,// Russian'Янв' => 1,'января' => 1,'Фев' => 2,'февраля' => 2,'Мар' => 3,'марта' => 3,'Апр' => 4,'апреля' => 4,'Май' => 5,'мая' => 5,'Июн' => 6,'июня' => 6,'Июл' => 7,'июля' => 7,'Авг' => 8,'августа' => 8,'Сен' => 9,'сентября' => 9,'Окт' => 10,'октября' => 10,'Ноя' => 11,'ноября' => 11,'Дек' => 12,'декабря' => 12,];/*** List of timezones, abbreviation => offset from UTC** @access protected* @var array*/public $timezone = ['ACDT' => 37800,'ACIT' => 28800,'ACST' => 34200,'ACT' => -18000,'ACWDT' => 35100,'ACWST' => 31500,'AEDT' => 39600,'AEST' => 36000,'AFT' => 16200,'AKDT' => -28800,'AKST' => -32400,'AMDT' => 18000,'AMT' => -14400,'ANAST' => 46800,'ANAT' => 43200,'ART' => -10800,'AZOST' => -3600,'AZST' => 18000,'AZT' => 14400,'BIOT' => 21600,'BIT' => -43200,'BOT' => -14400,'BRST' => -7200,'BRT' => -10800,'BST' => 3600,'BTT' => 21600,'CAST' => 18000,'CAT' => 7200,'CCT' => 23400,'CDT' => -18000,'CEDT' => 7200,'CEST' => 7200,'CET' => 3600,'CGST' => -7200,'CGT' => -10800,'CHADT' => 49500,'CHAST' => 45900,'CIST' => -28800,'CKT' => -36000,'CLDT' => -10800,'CLST' => -14400,'COT' => -18000,'CST' => -21600,'CVT' => -3600,'CXT' => 25200,'DAVT' => 25200,'DTAT' => 36000,'EADT' => -18000,'EAST' => -21600,'EAT' => 10800,'ECT' => -18000,'EDT' => -14400,'EEST' => 10800,'EET' => 7200,'EGT' => -3600,'EKST' => 21600,'EST' => -18000,'FJT' => 43200,'FKDT' => -10800,'FKST' => -14400,'FNT' => -7200,'GALT' => -21600,'GEDT' => 14400,'GEST' => 10800,'GFT' => -10800,'GILT' => 43200,'GIT' => -32400,'GST' => 14400,'GST' => -7200,'GYT' => -14400,'HAA' => -10800,'HAC' => -18000,'HADT' => -32400,'HAE' => -14400,'HAP' => -25200,'HAR' => -21600,'HAST' => -36000,'HAT' => -9000,'HAY' => -28800,'HKST' => 28800,'HMT' => 18000,'HNA' => -14400,'HNC' => -21600,'HNE' => -18000,'HNP' => -28800,'HNR' => -25200,'HNT' => -12600,'HNY' => -32400,'IRDT' => 16200,'IRKST' => 32400,'IRKT' => 28800,'IRST' => 12600,'JFDT' => -10800,'JFST' => -14400,'JST' => 32400,'KGST' => 21600,'KGT' => 18000,'KOST' => 39600,'KOVST' => 28800,'KOVT' => 25200,'KRAST' => 28800,'KRAT' => 25200,'KST' => 32400,'LHDT' => 39600,'LHST' => 37800,'LINT' => 50400,'LKT' => 21600,'MAGST' => 43200,'MAGT' => 39600,'MAWT' => 21600,'MDT' => -21600,'MESZ' => 7200,'MEZ' => 3600,'MHT' => 43200,'MIT' => -34200,'MNST' => 32400,'MSDT' => 14400,'MSST' => 10800,'MST' => -25200,'MUT' => 14400,'MVT' => 18000,'MYT' => 28800,'NCT' => 39600,'NDT' => -9000,'NFT' => 41400,'NMIT' => 36000,'NOVST' => 25200,'NOVT' => 21600,'NPT' => 20700,'NRT' => 43200,'NST' => -12600,'NUT' => -39600,'NZDT' => 46800,'NZST' => 43200,'OMSST' => 25200,'OMST' => 21600,'PDT' => -25200,'PET' => -18000,'PETST' => 46800,'PETT' => 43200,'PGT' => 36000,'PHOT' => 46800,'PHT' => 28800,'PKT' => 18000,'PMDT' => -7200,'PMST' => -10800,'PONT' => 39600,'PST' => -28800,'PWT' => 32400,'PYST' => -10800,'PYT' => -14400,'RET' => 14400,'ROTT' => -10800,'SAMST' => 18000,'SAMT' => 14400,'SAST' => 7200,'SBT' => 39600,'SCDT' => 46800,'SCST' => 43200,'SCT' => 14400,'SEST' => 3600,'SGT' => 28800,'SIT' => 28800,'SRT' => -10800,'SST' => -39600,'SYST' => 10800,'SYT' => 7200,'TFT' => 18000,'THAT' => -36000,'TJT' => 18000,'TKT' => -36000,'TMT' => 18000,'TOT' => 46800,'TPT' => 32400,'TRUT' => 36000,'TVT' => 43200,'TWT' => 28800,'UYST' => -7200,'UYT' => -10800,'UZT' => 18000,'VET' => -14400,'VLAST' => 39600,'VLAT' => 36000,'VOST' => 21600,'VUT' => 39600,'WAST' => 7200,'WAT' => 3600,'WDT' => 32400,'WEST' => 3600,'WFT' => 43200,'WIB' => 25200,'WIT' => 32400,'WITA' => 28800,'WKST' => 18000,'WST' => 28800,'YAKST' => 36000,'YAKT' => 32400,'YAPT' => 36000,'YEKST' => 21600,'YEKT' => 18000,];/*** Cached PCRE for Date::$day** @access protected* @var string*/public $day_pcre;/*** Cached PCRE for Date::$month** @access protected* @var string*/public $month_pcre;/*** Array of user-added callback methods** @access private* @var array*/public $built_in = [];/*** Array of user-added callback methods** @access private* @var array*/public $user = [];/*** Create new Date object, and set self::day_pcre,* self::month_pcre, and self::built_in** @access private*/public function __construct(){$this->day_pcre = '(' . implode('|', array_keys($this->day)) . ')';$this->month_pcre = '(' . implode('|', array_keys($this->month)) . ')';static $cache;if (!isset($cache[get_class($this)])) {$all_methods = get_class_methods($this);foreach ($all_methods as $method) {if (strtolower(substr($method, 0, 5)) === 'date_') {$cache[get_class($this)][] = $method;}}}foreach ($cache[get_class($this)] as $method) {$this->built_in[] = $method;}}/*** Get the object** @access public*/public static function get(){static $object;if (!$object) {$object = new Date();}return $object;}/*** Parse a date** @final* @access public* @param string $date Date to parse* @return int Timestamp corresponding to date string, or false on failure*/public function parse($date){foreach ($this->user as $method) {if (($returned = call_user_func($method, $date)) !== false) {return $returned;}}foreach ($this->built_in as $method) {if (($returned = call_user_func([$this, $method], $date)) !== false) {return $returned;}}return false;}/*** Add a callback method to parse a date** @final* @access public* @param callable $callback*/public function add_callback($callback){if (is_callable($callback)) {$this->user[] = $callback;} else {trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);}}/*** Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as* well as allowing any of upper or lower case "T", horizontal tabs, or* spaces to be used as the time separator (including more than one))** @access protected* @return int Timestamp*/public function date_w3cdtf($date){$pcre = <<<'PCRE'/^(?P<year>[0-9]{4})(?:-?(?P<month>[0-9]{2})(?:-?(?P<day>[0-9]{2})(?:[Tt\x09\x20]+(?P<hour>[0-9]{2})(?::?(?P<minute>[0-9]{2})(?::?(?P<second>[0-9]{2})(?:.(?P<second_fraction>[0-9]*))?)?)?(?:(?P<zulu>Z)| (?P<tz_sign>[+\-])(?P<tz_hour>[0-9]{1,2}):?(?P<tz_minute>[0-9]{1,2})))?)?)?$/xPCRE;if (preg_match($pcre, $date, $match)) {// Fill in empty matches and convert to proper types.$year = (int) $match['year'];$month = isset($match['month']) ? (int) $match['month'] : 1;$day = isset($match['day']) ? (int) $match['day'] : 1;$hour = isset($match['hour']) ? (int) $match['hour'] : 0;$minute = isset($match['minute']) ? (int) $match['minute'] : 0;$second = isset($match['second']) ? (int) $match['second'] : 0;$second_fraction = isset($match['second_fraction']) ? ((int) $match['second_fraction']) / (10 ** strlen($match['second_fraction'])) : 0;$tz_sign = ($match['tz_sign'] ?? '') === '-' ? -1 : 1;$tz_hour = isset($match['tz_hour']) ? (int) $match['tz_hour'] : 0;$tz_minute = isset($match['tz_minute']) ? (int) $match['tz_minute'] : 0;// Numeric timezone$timezone = $tz_hour * 3600;$timezone += $tz_minute * 60;$timezone *= $tz_sign;// Convert the number of seconds to an integer, taking decimals into account$second = (int) round($second + $second_fraction);return gmmktime($hour, $minute, $second, $month, $day, $year) - $timezone;}return false;}/*** Remove RFC822 comments** @access protected* @param string $data Data to strip comments from* @return string Comment stripped string*/public function remove_rfc2822_comments($string){$string = (string) $string;$position = 0;$length = strlen($string);$depth = 0;$output = '';while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) {$output .= substr($string, $position, $pos - $position);$position = $pos + 1;if ($pos === 0 || $string[$pos - 1] !== '\\') {$depth++;while ($depth && $position < $length) {$position += strcspn($string, '()', $position);if ($string[$position - 1] === '\\') {$position++;continue;} elseif (isset($string[$position])) {switch ($string[$position]) {case '(':$depth++;break;case ')':$depth--;break;}$position++;} else {break;}}} else {$output .= '(';}}$output .= substr($string, $position);return $output;}/*** Parse RFC2822's date format** @access protected* @return int Timestamp*/public function date_rfc2822($date){static $pcre;if (!$pcre) {$wsp = '[\x09\x20]';$fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';$optional_fws = $fws . '?';$day_name = $this->day_pcre;$month = $this->month_pcre;$day = '([0-9]{1,2})';$hour = $minute = $second = '([0-9]{2})';$year = '([0-9]{2,4})';$num_zone = '([+\-])([0-9]{2})([0-9]{2})';$character_zone = '([A-Z]{1,5})';$zone = '(?:' . $num_zone . '|' . $character_zone . ')';$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';}if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match)) {/*Capturing subpatterns:1: Day name2: Day3: Month4: Year5: Hour6: Minute7: Second8: Timezone ±9: Timezone hours10: Timezone minutes11: Alphabetic timezone*/// Find the month number$month = $this->month[strtolower($match[3])];// Numeric timezoneif ($match[8] !== '') {$timezone = $match[9] * 3600;$timezone += $match[10] * 60;if ($match[8] === '-') {$timezone = 0 - $timezone;}}// Character timezoneelseif (isset($this->timezone[strtoupper($match[11])])) {$timezone = $this->timezone[strtoupper($match[11])];}// Assume everything else to be -0000else {$timezone = 0;}// Deal with 2/3 digit yearsif ($match[4] < 50) {$match[4] += 2000;} elseif ($match[4] < 1000) {$match[4] += 1900;}// Second is optional, if it is empty set it to zeroif ($match[7] !== '') {$second = $match[7];} else {$second = 0;}return gmmktime(intval($match[5]), intval($match[6]), intval($second), intval($month), intval($match[2]), intval($match[4])) - $timezone;}return false;}/*** Parse RFC850's date format** @access protected* @return int Timestamp*/public function date_rfc850($date){static $pcre;if (!$pcre) {$space = '[\x09\x20]+';$day_name = $this->day_pcre;$month = $this->month_pcre;$day = '([0-9]{1,2})';$year = $hour = $minute = $second = '([0-9]{2})';$zone = '([A-Z]{1,5})';$pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';}if (preg_match($pcre, $date, $match)) {/*Capturing subpatterns:1: Day name2: Day3: Month4: Year5: Hour6: Minute7: Second8: Timezone*/// Month$month = $this->month[strtolower($match[3])];// Character timezoneif (isset($this->timezone[strtoupper($match[8])])) {$timezone = $this->timezone[strtoupper($match[8])];}// Assume everything else to be -0000else {$timezone = 0;}// Deal with 2 digit yearif ($match[4] < 50) {$match[4] += 2000;} else {$match[4] += 1900;}return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;}return false;}/*** Parse C99's asctime()'s date format** @access protected* @return int Timestamp*/public function date_asctime($date){static $pcre;if (!$pcre) {$space = '[\x09\x20]+';$wday_name = $this->day_pcre;$mon_name = $this->month_pcre;$day = '([0-9]{1,2})';$hour = $sec = $min = '([0-9]{2})';$year = '([0-9]{4})';$terminator = '\x0A?\x00?';$pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';}if (preg_match($pcre, $date, $match)) {/*Capturing subpatterns:1: Day name2: Month3: Day4: Hour5: Minute6: Second7: Year*/$month = $this->month[strtolower($match[2])];return gmmktime((int) $match[4], (int) $match[5], (int) $match[6], $month, (int) $match[3], (int) $match[7]);}return false;}/*** Parse dates using strtotime()** @access protected* @return int Timestamp*/public function date_strtotime($date){$strtotime = strtotime($date);if ($strtotime === -1 || $strtotime === false) {return false;}return $strtotime;}}class_alias('SimplePie\Parse\Date', 'SimplePie_Parse_Date');