8

私が書いたラッパークラスを使用してサードパーティのスクリプトを実行しています。これはshell_exec()、後でphpコードを使用して解析するファイルを呼び出してパイプします。これは機能していることに言及する必要がありますが、考えもしなかったユースケースに遭遇したため、機能を強化しようとしています。

shell_exec() でタイムアウトを管理するにはどうすればよいですか? でラップすることを考えていましたtry() catch()が、時間コンポーネントを最適に処理する方法がわかりません。

shell_exec()ここで andに関連するいくつかの質問を読んでいますがexec()、出力パラメーターを渡すexec()ことでリターンを得ることができるようですが、それはスクリプトがリターンステータスで終了することに依存しています。さらに、私のミニテストページでは、出力を返すことができないようです!

私が考えたもう1つのオプションは、モーダルダイアログを使用し、スクリプトが機能している間にajaxスタイルのスピナーを使用し、javascriptで手動タイムアウトを設定することでした。次に、失敗/タイムアウトおよび終了に関するモデルダイアログメッセージをユーザーに提供しました。

このユースケースで受け入れられている方法はありますか?

私のミニテストは、次のもので構成されていました。

public $e_return = array();
public $e_status = '';
// Paths are absolute from /
public function execCheck($domain){
    exec($this->ssl_check_path." -s ".$domain." -p 443 > ".$this->folder.$this->filename." 2>&1 &", &$this->e_return, &$this->e_status);
}

// Returns
Array
(
)

0

この質問を参照として使用 すると、 PHP exec を使用して PHP スクリプトを実行できません

http://www.php.net/manual/en/function.exec.php

4

4 に答える 4

19

私はそのようなタスクのためにいくつかの実用的なコードを書きます。関数は終了コード (0 - OK、>0 - エラー) を返し、stdout、stderr を参照変数に書き込みます。

/*execute program and write all output to $out
terminate program if it runs more than 30 seconds */
execute("program --option", null, $out, $out, 30);
echo $out;

function execute($cmd, $stdin=null, &$stdout, &$stderr, $timeout=false)
{
    $pipes = array();
    $process = proc_open(
        $cmd,
        array(array('pipe','r'),array('pipe','w'),array('pipe','w')),
        $pipes
    );
    $start = time();
    $stdout = '';
    $stderr = '';

    if(is_resource($process))
    {
        stream_set_blocking($pipes[0], 0);
        stream_set_blocking($pipes[1], 0);
        stream_set_blocking($pipes[2], 0);
        fwrite($pipes[0], $stdin);
        fclose($pipes[0]);
    }

    while(is_resource($process))
    {
        //echo ".";
        $stdout .= stream_get_contents($pipes[1]);
        $stderr .= stream_get_contents($pipes[2]);

        if($timeout !== false && time() - $start > $timeout)
        {
            proc_terminate($process, 9);
            return 1;
        }

        $status = proc_get_status($process);
        if(!$status['running'])
        {
            fclose($pipes[1]);
            fclose($pipes[2]);
            proc_close($process);
            return $status['exitcode'];
        }

        usleep(100000);
    }

    return 1;
}
于 2012-11-08T11:12:14.797 に答える
8

の使用を検討することをお勧めしますproc_open。ストリーム リソースを返し、タイマーを手動で保持するように構成できます。プロセスが完了する前にタイマーが期限切れになった場合は、 で終了できますproc_terminate。タイマーが期限切れになる前に完了した場合は、それ以外の場合は stdout に書き込まれるデータを取得するためproc_closeに thenを使用できます。stream_get_contents

http://www.php.net/manual/en/function.proc-open.phpを参照してください。

于 2010-08-04T17:15:10.393 に答える
0

で試しましpopen()たが、後でプロセスを終了する方法がありません。また、stream_get_contents()Windows で stream_set_blocking を使用してもストリームをブロックするため、代わりに fread を使用する必要がありました。さらに、Windows では proc_terminate が正しく動作しないため、別の kill 関数を使用する必要がありました。

私はこれを思いつきました.WindowsとLinuxの両方で動作するはずです:

function execute($command, $timeout = 5) {
    $handle = proc_open($command, [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipe);

    $startTime = microtime(true);

    /* Read the command output and kill it if the proccess surpassed the timeout */
    while(!feof($pipe[1])) {
        $read .= fread($pipe[1], 8192);
        if($startTime + $timeout < microtime(true)) break;
    }

    kill(proc_get_status($handle)['pid']);
    proc_close($handle);

    return $read;
}

/* The proc_terminate() function doesn't end proccess properly on Windows */
function kill($pid) {
    return strstr(PHP_OS, 'WIN') ? exec("taskkill /F /T /PID $pid") : exec("kill -9 $pid");
}
于 2016-10-27T11:26:21.513 に答える