tags:

views:

402

answers:

2

I would like to execute php script from the C Program and store the returning content in to a C variable.

I tried like following but it doesnt works:

C Code:

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

Php Code:

<?php
echo "hello";
?>

Environment:

  • PHP 5.2.6
  • Apache 2.0
  • Fedora Core 10

Also suggest any other better way to do this.

+6  A: 

Probably the easiest way would be to use the popen function: (excerpt from linked page):

The following example demonstrates the use of popen() and pclose() to execute the command ls * in order to obtain a list of files in the current directory:

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

However, wanting to read the output of a PHP script from within a C program is kind of red flag, and I suspect there is probably some cleaner overall solution to this, but it's hard to say more without a higher level description of what you're trying to do.

Jason Creighton
Jason Thanks for the reply. Im trying to do the following in a php script(test1.php): Whenever the new records gets inserted in to a table(ex: table_1) ill be inserting the status say "UPDATE" in to another table (ex:table_2). This need to be put in a scheduler for this im already running a c program all the time so i would like to call the test1.php.
Webrsk
+6  A: 

Short answer here is to use system() or popen() rather than execl(). Seeing as Jason has already posted a good answer about using popen(), I'll skip that and explain how to use execl() just in case you actually care. Most likely, this is all unnecessary technical mumbo jumbo--but dammit, I had most of this typed out already as a long prelude before discussing popen() and I'm not throwing it away now!

Firstly...

When calling execl() all of the command-line arguments need to be passed separately. Also, the first argument must be repeated as argv[0] in any program's main() is traditionally the name of the program. So the fixed call should look like:

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

(I added the cast to (char *) to ensure that a null pointer is passed as the final argument rather than the integer 0, if NULL happens to be defined as 0 and not (void *) 0, which is legal.)

However...

This gets the execl() call right, but there's a bigger problem. The exec family of functions are almost always used in combination with fork() and some complicated pipe() juggling. This is because the exec functions do not actually run the program in a separate process; they actually replace the current process! So once you call execl(), your code is done. Finished. execl() never returns. If you just call it like you've done you'll never get to see what happens as your program will magically transform into a /usr/bin/php process.

OK, so what's this about fork() and pipe()? At a high level, what you've got to do is split your process into two processes. The parent process will continue to be "your" process, while the child process will immediately call execl() and transform itself into /usr/bin/php. Then if you've wired the parent and child processes together correctly they'll be able to communicate with each other.

To make a long story short, if you're still here and haven't nodded off you should consult the wise oracle Google for way more details about all of this. There are plenty of web sites out there giving even more (!) in-depth details about how to do the fork/exec dance.

I won't leave you hanging though. Here's a function I use for my own programs that does exactly what I've outlined. It is very similar to popen() in fact, the only difference being that the caller can access the child's stderr stream in addition to stdin and stdout.

Code...

#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;
    }
}
John Kugelman
+1 for taking the time to explain the pipe()/fork()/dup()/exec() dance, which was clearly needed giving the OP's obvious confusion about how exec() works, but I was too lazy and took the easy route. :)
Jason Creighton
+1 Thanks John for the brilliant detailed answer :)
Webrsk