This commit is contained in:
2025-05-12 14:25:25 +02:00
parent ab2db755ef
commit 9e378ca2b7
2719 changed files with 46505 additions and 60181 deletions

View File

@@ -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);