}
?>
+- Download a big file
+
+<?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;
+ }
+}
+?>