所以......我有一个 PHP 页面,其中涉及大量后端执行,即“exec”调用以在主机服务器上运行 shell 命令。
根据所涉及的调用,这可能需要几分钟的时间。(如果您查看下文,通过 exec 调用的每次递归都会安装一个 LUN;有时我希望每次执行安装 100 个以上。)我很好奇我可以做些什么来将内容发送回浏览器(并防止其超时)。
<!DOCTYPE html>
<html>
<head>
<title>sfvmtk</title>
</head>
<body>
<?php
// TEMPORARY VARIABLES FOR TESTING
$hba = 'vmhba38';
$svip = '10.10.20.100';
$targets = array ( 0 => array ( 'iqn' => 'iqn.2010-01.com.sf:t5np.esxtest.41',
'account' => 'esx',
'isecret' => 'isecret00000',
'tsecret' => 'tsecret00000'
),
1 => array ( 'iqn' => 'iqn.2010-01.com.sf:t5np.esxtest2.42',
'account' => 'esx2',
'isecret' => 'isecret00001',
'tsecret' => 'tsecret00001'
)
);
$hostname = $_REQUEST['hostname'];
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];
foreach ($targets as $ctarget) {
exec('esxcli -s '.$hostname.' -u '.$username.' -p '.$password.' iscsi adapter discovery statictarget add -A '.$hba.' -a '.$svip.' -n '.$ctarget['iqn'], $out);
exec('esxcli -s '.$hostname.' -u '.$username.' -p '.$password.' iscsi adapter target portal auth chap set -A '.$hba.' -a '.$svip.' -N '.$ctarget['account'].' -d uni -l required -n '.$ctarget['iqn'].' -S '.$ctarget['isecret'], $out);
exec('esxcli -s '.$hostname.' -u '.$username.' -p '.$password.' iscsi adapter target portal auth chap set -A '.$hba.' -a '.$svip.' -N '.$ctarget['account'].' -d mutual -l required -n '.$ctarget['iqn'].' -S '.$ctarget['tsecret'], $out);
}
exec('vicfg-rescan --server '.$hostname.' --username '.$username.' --password '.$password.' '.$hba, $out);
?>
</body>
</html>
答案1
使用 jQuery 和 Ajax 在 DIV 中处理上述任务。对于超时,您需要调整 Web 服务器的 php.ini(或在 Apache 的 .htaccess 中修改它)。由于其线程正忙于工作,因此脚本本身无法真正报告。
您可以尝试在每个循环中放置一个echo
或printf
,我已经尝试过这个技巧很多次了,通常,输出不会缓冲,直到脚本完成。这需要反复试验。如果您有很多记录并且这个技巧确实有效,我会在每个循环中都这样做:
echo ".";
if( $i++%100 == 0 )
echo "\n";
这样,点就会在页面上不断增长,直到 100 列/循环/记录,然后开始新的一行。
答案2
您是否考虑过为此类任务添加一个抽象层,例如吉曼? 您可以轮询后端并仍然保持响应的前端或在执行时将用户锁定到页面。
答案3
对于通过 HTTP 调用的任何长时间运行的进程,解决方案通常是异步处理(即,在与网络服务器分开的进程组中)。
您可以在专门为处理这些请求而优化的 Web 服务器上处理非常长的请求 - 但前提是所有介入的 HTP 感知设备都准备好配合(使用 SSL 会有所帮助)。但在此配置中无法显示处理的范围,另一方面,轮询由单独进程生成的日志文件可以通过简短、自动刷新的 HTTP 请求来完成。
答案4
您需要使用 proc_openhttp://www.php.net/manual/en/function.proc-open.php,proc_get_statushttp://php.net/manual/en/function.proc-get-status.php,流设置阻塞http://php.net/manual/en/function.stream-set-blocking.php以及睡眠http://php.net/manual/en/function.sleep.php并且回显和刷新应该可以正常工作。
这可以防止 PHP 超时并被父 apache 处理程序杀死(无论它是什么),因此您需要将 PHP 缓冲区刷新到 apache,但这并不意味着数据将被发送到客户端,因为存在缓存、压缩等,因此在这种情况下,您需要使用 http/xml 请求 (ajax) 来检查另一个进程,并且您可以使用 DB、文件系统、缓存或会话来处理此信息。您甚至需要进一步妥善保护它,您将从不同的帐户运行进程和网站,这样就没有人可以从您的网站运行命令。