phpunixpcntl

PHP: pcntl_exec does not work even when valid executable path provided


My setup of my test suite requires a local web server to be launched.

So far, I have come up with this: I employ a PHP built-in web server, a PHP script that starts a web server, runs tests, and finally terminates the webserver it started.

<?php

$childPid = pcntl_fork();

if ($childPid == -1) {
    die('Fork failed');
} else if ($childPid == 0) {;
    // start webserver
    pcntl_exec('/usr/local/bin/php -S localhost:1234');
} else {
    // TODO: check if the webserver is ready 
    
    // run tests
    passthru(__DIR__.'/vendor/bin/phpunit tests');
    
    // terminate webserver
    exec("kill -15 $childPid");
}

The above script is located under /app/test.php. When I run it like so

php test.php

I'm getting this error:

PHP Warning: pcntl_exec(): Error has occurred: (errno 2) No such file or directory in /app/test.php on line 9

For reference, this is what the official doc says about the $path parameter (the first parameter of pcntl_exec):

path must be the path to a binary executable or a script with a valid path pointing to an executable in the shebang ( #!/usr/local/bin/perl for example) as the first line. See your system's man execve(2) page for additional information.

I'm pretty sure the path (/usr/local/bin/php) I provided is correct and it's not a symlink.

When

/usr/local/bin/php -S localhost:1234

is called from the command line the webserver is launched successfully.


Solution

  • TLDR: pcntl_exec('.../php', ['-S', ...]);


    You describe

    the $path parameter (the first parameter of pcntl_exec)

    and you write you are pretty sure that the following is an executable path:

    /usr/local/bin/php -S localhost:1234
    

    As the error message diagnoses, this is ultimately not the case.

    (errno 2) No such file or directory

    And indeed, according to the common php(1) invocation, the executable path is:

    /usr/local/bin/php
    

    Therefore, remove the arguments from the $path parameter, they do not belong there and put them on the appropriate $args parameter.

    pcntl_exec('/usr/local/bin/php', ['-S', 'localhost:1234']);
    

    Bonus:

    To test in the shell if (the wrong) path "/usr/local/bin/php -S localhost:1234" is an executable path, use the command special built-in:

    $ command -v /usr/local/bin/php -S localhost:1234
    $ echo $?
    1
    

    (non-zero exit status code (1), a.k.a. failure)

    For the happy path, it shows the commands' pathname and exits in success:

    $ command -v /usr/bin/php      
    /usr/bin/php
    $ echo $?
    0
    

    (exit status code of zero (0), a.k.a. success)