executar script php a partir do programa C e armazenar os resultados em uma variável
Pergunta
Gostaria de executar um script PHP a partir de um programa C e armazenar o conteúdo de voltar-se para uma variável C.
Eu tentei como seguir, mas ele não funciona:
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";
?>
Ambiente:
- PHP 5.2.6
- Apache 2.0
- Fedora Core 10
Também sugerir alguma outra maneira melhor de fazer isso.
Solução
A resposta curta aqui é usar system()
ou popen()
em vez de execl()
. Vendo como Jason já postou uma boa resposta sobre o uso popen()
, eu vou pular isso e explicar como usar execl()
apenas no caso de você realmente se importa. Provavelmente, isso é tudo desnecessário patranhas técnico - mas droga, eu tinha a maior parte deste digitado já como um longo prelúdio antes de discutir popen()
e não vou jogá-lo fora agora
Em primeiro lugar ...
Ao chamar execl()
toda a linha de comando argumentos precisam ser passados ??separadamente. Além disso, o primeiro argumento deve ser repetido como argv[0]
em main()
qualquer programa é tradicionalmente o nome do programa. Assim, a chamada fixo deve ser parecido:
execl("/usr/bin/php", "/usr/bin/php", "-q",
"/var/www/html/phpinfo.php", (char *) NULL);
(I adicionou-se o fundido para (char *)
para assegurar que um ponteiro nulo é transmitido como o argumento final, em vez do número inteiro 0, se NULL
acontece para ser definido como 0
e não (void *) 0
, que é legal.)
No entanto ...
Este recebe a chamada direita execl()
, mas há um problema maior. A família exec
de funções são quase sempre usados ??em combinação com fork()
e alguns malabarismos pipe()
complicado. Isso ocorre porque as funções exec
não executar o programa em um processo separado; eles realmente substituir o atual processo! Então, quando você chamar execl()
, seu código é feito. Acabado. execl()
nunca retorna. Se você chamá-lo apenas como você fez você nunca vai conseguir ver o que acontece como seu programa irá magicamente transformar em um processo /usr/bin/php
.
OK, então o que é isso de fork()
e pipe()
? Em um nível alto, o que você tem a fazer é dividir o seu processo em dois processos. O processo pai continuará a ser "seu" processo, enquanto o processo filho vai chamar imediatamente execl()
e transformar-se em /usr/bin/php
. Então, se você fio os processos pai e filho juntos corretamente eles serão capazes de se comunicar uns com os outros.
Para fazer uma longa história curta, se você ainda está aqui e não ter cochilado você deve consultar o oráculo sábio Google para maneira mais detalhes sobre tudo isso. Há uma abundância de sites lá fora, dando ainda mais (!) Em profundidade detalhes sobre como fazer a dança fork
/ exec
.
Eu não vou deixá-lo pendurado no entanto. Aqui está um uso I função para os meus próprios programas que faz exatamente o que eu esbocei. É muito semelhante ao popen()
na verdade, a única diferença é que o chamador pode acessar fluxo stderr
da criança, além de stdin
e stdout
.
Código ...
#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;
}
}
Outras dicas
Provavelmente a maneira mais fácil seria usar o popen função : (trecho de página vinculada):
O exemplo a seguir demonstra o uso de popen () e pclose () para executar o comando ls * a fim de obter uma lista de arquivos no diretório atual:
#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() */
...
}
No entanto, querendo ler a saída de um script PHP de dentro de um programa C é uma espécie de bandeira vermelha, e eu suspeito que provavelmente há alguma solução global mais clara para isso, mas é difícil dizer mais sem uma descrição maior nível de o que você está tentando fazer.
Lembre-se de quando você usa execl()
ele irá "saída em caso de sucesso". Então, você nunca vai ver "função php End" porque ele nunca vai chegar a essa linha de código.
Para superar esse problema, você pode usar tanto system
ou utilização fork()
para criar um processo filho e na sua utilização execl
processo filho ou qualquer outra função da família exec
.