Passed
Push — develop ( 9ebae4...47fa61 )
by Портнов
12:40
created

Entrypoint::updateSetting()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
c 1
b 0
f 0
dl 0
loc 15
rs 9.8666
cc 2
nc 2
nop 3
1
#!/usr/bin/php -f
2
<?php
3
/*
4
 * MikoPBX - free phone system for small business
5
 * Copyright © 2017-2021 Alexey Portnov and Nikolay Beketov
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along with this program.
18
 * If not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
define('START_DOCKER',1);
22
require_once('Globals.php');
23
use MikoPBX\Core\System\Processes;
24
use MikoPBX\Core\System\Util;
25
use function MikoPBX\Common\Config\appPath;
26
27
class Entrypoint
28
{
29
    private array  $env;
30
    private array  $incSettings;
31
    private array  $settings;
32
    public  float  $workerStartTime;
33
    public  const  PATH_DB = '/cf/conf/mikopbx.db';
34
    private const  pathInc = '/etc/inc/mikopbx-settings.json';
35
36
    public function __construct()
37
    {
38
        pcntl_async_signals(true);
39
        register_shutdown_function([$this, 'shutdownHandler']);
40
41
        $this->env = [
42
            // Идентификация WWW пользователя.
43
            'ID_WWW_USER'     => '',
44
            'ID_WWW_GROUP'    => '',
45
            //
46
            'BEANSTALK_PORT'  => 'beanstalk',
47
            'REDIS_PORT'      => 'redis',
48
            'GNATS_PORT'      => 'gnats',
49
            // General Settings.
50
            'SSH_PORT'        => 'SSHPort',
51
            'WEB_PORT'        => 'WEBPort',
52
            'WEB_HTTPS_PORT'  => 'WEBHTTPSPort',
53
            'SIP_PORT'        => 'SIPPort',
54
            'TLS_PORT'        => 'TLS_PORT',
55
            'RTP_FROM'        => 'RTPPortFrom',
56
            'RTP_TO'          => 'RTPPortTo',
57
            'IAX_PORT'        => 'IAXPort',
58
            'AMI_PORT'        => 'AMIPort',
59
            'AJAM_PORT'       => 'AJAMPort',
60
            'AJAM_PORT_TLS'   => 'AJAMPortTLS',
61
        ];
62
    }
63
    
64
    /**
65
     * Process shutdown event
66
     *
67
     */
68
    public function shutdownHandler(): void
69
    {
70
        $e = error_get_last();
71
        $delta = round(microtime(true) - $this->workerStartTime,2);
72
        if ($e === null) {
73
            Util::sysLogMsg(static::class, "shutdownHandler after $delta seconds", LOG_DEBUG);
74
        } else {
75
            $details = (string) print_r($e, true);
76
            Util::sysLogMsg(static::class, "shutdownHandler after $delta seconds with error: $details", LOG_DEBUG);
77
        }
78
    }
79
80
    public function start():void
81
    {
82
        $this->workerStartTime = microtime(true);
83
        $sysLogdPath = Util::which('syslogd');
84
        // Запуск системного лога.
85
        Processes::mwExecBg($sysLogdPath.' -S -C512');
86
        $out = [];
87
        Processes::mwExec('sqlite3 '.self::PATH_DB.' .tables', $out);
88
        if(trim(implode('',$out)) === ''){
89
            Util::mwMkdir(dirname(self::PATH_DB));
90
            Processes::mwExec("rm -rf ".self::PATH_DB."; cp /conf.default/mikopbx.db ".self::PATH_DB);
91
            Util::addRegularWWWRights(self::PATH_DB);
92
        }
93
        $this->checkUpdate();
94
        shell_exec("rm -rf /tmp/*");
95
        $commands = 'exec </dev/console >/dev/console 2>/dev/console;'.
96
            '/etc/rc/bootup docker 2>/dev/null && '.
97
            '/etc/rc/bootup_pbx 2>/dev/null';
98
        passthru($commands);
99
    }
100
101
    /**
102
     * Изменение ID пользователя www.
103
     * @param string $newUserId
104
     * @param string $newGroupId
105
     */
106
    private function changeWwwUserID(string $newUserId, string $newGroupId):void
107
    {
108
        Util::echoWithSyslog(' - Check user id... '. PHP_EOL);
109
        $pidIdPath = '/cf/conf/user.id';
110
        $pidGrPath = '/cf/conf/group.id';
111
112
        if(empty($newUserId) && file_exists($pidIdPath)){
113
            $newUserId = file_get_contents($pidIdPath);
114
        }
115
        if(empty($newGroupId) && file_exists($pidGrPath)){
116
            $newGroupId = file_get_contents($pidGrPath);
117
        }
118
119
        $commands   = [];
120
        $userID     = 'www';
121
        $currentUserId  = trim(shell_exec("grep '^$userID:' < /etc/passwd | cut -d ':' -f 3"));
122
        $currentGroupId = trim(shell_exec("grep '^$userID:' < /etc/passwd | cut -d ':' -f 4"));
123
124
        Util::echoWithSyslog(" - Old user id: $currentUserId; New user id: $newUserId". PHP_EOL);
125
        Util::echoWithSyslog(" - Old group id: $currentGroupId; New user id: $newGroupId". PHP_EOL);
126
        if( !empty($currentUserId) && !empty($newUserId) && $currentUserId !== $newUserId){
127
            $commands[] = "sed -i 's/$userID:x:$currentUserId:/$userID:x:$newUserId:/g' /etc/passwd*";
128
            $id = '';
129
            if(file_exists($pidIdPath)){
130
                $id = file_get_contents($pidIdPath);
131
            }
132
            if($id !== $newUserId){
133
                $commands[] = "find / -not -path '/proc/*' -user $currentUserId -exec chown -h $userID {} \;";
134
                file_put_contents($pidIdPath, $newUserId);
135
            }
136
        }
137
        if( !empty($currentGroupId) && !empty($newGroupId) && $currentGroupId !== $newGroupId) {
138
            $commands[] = "sed -i 's/$userID:x:$currentGroupId:/$userID:x:$newGroupId:/g' /etc/group";
139
            $commands[] = "sed -i 's/:$currentGroupId:Web/:$newGroupId:Web/g' /etc/passwd";
140
141
            $id = '';
142
            if(file_exists($pidGrPath)){
143
                $id = file_get_contents($pidGrPath);
144
            }
145
            if($id !== $newGroupId){
146
                $commands[] = "find / -not -path '/proc/*' -group $currentGroupId -exec chgrp -h $newGroupId {} \;";
147
                file_put_contents($pidGrPath, $newGroupId);
148
            }
149
        }
150
        if(!empty($commands)){
151
            passthru(implode('; ', $commands));
152
        }
153
    }
154
155
    /**
156
     * Инициализация настроек. Необходима для проверки и обновления настроек портов.
157
     */
158
    private function initSettings():void{
159
        $jsonString     = file_get_contents(self::pathInc);
160
        try {
161
            $this->incSettings = json_decode($jsonString, true, 512, JSON_THROW_ON_ERROR);
162
        } catch (JsonException $exception) {
163
            $this->incSettings = [];
164
            throw new Error(self::pathInc." has broken format");
165
        }
166
167
        $out = [];
168
        Processes::mwExec("sqlite3 ".self::PATH_DB." 'SELECT * FROM m_PbxSettings' | grep -i port", $out);
169
        $this->settings = [];
170
        $keys = array_flip($this->env);
171
        foreach ($out as $row){
172
            $data = explode('|', $row);
173
            $key  = $data[0]??'';
174
            $value= $data[1]??'';
175
176
            if(!isset($keys[$key]) || empty($value)){
177
                continue;
178
            }
179
            $this->settings[$key] = $value;
180
        }
181
    }
182
183
    /**
184
     * Проверяем есть ли указание применить кастомное значение порта.
185
     * Вызывеем функцию обновления сохраненной настройки.
186
     */
187
    public function checkUpdate():void
188
    {
189
        Util::echoWithSyslog(' - Check update... '. PHP_EOL);
190
        $this->initSettings();
191
        foreach ($this->env as $key => $dataPath) {
192
            $newValue = getenv($key);
193
            if(!is_numeric($newValue)){
194
                continue;
195
            }
196
197
            if(empty($dataPath)){
198
                $this->env[$key] = $newValue;
199
                continue;
200
            }
201
202
            $isInc = false;
203
            $oldValue    = $this->settings[$dataPath]??'';
204
            if(empty($oldValue)){
205
                $oldValue = 1*$this->incSettings[$dataPath]['port']??0;
206
                $newValue = 1*$newValue;
207
                $isInc = true;
208
            }
209
210
            if (empty($oldValue) || $newValue === $oldValue){
211
                continue;
212
            }
213
            $this->updateSetting($dataPath, $newValue, $isInc);
214
        }
215
216
        $this->changeWwwUserID($this->env['ID_WWW_USER'], $this->env['ID_WWW_GROUP']);
217
    }
218
219
    private function updateSetting($dataPath, $newValue, $isInc):void
220
    {
221
        $msg = " - Update $dataPath (port) to '$newValue' ...". PHP_EOL;
222
        Util::echoWithSyslog($msg);
223
        if($isInc === true){
224
            $this->incSettings[$dataPath]['port'] = $newValue;
225
            $newData = json_encode($this->incSettings, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
226
            $res = file_put_contents(self::pathInc, $newData);
227
            file_put_contents(appPath('config/mikopbx-settings.json'), $newData);
228
            $result = (false !== $res);
229
        }else{
230
            $res = Processes::mwExec("sqlite3 ".self::PATH_DB." 'UPDATE m_PbxSettings SET value=\"$newValue\" WHERE key=\"$dataPath\"'");
231
            $result = ($res === 0);
232
        }
233
        Util::echoResult($msg, $result);
234
    }
235
}
236
237
Util::echoWithSyslog(' - Start Entrypoint (php)... '. PHP_EOL);
238
$main = new Entrypoint();
239
$main->start();