php - 如何同时(非阻塞)运行 2 个 PHP 脚本来监视 popen 命令?

标签 php jquery listener popen progress

如何同时(同步)运行 2 个 PHP 脚本来监控 popen 命令?

我有一个脚本启动这样的命令:

7za a -t7z -mx9 backup.7z "H:\Informatique\*"

我想使用 jQuery 和 PHP 在页面上显示压缩进度。

运行此命令的 php 脚本如下所示:

    if( ($fp = popen("7za a -t7z ".$GLOBALS["backup_compression"]." \"".$backuplocation.$backupname."\" \"".$pathtobackup."\"", "r")) ) {
        while( !feof($fp) ){

            $fread = fread($fp, 256);
            $line_array = preg_split('/\n/',$fread);
            $num_lines = count($line_array);
            $_SESSION['job'][$jobid]['currentfile'] = $_SESSION['job'][$jobid]['currentfile']+$num_lines;
            $num_lines = 0;
            flush();
        }
        pclose($fp);
    }

jQuery 调用 7za 脚本,然后 jquery 每 1000 毫秒调用一次监听器 (listener.php)。 listener.php 页面包含以下代码:

session_start();
$jobid = $_GET['jobid'];

if(!isset($_SESSION['job'][$jobid])) { $arr = array("error"=>"Job not found"); echo json_encode($arr); exit(); };
$arr = array(
    "curfile" => $_SESSION['job'][$jobid]['currentfile'],
    "totalfiles" => $_SESSION['job'][$jobid]['totalfiles'],
);
echo json_encode($arr);
$jobid = null;
$arr = null;
exit();

在 jquery 调用完成后(通过监听器,我们从服务器得到了响应)我们用一些正常的东西显示信息,比如:$("currentfile").text(data['curfile']) ;

问题在于监听器处于无限循环中等待第一个脚本完成...而这不是监听器的工作...它在一切结束时监听...当您监听时,它是知道发生了什么。 :P

您知道发生了什么吗?我该如何解决这个问题? 或者,也许您可​​以帮我解决这个问题?

一如既往,我们欢迎任何建议。 谢谢。

编辑

jQuery 脚本:

function backup_launch(jobid) {
    x('jobid: '+jobid+' on state '+state);

    x('Listener launched');
    listen(jobid);

    timeout = setTimeout("listen('"+jobid+"')", 500);
    $.ajax({
        url:'backup.manager.php?json&jobid='+jobid+'&state='+state, 
        dataType:'json', 
        success:function(data)
        {
            state = 3;
        }
    });
}
function listen(jobid) {

    $.ajax({
        url:'backup.listener.php?json&jobid='+jobid, 
        dataType:'json', 
        success:function(data)
        {
            var curfile = data['curfile'];
            var totalfiles = data['totalfiles'];
            var p = curfile * 100 / totalfiles;
            x('File '+curfile+' out of '+totalfiles+' progress%: '+p);
            timeout = setTimeout("listen('"+jobid+"')", 500);

        }
    });
}

编辑 2 我找到了 Gearman (http://gearman.org/),但我完全不知道如何实现它,它需要是可移植的/独立的……我会尝试调查一下。

编辑 3

backup.manager.php 页面的完整代码。脚本会立即发送响应,但会在后台完成这项工作。

listen.php 页面在返回任何结果之前仍然等待命令完成。

$jobid = isset($_GET['jobid']) ? $_GET['jobid'] : 0;

//Make sure jobid is specified
if($jobid == 0) { return; } 

header("Connection: close");
@ob_end_clean();
ignore_user_abort();
ob_start();

echo 'Launched in backgroud';

$size = ob_get_length();
header("Content-Length: ".$size);
ob_end_flush();
flush();




$_SESSION['job'][$jobid]['currentfile'] = 0;


// 3. When app appove backup, 
//  - Write infos to DB
//  - Zip all files into 1 backup file
$datebackup = time();
$bckpstatus = 1; //In progress

$pathtobackup = $_SESSION['job'][$jobid]['path'];


/*
$query = "INSERT INTO backups (watchID, path, datebackup, checksum, sizeori, sizebackup, bckpcomplete)
        VALUES ($watchID, '{$path}', '{$datebackup}', '', '{$files_totalsize}', '', '{$bckpstatus}')"; 


$sth = $db->prepare($query);

$db->beginTransaction();
$sth->execute();
$db->commit();
$sth->closeCursor();
*/



$backupname = $jobid.".".$GLOBALS["backup_ext"];
$backuplocation = "D:\\";

if( ($fp = popen("7za a -t7z ".$GLOBALS["backup_compression"]." \"".$backuplocation.$backupname."\" \"".$pathtobackup."\"", "r")) ) {
    while( !feof($fp) ){

        $fread = fread($fp, 256);
        $line_array = preg_split('/\n/',$fread);
        $num_lines = count($line_array);
        $_SESSION['job'][$jobid]['currentfile'] = $_SESSION['job'][$jobid]['currentfile']+$num_lines;
        $num_lines = 0;
        sleep(1);
        flush();
    }
    pclose($fp);
}

最佳答案

杰里米,

几个月前,我回答了一个关于在 *NIX/PHP 环境中运行服务器端批处理作业的类似问题。如果我理解正确,您的要求会有所不同,但答案中可能会有一些帮助。

Run a batch file from my website

编辑

这是您的客户端代码的修改版本。您会看到我所做的主要更改是:

  • listen(jobid); 移动到 backup_launch 的成功处理程序中。
  • 添加错误处理程序以便您可以观察错误。

其他一切都只是编程风格的问题。

function backup_launch(jobid) {
    x(['jobid: ' + jobid, 'on state', state].join(' '));
    $.ajax({
        url: 'backup.manager.php',
        data: {
            'json': 1,
            'jobid': jobid,
            'state': state
        }
        dataType: 'json',
        success:function(data) {
            state = 3;
            x("Job started: " + jobid);
            listen(jobid);
            x("Listener launched: " + jobid);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            x(["backup.manager error", textStatus, errorThrown, jobid].join(": "));
        }
    });
}
function listen(jobid) {
    $.ajax({
        url: 'backup.listener.php',
        data: {
            'json': 1
            'jobid': jobid
        },
        dataType: 'json', 
        success: function(data) {
            var curfile = data.curfile;
            var totalfiles = data.totalfiles;
            var p = curfile * 100 / totalfiles;
            x(['File', curfile, 'out of', totalfiles, 'progress%:', p].join(' '));
            timeout = setTimeout(function() {
                listen(jobid);
            }, 500);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            x(["Listener error", textStatus, errorThrown, jobid].join(": "));
        }
    });
}

关于php - 如何同时(非阻塞)运行 2 个 PHP 脚本来监视 popen 命令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14289547/

相关文章:

java - 出错时触发 VideoView onCompletion 事件

php - 防止访问PHP中某个目录之外的文件

jquery - 具有转换内容的图像悬停效果

php - 如何解码来自 facebook 的 Json 响应

javascript - 如何将 javascript 添加到 Rails 5 中的单个 View ?

javascript - Chartist 总是留有间距?

Java 监听器未在 Tomcat 下启动

Java JTable,如何更改单元格数据(写入文本)?

php - 将 <br/> 转换为用于文本区域的新行

php - 在更新时我的 where 条件不起作用