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

Skip to content

[Process] add a method to the ProcessBuilder to automatically prepend the executed script with "exec" #11335

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

xabbuh
Copy link
Member

@xabbuh xabbuh commented Jul 6, 2014

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets
License MIT
Doc PR symfony/symfony-docs#3999

This pull requests addresses the issue raised by @romainneutron in #5759. It eases the process of creating a Process whose script should be prepended by exec.

@@ -258,6 +283,10 @@ public function getProcess()
$arguments = array_merge($this->prefix, $this->arguments);
$script = implode(' ', array_map(array(__NAMESPACE__.'\\ProcessUtils', 'escapeArgument'), $arguments));

if ($this->useExec) {
$script = 'exec '.$script;
}
Copy link
Member

Choose a reason for hiding this comment

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

Prepending with exec will break several cases, which are not prevented by your current patch:

  • Windows (which does not have exec)
  • complex commands (using &&, || or multiple commands separated by ;)
  • enhanced sigchild compatibility mode (because of the previous case)

Copy link
Member Author

Choose a reason for hiding this comment

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

  • Does Windows have a similar command?
  • How would you use exec in the context of multiple commands? Is that actually possible at all?

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 exec for multiple commands.
But actually, I'm not sure the ProcessBuilder allows building such commands though. It needs to be checked.
the case of sigchild is an issue though.

I don't know about such a command for windows. @romainneutron do you have an idea ?

Copy link
Member Author

Choose a reason for hiding this comment

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

From what I see, the ProcessBuilder cannot create multiple commands. Running something like this:

$builder = new ProcessBuilder(array(
    'php',
    './test1.php',
    ';',
    'php',
    './test2.php',
));

passes ;, php and ./test2.php as arguments to the test1.php script.

Copy link
Member Author

Choose a reason for hiding this comment

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

@romainneutron Do you have any thoughts about this?

Copy link
Contributor

Choose a reason for hiding this comment

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

ProcessBuilder cannot create chained commands (commands separated by ; or &&), it only allows single commands.

I don't know any equivalent on windows, but I don't think it's relevant on this platform: We would use exec to solve the issue mentioned in #5759 (The sh wrapper paragraph)

I think we could allow preprending on linux system that are not in sigchild environment. I've to admit this is a hacky way to solve this PHP issue, however it works very well and would allow using the ProcessBuilder when the use of exec is needed: There is no way to use this functionality at the moment: as the ProcessBuilder escapes all arguments and as exec is not a command (it must not be escaped), the only way is to build the command by hand, which is not something I would recommend.

I'd be in favor of such addition, with all the care and love suggested by @stof (windows and sigchild environments detection to avoid errors)

@xabbuh xabbuh force-pushed the process-builder-use-exec branch from 90b75f3 to b30a57a Compare August 28, 2014 08:33
@xabbuh
Copy link
Member Author

xabbuh commented Aug 28, 2014

@stof @romainneutron Sorry for the delay. I finally changed the pull request according to your comments. However, to be able to detect sigchild environments I had to copy the detection code from the Process class which is not really nice. Would it make sense to move the method into a separate class (for example, into the ProcessUtils class) and keeping the one in Process only for BC?

I didn't like the names enableUseExec() and disableUseExec(). So I changed them to enableShellWrapper() and disableShellWrapper().

On Linux, processes built and executed with the Process component are
automatically wrapped by PHP inside a call to `sh`. This makes it
hard to use methods like `getPid()` or `stop()` since they work with
the `sh` process but not with the process the user intended to start.
The solution is to prepend the command being executed with
[exec](https://en.wikipedia.org/wiki/Exec_%28operating_system%29) (as
described in symfony#5759). The `ProcessBuilder` now has two methods
`enableShellWrapper()` and `disableShellWrapper()` to enable or
disable the shell wrapper.
@xabbuh xabbuh force-pushed the process-builder-use-exec branch from b30a57a to 130608f Compare August 28, 2014 08:48
@xabbuh
Copy link
Member Author

xabbuh commented Sep 17, 2014

ping

@fabpot
Copy link
Member

fabpot commented Sep 26, 2014

@romainneutron What's your thoughts on this PR?

@xabbuh
Copy link
Member Author

xabbuh commented Sep 29, 2014

@romainneutron Any chance to get this into 2.6?

@romainneutron
Copy link
Contributor

The idea is quite interesting, but:

  • I don't like this implementation very much. It affects the Process component at top level, and I'd better love to see such possibilities in the Process\Command I proposed (for 2.7).
  • This is a prefix for command that I use very often, nearly every time I use the Process component and i'd really love to get an helper in the Process component to use it (and enforce ProcessBuilder usage)

@fabpot What do you think about merging this in 2.6 and deprecate it in 2.7 in favor of a better support for non-escaped prefixes/arguments in 2.7 via the Process\Command?

@xabbuh
Copy link
Member Author

xabbuh commented Sep 29, 2014

I don't think that it is a good idea to merge feature if which we know that it will be deprecated in the next release. I would then rather postpone this, discuss your proposal and then decide afterwards if the solution from this pull requested is really needed at all.

@stof
Copy link
Member

stof commented Sep 30, 2014

I'm also against merging this if you already plan to deprecate it

@fabpot
Copy link
Member

fabpot commented Sep 30, 2014

Same as the others. Closing this PR and waiting for the feature to be available in 2.7 via the Process\Command PR.

@fabpot fabpot closed this Sep 30, 2014
@xabbuh xabbuh deleted the process-builder-use-exec branch October 1, 2014 08:26
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
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.

4 participants