public function receive($fd, $data)
{
if (!isset($this->connections[$fd]['buff'])) {
$this->connections[$fd]['buff'] = '';
} else {
$data = $this->connections[$fd]['buff'] . $data;
}
if (!isset($this->connections[$fd]['length'])) {
$pack = substr($data, 4, 3);
$info = unpack('ncontentLength/CpaddingLength', $pack);
$this->connections[$fd]['length'] = 8 + $info['contentLength'] + $info['paddingLength'];
}
if ($this->connections[$fd]['length'] <= strlen($data)) {
$result = $this->parseRecord($data);
$this->connections[$fd]['buff'] = $result['remainder'];
$this->connections[$fd]['length'] = null;
} else {
$this->connections[$fd]['buff'] = $data;
return;
}
if (count($result['records']) == 0) {
fwrite(STDOUT, "Bad Request. data length: " . strlen($data));
$this->closeConnection($fd);
return;
}
foreach ($result['records'] as $record) {
$rid = $record['requestId'];
$type = $record['type'];
if ($type == $this->FCGI_BEGIN_REQUEST) {
$req = $this->requests[$rid] = new Request($fd);
$req->id = $rid;
$u = unpack('nrole/Cflags', $record['contentData']);
$req->attrs->role = $this->roles[$u['role']];
$req->attrs->flags = $u['flags'];
$this->connections[$fd]['request'] = $req;
} elseif (isset($this->requests[$rid])) {
$req = $this->requests[$rid];
} else {
fwrite(STDOUT, "Unexpected FastCGI-record #. Request ID: {$fd}\n");
return;
}
if ($type == $this->FCGI_ABORT_REQUEST) {
$req->destoryTempFiles();
$this->closeConnection($fd);
} elseif ($type == $this->FCGI_PARAMS) {
if (!$record['contentLength']) {
$req->finishParams();
} else {
$p = 0;
while ($p < $record['contentLength']) {
if (($namelen = ord($record['contentData'][$p])) < 128) {
++$p;
} else {
$u = unpack('Nlen', chr(ord($record['contentData'][$p]) & 0x7f) . substr($record['contentData'], $p + 1, 3));
$namelen = $u['len'];
$p += 4;
}
if (($vlen = ord($record['contentData'][$p])) < 128) {
++$p;
} else {
$u = unpack('Nlen', chr(ord($record['contentData'][$p]) & 0x7f) . substr($record['contentData'], $p + 1, 3));
$vlen = $u['len'];
$p += 4;
}
$req->server[substr($record['contentData'], $p, $namelen)] = substr($record['contentData'], $p + $namelen, $vlen);
$p += $namelen + $vlen;
}
}
} elseif ($type === $this->FCGI_STDIN) {
if ($record['contentLength']) {
$req->setRawContent($record['contentData']);
continue;
} else {
$req->finishRawContent();
}
}
if ($req->attrs->paramsDone && $req->attrs->inputDone) {
$header = [];
foreach ($req->server as $k => $v) {
if (strncmp($k, 'HTTP_', 5) === 0) {
$header[strtr(ucwords(strtolower(substr($k, 5)), '_'), '_', '-')] = $v;
}
}
$req->header = $header;
Parser::parseCookie($req);
Parser::parseBody($req);
$response = new Response($this, $req);
$this->onRequest($req, $response);
// destory tmp files
$req->destoryTempFiles();
}
}
}