3

popenコマンドを監視するために2つのPHPスクリプトを同時に(同期的に)実行するには?

次のようなコマンドを起動するスクリプトがあります。

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 はリスナー ( l​​istener.php )を 1000ms ごとに呼び出します。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);

        }
    });
}

EDIT 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 環境でのサーバー側バッチ ジョブの実行に関する同様の質問に回答しました。私が正しく理解している場合、あなたの要件は異なりますが、答えに役立つ何かがある可能性があります。

Web サイトからバッチ ファイルを実行する

編集

クライアント側コードの修正版を次に示します。主な変更点は次のとおりです。

  • 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

I've decided to call the command for each individual file.

It is going to be slower, but it is safer to manage with file cause errors and which files was properly inserted in the archive.

I'll try to find something faster is the direcotry to archive got 10 000 icons file for exemple. Maybe 5 files at a time instead of one file at a time.

This code was intended for testing purposes, the code is not optimized at all for production.

index.html jquery script:

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);

        }
    });
}

backup.manager.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 に答える