выполнение php-скрипта из программы C и сохранение результатов в переменной

StackOverflow https://stackoverflow.com/questions/1047385

  •  20-08-2019
  •  | 
  •  

Вопрос

Я хотел бы выполнить PHP-скрипт из программы C и сохранить возвращаемое содержимое в переменной 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

Также предложите любой другой лучший способ сделать это.

Это было полезно?

Решение

Короткий ответ здесь - использовать system() или popen() скорее, чем execl().Видя, что Джейсон уже опубликовал хороший ответ об использовании 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 случается, определяется как 0 и не (void *) 0, что законно.)

Однако...

Это получает execl() позвони правильно, но есть более серьезная проблема.А exec семейство функций почти всегда используются в сочетании с fork() и некоторые сложные pipe() жонглирование.Это потому, что exec функции не запускают программу в отдельном процессе;они фактически заменяют текущий процесс!Итак, как только вы позвоните execl(), ваш код готов.Законченный. execl() никогда не возвращается.Если вы просто вызовете ее так, как вы это сделали, вы никогда не увидите, что произойдет, поскольку ваша программа волшебным образом превратится в /usr/bin/php процесс.

ОК, так о чем это? fork() и pipe()?На высоком уровне вам нужно разделить ваш процесс на два процесса.Родительский процесс останется «вашим» процессом, а дочерний процесс немедленно вызовет execl() и превратиться в /usr/bin/php.Тогда, если вы правильно соединили родительский и дочерний процессы, они смогут взаимодействовать друг с другом.

Короче говоря, если вы все еще здесь и не задремали, вам следует обратиться к мудрому оракулу Google за более подробной информацией обо всем этом.Существует множество веб-сайтов, на которых даны еще более (!) подробные сведения о том, как это сделать. fork/exec танец.

Но я не оставлю тебя в подвешенном состоянии.Вот функция, которую я использую в своих программах и которая делает именно то, что я описал.Это очень похоже на popen() фактически, единственная разница в том, что вызывающий может получить доступ к дочернему stderr поток в дополнение к stdin и stdout.

Код...

#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;
    }
}

Другие советы

Вероятно, самым простым способом было бы использовать функция открытия:(отрывок со связанной страницы):

В следующем примере показано использование 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() */
    ...
}

Тем не менее, желание прочитать выходные данные PHP-скрипта из программы на C — это своего рода красный флаг, и я подозреваю, что, вероятно, есть какое-то более чистое общее решение, но трудно сказать больше без описания более высокого уровня того, что вы хотите. пытаешься сделать.

Помните, когда вы используете execl() он «завершится в случае успеха».Итак, вы никогда не увидите «Завершить функцию php», потому что она никогда не дойдет до этой строки кода.

Чтобы решить эту проблему, вы можете использовать system или используйте fork() создать дочерний процесс и в вашем дочернем процессе использовать execl или любую другую функцию из exec семья.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top