Skip to content

Instantly share code, notes, and snippets.

@BenMorel
Last active September 7, 2022 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BenMorel/eca011a88cb889d8865aa446ed001be0 to your computer and use it in GitHub Desktop.
Save BenMorel/eca011a88cb889d8865aa446ed001be0 to your computer and use it in GitHub Desktop.
Stream a file that is being written to by another process
<?php
/**
* This script streams a file that is being written to by another process.
* It will continue fread()ing past EOF until explicitly stopped with CTRL+C.
*
* The script will exit with a status code of 0 if and only if the stream is stopped *after* EOF has been reached,
* i.e. if actual EOF *MAY* have been reached.
*
* The output of the streamed file is sent to STDOUT, and the output of the script is sent to STDERR,
* so the output can be piped to another program while watching progress in the terminal.
*/
declare(strict_types=1);
declare(ticks=1);
if (!extension_loaded('pcntl')) {
fwrite(STDERR, 'The pcntl extension is required.');
exit(1);
}
$interrupted = false;
pcntl_signal(SIGINT, function () use (&$interrupted): void {
$interrupted = true;
});
if ($argc !== 2) {
fwrite(STDERR, sprintf("Usage: %s <file>\n", $argv[0]));
exit(1);
}
$filename = $argv[1];
$fp = @fopen($filename, 'rb');
if ($fp === false) {
fwrite(STDERR, sprintf("Could not open file '%s' for reading\n", $filename));
exit(1);
}
$totalBytes = 0;
$totalBytesSinceEof = 0;
$lastRead = null;
$eof = false;
while (true) {
$eof = $eof || feof($fp);
$data = @fread($fp, 1024 * 1024);
if ($data === false) {
fwrite(STDERR, sprintf("Could not read from file '%s'\n", $filename));
exit(1);
}
$bytes = strlen($data);
$totalBytes += $bytes;
if ($eof) {
$totalBytesSinceEof += $bytes;
}
if ($bytes !== 0) {
$lastRead = time();
}
fwrite(STDOUT, $data);
fwrite(STDERR, "\r\033[K"); // clear line
fwrite(STDERR, sprintf('%s bytes read', number_format((float) $totalBytes)));
if ($eof) {
fwrite(STDERR, sprintf(', %s bytes since EOF', number_format((float) $totalBytesSinceEof)));
if ($lastRead !== null) {
fwrite(STDERR, sprintf(', last read %s seconds ago', time() - $lastRead));
}
}
if ($interrupted) {
break;
}
if ($bytes === 0) {
usleep(100000);
}
}
exit($eof ? 0 : 1);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment