fix normal/verbose/quiet output
[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 /* avoid bytes_max bug of older PHP versions */
37 $maxbytes = 0;
38 return stream_context_create([],["notification" => function($notification, $severity, $message, $code, $bytes_cur, $bytes_max) use($progress, &$maxbytes) {
39 if ($bytes_max > $maxbytes) {
40 $maxbytes = $bytes_max;
41 }
42 switch ($notification) {
43 case STREAM_NOTIFY_CONNECT:
44 $progress(0);
45 break;
46 case STREAM_NOTIFY_PROGRESS:
47 $progress($maxbytes > 0 ? $bytes_cur/$maxbytes : .5);
48 break;
49 case STREAM_NOTIFY_COMPLETED:
50 /* this is sometimes not generated, why? */
51 $progress(1);
52 break;
53 }
54 }]);
55 }
56
57 /**
58 * @param bool $verbose
59 * @return \pharext\Task\Tempfile
60 * @throws \pharext\Exception
61 */
62 public function run($verbose = false) {
63 if ($verbose !== false) {
64 printf("Fetching %s ...\n", $this->source);
65 }
66 $context = $this->createStreamContext();
67
68 if (!$remote = @fopen($this->source, "r", false, $context)) {
69 throw new Exception;
70 }
71
72 $local = new Tempfile("remote");
73 if (!stream_copy_to_stream($remote, $local->getStream())) {
74 throw new Exception;
75 }
76 $local->closeStream();
77
78 /* STREAM_NOTIFY_COMPLETED is not generated, see above */
79 call_user_func($this->progress, 1);
80
81 return $local;
82 }
83 }