PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Jyxo/Shell/Client.php

http://github.com/jyxo/php
PHP | 271 lines | 114 code | 42 blank | 115 comment | 5 complexity | ea78a6d17f390b33a2fe02ffe39aab69 MD5 | raw file
  1. <?php declare(strict_types = 1);
  2. /**
  3. * Jyxo PHP Library
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file license.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * https://github.com/jyxo/php/blob/master/license.txt
  11. */
  12. namespace Jyxo\Shell;
  13. use function array_diff_key;
  14. use function array_fill_keys;
  15. use function array_key_exists;
  16. use function array_merge;
  17. use function explode;
  18. use function fclose;
  19. use function ini_get;
  20. use function is_resource;
  21. use function preg_replace;
  22. use function proc_close;
  23. use function proc_open;
  24. use function shell_exec;
  25. use function stream_get_contents;
  26. use function strlen;
  27. use function substr;
  28. /**
  29. * Class for executing external commands.
  30. *
  31. * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
  32. * @license https://github.com/jyxo/php/blob/master/license.txt
  33. * @author Ondřej Procházka
  34. * @author Matěj Humpál
  35. */
  36. class Client
  37. {
  38. /**
  39. * List of running processes.
  40. *
  41. * @var array
  42. */
  43. protected $processList;
  44. /**
  45. * Actual working directory.
  46. *
  47. * @var string
  48. */
  49. protected $cwd;
  50. /**
  51. * Environment properties.
  52. *
  53. * @var array
  54. */
  55. protected $env = [];
  56. /**
  57. * Stdout output.
  58. *
  59. * @var string
  60. */
  61. protected $out;
  62. /**
  63. * Stderr output.
  64. *
  65. * @var string
  66. */
  67. protected $error;
  68. /**
  69. * Constructor.
  70. *
  71. * @param string $cwd Working directory
  72. * @param array $env Array of environment properties
  73. */
  74. public function __construct(string $cwd = '', array $env = [])
  75. {
  76. $this->setCwd($cwd);
  77. $this->env = $_ENV;
  78. $this->setEnv($env);
  79. }
  80. /**
  81. * Returns a list of processes.
  82. *
  83. * Works only on Linux.
  84. *
  85. * @return Client
  86. */
  87. public function loadProcessList(): self
  88. {
  89. $output = shell_exec('ps aux');
  90. $data = explode("\n", $output);
  91. foreach ($data as $value) {
  92. $value = preg_replace('/ +/', ' ', $value);
  93. $list = explode(' ', $value);
  94. $commands[$list[10]][] = $list[1];
  95. }
  96. $this->processList = $commands;
  97. return $this;
  98. }
  99. /**
  100. * Checks if there is a process of the given name.
  101. *
  102. * Works only on Linux.
  103. *
  104. * @param string $name Process name
  105. * @return bool
  106. */
  107. public function processExists(string $name): bool
  108. {
  109. return array_key_exists($name, $this->processList);
  110. }
  111. /**
  112. * Kills all processes of the given name.
  113. *
  114. * Works only on Linux.
  115. *
  116. * @param string $name Process name
  117. * @return Client
  118. */
  119. public function killProcess(string $name): self
  120. {
  121. shell_exec('killall -s KILL ' . $name);
  122. return $this;
  123. }
  124. /**
  125. * Sets working directory.
  126. *
  127. * Defaults to null.
  128. *
  129. * @param string $cwd Working directory
  130. * @return Client
  131. */
  132. public function setCwd(string $cwd = ''): Client
  133. {
  134. $this->cwd = $cwd;
  135. return $this;
  136. }
  137. /**
  138. * Adds one or more environment properties.
  139. *
  140. * @param array $env Array of properties
  141. * @return Client
  142. */
  143. public function setEnv(array $env): Client
  144. {
  145. $this->env = array_merge($this->env, $env);
  146. return $this;
  147. }
  148. /**
  149. * Removes environment properties.
  150. *
  151. * @return Client
  152. */
  153. public function clearEnv(): Client
  154. {
  155. $this->env = $_ENV;
  156. return $this;
  157. }
  158. /**
  159. * Executes an external command.
  160. *
  161. * Captures stdout and stderr.
  162. * Throws an exception on status code != 0.
  163. *
  164. * @param string $cmd Command to execute
  165. * @param int $status Status code
  166. * @return Client
  167. */
  168. public function exec(string $cmd, ?int &$status = null): Client
  169. {
  170. static $descriptorSpec = [
  171. 0 => ['pipe', 'r'],
  172. 1 => ['pipe', 'w'],
  173. 2 => ['pipe', 'w'],
  174. ];
  175. $env = $this->env;
  176. if (ini_get('safe_mode')) {
  177. // If the safe_mode is set on, we have to check which properties we are allowed to set.
  178. $allowedPrefixes = explode(',', ini_get('safe_mode_allowed_env_vars'));
  179. $protectedVars = explode(',', ini_get('safe_mode_protected_env_vars'));
  180. // Throw away protected properties.
  181. $env = array_diff_key($env, array_fill_keys($protectedVars, true));
  182. // Throw away properties that do not have the allowed prefix.
  183. foreach ($env as $name => $value) {
  184. foreach ($allowedPrefixes as $prefix) {
  185. // Empty prefix - allow all properties.
  186. if ($prefix === '') {
  187. break 2;
  188. }
  189. if (substr($name, 0, strlen($prefix)) === $prefix) {
  190. continue 2;
  191. }
  192. }
  193. unset($env[$name]);
  194. }
  195. }
  196. $cmd = (string) $cmd;
  197. $process = proc_open($cmd, $descriptorSpec, $pipes, !empty($this->cwd) ? $this->cwd : null, !empty($env) ? $env : null);
  198. if (!is_resource($process)) {
  199. throw new Exception('Unable to start shell process.');
  200. }
  201. $this->out = stream_get_contents($pipes[1]);
  202. fclose($pipes[1]);
  203. $this->error = stream_get_contents($pipes[2]);
  204. fclose($pipes[2]);
  205. $status = proc_close($process);
  206. if ($status !== 0) {
  207. throw new Exception('Command ' . $cmd . ' returned code ' . $status . '. Output: ' . $this->error);
  208. }
  209. return $this;
  210. }
  211. /**
  212. * Returns stdout contents.
  213. *
  214. * @return string
  215. */
  216. public function getOut(): string
  217. {
  218. return $this->out;
  219. }
  220. /**
  221. * Returns stderr contents.
  222. *
  223. * @return string
  224. */
  225. public function getError(): string
  226. {
  227. return $this->error;
  228. }
  229. }