ProcessUtils.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Process;
  11. use Symfony\Component\Process\Exception\InvalidArgumentException;
  12. /**
  13. * ProcessUtils is a bunch of utility methods.
  14. *
  15. * This class contains static methods only and is not meant to be instantiated.
  16. *
  17. * @author Martin Hasoň <martin.hason@gmail.com>
  18. */
  19. class ProcessUtils
  20. {
  21. /**
  22. * This class should not be instantiated.
  23. */
  24. private function __construct()
  25. {
  26. }
  27. /**
  28. * Escapes a string to be used as a shell argument.
  29. *
  30. * @param string $argument The argument that will be escaped
  31. *
  32. * @return string The escaped argument
  33. */
  34. public static function escapeArgument($argument)
  35. {
  36. //Fix for PHP bug #43784 escapeshellarg removes % from given string
  37. //Fix for PHP bug #49446 escapeshellarg doesn't work on Windows
  38. //@see https://bugs.php.net/bug.php?id=43784
  39. //@see https://bugs.php.net/bug.php?id=49446
  40. if ('\\' === \DIRECTORY_SEPARATOR) {
  41. if ('' === $argument) {
  42. return escapeshellarg($argument);
  43. }
  44. $escapedArgument = '';
  45. $quote = false;
  46. foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
  47. if ('"' === $part) {
  48. $escapedArgument .= '\\"';
  49. } elseif (self::isSurroundedBy($part, '%')) {
  50. // Avoid environment variable expansion
  51. $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
  52. } else {
  53. // escape trailing backslash
  54. if ('\\' === substr($part, -1)) {
  55. $part .= '\\';
  56. }
  57. $quote = true;
  58. $escapedArgument .= $part;
  59. }
  60. }
  61. if ($quote) {
  62. $escapedArgument = '"'.$escapedArgument.'"';
  63. }
  64. return $escapedArgument;
  65. }
  66. return "'".str_replace("'", "'\\''", $argument)."'";
  67. }
  68. /**
  69. * Validates and normalizes a Process input.
  70. *
  71. * @param string $caller The name of method call that validates the input
  72. * @param mixed $input The input to validate
  73. *
  74. * @return mixed The validated input
  75. *
  76. * @throws InvalidArgumentException In case the input is not valid
  77. *
  78. * Passing an object as an input is deprecated since version 2.5 and will be removed in 3.0.
  79. */
  80. public static function validateInput($caller, $input)
  81. {
  82. if (null !== $input) {
  83. if (\is_resource($input)) {
  84. return $input;
  85. }
  86. if (\is_string($input)) {
  87. return $input;
  88. }
  89. if (is_scalar($input)) {
  90. return (string) $input;
  91. }
  92. // deprecated as of Symfony 2.5, to be removed in 3.0
  93. if (\is_object($input) && method_exists($input, '__toString')) {
  94. @trigger_error('Passing an object as an input is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
  95. return (string) $input;
  96. }
  97. throw new InvalidArgumentException(sprintf('%s only accepts strings or stream resources.', $caller));
  98. }
  99. return $input;
  100. }
  101. private static function isSurroundedBy($arg, $char)
  102. {
  103. return 2 < \strlen($arg) && $char === $arg[0] && $char === $arg[\strlen($arg) - 1];
  104. }
  105. }