Passed
Push — develop ( ecce15...7c58c1 )
by Портнов
06:13
created

Util::generateSslCert()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 37
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 37
rs 9.584
c 0
b 0
f 0
cc 4
nc 8
nop 3
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;
21
22
use DateTime;
23
use Exception;
24
use MikoPBX\Common\Models\{CustomFiles};
25
use MikoPBX\Common\Providers\LoggerProvider;
26
use MikoPBX\Common\Providers\TranslationProvider;
27
use MikoPBX\Core\Asterisk\AsteriskManager;
28
use Phalcon\Di;
29
use ReflectionClass;
30
use ReflectionException;
31
use Throwable;
32
33
/**
34
 * Universal commands and procedures
35
 */
36
class Util
37
{
38
39
    /**
40
     * @param $options
41
     * @param $manual_attributes
42
     * @param $section
43
     *
44
     * @return string
45
     */
46
    public static function overrideConfigurationArray($options, $manual_attributes, $section): string
47
    {
48
        $result_config = '';
49
        if ($manual_attributes !== null && isset($manual_attributes[$section])) {
50
            foreach ($manual_attributes[$section] as $key => $value) {
51
                if ($key === 'type') {
52
                    continue;
53
                }
54
                $options[$key] = $value;
55
            }
56
        }
57
        foreach ($options as $key => $value) {
58
            if (empty($value) || empty($key)) {
59
                continue;
60
            }
61
            if (is_array($value)) {
62
                array_unshift($value, ' ');
63
                $result_config .= trim(implode("\n{$key} = ", $value)) . "\n";
64
            } else {
65
                $result_config .= "{$key} = {$value}\n";
66
            }
67
        }
68
69
        return "$result_config\n";
70
    }
71
72
    /**
73
     * Инициация телефонного звонка.
74
     *
75
     * @param $peer_number
76
     * @param $peer_mobile
77
     * @param $dest_number
78
     *
79
     * @return array
80
     * @throws Exception
81
     */
82
    public static function amiOriginate($peer_number, $peer_mobile, $dest_number): array
83
    {
84
        $am       = self::getAstManager('off');
85
        $channel  = 'Local/' . $peer_number . '@internal-originate';
86
        $context  = 'all_peers';
87
        $IS_ORGNT = self::generateRandomString();
88
        $variable = "_IS_ORGNT={$IS_ORGNT},pt1c_cid={$dest_number},_extenfrom1c={$peer_number},__peer_mobile={$peer_mobile},_FROM_PEER={$peer_number}";
89
90
        return $am->Originate(
91
            $channel,
92
            $dest_number,
93
            $context,
94
            '1',
95
            null,
96
            null,
97
            null,
98
            null,
99
            $variable,
100
            null,
101
            true
102
        );
103
    }
104
105
    /**
106
     * Получаем объект менеджер asterisk.
107
     *
108
     * @param string $events
109
     *
110
     * @return AsteriskManager
111
     */
112
    public static function getAstManager($events = 'on'): AsteriskManager
113
    {
114
        if ($events === 'on') {
115
            $nameService = 'amiListner';
116
        } else {
117
            $nameService = 'amiCommander';
118
        }
119
120
        $di = Di::getDefault();
121
        $am = $di->getShared($nameService);
122
        if (is_resource($am->socket)) {
123
            return $am;
124
        }
125
126
        return $di->get($nameService);
127
    }
128
129
    /**
130
     * Генератор произвольной строки.
131
     *
132
     * @param int $length
133
     *
134
     * @return string
135
     */
136
    public static function generateRandomString($length = 10): string
137
    {
138
        $characters       = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
139
        $charactersLength = strlen($characters);
140
        $randomString     = '';
141
        for ($i = 0; $i < $length; $i++) {
142
            try {
143
                $randomString .= $characters[random_int(0, $charactersLength - 1)];
144
            } catch (Throwable $e) {
145
                $randomString = '';
146
            }
147
        }
148
149
        return $randomString;
150
    }
151
152
    /**
153
     * Json validate
154
     *
155
     * @param $jsonString
156
     *
157
     * @return bool
158
     */
159
    public static function isJson($jsonString): bool
160
    {
161
        json_decode($jsonString, true);
162
163
        return (json_last_error() === JSON_ERROR_NONE);
164
    }
165
166
    /**
167
     *  Возвращает размер файла в Мб.
168
     *
169
     * @param $filename
170
     *
171
     * @return float|int
172
     */
173
    public static function mFileSize($filename)
174
    {
175
        $size = 0;
176
        if (file_exists($filename)) {
177
            $tmp_size = filesize($filename);
178
            if ($tmp_size !== false) {
179
                // Получим размер в Мб.
180
                $size = $tmp_size;
181
            }
182
        }
183
184
        return $size;
185
    }
186
187
    /**
188
     * Возвращает указанное количество X.
189
     *
190
     * @param $length
191
     *
192
     * @return string
193
     */
194
    public static function getExtensionX($length): string
195
    {
196
        $extension = '';
197
        for ($i = 0; $i < $length; $i++) {
198
            $extension .= 'X';
199
        }
200
201
        return $extension;
202
    }
203
204
    /**
205
     * Проверяет существование файла.
206
     *
207
     * @param $filename
208
     *
209
     * @return bool
210
     */
211
    public static function recFileExists($filename): ?bool
212
    {
213
        return (file_exists($filename) && filesize($filename) > 0);
214
    }
215
216
    /**
217
     * Если переданный параметр - число, то будет возвращена дата.
218
     *
219
     * @param $data
220
     *
221
     * @return string
222
     */
223
    public static function numberToDate($data): string
224
    {
225
        $re_number = '/^\d+.\d+$/';
226
        preg_match_all($re_number, $data, $matches, PREG_SET_ORDER, 0);
227
        if (count($matches) > 0) {
228
            $data = date('Y.m.d-H:i:s', $data);
229
        }
230
231
        return $data;
232
    }
233
234
    /**
235
     * Записывает данные в файл.
236
     *
237
     * @param $filename
238
     * @param $data
239
     */
240
    public static function fileWriteContent($filename, $data): void
241
    {
242
        /** @var CustomFiles $res */
243
        $res = CustomFiles::findFirst("filepath = '{$filename}'");
244
245
        $filename_orgn = "{$filename}.orgn";
246
        if (($res === null || $res->mode === 'none') && file_exists($filename_orgn)) {
247
            unlink($filename_orgn);
248
        } elseif ($res !== null && $res->mode !== 'none') {
249
            // Запишем оригинальный файл.
250
            file_put_contents($filename_orgn, $data);
251
        }
252
253
        if ($res === null) {
254
            // Файл еще не зарегистрирован в базе. Сделаем это.
255
            $res = new CustomFiles();
256
            $res->writeAttribute('filepath', $filename);
257
            $res->writeAttribute('mode', 'none');
258
            $res->save();
259
        } elseif ($res->mode === 'append') {
260
            // Добавить к файлу.
261
            $data .= "\n\n";
262
            $data .= base64_decode((string)$res->content);
263
        } elseif ($res->mode === 'override') {
264
            // Переопределить файл.
265
            $data = base64_decode((string)$res->content);
266
        }
267
        file_put_contents($filename, $data);
268
    }
269
270
    /**
271
     * Adds messages to Syslog.
272
     *
273
     * @param string $ident category, class, method
274
     * @param string $message log message
275
     * @param int $level log level https://docs.phalcon.io/4.0/en/logger#constants
276
     *
277
     */
278
    public static function sysLogMsg(string $ident, string $message, $level = LOG_WARNING): void
279
    {
280
        /** @var \Phalcon\Logger $logger */
281
        $logger = Di::getDefault()->getShared(LoggerProvider::SERVICE_NAME);
282
        $logger->log($level, "{$message} on {$ident}" );
283
    }
284
285
    /**
286
     * Возвращает текущую дату в виде строки с точностью до милисекунд.
287
     *
288
     * @return string
289
     */
290
    public static function getNowDate(): ?string
291
    {
292
        $result = null;
293
        try {
294
            $d      = new DateTime();
295
            $result = $d->format("Y-m-d H:i:s.v");
296
        } catch (Exception $e) {
297
            unset($e);
298
        }
299
300
        return $result;
301
    }
302
303
    /**
304
     * Получает расширение файла.
305
     *
306
     * @param        $filename
307
     *
308
     * @return mixed
309
     */
310
    public static function getExtensionOfFile($filename)
311
    {
312
        $path_parts = pathinfo($filename);
313
314
        return $path_parts['extension'] ?? '';
315
    }
316
317
    /**
318
     * Удаляет расширение файла.
319
     *
320
     * @param        $filename
321
     * @param string $delimiter
322
     *
323
     * @return string
324
     */
325
    public static function trimExtensionForFile($filename, $delimiter = '.'): string
326
    {
327
        // Отсечем расширение файла.
328
        $tmp_arr = explode((string)$delimiter, $filename);
329
        if (count($tmp_arr) > 1) {
330
            unset($tmp_arr[count($tmp_arr) - 1]);
331
            $filename = implode((string)$delimiter, $tmp_arr);
332
        }
333
334
        return $filename;
335
    }
336
337
    /**
338
     * Получаем размер файла / директории.
339
     *
340
     * @param $filename
341
     *
342
     * @return float
343
     */
344
    public static function getSizeOfFile($filename): float
345
    {
346
        $result = 0;
347
        if (file_exists($filename)) {
348
            $duPath  = self::which('du');
349
            $awkPath = self::which('awk');
350
            Processes::mwExec("{$duPath} -d 0 -k '{$filename}' | {$awkPath}  '{ print $1}'", $out);
351
            $time_str = implode($out);
352
            preg_match_all('/^\d+$/', $time_str, $matches, PREG_SET_ORDER, 0);
353
            if (count($matches) > 0) {
354
                $result = round(1 * $time_str / 1024, 2);
355
            }
356
        }
357
358
        return $result;
359
    }
360
361
    /**
362
     * Return full path to executable binary
363
     *
364
     * @param string $cmd - name of file
365
     *
366
     * @return string
367
     */
368
    public static function which(string $cmd): string
369
    {
370
        global $_ENV;
371
        if (array_key_exists('PATH', $_ENV)) {
372
            $binaryFolders = $_ENV['PATH'];
373
374
            foreach (explode(':', $binaryFolders) as $path) {
375
                if (is_executable("{$path}/{$cmd}")) {
376
                    return "{$path}/{$cmd}";
377
                }
378
            }
379
        }
380
        $binaryFolders =
381
            [
382
                '/bin',
383
                '/sbin',
384
                '/usr/bin',
385
                '/usr/sbin',
386
                '/usr/local/bin',
387
                '/usr/local/sbin',
388
            ];
389
        foreach ($binaryFolders as $path) {
390
            if (is_executable("{$path}/{$cmd}")) {
391
                return "{$path}/{$cmd}";
392
            }
393
        }
394
395
        return $cmd;
396
    }
397
398
    /**
399
     * DEPRICATED
400
     * Executes command exec().
401
     *
402
     * @param $command
403
     * @param $outArr
404
     * @param $retVal
405
     *
406
     * @return int
407
     */
408
    public static function mwExec($command, &$outArr = null, &$retVal = null): int
409
    {
410
        self::sysLogMsg('Util', 'Deprecated call ' . __METHOD__ . ' from ' . static::class, LOG_DEBUG);
411
412
        return Processes::mwExec($command, $outArr, $retVal);
413
    }
414
415
    /**
416
     * Устанавливаем шрифт для консоли.
417
     */
418
    public static function setCyrillicFont(): void
419
    {
420
        $setfontPath = self::which('setfont');
421
        Processes::mwExec("{$setfontPath} /usr/share/consolefonts/Cyr_a8x16.psfu.gz 2>/dev/null");
422
    }
423
424
    /**
425
     * Получить перевод строки текста.
426
     * @param string $text
427
     * @param bool   $cliLang
428
     * @return string
429
     */
430
    public static function translate(string $text, bool $cliLang = true):string
431
    {
432
        $di = Di::getDefault();
433
        if ($di !== null) {
434
            if(!$cliLang){
435
                $di->setShared('PREFERRED_LANG_WEB', true);
436
            }
437
            $text = $di->getShared(TranslationProvider::SERVICE_NAME)->_($text);
438
            if(!$cliLang){
439
                $di->remove('PREFERRED_LANG_WEB');
440
            }
441
        }
442
        return $text;
443
    }
444
445
    /**
446
     *
447
     * Delete a directory RECURSIVELY
448
     *
449
     * @param string $dir - directory path
450
     *
451
     * @link http://php.net/manual/en/function.rmdir.php
452
     */
453
    public static function rRmDir(string $dir): void
454
    {
455
        if (is_dir($dir)) {
456
            $objects = scandir($dir);
457
            foreach ($objects as $object) {
458
                if ($object != "." && $object != "..") {
459
                    if (filetype($dir . "/" . $object) == "dir") {
460
                        self::rRmDir($dir . "/" . $object);
461
                    } else {
462
                        unlink($dir . "/" . $object);
463
                    }
464
                }
465
            }
466
            if ($objects !== false) {
467
                reset($objects);
468
            }
469
            rmdir($dir);
470
        }
471
    }
472
473
    /**
474
     * Генерация сертификата средствами openssl.
475
     *
476
     * @param ?array $options
477
     * @param ?array $config_args_pkey
478
     * @param ?array $config_args_csr
479
     *
480
     * @return array
481
     */
482
    public static function generateSslCert($options = null, $config_args_pkey = null, $config_args_csr = null): array
483
    {
484
        // Инициализация настроек.
485
        if ( ! $options) {
486
            $options = [
487
                "countryName"            => 'RU',
488
                "stateOrProvinceName"    => 'Moscow',
489
                "localityName"           => 'Zelenograd',
490
                "organizationName"       => 'MIKO LLC',
491
                "organizationalUnitName" => 'Software development',
492
                "commonName"             => 'MIKO PBX',
493
                "emailAddress"           => '[email protected]',
494
            ];
495
        }
496
497
        if ( ! $config_args_csr) {
498
            $config_args_csr = ['digest_alg' => 'sha256'];
499
        }
500
501
        if ( ! $config_args_pkey) {
502
            $config_args_pkey = [
503
                "private_key_bits" => 2048,
504
                "private_key_type" => OPENSSL_KEYTYPE_RSA,
505
            ];
506
        }
507
508
        // Генерация ключей.
509
        $private_key = openssl_pkey_new($config_args_pkey);
510
        $csr         = openssl_csr_new($options, $private_key, $config_args_csr);
0 ignored issues
show
Bug introduced by
It seems like $private_key can also be of type resource; however, parameter $private_key of openssl_csr_new() does only seem to accept OpenSSLAsymmetricKey, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

510
        $csr         = openssl_csr_new($options, /** @scrutinizer ignore-type */ $private_key, $config_args_csr);
Loading history...
511
        $x509        = openssl_csr_sign($csr, null, $private_key, $days = 3650, $config_args_csr);
512
513
        // Экспорт ключей.
514
        openssl_x509_export($x509, $certout);
515
        openssl_pkey_export($private_key, $pkeyout);
516
        // echo $pkeyout; // -> WEBHTTPSPrivateKey
517
        // echo $certout; // -> WEBHTTPSPublicKey
518
        return ['PublicKey' => $certout, 'PrivateKey' => $pkeyout];
519
    }
520
521
    /**
522
     * @return bool
523
     */
524
    public static function isSystemctl(): bool
525
    {
526
        return (stripos(php_uname('v'), 'debian') !== false);
527
    }
528
529
    /**
530
     * @return bool
531
     */
532
    public static function isDocker(): bool
533
    {
534
        return file_exists('/.dockerenv');
535
    }
536
537
    /**
538
     * Вывод в основной teletype.
539
     * @param string $message
540
     * @param string $ttyPath
541
     * @return void
542
     */
543
    public static function teletypeEcho(string $message, string $ttyPath = '/dev/ttyS0'):void
544
    {
545
        $pathBusyBox    = self::which('busybox');
546
        $ttyTittle      = trim(shell_exec("$pathBusyBox setserial -g $ttyPath 2> /dev/null"));
547
        if(strpos($ttyTittle, $ttyPath) !== false && strpos($ttyTittle, 'unknown') === false){
548
            @file_put_contents($ttyPath, $message, FILE_APPEND);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for file_put_contents(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

548
            /** @scrutinizer ignore-unhandled */ @file_put_contents($ttyPath, $message, FILE_APPEND);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
549
        }
550
    }
551
552
    /**
553
     * Вывод DONE / FAIL основной teletype.
554
     * @param $result
555
     * @return void
556
     */
557
    public static function teletypeEchoDone(string $message, $result):void
558
    {
559
        $len    = max(0, 80 - strlen($message) - 9);
560
        $spaces = str_repeat('.', $len);
561
        if($result === false){
562
            $message = " \033[31;1mFAIL\033[0m \n";
563
        }else{
564
            $message = " \033[32;1mDONE\033[0m \n";
565
        }
566
        self::teletypeEcho($spaces.$message);
567
    }
568
569
    /**
570
     * Выводить текстовое сообщение "done" подсвечивает зеленым цветом.
571
     */
572
    public static function echoDone(bool $result=true): void
573
    {
574
        if($result === false){
575
            echo "\033[31;1mFAIL\033[0m \n";
576
        }else{
577
            echo "\033[32;1mDONE\033[0m \n";
578
        }
579
    }
580
581
    public static function echoResult(string $message, bool $result = true):void
582
    {
583
        $cols   = self::getCountCols();
584
        if(!is_numeric($cols)){
585
            // Не удалось получить ширину экрана.
586
            return;
587
        }
588
        $len = $cols - strlen($message) - 8;
589
        if($len < 2){
590
            // Не корректная ширина экрана.
591
            return;
592
        }
593
594
        $spaces = str_repeat('.', $len);
595
        echo "\r".$message.$spaces;
596
        self::echoDone($result);
597
    }
598
599
    public static function getCountCols():string
600
    {
601
        $len = 1*trim(shell_exec('tput cols'));
602
        if($len === 0){
603
            $len = 80;
604
        }else{
605
            $len = min($len, 80);
606
        }
607
        return $len;
608
    }
609
610
    /**
611
     * Создание символической ссылки, если необходимо.
612
     *
613
     * @param $target
614
     * @param $link
615
     * @param bool $isFile
616
     *
617
     * @return bool
618
     */
619
    public static function createUpdateSymlink($target, $link, $isFile=false): bool
620
    {
621
        $need_create_link = true;
622
        if (is_link($link)) {
623
            $old_target       = readlink($link);
624
            $need_create_link = ($old_target != $target);
625
            // Если необходимо, удаляем старую ссылку.
626
            if ($need_create_link) {
627
                $cpPath = self::which('cp');
628
                Processes::mwExec("{$cpPath} {$old_target}/* {$target}");
629
                unlink($link);
630
            }
631
        } elseif (is_dir($link)) {
632
            // Это должна быть именно ссылка. Файл удаляем.
633
            rmdir($link);
634
        } elseif (file_exists($link)) {
635
            // Это должна быть именно ссылка. Файл удаляем.
636
            unlink($link);
637
        }
638
        if($isFile === false){
639
            self::mwMkdir($target);
640
        }
641
        if ($need_create_link) {
642
            $lnPath = self::which('ln');
643
            Processes::mwExec("{$lnPath} -s {$target}  {$link}");
644
        }
645
646
        return $need_create_link;
647
    }
648
649
    /**
650
     * Create folder if it not exist.
651
     *
652
     * @param      $parameters string one or multiple paths separated by space
653
     *
654
     * @param bool $addWWWRights
655
     *
656
     * @return bool
657
     */
658
    public static function mwMkdir(string $parameters, bool $addWWWRights = false): bool
659
    {
660
        $result = true;
661
        if (posix_getuid() === 0) {
662
            $arrPaths = explode(' ', $parameters);
663
            if (count($arrPaths) > 0) {
664
                foreach ($arrPaths as $path) {
665
                    if ( ! empty($path)
666
                        && ! file_exists($path)
667
                        && ! mkdir($path, 0755, true)
668
                        && ! is_dir($path)) {
669
                        $result = false;
670
                        self::sysLogMsg('Util', 'Error on create folder ' . $path, LOG_ERR);
671
                    }
672
                    if ($addWWWRights) {
673
                        self::addRegularWWWRights($path);
674
                    }
675
                }
676
            }
677
        }
678
679
        return $result;
680
    }
681
682
    /**
683
     * Apply regular rights for folders and files
684
     *
685
     * @param $folder
686
     */
687
    public static function addRegularWWWRights($folder): void
688
    {
689
        if (posix_getuid() === 0) {
690
            $findPath  = self::which('find');
691
            $chownPath = self::which('chown');
692
            $chmodPath = self::which('chmod');
693
            Processes::mwExec("{$findPath} {$folder} -type d -exec {$chmodPath} 755 {} \;");
694
            Processes::mwExec("{$findPath} {$folder} -type f -exec {$chmodPath} 644 {} \;");
695
            Processes::mwExec("{$chownPath} -R www:www {$folder}");
696
        }
697
    }
698
699
    /**
700
     * Print message and write it to syslog
701
     *
702
     * @param $message
703
     */
704
    public static function echoWithSyslog($message): void
705
    {
706
        echo $message;
707
        self::sysLogMsg(static::class, $message, LOG_INFO);
708
    }
709
710
    /**
711
     * Apply executable rights for files
712
     *
713
     * @param $folder
714
     */
715
    public static function addExecutableRights($folder): void
716
    {
717
        if (posix_getuid() === 0) {
718
            $findPath  = self::which('find');
719
            $chmodPath = self::which('chmod');
720
            Processes::mwExec("{$findPath} {$folder} -type f -exec {$chmodPath} 755 {} \;");
721
        }
722
    }
723
724
    /**
725
     * Разбор INI конфига
726
     *
727
     * @param string $manual_attributes
728
     *
729
     * @return array
730
     */
731
    public static function parseIniSettings(string $manual_attributes): array
732
    {
733
        $tmp_data = base64_decode($manual_attributes);
734
        if (base64_encode($tmp_data) === $manual_attributes) {
735
            $manual_attributes = $tmp_data;
736
        }
737
        unset($tmp_data);
738
        // TRIMMING
739
        $tmp_arr = explode("\n", $manual_attributes);
740
        foreach ($tmp_arr as &$row) {
741
            $row = trim($row);
742
            $pos = strpos($row, ']');
743
            if ($pos !== false && strpos($row, '[') === 0) {
744
                $row = "\n" . substr($row, 0, $pos);
745
            }
746
        }
747
        unset($row);
748
        $manual_attributes = implode("\n", $tmp_arr);
749
        // TRIMMING END
750
751
        $manual_data = [];
752
        $sections    = explode("\n[", str_replace(']', '', $manual_attributes));
753
        foreach ($sections as $section) {
754
            $data_rows    = explode("\n", trim($section));
755
            $section_name = trim($data_rows[0] ?? '');
756
            if ( ! empty($section_name)) {
757
                unset($data_rows[0]);
758
                $manual_data[$section_name] = [];
759
                foreach ($data_rows as $row) {
760
                    $value = '';
761
                    if (strpos($row, '=') === false) {
762
                        continue;
763
                    }
764
                    $key       = '';
765
                    $arr_value = explode('=', $row);
766
                    if (count($arr_value) > 1) {
767
                        $key = trim($arr_value[0]);
768
                        unset($arr_value[0]);
769
                        $value = trim(implode('=', $arr_value));
770
                    }
771
                    if ( ($value !== '0' && empty($value)) || empty($key)) {
772
                        continue;
773
                    }
774
                    $manual_data[$section_name][$key] = $value;
775
                }
776
            }
777
        }
778
779
        return $manual_data;
780
    }
781
782
    /**
783
     * Converts multidimensional array into single array
784
     *
785
     * @param $array
786
     *
787
     * @return array
788
     */
789
    public static function flattenArray(array $array)
790
    {
791
        $result = [];
792
        foreach ($array as $value) {
793
            if (is_array($value)) {
794
                $result = array_merge($result, self::flattenArray($value));
795
            } else {
796
                $result[] = $value;
797
            }
798
        }
799
800
        return $result;
801
    }
802
803
    /**
804
     * Try to find full path to php file by class name
805
     *
806
     * @param $className
807
     *
808
     * @return string|null
809
     */
810
    public static function getFilePathByClassName($className): ?string
811
    {
812
        $filename = null;
813
        try {
814
            $reflection = new ReflectionClass($className);
815
            $filename   = $reflection->getFileName();
816
        } catch (ReflectionException $exception) {
817
            self::sysLogMsg(__METHOD__, 'ReflectionException ' . $exception->getMessage(), LOG_ERR);
818
        }
819
820
        return $filename;
821
    }
822
823
    /**
824
     * DEPRICATED
825
     * Возвращает PID процесса по его имени.
826
     *
827
     * @param        $name
828
     * @param string $exclude
829
     *
830
     * @return string
831
     */
832
    public static function getPidOfProcess($name, $exclude = ''): string
833
    {
834
        self::sysLogMsg('Util', 'Deprecated call ' . __METHOD__ . ' from ' . static::class, LOG_DEBUG);
835
836
        return Processes::getPidOfProcess($name, $exclude);
837
    }
838
839
    /**
840
     * DEPRICATED
841
     * Manages a daemon/worker process
842
     * Returns process statuses by name of it
843
     *
844
     * @param $cmd
845
     * @param $param
846
     * @param $proc_name
847
     * @param $action
848
     * @param $out_file
849
     *
850
     * @return array | bool
851
     */
852
    public static function processWorker($cmd, $param, $proc_name, $action, $out_file = '/dev/null')
853
    {
854
        self::sysLogMsg('Util', 'Deprecated call ' . __METHOD__ . ' from ' . static::class, LOG_DEBUG);
855
856
        return Processes::processWorker($cmd, $param, $proc_name, $action, $out_file);
857
    }
858
859
    /**
860
     * DEPRICATED
861
     * Process PHP workers
862
     *
863
     * @param string $className
864
     * @param string $param
865
     * @param string $action
866
     */
867
    public static function processPHPWorker(
868
        string $className,
869
        string $param = 'start',
870
        string $action = 'restart'
871
    ): void {
872
        self::sysLogMsg('Util', 'Deprecated call ' . __METHOD__ . ' from ' . static::class, LOG_DEBUG);
873
        Processes::processPHPWorker($className, $param, $action);
874
    }
875
876
    /**
877
     * DEPRICATED
878
     * Kills process/daemon by name
879
     *
880
     * @param $procName
881
     *
882
     * @return int|null
883
     */
884
    public static function killByName($procName): ?int
885
    {
886
        self::sysLogMsg('Util', 'Deprecated call ' . __METHOD__ . ' from ' . static::class, LOG_DEBUG);
887
888
        return Processes::killByName($procName);
889
    }
890
891
    /**
892
     * DEPRICATED
893
     * Executes command exec() as background process.
894
     *
895
     * @param $command
896
     * @param $out_file
897
     * @param $sleep_time
898
     */
899
    public static function mwExecBg($command, $out_file = '/dev/null', $sleep_time = 0): void
900
    {
901
        self::sysLogMsg('Util', 'Deprecated call ' . __METHOD__ . ' from ' . static::class, LOG_DEBUG);
902
        Processes::mwExecBg($command, $out_file, $sleep_time);
903
    }
904
905
    /**
906
     * DEPRICATED
907
     * Executes command exec() as background process with an execution timeout.
908
     *
909
     * @param        $command
910
     * @param int    $timeout
911
     * @param string $logname
912
     */
913
    public static function mwExecBgWithTimeout($command, $timeout = 4, $logname = '/dev/null'): void
914
    {
915
        self::sysLogMsg('Util', 'Deprecated call ' . __METHOD__ . ' from ' . static::class, LOG_DEBUG);
916
        Processes::mwExecBgWithTimeout($command, $timeout, $logname);
917
    }
918
919
    /**
920
     * DEPRICATED
921
     * Executes multiple commands.
922
     *
923
     * @param        $arr_cmds
924
     * @param array  $out
925
     * @param string $logname
926
     */
927
    public static function mwExecCommands($arr_cmds, &$out = [], $logname = ''): void
928
    {
929
        self::sysLogMsg('Util', 'Deprecated call ' . __METHOD__ . ' from ' . static::class, LOG_DEBUG);
930
        Processes::mwExecCommands($arr_cmds, $out, $logname);
931
    }
932
933
    /**
934
     * Добавляем задачу для уведомлений.
935
     *
936
     * @param string $tube
937
     * @param        $data
938
     */
939
    public function addJobToBeanstalk(string $tube, $data): void
940
    {
941
        $queue = new BeanstalkClient($tube);
942
        $queue->publish(json_encode($data));
943
    }
944
945
946
}