8000 [Process] Make arg escaping on Windows more robust · symfony/symfony@02a6451 · GitHub
[go: up one dir, main page]

Skip to content

Commit 02a6451

Browse files
[Process] Make arg escaping on Windows more robust
1 parent 17ce5f5 commit 02a6451

File tree

1 file changed

+22
-39
lines changed

1 file changed

+22
-39
lines changed

src/Symfony/Component/Process/ProcessUtils.php

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
* ProcessUtils is a bunch of utility methods.
1818
*
1919
* This class contains static methods only and is not meant to be instantiated.
20-
*
21-
* @author Martin Hasoň <martin.hason@gmail.com>
2220
*/
2321
class ProcessUtils
2422
{
@@ -32,46 +30,36 @@ private function __construct()
3230
/**
3331
* Escapes a string to be used as a shell argument.
3432
*
35-
* @param string $argument The argument that will be escaped
33+
* Provides a more robust method on Windows than escapeshellarg.
34+
*
35+
* Feel free to copy this function, but please keep the following notice:
36+
* MIT Licensed (c) John Stevenson <john-stevenson@blueyonder.co.uk>
37+
* See https://github.com/johnstevenson/winbox-args for more information.
38+
*
39+
* @param string $arg The argument to be escaped
3640
*
3741
* @return string The escaped argument
3842
*/
39-
public static function escapeArgument($argument)
43+
public static function escapeArgument($arg)
4044
{
41-
//Fix for PHP bug #43784 escapeshellarg removes % from given string
42-
//Fix for PHP bug #49446 escapeshellarg doesn't work on Windows
43-
//@see https://bugs.php.net/bug.php?id=43784
44-
//@see https://bugs.php.net/bug.php?id=49446
45-
if ('\\' === DIRECTORY_SEPARATOR) {
46-
if ('' === $argument) {
47-
return escapeshellarg($argument);
48-
}
45+
if ('\\' !== DIRECTORY_SEPARATOR) {
46+
return escapeshellarg($arg);
47+
}
4948

50-
$escapedArgument = '';
51-
$quote = false;
52-
foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
53-
if ('"' === $part) {
54-
$escapedArgument .= '\\"';
55-
} elseif (self::isSurroundedBy($part, '%')) {
56-
// Avoid environment variable expansion
57-
$escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
58-
} else {
59-
// escape trailing backslash
60-
if ('\\' === substr($part, -1)) {
61-
$part .= '\\';
62-
}
63-
$quote = true;
64-
$escapedArgument .= $part;
65-
}
66-
}
67-
if ($quote) {
68-
$escapedArgument = '"'.$escapedArgument.'"';
69-
}
49+
$arg = (string) $arg;
50+
$quote = '' === $arg || false !== strpbrk($arg, " \t");
51+
$arg = preg_replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes);
52+
53+
if (!$quote && !$dquotes && !preg_match('/%[^%]++%/', $arg)) {
54+
$quote = false !== strpbrk($arg, '^&|<>()');
55+
}
7056

71-
return $escapedArgument;
57+
if ($quote) {
58+
$arg = preg_replace('/(\\\\*)$/', '$1$1', $arg);
59+
$arg = '"'.$arg.'"';
7260
}
7361

74-
return escapeshellarg($argument);
62+
return preg_replace('/(["^&|<>()%])/', '^$1', $arg);
7563
}
7664

7765
/**
@@ -110,9 +98,4 @@ public static function validateInput($caller, $input)
11098

11199
return $input;
112100
}
113-
114-
private static function isSurroundedBy($arg, $char)
115-
{
116-
return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];
117-
}
118101
}

0 commit comments

Comments
 (0)
0