MediaWiki master
HttpDate.php
Go to the documentation of this file.
1<?php
2
4
24 private static $dayNames = [
25 'Mon' => true,
26 'Tue' => true,
27 'Wed' => true,
28 'Thu' => true,
29 'Fri' => true,
30 'Sat' => true,
31 'Sun' => true
32 ];
33
34 private static $monthsByName = [
35 'Jan' => 1,
36 'Feb' => 2,
37 'Mar' => 3,
38 'Apr' => 4,
39 'May' => 5,
40 'Jun' => 6,
41 'Jul' => 7,
42 'Aug' => 8,
43 'Sep' => 9,
44 'Oct' => 10,
45 'Nov' => 11,
46 'Dec' => 12,
47 ];
48
49 private static $dayNamesLong = [
50 'Monday',
51 'Tuesday',
52 'Wednesday',
53 'Thursday',
54 'Friday',
55 'Saturday',
56 'Sunday',
57 ];
58
60 private $dayName;
62 private $day;
64 private $month;
66 private $year;
68 private $hour;
70 private $minute;
72 private $second;
73
80 public static function parse( $dateString ) {
81 $parser = new self( $dateString );
82 if ( $parser->execute() ) {
83 return $parser->getUnixTime();
84 } else {
85 return null;
86 }
87 }
88
96 public static function format( $unixTime ) {
97 return gmdate( 'D, d M Y H:i:s \G\M\T', $unixTime );
98 }
99
105 private function __construct( $input ) {
106 $this->setInput( $input );
107 }
108
114 private function execute() {
115 $this->pos = 0;
116 try {
117 $this->consumeFixdate();
118 $this->assertEnd();
119 return true;
120 } catch ( HeaderParserError $e ) {
121 }
122 $this->pos = 0;
123 try {
124 $this->consumeRfc850Date();
125 $this->assertEnd();
126 return true;
127 } catch ( HeaderParserError $e ) {
128 }
129 $this->pos = 0;
130 try {
131 $this->consumeAsctimeDate();
132 $this->assertEnd();
133 return true;
134 } catch ( HeaderParserError $e ) {
135 }
136 return false;
137 }
138
144 private function consumeFixdate() {
145 $this->consumeDayName();
146 $this->consumeString( ', ' );
147 $this->consumeDate1();
148 $this->consumeString( ' ' );
149 $this->consumeTimeOfDay();
150 $this->consumeString( ' GMT' );
151 }
152
158 private function consumeDayName() {
159 $next3 = substr( $this->input, $this->pos, 3 );
160 if ( isset( self::$dayNames[$next3] ) ) {
161 $this->dayName = $next3;
162 $this->pos += 3;
163 } else {
164 $this->error( 'expected day-name' );
165 }
166 }
167
173 private function consumeDate1() {
174 $this->consumeDay();
175 $this->consumeString( ' ' );
176 $this->consumeMonth();
177 $this->consumeString( ' ' );
178 $this->consumeYear();
179 }
180
186 private function consumeDay() {
187 $this->day = $this->consumeFixedDigits( 2 );
188 }
189
195 private function consumeMonth() {
196 $next3 = substr( $this->input, $this->pos, 3 );
197 if ( isset( self::$monthsByName[$next3] ) ) {
198 $this->month = self::$monthsByName[$next3];
199 $this->pos += 3;
200 } else {
201 $this->error( 'expected month' );
202 }
203 }
204
210 private function consumeYear() {
211 $this->year = (int)$this->consumeFixedDigits( 4 );
212 }
213
218 private function consumeTimeOfDay() {
219 $this->hour = $this->consumeFixedDigits( 2 );
220 $this->consumeString( ':' );
221 $this->minute = $this->consumeFixedDigits( 2 );
222 $this->consumeString( ':' );
223 $this->second = $this->consumeFixedDigits( 2 );
224 }
225
231 private function consumeRfc850Date() {
232 $this->consumeDayNameLong();
233 $this->consumeString( ', ' );
234 $this->consumeDate2();
235 $this->consumeString( ' ' );
236 $this->consumeTimeOfDay();
237 $this->consumeString( ' GMT' );
238 }
239
245 private function consumeDate2() {
246 $this->consumeDay();
247 $this->consumeString( '-' );
248 $this->consumeMonth();
249 $this->consumeString( '-' );
250 $year = $this->consumeFixedDigits( 2 );
251 // RFC 2626 section 11.2
252 $currentYear = (int)gmdate( 'Y' );
253 $startOfCentury = (int)round( $currentYear, -2 );
254 $this->year = $startOfCentury + intval( $year );
255 $pivot = $currentYear + 50;
256 if ( $this->year > $pivot ) {
257 $this->year -= 100;
258 }
259 }
260
266 private function consumeDayNameLong() {
267 foreach ( self::$dayNamesLong as $dayName ) {
268 if ( substr_compare( $this->input, $dayName, $this->pos, strlen( $dayName ) ) === 0 ) {
269 $this->dayName = substr( $dayName, 0, 3 );
270 $this->pos += strlen( $dayName );
271 return;
272 }
273 }
274 $this->error( 'expected day-name-l' );
275 }
276
282 private function consumeAsctimeDate() {
283 $this->consumeDayName();
284 $this->consumeString( ' ' );
285 $this->consumeDate3();
286 $this->consumeString( ' ' );
287 $this->consumeTimeOfDay();
288 $this->consumeString( ' ' );
289 $this->consumeYear();
290 }
291
297 private function consumeDate3() {
298 $this->consumeMonth();
299 $this->consumeString( ' ' );
300 if ( ( $this->input[$this->pos] ?? '' ) === ' ' ) {
301 $this->pos++;
302 $this->day = '0' . $this->consumeFixedDigits( 1 );
303 } else {
304 $this->day = $this->consumeFixedDigits( 2 );
305 }
306 }
307
314 private function getUnixTime() {
315 return gmmktime( (int)$this->hour, (int)$this->minute, (int)$this->second,
316 $this->month, (int)$this->day, $this->year );
317 }
318}
string $input
The input string being processed.
setInput( $input)
Set the input, and derived convenience properties.
assertEnd()
If the position is not at the end of the input string, raise an error, complaining of trailing charac...
consumeFixedDigits( $numDigits)
Consume a specified number of digits, or throw an exception.
consumeString( $s)
Consume a specified string, or throw an exception.
error( $message)
Throw an exception to indicate a parse error.
This is a parser for "HTTP-date" as defined by RFC 7231.
Definition HttpDate.php:23
static parse( $dateString)
Parse an HTTP-date string.
Definition HttpDate.php:80
static format( $unixTime)
A convenience function to convert a UNIX timestamp to the preferred IMF-fixdate format for HTTP heade...
Definition HttpDate.php:96