3b1fc29cb53b4db1ce44ff6261e91444e3c591e8
[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 if ($verbose !== false) {
59 printf("Fetching %s ...\n", $this->source);
60 }
61 $context = $this->createStreamContext();
62
63 if (!$remote = fopen($this->source, "r", false, $context)) {
64 throw new Exception;
65 }
66
67 $local = new Tempfile("remote");
68 if (!stream_copy_to_stream($remote, $local->getStream())) {
69 throw new Exception;
70 }
71 $local->closeStream();
72
73 /* STREAM_NOTIFY_COMPLETED is not generated, see above */
74 call_user_func($this->progress, 1);
75
76 return $local;
77 }
78 }