Date.php 19 KB

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