Last active
April 12, 2016 14:27
-
-
Save BYK/f85c0845d9ad75fc508927ae39210803 to your computer and use it in GitHub Desktop.
Process call argument escaping on Windows with PHP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Escapes a single argument to be glued together and passed into | |
* CreateProcess on Windows through `proc_open`. | |
* | |
* Adapted from https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ | |
* | |
* @param string The argument to be escaped | |
* @result string Escaped argument that can be used in a CreateProcess call | |
*/ | |
function escapeWindowsArgv($value) { | |
// Don't quote unless we actually need to do so hopefully | |
// avoid problems if programs won't parse quotes properly | |
if ($value && !preg_match('/["[:space:]]/', $value)) { | |
return $value; | |
} | |
$result = '"'; | |
$len = strlen($value); | |
for ($i = 0; $i < $len; $i++) { | |
$numBackslashes = 0; | |
while ($i < $len && $value[$i] == '\\') { | |
$i++; | |
$numBackslashes++; | |
} | |
if ($i == $len) { | |
// Escape all backslashes, but let the terminating | |
// double quotation mark we add below be interpreted | |
// as a metacharacter. | |
$result .= str_repeat('\\', $numBackslashes * 2); | |
break; | |
} elseif ($value[$i] == '"') { | |
// Escape all backslashes and the following double quotation mark. | |
$result .= str_repeat('\\', $numBackslashes * 2 + 1); | |
$result .= $value[$i]; | |
} else { | |
// Backslashes aren't special here. | |
$result .= str_repeat('\\', $numBackslashes); | |
$result .= $value[$i]; | |
} | |
} | |
$result .= '"'; | |
return $result; | |
} | |
/** | |
* Escapes all CMD metacharacters with a `^`. | |
* | |
* Adapted from https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ | |
* | |
* @param string The argument to be escaped | |
* @result string Escaped argument that can be used in CMD.exe | |
*/ | |
function escapeWindowsCMD($value) { | |
// Make sure this is CreateProcess-safe first | |
$value = escapeWindowsArgv($value); | |
// Now prefix all CMD meta characters with a `^` to escape them | |
return preg_replace('/[()%!^"<>&|]/', '^$0', $value); | |
} | |
/* Some strings that are tested: | |
$edgeCases = array( | |
'\0', // null byte | |
'\\', | |
'%', | |
'%%', | |
' ', // space | |
'', // empty string | |
'-', | |
'/flag', | |
'\\\^\%\\\'\ \\', | |
'%PATH%', | |
'%XYZ%', | |
'%%HOMEDIR%', | |
'\n', // newline | |
'\r', // newline | |
'a b', | |
'"a b"', | |
'"%%$HOMEDIR%^^"', | |
'\'a b\'', | |
'^%HO ^"M\'EDIR^%^%\'', | |
'"\'a\0\r\nb%PATH%%`\'"\'`\'`\'', | |
); | |
*/ | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment