我正在 PHP 中读取流,使用 proc_open 和 fgets($stdout),试图获取每一行。
许多 linux 程序(包管理器、wget、rsync)只使用 CR(回车)字符来表示定期“就地”更新的行,例如下载进度。我想在它们发生时立即捕获这些更新(作为单独的行)。
目前,fgets($stdout) 只会一直读取直到 LF,所以当进度非常缓慢时(例如大文件),它只会继续读取直到完全完成,然后将所有更新的行作为一个长字符串返回,包括CR。
我尝试设置“mac”选项以将 CR 检测为行尾:
ini_set('auto_detect_line_endings',true);
Run Code Online (Sandbox Code Playgroud)
但这似乎不起作用。
现在,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. …Run Code Online (Sandbox Code Playgroud) 我proc_open在 Windows 上遇到过这个问题,当我尝试使用 将 wmv 文件(到 flv)转换时ffmpeg,但是我怀疑每当某些情况发生时我都会遇到同样的情况。
基本上我的代码如下:
$descriptorspec = array
(
array("pipe", "r"),
array("pipe", "w"),
array("pipe", "w")
);
$pipes = array();
$procedure = proc_open('cd "C:/Program Files/ffmpeg/bin" && "ffmpeg.exe" -i "C:/wamp/www/project/Wildlife.wmv" -deinterlace -qdiff 2 -ar 22050 "C:/wamp/www/project/Wildlife.flv"', $descriptorspec, $pipes);
var_dump(stream_get_contents($pipes[1]));
Run Code Online (Sandbox Code Playgroud)
现在,此代码将导致 PHP 无限期挂起(如果不是stream_get_contents我将使用fgetsor stream_select,行为是一致的,则无关紧要)。
其原因(我怀疑)是,虽然 STDOUT 流成功打开,但进程不会向它写入任何内容(即使在 cmd 中运行相同的命令显示输出),因此,尝试从此类流中读取,会导致与此处描述的相同的问题,因此 - PHP 等待流中包含任何内容,进程不会向其中写入任何内容。
但是(额外的乐趣),设置stream_set_timeout还是stream_set_blocking没有任何效果。
因此 - 有人可以确认/否认正在发生的事情吗,如果可能的话,展示我如何应对这种情况?我查看了 PHP 错误,所有错误proc_open hangs似乎都已修复。
暂时我已经实施了这样的解决方案:
$timeout = 60; …Run Code Online (Sandbox Code Playgroud) 我在Windows Server 2012 R2和IIS 8.5上运行我的网站,我遇到了问题.
exec('whoami'),它返回nt authority\iusr.proc_open('whoami', $desc, $pipes),结果是iis apppool\mysite.为什么会这样?
我对composer有问题,它一直运行良好,但现在不想……
这是一个简单composer install命令的结果:
bob@SRV04:~/testdir$ composer install
Loading composer repositories with package information
Updating dependencies
Package operations: 44 installs, 0 updates, 0 removals
- Installing psr/container (1.0.0): The following exception is caused by a
lack of memory or swap, or not having swap configured
Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-
fork-failed-errors for details
PHP Warning: proc_open(): fork failed - Cannot allocate memory in
phar:///bin/composer/vendor/symfony/console/Application.php on line 952
Warning: proc_open(): fork failed - Cannot allocate memory in
phar:///bin/composer/vendor/symfony/console/Application.php on line 952
[ErrorException] …Run Code Online (Sandbox Code Playgroud) 嗨我正在用popen运行一个进程; -
$handle = popen('python scriptos.py', "r");
while (!feof($handle)) {
$data = fgets($handle);
echo "> ".$data;
}
Run Code Online (Sandbox Code Playgroud)
而且我只从一个返回5行的进程中得到3行.我在CLi中运行这个确切的命令,我会得到更多的响应.就像它提前停止阅读一样(在完成工作时需要时间来完成并更新下两行,这是一个进度指示器).
我做错了吗?是proc_open更适合(我已经开始看,如果我可以试试).
我正在尝试通过Mac OS X 10.6上的命令行使用PHP建立到远程服务器的交互式SSH连接.我目前正在使用PHP的proc_open函数来执行以下命令:
ssh -t -t -p 22 user@server.com
Run Code Online (Sandbox Code Playgroud)
这几乎可行.该-t -t选项都应该强制伪终端,他们几乎做.我可以输入SSH密码并按Enter键.但是,按下后,终端似乎只是挂起.没有输出,没有任何东西 - 就像SSH会话失败一样.我无法运行命令或任何东西,必须使用Ctrl + C杀死整个事物.我知道登录成功,因为我可以执行命令,ssh -t -t -p 22 user@server.com "ls -la"并获得正确的输出.
我认为这个问题必须与我在proc_open调用中使用标准管道的事实有关,所以我用pty替换它们.我收到以下错误:"此系统不支持pty伪终端......"
Mac OS X根本不支持pty或伪终端吗?(我很擅长使用所有这些shell术语).
这是PHP代码:
$descriptorspec = array(0 => array("pty"), 1 => array("pty"), 2 => array("pty"));
$cwd = getcwd();
$process = proc_open('ssh -t -t -p 22 user@server.com', $descriptorspec, $pipes, $cwd);
if (is_resource($process))
{
while (true)
{
echo(stream_get_contents($pipes[1]));
$status = proc_get_status($process);
if (! $status["running"])
break;
}
}
Run Code Online (Sandbox Code Playgroud)
(对不起 - 我不能为我的生活弄清楚SO的格式说明......)
我究竟做错了什么?为什么我不能用pty?这在Mac OS X上是不可能的吗?谢谢你的帮助!
我一直在四处寻找,但未能找到这个问题的直接答案。首先,我要声明的是,我想要实现的目标不一定特别有用,但目的部分是为了理解 PHP 如何与其他进程和流等交互。
在 shell 终端,您可以运行一个命令,例如echo $USER,它将输出名为 的环境变量中的任何内容USER。
我想知道是否可以执行此命令,然后echo使用 PHP 的proc_open函数捕获 shell 命令的输出。
这就是我目前正在尝试的:
$descriptors = [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']];
$handle = proc_open('echo Hello world, $USER!', $descriptors, $pipes, null, ['USER' => 'guest']);
$world = stream_get_contents($pipes[0]);
Run Code Online (Sandbox Code Playgroud)
$world保持空(即'')。
我有几个理论来解释为什么它不起作用[以及方括号中的每个理论可能是错误的原因],但我想知道是否有人可以证实其中一个或提供另一种解释为什么它不工作?
理论 1 echo 命令在 PHP 有机会读取输出之前立即终止。[真的吗?有没有办法使用 proc_open 捕获立即终止的命令的输出?也许这不是 proc_open 的用途?]
理论 2
echo 在某种程度上被视为 shell 内置命令而不是独立的可执行文件,这就是它的行为不同的原因?[Linux 提供了一个名为 echo in 的可执行文件/bin/echo,难道它不能只使用那个吗?另外更改echo为/bin/echo也不能解决问题]
先感谢您