mlandauer / phplib

Web Application component for Open Australia (phplib module)

This URL has Read+Write access

phplib / conditional.php
100644 153 lines (134 sloc) 5.069 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<?php
/*
* conditional.php:
* Support for HTTP conditional GET.
*
* Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
* Email: chris@mysociety.org; WWW: http://www.mysociety.org/
*
* $Id: conditional.php,v 1.6 2007/09/19 17:32:43 matthew Exp $
*
*/
 
$cond_wkday_re = '(Sun|Mon|Tue|Wed|Thu|Fri|Sat)';
$cond_weekday_re = '(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)';
$cond_month_re = '(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)';
$cond_month_map = array(
        'Jan' => 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4,
        'May' => 5, 'Jun' => 6, 'Jul' => 7, 'Aug' => 8,
        'Sep' => 9, 'Oct' => 10, 'Nov' => 11, 'Dec' => 12
    );
 
$cond_date1_re = '(\d\d) ' . $cond_month_re . ' (\d\d\d\d)';
$cond_date2_re = '(\d\d)-' . $cond_month_re . '-(\d\d)';
$cond_date3_re = $cond_month_re . ' (\d\d| \d)';
 
$cond_time_re = '([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|6[012])';
    /* XXX RFC 2616 prohibits seconds beyond 59, but presumably they will occur
* as leap seconds sometimes. */
 
/* cond_parse_http_date DATE
* Parse the supplied HTTP-style DATE, returning the number of seconds since
* the epoch that it represents, or null if it could not be parsed. */
function cond_parse_http_date($date) {
    /* Unfortunately there is no strptime in PHP <5, so we must do this
* manually. */
    $H = $M = $S = 0;
    $Y = $m = $d = 0;
 
    $ma = array();
    global $cond_wkday_re, $cond_weekday_re, $cond_month_re, $cond_month_map,
            $cond_date1_re, $cond_date2_re, $cond_date3_re, $cond_time_re;
    if (preg_match("/^$cond_wkday_re, $cond_date1_re $cond_time_re GMT\$/", $date, $ma)) {
        /* RFC 1123 */
        $d = $ma[2];
        $m = $cond_month_map[$ma[3]];
        $Y = $ma[4];
        $H = $ma[5];
        $M = $ma[6];
        $S = $ma[7];
    } else if (preg_match("/^$cond_weekday_re, $cond_date2_re $cond_time_re GMT\$/", $date, $ma)) {
        /* RFC 850 */
        $d = $ma[2];
        $m = $cond_month_map[$ma[3]];
        $Y = $ma[4] + ($ma[4] < 50 ? 2000 : 1900); /* XXX */
        $H = $ma[5];
        $M = $ma[6];
        $S = $ma[7];
    } else if (preg_match("/^$cond_wkday_re $cond_date3_re $cond_time_re (\\d{4})\$/", $date, $ma)) {
        /* asctime(3) */
        $d = preg_replace('/ /', '', $ma[3]);
        $m = $cond_month_map[$ma[2]];
        $Y = $ma[7];
        $H = $ma[4];
        $M = $ma[5];
        $S = $ma[6];
    } else
        return null;
 
    return gmmktime($H, $M, $S, $m, $d, $Y);
}
 
/* cond_quote_etag ETAG
* Return a quoted copy of ETAG suitable for including in an ETag: header. */
function cond_quote_etag($etag) {
    return '"' . preg_replace('/([\\"])/', '\\\\$1', $etag) . '"';
}
 
/* cond_headers TIME [ETAG]
* Send Last-Modified: and ETag: headers. The ETAG is assumed to be a weak
* one. */
function cond_headers($time, $etag = null) {
    if (isset($time))
        header('Last-Modified: ' . gmstrftime('%a, %d %b %Y %H:%M:%S GMT', $time));
    if (isset($etag))
        header('ETag: W/' . cond_quote_etag($etag));
}
 
/* cond_304 TIME [ETAG]
* Do a 304 Not Modified response. */
function cond_304($time, $etag = null) {
    header('Status: 304 Not Modified');
    cond_headers($time, $etag);
}
 
/* cond_maybe_respond TIME [ETAG]
* If the client has indicated that they already have a page modified at or
* after the given last-modified TIME, or one which matches the supplied ETAG,
* then generate an appropriate 304 Not Modified response and return true;
* otherwise, return false. Either TIME or ETAG may be null if a last-modified
* time or entity tag are not available for this page. ETAG is assumed to be
* a weak etag if it is supplied. */
function cond_maybe_respond($time, $etag = null) {
 
    if (!array_key_exists('REQUEST_METHOD', $_SERVER)
        && $_SERVER['REQUEST_METHOD'] != 'GET'
        && $_SERVER['REQUEST_METHOD'] != 'HEAD')
        return false;
 
    $check_etag = (isset($etag) && array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER));
    $check_ims = (isset($time) && array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER));
 
    if ($check_etag && $check_ims) {
        if (cond_if_modified_since($time) && cond_if_none_match($etag)) {
cond_304($time, $etag);
return true;
}
    } elseif ($check_etag) {
        if (cond_if_none_match($etag)) {
cond_304($time, $etag);
return true;
}
    } elseif ($check_ims) {
        if (cond_if_modified_since($time)) {
            cond_304($time, $etag);
            return true;
        }
    }
    
    return false;
}
 
function cond_if_modified_since($time) {
    $t = cond_parse_http_date($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    if (isset($t) && $t >= $time)
        return true;
    return false;
}
 
function cond_if_none_match($etag) {
    if ($_SERVER['HTTP_IF_NONE_MATCH'] == '*') return true;
    $etags = preg_split('/\s*,\s*/', $_SERVER['HTTP_IF_NONE_MATCH']);
    $q = 'W/' . cond_quote_etag($etag);
    foreach ($etags as $q2) {
        if ($q2 == $q) {
            return true;
        }
    }
 
    return false;
}
 
?>