comparison vendor/symfony/process/Process.php @ 14:1fec387a4317

Update Drupal core to 8.5.2 via Composer
author Chris Cannam
date Mon, 23 Apr 2018 09:46:53 +0100
parents 4c8ae668cc8c
children 129ea1e6d783
comparison
equal deleted inserted replaced
13:5fb285c0d0e3 14:1fec387a4317
56 private $input; 56 private $input;
57 private $starttime; 57 private $starttime;
58 private $lastOutputTime; 58 private $lastOutputTime;
59 private $timeout; 59 private $timeout;
60 private $idleTimeout; 60 private $idleTimeout;
61 private $options; 61 private $options = array('suppress_errors' => true);
62 private $exitcode; 62 private $exitcode;
63 private $fallbackStatus = array(); 63 private $fallbackStatus = array();
64 private $processInformation; 64 private $processInformation;
65 private $outputDisabled = false; 65 private $outputDisabled = false;
66 private $stdout; 66 private $stdout;
85 85
86 /** 86 /**
87 * Exit codes translation table. 87 * Exit codes translation table.
88 * 88 *
89 * User-defined errors must use exit codes in the 64-113 range. 89 * User-defined errors must use exit codes in the 64-113 range.
90 *
91 * @var array
92 */ 90 */
93 public static $exitCodes = array( 91 public static $exitCodes = array(
94 0 => 'OK', 92 0 => 'OK',
95 1 => 'General error', 93 1 => 'General error',
96 2 => 'Misuse of shell builtins', 94 2 => 'Misuse of shell builtins',
132 // 158 - not defined 130 // 158 - not defined
133 159 => 'Bad syscall', 131 159 => 'Bad syscall',
134 ); 132 );
135 133
136 /** 134 /**
137 * Constructor. 135 * @param string|array $commandline The command line to run
138 *
139 * @param string $commandline The command line to run
140 * @param string|null $cwd The working directory or null to use the working dir of the current PHP process 136 * @param string|null $cwd The working directory or null to use the working dir of the current PHP process
141 * @param array|null $env The environment variables or null to use the same environment as the current PHP process 137 * @param array|null $env The environment variables or null to use the same environment as the current PHP process
142 * @param mixed|null $input The input as stream resource, scalar or \Traversable, or null for no input 138 * @param mixed|null $input The input as stream resource, scalar or \Traversable, or null for no input
143 * @param int|float|null $timeout The timeout in seconds or null to disable 139 * @param int|float|null $timeout The timeout in seconds or null to disable
144 * @param array $options An array of options for proc_open 140 * @param array $options An array of options for proc_open
145 * 141 *
146 * @throws RuntimeException When proc_open is not installed 142 * @throws RuntimeException When proc_open is not installed
147 */ 143 */
148 public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array()) 144 public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = null)
149 { 145 {
150 if (!function_exists('proc_open')) { 146 if (!function_exists('proc_open')) {
151 throw new RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.'); 147 throw new RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.');
152 } 148 }
153 149
168 $this->setInput($input); 164 $this->setInput($input);
169 $this->setTimeout($timeout); 165 $this->setTimeout($timeout);
170 $this->useFileHandles = '\\' === DIRECTORY_SEPARATOR; 166 $this->useFileHandles = '\\' === DIRECTORY_SEPARATOR;
171 $this->pty = false; 167 $this->pty = false;
172 $this->enhanceSigchildCompatibility = '\\' !== DIRECTORY_SEPARATOR && $this->isSigchildEnabled(); 168 $this->enhanceSigchildCompatibility = '\\' !== DIRECTORY_SEPARATOR && $this->isSigchildEnabled();
173 $this->options = array_replace(array('suppress_errors' => true, 'binary_pipes' => true), $options); 169 if (null !== $options) {
170 @trigger_error(sprintf('The $options parameter of the %s constructor is deprecated since Symfony 3.3 and will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
171 $this->options = array_replace($this->options, $options);
172 }
174 } 173 }
175 174
176 public function __destruct() 175 public function __destruct()
177 { 176 {
178 $this->stop(0); 177 $this->stop(0);
193 * The STDOUT and STDERR are also available after the process is finished 192 * The STDOUT and STDERR are also available after the process is finished
194 * via the getOutput() and getErrorOutput() methods. 193 * via the getOutput() and getErrorOutput() methods.
195 * 194 *
196 * @param callable|null $callback A PHP callback to run whenever there is some 195 * @param callable|null $callback A PHP callback to run whenever there is some
197 * output available on STDOUT or STDERR 196 * output available on STDOUT or STDERR
197 * @param array $env An array of additional env vars to set when running the process
198 * 198 *
199 * @return int The exit status code 199 * @return int The exit status code
200 * 200 *
201 * @throws RuntimeException When process can't be launched 201 * @throws RuntimeException When process can't be launched
202 * @throws RuntimeException When process stopped after receiving signal 202 * @throws RuntimeException When process stopped after receiving signal
203 * @throws LogicException In case a callback is provided and output has been disabled 203 * @throws LogicException In case a callback is provided and output has been disabled
204 */ 204 *
205 public function run($callback = null) 205 * @final since version 3.3
206 { 206 */
207 $this->start($callback); 207 public function run($callback = null/*, array $env = array()*/)
208 {
209 $env = 1 < func_num_args() ? func_get_arg(1) : null;
210 $this->start($callback, $env);
208 211
209 return $this->wait(); 212 return $this->wait();
210 } 213 }
211 214
212 /** 215 /**
214 * 217 *
215 * This is identical to run() except that an exception is thrown if the process 218 * This is identical to run() except that an exception is thrown if the process
216 * exits with a non-zero exit code. 219 * exits with a non-zero exit code.
217 * 220 *
218 * @param callable|null $callback 221 * @param callable|null $callback
222 * @param array $env An array of additional env vars to set when running the process
219 * 223 *
220 * @return self 224 * @return self
221 * 225 *
222 * @throws RuntimeException if PHP was compiled with --enable-sigchild and the enhanced sigchild compatibility mode is not enabled 226 * @throws RuntimeException if PHP was compiled with --enable-sigchild and the enhanced sigchild compatibility mode is not enabled
223 * @throws ProcessFailedException if the process didn't terminate successfully 227 * @throws ProcessFailedException if the process didn't terminate successfully
224 */ 228 *
225 public function mustRun(callable $callback = null) 229 * @final since version 3.3
230 */
231 public function mustRun(callable $callback = null/*, array $env = array()*/)
226 { 232 {
227 if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { 233 if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
228 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.'); 234 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
229 } 235 }
230 236 $env = 1 < func_num_args() ? func_get_arg(1) : null;
231 if (0 !== $this->run($callback)) { 237
238 if (0 !== $this->run($callback, $env)) {
232 throw new ProcessFailedException($this); 239 throw new ProcessFailedException($this);
233 } 240 }
234 241
235 return $this; 242 return $this;
236 } 243 }
247 * the output in real-time while writing the standard input to the process. 254 * the output in real-time while writing the standard input to the process.
248 * It allows to have feedback from the independent process during execution. 255 * It allows to have feedback from the independent process during execution.
249 * 256 *
250 * @param callable|null $callback A PHP callback to run whenever there is some 257 * @param callable|null $callback A PHP callback to run whenever there is some
251 * output available on STDOUT or STDERR 258 * output available on STDOUT or STDERR
259 * @param array $env An array of additional env vars to set when running the process
252 * 260 *
253 * @throws RuntimeException When process can't be launched 261 * @throws RuntimeException When process can't be launched
254 * @throws RuntimeException When process is already running 262 * @throws RuntimeException When process is already running
255 * @throws LogicException In case a callback is provided and output has been disabled 263 * @throws LogicException In case a callback is provided and output has been disabled
256 */ 264 */
257 public function start(callable $callback = null) 265 public function start(callable $callback = null/*, array $env = array()*/)
258 { 266 {
259 if ($this->isRunning()) { 267 if ($this->isRunning()) {
260 throw new RuntimeException('Process is already running'); 268 throw new RuntimeException('Process is already running');
269 }
270 if (2 <= func_num_args()) {
271 $env = func_get_arg(1);
272 } else {
273 if (__CLASS__ !== static::class) {
274 $r = new \ReflectionMethod($this, __FUNCTION__);
275 if (__CLASS__ !== $r->getDeclaringClass()->getName() && (2 > $r->getNumberOfParameters() || 'env' !== $r->getParameters()[0]->name)) {
276 @trigger_error(sprintf('The %s::start() method expects a second "$env" argument since Symfony 3.3. It will be made mandatory in 4.0.', static::class), E_USER_DEPRECATED);
277 }
278 }
279 $env = null;
261 } 280 }
262 281
263 $this->resetProcessData(); 282 $this->resetProcessData();
264 $this->starttime = $this->lastOutputTime = microtime(true); 283 $this->starttime = $this->lastOutputTime = microtime(true);
265 $this->callback = $this->buildCallback($callback); 284 $this->callback = $this->buildCallback($callback);
266 $this->hasCallback = null !== $callback; 285 $this->hasCallback = null !== $callback;
267 $descriptors = $this->getDescriptors(); 286 $descriptors = $this->getDescriptors();
268 $inheritEnv = $this->inheritEnv; 287 $inheritEnv = $this->inheritEnv;
269 288
270 $commandline = $this->commandline; 289 if (is_array($commandline = $this->commandline)) {
271 290 $commandline = implode(' ', array_map(array($this, 'escapeArgument'), $commandline));
272 $env = $this->env; 291
273 $envBackup = array(); 292 if ('\\' !== DIRECTORY_SEPARATOR) {
293 // exec is mandatory to deal with sending a signal to the process
294 $commandline = 'exec '.$commandline;
295 }
296 }
297
298 if (null === $env) {
299 $env = $this->env;
300 } else {
301 if ($this->env) {
302 $env += $this->env;
303 }
304 $inheritEnv = true;
305 }
306
274 if (null !== $env && $inheritEnv) { 307 if (null !== $env && $inheritEnv) {
275 if ('\\' === DIRECTORY_SEPARATOR && !empty($this->options['bypass_shell']) && !$this->enhanceWindowsCompatibility) { 308 $env += $this->getDefaultEnv();
276 throw new LogicException('The "bypass_shell" option must be false to inherit environment variables while enhanced Windows compatibility is off'); 309 } elseif (null !== $env) {
277 } 310 @trigger_error('Not inheriting environment variables is deprecated since Symfony 3.3 and will always happen in 4.0. Set "Process::inheritEnvironmentVariables()" to true instead.', E_USER_DEPRECATED);
278 311 } else {
279 foreach ($env as $k => $v) { 312 $env = $this->getDefaultEnv();
280 $envBackup[$k] = getenv($k);
281 putenv(false === $v || null === $v ? $k : "$k=$v");
282 }
283 $env = null;
284 } 313 }
285 if ('\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) { 314 if ('\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
286 $commandline = 'cmd /V:ON /E:ON /D /C "('.$commandline.')'; 315 $this->options['bypass_shell'] = true;
287 foreach ($this->processPipes->getFiles() as $offset => $filename) { 316 $commandline = $this->prepareWindowsCommandLine($commandline, $env);
288 $commandline .= ' '.$offset.'>'.ProcessUtils::escapeArgument($filename);
289 }
290 $commandline .= '"';
291
292 if (!isset($this->options['bypass_shell'])) {
293 $this->options['bypass_shell'] = true;
294 }
295 } elseif (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { 317 } elseif (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
296 // last exit code is output on the fourth pipe and caught to work around --enable-sigchild 318 // last exit code is output on the fourth pipe and caught to work around --enable-sigchild
297 $descriptors[3] = array('pipe', 'w'); 319 $descriptors[3] = array('pipe', 'w');
298 320
299 // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input 321 // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
300 $commandline = '{ ('.$this->commandline.') <&3 3<&- 3>/dev/null & } 3<&0;'; 322 $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
301 $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code'; 323 $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
302 324
303 // Workaround for the bug, when PTS functionality is enabled. 325 // Workaround for the bug, when PTS functionality is enabled.
304 // @see : https://bugs.php.net/69442 326 // @see : https://bugs.php.net/69442
305 $ptsWorkaround = fopen(__FILE__, 'r'); 327 $ptsWorkaround = fopen(__FILE__, 'r');
306 } 328 }
307 329 if (defined('HHVM_VERSION')) {
308 $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $env, $this->options); 330 $envPairs = $env;
309 331 } else {
310 foreach ($envBackup as $k => $v) { 332 $envPairs = array();
311 putenv(false === $v ? $k : "$k=$v"); 333 foreach ($env as $k => $v) {
312 } 334 if (false !== $v) {
335 $envPairs[] = $k.'='.$v;
336 }
337 }
338 }
339
340 if (!is_dir($this->cwd)) {
341 @trigger_error('The provided cwd does not exist. Command is currently ran against getcwd(). This behavior is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
342 }
343
344 $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
313 345
314 if (!is_resource($this->process)) { 346 if (!is_resource($this->process)) {
315 throw new RuntimeException('Unable to launch a new process.'); 347 throw new RuntimeException('Unable to launch a new process.');
316 } 348 }
317 $this->status = self::STATUS_STARTED; 349 $this->status = self::STATUS_STARTED;
333 * 365 *
334 * Be warned that the process is cloned before being started. 366 * Be warned that the process is cloned before being started.
335 * 367 *
336 * @param callable|null $callback A PHP callback to run whenever there is some 368 * @param callable|null $callback A PHP callback to run whenever there is some
337 * output available on STDOUT or STDERR 369 * output available on STDOUT or STDERR
370 * @param array $env An array of additional env vars to set when running the process
338 * 371 *
339 * @return $this 372 * @return $this
340 * 373 *
341 * @throws RuntimeException When process can't be launched 374 * @throws RuntimeException When process can't be launched
342 * @throws RuntimeException When process is already running 375 * @throws RuntimeException When process is already running
343 * 376 *
344 * @see start() 377 * @see start()
345 */ 378 *
346 public function restart(callable $callback = null) 379 * @final since version 3.3
380 */
381 public function restart(callable $callback = null/*, array $env = array()*/)
347 { 382 {
348 if ($this->isRunning()) { 383 if ($this->isRunning()) {
349 throw new RuntimeException('Process is already running'); 384 throw new RuntimeException('Process is already running');
350 } 385 }
386 $env = 1 < func_num_args() ? func_get_arg(1) : null;
351 387
352 $process = clone $this; 388 $process = clone $this;
353 $process->start($callback); 389 $process->start($callback, $env);
354 390
355 return $process; 391 return $process;
356 } 392 }
357 393
358 /** 394 /**
796 * 832 *
797 * @return bool true if status is ready, false otherwise 833 * @return bool true if status is ready, false otherwise
798 */ 834 */
799 public function isStarted() 835 public function isStarted()
800 { 836 {
801 return $this->status != self::STATUS_READY; 837 return self::STATUS_READY != $this->status;
802 } 838 }
803 839
804 /** 840 /**
805 * Checks if the process is terminated. 841 * Checks if the process is terminated.
806 * 842 *
808 */ 844 */
809 public function isTerminated() 845 public function isTerminated()
810 { 846 {
811 $this->updateStatus(false); 847 $this->updateStatus(false);
812 848
813 return $this->status == self::STATUS_TERMINATED; 849 return self::STATUS_TERMINATED == $this->status;
814 } 850 }
815 851
816 /** 852 /**
817 * Gets the process status. 853 * Gets the process status.
818 * 854 *
901 * 937 *
902 * @return string The command to execute 938 * @return string The command to execute
903 */ 939 */
904 public function getCommandLine() 940 public function getCommandLine()
905 { 941 {
906 return $this->commandline; 942 return is_array($this->commandline) ? implode(' ', array_map(array($this, 'escapeArgument'), $this->commandline)) : $this->commandline;
907 } 943 }
908 944
909 /** 945 /**
910 * Sets the command line to be executed. 946 * Sets the command line to be executed.
911 * 947 *
912 * @param string $commandline The command to execute 948 * @param string|array $commandline The command to execute
913 * 949 *
914 * @return self The current Process instance 950 * @return self The current Process instance
915 */ 951 */
916 public function setCommandLine($commandline) 952 public function setCommandLine($commandline)
917 { 953 {
1087 } 1123 }
1088 1124
1089 /** 1125 /**
1090 * Sets the environment variables. 1126 * Sets the environment variables.
1091 * 1127 *
1092 * An environment variable value should be a string. 1128 * Each environment variable value should be a string.
1093 * If it is an array, the variable is ignored. 1129 * If it is an array, the variable is ignored.
1130 * If it is false or null, it will be removed when
1131 * env vars are otherwise inherited.
1094 * 1132 *
1095 * That happens in PHP when 'argv' is registered into 1133 * That happens in PHP when 'argv' is registered into
1096 * the $_ENV array for instance. 1134 * the $_ENV array for instance.
1097 * 1135 *
1098 * @param array $env The new environment variables 1136 * @param array $env The new environment variables
1124 /** 1162 /**
1125 * Sets the input. 1163 * Sets the input.
1126 * 1164 *
1127 * This content will be passed to the underlying process standard input. 1165 * This content will be passed to the underlying process standard input.
1128 * 1166 *
1129 * @param resource|scalar|\Traversable|null $input The content 1167 * @param string|int|float|bool|resource|\Traversable|null $input The content
1130 * 1168 *
1131 * @return self The current Process instance 1169 * @return self The current Process instance
1132 * 1170 *
1133 * @throws LogicException In case the process is running 1171 * @throws LogicException In case the process is running
1134 */ 1172 */
1145 1183
1146 /** 1184 /**
1147 * Gets the options for proc_open. 1185 * Gets the options for proc_open.
1148 * 1186 *
1149 * @return array The current options 1187 * @return array The current options
1188 *
1189 * @deprecated since version 3.3, to be removed in 4.0.
1150 */ 1190 */
1151 public function getOptions() 1191 public function getOptions()
1152 { 1192 {
1193 @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED);
1194
1153 return $this->options; 1195 return $this->options;
1154 } 1196 }
1155 1197
1156 /** 1198 /**
1157 * Sets the options for proc_open. 1199 * Sets the options for proc_open.
1158 * 1200 *
1159 * @param array $options The new options 1201 * @param array $options The new options
1160 * 1202 *
1161 * @return self The current Process instance 1203 * @return self The current Process instance
1204 *
1205 * @deprecated since version 3.3, to be removed in 4.0.
1162 */ 1206 */
1163 public function setOptions(array $options) 1207 public function setOptions(array $options)
1164 { 1208 {
1209 @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED);
1210
1165 $this->options = $options; 1211 $this->options = $options;
1166 1212
1167 return $this; 1213 return $this;
1168 } 1214 }
1169 1215
1171 * Gets whether or not Windows compatibility is enabled. 1217 * Gets whether or not Windows compatibility is enabled.
1172 * 1218 *
1173 * This is true by default. 1219 * This is true by default.
1174 * 1220 *
1175 * @return bool 1221 * @return bool
1222 *
1223 * @deprecated since version 3.3, to be removed in 4.0. Enhanced Windows compatibility will always be enabled.
1176 */ 1224 */
1177 public function getEnhanceWindowsCompatibility() 1225 public function getEnhanceWindowsCompatibility()
1178 { 1226 {
1227 @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Enhanced Windows compatibility will always be enabled.', __METHOD__), E_USER_DEPRECATED);
1228
1179 return $this->enhanceWindowsCompatibility; 1229 return $this->enhanceWindowsCompatibility;
1180 } 1230 }
1181 1231
1182 /** 1232 /**
1183 * Sets whether or not Windows compatibility is enabled. 1233 * Sets whether or not Windows compatibility is enabled.
1184 * 1234 *
1185 * @param bool $enhance 1235 * @param bool $enhance
1186 * 1236 *
1187 * @return self The current Process instance 1237 * @return self The current Process instance
1238 *
1239 * @deprecated since version 3.3, to be removed in 4.0. Enhanced Windows compatibility will always be enabled.
1188 */ 1240 */
1189 public function setEnhanceWindowsCompatibility($enhance) 1241 public function setEnhanceWindowsCompatibility($enhance)
1190 { 1242 {
1243 @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Enhanced Windows compatibility will always be enabled.', __METHOD__), E_USER_DEPRECATED);
1244
1191 $this->enhanceWindowsCompatibility = (bool) $enhance; 1245 $this->enhanceWindowsCompatibility = (bool) $enhance;
1192 1246
1193 return $this; 1247 return $this;
1194 } 1248 }
1195 1249
1196 /** 1250 /**
1197 * Returns whether sigchild compatibility mode is activated or not. 1251 * Returns whether sigchild compatibility mode is activated or not.
1198 * 1252 *
1199 * @return bool 1253 * @return bool
1254 *
1255 * @deprecated since version 3.3, to be removed in 4.0. Sigchild compatibility will always be enabled.
1200 */ 1256 */
1201 public function getEnhanceSigchildCompatibility() 1257 public function getEnhanceSigchildCompatibility()
1202 { 1258 {
1259 @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Sigchild compatibility will always be enabled.', __METHOD__), E_USER_DEPRECATED);
1260
1203 return $this->enhanceSigchildCompatibility; 1261 return $this->enhanceSigchildCompatibility;
1204 } 1262 }
1205 1263
1206 /** 1264 /**
1207 * Activates sigchild compatibility mode. 1265 * Activates sigchild compatibility mode.
1211 * the --enable-sigchild option 1269 * the --enable-sigchild option
1212 * 1270 *
1213 * @param bool $enhance 1271 * @param bool $enhance
1214 * 1272 *
1215 * @return self The current Process instance 1273 * @return self The current Process instance
1274 *
1275 * @deprecated since version 3.3, to be removed in 4.0.
1216 */ 1276 */
1217 public function setEnhanceSigchildCompatibility($enhance) 1277 public function setEnhanceSigchildCompatibility($enhance)
1218 { 1278 {
1279 @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Sigchild compatibility will always be enabled.', __METHOD__), E_USER_DEPRECATED);
1280
1219 $this->enhanceSigchildCompatibility = (bool) $enhance; 1281 $this->enhanceSigchildCompatibility = (bool) $enhance;
1220 1282
1221 return $this; 1283 return $this;
1222 } 1284 }
1223 1285
1228 * 1290 *
1229 * @return self The current Process instance 1291 * @return self The current Process instance
1230 */ 1292 */
1231 public function inheritEnvironmentVariables($inheritEnv = true) 1293 public function inheritEnvironmentVariables($inheritEnv = true)
1232 { 1294 {
1295 if (!$inheritEnv) {
1296 @trigger_error('Not inheriting environment variables is deprecated since Symfony 3.3 and will always happen in 4.0. Set "Process::inheritEnvironmentVariables()" to true instead.', E_USER_DEPRECATED);
1297 }
1298
1233 $this->inheritEnv = (bool) $inheritEnv; 1299 $this->inheritEnv = (bool) $inheritEnv;
1234 1300
1235 return $this; 1301 return $this;
1236 } 1302 }
1237 1303
1238 /** 1304 /**
1239 * Returns whether environment variables will be inherited or not. 1305 * Returns whether environment variables will be inherited or not.
1240 * 1306 *
1241 * @return bool 1307 * @return bool
1308 *
1309 * @deprecated since version 3.3, to be removed in 4.0. Environment variables will always be inherited.
1242 */ 1310 */
1243 public function areEnvironmentVariablesInherited() 1311 public function areEnvironmentVariablesInherited()
1244 { 1312 {
1313 @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Environment variables will always be inherited.', __METHOD__), E_USER_DEPRECATED);
1314
1245 return $this->inheritEnv; 1315 return $this->inheritEnv;
1246 } 1316 }
1247 1317
1248 /** 1318 /**
1249 * Performs a check between the timeout definition and the time the process started. 1319 * Performs a check between the timeout definition and the time the process started.
1253 * 1323 *
1254 * @throws ProcessTimedOutException In case the timeout was reached 1324 * @throws ProcessTimedOutException In case the timeout was reached
1255 */ 1325 */
1256 public function checkTimeout() 1326 public function checkTimeout()
1257 { 1327 {
1258 if ($this->status !== self::STATUS_STARTED) { 1328 if (self::STATUS_STARTED !== $this->status) {
1259 return; 1329 return;
1260 } 1330 }
1261 1331
1262 if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) { 1332 if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
1263 $this->stop(0); 1333 $this->stop(0);
1444 $result = $this->processPipes->readAndWrite($blocking, $close); 1514 $result = $this->processPipes->readAndWrite($blocking, $close);
1445 1515
1446 $callback = $this->callback; 1516 $callback = $this->callback;
1447 foreach ($result as $type => $data) { 1517 foreach ($result as $type => $data) {
1448 if (3 !== $type) { 1518 if (3 !== $type) {
1449 $callback($type === self::STDOUT ? self::OUT : self::ERR, $data); 1519 $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
1450 } elseif (!isset($this->fallbackStatus['signaled'])) { 1520 } elseif (!isset($this->fallbackStatus['signaled'])) {
1451 $this->fallbackStatus['exitcode'] = (int) $data; 1521 $this->fallbackStatus['exitcode'] = (int) $data;
1452 } 1522 }
1453 } 1523 }
1454 } 1524 }
1558 $this->fallbackStatus['termsig'] = $this->latestSignal; 1628 $this->fallbackStatus['termsig'] = $this->latestSignal;
1559 1629
1560 return true; 1630 return true;
1561 } 1631 }
1562 1632
1633 private function prepareWindowsCommandLine($cmd, array &$env)
1634 {
1635 $uid = uniqid('', true);
1636 $varCount = 0;
1637 $varCache = array();
1638 $cmd = preg_replace_callback(
1639 '/"(?:(
1640 [^"%!^]*+
1641 (?:
1642 (?: !LF! | "(?:\^[%!^])?+" )
1643 [^"%!^]*+
1644 )++
1645 ) | [^"]*+ )"/x',
1646 function ($m) use (&$env, &$varCache, &$varCount, $uid) {
1647 if (!isset($m[1])) {
1648 return $m[0];
1649 }
1650 if (isset($varCache[$m[0]])) {
1651 return $varCache[$m[0]];
1652 }
1653 if (false !== strpos($value = $m[1], "\0")) {
1654 $value = str_replace("\0", '?', $value);
1655 }
1656 if (false === strpbrk($value, "\"%!\n")) {
1657 return '"'.$value.'"';
1658 }
1659
1660 $value = str_replace(array('!LF!', '"^!"', '"^%"', '"^^"', '""'), array("\n", '!', '%', '^', '"'), $value);
1661 $value = '"'.preg_replace('/(\\\\*)"/', '$1$1\\"', $value).'"';
1662 $var = $uid.++$varCount;
1663
1664 $env[$var] = $value;
1665
1666 return $varCache[$m[0]] = '!'.$var.'!';
1667 },
1668 $cmd
1669 );
1670
1671 $cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
1672 foreach ($this->processPipes->getFiles() as $offset => $filename) {
1673 $cmd .= ' '.$offset.'>"'.$filename.'"';
1674 }
1675
1676 return $cmd;
1677 }
1678
1563 /** 1679 /**
1564 * Ensures the process is running or terminated, throws a LogicException if the process has a not started. 1680 * Ensures the process is running or terminated, throws a LogicException if the process has a not started.
1565 * 1681 *
1566 * @param string $functionName The function name that was called 1682 * @param string $functionName The function name that was called
1567 * 1683 *
1568 * @throws LogicException If the process has not run. 1684 * @throws LogicException if the process has not run
1569 */ 1685 */
1570 private function requireProcessIsStarted($functionName) 1686 private function requireProcessIsStarted($functionName)
1571 { 1687 {
1572 if (!$this->isStarted()) { 1688 if (!$this->isStarted()) {
1573 throw new LogicException(sprintf('Process must be started before calling %s.', $functionName)); 1689 throw new LogicException(sprintf('Process must be started before calling %s.', $functionName));
1577 /** 1693 /**
1578 * Ensures the process is terminated, throws a LogicException if the process has a status different than `terminated`. 1694 * Ensures the process is terminated, throws a LogicException if the process has a status different than `terminated`.
1579 * 1695 *
1580 * @param string $functionName The function name that was called 1696 * @param string $functionName The function name that was called
1581 * 1697 *
1582 * @throws LogicException If the process is not yet terminated. 1698 * @throws LogicException if the process is not yet terminated
1583 */ 1699 */
1584 private function requireProcessIsTerminated($functionName) 1700 private function requireProcessIsTerminated($functionName)
1585 { 1701 {
1586 if (!$this->isTerminated()) { 1702 if (!$this->isTerminated()) {
1587 throw new LogicException(sprintf('Process must be terminated before calling %s.', $functionName)); 1703 throw new LogicException(sprintf('Process must be terminated before calling %s.', $functionName));
1588 } 1704 }
1589 } 1705 }
1706
1707 /**
1708 * Escapes a string to be used as a shell argument.
1709 *
1710 * @param string $argument The argument that will be escaped
1711 *
1712 * @return string The escaped argument
1713 */
1714 private function escapeArgument($argument)
1715 {
1716 if ('\\' !== DIRECTORY_SEPARATOR) {
1717 return "'".str_replace("'", "'\\''", $argument)."'";
1718 }
1719 if ('' === $argument = (string) $argument) {
1720 return '""';
1721 }
1722 if (false !== strpos($argument, "\0")) {
1723 $argument = str_replace("\0", '?', $argument);
1724 }
1725 if (!preg_match('/[\/()%!^"<>&|\s]/', $argument)) {
1726 return $argument;
1727 }
1728 $argument = preg_replace('/(\\\\+)$/', '$1$1', $argument);
1729
1730 return '"'.str_replace(array('"', '^', '%', '!', "\n"), array('""', '"^^"', '"^%"', '"^!"', '!LF!'), $argument).'"';
1731 }
1732
1733 private function getDefaultEnv()
1734 {
1735 $env = array();
1736
1737 foreach ($_SERVER as $k => $v) {
1738 if (is_string($v) && false !== $v = getenv($k)) {
1739 $env[$k] = $v;
1740 }
1741 }
1742
1743 foreach ($_ENV as $k => $v) {
1744 if (is_string($v)) {
1745 $env[$k] = $v;
1746 }
1747 }
1748
1749 return $env;
1750 }
1590 } 1751 }