我正在使用 proc_open 和 fgets($stdout) 读取 PHP 中的流,尝试获取传入的每一行。
许多 Linux 程序(包管理器、wget、rsync)仅使用 CR(回车)字符来表示定期“就地”更新的行,例如下载进度。我希望在这些更新发生后立即捕获它们(作为单独的行)。
目前, fgets($stdout) 只是继续读取直到 LF,因此当进度非常缓慢(例如大文件)时,它只会继续读取直到完全完成,然后将所有更新的行作为一个长字符串返回,包括CR。
我尝试设置“mac”选项来检测 CR 作为行结尾:
ini_set('auto_detect_line_endings',true);
但这似乎不起作用。
现在,stream_get_line 允许我将 CR 设置为换行符,但不是将 CRLF、CR 和 LF 视为分隔符的“包罗万象”解决方案。
我当然可以读取整行,使用各种 PHP 方法将其分割,并用 LF 替换所有类型的换行符,但它是一个流,我希望 PHP 能够在其仍在运行时获得进度指示。
所以我的问题是:
如何从 STDOUT 管道(从 proc_open)读取 LForCR发生,而不需要等到整条线都进来?
提前致谢!
解决方案:
我使用 Fleshgrinder 的过滤器类在流中将 \r 替换为 \n (请参阅接受的答案),并将 fgets() 替换为 fgetc() 以获得对 STDOUT 内容的更多“实时”访问:
$stdout = $proc->pipe(1);
stream_filter_register("EOL", "EOLStreamFilter");
stream_filter_append($stdout, "EOL");
while (($o = fgetc($stdout))!== false){
$out .= $o; // buffer the characters into line, until \n.
if ($o == "\n"){echo $out;$out='';} // can now easily wrap the $out lines in JSON
}