【发布时间】:2011-10-09 11:51:07
【问题描述】:
当我像这样从 PHP 运行 exec 时:
$result = exec('command');
由此产生的结果将存储在$result。但在我目前的情况下,我的命令可能需要几分钟并在运行时输出结果。有没有办法在运行时获得输出?我知道passthru方法会将结果输出到浏览器,但我其实是直接想要的。
【问题讨论】:
-
用 CGI 代替 PHP,可以吗?
当我像这样从 PHP 运行 exec 时:
$result = exec('command');
由此产生的结果将存储在$result。但在我目前的情况下,我的命令可能需要几分钟并在运行时输出结果。有没有办法在运行时获得输出?我知道passthru方法会将结果输出到浏览器,但我其实是直接想要的。
【问题讨论】:
你应该看看proc_open
在使输出流成为非阻塞(使用stream_set_blocking)后,您可以随时读取它,而不会阻塞您的 PHP 代码。
-编辑- 如果你使用
$result = exec('command > /path/to/file &');
它将在后台运行,您可以在 /path/to/file 中读取输出
【讨论】:
也许不是最好的方法(但对我有用):
<?php
$cmd = "ping 127.0.0.1 -c 5"; //example command
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "a")
);
$pipes = array();
$process = proc_open($cmd, $descriptorspec, $pipes, null, null);
echo "Start process:\n";
$str = "";
if(is_resource($process)) {
do {
$curStr = fgets($pipes[1]); //will wait for a end of line
echo $curStr;
$str .= $curStr;
$arr = proc_get_status($process);
}while($arr['running']);
}else{
echo "Unable to start process\n";
}
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
echo "\n\n\nDone\n";
echo "Result is:\n----\n".$str."\n----\n";
?>
【讨论】:
指定第二个参数
exec('command', $result);
如果输出参数存在,那么指定的数组将是 填充命令的每一行输出。尾随 此数组中不包含空格,例如 \n。请注意,如果 数组已经包含一些元素, exec() 将追加到 数组的末尾。如果您不希望函数附加元素, 在将数组传递给 exec() 之前调用数组上的 unset()。
【讨论】:
结合使用passthru() 和output buffering 或许可以实现您所需要的。不过不确定。
【讨论】:
无论对谁有帮助,我都使用了 Eddie 的答案并根据我的目的对其进行了修改(输出 MySQL 转储文件而不会使服务器的 RAM 泛滥)
$dumpCommand = "mysqldump --skip-lock-tables -u $dbuser -p$dbpasswd $dbname";
$dumpFileName = 'backup_'.$dbname.'-'.date('Ymd-Hi').'.sql';
$descriptorSpec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "a")
);
$pipes = array();
$process = proc_open($dumpCommand, $descriptorSpec, $pipes, null, null);
if(!is_resource($process)) {
die('Unable to start process');
}
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$dumpFileName.'"');
do {
echo fgets($pipes[1]); // Will wait for EOL
$arrStatus = proc_get_status($process);
} while($arrStatus['running']);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
【讨论】: