web-dev-qa-db-ja.com

from PHPで実行すると、出力が得られません

at Unixシステムコマンドを使用してタスクを追加するときに、exec()を使って出力をキャプチャしようと取り組んでいます。私の問題は、スクリプトから実行しても何も出力されないことですが、ターミナルから実行するとおよびPHP対話モードでは、数行が出力されます。

実行したいコマンドは次のとおりです。

_echo exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);
_

var_dump()string(0) ""を与え、print_r()Array ()を吐き出します。 NULLを出力するShell_exec()を使用してみましたが、Webページのコンテキストで実行すると次のようにhiが出力されます。

_echo exec("echo 'hi'");
_

これも出力します:

_echo exec("atq");
_

ただし、atを使用すると、何も出力されません。次の出力を取得するにはどうすればよいですか。

_exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);
_

現在のところ、Apacheを介してPHP=で「通常」として実行しても何も出力されないため、ターミナルとPHPのインタラクティブコンソールでコマンドを実行すると、次のような結果が期待されます。

_php > echo exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);
warning: commands will be executed using /bin/sh
job 1219 at Sun Jun 10 12:43:00 2012
_

_safe_mode_がオフであり、atまたはexec()を使用したその他のコマンドを実行すると、パイプラインエコーステートメントでatqから出力が得られない理由を理解できません。私は この質問 を検索して読みましたが、まったく役に立ちませんでした。

atからの出力を文字列またはexec()で2番目の引数を使用している場合は配列に戻すには、exec()をどのように取得できますか?

17
Bojangles

実用的なワンラインソリューション

こんなに簡単なことだとは思いませんでした。必要なのは、実行するコマンドの最後に_2>&1_を置いて、stderrをstdoutに再ルーティングすることだけです。これで、atからの出力はすべてstdoutに出力されるため、exec()によってキャプチャされます。

_echo exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes 2>&1", $result);
_

私の古い解決策:

私は1行または2行のソリューションを維持しようとしましたが、最終的に機能したのはproc_open()を使用することだけでした。これは、atがstderrにログを記録するためです。 、exec()は読みません!これを指摘してくれた@Tourniquetに感謝しますが、彼は答えを削除しました。引用するには:

私が見る限り、execによってキャプチャされていないstderrへの出力で。私はそれにはあまり自信がありませんが、 http://php.net/manual/en/function.proc-open.php を使用することを検討してください。これにより、stderrを独自のパイプに転送できます。

これは実際には正しい方法です。私の解決策(stderrのみが必要なため)はこれを行うことでした:

_// Open process to run `at` command
$process = proc_open("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", array(2 => array("pipe", "w")), $pipes);

// Get stuff from stderr, because `at` prints out there for some odd reason
if(is_resource($process)) {
    $output = stream_get_contents($pipes[2], 100);
    fclose($pipes[2]);

    $return_value = proc_close($process);
}
_

_$output_には、stderrに出力されたatがすべて含まれるようになり(エラーではないため、実際にはstdoutに移動する必要があります)、_$return_value_には成功すると_0_が含まれます。

28
Bojangles

ここでは、proc_openを使用したより複雑なソリューションを示します。私の場合、 '2>&1'の回避策が機能しないため、この回答を書いています。

function runCommand($bin, $command = '', $force = true)
{
    $stream = null;
    $bin .= $force ? ' 2>&1' : '';

    $descriptorSpec = array
    (
        0 => array('pipe', 'r'),
        1 => array('pipe', 'w')
    );

    $process = proc_open($bin, $descriptorSpec, $pipes);

    if (is_resource($process))
    {
        fwrite($pipes[0], $command);
        fclose($pipes[0]);

        $stream = stream_get_contents($pipes[1]);
        fclose($pipes[1]);

        proc_close($process);
    }

    return $stream;
}

使用例:

// getting the mime type of a supplied file
echo runCommand('file -bi ' . escapeshellarg($file));

commandパラメーターを使用した別の例:

// executing php code on the fly
echo runCommand('/usr/bin/php', '<?php echo "hello world!"; ?>');

forceパラメーターを使用した別の例(これは、実行プロセス中に出力を変更するコマンドに役立ちます):

// converting an mp3 to a wav file
echo runCommand('lame --decode ' . escapeshellarg($source) . ' ' . escapeshellarg($dest), '', true);

これが役に立てば幸い:-)

8

最小限の(非)動作例を作成してみてください。すべてを分解し、一度に1つだけテストします。

これがあなたのbashの1つのエラーです:

hpek@melda:~/temp$ echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes
at: pluralization is wrong
job 22 at Sun Jun 10 14:48:00 2012
hpek@melda:~/temp$ 

Og minuteの代わりにminutesと記述します。

atからの出力は、メールで送信されます!!

1
hpekristiansen