Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

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