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 | namespace PHPDaemon\Thread; |
||
3 | |||
4 | use PHPDaemon\Cache\CappedStorageHits; |
||
5 | use PHPDaemon\Core\AppInstance; |
||
6 | use PHPDaemon\Core\Daemon; |
||
7 | use PHPDaemon\Core\Debug; |
||
8 | use PHPDaemon\Core\EventLoop; |
||
9 | use PHPDaemon\Core\Timer; |
||
10 | use PHPDaemon\FS\FileSystem; |
||
11 | |||
12 | /** |
||
13 | * Implementation of the worker thread |
||
14 | * |
||
15 | * @package Core |
||
16 | * |
||
17 | * @author Vasily Zorin <[email protected]> |
||
18 | */ |
||
19 | class Worker extends Generic |
||
20 | { |
||
21 | |||
22 | /** |
||
23 | * Update? |
||
24 | * @var boolean |
||
25 | */ |
||
26 | public $update = false; |
||
27 | |||
28 | /** |
||
29 | * Reload? |
||
30 | * @var boolean |
||
31 | */ |
||
32 | public $reload = false; |
||
33 | |||
34 | protected $graceful = false; |
||
35 | |||
36 | /** |
||
37 | * Reload delay |
||
38 | * @var integer |
||
39 | */ |
||
40 | protected $reloadDelay = 2; |
||
41 | |||
42 | /** |
||
43 | * Reloaded? |
||
44 | * @var boolean |
||
45 | */ |
||
46 | public $reloaded = false; |
||
47 | |||
48 | /** |
||
49 | * Time of last activity |
||
50 | * @var integer |
||
51 | */ |
||
52 | public $timeLastActivity = 0; |
||
53 | |||
54 | /** |
||
55 | * Last time of auto reload |
||
56 | * @var integer |
||
57 | */ |
||
58 | protected $autoReloadLast = 0; |
||
59 | |||
60 | /** |
||
61 | * State |
||
62 | * @var integer |
||
63 | */ |
||
64 | public $state = 0; |
||
65 | |||
66 | /** |
||
67 | * Request counter |
||
68 | * @var integer |
||
69 | */ |
||
70 | public $reqCounter = 0; |
||
71 | |||
72 | /** |
||
73 | * Break main loop? |
||
74 | * @var boolean |
||
75 | */ |
||
76 | public $breakMainLoop = false; |
||
77 | |||
78 | /** |
||
79 | * Reload ready? |
||
80 | * @var boolean |
||
81 | */ |
||
82 | public $reloadReady = false; |
||
83 | |||
84 | /** |
||
85 | * If true, we do not register signals automatically at start |
||
86 | * @var boolean |
||
87 | */ |
||
88 | protected $delayedSigReg = false; |
||
89 | |||
90 | /** |
||
91 | * Instances count |
||
92 | * @var array |
||
93 | */ |
||
94 | public $instancesCount = []; |
||
95 | |||
96 | /** |
||
97 | * Connection |
||
98 | * @var Connection |
||
99 | */ |
||
100 | public $connection; |
||
101 | |||
102 | /** |
||
103 | * Counter GC |
||
104 | * @var integer |
||
105 | */ |
||
106 | public $counterGC = 0; |
||
107 | |||
108 | |||
109 | /** @var \PHPDaemon\IPCManager\IPCManager */ |
||
110 | public $IPCManager; |
||
111 | |||
112 | public $lambdaCache; |
||
113 | |||
114 | /** |
||
115 | * Runtime of Worker process. |
||
116 | * @return void |
||
117 | */ |
||
118 | protected function run() |
||
119 | { |
||
120 | $this->lambdaCache = new CappedStorageHits; |
||
121 | $this->lambdaCache->setMaxCacheSize(Daemon::$config->lambdacachemaxsize->value); |
||
122 | $this->lambdaCache->setCapWindow(Daemon::$config->lambdacachecapwindow->value); |
||
123 | |||
124 | if (Daemon::$process instanceof Master) { |
||
125 | Daemon::$process->unregisterSignals(); |
||
0 ignored issues
–
show
|
|||
126 | } |
||
127 | |||
128 | EventLoop::init(); |
||
129 | |||
130 | Daemon::$process = $this; |
||
131 | if (Daemon::$logpointerAsync) { |
||
132 | Daemon::$logpointerAsync->fd = null; |
||
133 | Daemon::$logpointerAsync = null; |
||
134 | } |
||
135 | class_exists('Timer'); |
||
136 | $this->autoReloadLast = time(); |
||
137 | $this->reloadDelay = Daemon::$config->mpmdelay->value + 2; |
||
138 | $this->setState(Daemon::WSTATE_PREINIT); |
||
139 | |||
140 | if (Daemon::$config->autogc->value > 0) { |
||
141 | gc_enable(); |
||
142 | gc_collect_cycles(); |
||
143 | } else { |
||
144 | gc_disable(); |
||
145 | } |
||
146 | |||
147 | if (Daemon::$runworkerMode) { |
||
148 | View Code Duplication | if (!Daemon::$config->verbosetty->value) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
149 | fclose(STDIN); |
||
150 | fclose(STDOUT); |
||
151 | fclose(STDERR); |
||
152 | } |
||
153 | |||
154 | Daemon::$appResolver->preload(true); |
||
155 | } |
||
156 | |||
157 | $this->prepareSystemEnv(); |
||
158 | $this->overrideNativeFuncs(); |
||
159 | |||
160 | $this->setState(Daemon::WSTATE_INIT); |
||
161 | $this->registerEventSignals(); |
||
162 | |||
163 | FileSystem::init(); |
||
164 | FileSystem::initEvent(); |
||
165 | Daemon::openLogs(); |
||
166 | |||
167 | $this->IPCManager = Daemon::$appResolver->getInstanceByAppName('\PHPDaemon\IPCManager\IPCManager'); |
||
168 | if (!$this->IPCManager) { |
||
169 | $this->log('cannot instantiate IPCManager'); |
||
170 | } |
||
171 | |||
172 | Daemon::$appResolver->preload(); |
||
173 | |||
174 | foreach (Daemon::$appInstances as $app) { |
||
175 | foreach ($app as $appInstance) { |
||
176 | if (!$appInstance->ready) { |
||
177 | $appInstance->ready = true; |
||
178 | $appInstance->onReady(); |
||
179 | } |
||
180 | } |
||
181 | } |
||
182 | |||
183 | $this->setState(Daemon::WSTATE_IDLE); |
||
184 | |||
185 | Timer::add(function ($event) { |
||
186 | |||
187 | if (!Daemon::$runworkerMode) { |
||
188 | if ($this->IPCManager) { |
||
189 | $this->IPCManager->ensureConnection(); |
||
190 | } |
||
191 | } |
||
192 | |||
193 | $this->breakMainLoopCheck(); |
||
194 | if (Daemon::checkAutoGC()) { |
||
195 | EventLoop::$instance->interrupt(function () { |
||
196 | gc_collect_cycles(); |
||
197 | }); |
||
198 | } |
||
199 | |||
200 | $event->timeout(); |
||
201 | }, 1e6 * 1, 'breakMainLoopCheck'); |
||
202 | if (Daemon::$config->autoreload->value > 0) { |
||
203 | Timer::add(function ($event) { |
||
204 | static $n = 0; |
||
205 | $list = get_included_files(); |
||
206 | $s = sizeof($list); |
||
207 | if ($s > $n) { |
||
208 | $slice = array_map('realpath', array_slice($list, $n)); |
||
209 | Daemon::$process->IPCManager->sendPacket(['op' => 'addIncludedFiles', 'files' => $slice]); |
||
210 | $n = $s; |
||
211 | } |
||
212 | $event->timeout(); |
||
213 | }, 1e6 * Daemon::$config->autoreload->value, 'watchIncludedFiles'); |
||
214 | } |
||
215 | EventLoop::$instance->run(); |
||
216 | $this->shutdown(); |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Override a standard PHP function |
||
221 | * @param string $local e.g. isUploadedFile |
||
0 ignored issues
–
show
There is no parameter named
$local . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
222 | * @param string $real e.g. is_uploaded_file |
||
223 | */ |
||
224 | protected function override($camelCase, $real) |
||
225 | { |
||
226 | runkit_function_rename($real, $real . '_native'); |
||
227 | runkit_function_rename('PHPDaemon\\Thread\\' . $camelCase, $real); |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * Overrides native PHP functions. |
||
232 | * @return void |
||
233 | */ |
||
234 | protected function overrideNativeFuncs() |
||
235 | { |
||
236 | if (Daemon::supported(Daemon::SUPPORT_RUNKIT_INTERNAL_MODIFY)) { |
||
237 | function define($k, $v) |
||
238 | { |
||
239 | if (defined($k)) { |
||
240 | runkit_constant_redefine($k, $v); |
||
241 | } else { |
||
242 | runkit_constant_add($k, $v); |
||
243 | } |
||
244 | } |
||
245 | |||
246 | $this->override('define', 'define'); |
||
247 | |||
248 | function header(...$args) |
||
0 ignored issues
–
show
|
|||
249 | { |
||
250 | if (!Daemon::$context instanceof \PHPDaemon\Request\Generic) { |
||
251 | return false; |
||
252 | } |
||
253 | return Daemon::$context->header(...$args); |
||
0 ignored issues
–
show
The method
header does not exist on object<PHPDaemon\Request\Generic> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
254 | } |
||
255 | |||
256 | $this->override('header', 'header'); |
||
257 | |||
258 | function isUploadedFile(...$args) |
||
0 ignored issues
–
show
|
|||
259 | { |
||
260 | if (!Daemon::$context instanceof \PHPDaemon\Request\Generic) { |
||
261 | return false; |
||
262 | } |
||
263 | return Daemon::$context->isUploadedFile(...$args); |
||
0 ignored issues
–
show
The method
isUploadedFile does not exist on object<PHPDaemon\Request\Generic> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
264 | } |
||
265 | |||
266 | $this->override('isUploadedFile', 'is_uploaded_file'); |
||
267 | |||
268 | function moveUploadedFile(...$args) |
||
0 ignored issues
–
show
|
|||
269 | { |
||
270 | if (!Daemon::$context instanceof \PHPDaemon\Request\Generic) { |
||
271 | return false; |
||
272 | } |
||
273 | return Daemon::$context->moveUploadedFile(...$args); |
||
0 ignored issues
–
show
The method
moveUploadedFile does not exist on object<PHPDaemon\Request\Generic> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
274 | } |
||
275 | |||
276 | $this->override('moveUploadedFile', 'move_uploaded_file'); |
||
277 | |||
278 | function headersSent(&$file = null, &$line = null) |
||
0 ignored issues
–
show
|
|||
279 | { |
||
280 | if (!Daemon::$context instanceof \PHPDaemon\Request\Generic) { |
||
281 | return false; |
||
282 | } |
||
283 | return Daemon::$context->headers_sent($file, $line); |
||
0 ignored issues
–
show
The method
headers_sent does not exist on object<PHPDaemon\Request\Generic> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
284 | } |
||
285 | |||
286 | //$this->override('headersSent', 'headers_sent); // Commented out due to a runkit bug |
||
287 | |||
288 | function headersList() |
||
0 ignored issues
–
show
|
|||
289 | { |
||
290 | if (!Daemon::$context instanceof \PHPDaemon\Request\Generic) { |
||
291 | return false; |
||
292 | } |
||
293 | return Daemon::$context->headers_list(); |
||
0 ignored issues
–
show
The method
headers_list does not exist on object<PHPDaemon\Request\Generic> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
294 | } |
||
295 | |||
296 | $this->override('headersList', 'headers_list'); |
||
297 | |||
298 | function setcookie(...$args) |
||
0 ignored issues
–
show
|
|||
299 | { |
||
300 | if (!Daemon::$context instanceof \PHPDaemon\Request\Generic) { |
||
301 | return false; |
||
302 | } |
||
303 | return Daemon::$context->setcookie(...$args); |
||
0 ignored issues
–
show
The method
setcookie does not exist on object<PHPDaemon\Request\Generic> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
304 | } |
||
305 | |||
306 | $this->override('setcookie', 'setcookie'); |
||
307 | |||
308 | /** |
||
309 | * @param callable $cb |
||
310 | */ |
||
311 | function registerShutdownFunction($cb) |
||
0 ignored issues
–
show
|
|||
312 | { |
||
313 | if (!Daemon::$context instanceof \PHPDaemon\Request\Generic) { |
||
314 | return false; |
||
315 | } |
||
316 | return Daemon::$context->registerShutdownFunction($cb); |
||
317 | } |
||
318 | |||
319 | $this->override('registerShutdownFunction', 'register_shutdown_function'); |
||
320 | |||
321 | runkit_function_copy('create_function', 'create_function_native'); |
||
322 | runkit_function_redefine('create_function', '$arg,$body', |
||
323 | 'return \PHPDaemon\Core\Daemon::$process->createFunction($arg,$body);'); |
||
324 | } |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * Creates anonymous function (old-fashioned) like create_function() |
||
329 | * @return void |
||
330 | */ |
||
331 | public function createFunction($args, $body, $ttl = null) |
||
332 | { |
||
333 | $key = $args . "\x00" . $body; |
||
334 | if (($f = $this->lambdaCache->getValue($key)) !== null) { |
||
335 | return $f; |
||
336 | } |
||
337 | $f = eval('return function(' . $args . '){' . $body . '};'); |
||
338 | if ($ttl === null && Daemon::$config->lambdacachettl->value) { |
||
339 | $ttl = Daemon::$config->lambdacachettl->value; |
||
340 | } |
||
341 | $this->lambdaCache->put($key, $f, $ttl); |
||
342 | return $f; |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Setup settings on start. |
||
347 | * @return void |
||
348 | */ |
||
349 | protected function prepareSystemEnv() |
||
350 | { |
||
351 | proc_nice(Daemon::$config->workerpriority->value); |
||
352 | |||
353 | register_shutdown_function(function () { |
||
354 | $this->shutdown(true); |
||
355 | }); |
||
356 | |||
357 | $this->setTitle( |
||
358 | Daemon::$runName . ': worker process' |
||
359 | . (Daemon::$config->pidfile->value !== Daemon::$config->defaultpidfile->value |
||
360 | ? ' (' . Daemon::$config->pidfile->value . ')' : '') |
||
361 | ); |
||
362 | |||
363 | |||
364 | if (isset(Daemon::$config->group->value)) { |
||
365 | $sg = posix_getgrnam(Daemon::$config->group->value); |
||
366 | } |
||
367 | |||
368 | if (isset(Daemon::$config->user->value)) { |
||
369 | $su = posix_getpwnam(Daemon::$config->user->value); |
||
370 | } |
||
371 | |||
372 | $flushCache = false; |
||
373 | if (Daemon::$config->chroot->value !== '/') { |
||
374 | View Code Duplication | if (posix_getuid() != 0) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
375 | Daemon::log('You must have the root privileges to change root.'); |
||
376 | exit(0); |
||
377 | } elseif (!chroot(Daemon::$config->chroot->value)) { |
||
378 | Daemon::log('Couldn\'t change root to \'' . Daemon::$config->chroot->value . '\'.'); |
||
379 | exit(0); |
||
380 | } |
||
381 | $flushCache = true; |
||
382 | } |
||
383 | |||
384 | if (isset(Daemon::$config->group->value)) { |
||
385 | if ($sg === false) { |
||
386 | Daemon::log('Couldn\'t change group to \'' . Daemon::$config->group->value . '\'. You must replace config-variable \'group\' with existing group.'); |
||
387 | exit(0); |
||
388 | } elseif (($sg['gid'] != posix_getgid()) && (!posix_setgid($sg['gid']))) { |
||
0 ignored issues
–
show
The variable
$sg does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
389 | Daemon::log('Couldn\'t change group to \'' . Daemon::$config->group->value . "'. Error (" . ($errno = posix_get_last_error()) . '): ' . posix_strerror($errno)); |
||
390 | exit(0); |
||
391 | } |
||
392 | $flushCache = true; |
||
393 | } |
||
394 | |||
395 | if (isset(Daemon::$config->user->value)) { |
||
396 | if ($su === false) { |
||
397 | Daemon::log('Couldn\'t change user to \'' . Daemon::$config->user->value . '\', user not found. You must replace config-variable \'user\' with existing username.'); |
||
398 | exit(0); |
||
399 | } else { |
||
400 | posix_initgroups($su['name'], $su['gid']); |
||
0 ignored issues
–
show
The variable
$su does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
401 | if ($su['uid'] != posix_getuid() && !posix_setuid($su['uid'])) { |
||
402 | Daemon::log('Couldn\'t change user to \'' . Daemon::$config->user->value . "'. Error (" . ($errno = posix_get_last_error()) . '): ' . posix_strerror($errno)); |
||
403 | exit(0); |
||
404 | } |
||
405 | } |
||
406 | $flushCache = true; |
||
407 | } |
||
408 | if ($flushCache) { |
||
409 | clearstatcache(true); |
||
410 | } |
||
411 | if (Daemon::$config->cwd->value !== '.') { |
||
412 | View Code Duplication | if (!@chdir(Daemon::$config->cwd->value)) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
413 | Daemon::log('Couldn\'t change directory to \'' . Daemon::$config->cwd->value . '.'); |
||
414 | } |
||
415 | clearstatcache(true); |
||
416 | } |
||
417 | } |
||
418 | |||
419 | /** |
||
420 | * Log something |
||
421 | * @param string - Message. |
||
422 | * @param string $message |
||
423 | * @return void |
||
424 | */ |
||
425 | public function log($message) |
||
426 | { |
||
427 | Daemon::log('W#' . $this->pid . ' ' . $message); |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * Reloads additional config-files on-the-fly. |
||
432 | * @return void |
||
433 | */ |
||
434 | protected function update() |
||
435 | { |
||
436 | FileSystem::updateConfig(); |
||
437 | foreach (Daemon::$appInstances as $app) { |
||
438 | foreach ($app as $appInstance) { |
||
439 | $appInstance->handleStatus(AppInstance::EVENT_CONFIG_UPDATED); |
||
440 | } |
||
441 | } |
||
442 | } |
||
443 | |||
444 | /** |
||
445 | * Check if we should break main loop |
||
446 | * @return void |
||
447 | */ |
||
448 | protected function breakMainLoopCheck() |
||
449 | { |
||
450 | $time = microtime(true); |
||
451 | |||
452 | if ($this->terminated || $this->breakMainLoop) { |
||
453 | EventLoop::$instance->stop(); |
||
454 | return; |
||
455 | } |
||
456 | |||
457 | if ($this->shutdown) { |
||
458 | EventLoop::$instance->stop(); |
||
459 | return; |
||
460 | } |
||
461 | |||
462 | if ($this->reload) { |
||
463 | return; |
||
464 | } |
||
465 | |||
466 | if (Daemon::$config->maxmemoryusage->value > 0 |
||
467 | && (memory_get_usage(true) > Daemon::$config->maxmemoryusage->value) |
||
468 | ) { |
||
469 | $this->log('\'maxmemory\' exceed. Graceful shutdown.'); |
||
470 | |||
471 | $this->gracefulRestart(); |
||
472 | } |
||
473 | |||
474 | if (Daemon::$config->maxrequests->value > 0 |
||
475 | && ($this->reqCounter >= Daemon::$config->maxrequests->value) |
||
476 | ) { |
||
477 | $this->log('\'max-requests\' exceed. Graceful shutdown.'); |
||
478 | |||
479 | $this->gracefulRestart(); |
||
480 | } |
||
481 | |||
482 | if (Daemon::$config->maxidle->value |
||
483 | && $this->timeLastActivity && ($time - $this->timeLastActivity > Daemon::$config->maxidle->value) |
||
484 | ) { |
||
485 | $this->log('\'maxworkeridle\' exceed. Graceful shutdown.'); |
||
486 | |||
487 | $this->gracefulRestart(); |
||
488 | } |
||
489 | |||
490 | if ($this->update === true) { |
||
491 | $this->update = false; |
||
492 | $this->update(); |
||
493 | } |
||
494 | } |
||
495 | |||
496 | /** |
||
497 | * Graceful restart |
||
498 | * @return void |
||
499 | */ |
||
500 | View Code Duplication | public function gracefulRestart() |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
501 | { |
||
502 | $this->graceful = true; |
||
503 | $this->reload = true; |
||
504 | Timer::add(function () { |
||
505 | EventLoop::$instance->stop(); |
||
506 | }, $this->reloadDelay * 1e6); |
||
507 | $this->setState($this->state); |
||
0 ignored issues
–
show
$this->state is of type integer , but the function expects a object<PHPDaemon\Thread\Constant> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
508 | } |
||
509 | |||
510 | /** |
||
511 | * Graceful stop |
||
512 | * @return void |
||
513 | */ |
||
514 | View Code Duplication | public function gracefulStop() |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
515 | { |
||
516 | $this->graceful = true; |
||
517 | Timer::add(function () { |
||
518 | EventLoop::$instance->stop(); |
||
519 | }, $this->reloadDelay * 1e6); |
||
520 | $this->setState($this->state); |
||
0 ignored issues
–
show
$this->state is of type integer , but the function expects a object<PHPDaemon\Thread\Constant> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
521 | } |
||
522 | |||
523 | /** |
||
524 | * Asks the running applications the whether we can go to shutdown current (old) worker. |
||
525 | * @return boolean - Ready? |
||
526 | */ |
||
527 | protected function appInstancesReloadReady() |
||
528 | { |
||
529 | $ready = true; |
||
530 | |||
531 | foreach (Daemon::$appInstances as $k => $app) { |
||
532 | foreach ($app as $name => $appInstance) { |
||
533 | if (!$appInstance->handleStatus($this->graceful ? AppInstance::EVENT_GRACEFUL_SHUTDOWN : AppInstance::EVENT_SHUTDOWN)) { |
||
534 | $this->log(__METHOD__ . ': waiting for ' . $k . ':' . $name); |
||
535 | $ready = false; |
||
536 | } |
||
537 | } |
||
538 | } |
||
539 | return $ready; |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * Shutdown this worker |
||
544 | * @param boolean Hard? If hard, we shouldn't wait for graceful shutdown of the running applications. |
||
545 | * @return boolean|null Ready? |
||
546 | */ |
||
547 | protected function shutdown($hard = false) |
||
548 | { |
||
549 | $error = error_get_last(); |
||
550 | View Code Duplication | if ($error) { |
|
0 ignored issues
–
show
The expression
$error of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
551 | if ($error['type'] === E_ERROR) { |
||
552 | Daemon::log('W#' . $this->pid . ' crashed by error \'' . $error['message'] . '\' at ' . $error['file'] . ':' . $error['line']); |
||
553 | } |
||
554 | } |
||
555 | |||
556 | if (Daemon::$config->throwexceptiononshutdown->value) { |
||
557 | throw new \Exception('event shutdown'); |
||
558 | } |
||
559 | |||
560 | @ob_flush(); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
561 | |||
562 | View Code Duplication | if ($this->terminated === true) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
563 | if ($hard) { |
||
564 | posix_kill(getmypid(), SIGKILL); |
||
565 | exit(0); |
||
566 | } |
||
567 | |||
568 | return; |
||
569 | } |
||
570 | |||
571 | $this->terminated = true; |
||
572 | |||
573 | if ($hard) { |
||
574 | $this->setState(Daemon::WSTATE_SHUTDOWN); |
||
575 | posix_kill(getmypid(), SIGKILL); |
||
576 | exit(0); |
||
577 | } |
||
578 | |||
579 | $this->reloadReady = $this->appInstancesReloadReady(); |
||
580 | Timer::remove('breakMainLoopCheck'); |
||
581 | |||
582 | Timer::add(function ($event) { |
||
583 | $self = Daemon::$process; |
||
584 | |||
585 | $self->reloadReady = $self->appInstancesReloadReady(); |
||
0 ignored issues
–
show
The method
appInstancesReloadReady does only exist in PHPDaemon\Thread\Worker , but not in PHPDaemon\Thread\IPC and PHPDaemon\Thread\Master .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
586 | |||
587 | if ($self->reload === true) { |
||
588 | $self->reloadReady = $self->reloadReady && (microtime(true) > $self->reloadTime); |
||
589 | } |
||
590 | if (!$self->reloadReady) { |
||
591 | $event->timeout(); |
||
592 | } else { |
||
593 | EventLoop::$instance->stop(); |
||
594 | } |
||
595 | }, 1e6, 'checkReloadReady'); |
||
596 | while (!$this->reloadReady) { |
||
597 | EventLoop::$instance->run(); |
||
598 | } |
||
599 | FileSystem::waitAllEvents(); // ensure that all I/O events completed before suicide |
||
600 | posix_kill(getmypid(), SIGKILL); |
||
601 | exit(0); // R.I.P. |
||
602 | } |
||
603 | |||
604 | /** |
||
605 | * Set current status of worker |
||
606 | * @param int Constant |
||
607 | * @return boolean Success. |
||
608 | */ |
||
609 | public function setState($int) |
||
610 | { |
||
611 | if (Daemon::$compatMode) { |
||
612 | return true; |
||
613 | } |
||
614 | if (!$this->id) { |
||
615 | return false; |
||
616 | } |
||
617 | |||
618 | if (Daemon::$config->logworkersetstate->value) { |
||
619 | $this->log('state is ' . Daemon::$wstateRev[$int]); |
||
620 | } |
||
621 | |||
622 | $this->state = $int; |
||
0 ignored issues
–
show
It seems like
$int of type object<PHPDaemon\Thread\Constant> is incompatible with the declared type integer of property $state .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
623 | |||
624 | if ($this->reload) { |
||
625 | $int += 100; |
||
626 | } |
||
627 | if (Daemon::$shm_wstate !== null) { |
||
628 | Daemon::$shm_wstate->write(chr($int), $this->id - 1); |
||
629 | } |
||
630 | return true; |
||
631 | } |
||
632 | |||
633 | /** |
||
634 | * Handler of the SIGINT (hard shutdown) signal in worker process. |
||
635 | * @return void |
||
636 | */ |
||
637 | protected function sigint() |
||
638 | { |
||
639 | if (Daemon::$config->logsignals->value) { |
||
640 | $this->log('caught SIGINT.'); |
||
641 | } |
||
642 | |||
643 | $this->shutdown(true); |
||
644 | } |
||
645 | |||
646 | /** |
||
647 | * Handler of the SIGTERM (graceful shutdown) signal in worker process. |
||
648 | * @return void |
||
649 | */ |
||
650 | protected function sigterm() |
||
651 | { |
||
652 | if (Daemon::$config->logsignals->value) { |
||
653 | $this->log('caught SIGTERM.'); |
||
654 | } |
||
655 | |||
656 | $this->graceful = false; |
||
657 | EventLoop::$instance->stop(); |
||
658 | } |
||
659 | |||
660 | /** |
||
661 | * Handler of the SIGQUIT (graceful shutdown) signal in worker process. |
||
662 | * @return void |
||
663 | */ |
||
664 | protected function sigquit() |
||
665 | { |
||
666 | if (Daemon::$config->logsignals->value) { |
||
667 | $this->log('caught SIGQUIT.'); |
||
668 | } |
||
669 | |||
670 | parent::sigquit(); |
||
671 | } |
||
672 | |||
673 | /** |
||
674 | * Handler of the SIGHUP (reload config) signal in worker process. |
||
675 | * @return void |
||
676 | */ |
||
677 | View Code Duplication | protected function sighup() |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
678 | { |
||
679 | if (Daemon::$config->logsignals->value) { |
||
680 | $this->log('caught SIGHUP (reload config).'); |
||
681 | } |
||
682 | |||
683 | if (isset(Daemon::$config->configfile->value)) { |
||
684 | Daemon::loadConfig(Daemon::$config->configfile->value); |
||
685 | } |
||
686 | |||
687 | $this->update = true; |
||
688 | } |
||
689 | |||
690 | /** |
||
691 | * Handler of the SIGUSR1 (re-open log-file) signal in worker process. |
||
692 | * @return void |
||
693 | */ |
||
694 | protected function sigusr1() |
||
695 | { |
||
696 | if (Daemon::$config->logsignals->value) { |
||
697 | $this->log('caught SIGUSR1 (re-open log-file).'); |
||
698 | } |
||
699 | |||
700 | Daemon::openLogs(); |
||
701 | } |
||
702 | |||
703 | /** |
||
704 | * Handler of the SIGUSR2 (graceful shutdown for update) signal in worker process. |
||
705 | * @return void |
||
706 | */ |
||
707 | protected function sigusr2() |
||
708 | { |
||
709 | if (Daemon::$config->logsignals->value) { |
||
710 | $this->log('caught SIGUSR2 (graceful shutdown for update).'); |
||
711 | } |
||
712 | |||
713 | $this->gracefulRestart(); |
||
714 | } |
||
715 | |||
716 | /** |
||
717 | * Handler of the SIGTSTP (graceful stop) signal in worker process. |
||
718 | * @return void |
||
719 | */ |
||
720 | protected function sigtstp() |
||
721 | { |
||
722 | if (Daemon::$config->logsignals->value) { |
||
723 | $this->log('caught SIGTSTP (graceful stop).'); |
||
724 | } |
||
725 | |||
726 | $this->gracefulStop(); |
||
727 | } |
||
728 | |||
729 | /** |
||
730 | * Handler of the SIGTTIN signal in worker process. |
||
731 | * @return void |
||
732 | */ |
||
733 | protected function sigttin() |
||
734 | { |
||
735 | } |
||
736 | |||
737 | /** |
||
738 | * Handler of the SIGPIPE signal in worker process. |
||
739 | * @return void |
||
740 | */ |
||
741 | protected function sigpipe() |
||
742 | { |
||
743 | } |
||
744 | |||
745 | /** |
||
746 | * Handler of non-known signals. |
||
747 | * @return void |
||
748 | */ |
||
749 | View Code Duplication | protected function sigunknown($signo) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
750 | { |
||
751 | if (isset(Generic::$signals[$signo])) { |
||
752 | $sig = Generic::$signals[$signo]; |
||
753 | } else { |
||
754 | $sig = 'UNKNOWN'; |
||
755 | } |
||
756 | |||
757 | $this->log('caught signal #' . $signo . ' (' . $sig . ').'); |
||
758 | } |
||
759 | |||
760 | /** |
||
761 | * Called (in master) when process is terminated |
||
762 | * @return void |
||
763 | */ |
||
764 | public function onTerminated() |
||
765 | { |
||
766 | $this->setState(Daemon::WSTATE_SHUTDOWN); |
||
767 | } |
||
768 | |||
769 | /** |
||
770 | * Destructor of worker thread. |
||
771 | * @return void |
||
772 | */ |
||
773 | public function __destruct() |
||
774 | { |
||
775 | if (posix_getpid() === $this->pid) { |
||
776 | $this->setState(Daemon::WSTATE_SHUTDOWN); |
||
777 | } |
||
778 | } |
||
779 | } |
||
780 |
This check looks for access to methods that are not accessible from the current context.
If you need to make a method accessible to another context you can raise its visibility level in the defining class.