PageRenderTime 272ms CodeModel.GetById 36ms RepoModel.GetById 3ms app.codeStats 0ms

/wp-includes/SimplePie/Parse/Date.php

https://bitbucket.org/abnopanda/wordpress
PHP | 983 lines | 697 code | 44 blank | 242 comment | 31 complexity | 9a0a326d308c1e48a0f89bd3ce6e2760 MD5 | raw file
  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-2012, 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. * @version 1.3.1
  37. * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  38. * @author Ryan Parman
  39. * @author Geoffrey Sneddon
  40. * @author Ryan McCue
  41. * @link http://simplepie.org/ SimplePie
  42. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  43. */
  44. /**
  45. * Date Parser
  46. *
  47. * @package SimplePie
  48. * @subpackage Parsing
  49. */
  50. class SimplePie_Parse_Date
  51. {
  52. /**
  53. * Input data
  54. *
  55. * @access protected
  56. * @var string
  57. */
  58. var $date;
  59. /**
  60. * List of days, calendar day name => ordinal day number in the week
  61. *
  62. * @access protected
  63. * @var array
  64. */
  65. var $day = array(
  66. // English
  67. 'mon' => 1,
  68. 'monday' => 1,
  69. 'tue' => 2,
  70. 'tuesday' => 2,
  71. 'wed' => 3,
  72. 'wednesday' => 3,
  73. 'thu' => 4,
  74. 'thursday' => 4,
  75. 'fri' => 5,
  76. 'friday' => 5,
  77. 'sat' => 6,
  78. 'saturday' => 6,
  79. 'sun' => 7,
  80. 'sunday' => 7,
  81. // Dutch
  82. 'maandag' => 1,
  83. 'dinsdag' => 2,
  84. 'woensdag' => 3,
  85. 'donderdag' => 4,
  86. 'vrijdag' => 5,
  87. 'zaterdag' => 6,
  88. 'zondag' => 7,
  89. // French
  90. 'lundi' => 1,
  91. 'mardi' => 2,
  92. 'mercredi' => 3,
  93. 'jeudi' => 4,
  94. 'vendredi' => 5,
  95. 'samedi' => 6,
  96. 'dimanche' => 7,
  97. // German
  98. 'montag' => 1,
  99. 'dienstag' => 2,
  100. 'mittwoch' => 3,
  101. 'donnerstag' => 4,
  102. 'freitag' => 5,
  103. 'samstag' => 6,
  104. 'sonnabend' => 6,
  105. 'sonntag' => 7,
  106. // Italian
  107. 'lunedì' => 1,
  108. 'martedì' => 2,
  109. 'mercoledì' => 3,
  110. 'giovedì' => 4,
  111. 'venerdì' => 5,
  112. 'sabato' => 6,
  113. 'domenica' => 7,
  114. // Spanish
  115. 'lunes' => 1,
  116. 'martes' => 2,
  117. 'miércoles' => 3,
  118. 'jueves' => 4,
  119. 'viernes' => 5,
  120. 'sábado' => 6,
  121. 'domingo' => 7,
  122. // Finnish
  123. 'maanantai' => 1,
  124. 'tiistai' => 2,
  125. 'keskiviikko' => 3,
  126. 'torstai' => 4,
  127. 'perjantai' => 5,
  128. 'lauantai' => 6,
  129. 'sunnuntai' => 7,
  130. // Hungarian
  131. 'hétfő' => 1,
  132. 'kedd' => 2,
  133. 'szerda' => 3,
  134. 'csütörtok' => 4,
  135. 'péntek' => 5,
  136. 'szombat' => 6,
  137. 'vasárnap' => 7,
  138. // Greek
  139. 'Δευ' => 1,
  140. 'Τρι' => 2,
  141. 'Τετ' => 3,
  142. 'Πεμ' => 4,
  143. 'Παρ' => 5,
  144. 'Σαβ' => 6,
  145. 'Κυρ' => 7,
  146. );
  147. /**
  148. * List of months, calendar month name => calendar month number
  149. *
  150. * @access protected
  151. * @var array
  152. */
  153. var $month = array(
  154. // English
  155. 'jan' => 1,
  156. 'january' => 1,
  157. 'feb' => 2,
  158. 'february' => 2,
  159. 'mar' => 3,
  160. 'march' => 3,
  161. 'apr' => 4,
  162. 'april' => 4,
  163. 'may' => 5,
  164. // No long form of May
  165. 'jun' => 6,
  166. 'june' => 6,
  167. 'jul' => 7,
  168. 'july' => 7,
  169. 'aug' => 8,
  170. 'august' => 8,
  171. 'sep' => 9,
  172. 'september' => 8,
  173. 'oct' => 10,
  174. 'october' => 10,
  175. 'nov' => 11,
  176. 'november' => 11,
  177. 'dec' => 12,
  178. 'december' => 12,
  179. // Dutch
  180. 'januari' => 1,
  181. 'februari' => 2,
  182. 'maart' => 3,
  183. 'april' => 4,
  184. 'mei' => 5,
  185. 'juni' => 6,
  186. 'juli' => 7,
  187. 'augustus' => 8,
  188. 'september' => 9,
  189. 'oktober' => 10,
  190. 'november' => 11,
  191. 'december' => 12,
  192. // French
  193. 'janvier' => 1,
  194. 'février' => 2,
  195. 'mars' => 3,
  196. 'avril' => 4,
  197. 'mai' => 5,
  198. 'juin' => 6,
  199. 'juillet' => 7,
  200. 'août' => 8,
  201. 'septembre' => 9,
  202. 'octobre' => 10,
  203. 'novembre' => 11,
  204. 'décembre' => 12,
  205. // German
  206. 'januar' => 1,
  207. 'februar' => 2,
  208. 'märz' => 3,
  209. 'april' => 4,
  210. 'mai' => 5,
  211. 'juni' => 6,
  212. 'juli' => 7,
  213. 'august' => 8,
  214. 'september' => 9,
  215. 'oktober' => 10,
  216. 'november' => 11,
  217. 'dezember' => 12,
  218. // Italian
  219. 'gennaio' => 1,
  220. 'febbraio' => 2,
  221. 'marzo' => 3,
  222. 'aprile' => 4,
  223. 'maggio' => 5,
  224. 'giugno' => 6,
  225. 'luglio' => 7,
  226. 'agosto' => 8,
  227. 'settembre' => 9,
  228. 'ottobre' => 10,
  229. 'novembre' => 11,
  230. 'dicembre' => 12,
  231. // Spanish
  232. 'enero' => 1,
  233. 'febrero' => 2,
  234. 'marzo' => 3,
  235. 'abril' => 4,
  236. 'mayo' => 5,
  237. 'junio' => 6,
  238. 'julio' => 7,
  239. 'agosto' => 8,
  240. 'septiembre' => 9,
  241. 'setiembre' => 9,
  242. 'octubre' => 10,
  243. 'noviembre' => 11,
  244. 'diciembre' => 12,
  245. // Finnish
  246. 'tammikuu' => 1,
  247. 'helmikuu' => 2,
  248. 'maaliskuu' => 3,
  249. 'huhtikuu' => 4,
  250. 'toukokuu' => 5,
  251. 'kesäkuu' => 6,
  252. 'heinäkuu' => 7,
  253. 'elokuu' => 8,
  254. 'suuskuu' => 9,
  255. 'lokakuu' => 10,
  256. 'marras' => 11,
  257. 'joulukuu' => 12,
  258. // Hungarian
  259. 'január' => 1,
  260. 'február' => 2,
  261. 'március' => 3,
  262. 'április' => 4,
  263. 'május' => 5,
  264. 'június' => 6,
  265. 'július' => 7,
  266. 'augusztus' => 8,
  267. 'szeptember' => 9,
  268. 'október' => 10,
  269. 'november' => 11,
  270. 'december' => 12,
  271. // Greek
  272. 'Ιαν' => 1,
  273. 'Φεβ' => 2,
  274. 'Μάώ' => 3,
  275. 'Μαώ' => 3,
  276. 'Απρ' => 4,
  277. 'Μάι' => 5,
  278. 'Μαϊ' => 5,
  279. 'Μαι' => 5,
  280. 'Ιούν' => 6,
  281. 'Ιον' => 6,
  282. 'Ιούλ' => 7,
  283. 'Ιολ' => 7,
  284. 'Αύγ' => 8,
  285. 'Αυγ' => 8,
  286. 'Σεπ' => 9,
  287. 'Οκτ' => 10,
  288. 'Νοέ' => 11,
  289. 'Δεκ' => 12,
  290. );
  291. /**
  292. * List of timezones, abbreviation => offset from UTC
  293. *
  294. * @access protected
  295. * @var array
  296. */
  297. var $timezone = array(
  298. 'ACDT' => 37800,
  299. 'ACIT' => 28800,
  300. 'ACST' => 34200,
  301. 'ACT' => -18000,
  302. 'ACWDT' => 35100,
  303. 'ACWST' => 31500,
  304. 'AEDT' => 39600,
  305. 'AEST' => 36000,
  306. 'AFT' => 16200,
  307. 'AKDT' => -28800,
  308. 'AKST' => -32400,
  309. 'AMDT' => 18000,
  310. 'AMT' => -14400,
  311. 'ANAST' => 46800,
  312. 'ANAT' => 43200,
  313. 'ART' => -10800,
  314. 'AZOST' => -3600,
  315. 'AZST' => 18000,
  316. 'AZT' => 14400,
  317. 'BIOT' => 21600,
  318. 'BIT' => -43200,
  319. 'BOT' => -14400,
  320. 'BRST' => -7200,
  321. 'BRT' => -10800,
  322. 'BST' => 3600,
  323. 'BTT' => 21600,
  324. 'CAST' => 18000,
  325. 'CAT' => 7200,
  326. 'CCT' => 23400,
  327. 'CDT' => -18000,
  328. 'CEDT' => 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 seperator (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($match[6] + $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 ($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. }