Skip to content

Commit c31f07e

Browse files
authored
fix: Fix the double escaping done to options passed to the child process (#325)
1 parent faf7dd9 commit c31f07e

File tree

3 files changed

+18
-69
lines changed

3 files changed

+18
-69
lines changed

src/Input/InputOptionsSerializer.php

+2-38
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,13 @@
2222
use function array_map;
2323
use function array_merge;
2424
use function is_array;
25-
use function is_string;
26-
use function preg_match;
2725
use function sprintf;
28-
use function str_replace;
2926

3027
/**
3128
* @internal
3229
*/
3330
final class InputOptionsSerializer
3431
{
35-
private const string ESCAPE_TOKEN_PATTERN = '/[\s\W]/';
36-
3732
private function __construct()
3833
{
3934
}
@@ -81,10 +76,7 @@ private static function serializeOption(
8176
return match (true) {
8277
$option->isNegatable() => sprintf('--%s%s', $value ? '' : 'no-', $name),
8378
!$option->acceptValue() => sprintf('--%s', $name),
84-
self::isArray($option, $value) => array_map(
85-
static fn ($item) => self::serializeOptionWithValue($name, $item),
86-
$value,
87-
),
79+
self::isArray($option, $value) => array_map(static fn ($item) => self::serializeOptionWithValue($name, $item), $value),
8880
default => self::serializeOptionWithValue($name, $value),
8981
};
9082
}
@@ -105,34 +97,6 @@ private static function serializeOptionWithValue(
10597
string $name,
10698
bool|float|int|string|null $value,
10799
): string {
108-
return sprintf(
109-
'--%s=%s',
110-
$name,
111-
self::quoteOptionValue($value),
112-
);
113-
}
114-
115-
/**
116-
* Ensure that an option value is quoted correctly before it is passed to a
117-
* child process.
118-
*/
119-
private static function quoteOptionValue(bool|float|int|string|null $value): bool|float|int|string|null
120-
{
121-
if (self::isValueRequiresQuoting($value)) {
122-
return sprintf(
123-
'"%s"',
124-
str_replace('"', '\"', (string) $value),
125-
);
126-
}
127-
128-
return $value;
129-
}
130-
131-
/**
132-
* Validate whether a command option requires quoting.
133-
*/
134-
private static function isValueRequiresQuoting(mixed $value): bool
135-
{
136-
return is_string($value) && 0 < preg_match(self::ESCAPE_TOKEN_PATTERN, $value);
100+
return sprintf('--%s=%s', $name, $value);
137101
}
138102
}

tests/Input/InputOptionsSerializerTest.php

+9-5
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,11 @@ private static function optionSerializationProvider(): iterable
255255
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
256256
),
257257
['--opt' => ['v1', 'v2', 'v3']],
258-
['--opt=v1', '--opt=v2', '--opt=v3'],
258+
[
259+
'--opt=v1',
260+
'--opt=v2',
261+
'--opt=v3',
262+
],
259263
);
260264

261265
if (!$isSymfony4) {
@@ -315,22 +319,22 @@ private static function escapedValuesProvider(): iterable
315319

316320
yield $createSet(
317321
'"foo"',
318-
'"\"foo\""',
322+
'"foo"',
319323
);
320324

321325
yield $createSet(
322326
'"o_id in(\'20\')"',
323-
'"\"o_id in(\'20\')\""',
327+
'"o_id in(\'20\')"',
324328
);
325329

326330
yield $createSet(
327331
'a b c d',
328-
'"a b c d"',
332+
'a b c d',
329333
);
330334

331335
yield $createSet(
332336
"A\nB'C",
333-
"\"A\nB'C\"",
337+
"A\nB'C",
334338
);
335339
}
336340

tests/Integration/DebugChildProcessInputsTest.php

+7-26
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,19 @@ public function test_it_can_run_the_command_without_sub_processes(
4949
string $item,
5050
?string $simpleOption,
5151
array $arrayOption,
52-
string $expected,
52+
?string $expected = null,
5353
): void {
5454
$logger = new DummyLogger();
5555

5656
$this->command->setItem($item);
5757
$this->command->setLogger($logger);
5858

59+
$expected ??= DebugChildProcessCommand::createContent(
60+
$item,
61+
$simpleOption,
62+
$arrayOption,
63+
);
64+
5965
$this->commandTester->execute(
6066
[
6167
'command' => 'debug:process',
@@ -78,55 +84,30 @@ public static function inputProvider(): iterable
7884
'item',
7985
null,
8086
[],
81-
DebugChildProcessCommand::createContent(
82-
'item',
83-
'',
84-
[],
85-
),
8687
];
8788

8889
yield 'with values' => [
8990
'item',
9091
'option',
9192
['option1', 'option2'],
92-
DebugChildProcessCommand::createContent(
93-
'item',
94-
'option',
95-
['option1', 'option2'],
96-
),
9793
];
9894

9995
yield 'escaped string token' => [
10096
'"foo"',
10197
'"bar"',
10298
['"option1"', '"option2"'],
103-
DebugChildProcessCommand::createContent(
104-
'"foo"',
105-
'"\"bar\""',
106-
['"\"option1\""', '"\"option2\""'],
107-
),
10899
];
109100

110101
yield 'escaped string token with both types of quotes' => [
111102
'"o_id in(\'20\')"',
112103
'"p_id in(\'22\')"',
113104
['"option in(\'1\')"', '"option in(\'2\')"'],
114-
DebugChildProcessCommand::createContent(
115-
'"o_id in(\'20\')"',
116-
'"\"p_id in(\'22\')\""',
117-
['"\"option in(\'1\')\""', '"\"option in(\'2\')\""'],
118-
),
119105
];
120106

121107
yield 'with values with spaces' => [
122108
'a b c d',
123109
'd c b a',
124110
['option 1', 'option 2'],
125-
DebugChildProcessCommand::createContent(
126-
'a b c d',
127-
'"d c b a"',
128-
['"option 1"', '"option 2"'],
129-
),
130111
];
131112
}
132113
}

0 commit comments

Comments
 (0)