我正在为我们的技术团队构建一个内部工具套件,该套件涉及针对世界各地的一系列远程服务器运行命令。我遇到了一个小问题,但我想不出办法轻易解决。以下是该工具集特定部分的流程:
- 主服务器上的Web表单、用户输入的检查类型和主机名/IP
- 将输入变量提交到主服务器上的PHP脚本,该脚本将URL构建到cURL,cURL针对远程服务器(本例仅限于一个远程服务器),echo的输出
- 远程服务器接收带有变量的PHP脚本的web请求,运行一个linux shell命令来满足请求,并通过cURL将其输出返回给主服务器
所以这一切都很好,但我决定喜欢traceroute和ping工具,并让他们通过使用popen()和fread()将进度实时输出到浏览器,示例如下:
#Get the variables
$type = $_GET['type'];
$hostname = $_GET['host'];
#Start switch to decide what to do
switch ($type) {
case "trace":
$cmd = "traceroute $hostname";
while (@ ob_end_flush());
$proc = popen($cmd, 'r');
echo "<pre>";
while (!feof($proc))
{
echo fread($proc, 4096);
@ flush();
}
echo "</pre>";
break;
case "ping":
$cmd = "ping -c 5 " . $hostname;
while (@ ob_end_flush());
$proc = popen($cmd, 'r');
echo "<pre>";
while (!feof($proc))
{
echo fread($proc, 4096);
@ flush();
}
echo "</pre>";
break;
}
当在浏览器中直接针对远程服务器运行时,上述操作效果良好。当然,从主控端调用它不会返回实时输出,它只是在达到断点时返回完成的输出。这很令人沮丧,因为一个页面上会同时运行5-10个这样的程序,而像traceroutes这样的程序我真的不想等到30跳超时后用户才能从中获得任何输出
因此,我在这里的总体问题是……我如何获得cURL来模拟上面popen和fread之类的实时PHP输出?cURL能做到吗?我可以使用另一个PHP函数从远程URL获得实时输出吗?
$ch=curl_init();
$buffer='';//your download buffer goes here.
function progressfunc($ch,$totalDownloadSize,$bytesDownloaded,$totalRequestSize,$bytesUploaded){
global $buffer;
echo $buffer;
$buffer='';
//echo str_repeat('<span></span>',100);//if you have buffering issues, this is an ugly workaround...
flush();
};
function writefunc($ch,$data){
global $buffer;
static $written=0;
$buffer.=$data;
$written+=strlen($data);
return $written;
};
if(!curl_setopt_array($ch,array(
CURLOPT_WRITEFUNCTION=>'writefunc',
CURLOPT_PROGRESSFUNCTION=>'progressfunc',
CURLOPT_URL=>'slow_download'
))){
throw new RuntimeException('curl_setopt_array error. errno:'.curl_errno($ch).' error:'.curl_error($ch));
}
curl_exec($ch);