3

如何同时(同步)运行 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);
}
4

2 回答 2

1

杰里米,

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

从我的网站运行批处理文件

编辑

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

  • 移动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(": "));
        }
    });
}
于 2013-01-12T03:44:05.860 回答
0

我决定为每个单独的文件调用命令。

它会变慢,但管理文件原因错误以及哪些文件已正确插入存档会更安全。

我会尝试更快地找到一些东西,例如存档的目录有 10 000 个图标文件。也许一次 5 个文件,而不是一次一个文件。

此代码用于测试目的,代码根本没有针对生产进行优化。

index.html jquery 脚本:

var state = 0;
var jobid = '';
var timeout;
var jobfiles;
var jobpaths = [];
$(document).ready(function() {
    $("button").click(function(e) {
        e.preventDefault();

        console.log('Sending');
        var path = $("input").val();
        x('state 1 getting info - infpb');
        state = 1;
        $.ajax({
            url:'backup.manager.php?json&path='+encodeURI(path)+'&type=0&state='+state, 
            dataType:'json', 
            success:function(data)
            {

                jobid = data['stats']['jobid'];
                jobfiles = data['stats']['totalfiles'];
                var jobsize = data['stats']['totalsize'];
                for(var i = 0, len = jobfiles; i < len; i++) {
                    jobpaths.push(data[i]['File']);
                }
                state = 2;
                x('state 2 - infpb stop (Information retrieved, launch backup) '+jobfiles+' files with '+jobsize+' bytes');
                backup_launch(jobid);

            }
        });
    });
});
function x(x) {
    $("#l").append(x+"<br>");   
}
var curfileid = 0;
function backup_launch(jobid) {
    x('jobid: '+jobid+' on state '+state);
    $.ajax({
        url:'backup.manager.php',
        data: {
            'json': 1,
            'jobid': jobid,
            'state': state,
            'path': jobpaths[curfileid]
        },
        dataType:'json', 
        success:function(data)
        {

            if(curfileid < jobfiles) {
                x((curfileid+1)+' / '+jobfiles);
                    curfileid++;
                    backup_launch(jobid);
            }
        },
        error: function(jqXHR, textStatus, errorThrown) {
            x(["backup.manager error", textStatus, errorThrown, jobid].join(": "));
        }
    });
}
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);

        }
    });
}

备份管理器.php

set_time_limit(0);
require('../functions.php');
session_start();



$keepCPUlow_lastlookup = time();
$keepCPUlow_mindelay = 60;
function keepCPUlow() {
    global $keepCPUlow_lastlookup, $keepCPUlow_mindelay;
    if((time() - $keepCPUlow_lastlookup) > $keepCPUlow_mindelay) {
        $keepCPUlow_lastlookup = time();
        getSysload(75, 1000);   // Max %, wait time in ms
    }
}



$state = isset($_GET['state']) ? $_GET['state'] : 0;
if($state == '1') {
    //
    $json = isset($_GET['json']) ? true : false;// Result should be in json format
    $path = isset($_GET['path']) ? $_GET['path'] : ''; // Path of the file or folder to backup
    $type = isset($_GET['type']) ? $_GET['type'] : ''; // Type - not very useful, for now

    //0. Assign a jobid for this job, it will help retrieve realtime information about this task
    $jobid = hash('md4', (time().uniqid().session_id()));
    //Store the current status (0) job not started
    $_SESSION['job'][$jobid]['status'] = 0; //Not started... yet

    // 1. Retrive list of files and stats
    $fileslist = array(); //Will contain the list of files
    $files_totalsize = 0; // Total size of files

    // Check if file or folder
    if(is_dir($path)) {
        //Path is a folder, get the list of files
        $files = getFilelist($path);


        foreach($files as $file) { //For each files
            if(!is_dir($file['File'])) { //That is not a directory
                $files_totalsize = $files_totalsize+$file['Filesize']; //Increment toal size
                $cpumon = keepCPUlow(); //if($cpumon[1]) echo ">CPU BURN".$cpumon[0]."<";

            }
        }

        $files_total = count($files); // Number of files
    } else {
        $files_totalsize = $files_totalsize+getFilesize($path);

        $files_total = 1;
    }


    $files['stats'] = array("totalfiles"=>$files_total, "jobid"=>$jobid, "totalsize"=>$files_totalsize);

    //Store infos in session
    $_SESSION['job'][$jobid]['totalfiles'] = $files_total;
    $_SESSION['job'][$jobid]['totalsize'] = $files_totalsize;
    $_SESSION['job'][$jobid]['path'] = is_dir($path) ? $path.'\\*' : $path;
    $_SESSION['job'][$jobid]['currentfile'] = 0;
    $_SESSION['job'][$jobid]['currentfile_path'] = '';
    $_SESSION['job'][$jobid]['bname'] = "SafeGuard_".$jobid.".".$GLOBALS["backup_ext"];
    $_SESSION['job'][$jobid]['blocation'] = "D:\\";


    // 2. return to app and wait for ready confirmation
    if(isset($_GET['json'])) {
        echo json_encode($files);
    }
    exit();
}
else if($state == '2') {

    $jobid = isset($_GET['jobid']) ? $_GET['jobid'] : 0;
    $_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'];
    $pathtobackup = isset($_GET['path']) ? $_GET['path'] : "--";

    $backupname = $_SESSION['job'][$jobid]['bname'];
    $backuplocation = $_SESSION['job'][$jobid]['blocation'];
    /*
    $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();
    */



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

            fread($fp, 256);
            $num_lines = 1;
            $_SESSION['job'][$jobid]['currentfile'] = $_SESSION['job'][$jobid]['currentfile']+$num_lines;
            $num_lines = 0;

            flush();
            echo '1';
        }
        pclose($fp);
    }




}
于 2013-01-12T18:52:18.720 回答