<?php
class HTTPGETResponse {
const RECVPROGRESS_NODATA = 0;
const RECVPROGRESS_HEAD = 1;
const RECVPROGRESS_BODY = 2;
const RECVPROGRESS_TRAIL = 3;
const RECVPROGRESS_END = 4;
const ERR_NOERROR = 0;
const ERR_MALFORMEDRESPONSE = 1;
const ERR_INVALIDCONTENTLENGTH = 2;
private $buffer = '';
private $unchunk = FALSE;
public $error = 0;
public $recvProgress = 0;
public $httpVersion;
public $responseCode;
public $responseMsg;
public $body = '';
public $contentLength = 0;
public $headers = array();
public function create() {
return new $this();
}
private function setErrorState($state) {
$this->error = $state;
$this->buffer = NULL;
}
private function getBufferLine() {
$line = FALSE;
if (FALSE !== $pos = strpos($this->buffer, "\r\n")) {
$line = substr($this->buffer, 0, $pos);
$this->buffer = substr($this->buffer, $pos + 2);
}
return $line;
}
private function processBufferLine($line) {
if ($this->recvProgress === self::RECVPROGRESS_NODATA) {
$this->processResponseLine($line);
} else {
$this->processHeaderLine($line);
}
}
private function processResponseLine($line) {
if (!preg_match('#^HTTP/(1\.[01]) (\d{3}) (.+)$#i', rtrim($line), $matches)) {
$this->setErrorState(self::ERR_MALFORMEDRESPONSE);
} else {
$this->httpVersion = $matches[1];
$this->responseCode = (int) $matches[2];
$this->responseMsg = $matches[3];
$this->recvProgress = self::RECVPROGRESS_HEAD;
}
}
private function processHeaderLine($line) {
if ($line === "\r\n") {
if ($this->recvProgress === self::RECVPROGRESS_HEAD) {
$this->unchunk = isset($this->headers['transfer-encoding']) && strtolower($this->headers['transfer-encoding']) === 'chunked';
$this->recvProgress = self::RECVPROGRESS_BODY;
}
} else {
list($key, $val) = explode(':', $line, 2);
$key = strtolower(trim($key));
$val = trim($val);
if (!isset($this->headers[$key])) {
$this->headers[$key] = array();
}
$this->headers[$key][] = $val;
}
}
private function processBodyData() {
if ($this->unchunk) {
$this->processBodyChunks();
} else {
$this->body .= $this->buffer;
$this->buffer = '';
}
}
private function processBodyChunks() {
if (strlen($this->buffer)) {
if (!preg_match('/^([\da-f]+)\r\n/i', $this->buffer, $matches)) {
$chunkLen = hexdec($matches[1]);
if ($chunkLen > 0) {
$headerLen = strlen($matches[1]) + 2;
if (strlen($this->buffer) >= $chunkLen + $headerLen + 2) {
$this->body .= substr($this->buffer, $headerLen, $chunkLen);
$this->buffer = substr($this->buffer, $chunkLen + $headerLen + 2);
}
} else {
$this->buffer = (string) substr($this->buffer, 5);
$this->recvProgress = self::RECVPROGRESS_TRAIL;
}
} else {
$this->setErrorState(self::ERR_MALFORMEDRESPONSE);
}
}
}
public function progress($str) {
if (!$this->error) {
$this->buffer .= $str;
while ($this->recvProgress !== self::RECVPROGRESS_BODY && FALSE !== $line = $this->getBufferLine()) {
$this->processBufferLine($line);
if ($this->error) {
break;
}
}
if ($this->recvProgress === self::RECVPROGRESS_BODY) {
$this->processBodyData();
}
}
return $this->error;
}
public function close() {
$this->recvProgress = self::RECVPROGRESS_END;
$this->contentLength = strlen($this->body);
if (!$this->error && isset($this->headers['content-length'])) {
if ($this->contentLength !== (int) $this->headers['content-length']) {
$this->setErrorState(self::ERR_INVALIDCONTENTLENGTH);
}
}
}
}
$factory = new HTTPGETResponse();
$response = $factory->create();
$chunks = array("HTTP/1.1 200 OK\r\nServer: yo-mama\r\n\r\nbooooooobs");
foreach($chunks as $chunk) {
$response->progress($chunk);
if ($response->error) {
echo "Error!\n";
break;
}
}
print_r($response);
- Output for git.master, git.master_jit, rfc.property-hooks
- Warning: Undefined array key 1 in /in/bUmAc on line 74
Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /in/bUmAc on line 76
HTTPGETResponse Object
(
[buffer:HTTPGETResponse:private] => booooooobs
[unchunk:HTTPGETResponse:private] =>
[error] => 0
[recvProgress] => 1
[httpVersion] => 1.1
[responseCode] => 200
[responseMsg] => OK
[body] =>
[contentLength] => 0
[headers] => Array
(
[server] => Array
(
[0] => yo-mama
)
[] => Array
(
[0] =>
)
)
)
This tab shows result from various feature-branches currently under review by the php developers. Contact me to have additional branches featured.
Active branches
Archived branches
Once feature-branches are merged or declined, they are no longer available. Their functionality (when merged) can be viewed from the main output page
preferences:
38.67 ms | 403 KiB | 8 Q