1
0
mirror of https://github.com/danog/process.git synced 2024-12-02 09:37:55 +01:00

Pass command via STDIN on Windows

This commit is contained in:
Niklas Keller 2017-09-19 13:14:43 +02:00
parent 1ccc4837d4
commit 0e57b8d379
8 changed files with 21 additions and 11 deletions

Binary file not shown.

Binary file not shown.

View File

@ -6,7 +6,10 @@ use Amp\ByteStream\Message;
use Amp\Process\Process; use Amp\Process\Process;
Amp\Loop::run(function () { Amp\Loop::run(function () {
$process = new Process("echo 'Hello, world!'"); // "echo" is a shell internal command on Windows and doesn't work.
$command = DIRECTORY_SEPARATOR === "\\" ? "cmd /c echo Hello World!" : "echo 'Hello, world!'";
$process = new Process($command);
$process->start(); $process->start();
echo yield new Message($process->getStdout()); echo yield new Message($process->getStdout());

View File

@ -9,6 +9,7 @@ use function Amp\Promise\all;
function show_process_output(Process $process): \Generator function show_process_output(Process $process): \Generator
{ {
$stream = $process->getStdout(); $stream = $process->getStdout();
while (null !== $chunk = yield $stream->read()) { while (null !== $chunk = yield $stream->read()) {
echo $chunk; echo $chunk;
} }

View File

@ -9,6 +9,7 @@ Amp\Loop::run(function () {
$process->start(); $process->start();
$stream = $process->getStdout(); $stream = $process->getStdout();
while (null !== $chunk = yield $stream->read()) { while (null !== $chunk = yield $stream->read()) {
echo $chunk; echo $chunk;
} }

View File

@ -6,7 +6,12 @@ use Amp\ByteStream\Message;
use Amp\Process\Process; use Amp\Process\Process;
Amp\Loop::run(function () { Amp\Loop::run(function () {
$process = new Process('read ; echo "$REPLY"'); if (DIRECTORY_SEPARATOR === "\\") {
echo "This example doesn't work on Windows." . PHP_EOL;
exit(1);
}
$process = new Process('read; echo "$REPLY"');
$process->start(); $process->start();
/* send to stdin */ /* send to stdin */

View File

@ -27,7 +27,7 @@ final class Runner implements ProcessRunner {
private $socketConnector; private $socketConnector;
private function makeCommand(string $command, string $workingDirectory): string { private function makeCommand(string $workingDirectory): string {
$result = sprintf( $result = sprintf(
'%s --address=%s --port=%d --token-size=%d', '%s --address=%s --port=%d --token-size=%d',
\escapeshellarg(self::WRAPPER_EXE_PATH), \escapeshellarg(self::WRAPPER_EXE_PATH),
@ -40,8 +40,6 @@ final class Runner implements ProcessRunner {
$result .= ' ' . \escapeshellarg('--cwd=' . \rtrim($workingDirectory, '\\')); $result .= ' ' . \escapeshellarg('--cwd=' . \rtrim($workingDirectory, '\\'));
} }
$result .= ' ' . $command;
return $result; return $result;
} }
@ -51,12 +49,14 @@ final class Runner implements ProcessRunner {
/** @inheritdoc */ /** @inheritdoc */
public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle { public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle {
$command = $this->makeCommand($command, $cwd ?? ''); if (strpos($command, "\0") !== false) {
throw new ProcessException("Can't execute commands that contain null bytes.");
}
$options['bypass_shell'] = true; $options['bypass_shell'] = true;
$handle = new Handle; $handle = new Handle;
$handle->proc = @\proc_open($command, self::FD_SPEC, $pipes, $cwd ?: null, $env ?: null, $options); $handle->proc = @\proc_open($this->makeCommand($cwd ?? ''), self::FD_SPEC, $pipes, $cwd ?: null, $env ?: null, $options);
if (!\is_resource($handle->proc)) { if (!\is_resource($handle->proc)) {
$message = "Could not start process"; $message = "Could not start process";
@ -74,16 +74,16 @@ final class Runner implements ProcessRunner {
} }
$securityTokens = \random_bytes(SocketConnector::SECURITY_TOKEN_SIZE * 6); $securityTokens = \random_bytes(SocketConnector::SECURITY_TOKEN_SIZE * 6);
$written = \fwrite($pipes[0], $securityTokens); $written = \fwrite($pipes[0], $securityTokens . "\0" . $command . "\0");
\fclose($pipes[0]); \fclose($pipes[0]);
\fclose($pipes[1]); \fclose($pipes[1]);
if ($written !== SocketConnector::SECURITY_TOKEN_SIZE * 6) { if ($written !== SocketConnector::SECURITY_TOKEN_SIZE * 6 + \strlen($command) + 2) {
\fclose($pipes[2]); \fclose($pipes[2]);
\proc_close($handle->proc); \proc_close($handle->proc);
throw new ProcessException("Could not send security tokens to process wrapper"); throw new ProcessException("Could not send security tokens / command to process wrapper");
} }
$handle->securityTokens = \str_split($securityTokens, SocketConnector::SECURITY_TOKEN_SIZE); $handle->securityTokens = \str_split($securityTokens, SocketConnector::SECURITY_TOKEN_SIZE);

View File

@ -46,7 +46,7 @@ final class SocketConnector {
Loop::unreference(Loop::onReadable($this->server, [$this, 'onServerSocketReadable'])); Loop::unreference(Loop::onReadable($this->server, [$this, 'onServerSocketReadable']));
} }
private function failClientHandshake($socket, int $code): void { private function failClientHandshake($socket, int $code) {
\fwrite($socket, \chr(SignalCode::HANDSHAKE_ACK) . \chr($code)); \fwrite($socket, \chr(SignalCode::HANDSHAKE_ACK) . \chr($code));
\fclose($socket); \fclose($socket);