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