Domanda

Vorrei eseguire uno script PHP da un programma C e archiviare il contenuto restituito in una variabile C.

Ho provato come segue ma non funziona:

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

Suggerisci anche qualsiasi altro modo migliore per farlo.

È stato utile?

Soluzione

La risposta breve qui è usare system() o popen() anziché execl(). Visto che Jason ha già pubblicato una buona risposta sull'uso di argv[0], lo salterò e spiegherò come usare main() nel caso in cui ti interessi. Molto probabilmente, questo è tutto inutile jumbo tecnico mumbo - ma dannazione, avevo già scritto quasi tutto come un lungo preludio prima di discutere di (char *) e non lo sto buttando via adesso!

In primo luogo ...

Quando si chiama NULL tutti gli argomenti della riga di comando devono essere passati separatamente. Inoltre, il primo argomento deve essere ripetuto come 0 in qualsiasi programma (void *) 0 è tradizionalmente il nome del programma. Quindi la chiamata fissa dovrebbe apparire come:

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

(Ho aggiunto il cast a exec per assicurarmi che un puntatore nullo venga passato come argomento finale anziché l'intero 0, se fork() sembra essere definito come pipe() e non /usr/bin/php, che è legale.)

Tuttavia ...

Questo ottiene la fork chiamata corretta, ma c'è un problema più grande. La famiglia di funzioni stderr viene quasi sempre utilizzata in combinazione con stdin e alcune complicate giocolette stdout. Questo perché le funzioni <=> non eseguono il programma in un processo separato; sostituiscono effettivamente l'attuale processo! Quindi, una volta chiamato <=>, il codice è terminato. Finito. <=> non ritorna mai. Se lo chiami come hai fatto, non vedrai mai cosa succede poiché il tuo programma si trasformerà magicamente in un <=> processo.

OK, quindi di cosa si tratta <=> e <=>? Ad alto livello, ciò che devi fare è dividere il processo in due processi. Il processo principale continuerà ad essere & Quot; il tuo & Quot; processo, mentre il processo figlio chiamerà immediatamente <=> e si trasformerà in <=>. Quindi se hai collegato correttamente i processi padre e figlio saranno in grado di comunicare tra loro.

Per farla breve, se sei ancora qui e non hai annuito, dovresti consultare il saggio oracolo di Google per ulteriori dettagli su tutto questo. Ci sono molti siti web là fuori che danno ancora più (!) Dettagli approfonditi su come fare la danza <=> / <=>.

Non ti lascerò sospeso però. Ecco una funzione che uso per i miei programmi che fa esattamente quello che ho delineato. È molto simile a <=>, infatti, l'unica differenza è che il chiamante può accedere allo stream <=> del bambino oltre a <=> e <=>.

Codice ...

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

Altri suggerimenti

Probabilmente il modo più semplice sarebbe usare la funzione popen : (estratto dalla pagina collegata):

  

L'esempio seguente mostra l'uso di popen () e pclose () per eseguire il comando ls * per ottenere un elenco di file nella directory corrente:

#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() */
    ...
}

Tuttavia, voler leggere l'output di uno script PHP all'interno di un programma C è una specie di bandiera rossa, e sospetto che ci sia probabilmente una soluzione globale più pulita a questo, ma è difficile dire di più senza una descrizione di livello superiore di cosa stai cercando di fare.

Ricorda quando usi execl() sarà " uscirà in caso di successo " ;. Quindi, non vedrai mai & Quot; Termina la funzione php & Quot; perché non arriverà mai a quella riga di codice.

Per ovviare a questo problema, è possibile utilizzare system o utilizzare fork() per creare un processo figlio e nel processo figlio utilizzare execl o qualsiasi altra funzione della famiglia exec.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top