Date.php 20 KB

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