private static function GetResponse($fp, $debug, $options, $startts, $timeout) { $recvstart = microtime(true); $rawdata = $data = ""; $rawsize = $rawrecvheadersize = 0; do { $autodecode = !isset($options["auto_decode"]) || $options["auto_decode"]; // Process the response line. while (strpos($data, "\n") === false && ($data2 = fgets($fp, 116000)) !== false) { if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) { return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); } $rawsize += strlen($data2); $data .= $data2; if (isset($options["recvratelimit"])) { self::ProcessRateLimit($rawsize, $recvstart, $options["recvratelimit"]); } if (isset($options["debug_callback"])) { $options["debug_callback"]("rawrecv", $data2, $options["debug_callback_opts"]); } else { if ($debug) { $rawdata .= $data2; } } if (feof($fp)) { break; } } if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } $pos = strpos($data, "\n"); if ($pos === false) { return array("success" => false, "error" => self::HTTPTranslate("Unable to retrieve response line."), "errorcode" => "get_response_line"); } $line = trim(substr($data, 0, $pos)); $data = substr($data, $pos + 1); $rawrecvheadersize += $pos + 1; $response = explode(" ", $line, 3); $response = array("line" => $line, "httpver" => strtoupper($response[0]), "code" => $response[1], "meaning" => $response[2]); // Process the headers. $headers = array(); $lastheader = ""; do { while (strpos($data, "\n") === false && ($data2 = fgets($fp, 116000)) !== false) { if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) { return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); } $rawsize += strlen($data2); $data .= $data2; if (isset($options["recvratelimit"])) { self::ProcessRateLimit($rawsize, $recvstart, $options["recvratelimit"]); } if (isset($options["debug_callback"])) { $options["debug_callback"]("rawrecv", $data2, $options["debug_callback_opts"]); } else { if ($debug) { $rawdata .= $data2; } } if (feof($fp)) { break; } } if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } $pos = strpos($data, "\n"); if ($pos === false) { $pos = strlen($data); } $header = rtrim(substr($data, 0, $pos)); $data = substr($data, $pos + 1); $rawrecvheadersize += $pos + 1; if ($header != "") { if ($lastheader != "" && (substr($header, 0, 1) == " " || substr($header, 0, 1) == "\t")) { $headers[$lastheader][count($headers[$lastheader]) - 1] .= $header; } else { $pos = strpos($header, ":"); if ($pos === false) { $pos = strlen($header); } $lastheader = self::HeaderNameCleanup(substr($header, 0, $pos)); if (!isset($headers[$lastheader])) { $headers[$lastheader] = array(); } $headers[$lastheader][] = ltrim(substr($header, $pos + 1)); } } } while ($header != ""); if ($response["code"] != 100 && isset($options["read_headers_callback"])) { if (!$options["read_headers_callback"]($response, $headers, $options["read_headers_callback_opts"])) { return array("success" => false, "error" => self::HTTPTranslate("Read headers callback returned with a failure condition."), "errorcode" => "read_header_callback"); } } $body = ""; // Handle WebSocket among other things. if ($response["code"] == 101) { break; } // Determine if decoding the content is possible and necessary. if ($autodecode && !isset($headers["Content-Encoding"]) || strtolower($headers["Content-Encoding"][0]) != "gzip" && strtolower($headers["Content-Encoding"][0]) != "deflate") { $autodecode = false; } if (!$autodecode) { $autodecode_ds = false; } else { require_once str_replace("\\", "/", dirname(__FILE__)) . "/deflate_stream.php"; // Since servers and browsers do everything wrong, ignore the encoding claim and attempt to auto-detect the encoding. $autodecode_ds = new DeflateStream(); $autodecode_ds->Init("rb", -1, array("type" => "auto")); } // Process the body. if (isset($headers["Transfer-Encoding"]) && strtolower($headers["Transfer-Encoding"][0]) == "chunked") { do { // Calculate the next chunked size and ignore chunked extensions. while (strpos($data, "\n") === false && ($data2 = fgets($fp, 116000)) !== false) { if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) { return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); } $rawsize += strlen($data2); $data .= $data2; if (isset($options["recvratelimit"])) { self::ProcessRateLimit($rawsize, $recvstart, $options["recvratelimit"]); } if (isset($options["debug_callback"])) { $options["debug_callback"]("rawrecv", $data2, $options["debug_callback_opts"]); } else { if ($debug) { $rawdata .= $data2; } } if (feof($fp)) { break; } } if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } $pos = strpos($data, "\n"); if ($pos === false) { $pos = strlen($data); } $line = trim(substr($data, 0, $pos)); $data = substr($data, $pos + 1); $pos = strpos($line, ";"); if ($pos === false) { $pos = strlen($line); } $size = hexdec(substr($line, 0, $pos)); if ($size < 0) { $size = 0; } // Retrieve content. $size2 = $size; $size3 = min(strlen($data), $size); if ($size3 > 0) { $data2 = substr($data, 0, $size3); $data = substr($data, $size3); $size2 -= $size3; if ($response["code"] == 100 || !isset($options["read_body_callback"])) { $body .= self::GetDecodedBody($autodecode_ds, $data2); } else { if (!$options["read_body_callback"]($response, self::GetDecodedBody($autodecode_ds, $data2), $options["read_body_callback_opts"])) { return array("success" => false, "error" => self::HTTPTranslate("Read body callback returned with a failure condition."), "errorcode" => "read_body_callback"); } } } while ($size2 > 0 && ($data2 = fread($fp, $size2 > 65536 ? 65536 : $size2)) !== false) { if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) { return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); } $tempsize = strlen($data2); $rawsize += $tempsize; $size2 -= $tempsize; if ($response["code"] == 100 || !isset($options["read_body_callback"])) { $body .= self::GetDecodedBody($autodecode_ds, $data2); } else { if (!$options["read_body_callback"]($response, self::GetDecodedBody($autodecode_ds, $data2), $options["read_body_callback_opts"])) { return array("success" => false, "error" => self::HTTPTranslate("Read body callback returned with a failure condition."), "errorcode" => "read_body_callback"); } } if (isset($options["recvratelimit"])) { self::ProcessRateLimit($rawsize, $recvstart, $options["recvratelimit"]); } if (isset($options["debug_callback"])) { $options["debug_callback"]("rawrecv", $data2, $options["debug_callback_opts"]); } else { if ($debug) { $rawdata .= $data2; } } if (feof($fp)) { break; } } if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } // Ignore one newline. while (strpos($data, "\n") === false && ($data2 = fgets($fp, 116000)) !== false) { if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) { return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); } $rawsize += strlen($data2); $data .= $data2; if (isset($options["recvratelimit"])) { self::ProcessRateLimit($rawsize, $recvstart, $options["recvratelimit"]); } if (isset($options["debug_callback"])) { $options["debug_callback"]("rawrecv", $data2, $options["debug_callback_opts"]); } else { if ($debug) { $rawdata .= $data2; } } if (feof($fp)) { break; } } if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } $pos = strpos($data, "\n"); if ($pos === false) { $pos = strlen($data); } $data = substr($data, $pos + 1); } while ($size); // Process additional headers. $lastheader = ""; do { while (strpos($data, "\n") === false && ($data2 = fgets($fp, 116000)) !== false) { if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) { return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); } $rawsize += strlen($data2); $data .= $data2; if (isset($options["recvratelimit"])) { self::ProcessRateLimit($rawsize, $recvstart, $options["recvratelimit"]); } if (isset($options["debug_callback"])) { $options["debug_callback"]("rawrecv", $data2, $options["debug_callback_opts"]); } else { if ($debug) { $rawdata .= $data2; } } if (feof($fp)) { break; } } if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } $pos = strpos($data, "\n"); if ($pos === false) { $pos = strlen($data); } $header = rtrim(substr($data, 0, $pos)); $data = substr($data, $pos + 1); $rawrecvheadersize += $pos + 1; if ($header != "") { if ($lastheader != "" && (substr($header, 0, 1) == " " || substr($header, 0, 1) == "\t")) { $headers[$lastheader][count($headers[$lastheader]) - 1] .= $header; } else { $pos = strpos($header, ":"); if ($pos === false) { $pos = strlen($header); } $lastheader = self::HeaderNameCleanup(substr($header, 0, $pos)); if (!isset($headers[$lastheader])) { $headers[$lastheader] = array(); } $headers[$lastheader][] = ltrim(substr($header, $pos + 1)); } } } while ($header != ""); if ($response["code"] != 100 && isset($options["read_headers_callback"])) { if (!$options["read_headers_callback"]($response, $headers, $options["read_headers_callback_opts"])) { return array("success" => false, "error" => self::HTTPTranslate("Read headers callback returned with a failure condition."), "errorcode" => "read_header_callback"); } } } else { if (isset($headers["Content-Length"])) { $size = (int) $headers["Content-Length"][0]; $datasize = 0; while ($datasize < $size && ($data2 = fread($fp, $size > 65536 ? 65536 : $size)) !== false) { if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) { return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); } $tempsize = strlen($data2); $datasize += $tempsize; $rawsize += $tempsize; if ($response["code"] == 100 || !isset($options["read_body_callback"])) { $body .= self::GetDecodedBody($autodecode_ds, $data2); } else { if (!$options["read_body_callback"]($response, self::GetDecodedBody($autodecode_ds, $data2), $options["read_body_callback_opts"])) { return array("success" => false, "error" => self::HTTPTranslate("Read body callback returned with a failure condition."), "errorcode" => "read_body_callback"); } } if (isset($options["recvratelimit"])) { self::ProcessRateLimit($rawsize, $recvstart, $options["recvratelimit"]); } if (isset($options["debug_callback"])) { $options["debug_callback"]("rawrecv", $data2, $options["debug_callback_opts"]); } else { if ($debug) { $rawdata .= $data2; } } if (feof($fp)) { break; } } if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } } else { if ($response["code"] != 100) { while (($data2 = fread($fp, 65536)) !== false) { if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) { return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"); } $tempsize = strlen($data2); $rawsize += $tempsize; if ($response["code"] == 100 || !isset($options["read_body_callback"])) { $body .= self::GetDecodedBody($autodecode_ds, $data2); } else { if (!$options["read_body_callback"]($response, self::GetDecodedBody($autodecode_ds, $data2), $options["read_body_callback_opts"])) { return array("success" => false, "error" => self::HTTPTranslate("Read body callback returned with a failure condition."), "errorcode" => "read_body_callback"); } } if (isset($options["recvratelimit"])) { self::ProcessRateLimit($rawsize, $recvstart, $options["recvratelimit"]); } if (isset($options["debug_callback"])) { $options["debug_callback"]("rawrecv", $data2, $options["debug_callback_opts"]); } else { if ($debug) { $rawdata .= $data2; } } if (feof($fp)) { break; } } if (self::StreamTimedOut($fp)) { return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded"); } } } } if ($autodecode_ds !== false) { $autodecode_ds->Finalize(); $data2 = $autodecode_ds->Read(); if ($response["code"] == 100 || !isset($options["read_body_callback"])) { $body .= $data2; } else { if (!$options["read_body_callback"]($response, $data2, $options["read_body_callback_opts"])) { return array("success" => false, "error" => self::HTTPTranslate("Read body callback returned with a failure condition."), "errorcode" => "read_body_callback"); } } } } while ($response["code"] == 100); return array("success" => true, "rawrecv" => $rawdata, "rawrecvsize" => $rawsize, "rawrecvheadersize" => $rawrecvheadersize, "recvstart" => $recvstart, "response" => $response, "headers" => $headers, "body" => $body); }
private function streamFileData($stream, $compress, $level) { $dataLength = Count64::construct(0, !$this->zip64); $gzLength = Count64::construct(0, !$this->zip64); $hashCtx = hash_init('crc32b'); if (COMPR::DEFLATE === $compress) { $compStream = DeflateStream::create($level); } while (!feof($stream)) { $data = fread($stream, self::STREAM_CHUNK_SIZE); $dataLength->add(strlen($data)); hash_update($hashCtx, $data); if (COMPR::DEFLATE === $compress) { $data = $compStream->update($data); } $gzLength->add(strlen($data)); $this->write($data); $this->flush(); } if (COMPR::DEFLATE === $compress) { $data = $compStream->finish(); $gzLength->add(strlen($data)); $this->write($data); $this->flush(); } $crc = unpack('N', hash_final($hashCtx, true)); return array($dataLength, $gzLength, $crc[1]); }