Passed
Push — develop ( d91dd3...b816f7 )
by Nikolay
05:31
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 (C) MIKO LLC - All Rights Reserved
4
 * Unauthorized copying of this file, via any medium is strictly prohibited
5
 * Proprietary and confidential
6
 * Written by Nikolay Beketov, 7 2020
7
 *
8
 */
9
10
namespace MikoPBX\Core\System\Configs;
11
12
13
use MikoPBX\Core\System\MikoPBXConfig;
14
use MikoPBX\Core\System\Network;
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
        $pid       = Util::getPidOfProcess($NginxPath);
42
        if ( ! empty($pid)) {
43
            Util::mwExec("{$NginxPath} -s reload");
44
        } elseif (Util::isSystemctl()) {
45
            $systemCtrlPath = Util::which('systemctl');
46
            Util::mwExec("{$systemCtrlPath}  nginx.service");
47
        } else {
48
            Util::killByName('nginx');
49
            Util::mwExec($NginxPath);
50
        }
51
    }
52
53
    /**
54
     * Write additional settings the nginx.conf
55
     *
56
     * @param bool $not_ssl
57
     * @param int  $level
58
     */
59
    public function generateConf($not_ssl = false, $level = 0): void
60
    {
61
        $configPath      = '/etc/nginx/mikopbx/conf.d';
62
        $httpConfigFile  = "{$configPath}/http-server.conf";
63
        $httpsConfigFile = "{$configPath}/https-server.conf";
64
        $dns_server      = '127.0.0.1';
65
66
        $net = new Network();
67
        $dns = $net->getHostDNS();
68
        foreach ($dns as $ns) {
69
            if (Verify::isIpAddress($ns)) {
70
                $dns_server = trim($ns);
71
                break;
72
            }
73
        }
74
75
        // HTTP
76
        $WEBPort      = $this->mikoPBXConfig->getGeneralSettings('WEBPort');
77
        $WEBHTTPSPort = $this->mikoPBXConfig->getGeneralSettings('WEBHTTPSPort');
78
79
        $config = file_get_contents("{$httpConfigFile}.original");
80
        $config = str_replace(['<DNS>', '<WEBPort>'], [$dns_server, $WEBPort], $config);
81
82
        $RedirectToHttps = $this->mikoPBXConfig->getGeneralSettings('RedirectToHttps');
83
        if ($RedirectToHttps === '1' && $not_ssl === false) {
84
            $conf_data = 'if ( $remote_addr != "127.0.0.1" ) {' . PHP_EOL
85
                . '        ' . 'return 301 https://$host:' . $WEBHTTPSPort . '$request_uri;' . PHP_EOL
86
                . '       }' . PHP_EOL;
87
            $config    = str_replace('include mikopbx/locations/*.conf;', $conf_data, $config);
88
        }
89
        file_put_contents($httpConfigFile, $config);
90
91
        // SSL
92
        $WEBHTTPSPublicKey  = $this->mikoPBXConfig->getGeneralSettings('WEBHTTPSPublicKey');
93
        $WEBHTTPSPrivateKey = $this->mikoPBXConfig->getGeneralSettings('WEBHTTPSPrivateKey');
94
        if (
95
            $not_ssl === false
96
            && ! empty($WEBHTTPSPublicKey)
97
            && ! empty($WEBHTTPSPrivateKey)
98
        ) {
99
            $public_filename  = '/etc/ssl/certs/nginx.crt';
100
            $private_filename = '/etc/ssl/private/nginx.key';
101
            file_put_contents($public_filename, $WEBHTTPSPublicKey);
102
            file_put_contents($private_filename, $WEBHTTPSPrivateKey);
103
            $config = file_get_contents("{$httpsConfigFile}.original");
104
            $config = str_replace(['<DNS>', '<WEBHTTPSPort>'], [$dns_server, $WEBHTTPSPort], $config);
105
            file_put_contents($httpsConfigFile, $config);
106
        } elseif (file_exists($httpsConfigFile)) {
107
            unlink($httpsConfigFile);
108
        }
109
110
        // Test work
111
        $currentConfigIsGood = $this->testCurrentNginxConfig();
112
        if ($level < 1 && ! $currentConfigIsGood) {
113
            ++$level;
114
            Util::sysLogMsg('nginx', 'Failed test config file. SSL will be disable...');
115
            $this->generateConf(true, $level);
116
        }
117
        // Add additional rules from modules
118
        $this->generateModulesConf();
119
    }
120
121
    /**
122
     * Test current nginx config on errors
123
     *
124
     * @return bool
125
     */
126
    private function testCurrentNginxConfig(): bool
127
    {
128
        $nginxPath = Util::which('nginx');
129
        $out       = [];
130
        Util::mwExec("{$nginxPath} -t", $out);
131
        $res = implode($out);
132
133
        return (false === stripos($res, 'test failed'));
134
    }
135
136
    /**
137
     * Generate modules locations conf files
138
     */
139
    public function generateModulesConf(): void
140
    {
141
        $locationsPath     = self::MODULES_LOCATIONS_PATH;
142
        if (!is_dir($locationsPath)){
143
            Util::mwMkdir($locationsPath,true);
144
        }
145
        $additionalModules = $this->di->getShared('pbxConfModules');
146
        $rmPath            = Util::which('rm');
147
        Util::mwExec("{$rmPath} -rf {$locationsPath}/*.conf");
148
        foreach ($additionalModules as $appClass) {
149
            if (method_exists($appClass, 'createNginxLocations')) {
150
                $locationContent = $appClass->createNginxLocations();
151
                if ( ! empty($locationContent)) {
152
                    $confFileName = "{$locationsPath}/{$appClass->moduleUniqueId}.conf";
153
                    file_put_contents($confFileName, $locationContent);
154
                    if ( ! $this->testCurrentNginxConfig()) {
155
                        Util::mwExec("{$rmPath} {$confFileName}");
156
                        Util::sysLogMsg('nginx', 'Failed test config file for module' . $appClass->moduleUniqueId);
157
                    }
158
                }
159
            }
160
        }
161
    }
162
}