我正在使用proc_open和fgets($stdout)在PHP中读取流,尝试获取每一行数据。
许多Linux程序(例如包管理器、wget和rsync)仅使用回车符(CR)作为在某些情况下“原地”更新的行,例如下载进度。我想立即捕获这些更新(作为单独的行)。
目前,fgets($stdout)会一直读取,直到LF字符,因此当进度非常缓慢时(例如大文件),它会一直读取直到完全完成,然后将所有更新的行作为一个长字符串返回,其中也包括CR字符。
我已尝试设置"mac"选项以检测CR字符作为行结束符:
但似乎这并不起作用。
现在,stream_get_line可以让我将CR设置为换行符,但不能将CRLF、CR和LF统一视为分隔符。
我当然可以读取整行,使用各种PHP方法拆分它,并将所有类型的换行符替换为LF,但这是一个流,并且我希望PHP能够在运行时获得进度指示。
所以我的问题是:
如何从STDOUT管道(来自proc_open)读取,直到出现LF或CR,而不必等到整行完整?
先感谢您!
解决方案:
我使用了Fleshgrinder的过滤器类来在流中将\r替换为\n(请参见接受的答案),并将fgets()替换为fgetc()以更实时地访问STDOUT的内容:
许多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)读取,直到出现LF或CR,而不必等到整行完整?
先感谢您!
解决方案:
我使用了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
}
wget server.com/file
的命令,它会直接输出更新,就像从屏幕宽度的1%[==> ]
行到2%[==> ]
一样,只要发生就会立即显示。或者,从PHP中的STDOUT管道读取与终端显示的基本不同吗? - okdewit