39

I need something like this in php:

If (!command_exists('makemiracle')) {
  print 'no miracles';
  return FALSE;
}
else {
  // safely call the command knowing that it exists in the host system
  shell_exec('makemiracle');
}

Are there any solutions?

David G
  • 94,763
  • 41
  • 167
  • 253
mimrock
  • 4,813
  • 8
  • 32
  • 35
  • 1
    Possible duplicate: [How to check whether a command can be executed?](http://stackoverflow.com/questions/3209836/how-to-check-whether-a-command-can-be-executed) – Brad Koch Dec 06 '12 at 18:32

6 Answers6

55

On Linux/Mac OS Try this:

function command_exist($cmd) {
    $return = shell_exec(sprintf("which %s", escapeshellarg($cmd)));
    return !empty($return);
}

Then use it in code:

if (!command_exist('makemiracle')) {
    print 'no miracles';
} else {
    shell_exec('makemiracle');
}

Update: As suggested by @camilo-martin you could simply use:

if (`which makemiracle`) {
    shell_exec('makemiracle');
}
aorcsik
  • 15,271
  • 5
  • 39
  • 49
docksteaderluke
  • 2,195
  • 5
  • 27
  • 38
  • 4
    This can be shortened to `return !empty(shell_exec("which $cmd"));` – tjbp Oct 27 '13 at 15:41
  • 12
    @tjbp even shorter: `return !!\`which $cmd\``. It's actually so short that I'd use it just like that in a condition: `if (\`which foo\`) { ... }` – Camilo Martin Jan 17 '14 at 21:35
  • 2
    Also not you can use `where` on windows. – Petah Feb 12 '14 at 20:10
  • 8
    [I don't think you should use `which` for this.](http://stackoverflow.com/a/677212/937377) – Nathan Arthur Dec 20 '16 at 19:00
  • 3
    `"which %s"` will cause output on STDERR if it can't find the program, and will output to the screen (if run from CLI) or the error log (if run from the web). Use `"which %s 2>/dev/null"` to suppress this output. – amphetamachine May 23 '17 at 15:06
14

Windows uses where, UNIX systems which to allow to localize a command. Both will return an empty string in STDOUT if the command isn't found.

PHP_OS is currently WINNT for every supported Windows version by PHP.

So here a portable solution:

/**
 * Determines if a command exists on the current environment
 *
 * @param string $command The command to check
 * @return bool True if the command has been found ; otherwise, false.
 */
function command_exists ($command) {
  $whereIsCommand = (PHP_OS == 'WINNT') ? 'where' : 'which';

  $process = proc_open(
    "$whereIsCommand $command",
    array(
      0 => array("pipe", "r"), //STDIN
      1 => array("pipe", "w"), //STDOUT
      2 => array("pipe", "w"), //STDERR
    ),
    $pipes
  );
  if ($process !== false) {
    $stdout = stream_get_contents($pipes[1]);
    $stderr = stream_get_contents($pipes[2]);
    fclose($pipes[1]);
    fclose($pipes[2]);
    proc_close($process);

    return $stdout != '';
  }

  return false;
}
Dereckson
  • 1,340
  • 17
  • 30
  • 2
    For Unix, usage of which is not recommended - see http://stackoverflow.com/questions/592620/how-to-check-if-a-program-exists-from-a-bash-script – rr- Sep 20 '14 at 16:00
  • There $whereIsCommand could be `command -v` for UNIX if which doesn't give satisfaction, as pointed by the question given by @rr. – Dereckson Jan 11 '16 at 19:36
  • 1
    `where` actually fails if you pass the full path to the command. On recent Windows it expects a `path:wildcard` and not a filename – Dario Corno Feb 08 '17 at 05:03
  • 2
    Windows does not always necessarily return an empty string if the command is not found. Also things like `INFO: Could not find files for the given pattern(s).` are possible. – David Mar 20 '17 at 14:35
  • PHP is not BASH. Spawning a bash process is arguably more heavy than a which process. If there is a which binary which doesn't return an error code, then it is *broken* and that is not something developers should concern themselves with. – hackel Aug 17 '17 at 18:07
8

Based on @jcubic and that 'which' should be avoided, this is the cross platform I came up with:

function verifyCommand($command) :bool {
  $windows = strpos(PHP_OS, 'WIN') === 0;
  $test = $windows ? 'where' : 'command -v';
  return is_executable(trim(shell_exec("$test $command")));
}
botris
  • 161
  • 2
  • 2
  • Note: This does not work for executeables such as `.bat` files on Windows. `is_executable` will return false for those. – h2ooooooo Jul 14 '21 at 10:00
4

You could use is_executable to check whether it is executable, but you need to know the path of the command, which you could use which command to get it.

xdazz
  • 158,678
  • 38
  • 247
  • 274
  • Well, if `shell_exec( 'which curl' )` gives me `/usr/bin/curl` this means that `curl` shell command exists, right? Why do I still need `is_executable` in the case? – jibiel Oct 26 '14 at 13:27
  • @jibiel File exists and file is executable are different things. – xdazz Oct 27 '14 at 02:22
  • 1
    @xdazz From the man page of which: "which returns the pathnames of the files (or links) which would be **executed** in the current environment" – Ferrybig Nov 24 '16 at 10:49
4

Platform independent solution:

function cmd_exists($command)
{
    if (\strtolower(\substr(PHP_OS, 0, 3)) === 'win')
    {
        $fp = \popen("where $command", "r");
        $result = \fgets($fp, 255);
        $exists = ! \preg_match('#Could not find files#', $result);
        \pclose($fp);   
    }
    else # non-Windows
    {
        $fp = \popen("which $command", "r");
        $result = \fgets($fp, 255);
        $exists = ! empty($result);
        \pclose($fp);
    }

    return $exists;
}
srcspider
  • 10,977
  • 5
  • 40
  • 35
  • 4
    The “Could not find files” string search works only on English Windows platforms. To have a portable solution, gets instead STDOUT, as the “INFO: Could not find files for the given pattern(s).” is sent to STDERR. – Dereckson Aug 30 '13 at 16:06
  • 1
    Why would you put those slashes in front of the standard php functions? – Svetoslav Marinov Aug 31 '16 at 07:41
0

Based on @xdazz answer, works on Windows and Linux. Should also work on MacOSX too, since it's unix.

function is_windows() {
  return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
}

function command_exists($command) {
    $test = is_windows() ? "where" : "which";
    return is_executable(trim(shell_exec("$test $command")));
}
jcubic
  • 61,973
  • 54
  • 229
  • 402