4f090efb74579b0b21970ca87ad7ee6f76a859cc
[pharext/pharext] / src / pharext / Task / StreamFetch.php
1 <?php
2
3 namespace pharext\Task;
4
5 use pharext\Exception;
6 use pharext\Task;
7 use pharext\Tempfile;
8
9 /**
10 * Fetch a remote archive
11 */
12 class StreamFetch implements Task
13 {
14 /**
15 * @var string
16 */
17 private $source;
18
19 /**
20 * @var callable
21 */
22 private $progress;
23
24 /**
25 * @param string $source remote file location
26 * @param callable $progress progress callback
27 */
28 public function __construct($source, callable $progress) {
29 $this->source = $source;
30 $this->progress = $progress;
31 }
32
33 private function createStreamContext() {
34 $progress = $this->progress;
35
36 return stream_context_create([],["notification" => function($notification, $severity, $message, $code, $bytes_cur, $bytes_max) use($progress) {
37 switch ($notification) {
38 case STREAM_NOTIFY_CONNECT:
39 $progress(0);
40 break;
41 case STREAM_NOTIFY_PROGRESS:
42 $progress($bytes_max ? $bytes_cur/$bytes_max : .5);
43 break;
44 case STREAM_NOTIFY_COMPLETED:
45 /* this is not generated, why? */
46 $progress(1);
47 break;
48 }
49 }]);
50 }
51
52 /**
53 * @param bool $verbose
54 * @return \pharext\Task\Tempfile
55 * @throws \pharext\Exception
56 */
57 public function run($verbose = false) {
58 $context = $this->createStreamContext();
59
60 if (!$remote = fopen($this->source, "r", false, $context)) {
61 throw new Exception;
62 }
63
64 $local = new Tempfile("remote");
65 if (!stream_copy_to_stream($remote, $local->getStream())) {
66 throw new Exception;
67 }
68 $local->closeStream();
69
70 /* STREAM_NOTIFY_COMPLETED is not generated, see above */
71 call_user_func($this->progress, 1);
72
73 return $local;
74 }
75 }