3

C プログラムから PHP スクリプトを実行し、返されたコンテンツを C 変数に格納したいと考えています。

私は次のように試しましたが、うまくいきません:

子:

printf("calling php function\n");
execl("/usr/bin/php -q", "/var/www/html/phpinfo.php", NULL);
printf("End php function\n");

PHP:

<?php
echo "hello";
?>

環境:

  • PHP 5.2.6
  • アパッチ 2.0
  • フェドラコア10

また、これを行うための他のより良い方法を提案してください。

4

3 に答える 3

14

ここでの短い答えは、system()orpopen()ではなくを使用することですexecl()。Jason が の使用に関する適切な回答を既に投稿しているので、それをスキップして、実際に気にする場合に備えpopen()て使用方法を説明します。execl()ほとんどの場合、これはすべて不必要な技術的な巨大なジャンボです--しかし、くそー、私はこれのほとんどを議論する前の長いプレリュードとしてすでにタイプアウトしていました、popen()そして私は今それを捨てません!

まず...

すべてのコマンドライン引数を呼び出すときexecl()は、個別に渡す必要があります。また、最初の引数は、伝統的にargv[0]プログラムの名前であるため、繰り返す必要があります。main()したがって、固定呼び出しは次のようになります。

execl("/usr/bin/php", "/usr/bin/php", "-q",
    "/var/www/html/phpinfo.php", (char *) NULL);

( にキャストを追加して、(char *)整数 0 ではなく null ポインターが最終引数として渡されるようにしましNULLた。0(void *) 0

でも...

これでexecl()呼び出しは正しく行われますが、もっと大きな問題があります。関数のexecファミリは、ほとんどの場合fork()、いくつかの複雑なpipe()ジャグリングと組み合わせて使用​​されます。これは、exec関数が別のプロセスでプログラムを実行しないためです。それらは実際に現在のプロセスを置き換えます! したがって、 を呼び出すexecl()と、コードは完了です。終了した。execl()二度と戻りません。行ったように呼び出すだけでは、プログラムが魔法のようにプロセスに変換されるため、何が起こるかを確認することはできません/usr/bin/php

fork()では、これは何pipe()ですか?大まかに言えば、やらなければならないことは、プロセスを 2 つのプロセスに分割することです。親プロセスは引き続き「あなたの」プロセスですが、子プロセスはすぐに呼び出さexecl()れて に変換され/usr/bin/phpます。次に、親プロセスと子プロセスを正しく配線すると、相互に通信できるようになります。

手短に言えば、まだここにいて、うなずいていない場合は、これらすべての詳細について賢明なオラクル Google に相談する必要があります。fork/execダンスのやり方について、さらに (!) 詳細な情報を提供している Web サイトがたくさんあります。

私はあなたをぶら下げたままにしません。これは、私が概説したことを正確に行う独自のプログラムに使用する関数です。実際には と非常に似ていますが、唯一の違いは、呼び出し元がとに加えて子のストリームにpopen()アクセスできることです。stderrstdinstdout

コード...

#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

pid_t execute(const char *command, FILE **in, FILE **out, FILE **err)
{
    pid_t pid;
    int   fd[6];

    pipe(&fd[0]);
    pipe(&fd[2]);
    pipe(&fd[4]);

    switch (pid = fork()) {
        case -1:
            perror("unable to fork()");
            exit(1);

        case 0:
            close(fd[1]);   // Close write end of stdin.
            close(fd[2]);   // Close read end of stdout.
            close(fd[4]);   // Close read end of stderr.

            dup2(fd[0], STDIN_FILENO);  // Have stdin read from the first pipe.
            dup2(fd[3], STDOUT_FILENO); // Have stdout write to the second pipe.
            dup2(fd[5], STDERR_FILENO); // Have stderr write to the third pipe.

            execlp("/bin/sh", "/bin/sh", "-c", command, (char *) NULL);

            perror("execlp() failed");
            _exit(1);

        default:
            close(fd[0]); // Close read end of stdin.
            close(fd[3]); // Close write end of stdout.
            close(fd[5]); // Close write end of stderr.

            if (in)  *in  = fdopen(fd[1], "wb"); else close(fd[1]);
            if (out) *out = fdopen(fd[2], "rb"); else close(fd[2]);
            if (err) *err = fdopen(fd[4], "rb"); else close(fd[4]);

            return pid;
    }
}
于 2009-06-26T05:09:43.840 に答える
7

おそらく最も簡単な方法は、popen関数を使用することです:(リンクされたページからの抜粋):

次の例は、現在のディレクトリ内のファイルのリストを取得するために、popen()およびpclose()を使用してコマンドls*を実行する方法を示しています。

#include <stdio.h>
...


FILE *fp;
int status;
char path[PATH_MAX];


fp = popen("ls *", "r");
if (fp == NULL)
    /* Handle error */;


while (fgets(path, PATH_MAX, fp) != NULL)
    printf("%s", path);


status = pclose(fp);
if (status == -1) {
    /* Error reported by pclose() */
    ...
} else {
    /* Use macros described under wait() to inspect `status' in order
       to determine success/failure of command executed by popen() */
    ...
}

ただし、Cプログラム内からPHPスクリプトの出力を読み取りたいというのは一種の危険信号であり、おそらくこれに対する全体的な解決策はもっときれいだと思いますが、あなたが何をしているのかをより高いレベルで説明しなければ、これ以上言うのは難しいでしょう。再しようとしています。

于 2009-06-26T04:56:03.950 に答える
1

execl()使用すると「成功すると終了」することを忘れないでください。したがって、そのコード行に到達することはないため、「End php function」が表示されることはありません。

この問題を解決するには、 を使用するか、 をsystem使用fork()して子プロセスを作成し、子プロセスでファミリーexeclの関数を使用するか、その他の関数を使用します。exec

于 2015-12-29T17:28:46.797 に答える