This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Created by PhpStorm. |
||
4 | * User: Jenner |
||
5 | * Date: 2015/8/12 |
||
6 | * Time: 15:25 |
||
7 | */ |
||
8 | |||
9 | namespace Jenner\SimpleFork; |
||
10 | |||
11 | class Process |
||
12 | { |
||
13 | /** |
||
14 | * @var Runnable|callable |
||
15 | */ |
||
16 | protected $runnable; |
||
17 | |||
18 | /** |
||
19 | * @var int |
||
20 | */ |
||
21 | protected $pid = 0; |
||
22 | |||
23 | /** |
||
24 | * @var string custom process name |
||
25 | */ |
||
26 | protected $name = null; |
||
27 | |||
28 | /** |
||
29 | * @var bool if the process is started |
||
30 | */ |
||
31 | protected $started = false; |
||
32 | |||
33 | /** |
||
34 | * @var bool |
||
35 | */ |
||
36 | protected $running = false; |
||
37 | |||
38 | /** |
||
39 | * @var int the signal which made the process terminate |
||
40 | */ |
||
41 | protected $term_signal = null; |
||
42 | |||
43 | /** |
||
44 | * @var int the signal which made the process stop |
||
45 | */ |
||
46 | protected $stop_signal = null; |
||
47 | |||
48 | /** |
||
49 | * @var int error code |
||
50 | */ |
||
51 | protected $errno = null; |
||
52 | |||
53 | /** |
||
54 | * @var string error message |
||
55 | */ |
||
56 | protected $errmsg = null; |
||
57 | |||
58 | /** |
||
59 | * @var bool |
||
60 | */ |
||
61 | protected $if_signal = false; |
||
62 | |||
63 | /** |
||
64 | * @var array |
||
65 | */ |
||
66 | protected $callbacks = array(); |
||
67 | |||
68 | /** |
||
69 | * @var array signal handlers |
||
70 | */ |
||
71 | protected $signal_handlers = array(); |
||
72 | |||
73 | |||
74 | /** |
||
75 | * @param string $execution it can be a Runnable object, callback function or null |
||
76 | * @param null $name process name,you can manager the process by it's name. |
||
77 | */ |
||
78 | 60 | public function __construct($execution = null, $name = null) |
|
79 | { |
||
80 | 60 | if (!is_null($execution) && $execution instanceof Runnable) { |
|
81 | 9 | $this->runnable = $execution; |
|
82 | 60 | } elseif (!is_null($execution) && is_callable($execution)) { |
|
83 | 45 | $this->runnable = $execution; |
|
84 | 54 | } elseif (!is_null($execution)) { |
|
85 | throw new \InvalidArgumentException('param execution is not a object of Runnable or callable'); |
||
86 | } else { |
||
87 | 12 | Utils::checkOverwriteRunMethod(get_class($this)); |
|
88 | } |
||
89 | 57 | if (!is_null($name)) { |
|
90 | 3 | $this->name = $name; |
|
91 | 3 | } |
|
92 | |||
93 | 57 | $this->initStatus(); |
|
94 | 57 | } |
|
95 | |||
96 | /** |
||
97 | * init process status |
||
98 | */ |
||
99 | 57 | protected function initStatus() |
|
100 | { |
||
101 | 57 | $this->pid = null; |
|
102 | 57 | $this->running = null; |
|
103 | 57 | $this->term_signal = null; |
|
104 | 57 | $this->stop_signal = null; |
|
105 | 57 | $this->errno = null; |
|
106 | 57 | $this->errmsg = null; |
|
107 | 57 | } |
|
108 | |||
109 | /** |
||
110 | * get pid |
||
111 | * |
||
112 | * @return int |
||
113 | */ |
||
114 | 9 | public function getPid() |
|
115 | { |
||
116 | 9 | return $this->pid; |
|
117 | } |
||
118 | |||
119 | /** |
||
120 | * get or set name |
||
121 | * |
||
122 | * @param string|null $name |
||
123 | * @return mixed |
||
124 | */ |
||
125 | 3 | public function name($name = null) |
|
126 | { |
||
127 | 3 | if (!is_null($name)) { |
|
128 | $this->name = $name; |
||
129 | } else { |
||
130 | 3 | return $this->name; |
|
131 | } |
||
132 | } |
||
133 | |||
134 | /** |
||
135 | * if the process is stopped |
||
136 | * |
||
137 | * @return bool |
||
138 | */ |
||
139 | 3 | public function isStopped() |
|
140 | { |
||
141 | 3 | if (is_null($this->errno)) { |
|
142 | 3 | return false; |
|
143 | } |
||
144 | |||
145 | 3 | return true; |
|
146 | } |
||
147 | |||
148 | /** |
||
149 | * if the process is started |
||
150 | * |
||
151 | * @return bool |
||
152 | */ |
||
153 | 15 | public function isStarted() |
|
154 | { |
||
155 | 15 | return $this->started; |
|
156 | } |
||
157 | |||
158 | /** |
||
159 | * get pcntl errno |
||
160 | * |
||
161 | * @return int |
||
162 | */ |
||
163 | 9 | public function errno() |
|
164 | { |
||
165 | 9 | return $this->errno; |
|
166 | } |
||
167 | |||
168 | /** |
||
169 | * get pcntl errmsg |
||
170 | * |
||
171 | * @return string |
||
172 | */ |
||
173 | 6 | public function errmsg() |
|
174 | { |
||
175 | 6 | return $this->errmsg; |
|
176 | } |
||
177 | |||
178 | 3 | public function ifSignal() |
|
179 | { |
||
180 | 3 | return $this->if_signal; |
|
181 | } |
||
182 | |||
183 | /** |
||
184 | * start the sub process |
||
185 | * and run the callback |
||
186 | * |
||
187 | * @return string pid |
||
188 | */ |
||
189 | 54 | public function start() |
|
190 | { |
||
191 | 54 | if (!empty($this->pid) && $this->isRunning()) { |
|
192 | throw new \LogicException("the process is already running"); |
||
193 | } |
||
194 | |||
195 | 54 | $callback = $this->getCallable(); |
|
196 | |||
197 | 54 | $pid = pcntl_fork(); |
|
198 | 54 | if ($pid < 0) { |
|
199 | throw new \RuntimeException("fork error"); |
||
200 | 54 | } elseif ($pid > 0) { |
|
201 | 54 | $this->pid = $pid; |
|
202 | 54 | $this->running = true; |
|
203 | 54 | $this->started = true; |
|
204 | 54 | } else { |
|
205 | $this->pid = getmypid(); |
||
206 | $this->signal(); |
||
207 | foreach ($this->signal_handlers as $signal => $handler) { |
||
208 | pcntl_signal($signal, $handler); |
||
209 | } |
||
210 | call_user_func($callback); |
||
211 | exit(0); |
||
0 ignored issues
–
show
|
|||
212 | } |
||
213 | 54 | } |
|
214 | |||
215 | /** |
||
216 | * if the process is running |
||
217 | * |
||
218 | * @return bool |
||
219 | */ |
||
220 | 54 | public function isRunning() |
|
221 | { |
||
222 | 54 | $this->updateStatus(); |
|
223 | 54 | return $this->running; |
|
224 | } |
||
225 | |||
226 | /** |
||
227 | * update the process status |
||
228 | * |
||
229 | * @param bool $block |
||
230 | */ |
||
231 | 54 | protected function updateStatus($block = false) |
|
232 | { |
||
233 | 54 | if ($this->running !== true) { |
|
234 | 24 | return; |
|
235 | } |
||
236 | |||
237 | 54 | if ($block) { |
|
238 | 12 | $res = pcntl_waitpid($this->pid, $status); |
|
0 ignored issues
–
show
|
|||
239 | 12 | } else { |
|
240 | 54 | $res = pcntl_waitpid($this->pid, $status, WNOHANG | WUNTRACED); |
|
241 | } |
||
242 | |||
243 | 54 | if ($res === -1) { |
|
244 | throw new \RuntimeException('pcntl_waitpid failed. the process maybe available'); |
||
245 | 54 | } elseif ($res === 0) { |
|
246 | 54 | $this->running = true; |
|
247 | 54 | } else { |
|
248 | 51 | if (pcntl_wifsignaled($status)) { |
|
249 | 6 | $this->term_signal = pcntl_wtermsig($status); |
|
250 | 6 | } |
|
251 | 51 | if (pcntl_wifstopped($status)) { |
|
252 | $this->stop_signal = pcntl_wstopsig($status); |
||
253 | } |
||
254 | 51 | if (pcntl_wifexited($status)) { |
|
255 | 45 | $this->errno = pcntl_wexitstatus($status); |
|
256 | 45 | $this->errmsg = pcntl_strerror($this->errno); |
|
257 | 45 | } else { |
|
258 | 6 | $this->errno = pcntl_get_last_error(); |
|
259 | 6 | $this->errmsg = pcntl_strerror($this->errno); |
|
260 | } |
||
261 | 51 | if (pcntl_wifsignaled($status)) { |
|
262 | 6 | $this->if_signal = true; |
|
263 | 6 | } else { |
|
264 | 45 | $this->if_signal = false; |
|
265 | } |
||
266 | |||
267 | 51 | $this->running = false; |
|
268 | } |
||
269 | 54 | } |
|
270 | |||
271 | /** |
||
272 | * get sub process callback |
||
273 | * |
||
274 | * @return array|callable|null |
||
275 | */ |
||
276 | 54 | protected function getCallable() |
|
277 | { |
||
278 | 54 | $callback = null; |
|
0 ignored issues
–
show
$callback is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
279 | 54 | if (is_object($this->runnable) && $this->runnable instanceof Runnable) { |
|
280 | 9 | $callback = array($this->runnable, 'run'); |
|
281 | 54 | } elseif (is_callable($this->runnable)) { |
|
282 | 45 | $callback = $this->runnable; |
|
283 | 45 | } else { |
|
284 | 6 | $callback = array($this, 'run'); |
|
285 | } |
||
286 | |||
287 | 54 | return $callback; |
|
288 | } |
||
289 | |||
290 | /** |
||
291 | * register signal SIGTERM handler, |
||
292 | * when the parent process call shutdown and use the default signal, |
||
293 | * this handler will be triggered |
||
294 | */ |
||
295 | protected function signal() |
||
296 | { |
||
297 | pcntl_signal(SIGTERM, function () { |
||
298 | exit(0); |
||
0 ignored issues
–
show
The method
signal() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
299 | }); |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * kill self |
||
304 | * |
||
305 | * @param bool|true $block |
||
306 | * @param int $signal |
||
307 | */ |
||
308 | 12 | public function shutdown($block = true, $signal = SIGTERM) |
|
309 | { |
||
310 | 12 | if (empty($this->pid)) { |
|
311 | throw new \LogicException('the process pid is null, so maybe the process is not started'); |
||
312 | } |
||
313 | 12 | if (!$this->isRunning()) { |
|
314 | throw new \LogicException("the process is not running"); |
||
315 | } |
||
316 | 12 | if (!posix_kill($this->pid, $signal)) { |
|
317 | throw new \RuntimeException("kill son process failed"); |
||
318 | } |
||
319 | |||
320 | 12 | $this->updateStatus($block); |
|
321 | 12 | } |
|
322 | |||
323 | /** |
||
324 | * waiting for the sub process exit |
||
325 | * |
||
326 | * @param bool|true $block if block the process |
||
327 | * @param int $sleep default 0.1s check sub process status |
||
328 | * every $sleep milliseconds. |
||
329 | */ |
||
330 | 33 | public function wait($block = true, $sleep = 100000) |
|
331 | { |
||
332 | 33 | while (true) { |
|
333 | 33 | if ($this->isRunning() === false) { |
|
334 | 33 | return; |
|
335 | } |
||
336 | 30 | if (!$block) { |
|
337 | break; |
||
338 | } |
||
339 | 30 | usleep($sleep); |
|
340 | 30 | } |
|
341 | } |
||
342 | |||
343 | /** |
||
344 | * register sub process signal handler, |
||
345 | * when the sub process start, the handlers will be registered |
||
346 | * |
||
347 | * @param $signal |
||
348 | * @param callable $handler |
||
349 | */ |
||
350 | public function registerSignalHandler($signal, callable $handler) |
||
351 | { |
||
352 | $this->signal_handlers[$signal] = $handler; |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * after php-5.3.0, we can call pcntl_singal_dispatch to call signal handlers for pending signals |
||
357 | * which can save cpu resources than using declare(tick=n) |
||
358 | * |
||
359 | * @return bool |
||
360 | */ |
||
361 | public function dispatchSignal() |
||
362 | { |
||
363 | return pcntl_signal_dispatch(); |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * you should overwrite this function |
||
368 | * if you do not use the Runnable or callback. |
||
369 | */ |
||
370 | public function run() |
||
371 | { |
||
372 | } |
||
373 | } |
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exit
expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.