<?php
/*
$bigget = Bigget::url('http://www.example.com/big_file.bin');
$bigget->saveTo('file.bin');
*/
class BiggetRequest extends HttpRequest
{
public $id;
}
class Bigget extends HttpRequestPool
{
const SIZE = 1048576;
private $url;
private $size;
private $count = 0;
private $files = array();
static function url($url)
{
$head = new HttpRequest($url, HttpRequest::METH_HEAD);
$headers = $head->send()->getHeaders();
$head = null;
if (!isset($headers['Accept-Ranges'])) {
throw new HttpExcpetion("Did not receive an Accept-Ranges header from HEAD $url");
}
if (!isset($headers['Content-Length'])) {
throw new HttpException("Did not receive a Content-Length header from HEAD $url");
}
$bigget = new Bigget;
$bigget->url = $url;
$bigget->size = $headers['Content-Length'];
return $bigget;
}
function saveTo($file)
{
$this->send();
if ($w = fopen($file, 'wb')) {
echo "\nCopying temp files to $file ...\n";
foreach (glob("bigget_????.tmp") as $tmp) {
echo "\t$tmp\n";
if ($r = fopen($tmp, 'rb')) {
stream_copy_to_stream($r, $w);
fclose($r);
}
unlink($tmp);
}
fclose($w);
echo "\nDone.\n";
}
}
function send()
{
// use max 3 simultanous requests with a req size of 1MiB
while ($this->count < 3 && -1 != $offset = $this->getRangeOffset()) {
$this->attachNew($offset);
}
while ($this->socketPerform()) {
if (!$this->socketSelect()) {
throw new HttpSocketException;
}
}
}
private function attachNew($offset)
{
$stop = min($this->count * self::SIZE + self::SIZE, $this->size) - 1;
echo "Attaching new request to get range: $offset-$stop\n";
$req = new BiggetRequest(
$this->url,
HttpRequest::METH_GET,
array(
'headers' => array(
'Range' => "bytes=$offset-$stop"
)
)
);
$this->attach($req);
$req->id = $this->count++;
}
private function getRangeOffset()
{
return ($this->size >= $start = $this->count * self::SIZE) ? $start : -1;
}
protected function socketPerform()
{
try {
$rc = parent::socketPerform();
} catch (HttpRequestPoolException $x) {
foreach ($x->exceptionStack as $e) {
echo $e->getMessage(), "\n";
}
}
foreach ($this->getFinishedRequests() as $r) {
$this->detach($r);
if (206 != $rc = $r->getResponseCode()) {
throw new HttpException("Unexpected response code: $rc");
}
file_put_contents(sprintf("bigget_%04d.tmp", $r->id), $r->getResponseBody());
if (-1 != $offset = $this->getRangeOffset()) {
$this->attachNew($offset);
}
}
return $rc;
}
}
?>
|