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 */
2321class 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