diff --git a/ExecutableFinder.php b/ExecutableFinder.php index ff68ed33..6f204947 100644 --- a/ExecutableFinder.php +++ b/ExecutableFinder.php @@ -19,7 +19,7 @@ */ class ExecutableFinder { - private $suffixes = ['.exe', '.bat', '.cmd', '.com']; + private $suffixes = []; /** * Replaces default suffixes of executable. @@ -70,19 +70,38 @@ public function find($name, $default = null, array $extraDirs = []) ); } - $suffixes = ['']; + $suffixes = []; if ('\\' === \DIRECTORY_SEPARATOR) { $pathExt = getenv('PATHEXT'); - $suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes); + $suffixes = $this->suffixes; + $suffixes = array_merge($suffixes, $pathExt ? explode(\PATH_SEPARATOR, $pathExt) : ['.exe', '.bat', '.cmd', '.com']); } + $suffixes = '' !== pathinfo($name, PATHINFO_EXTENSION) ? array_merge([''], $suffixes) : array_merge($suffixes, ['']); foreach ($suffixes as $suffix) { foreach ($dirs as $dir) { + if ('' === $dir) { + $dir = '.'; + } if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) { return $file; } + + if (!@is_dir($dir) && basename($dir) === $name.$suffix && @is_executable($dir)) { + return $dir; + } } } + if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('exec') || \strlen($name) !== strcspn($name, '/'.\DIRECTORY_SEPARATOR)) { + return $default; + } + + $execResult = exec('command -v -- '.escapeshellarg($name)); + + if (($executablePath = substr($execResult, 0, strpos($execResult, \PHP_EOL) ?: null)) && @is_executable($executablePath)) { + return $executablePath; + } + return $default; } } diff --git a/PhpExecutableFinder.php b/PhpExecutableFinder.php index b9a80156..d1b3b6e0 100644 --- a/PhpExecutableFinder.php +++ b/PhpExecutableFinder.php @@ -35,6 +35,18 @@ public function __construct() */ public function find($includeArgs = true) { + if ($php = getenv('PHP_BINARY')) { + if (!is_executable($php) && !$php = $this->executableFinder->find($php)) { + return false; + } + + if (@is_dir($php)) { + return false; + } + + return $php; + } + $args = $this->findArguments(); $args = $includeArgs && $args ? ' '.implode(' ', $args) : ''; diff --git a/Process.php b/Process.php index 91ce2c49..2a63f17e 100644 --- a/Process.php +++ b/Process.php @@ -1664,6 +1664,15 @@ function ($m) use (&$env, &$varCache, &$varCount, $uid) { ); $cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')'; + static $comSpec; + + if (!$comSpec && $comSpec = (new ExecutableFinder())->find('cmd.exe')) { + // Escape according to CommandLineToArgvW rules + $comSpec = '"'.preg_replace('{(\\\\*+)"}', '$1$1\"', $comSpec) .'"'; + } + + $cmd = ($comSpec !== null ? $comSpec : 'cmd').' /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')'; + foreach ($this->processPipes->getFiles() as $offset => $filename) { $cmd .= ' '.$offset.'>"'.$filename.'"'; }