Passed
Push — develop ( 06fb87...d66898 )
by Nikolay
23:43
created

NginxConf   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 160
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 24
eloc 88
dl 0
loc 160
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A testCurrentNginxConfig() 0 8 1
B generateConf() 0 60 11
A reStart() 0 14 3
A getPid() 0 8 2
A generateModulesConfigs() 0 27 6
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright (C) 2017-2020 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\Core\System\Configs;
21
22
23
use MikoPBX\Common\Providers\PBXConfModulesProvider;
24
use MikoPBX\Core\System\MikoPBXConfig;
25
use MikoPBX\Core\System\Network;
26
use MikoPBX\Core\System\Processes;
27
use MikoPBX\Core\System\Util;
28
use MikoPBX\Core\System\Verify;
29
use Phalcon\Di\Injectable;
30
31
class NginxConf extends Injectable
32
{
33
    public const  LOCATIONS_PATH = '/etc/nginx/mikopbx/locations';
34
    public const  MODULES_LOCATIONS_PATH = '/etc/nginx/mikopbx/modules_locations';
35
    private const PID_FILE = '/var/run/nginx.pid';
36
37
    private MikoPBXConfig $mikoPBXConfig;
38
39
    /**
40
     * NginxConf constructor.
41
     */
42
    public function __construct()
43
    {
44
        $this->mikoPBXConfig = new MikoPBXConfig();
45
    }
46
47
    /**
48
     * Restart Nginx gracefully
49
     * https://www.cyberciti.biz/faq/howto-unix-linux-gracefully-reload-restart-nginx-webserver/
50
     **/
51
    public function reStart(): void
52
    {
53
        $pid = self::getPid();
54
        if (!empty($pid)) {
55
            $killPath = Util::which('kill');
56
            // reload Nginx workers gracefully
57
            Processes::mwExec("{$killPath} -SIGHUP {$pid} ");
58
        } elseif (Util::isSystemctl()) {
59
            $systemCtrlPath = Util::which('systemctl');
60
            Processes::mwExec("{$systemCtrlPath} restart nginx.service");
61
        } else {
62
            $nginxPath = Util::which('nginx');
63
            Processes::killByName('nginx');
64
            Processes::mwExec($nginxPath);
65
        }
66
    }
67
68
    private static function getPid():string{
69
        if(file_exists(self::PID_FILE)) {
70
            $pid = file_get_contents(self::PID_FILE);
71
        }else{
72
            $nginxPath = Util::which('nginx');
73
            $pid       = Processes::getPidOfProcess($nginxPath);
74
        }
75
        return $pid;
76
    }
77
78
    /**
79
     * Write additional settings the nginx.conf
80
     *
81
     * @param bool $not_ssl
82
     * @param int  $level
83
     */
84
    public function generateConf($not_ssl = false, $level = 0): void
85
    {
86
        $configPath      = '/etc/nginx/mikopbx/conf.d';
87
        $httpConfigFile  = "{$configPath}/http-server.conf";
88
        $httpsConfigFile = "{$configPath}/https-server.conf";
89
        $dns_server      = '127.0.0.1';
90
91
        $net = new Network();
92
        $dns = $net->getHostDNS();
93
        foreach ($dns as $ns) {
94
            if (Verify::isIpAddress($ns)) {
95
                $dns_server = trim($ns);
96
                break;
97
            }
98
        }
99
100
        // HTTP
101
        $WEBPort      = $this->mikoPBXConfig->getGeneralSettings('WEBPort');
102
        $WEBHTTPSPort = $this->mikoPBXConfig->getGeneralSettings('WEBHTTPSPort');
103
104
        $config = file_get_contents("{$httpConfigFile}.original");
105
        $config = str_replace(['<DNS>', '<WEBPort>'], [$dns_server, $WEBPort], $config);
106
107
        $RedirectToHttps = $this->mikoPBXConfig->getGeneralSettings('RedirectToHttps');
108
        if ($RedirectToHttps === '1' && $not_ssl === false) {
109
            $conf_data = 'if ( $remote_addr != "127.0.0.1" ) {' . PHP_EOL
110
                . '        ' . 'return 301 https://$host:' . $WEBHTTPSPort . '$request_uri;' . PHP_EOL
111
                . '       }' . PHP_EOL;
112
            $config    = str_replace('include mikopbx/locations/*.conf;', $conf_data, $config);
113
        }
114
        file_put_contents($httpConfigFile, $config);
115
116
        // SSL
117
        $WEBHTTPSPublicKey  = $this->mikoPBXConfig->getGeneralSettings('WEBHTTPSPublicKey');
118
        $WEBHTTPSPrivateKey = $this->mikoPBXConfig->getGeneralSettings('WEBHTTPSPrivateKey');
119
        if (
120
            $not_ssl === false
121
            && ! empty($WEBHTTPSPublicKey)
122
            && ! empty($WEBHTTPSPrivateKey)
123
        ) {
124
            $public_filename  = '/etc/ssl/certs/nginx.crt';
125
            $private_filename = '/etc/ssl/private/nginx.key';
126
            file_put_contents($public_filename, $WEBHTTPSPublicKey);
127
            file_put_contents($private_filename, $WEBHTTPSPrivateKey);
128
            $config = file_get_contents("{$httpsConfigFile}.original");
129
            $config = str_replace(['<DNS>', '<WEBHTTPSPort>'], [$dns_server, $WEBHTTPSPort], $config);
130
            file_put_contents($httpsConfigFile, $config);
131
        } elseif (file_exists($httpsConfigFile)) {
132
            unlink($httpsConfigFile);
133
        }
134
135
        // Test work
136
        $currentConfigIsGood = $this->testCurrentNginxConfig();
137
        if ($level < 1 && ! $currentConfigIsGood) {
138
            ++$level;
139
            Util::sysLogMsg('nginx', 'Failed test config file. SSL will be disable...', LOG_ERR);
140
            $this->generateConf(true, $level);
141
        }
142
        // Add additional rules from modules
143
        $this->generateModulesConfigs();
144
    }
145
146
    /**
147
     * Test current nginx config on errors
148
     *
149
     * @return bool
150
     */
151
    private function testCurrentNginxConfig(): bool
152
    {
153
        $nginxPath = Util::which('nginx');
154
        $out       = [];
155
        Processes::mwExec("{$nginxPath} -t", $out);
156
        $res = implode($out);
157
158
        return (false === stripos($res, 'test failed'));
159
    }
160
161
    /**
162
     * Generate modules locations conf files
163
     */
164
    public function generateModulesConfigs(): void
165
    {
166
        $locationsPath     = self::MODULES_LOCATIONS_PATH;
167
        if (!is_dir($locationsPath)){
168
            Util::mwMkdir($locationsPath,true);
169
        }
170
        $additionalModules = $this->di->getShared(PBXConfModulesProvider::SERVICE_NAME);
171
        $rmPath            = Util::which('rm');
172
        Processes::mwExec("{$rmPath} -rf {$locationsPath}/*.conf");
173
        foreach ($additionalModules as $appClass) {
174
            if (!method_exists($appClass, 'createNginxLocations')) {
175
                continue;
176
            }
177
            $locationContent = $appClass->createNginxLocations();
178
            if (empty($locationContent)) {
179
                // Текст конфига не определен.
180
                continue;
181
            }
182
            $confFileName = "{$locationsPath}/{$appClass->moduleUniqueId}.conf";
183
            file_put_contents($confFileName, $locationContent);
184
            if ( $this->testCurrentNginxConfig()) {
185
                // Тест прошел успешно.
186
                continue;
187
            }
188
            // Откат конфига.
189
            Processes::mwExec("{$rmPath} {$confFileName}");
190
            Util::sysLogMsg('nginx', 'Failed test config file for module' . $appClass->moduleUniqueId, LOG_ERR);
191
        }
192
    }
193
}