Passed
Push — develop ( e1e3d7...c69915 )
by Nikolay
04:49 queued 11s
created

NginxConf::generateModulesConf()   A

Complexity

Conditions 6
Paths 10

Size

Total Lines 18
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
c 0
b 0
f 0
dl 0
loc 18
rs 9.2222
cc 6
nc 10
nop 0
1
<?php
2
/*
3
 * Copyright © MIKO LLC - All Rights Reserved
4
 * Unauthorized copying of this file, via any medium is strictly prohibited
5
 * Proprietary and confidential
6
 * Written by Alexey Portnov, 9 2020
7
 */
8
9
namespace MikoPBX\Core\System\Configs;
10
11
12
use MikoPBX\Core\System\MikoPBXConfig;
13
use MikoPBX\Core\System\Network;
14
use MikoPBX\Core\System\Processes;
15
use MikoPBX\Core\System\Util;
16
use MikoPBX\Core\System\Verify;
17
use Phalcon\Di\Injectable;
18
19
class NginxConf extends Injectable
20
{
21
    public const LOCATIONS_PATH = '/etc/nginx/mikopbx/locations';
22
    public const MODULES_LOCATIONS_PATH = '/etc/nginx/mikopbx/modules_locations';
23
24
    private MikoPBXConfig $mikoPBXConfig;
25
26
    /**
27
     * NginxConf constructor.
28
     */
29
    public function __construct()
30
    {
31
        $this->mikoPBXConfig = new MikoPBXConfig();
32
    }
33
34
    /**
35
     * Restart Nginx gracefully
36
     * https://www.cyberciti.biz/faq/howto-unix-linux-gracefully-reload-restart-nginx-webserver/
37
     **/
38
    public function reStart(): void
39
    {
40
        $nginxPath = Util::which('nginx');
41
        $killPath = Util::which('kill');
42
        $pid       = Processes::getPidOfProcess('master process nginx');
43
        if (!empty($pid)) {
44
            // reload Nginx workers gracefully
45
            Processes::mwExec("{$killPath} -SIGHUP {$pid} ");
46
        } elseif (Util::isSystemctl()) {
47
            $systemCtrlPath = Util::which('systemctl');
48
            Processes::mwExec("{$systemCtrlPath} restart nginx.service");
49
        } else {
50
            Processes::killByName('nginx');
51
            Processes::mwExec($nginxPath);
52
        }
53
    }
54
55
    /**
56
     * Write additional settings the nginx.conf
57
     *
58
     * @param bool $not_ssl
59
     * @param int  $level
60
     */
61
    public function generateConf($not_ssl = false, $level = 0): void
62
    {
63
        $configPath      = '/etc/nginx/mikopbx/conf.d';
64
        $httpConfigFile  = "{$configPath}/http-server.conf";
65
        $httpsConfigFile = "{$configPath}/https-server.conf";
66
        $dns_server      = '127.0.0.1';
67
68
        $net = new Network();
69
        $dns = $net->getHostDNS();
70
        foreach ($dns as $ns) {
71
            if (Verify::isIpAddress($ns)) {
72
                $dns_server = trim($ns);
73
                break;
74
            }
75
        }
76
77
        // HTTP
78
        $WEBPort      = $this->mikoPBXConfig->getGeneralSettings('WEBPort');
79
        $WEBHTTPSPort = $this->mikoPBXConfig->getGeneralSettings('WEBHTTPSPort');
80
81
        $config = file_get_contents("{$httpConfigFile}.original");
82
        $config = str_replace(['<DNS>', '<WEBPort>'], [$dns_server, $WEBPort], $config);
83
84
        $RedirectToHttps = $this->mikoPBXConfig->getGeneralSettings('RedirectToHttps');
85
        if ($RedirectToHttps === '1' && $not_ssl === false) {
86
            $conf_data = 'if ( $remote_addr != "127.0.0.1" ) {' . PHP_EOL
87
                . '        ' . 'return 301 https://$host:' . $WEBHTTPSPort . '$request_uri;' . PHP_EOL
88
                . '       }' . PHP_EOL;
89
            $config    = str_replace('include mikopbx/locations/*.conf;', $conf_data, $config);
90
        }
91
        file_put_contents($httpConfigFile, $config);
92
93
        // SSL
94
        $WEBHTTPSPublicKey  = $this->mikoPBXConfig->getGeneralSettings('WEBHTTPSPublicKey');
95
        $WEBHTTPSPrivateKey = $this->mikoPBXConfig->getGeneralSettings('WEBHTTPSPrivateKey');
96
        if (
97
            $not_ssl === false
98
            && ! empty($WEBHTTPSPublicKey)
99
            && ! empty($WEBHTTPSPrivateKey)
100
        ) {
101
            $public_filename  = '/etc/ssl/certs/nginx.crt';
102
            $private_filename = '/etc/ssl/private/nginx.key';
103
            file_put_contents($public_filename, $WEBHTTPSPublicKey);
104
            file_put_contents($private_filename, $WEBHTTPSPrivateKey);
105
            $config = file_get_contents("{$httpsConfigFile}.original");
106
            $config = str_replace(['<DNS>', '<WEBHTTPSPort>'], [$dns_server, $WEBHTTPSPort], $config);
107
            file_put_contents($httpsConfigFile, $config);
108
        } elseif (file_exists($httpsConfigFile)) {
109
            unlink($httpsConfigFile);
110
        }
111
112
        // Test work
113
        $currentConfigIsGood = $this->testCurrentNginxConfig();
114
        if ($level < 1 && ! $currentConfigIsGood) {
115
            ++$level;
116
            Util::sysLogMsg('nginx', 'Failed test config file. SSL will be disable...');
117
            $this->generateConf(true, $level);
118
        }
119
        // Add additional rules from modules
120
        $this->generateModulesConf();
121
    }
122
123
    /**
124
     * Test current nginx config on errors
125
     *
126
     * @return bool
127
     */
128
    private function testCurrentNginxConfig(): bool
129
    {
130
        $nginxPath = Util::which('nginx');
131
        $out       = [];
132
        Processes::mwExec("{$nginxPath} -t", $out);
133
        $res = implode($out);
134
135
        return (false === stripos($res, 'test failed'));
136
    }
137
138
    /**
139
     * Generate modules locations conf files
140
     */
141
    public function generateModulesConf(): void
142
    {
143
        $locationsPath     = self::MODULES_LOCATIONS_PATH;
144
        if (!is_dir($locationsPath)){
145
            Util::mwMkdir($locationsPath,true);
146
        }
147
        $additionalModules = $this->di->getShared('pbxConfModules');
148
        $rmPath            = Util::which('rm');
149
        Processes::mwExec("{$rmPath} -rf {$locationsPath}/*.conf");
150
        foreach ($additionalModules as $appClass) {
151
            if (method_exists($appClass, 'createNginxLocations')) {
152
                $locationContent = $appClass->createNginxLocations();
153
                if ( ! empty($locationContent)) {
154
                    $confFileName = "{$locationsPath}/{$appClass->moduleUniqueId}.conf";
155
                    file_put_contents($confFileName, $locationContent);
156
                    if ( ! $this->testCurrentNginxConfig()) {
157
                        Processes::mwExec("{$rmPath} {$confFileName}");
158
                        Util::sysLogMsg('nginx', 'Failed test config file for module' . $appClass->moduleUniqueId);
159
                    }
160
                }
161
            }
162
        }
163
    }
164
}