Bootstrap::start()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 3
nop 0
dl 0
loc 22
rs 9.568
c 0
b 0
f 0
1
<?php
2
3
namespace PHPDaemon\Core;
4
5
use PHPDaemon\Config\Entry\Generic;
6
use PHPDaemon\FS\FileSystem;
7
use PHPDaemon\Thread;
8
use PHPDaemon\Utils\DateTime;
9
use PHPDaemon\Utils\ShmEntity;
10
use PHPDaemon\Utils\Terminal;
11
12
/**
13
 * Bootstrap for PHPDaemon
14
 *
15
 * @package Core
16
 *
17
 * @author  Vasily Zorin <[email protected]>
18
 */
19
class Bootstrap
20
{
21
    use \PHPDaemon\Traits\ClassWatchdog;
22
    use \PHPDaemon\Traits\StaticObjectWatchdog;
23
24
    /**
25
     * Master process ID
26
     *
27
     * @var integer
28
     */
29
    protected static $pid;
30
31
    /**
32
     * List of commands
33
     *
34
     * @var array
35
     */
36
    protected static $commands = [
37
        'start',
38
        'stop',
39
        'hardstop',
40
        'gracefulstop',
41
        'update',
42
        'reload',
43
        'restart',
44
        'hardrestart',
45
        'fullstatus',
46
        'status',
47
        'configtest',
48
        'log',
49
        'runworker',
50
        'ipcpath',
51
        'reopenlog',
52
    ];
53
54
    /**
55
     * Command-line params
56
     *
57
     * @var array
58
     */
59
    protected static $params = [
60
        'pid-file'     => [
61
            'val'  => '/path/to/pid-file',
62
            'desc' => 'Pid file',
63
        ],
64
        'max-requests' => [
65
            'desc' => 'Maximum requests to worker before respawn',
66
            'val'  => [
67
                'n' => 'Count',
68
            ],
69
        ],
70
        'path'         => [
71
            'desc' => 'Path to your application resolver',
72
            'val'  => '/path/to/resolver.php',
73
        ],
74
        'config-file'  => [
75
            'desc' => 'Paths to configuration file separated by semicolon. First found will be used.',
76
            'val'  => '/path/to/file',
77
        ],
78
        'logging'      => [
79
            'desc' => 'Logging status',
80
            'val'  => [
81
                '0' => 'Disabled',
82
                '1' => 'Enabled',
83
            ],
84
        ],
85
        'log-storage'  => [
86
            'desc' => 'Log storage',
87
            'val'  => '/path/to/file',
88
        ],
89
        'user'         => [
90
            'desc' => 'User of master process',
91
            'val'  => 'username',
92
        ],
93
        'group'        => [
94
            'desc' => 'Group of master process',
95
            'val'  => 'groupname',
96
        ],
97
        'help'         => 'This help information',
98
    ];
99
100
    /**
101
     * Actions on early startup.
102
     *
103
     * @param string Optional. Config file path.
104
     *
105
     * @return void
106
     */
107
    public static function init ($configFile = null)
108
    {
109
        if (!version_compare(PHP_VERSION, '5.6.0', '>=')) {
110
            Daemon::log('PHP >= 5.6.0 required.');
111
112
            return;
113
        }
114
115
        //run without composer
116
        if (!function_exists('setTimeout')) {
117
            require 'PHPDaemon/Utils/func.php';
118
        }
119
120
        Daemon::initSettings();
121
        FileSystem::init();
122
        Daemon::$runName = basename($_SERVER['argv'][0]);
123
124
        $error   = false;
125
        $argv    = $_SERVER['argv'];
126
        $runmode = isset($argv[1]) ? str_replace('-', '', $argv[1]) : '';
127
        $args    = Bootstrap::getArgs($argv);
128
129
        if ($runmode === 'pidfile') {
130
        }
131
        else if (!isset(self::$params[$runmode]) && !in_array($runmode, self::$commands)) {
132
            if ('' !== $runmode) {
133
                echo 'Unrecognized command: ' . $runmode . "\n";
134
            }
135
136
            self::printUsage();
137
            exit;
138
        }
139
        else if ('help' === $runmode) {
140
            self::printHelp();
141
            exit;
142
        }
143
144
        $n = null;
145
        if ('log' === $runmode) {
146
            if (isset($args['n'])) {
147
                $n = $args['n'];
148
                unset($args['n']);
149
            }
150
            else {
151
                $n = 20;
152
            }
153
        }
154
155
        if (isset($configFile)) {
156
            Daemon::$config->configfile->setHumanValue($configFile);
157
        }
158
        if (isset($args['configfile'])) {
159
            Daemon::$config->configfile->setHumanValue($args['configfile']);
160
        }
161
162
        if (!Daemon::$config->loadCmdLineArgs($args)) {
163
            $error = true;
164
        }
165
166
        if (!Daemon::loadConfig(Daemon::$config->configfile->value)) {
167
            $error = true;
168
        }
169
        if ($runmode === 'pidfile') {
170
            echo Daemon::$config->pidfile->value . PHP_EOL;
171
172
            return;
173
        }
174
175
        if ('log' === $runmode) {
176
            passthru('tail -n ' . $n . ' -f ' . escapeshellarg(Daemon::$config->logstorage->value));
177
            exit;
178
        }
179
180
        if (extension_loaded('apc') && ini_get('apc.enabled')) {
181
            Daemon::log(
182
                'Detected pecl-apc extension enabled. Usage of bytecode caching (APC/eAccelerator/xcache/...)  makes no sense at all in case of using phpDaemon \'cause phpDaemon includes files just in time itself.'
183
            );
184
        }
185
186
        if (isset(Daemon::$config->locale->value) && Daemon::$config->locale->value !== '') {
187
            setlocale(LC_ALL, array_map('trim', explode(',', Daemon::$config->locale->value)));
188
        }
189
190
        if (Daemon::$config->autoreimport->value && !is_callable('runkit_import')) {
191
            Daemon::log(
192
                '[WARN] runkit extension not found. You should install it or disable --auto-reimport. Non-critical error.'
193
            );
194
        }
195
196
        if (!is_callable('posix_kill')) {
197
            Daemon::log('[EMERG] Posix not found. You should compile PHP without \'--disable-posix\'.');
198
            $error = true;
199
        }
200
201
        if (!is_callable('pcntl_signal')) {
202
            Daemon::log('[EMERG] PCNTL not found. You should compile PHP with \'--enable-pcntl\'.');
203
            $error = true;
204
        }
205
206
        if (extension_loaded('libevent')) {
207
            Daemon::log('[EMERG] libevent extension found. You have to remove libevent.so extension.');
208
            $error = true;
209
        }
210
211
        $eventVer     = '1.6.1';
212
        $eventVerType = 'stable';
213
        if (!Daemon::loadModuleIfAbsent('event', $eventVer . '-' . $eventVerType)) {
214
            Daemon::log(
215
                '[EMERG] event extension >= ' . $eventVer . ' not found (or OUTDATED). You have to install it. `pecl install http://pecl.php.net/get/event`'
216
            );
217
            $error = true;
218
        }
219
220
        if (!is_callable('socket_create')) {
221
            Daemon::log('[EMERG] Sockets extension not found. You should compile PHP with \'--enable-sockets\'.');
222
            $error = true;
223
        }
224
225
        if (!is_callable('shmop_open')) {
226
            Daemon::log('[EMERG] Shmop extension not found. You should compile PHP with \'--enable-shmop\'.');
227
            $error = true;
228
        }
229
230
        if (!isset(Daemon::$config->user)) {
231
            Daemon::log('[EMERG] You must set \'user\' parameter.');
232
            $error = true;
233
        }
234
235
        if (!isset(Daemon::$config->path)) {
236
            Daemon::log('[EMERG] You must set \'path\' parameter (path to your application resolver).');
237
            $error = true;
238
        }
239
240
        if (!file_exists(Daemon::$config->pidfile->value)) {
241
            $dir = dirname(Daemon::$config->pidfile->value);
242
            is_dir($dir) || mkdir($dir, 0755, true);
243
            if (!touch(Daemon::$config->pidfile->value)) {
244
                Daemon::log('[EMERG] Couldn\'t create pid-file \'' . Daemon::$config->pidfile->value . '\'.');
245
                $error = true;
246
            }
247
248
            Bootstrap::$pid = 0;
249
        }
250
        else if (!is_file(Daemon::$config->pidfile->value)) {
251
            Daemon::log('Pid-file \'' . Daemon::$config->pidfile->value . '\' must be a regular file.');
252
            Bootstrap::$pid = false;
0 ignored issues
show
Documentation Bug introduced by
The property $pid was declared of type integer, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
253
            $error          = true;
254
        }
255
        else if (!is_writable(Daemon::$config->pidfile->value)) {
256
            Daemon::log('Pid-file \'' . Daemon::$config->pidfile->value . '\' must be writable.');
257
            $error = true;
258
        }
259
        else if (!is_readable(Daemon::$config->pidfile->value)) {
260
            Daemon::log('Pid-file \'' . Daemon::$config->pidfile->value . '\' must be readable.');
261
            Bootstrap::$pid = false;
262
            $error          = true;
263
        }
264
        else {
265
            Bootstrap::$pid = (int)file_get_contents(Daemon::$config->pidfile->value);
266
        }
267
268
        if (Daemon::$config->chroot->value !== '/') {
269
            if (posix_getuid() != 0) {
270
                Daemon::log('You must have the root privileges to change root.');
271
                $error = true;
272
            }
273
        }
274
275
        $pathList = preg_split('~\s*;\s*~', Daemon::$config->path->value);
276
        $found    = false;
277
        foreach ($pathList as $path) {
278
            if (@is_file($path)) {
279
                Daemon::$appResolverPath = $path;
280
                $found                   = true;
281
                break;
282
            }
283
        }
284
        if (!$found) {
285
            Daemon::log(
286
                'Your application resolver \'' . Daemon::$config->path->value . '\' is not available (config directive \'path\').'
287
            );
288
            $error = true;
289
        }
290
291
        Daemon::$appResolver = require Daemon::$appResolverPath;
292
293 View Code Duplication
        if (isset(Daemon::$config->group->value) && is_callable('posix_getgid')) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
294
            if (($sg = posix_getgrnam(Daemon::$config->group->value)) === false) {
295
                Daemon::log(
296
                    'Unexisting group \'' . Daemon::$config->group->value . '\'. You have to replace config-variable \'group\' with existing group-name.'
297
                );
298
                $error = true;
299
            }
300
            else if (($sg['gid'] != posix_getgid()) && (posix_getuid() != 0)) {
301
                Daemon::log('You must have the root privileges to change group.');
302
                $error = true;
303
            }
304
        }
305
306 View Code Duplication
        if (isset(Daemon::$config->user->value) && is_callable('posix_getuid')) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
307
            if (($su = posix_getpwnam(Daemon::$config->user->value)) === false) {
308
                Daemon::log(
309
                    'Unexisting user \'' . Daemon::$config->user->value . '\', user not found. You have to replace config-variable \'user\' with existing username.'
310
                );
311
                $error = true;
312
            }
313
            else if (($su['uid'] != posix_getuid()) && (posix_getuid() != 0)) {
314
                Daemon::log('You must have the root privileges to change user.');
315
                $error = true;
316
            }
317
        }
318
319
        if (isset(Daemon::$config->minspareworkers->value)
320
            && Daemon::$config->minspareworkers->value > 0
321
            && isset(Daemon::$config->maxspareworkers->value)
322
            && Daemon::$config->maxspareworkers->value > 0
323
        ) {
324
            if (Daemon::$config->minspareworkers->value > Daemon::$config->maxspareworkers->value) {
325
                Daemon::log('\'minspareworkers\' cannot be greater than \'maxspareworkers\'.');
326
                $error = true;
327
            }
328
        }
329
330
        if (isset(Daemon::$config->addincludepath->value)) {
331
            ini_set(
332
                'include_path',
333
                ini_get('include_path') . ':' . implode(':', Daemon::$config->addincludepath->value)
334
            );
335
        }
336
337
        if (isset(Daemon::$config->minworkers->value) && isset(Daemon::$config->maxworkers->value)) {
338
            if (Daemon::$config->minworkers->value > Daemon::$config->maxworkers->value) {
339
                Daemon::$config->minworkers->value = Daemon::$config->maxworkers->value;
340
            }
341
        }
342
343
        if ($runmode === 'start') {
344
            if ($error === false) {
345
                Bootstrap::start();
346
            }
347
            else {
348
                exit(6);
349
            }
350
        }
351
        else if ($runmode === 'runworker') {
352
            if ($error === false) {
353
                Bootstrap::runworker();
354
            }
355
            else {
356
                exit(6);
357
            }
358
        }
359
        else if ($runmode === 'status' || $runmode === 'fullstatus') {
360
            $status = Bootstrap::$pid && Thread\Generic::ifExistsByPid(Bootstrap::$pid);
0 ignored issues
show
Bug Best Practice introduced by
The expression \PHPDaemon\Core\Bootstrap::$pid of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
361
            echo '[STATUS] phpDaemon ' . Daemon::$version . ' is ' . ($status ? 'running' : 'NOT running') . ' (' . Daemon::$config->pidfile->value . ").\n";
362
363
            if ($status && ($runmode === 'fullstatus')) {
364
                echo 'Uptime: ' . DateTime::diffAsText(filemtime(Daemon::$config->pidfile->value), time()) . "\n";
365
366
                Daemon::$shm_wstate = new ShmEntity(Daemon::$config->pidfile->value, Daemon::SHM_WSTATE_SIZE, 'wstate');
367
368
                $stat = Daemon::getStateOfWorkers();
369
370
                echo "State of workers:\n";
371
                echo "\tTotal: " . $stat['alive'] . "\n";
372
                echo "\tIdle: " . $stat['idle'] . "\n";
373
                echo "\tBusy: " . $stat['busy'] . "\n";
374
                echo "\tShutdown: " . $stat['shutdown'] . "\n";
375
                echo "\tPre-init: " . $stat['preinit'] . "\n";
376
                echo "\tInit: " . $stat['init'] . "\n";
377
            }
378
379
            echo "\n";
380
        }
381
        else if ($runmode === 'update') {
382 View Code Duplication
            if ((!Bootstrap::$pid) || (!posix_kill(Bootstrap::$pid, SIGHUP))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression \PHPDaemon\Core\Bootstrap::$pid of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Duplication introduced by
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.

Loading history...
383
                echo '[UPDATE] ERROR. It seems that phpDaemon is not running' . (Bootstrap::$pid ? ' (PID ' . Bootstrap::$pid . ')' : '') . ".\n";
384
            }
385
        }
386
        else if ($runmode === 'reopenlog') {
387 View Code Duplication
            if ((!Bootstrap::$pid) || (!posix_kill(Bootstrap::$pid, SIGUSR1))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression \PHPDaemon\Core\Bootstrap::$pid of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Duplication introduced by
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.

Loading history...
388
                echo '[REOPEN-LOG] ERROR. It seems that phpDaemon is not running' . (Bootstrap::$pid ? ' (PID ' . Bootstrap::$pid . ')' : '') . ".\n";
389
            }
390
        }
391
        else if ($runmode === 'reload') {
392 View Code Duplication
            if ((!Bootstrap::$pid) || (!posix_kill(Bootstrap::$pid, SIGUSR2))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression \PHPDaemon\Core\Bootstrap::$pid of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Duplication introduced by
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.

Loading history...
393
                echo '[RELOAD] ERROR. It seems that phpDaemon is not running' . (Bootstrap::$pid ? ' (PID ' . Bootstrap::$pid . ')' : '') . ".\n";
394
            }
395
        }
396
        else if ($runmode === 'restart') {
397
            if ($error === false) {
398
                Bootstrap::stop(2);
399
                Bootstrap::start();
400
            }
401
        }
402
        else if ($runmode === 'hardrestart') {
403
            Bootstrap::stop(3);
404
            Bootstrap::start();
405
        }
406
        else if ($runmode === 'ipcpath') {
407
            $i = Daemon::$appResolver->getInstanceByAppName('\PHPDaemon\IPCManager\IPCManager');
408
            echo $i->getSocketUrl() . PHP_EOL;
409
        }
410
        else if ($runmode === 'configtest') {
411
            $term = new Terminal;
412
            $term->enableColor();
413
414
            echo "\n";
415
416
            $rows = [];
417
418
            $rows[] = [
419
                'parameter' => 'PARAMETER',
420
                'value'     => 'VALUE',
421
                '_color'    => '37',
422
                '_bold'     => true,
423
            ];
424
425
            foreach (Daemon::$config as $name => $entry) {
0 ignored issues
show
Bug introduced by
The expression \PHPDaemon\Core\Daemon::$config of type object<PHPDaemon\Config\_Object> is not traversable.
Loading history...
426
                if (!$entry instanceof Generic) {
427
                    continue;
428
                }
429
430
                $row = [
431
                    'parameter' => $name,
432
                    'value'     => var_export($entry->humanValue, true),
433
                ];
434
435
                if ($entry->defaultValue != $entry->humanValue) {
436
                    $row['value'] .= ' (' . var_export($entry->defaultValue, true) . ')';
437
                }
438
439
                $rows[] = $row;
440
            }
441
442
            $term->drawtable($rows);
443
444
            echo "\n";
445
        }
446
        else if ($runmode === 'stop') {
447
            Bootstrap::stop();
448
        }
449
        else if ($runmode === 'gracefulstop') {
450
            Bootstrap::stop(4);
451
        }
452
        else if ($runmode === 'hardstop') {
453
            echo '[HARDSTOP] Sending SIGINT to ' . Bootstrap::$pid . '... ';
454
455
            $ok = Bootstrap::$pid && posix_kill(Bootstrap::$pid, SIGINT);
0 ignored issues
show
Bug Best Practice introduced by
The expression \PHPDaemon\Core\Bootstrap::$pid of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
456
457
            echo $ok ? 'OK.' : 'ERROR. It seems that phpDaemon is not running.';
458
459
            if ($ok) {
460
                $i = 0;
461
462
                while ($r = Thread\Generic::ifExistsByPid(Bootstrap::$pid)) {
0 ignored issues
show
Unused Code introduced by
$r 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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
463
                    usleep(500000);
464
465
                    if ($i === 9) {
466
                        echo "\nphpDaemon master-process hasn't finished. Sending SIGKILL... ";
467
                        posix_kill(Bootstrap::$pid, SIGKILL);
468
                        sleep(0.2);
469
                        if (!Thread\Generic::ifExistsByPid(Bootstrap::$pid)) {
470
                            echo " Oh, his blood is on my hands :'(";
471
                        }
472
                        else {
473
                            echo "ERROR: Process alive. Permissions?";
474
                        }
475
476
                        break;
477
                    }
478
479
                    ++$i;
480
                }
481
            }
482
483
            echo "\n";
484
        }
485
    }
486
487
    /**
488
     * Print ussage
489
     *
490
     * @return void
491
     */
492
    protected static function printUsage ()
493
    {
494
        echo 'usage: ' . Daemon::$runName . " (start|(hard|graceful)stop|update|reload|reopenlog|(hard)restart|fullstatus|status|configtest|log|runworker|help) ...\n";
495
    }
496
497
    /**
498
     * Print help
499
     *
500
     * @return void
501
     */
502
    protected static function printHelp ()
503
    {
504
        $term = new Terminal();
505
506
        echo 'phpDaemon ' . Daemon::$version . ". http://phpdaemon.net\n";
507
508
        self::printUsage();
509
510
        echo "\nAlso you can use some optional parameters to override the same configuration variables:\n";
511
512
        foreach (self::$params as $name => $desc) {
513
            if (empty($desc)) {
514
                continue;
515
            }
516
            else if (!is_array($desc)) {
517
                $term->drawParam($name, $desc);
518
            }
519
            else {
520
                $term->drawParam(
521
                    $name,
522
                    isset($desc['desc']) ? $desc['desc'] : '',
523
                    isset($desc['val']) ? $desc['val'] : ''
524
                );
525
            }
526
        }
527
528
        echo "\n";
529
    }
530
531
    /**
532
     * Start master.
533
     *
534
     * @return void
535
     */
536
    public static function start ()
537
    {
538
        if (Bootstrap::$pid && Thread\Generic::ifExistsByPid(Bootstrap::$pid)) {
539
            Daemon::log(
540
                '[START] phpDaemon with pid-file \'' . Daemon::$config->pidfile->value . '\' is running already (PID ' . Bootstrap::$pid . ')'
541
            );
542
            exit(6);
543
        }
544
545
        $fp = fopen(Daemon::$config->pidfile->value, 'c');
546
        if (!flock($fp, LOCK_EX)) {
547
            Daemon::log(
548
                '[START] phpDaemon with pid-file \'' . Daemon::$config->pidfile->value . '\' is running already as the file is locked (PID ' . Bootstrap::$pid . ')'
549
            );
550
            exit(6);
551
        }
552
553
        Daemon::init();
554
        $pid = Daemon::spawnMaster();
555
        ftruncate($fp, 0);
556
        fwrite($fp, $pid);
557
    }
558
559
    /**
560
     * Runworker.
561
     *
562
     * @return void
563
     */
564
    public static function runworker ()
565
    {
566
        Daemon::log('USE runworker ONLY FOR DEBUGGING PURPOSES');
567
        Daemon::init(false);
568
        Daemon::runWorker();
569
    }
570
571
    /**
572
     * Stop script.
573
     *
574
     * @param int $mode
575
     *
576
     * @return void
577
     */
578
    public static function stop ($mode = 1)
579
    {
580
        if ($mode === 3) {
581
            $signo = SIGINT;
582
        }
583
        else if ($mode === 4) {
584
            $signo = SIGTSTP;
585
        }
586
        else {
587
            $signo = SIGTERM;
588
        }
589
        $ok = Bootstrap::$pid && posix_kill(Bootstrap::$pid, $signo);
590
591
        if (!$ok) {
592
            echo '[WARN]. It seems that phpDaemon is not running' . (Bootstrap::$pid ? ' (PID ' . Bootstrap::$pid . ')' : '') . ".\n";
593
        }
594
595
        if ($ok && ($mode > 1)) {
596
            $i = 0;
597
598
            while ($r = Thread\Generic::ifExistsByPid(Bootstrap::$pid)) {
0 ignored issues
show
Unused Code introduced by
$r 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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
599
                usleep(10000);
600
                ++$i;
601
            }
602
        }
603
    }
604
605
    /**
606
     * Parses command-line arguments.
607
     *
608
     * @param array $args $_SERVER ['argv']
609
     *
610
     * @return array Arguments
611
     */
612
    public static function getArgs ($args)
613
    {
614
        $out      = [];
615
        $last_arg = null;
616
617
        for ($i = 1, $il = sizeof($args); $i < $il; ++$i) {
618
            if (preg_match('~^--(.+)~', $args[$i], $match)) {
619
                $parts = explode('=', $match[1]);
620
                $key   = preg_replace('~[^a-z0-9]+~', '', $parts[0]);
621
622
                if (isset($parts[1])) {
623
                    $out[$key] = $parts[1];
624
                }
625
                else {
626
                    $out[$key] = true;
627
                }
628
629
                $last_arg = $key;
630
            }
631
            else if (preg_match('~^-([a-zA-Z0-9]+)~', $args[$i], $match)) {
632
                $key = null;
633
                for ($j = 0, $jl = mb_orig_strlen($match[1]); $j < $jl; ++$j) {
634
                    $key       = $match[1][$j];
635
                    $out[$key] = true;
636
                }
637
638
                $last_arg = $key;
639
            }
640
            else if ($last_arg !== null) {
641
                $out[$last_arg] = $args[$i];
642
            }
643
        }
644
645
        return $out;
646
    }
647
}
648