Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[WIP][Process] Add Process\Command #11972

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

romainneutron
Copy link
Contributor

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? yes
Tests pass? yes
Fixed tickets #10025
License MIT
Doc PR todo

I open a PR for this work-in-progress as an alternative to #11971. The implementation of the Process Command is quite okay, it should be tested and the API validated.

This Command would help us to enforce the use of the ProcessBuilder and provide a way to avoid command injections.

return $command;
}

private function getredirects()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be getRedirects()

@romainneutron romainneutron force-pushed the process-pipe branch 2 times, most recently from 453972a to 7e53ff1 Compare September 21, 2014 14:39
@romainneutron romainneutron changed the title [WIP][Processs] Add Process\Command [WIP][Process] Add Process\Command Sep 21, 2014
}

if ($prepend) {
$this->parts = ($escape ? array_map([self, 'escape'], $parts) : $parts) + $this->parts;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You cannot use the short array syntax with PHP 5.3


public function __toString()
{
return implode(' ', $this->parts).array_map('; ', $this->appended).$this->getredirects().($this->piped ? ' | '.$this->piped : '');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be implode instead of array_map ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have both appended and piped, only last appended will be piped (same for redirects).
Should be
return implode(' ', $this->parts).($this->piped ? ' | '.$this->piped : '').$this->getredirects().implode('; ', $this->appended)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the last version, I think it has been fixed

@romainneutron romainneutron force-pushed the process-pipe branch 5 times, most recently from bf93366 to 75006d4 Compare September 21, 2014 15:20
$command = '('.$command.$this->getRedirects().')';
}

$command .= ($this->piped ? '| '.$this->piped : '');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if piped should be applied to the original command or the last appended ?
For instance, in the following code, should wc applied to ls or exit?

$c = new Command('ls -al');
$c->pipped(new Command('wc -l'))
  ->append(new Command('exit $code', false));

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, appended commands should be appended to the line after piped and redirects.
Because, if y want to execute cmd1 ; cmd2 | cmd3 I can use

new Command('cmd1')
  ->append(new Command('cmd2')->pipe(new Command('cmd3')));

But if I want execute cmd1 | cmd3; cmd2 and run

new Command('cmd1')
  ->append(new Command('cmd2'))
  ->pipe(new Command('cmd3'));

It will not works

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for your feedback @jeremy-derusse, this is indeed something we need to pay attention, I'm gonna work on this during the week, let's take some time to see what are the best options for us

@fabpot fabpot added the Process label Sep 22, 2014
if (!$commandline instanceof Command) {
$commandline = Command::fromString($commandline);
}

$this->commandline = $commandline;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should rename $this->commandLine to $this->command to have a more logical name given that it stores a command

@stof
Copy link
Member

stof commented Sep 24, 2014

@romainneutron if we go this way, it would make sense to allow combining commands with && or || rather than just ; or |

@@ -35,43 +38,12 @@ private function __construct()
* @param string $argument The argument that will be escaped
*
* @return string The escaped argument
*
* @deprecated Deprecated as of Symfony 2.6, to be removed in symfony 3.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 for deprecating it. Having the fixed escaping is useful for people not using the ProcessBuilder to build the process, for instance Composer: composer/composer#3297

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I deprecated it here because I moved it in the Command class. Do you mean it should be left open for external usage?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, yes (and then, Command can use it as well).

Btw, the ProcessBuilder still uses it too

@fabpot
Copy link
Member

fabpot commented Jan 25, 2016

@romainneutron What about this one?

@romainneutron romainneutron deleted the process-pipe branch January 27, 2016 11:03
@matejvelikonja
Copy link

so, at the moment there is no input redirect option to use for SF process?

fabpot added a commit that referenced this pull request Feb 8, 2017
…ars, fixing signaling and escaping (nicolas-grekas)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[Process] Accept command line arrays and per-run env vars, fixing signaling and escaping

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #12488, #11972, #10025, #11335, #5759, #5030, #19993, #10486
| License       | MIT
| Doc PR        | -

I think I found a way to fix this network of issues once for all.
Of all the linked ones, only the last two are still open: the remaining were closed in dead ends.

Instead of trying to make `ProcessUtil::escapeArgument` work correctly on Windows - which is impossible as discussed in #21347 - this PR deprecates it in favor of a more powerful approach.

Depending on the use case:

- when a simple command should be run, `Process` now accepts an array of arguments (the "binary" being the first arg). Making this the responsibility of `Process` (instead of `ProcessBuilder`) gives two benefits:
  - escape becomes an internal detail that doesn't leak - thus can't be misused ([see here](#21347 (comment)))
  - since we know we're running a single command, we can prefix it automatically by "exec" - thus fixing a long standing issue with signaling

```php
        $p = new Process(array('php', '-r', 'echo 123;'));
        echo $p->getCommandLine();
        // displays on Linux:
        // exec 'php' '-r' 'echo 123;'
```

- when a shell expression is required, passing a string is still allowed. To make it easy and look-like sql prepared statements, env vars can be used when running the command. Since the shell is OS-specific (think Windows vs Linux) - this PR assumes no portability, so one should just use each shell's specific syntax.

From the fixtures:
```php
        $env = array('FOO' => 'Foo', 'BAR' => 'Bar');
        $cmd = '\\' === DIRECTORY_SEPARATOR ? 'echo !FOO! !BAR! !BAZ!' : 'echo $FOO $BAR $BAZ';
        $p = new Process($cmd, null, $env);
        $p->run(null, array('BAR' => 'baR', 'BAZ' => 'baZ'));

        $this->assertSame('Foo baR baZ', rtrim($p->getOutput()));
        $this->assertSame($env, $p->getEnv());
```

Commits
-------

330b61f [Process] Accept command line arrays and per-run env vars, fixing signaling and escaping
@exteon
Copy link

exteon commented Dec 27, 2021

I don't know if it's the right place to ask, is there a similar ticket to also implement command concurrency operators:
proc1 || proc2, proc1 & proc2, proc1 && proc2, proc1 &?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants