WordPress 4.4
[autoinstalls/wordpress.git] / wp-includes / SimplePie / Parse / Date.php
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
46 /**
47  * Date Parser
48  *
49  * @package SimplePie
50  * @subpackage Parsing
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                 'CEST' => 7200,
335                 'CET' => 3600,
336                 'CGST' => -7200,
337                 'CGT' => -10800,
338                 'CHADT' => 49500,
339                 'CHAST' => 45900,
340                 'CIST' => -28800,
341                 'CKT' => -36000,
342                 'CLDT' => -10800,
343                 'CLST' => -14400,
344                 'COT' => -18000,
345                 'CST' => -21600,
346                 'CVT' => -3600,
347                 'CXT' => 25200,
348                 'DAVT' => 25200,
349                 'DTAT' => 36000,
350                 'EADT' => -18000,
351                 'EAST' => -21600,
352                 'EAT' => 10800,
353                 'ECT' => -18000,
354                 'EDT' => -14400,
355                 'EEST' => 10800,
356                 'EET' => 7200,
357                 'EGT' => -3600,
358                 'EKST' => 21600,
359                 'EST' => -18000,
360                 'FJT' => 43200,
361                 'FKDT' => -10800,
362                 'FKST' => -14400,
363                 'FNT' => -7200,
364                 'GALT' => -21600,
365                 'GEDT' => 14400,
366                 'GEST' => 10800,
367                 'GFT' => -10800,
368                 'GILT' => 43200,
369                 'GIT' => -32400,
370                 'GST' => 14400,
371                 'GST' => -7200,
372                 'GYT' => -14400,
373                 'HAA' => -10800,
374                 'HAC' => -18000,
375                 'HADT' => -32400,
376                 'HAE' => -14400,
377                 'HAP' => -25200,
378                 'HAR' => -21600,
379                 'HAST' => -36000,
380                 'HAT' => -9000,
381                 'HAY' => -28800,
382                 'HKST' => 28800,
383                 'HMT' => 18000,
384                 'HNA' => -14400,
385                 'HNC' => -21600,
386                 'HNE' => -18000,
387                 'HNP' => -28800,
388                 'HNR' => -25200,
389                 'HNT' => -12600,
390                 'HNY' => -32400,
391                 'IRDT' => 16200,
392                 'IRKST' => 32400,
393                 'IRKT' => 28800,
394                 'IRST' => 12600,
395                 'JFDT' => -10800,
396                 'JFST' => -14400,
397                 'JST' => 32400,
398                 'KGST' => 21600,
399                 'KGT' => 18000,
400                 'KOST' => 39600,
401                 'KOVST' => 28800,
402                 'KOVT' => 25200,
403                 'KRAST' => 28800,
404                 'KRAT' => 25200,
405                 'KST' => 32400,
406                 'LHDT' => 39600,
407                 'LHST' => 37800,
408                 'LINT' => 50400,
409                 'LKT' => 21600,
410                 'MAGST' => 43200,
411                 'MAGT' => 39600,
412                 'MAWT' => 21600,
413                 'MDT' => -21600,
414                 'MESZ' => 7200,
415                 'MEZ' => 3600,
416                 'MHT' => 43200,
417                 'MIT' => -34200,
418                 'MNST' => 32400,
419                 'MSDT' => 14400,
420                 'MSST' => 10800,
421                 'MST' => -25200,
422                 'MUT' => 14400,
423                 'MVT' => 18000,
424                 'MYT' => 28800,
425                 'NCT' => 39600,
426                 'NDT' => -9000,
427                 'NFT' => 41400,
428                 'NMIT' => 36000,
429                 'NOVST' => 25200,
430                 'NOVT' => 21600,
431                 'NPT' => 20700,
432                 'NRT' => 43200,
433                 'NST' => -12600,
434                 'NUT' => -39600,
435                 'NZDT' => 46800,
436                 'NZST' => 43200,
437                 'OMSST' => 25200,
438                 'OMST' => 21600,
439                 'PDT' => -25200,
440                 'PET' => -18000,
441                 'PETST' => 46800,
442                 'PETT' => 43200,
443                 'PGT' => 36000,
444                 'PHOT' => 46800,
445                 'PHT' => 28800,
446                 'PKT' => 18000,
447                 'PMDT' => -7200,
448                 'PMST' => -10800,
449                 'PONT' => 39600,
450                 'PST' => -28800,
451                 'PWT' => 32400,
452                 'PYST' => -10800,
453                 'PYT' => -14400,
454                 'RET' => 14400,
455                 'ROTT' => -10800,
456                 'SAMST' => 18000,
457                 'SAMT' => 14400,
458                 'SAST' => 7200,
459                 'SBT' => 39600,
460                 'SCDT' => 46800,
461                 'SCST' => 43200,
462                 'SCT' => 14400,
463                 'SEST' => 3600,
464                 'SGT' => 28800,
465                 'SIT' => 28800,
466                 'SRT' => -10800,
467                 'SST' => -39600,
468                 'SYST' => 10800,
469                 'SYT' => 7200,
470                 'TFT' => 18000,
471                 'THAT' => -36000,
472                 'TJT' => 18000,
473                 'TKT' => -36000,
474                 'TMT' => 18000,
475                 'TOT' => 46800,
476                 'TPT' => 32400,
477                 'TRUT' => 36000,
478                 'TVT' => 43200,
479                 'TWT' => 28800,
480                 'UYST' => -7200,
481                 'UYT' => -10800,
482                 'UZT' => 18000,
483                 'VET' => -14400,
484                 'VLAST' => 39600,
485                 'VLAT' => 36000,
486                 'VOST' => 21600,
487                 'VUT' => 39600,
488                 'WAST' => 7200,
489                 'WAT' => 3600,
490                 'WDT' => 32400,
491                 'WEST' => 3600,
492                 'WFT' => 43200,
493                 'WIB' => 25200,
494                 'WIT' => 32400,
495                 'WITA' => 28800,
496                 'WKST' => 18000,
497                 'WST' => 28800,
498                 'YAKST' => 36000,
499                 'YAKT' => 32400,
500                 'YAPT' => 36000,
501                 'YEKST' => 21600,
502                 'YEKT' => 18000,
503         );
504
505         /**
506          * Cached PCRE for SimplePie_Parse_Date::$day
507          *
508          * @access protected
509          * @var string
510          */
511         var $day_pcre;
512
513         /**
514          * Cached PCRE for SimplePie_Parse_Date::$month
515          *
516          * @access protected
517          * @var string
518          */
519         var $month_pcre;
520
521         /**
522          * Array of user-added callback methods
523          *
524          * @access private
525          * @var array
526          */
527         var $built_in = array();
528
529         /**
530          * Array of user-added callback methods
531          *
532          * @access private
533          * @var array
534          */
535         var $user = array();
536
537         /**
538          * Create new SimplePie_Parse_Date object, and set self::day_pcre,
539          * self::month_pcre, and self::built_in
540          *
541          * @access private
542          */
543         public function __construct()
544         {
545                 $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
546                 $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
547
548                 static $cache;
549                 if (!isset($cache[get_class($this)]))
550                 {
551                         $all_methods = get_class_methods($this);
552
553                         foreach ($all_methods as $method)
554                         {
555                                 if (strtolower(substr($method, 0, 5)) === 'date_')
556                                 {
557                                         $cache[get_class($this)][] = $method;
558                                 }
559                         }
560                 }
561
562                 foreach ($cache[get_class($this)] as $method)
563                 {
564                         $this->built_in[] = $method;
565                 }
566         }
567
568         /**
569          * Get the object
570          *
571          * @access public
572          */
573         public static function get()
574         {
575                 static $object;
576                 if (!$object)
577                 {
578                         $object = new SimplePie_Parse_Date;
579                 }
580                 return $object;
581         }
582
583         /**
584          * Parse a date
585          *
586          * @final
587          * @access public
588          * @param string $date Date to parse
589          * @return int Timestamp corresponding to date string, or false on failure
590          */
591         public function parse($date)
592         {
593                 foreach ($this->user as $method)
594                 {
595                         if (($returned = call_user_func($method, $date)) !== false)
596                         {
597                                 return $returned;
598                         }
599                 }
600
601                 foreach ($this->built_in as $method)
602                 {
603                         if (($returned = call_user_func(array($this, $method), $date)) !== false)
604                         {
605                                 return $returned;
606                         }
607                 }
608
609                 return false;
610         }
611
612         /**
613          * Add a callback method to parse a date
614          *
615          * @final
616          * @access public
617          * @param callable $callback
618          */
619         public function add_callback($callback)
620         {
621                 if (is_callable($callback))
622                 {
623                         $this->user[] = $callback;
624                 }
625                 else
626                 {
627                         trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
628                 }
629         }
630
631         /**
632          * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
633          * well as allowing any of upper or lower case "T", horizontal tabs, or
634          * spaces to be used as the time seperator (including more than one))
635          *
636          * @access protected
637          * @return int Timestamp
638          */
639         public function date_w3cdtf($date)
640         {
641                 static $pcre;
642                 if (!$pcre)
643                 {
644                         $year = '([0-9]{4})';
645                         $month = $day = $hour = $minute = $second = '([0-9]{2})';
646                         $decimal = '([0-9]*)';
647                         $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
648                         $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
649                 }
650                 if (preg_match($pcre, $date, $match))
651                 {
652                         /*
653                         Capturing subpatterns:
654                         1: Year
655                         2: Month
656                         3: Day
657                         4: Hour
658                         5: Minute
659                         6: Second
660                         7: Decimal fraction of a second
661                         8: Zulu
662                         9: Timezone ±
663                         10: Timezone hours
664                         11: Timezone minutes
665                         */
666
667                         // Fill in empty matches
668                         for ($i = count($match); $i <= 3; $i++)
669                         {
670                                 $match[$i] = '1';
671                         }
672
673                         for ($i = count($match); $i <= 7; $i++)
674                         {
675                                 $match[$i] = '0';
676                         }
677
678                         // Numeric timezone
679                         if (isset($match[9]) && $match[9] !== '')
680                         {
681                                 $timezone = $match[10] * 3600;
682                                 $timezone += $match[11] * 60;
683                                 if ($match[9] === '-')
684                                 {
685                                         $timezone = 0 - $timezone;
686                                 }
687                         }
688                         else
689                         {
690                                 $timezone = 0;
691                         }
692
693                         // Convert the number of seconds to an integer, taking decimals into account
694                         $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
695
696                         return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
697                 }
698                 else
699                 {
700                         return false;
701                 }
702         }
703
704         /**
705          * Remove RFC822 comments
706          *
707          * @access protected
708          * @param string $data Data to strip comments from
709          * @return string Comment stripped string
710          */
711         public function remove_rfc2822_comments($string)
712         {
713                 $string = (string) $string;
714                 $position = 0;
715                 $length = strlen($string);
716                 $depth = 0;
717
718                 $output = '';
719
720                 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
721                 {
722                         $output .= substr($string, $position, $pos - $position);
723                         $position = $pos + 1;
724                         if ($string[$pos - 1] !== '\\')
725                         {
726                                 $depth++;
727                                 while ($depth && $position < $length)
728                                 {
729                                         $position += strcspn($string, '()', $position);
730                                         if ($string[$position - 1] === '\\')
731                                         {
732                                                 $position++;
733                                                 continue;
734                                         }
735                                         elseif (isset($string[$position]))
736                                         {
737                                                 switch ($string[$position])
738                                                 {
739                                                         case '(':
740                                                                 $depth++;
741                                                                 break;
742
743                                                         case ')':
744                                                                 $depth--;
745                                                                 break;
746                                                 }
747                                                 $position++;
748                                         }
749                                         else
750                                         {
751                                                 break;
752                                         }
753                                 }
754                         }
755                         else
756                         {
757                                 $output .= '(';
758                         }
759                 }
760                 $output .= substr($string, $position);
761
762                 return $output;
763         }
764
765         /**
766          * Parse RFC2822's date format
767          *
768          * @access protected
769          * @return int Timestamp
770          */
771         public function date_rfc2822($date)
772         {
773                 static $pcre;
774                 if (!$pcre)
775                 {
776                         $wsp = '[\x09\x20]';
777                         $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
778                         $optional_fws = $fws . '?';
779                         $day_name = $this->day_pcre;
780                         $month = $this->month_pcre;
781                         $day = '([0-9]{1,2})';
782                         $hour = $minute = $second = '([0-9]{2})';
783                         $year = '([0-9]{2,4})';
784                         $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
785                         $character_zone = '([A-Z]{1,5})';
786                         $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
787                         $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';
788                 }
789                 if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
790                 {
791                         /*
792                         Capturing subpatterns:
793                         1: Day name
794                         2: Day
795                         3: Month
796                         4: Year
797                         5: Hour
798                         6: Minute
799                         7: Second
800                         8: Timezone ±
801                         9: Timezone hours
802                         10: Timezone minutes
803                         11: Alphabetic timezone
804                         */
805
806                         // Find the month number
807                         $month = $this->month[strtolower($match[3])];
808
809                         // Numeric timezone
810                         if ($match[8] !== '')
811                         {
812                                 $timezone = $match[9] * 3600;
813                                 $timezone += $match[10] * 60;
814                                 if ($match[8] === '-')
815                                 {
816                                         $timezone = 0 - $timezone;
817                                 }
818                         }
819                         // Character timezone
820                         elseif (isset($this->timezone[strtoupper($match[11])]))
821                         {
822                                 $timezone = $this->timezone[strtoupper($match[11])];
823                         }
824                         // Assume everything else to be -0000
825                         else
826                         {
827                                 $timezone = 0;
828                         }
829
830                         // Deal with 2/3 digit years
831                         if ($match[4] < 50)
832                         {
833                                 $match[4] += 2000;
834                         }
835                         elseif ($match[4] < 1000)
836                         {
837                                 $match[4] += 1900;
838                         }
839
840                         // Second is optional, if it is empty set it to zero
841                         if ($match[7] !== '')
842                         {
843                                 $second = $match[7];
844                         }
845                         else
846                         {
847                                 $second = 0;
848                         }
849
850                         return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
851                 }
852                 else
853                 {
854                         return false;
855                 }
856         }
857
858         /**
859          * Parse RFC850's date format
860          *
861          * @access protected
862          * @return int Timestamp
863          */
864         public function date_rfc850($date)
865         {
866                 static $pcre;
867                 if (!$pcre)
868                 {
869                         $space = '[\x09\x20]+';
870                         $day_name = $this->day_pcre;
871                         $month = $this->month_pcre;
872                         $day = '([0-9]{1,2})';
873                         $year = $hour = $minute = $second = '([0-9]{2})';
874                         $zone = '([A-Z]{1,5})';
875                         $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
876                 }
877                 if (preg_match($pcre, $date, $match))
878                 {
879                         /*
880                         Capturing subpatterns:
881                         1: Day name
882                         2: Day
883                         3: Month
884                         4: Year
885                         5: Hour
886                         6: Minute
887                         7: Second
888                         8: Timezone
889                         */
890
891                         // Month
892                         $month = $this->month[strtolower($match[3])];
893
894                         // Character timezone
895                         if (isset($this->timezone[strtoupper($match[8])]))
896                         {
897                                 $timezone = $this->timezone[strtoupper($match[8])];
898                         }
899                         // Assume everything else to be -0000
900                         else
901                         {
902                                 $timezone = 0;
903                         }
904
905                         // Deal with 2 digit year
906                         if ($match[4] < 50)
907                         {
908                                 $match[4] += 2000;
909                         }
910                         else
911                         {
912                                 $match[4] += 1900;
913                         }
914
915                         return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
916                 }
917                 else
918                 {
919                         return false;
920                 }
921         }
922
923         /**
924          * Parse C99's asctime()'s date format
925          *
926          * @access protected
927          * @return int Timestamp
928          */
929         public function date_asctime($date)
930         {
931                 static $pcre;
932                 if (!$pcre)
933                 {
934                         $space = '[\x09\x20]+';
935                         $wday_name = $this->day_pcre;
936                         $mon_name = $this->month_pcre;
937                         $day = '([0-9]{1,2})';
938                         $hour = $sec = $min = '([0-9]{2})';
939                         $year = '([0-9]{4})';
940                         $terminator = '\x0A?\x00?';
941                         $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
942                 }
943                 if (preg_match($pcre, $date, $match))
944                 {
945                         /*
946                         Capturing subpatterns:
947                         1: Day name
948                         2: Month
949                         3: Day
950                         4: Hour
951                         5: Minute
952                         6: Second
953                         7: Year
954                         */
955
956                         $month = $this->month[strtolower($match[2])];
957                         return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
958                 }
959                 else
960                 {
961                         return false;
962                 }
963         }
964
965         /**
966          * Parse dates using strtotime()
967          *
968          * @access protected
969          * @return int Timestamp
970          */
971         public function date_strtotime($date)
972         {
973                 $strtotime = strtotime($date);
974                 if ($strtotime === -1 || $strtotime === false)
975                 {
976                         return false;
977                 }
978                 else
979                 {
980                         return $strtotime;
981                 }
982         }
983 }
984