library/SimplePie/HTTP/Parser.php Quellcode

Parser.php
gehe zur Dokumentation dieser Datei
1 <?php
53 {
59  public $http_version = 0.0;
60 
66  public $status_code = 0;
67 
73  public $reason = '';
74 
80  public $headers = array();
81 
87  public $body = '';
88 
94  protected $state = 'http_version';
95 
101  protected $data = '';
102 
108  protected $data_length = 0;
109 
115  protected $position = 0;
116 
122  protected $name = '';
123 
129  protected $value = '';
130 
136  public function __construct($data)
137  {
138  $this->data = $data;
139  $this->data_length = strlen($this->data);
140  }
141 
147  public function parse()
148  {
149  while ($this->state && $this->state !== 'emit' && $this->has_data())
150  {
152  $this->$state();
153  }
154  $this->data = '';
155  if ($this->state === 'emit' || $this->state === 'body')
156  {
157  return true;
158  }
159  else
160  {
161  $this->http_version = '';
162  $this->status_code = '';
163  $this->reason = '';
164  $this->headers = array();
165  $this->body = '';
166  return false;
167  }
168  }
169 
175  protected function has_data()
176  {
177  return (bool) ($this->position < $this->data_length);
178  }
179 
185  protected function is_linear_whitespace()
186  {
187  return (bool) ($this->data[$this->position] === "\x09"
188  || $this->data[$this->position] === "\x20"
189  || ($this->data[$this->position] === "\x0A"
190  && isset($this->data[$this->position + 1])
191  && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
192  }
193 
197  protected function http_version()
198  {
199  if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
200  {
201  $len = strspn($this->data, '0123456789.', 5);
202  $this->http_version = substr($this->data, 5, $len);
203  $this->position += 5 + $len;
204  if (substr_count($this->http_version, '.') <= 1)
205  {
206  $this->http_version = (float) $this->http_version;
207  $this->position += strspn($this->data, "\x09\x20", $this->position);
208  $this->state = 'status';
209  }
210  else
211  {
212  $this->state = false;
213  }
214  }
215  else
216  {
217  $this->state = false;
218  }
219  }
220 
224  protected function status()
225  {
226  if ($len = strspn($this->data, '0123456789', $this->position))
227  {
228  $this->status_code = (int) substr($this->data, $this->position, $len);
229  $this->position += $len;
230  $this->state = 'reason';
231  }
232  else
233  {
234  $this->state = false;
235  }
236  }
237 
241  protected function reason()
242  {
243  $len = strcspn($this->data, "\x0A", $this->position);
244  $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
245  $this->position += $len + 1;
246  $this->state = 'new_line';
247  }
248 
252  protected function new_line()
253  {
254  $this->value = trim($this->value, "\x0D\x20");
255  if ($this->name !== '' && $this->value !== '')
256  {
257  $this->name = strtolower($this->name);
258  // We should only use the last Content-Type header. c.f. issue #1
259  if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
260  {
261  $this->headers[$this->name] .= ', ' . $this->value;
262  }
263  else
264  {
265  $this->headers[$this->name] = $this->value;
266  }
267  }
268  $this->name = '';
269  $this->value = '';
270  if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
271  {
272  $this->position += 2;
273  $this->state = 'body';
274  }
275  elseif ($this->data[$this->position] === "\x0A")
276  {
277  $this->position++;
278  $this->state = 'body';
279  }
280  else
281  {
282  $this->state = 'name';
283  }
284  }
285 
289  protected function name()
290  {
291  $len = strcspn($this->data, "\x0A:", $this->position);
292  if (isset($this->data[$this->position + $len]))
293  {
294  if ($this->data[$this->position + $len] === "\x0A")
295  {
296  $this->position += $len;
297  $this->state = 'new_line';
298  }
299  else
300  {
301  $this->name = substr($this->data, $this->position, $len);
302  $this->position += $len + 1;
303  $this->state = 'value';
304  }
305  }
306  else
307  {
308  $this->state = false;
309  }
310  }
311 
315  protected function linear_whitespace()
316  {
317  do
318  {
319  if (substr($this->data, $this->position, 2) === "\x0D\x0A")
320  {
321  $this->position += 2;
322  }
323  elseif ($this->data[$this->position] === "\x0A")
324  {
325  $this->position++;
326  }
327  $this->position += strspn($this->data, "\x09\x20", $this->position);
328  } while ($this->has_data() && $this->is_linear_whitespace());
329  $this->value .= "\x20";
330  }
331 
335  protected function value()
336  {
337  if ($this->is_linear_whitespace())
338  {
339  $this->linear_whitespace();
340  }
341  else
342  {
343  switch ($this->data[$this->position])
344  {
345  case '"':
346  // Workaround for ETags: we have to include the quotes as
347  // part of the tag.
348  if (strtolower($this->name) === 'etag')
349  {
350  $this->value .= '"';
351  $this->position++;
352  $this->state = 'value_char';
353  break;
354  }
355  $this->position++;
356  $this->state = 'quote';
357  break;
358 
359  case "\x0A":
360  $this->position++;
361  $this->state = 'new_line';
362  break;
363 
364  default:
365  $this->state = 'value_char';
366  break;
367  }
368  }
369  }
370 
374  protected function value_char()
375  {
376  $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
377  $this->value .= substr($this->data, $this->position, $len);
378  $this->position += $len;
379  $this->state = 'value';
380  }
381 
385  protected function quote()
386  {
387  if ($this->is_linear_whitespace())
388  {
389  $this->linear_whitespace();
390  }
391  else
392  {
393  switch ($this->data[$this->position])
394  {
395  case '"':
396  $this->position++;
397  $this->state = 'value';
398  break;
399 
400  case "\x0A":
401  $this->position++;
402  $this->state = 'new_line';
403  break;
404 
405  case '\\':
406  $this->position++;
407  $this->state = 'quote_escaped';
408  break;
409 
410  default:
411  $this->state = 'quote_char';
412  break;
413  }
414  }
415  }
416 
420  protected function quote_char()
421  {
422  $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
423  $this->value .= substr($this->data, $this->position, $len);
424  $this->position += $len;
425  $this->state = 'value';
426  }
427 
431  protected function quote_escaped()
432  {
433  $this->value .= $this->data[$this->position];
434  $this->position++;
435  $this->state = 'quote';
436  }
437 
441  protected function body()
442  {
443  $this->body = substr($this->data, $this->position);
444  if (!empty($this->headers['transfer-encoding']))
445  {
446  unset($this->headers['transfer-encoding']);
447  $this->state = 'chunked';
448  }
449  else
450  {
451  $this->state = 'emit';
452  }
453  }
454 
458  protected function chunked()
459  {
460  if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
461  {
462  $this->state = 'emit';
463  return;
464  }
465 
466  $decoded = '';
467  $encoded = $this->body;
468 
469  while (true)
470  {
471  $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
472  if (!$is_chunked)
473  {
474  // Looks like it's not chunked after all
475  $this->state = 'emit';
476  return;
477  }
478 
479  $length = hexdec(trim($matches[1]));
480  if ($length === 0)
481  {
482  // Ignore trailer headers
483  $this->state = 'emit';
484  $this->body = $decoded;
485  return;
486  }
487 
488  $chunk_length = strlen($matches[0]);
489  $decoded .= $part = substr($encoded, $chunk_length, $length);
490  $encoded = substr($encoded, $chunk_length + $length + 2);
491 
492  if (trim($encoded) === '0' || empty($encoded))
493  {
494  $this->state = 'emit';
495  $this->body = $decoded;
496  return;
497  }
498  }
499  }
500 }




Korrekturen, Hinweise und Ergänzungen

Bitte scheuen Sie sich nicht und melden Sie, was auf dieser Seite sachlich falsch oder irreführend ist, was ergänzt werden sollte, was fehlt usw. Dazu bitte oben aus dem Menü Seite den Eintrag Support Forum wählen. Es ist eine kostenlose Anmeldung erforderlich, um Anmerkungen zu posten. Unpassende Postings, Spam usw. werden kommentarlos entfernt.