null, ]; private ?int $max = null; private int $current = 0; private int $lastCurrent = 0; private ?int $nextRefresh = null; private array $deltas = []; private array $times = []; public function setArguments(array $args) { $this->args = array_merge(self::$defaultArgs, $args); $max = $this->args['max']; if (str_starts_with($max, '@')) { $this->max = filesize(substr($max,1)); } else { $this->max = $max; } } public function pipe(?string $chunk) { if ($chunk === null) { $this->nextRefresh = 0; $this->refresh(); fwrite(STDERR, "\n"); return; } $this->current += strlen($chunk); $this->refresh(); return $chunk; } private function refresh() { if (microtime(true) < $this->nextRefresh) { return; } $now = microtime(true); $delta = $this->current - $this->lastCurrent; array_push($this->deltas, $delta); array_push($this->times, $now); while (count($this->deltas) > 10) { array_shift($this->deltas); array_shift($this->times); } $deltaTime = end($this->times) - reset($this->times); if ($deltaTime > 0) { $rate = array_sum($this->deltas) / $deltaTime; $rateu = "b/s"; if ($rate > 1024) { $rate /= 1024; $rateu = "KiB/s"; if ($rate > 1024) { $rate /= 1024; $rateu = "MiB/s"; if ($rate > 1024) { $rate /= 1024; $rateu = "GiB/s"; } } } } else { $rate = null; } if ($this->max) { fprintf(STDERR, "\r%.1fMiB/%.1fMiB (%.1f%%) ", $this->current/1024/1024, $this->max/1024/1024, 100/$this->max*$this->current); } else { fprintf(STDERR, "\r%.1fMiB ", $this->current/1024/1024); } if ($rate) { fprintf(STDERR, "(%.1f%s)", $rate, $rateu); } fprintf(STDERR, "\e[K"); $this->lastCurrent = $this->current; $this->nextRefresh = $now + .1; } }