🔧
This commit is contained in:
1
vendor/symfony/process/CHANGELOG.md
vendored
1
vendor/symfony/process/CHANGELOG.md
vendored
@@ -7,7 +7,6 @@ CHANGELOG
|
||||
* Add `PhpSubprocess` to handle PHP subprocesses that take over the
|
||||
configuration from their parent
|
||||
* Add `RunProcessMessage` and `RunProcessMessageHandler`
|
||||
* Support using `Process::findExecutable()` independently of `open_basedir`
|
||||
|
||||
5.2.0
|
||||
-----
|
||||
|
||||
35
vendor/symfony/process/ExecutableFinder.php
vendored
35
vendor/symfony/process/ExecutableFinder.php
vendored
@@ -19,7 +19,15 @@ namespace Symfony\Component\Process;
|
||||
*/
|
||||
class ExecutableFinder
|
||||
{
|
||||
private array $suffixes = ['.exe', '.bat', '.cmd', '.com'];
|
||||
private const CMD_BUILTINS = [
|
||||
'assoc', 'break', 'call', 'cd', 'chdir', 'cls', 'color', 'copy', 'date',
|
||||
'del', 'dir', 'echo', 'endlocal', 'erase', 'exit', 'for', 'ftype', 'goto',
|
||||
'help', 'if', 'label', 'md', 'mkdir', 'mklink', 'move', 'path', 'pause',
|
||||
'popd', 'prompt', 'pushd', 'rd', 'rem', 'ren', 'rename', 'rmdir', 'set',
|
||||
'setlocal', 'shift', 'start', 'time', 'title', 'type', 'ver', 'vol',
|
||||
];
|
||||
|
||||
private array $suffixes = [];
|
||||
|
||||
/**
|
||||
* Replaces default suffixes of executable.
|
||||
@@ -48,20 +56,30 @@ class ExecutableFinder
|
||||
* @param string|null $default The default to return if no executable is found
|
||||
* @param array $extraDirs Additional dirs to check into
|
||||
*/
|
||||
public function find(string $name, string $default = null, array $extraDirs = []): ?string
|
||||
public function find(string $name, ?string $default = null, array $extraDirs = []): ?string
|
||||
{
|
||||
// windows built-in commands that are present in cmd.exe should not be resolved using PATH as they do not exist as exes
|
||||
if ('\\' === \DIRECTORY_SEPARATOR && \in_array(strtolower($name), self::CMD_BUILTINS, true)) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
$dirs = array_merge(
|
||||
explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
|
||||
$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;
|
||||
}
|
||||
@@ -72,8 +90,13 @@ class ExecutableFinder
|
||||
}
|
||||
}
|
||||
|
||||
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v';
|
||||
if (\function_exists('exec') && ($executablePath = strtok(@exec($command.' '.escapeshellarg($name)), \PHP_EOL)) && @is_executable($executablePath)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
2
vendor/symfony/process/InputStream.php
vendored
2
vendor/symfony/process/InputStream.php
vendored
@@ -31,7 +31,7 @@ class InputStream implements \IteratorAggregate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onEmpty(callable $onEmpty = null)
|
||||
public function onEmpty(?callable $onEmpty = null)
|
||||
{
|
||||
$this->onEmpty = null !== $onEmpty ? $onEmpty(...) : null;
|
||||
}
|
||||
|
||||
11
vendor/symfony/process/PhpExecutableFinder.php
vendored
11
vendor/symfony/process/PhpExecutableFinder.php
vendored
@@ -32,15 +32,8 @@ class PhpExecutableFinder
|
||||
public function find(bool $includeArgs = true): string|false
|
||||
{
|
||||
if ($php = getenv('PHP_BINARY')) {
|
||||
if (!is_executable($php)) {
|
||||
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v';
|
||||
if (\function_exists('exec') && $php = strtok(exec($command.' '.escapeshellarg($php)), \PHP_EOL)) {
|
||||
if (!is_executable($php)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (!is_executable($php) && !$php = $this->executableFinder->find($php)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (@is_dir($php)) {
|
||||
|
||||
6
vendor/symfony/process/PhpProcess.php
vendored
6
vendor/symfony/process/PhpProcess.php
vendored
@@ -32,7 +32,7 @@ class PhpProcess extends Process
|
||||
* @param int $timeout The timeout in seconds
|
||||
* @param array|null $php Path to the PHP binary to use with any additional arguments
|
||||
*/
|
||||
public function __construct(string $script, string $cwd = null, array $env = null, int $timeout = 60, array $php = null)
|
||||
public function __construct(string $script, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null)
|
||||
{
|
||||
if (null === $php) {
|
||||
$executableFinder = new PhpExecutableFinder();
|
||||
@@ -50,7 +50,7 @@ class PhpProcess extends Process
|
||||
parent::__construct($php, $cwd, $env, $script, $timeout);
|
||||
}
|
||||
|
||||
public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static
|
||||
public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static
|
||||
{
|
||||
throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class PhpProcess extends Process
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function start(callable $callback = null, array $env = [])
|
||||
public function start(?callable $callback = null, array $env = [])
|
||||
{
|
||||
if (null === $this->getCommandLine()) {
|
||||
throw new RuntimeException('Unable to find the PHP executable.');
|
||||
|
||||
8
vendor/symfony/process/PhpSubprocess.php
vendored
8
vendor/symfony/process/PhpSubprocess.php
vendored
@@ -51,7 +51,7 @@ class PhpSubprocess extends Process
|
||||
* @param int $timeout The timeout in seconds
|
||||
* @param array|null $php Path to the PHP binary to use with any additional arguments
|
||||
*/
|
||||
public function __construct(array $command, string $cwd = null, array $env = null, int $timeout = 60, array $php = null)
|
||||
public function __construct(array $command, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null)
|
||||
{
|
||||
if (null === $php) {
|
||||
$executableFinder = new PhpExecutableFinder();
|
||||
@@ -73,12 +73,12 @@ class PhpSubprocess extends Process
|
||||
parent::__construct($command, $cwd, $env, null, $timeout);
|
||||
}
|
||||
|
||||
public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static
|
||||
public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static
|
||||
{
|
||||
throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
|
||||
}
|
||||
|
||||
public function start(callable $callback = null, array $env = []): void
|
||||
public function start(?callable $callback = null, array $env = []): void
|
||||
{
|
||||
if (null === $this->getCommandLine()) {
|
||||
throw new RuntimeException('Unable to find the PHP executable.');
|
||||
@@ -106,7 +106,7 @@ class PhpSubprocess extends Process
|
||||
throw new RuntimeException('Unable to read ini: '.$file);
|
||||
}
|
||||
// Check and remove directives after HOST and PATH sections
|
||||
if (preg_match('/^\s*\[(?:PATH|HOST)\s*=/mi', $data, $matches)) {
|
||||
if (preg_match('/^\s*\[(?:PATH|HOST)\s*=/mi', $data, $matches, \PREG_OFFSET_CAPTURE)) {
|
||||
$data = substr($data, 0, $matches[0][1]);
|
||||
}
|
||||
|
||||
|
||||
2
vendor/symfony/process/Pipes/UnixPipes.php
vendored
2
vendor/symfony/process/Pipes/UnixPipes.php
vendored
@@ -74,7 +74,7 @@ class UnixPipes extends AbstractPipes
|
||||
return [
|
||||
['pty'],
|
||||
['pty'],
|
||||
['pty'],
|
||||
['pipe', 'w'], // stderr needs to be in a pipe to correctly split error and output, since PHP will use the same stream for both
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
40
vendor/symfony/process/Process.php
vendored
40
vendor/symfony/process/Process.php
vendored
@@ -140,7 +140,7 @@ class Process implements \IteratorAggregate
|
||||
*
|
||||
* @throws LogicException When proc_open is not installed
|
||||
*/
|
||||
public function __construct(array $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60)
|
||||
public function __construct(array $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60)
|
||||
{
|
||||
if (!\function_exists('proc_open')) {
|
||||
throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
|
||||
@@ -186,7 +186,7 @@ class Process implements \IteratorAggregate
|
||||
*
|
||||
* @throws LogicException When proc_open is not installed
|
||||
*/
|
||||
public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static
|
||||
public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static
|
||||
{
|
||||
$process = new static([], $cwd, $env, $input, $timeout);
|
||||
$process->commandline = $command;
|
||||
@@ -244,7 +244,7 @@ class Process implements \IteratorAggregate
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function run(callable $callback = null, array $env = []): int
|
||||
public function run(?callable $callback = null, array $env = []): int
|
||||
{
|
||||
$this->start($callback, $env);
|
||||
|
||||
@@ -263,7 +263,7 @@ class Process implements \IteratorAggregate
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function mustRun(callable $callback = null, array $env = []): static
|
||||
public function mustRun(?callable $callback = null, array $env = []): static
|
||||
{
|
||||
if (0 !== $this->run($callback, $env)) {
|
||||
throw new ProcessFailedException($this);
|
||||
@@ -293,7 +293,7 @@ class Process implements \IteratorAggregate
|
||||
* @throws RuntimeException When process is already running
|
||||
* @throws LogicException In case a callback is provided and output has been disabled
|
||||
*/
|
||||
public function start(callable $callback = null, array $env = [])
|
||||
public function start(?callable $callback = null, array $env = [])
|
||||
{
|
||||
if ($this->isRunning()) {
|
||||
throw new RuntimeException('Process is already running.');
|
||||
@@ -345,7 +345,7 @@ class Process implements \IteratorAggregate
|
||||
|
||||
$process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
|
||||
|
||||
if (!\is_resource($process)) {
|
||||
if (!$process) {
|
||||
throw new RuntimeException('Unable to launch a new process.');
|
||||
}
|
||||
$this->process = $process;
|
||||
@@ -378,7 +378,7 @@ class Process implements \IteratorAggregate
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function restart(callable $callback = null, array $env = []): static
|
||||
public function restart(?callable $callback = null, array $env = []): static
|
||||
{
|
||||
if ($this->isRunning()) {
|
||||
throw new RuntimeException('Process is already running.');
|
||||
@@ -405,7 +405,7 @@ class Process implements \IteratorAggregate
|
||||
* @throws ProcessSignaledException When process stopped after receiving signal
|
||||
* @throws LogicException When process is not yet started
|
||||
*/
|
||||
public function wait(callable $callback = null): int
|
||||
public function wait(?callable $callback = null): int
|
||||
{
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
|
||||
@@ -878,7 +878,7 @@ class Process implements \IteratorAggregate
|
||||
*
|
||||
* @return int|null The exit-code of the process or null if it's not running
|
||||
*/
|
||||
public function stop(float $timeout = 10, int $signal = null): ?int
|
||||
public function stop(float $timeout = 10, ?int $signal = null): ?int
|
||||
{
|
||||
$timeoutMicro = microtime(true) + $timeout;
|
||||
if ($this->isRunning()) {
|
||||
@@ -1210,7 +1210,7 @@ class Process implements \IteratorAggregate
|
||||
{
|
||||
static $isTtySupported;
|
||||
|
||||
return $isTtySupported ??= ('/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT));
|
||||
return $isTtySupported ??= ('/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT) && @is_writable('/dev/tty'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1256,7 +1256,7 @@ class Process implements \IteratorAggregate
|
||||
*
|
||||
* @param callable|null $callback The user defined PHP callback
|
||||
*/
|
||||
protected function buildCallback(callable $callback = null): \Closure
|
||||
protected function buildCallback(?callable $callback = null): \Closure
|
||||
{
|
||||
if ($this->outputDisabled) {
|
||||
return fn ($type, $data): bool => null !== $callback && $callback($type, $data);
|
||||
@@ -1288,7 +1288,9 @@ class Process implements \IteratorAggregate
|
||||
return;
|
||||
}
|
||||
|
||||
$this->processInformation = proc_get_status($this->process);
|
||||
if ($this->processInformation['running'] ?? true) {
|
||||
$this->processInformation = proc_get_status($this->process);
|
||||
}
|
||||
$running = $this->processInformation['running'];
|
||||
|
||||
$this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
|
||||
@@ -1386,8 +1388,9 @@ class Process implements \IteratorAggregate
|
||||
private function close(): int
|
||||
{
|
||||
$this->processPipes->close();
|
||||
if (\is_resource($this->process)) {
|
||||
if ($this->process) {
|
||||
proc_close($this->process);
|
||||
$this->process = null;
|
||||
}
|
||||
$this->exitcode = $this->processInformation['exitcode'];
|
||||
$this->status = self::STATUS_TERMINATED;
|
||||
@@ -1521,7 +1524,14 @@ class Process implements \IteratorAggregate
|
||||
$cmd
|
||||
);
|
||||
|
||||
$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 ?? 'cmd').' /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
|
||||
foreach ($this->processPipes->getFiles() as $offset => $filename) {
|
||||
$cmd .= ' '.$offset.'>"'.$filename.'"';
|
||||
}
|
||||
@@ -1567,7 +1577,7 @@ class Process implements \IteratorAggregate
|
||||
if (str_contains($argument, "\0")) {
|
||||
$argument = str_replace("\0", '?', $argument);
|
||||
}
|
||||
if (!preg_match('/[\/()%!^"<>&|\s]/', $argument)) {
|
||||
if (!preg_match('/[()%!^"<>&|\s]/', $argument)) {
|
||||
return $argument;
|
||||
}
|
||||
$argument = preg_replace('/(\\\\+)$/', '$1$1', $argument);
|
||||
|
||||
Reference in New Issue
Block a user