Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
/**
4
 *  BENNU - PHP iCalendar library
5
 *  (c) 2005-2006 Ioannis Papaioannou (pj@moodle.org). All rights reserved.
6
 *
7
 *  Released under the LGPL.
8
 *
9
 *  See http://bennu.sourceforge.net/ for more information and downloads.
10
 *
11
 * @author Ioannis Papaioannou
12
 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
13
 */
14
 
15
/*
16
 
17
   All names of properties, property parameters, enumerated property
18
   values and property parameter values are case-insensitive. However,
19
   all other property values are case-sensitive, unless otherwise
20
   stated.
21
 
22
*/
23
 
24
define('RFC2445_CRLF',               "\r\n");
25
define('RFC2445_WSP',                "\t ");
26
define('RFC2445_WEEKDAYS',           'MO,TU,WE,TH,FR,SA,SU');
27
define('RFC2445_FOLDED_LINE_LENGTH', 75);
28
 
29
define('RFC2445_PARAMETER_SEPARATOR',	';');
30
define('RFC2445_VALUE_SEPARATOR',    	':');
31
 
32
define('RFC2445_REQUIRED', 0x01);
33
define('RFC2445_OPTIONAL', 0x02);
34
define('RFC2445_ONCE',     0x04);
35
 
36
define('RFC2445_PROP_FLAGS',       0);
37
define('RFC2445_PROP_TYPE',        1);
38
define('RFC2445_PROP_DEFAULT',     2);
39
 
40
define('RFC2445_XNAME', 'X-');
41
 
42
define('RFC2445_TYPE_BINARY',       0);
43
define('RFC2445_TYPE_BOOLEAN',      1);
44
define('RFC2445_TYPE_CAL_ADDRESS',  2);
45
define('RFC2445_TYPE_DATE',         3);
46
define('RFC2445_TYPE_DATE_TIME',    4);
47
define('RFC2445_TYPE_DURATION',     5);
48
define('RFC2445_TYPE_FLOAT',        6);
49
define('RFC2445_TYPE_INTEGER',      7);
50
define('RFC2445_TYPE_PERIOD',       8);
51
define('RFC2445_TYPE_RECUR',        9);
52
define('RFC2445_TYPE_TEXT',        10);
53
define('RFC2445_TYPE_TIME',        11);
54
define('RFC2445_TYPE_URI',         12); // CAL_ADDRESS === URI
55
define('RFC2445_TYPE_UTC_OFFSET',  13);
56
 
57
 
58
function rfc2445_fold($string) {
59
    if(core_text::strlen($string, 'utf-8') <= RFC2445_FOLDED_LINE_LENGTH) {
60
        return $string;
61
    }
62
 
63
    $retval = '';
64
 
65
    $i=0;
66
    $len_count=0;
67
 
68
    //multi-byte string, get the correct length
69
    $section_len = core_text::strlen($string, 'utf-8');
70
 
71
    while($len_count<$section_len) {
72
 
73
        //get the current portion of the line
74
        $section = core_text::substr($string, ($i * RFC2445_FOLDED_LINE_LENGTH), (RFC2445_FOLDED_LINE_LENGTH), 'utf-8');
75
 
76
        //increment the length we've processed by the length of the new portion
77
        $len_count += core_text::strlen($section, 'utf-8');
78
 
79
        /* Add the portion to the return value, terminating with CRLF.HTAB
80
           As per RFC 2445, CRLF.HTAB will be replaced by the processor of the
81
           data */
82
        $retval .= $section . RFC2445_CRLF . substr(RFC2445_WSP, 0, 1);
83
 
84
        $i++;
85
    }
86
 
87
    return $retval;
88
 
89
}
90
 
91
function rfc2445_unfold($string) {
92
    for($i = 0; $i < strlen(RFC2445_WSP); ++$i) {
93
        $string = str_replace(RFC2445_CRLF.substr(RFC2445_WSP, $i, 1), '', $string);
94
    }
95
 
96
    return $string;
97
}
98
 
99
function rfc2445_is_xname($name) {
100
 
101
    // If it's less than 3 chars, it cannot be legal
102
    if(strlen($name) < 3) {
103
        return false;
104
    }
105
 
106
    // If it contains an illegal char anywhere, reject it
107
    if(strspn($name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-') != strlen($name)) {
108
        return false;
109
    }
110
 
111
    // To be legal, it must still start with "X-"
112
    return substr($name, 0, 2) === 'X-';
113
}
114
 
115
function rfc2445_is_valid_value($value, $type) {
116
 
117
    // This branch should only be taken with xname values
118
    if($type === NULL) {
119
        return true;
120
    }
121
 
122
    switch($type) {
123
        case RFC2445_TYPE_CAL_ADDRESS:
124
        case RFC2445_TYPE_URI:
125
            if(!is_string($value)) {
126
                return false;
127
            }
128
 
129
            $valid_schemes = array('ftp', 'http', 'ldap', 'gopher', 'mailto', 'news', 'nntp', 'telnet', 'wais', 'file', 'prospero');
130
 
131
            $pos = strpos($value, ':');
132
            if(!$pos) {
133
                return false;
134
            }
135
 
136
            $scheme = strtolower(substr($value, 0, $pos));
137
            $remain = substr($value, $pos + 1);
138
 
139
            if(!in_array($scheme, $valid_schemes)) {
140
                return false;
141
            }
142
 
143
            if($scheme === 'mailto') {
144
                $regexp = '#^[a-zA-Z0-9]+[_a-zA-Z0-9\-]*(\.[_a-z0-9\-]+)*@(([0-9a-zA-Z\-]+\.)+[a-zA-Z][0-9a-zA-Z\-]+|([0-9]{1,3}\.){3}[0-9]{1,3})$#';
145
            }
146
            else {
147
                $regexp = '#^//(.+(:.*)?@)?(([0-9a-zA-Z\-]+\.)+[a-zA-Z][0-9a-zA-Z\-]+|([0-9]{1,3}\.){3}[0-9]{1,3})(:[0-9]{1,5})?(/.*)?$#';
148
            }
149
 
150
            return preg_match($regexp, $remain);
151
        break;
152
 
153
        case RFC2445_TYPE_BINARY:
154
            if(!is_string($value)) {
155
                return false;
156
            }
157
 
158
            $len = strlen($value);
159
 
160
            if($len % 4 != 0) {
161
                return false;
162
            }
163
 
164
            for($i = 0; $i < $len; ++$i) {
165
                $ch = $value[$i];
166
                if(!($ch >= 'a' && $ch <= 'z' || $ch >= 'A' && $ch <= 'Z' || $ch >= '0' && $ch <= '9' || $ch == '-' || $ch == '+')) {
167
                    if($ch == '=' && $len - $i <= 2) {
168
                        continue;
169
                    }
170
                    return false;
171
                }
172
            }
173
            return true;
174
        break;
175
 
176
        case RFC2445_TYPE_BOOLEAN:
177
            if(is_bool($value)) {
178
                return true;
179
            }
180
            if(is_string($value)) {
181
                $value = strtoupper($value);
182
                return ($value == 'TRUE' || $value == 'FALSE');
183
            }
184
            return false;
185
        break;
186
 
187
        case RFC2445_TYPE_DATE:
188
            if(is_int($value)) {
189
                if($value < 0) {
190
                    return false;
191
                }
192
                $value = "$value";
193
            }
194
            else if(!is_string($value)) {
195
                return false;
196
            }
197
 
198
            if(strlen($value) != 8) {
199
                return false;
200
            }
201
 
202
            $y = intval(substr($value, 0, 4));
203
            $m = intval(substr($value, 4, 2));
204
            $d = intval(substr($value, 6, 2));
205
 
206
            return checkdate($m, $d, $y);
207
        break;
208
 
209
        case RFC2445_TYPE_DATE_TIME:
210
            if(!is_string($value) || strlen($value) < 15) {
211
                return false;
212
            }
213
 
214
            return($value[8] == 'T' &&
215
                   rfc2445_is_valid_value(substr($value, 0, 8), RFC2445_TYPE_DATE) &&
216
                   rfc2445_is_valid_value(substr($value, 9), RFC2445_TYPE_TIME));
217
        break;
218
 
219
        case RFC2445_TYPE_DURATION:
220
            if(!is_string($value)) {
221
                return false;
222
            }
223
 
224
            $len = strlen($value);
225
 
226
            if($len < 3) {
227
                // Minimum conformant length: "P1W"
228
                return false;
229
            }
230
 
231
            if($value[0] == '+' || $value[0] == '-') {
232
                $value = substr($value, 1);
233
                --$len; // Don't forget to update this!
234
            }
235
 
236
            if($value[0] != 'P') {
237
                return false;
238
            }
239
 
240
            // OK, now break it up
241
            $num = '';
242
            $allowed = 'WDT';
243
 
244
            for($i = 1; $i < $len; ++$i) {
245
                $ch = $value[$i];
246
                if($ch >= '0' && $ch <= '9') {
247
                    $num .= $ch;
248
                    continue;
249
                }
250
                if(strpos($allowed, $ch) === false) {
251
                    // Non-numeric character which shouldn't be here
252
                    return false;
253
                }
254
                if($num === '' && $ch != 'T') {
255
                    // Allowed non-numeric character, but no digits came before it
256
                    return false;
257
                }
258
 
259
                // OK, $ch now holds a character which tells us what $num is
260
                switch($ch) {
261
                    case 'W':
262
                        // If duration in weeks is specified, this must end the string
263
                        return ($i == $len - 1);
264
                    break;
265
 
266
                    case 'D':
267
                        // Days specified, now if anything comes after it must be a 'T'
268
                        $allowed = 'T';
269
                    break;
270
 
271
                    case 'T':
272
                        // Starting to specify time, H M S are now valid delimiters
273
                        $allowed = 'HMS';
274
                    break;
275
 
276
                    case 'H':
277
                        $allowed = 'M';
278
                    break;
279
 
280
                    case 'M':
281
                        $allowed = 'S';
282
                    break;
283
 
284
                    case 'S':
285
                        return ($i == $len - 1);
286
                    break;
287
                }
288
 
289
                // If we 're going to continue, reset $num
290
                $num = '';
291
 
292
            }
293
 
294
            // $num is kept for this reason: if we 're here, we ran out of chars
295
            // therefore $num must be empty for the period to be legal
296
            return ($num === '' && $ch != 'T');
297
 
298
        break;
299
 
300
        case RFC2445_TYPE_FLOAT:
301
            if(is_float($value)) {
302
                return true;
303
            }
304
            if(!is_string($value) || $value === '') {
305
                return false;
306
            }
307
 
308
            $dot = false;
309
            $int = false;
310
            $len = strlen($value);
311
            for($i = 0; $i < $len; ++$i) {
312
                switch($value[$i]) {
313
                    case '-': case '+':
314
                        // A sign can only be seen at position 0 and cannot be the only char
315
                        if($i != 0 || $len == 1) {
316
                            return false;
317
                        }
318
                    break;
319
                    case '.':
320
                        // A second dot is an error
321
                        // Make sure we had at least one int before the dot
322
                        if($dot || !$int) {
323
                            return false;
324
                        }
325
                        $dot = true;
326
                        // Make also sure that the float doesn't end with a dot
327
                        if($i == $len - 1) {
328
                            return false;
329
                        }
330
                    break;
331
                    case '0': case '1': case '2': case '3': case '4':
332
                    case '5': case '6': case '7': case '8': case '9':
333
                        $int = true;
334
                    break;
335
                    default:
336
                        // Any other char is a no-no
337
                        return false;
338
                    break;
339
                }
340
            }
341
            return true;
342
        break;
343
 
344
        case RFC2445_TYPE_INTEGER:
345
            if(is_int($value)) {
346
                return true;
347
            }
348
            if(!is_string($value) || $value === '') {
349
                return false;
350
            }
351
 
352
            if($value[0] == '+' || $value[0] == '-') {
353
                if(strlen($value) == 1) {
354
                    return false;
355
                }
356
                $value = substr($value, 1);
357
            }
358
 
359
            if(strspn($value, '0123456789') != strlen($value)) {
360
                return false;
361
            }
362
 
363
            return ($value >= -2147483648 && $value <= 2147483647);
364
        break;
365
 
366
        case RFC2445_TYPE_PERIOD:
367
            if(!is_string($value) || empty($value)) {
368
                return false;
369
            }
370
 
371
            $parts = explode('/', $value);
372
            if(count($parts) != 2) {
373
                return false;
374
            }
375
 
376
            if(!rfc2445_is_valid_value($parts[0], RFC2445_TYPE_DATE_TIME)) {
377
                return false;
378
            }
379
 
380
            // Two legal cases for the second part:
381
            if(rfc2445_is_valid_value($parts[1], RFC2445_TYPE_DATE_TIME)) {
382
                // It has to be after the start time, so
383
                return ($parts[1] > $parts[0]);
384
            }
385
            else if(rfc2445_is_valid_value($parts[1], RFC2445_TYPE_DURATION)) {
386
                // The period MUST NOT be negative
387
                return ($parts[1][0] != '-');
388
            }
389
 
390
            // It seems to be illegal
391
            return false;
392
        break;
393
 
394
        case RFC2445_TYPE_RECUR:
395
            if(!is_string($value)) {
396
                return false;
397
            }
398
 
399
            $parts = explode(';', strtoupper($value));
400
 
401
            // We need at least one part for a valid rule, for example: "FREQ=DAILY".
402
            if(empty($parts)) {
403
                return false;
404
            }
405
 
406
            // Let's get that into a more easily comprehensible format
407
            $vars = array();
408
            foreach($parts as $part) {
409
 
410
                $pieces = explode('=', $part);
411
                // There must be exactly 2 pieces, e.g. FREQ=WEEKLY
412
                if(count($pieces) != 2) {
413
                    return false;
414
                }
415
 
416
                // It's illegal for a variable to appear twice
417
                if(isset($vars[$pieces[0]])) {
418
                    return false;
419
                }
420
 
421
                // Sounds good
422
                $vars[$pieces[0]] = $pieces[1];
423
            }
424
 
425
            // OK... now to test everything else
426
 
427
            // FREQ must be the first thing appearing
428
            reset($vars);
429
            if(key($vars) != 'FREQ') {
430
                return false;
431
            }
432
 
433
            // It's illegal to have both UNTIL and COUNT appear
434
            if(isset($vars['UNTIL']) && isset($vars['COUNT'])) {
435
                return false;
436
            }
437
 
438
            // Special case: BYWEEKNO is only valid for FREQ=YEARLY
439
            if(isset($vars['BYWEEKNO']) && $vars['FREQ'] != 'YEARLY') {
440
                return false;
441
            }
442
 
443
            // Special case: BYSETPOS is only valid if another BY option is specified
444
            if(isset($vars['BYSETPOS'])) {
445
                $options = array('BYSECOND', 'BYMINUTE', 'BYHOUR', 'BYDAY', 'BYMONTHDAY', 'BYYEARDAY', 'BYWEEKNO', 'BYMONTH');
446
                $defined = array_keys($vars);
447
                $common  = array_intersect($options, $defined);
448
                if(empty($common)) {
449
                    return false;
450
                }
451
            }
452
 
453
            // OK, now simply check if each element has a valid value,
454
            // unsetting them on the way. If at the end the array still
455
            // has some elements, they are illegal.
456
 
457
            if($vars['FREQ'] != 'SECONDLY' && $vars['FREQ'] != 'MINUTELY' && $vars['FREQ'] != 'HOURLY' &&
458
               $vars['FREQ'] != 'DAILY'    && $vars['FREQ'] != 'WEEKLY' &&
459
               $vars['FREQ'] != 'MONTHLY'  && $vars['FREQ'] != 'YEARLY') {
460
                return false;
461
            }
462
            unset($vars['FREQ']);
463
 
464
            // Set this, we may need it later
465
            $weekdays = explode(',', RFC2445_WEEKDAYS);
466
 
467
            if(isset($vars['UNTIL'])) {
468
                if(rfc2445_is_valid_value($vars['UNTIL'], RFC2445_TYPE_DATE_TIME)) {
469
                    // The time MUST be in UTC format
470
                    if(!(substr($vars['UNTIL'], -1) == 'Z')) {
471
                        return false;
472
                    }
473
                }
474
                else if(!rfc2445_is_valid_value($vars['UNTIL'], RFC2445_TYPE_DATE_TIME)) {
475
                    return false;
476
                }
477
            }
478
            unset($vars['UNTIL']);
479
 
480
 
481
            if(isset($vars['COUNT'])) {
482
                if(empty($vars['COUNT'])) {
483
                    // This also catches the string '0', which makes no sense
484
                    return false;
485
                }
486
                if(strspn($vars['COUNT'], '0123456789') != strlen($vars['COUNT'])) {
487
                    return false;
488
                }
489
            }
490
            unset($vars['COUNT']);
491
 
492
 
493
            if(isset($vars['INTERVAL'])) {
494
                if(empty($vars['INTERVAL'])) {
495
                    // This also catches the string '0', which makes no sense
496
                    return false;
497
                }
498
                if(strspn($vars['INTERVAL'], '0123456789') != strlen($vars['INTERVAL'])) {
499
                    return false;
500
                }
501
            }
502
            unset($vars['INTERVAL']);
503
 
504
 
505
            if(isset($vars['BYSECOND'])) {
506
                if($vars['BYSECOND'] == '') {
507
                    return false;
508
                }
509
                // Comma also allowed
510
                if(strspn($vars['BYSECOND'], '0123456789,') != strlen($vars['BYSECOND'])) {
511
                    return false;
512
                }
513
                $secs = explode(',', $vars['BYSECOND']);
514
                foreach($secs as $sec) {
515
                    if($sec == '' || $sec < 0 || $sec > 59) {
516
                        return false;
517
                    }
518
                }
519
            }
520
            unset($vars['BYSECOND']);
521
 
522
 
523
            if(isset($vars['BYMINUTE'])) {
524
                if($vars['BYMINUTE'] == '') {
525
                    return false;
526
                }
527
                // Comma also allowed
528
                if(strspn($vars['BYMINUTE'], '0123456789,') != strlen($vars['BYMINUTE'])) {
529
                    return false;
530
                }
531
                $mins = explode(',', $vars['BYMINUTE']);
532
                foreach($mins as $min) {
533
                    if($min == '' || $min < 0 || $min > 59) {
534
                        return false;
535
                    }
536
                }
537
            }
538
            unset($vars['BYMINUTE']);
539
 
540
 
541
            if(isset($vars['BYHOUR'])) {
542
                if($vars['BYHOUR'] == '') {
543
                    return false;
544
                }
545
                // Comma also allowed
546
                if(strspn($vars['BYHOUR'], '0123456789,') != strlen($vars['BYHOUR'])) {
547
                    return false;
548
                }
549
                $hours = explode(',', $vars['BYHOUR']);
550
                foreach($hours as $hour) {
551
                    if($hour == '' || $hour < 0 || $hour > 23) {
552
                        return false;
553
                    }
554
                }
555
            }
556
            unset($vars['BYHOUR']);
557
 
558
 
559
            if(isset($vars['BYDAY'])) {
560
                if(empty($vars['BYDAY'])) {
561
                    return false;
562
                }
563
 
564
                // First off, split up all values we may have
565
                $days = explode(',', $vars['BYDAY']);
566
 
567
                foreach($days as $day) {
568
                    $daypart = substr($day, -2);
569
                    if(!in_array($daypart, $weekdays)) {
570
                        return false;
571
                    }
572
 
573
                    if(strlen($day) > 2) {
574
                        $intpart = substr($day, 0, strlen($day) - 2);
575
                        if(!rfc2445_is_valid_value($intpart, RFC2445_TYPE_INTEGER)) {
576
                            return false;
577
                        }
578
                        if(intval($intpart) == 0) {
579
                            return false;
580
                        }
581
                    }
582
                }
583
            }
584
            unset($vars['BYDAY']);
585
 
586
 
587
            if(isset($vars['BYMONTHDAY'])) {
588
                if(empty($vars['BYMONTHDAY'])) {
589
                    return false;
590
                }
591
                $mdays = explode(',', $vars['BYMONTHDAY']);
592
                foreach($mdays as $mday) {
593
                    if(!rfc2445_is_valid_value($mday, RFC2445_TYPE_INTEGER)) {
594
                        return false;
595
                    }
596
                    $mday = abs(intval($mday));
597
                    if($mday == 0 || $mday > 31) {
598
                        return false;
599
                    }
600
                }
601
            }
602
            unset($vars['BYMONTHDAY']);
603
 
604
 
605
            if(isset($vars['BYYEARDAY'])) {
606
                if(empty($vars['BYYEARDAY'])) {
607
                    return false;
608
                }
609
                $ydays = explode(',', $vars['BYYEARDAY']);
610
                foreach($ydays as $yday) {
611
                    if(!rfc2445_is_valid_value($yday, RFC2445_TYPE_INTEGER)) {
612
                        return false;
613
                    }
614
                    $yday = abs(intval($yday));
615
                    if($yday == 0 || $yday > 366) {
616
                        return false;
617
                    }
618
                }
619
            }
620
            unset($vars['BYYEARDAY']);
621
 
622
 
623
            if(isset($vars['BYWEEKNO'])) {
624
                if(empty($vars['BYWEEKNO'])) {
625
                    return false;
626
                }
627
                $weeknos = explode(',', $vars['BYWEEKNO']);
628
                foreach($weeknos as $weekno) {
629
                    if(!rfc2445_is_valid_value($weekno, RFC2445_TYPE_INTEGER)) {
630
                        return false;
631
                    }
632
                    $weekno = abs(intval($weekno));
633
                    if($weekno == 0 || $weekno > 53) {
634
                        return false;
635
                    }
636
                }
637
            }
638
            unset($vars['BYWEEKNO']);
639
 
640
 
641
            if(isset($vars['BYMONTH'])) {
642
                if(empty($vars['BYMONTH'])) {
643
                    return false;
644
                }
645
                // Comma also allowed
646
                if(strspn($vars['BYMONTH'], '0123456789,') != strlen($vars['BYMONTH'])) {
647
                    return false;
648
                }
649
                $months = explode(',', $vars['BYMONTH']);
650
                foreach($months as $month) {
651
                    if($month == '' || $month < 1 || $month > 12) {
652
                        return false;
653
                    }
654
                }
655
            }
656
            unset($vars['BYMONTH']);
657
 
658
 
659
            if(isset($vars['BYSETPOS'])) {
660
                if(empty($vars['BYSETPOS'])) {
661
                    return false;
662
                }
663
                $sets = explode(',', $vars['BYSETPOS']);
664
                foreach($sets as $set) {
665
                    if(!rfc2445_is_valid_value($set, RFC2445_TYPE_INTEGER)) {
666
                        return false;
667
                    }
668
                    $set = abs(intval($set));
669
                    if($set == 0 || $set > 366) {
670
                        return false;
671
                    }
672
                }
673
            }
674
            unset($vars['BYSETPOS']);
675
 
676
 
677
            if(isset($vars['WKST'])) {
678
                if(!in_array($vars['WKST'], $weekdays)) {
679
                    return false;
680
                }
681
            }
682
            unset($vars['WKST']);
683
 
684
 
685
            // Any remaining vars must be x-names
686
            if(empty($vars)) {
687
                return true;
688
            }
689
 
690
            foreach($vars as $name => $var) {
691
                if(!rfc2445_is_xname($name)) {
692
                    return false;
693
                }
694
            }
695
 
696
            // At last, all is OK!
697
            return true;
698
 
699
        break;
700
 
701
        case RFC2445_TYPE_TEXT:
702
            return true;
703
        break;
704
 
705
        case RFC2445_TYPE_TIME:
706
            if(is_int($value)) {
707
                if($value < 0) {
708
                    return false;
709
                }
710
                $value = "$value";
711
            }
712
            else if(!is_string($value)) {
713
                return false;
714
            }
715
 
716
            if(strlen($value) == 7) {
717
                if(strtoupper(substr($value, -1)) != 'Z') {
718
                    return false;
719
                }
720
                $value = substr($value, 0, 6);
721
            }
722
            if(strlen($value) != 6) {
723
                return false;
724
            }
725
 
726
            $h = intval(substr($value, 0, 2));
727
            $m = intval(substr($value, 2, 2));
728
            $s = intval(substr($value, 4, 2));
729
 
730
            return ($h <= 23 && $m <= 59 && $s <= 60);
731
        break;
732
 
733
        case RFC2445_TYPE_UTC_OFFSET:
734
            if(is_int($value)) {
735
                if($value >= 0) {
736
                    $value = "+$value";
737
                }
738
                else {
739
                    $value = "$value";
740
                }
741
            }
742
            else if(!is_string($value)) {
743
                return false;
744
            }
745
 
746
            $s = 0;
747
            if(strlen($value) == 7) {
748
                $s = intval(substr($value, 5, 2));
749
                $value = substr($value, 0, 5);
750
            }
751
            if(strlen($value) != 5 || $value == "-0000") {
752
                return false;
753
            }
754
 
755
            if($value[0] != '+' && $value[0] != '-') {
756
                return false;
757
            }
758
 
759
            $h = intval(substr($value, 1, 2));
760
            $m = intval(substr($value, 3, 2));
761
 
762
            return ($h <= 23 && $m <= 59 && $s <= 59);
763
        break;
764
    }
765
 
766
    // TODO: remove this assertion
767
    trigger_error('bad code path', E_USER_WARNING);
768
    var_dump($type);
769
    return false;
770
}
771
 
772
function rfc2445_do_value_formatting($value, $type) {
773
    // Note: this does not only do formatting; it also does conversion to string!
774
    switch($type) {
775
        case RFC2445_TYPE_CAL_ADDRESS:
776
        case RFC2445_TYPE_URI:
777
            // Enclose in double quotes
778
            $value = '"'.$value.'"';
779
        break;
780
        case RFC2445_TYPE_TEXT:
781
            // Escape entities
782
            $value = strtr($value, array("\r\n" => '\\n', "\n" => '\\n', '\\' => '\\\\', ',' => '\\,', ';' => '\\;'));
783
        break;
784
    }
785
    return $value;
786
}
787
 
788
function rfc2445_undo_value_formatting($value, $type) {
789
    switch($type) {
790
        case RFC2445_TYPE_CAL_ADDRESS:
791
        case RFC2445_TYPE_URI:
792
            // Trim beginning and end double quote
793
            $value = substr($value, 1, strlen($value) - 2);
794
        break;
795
        case RFC2445_TYPE_TEXT:
796
            // Unescape entities
797
            $value = strtr($value, array('\\n' => "\n", '\\N' => "\n", '\\\\' => '\\', '\\,' => ',', '\\;' => ';'));
798
        break;
799
    }
800
    return $value;
801
}