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