Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
2
 
3
/*
4
 * This file is part of the Monolog package.
5
 *
6
 * (c) Jordi Boggiano <j.boggiano@seld.be>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Monolog;
13
 
14
use Psr\Log\LoggerInterface;
15
use Psr\Log\LogLevel;
16
use ReflectionExtension;
17
 
18
/**
19
 * Monolog POSIX signal handler
20
 *
21
 * @author Robert Gust-Bardon <robert@gust-bardon.org>
22
 *
23
 * @phpstan-import-type Level from \Monolog\Logger
24
 * @phpstan-import-type LevelName from \Monolog\Logger
25
 */
26
class SignalHandler
27
{
28
    /** @var LoggerInterface */
29
    private $logger;
30
 
31
    /** @var array<int, callable|string|int> SIG_DFL, SIG_IGN or previous callable */
32
    private $previousSignalHandler = [];
33
    /** @var array<int, int> */
34
    private $signalLevelMap = [];
35
    /** @var array<int, bool> */
36
    private $signalRestartSyscalls = [];
37
 
38
    public function __construct(LoggerInterface $logger)
39
    {
40
        $this->logger = $logger;
41
    }
42
 
43
    /**
44
     * @param  int|string $level           Level or level name
45
     * @param  bool       $callPrevious
46
     * @param  bool       $restartSyscalls
47
     * @param  bool|null  $async
48
     * @return $this
49
     *
50
     * @phpstan-param Level|LevelName|LogLevel::* $level
51
     */
52
    public function registerSignalHandler(int $signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self
53
    {
54
        if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) {
55
            return $this;
56
        }
57
 
58
        $level = Logger::toMonologLevel($level);
59
 
60
        if ($callPrevious) {
61
            $handler = pcntl_signal_get_handler($signo);
62
            $this->previousSignalHandler[$signo] = $handler;
63
        } else {
64
            unset($this->previousSignalHandler[$signo]);
65
        }
66
        $this->signalLevelMap[$signo] = $level;
67
        $this->signalRestartSyscalls[$signo] = $restartSyscalls;
68
 
69
        if ($async !== null) {
70
            pcntl_async_signals($async);
71
        }
72
 
73
        pcntl_signal($signo, [$this, 'handleSignal'], $restartSyscalls);
74
 
75
        return $this;
76
    }
77
 
78
    /**
79
     * @param mixed $siginfo
80
     */
81
    public function handleSignal(int $signo, $siginfo = null): void
82
    {
83
        static $signals = [];
84
 
85
        if (!$signals && extension_loaded('pcntl')) {
86
            $pcntl = new ReflectionExtension('pcntl');
87
            // HHVM 3.24.2 returns an empty array.
88
            foreach ($pcntl->getConstants() ?: get_defined_constants(true)['Core'] as $name => $value) {
89
                if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) {
90
                    $signals[$value] = $name;
91
                }
92
            }
93
        }
94
 
95
        $level = $this->signalLevelMap[$signo] ?? LogLevel::CRITICAL;
96
        $signal = $signals[$signo] ?? $signo;
97
        $context = $siginfo ?? [];
98
        $this->logger->log($level, sprintf('Program received signal %s', $signal), $context);
99
 
100
        if (!isset($this->previousSignalHandler[$signo])) {
101
            return;
102
        }
103
 
104
        if ($this->previousSignalHandler[$signo] === SIG_DFL) {
105
            if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch')
106
                && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')
107
            ) {
108
                $restartSyscalls = $this->signalRestartSyscalls[$signo] ?? true;
109
                pcntl_signal($signo, SIG_DFL, $restartSyscalls);
110
                pcntl_sigprocmask(SIG_UNBLOCK, [$signo], $oldset);
111
                posix_kill(posix_getpid(), $signo);
112
                pcntl_signal_dispatch();
113
                pcntl_sigprocmask(SIG_SETMASK, $oldset);
114
                pcntl_signal($signo, [$this, 'handleSignal'], $restartSyscalls);
115
            }
116
        } elseif (is_callable($this->previousSignalHandler[$signo])) {
117
            $this->previousSignalHandler[$signo]($signo, $siginfo);
118
        }
119
    }
120
}