1<?php
2///////////////////////////////////////////////////////////////////////////////
3//
4// NagiosQL
5//
6///////////////////////////////////////////////////////////////////////////////
7//
8// (c) 2005-2020 by Martin Willisegger
9//
10// Project   : NagiosQL
11// Component : Configuration Class
12// Website   : https://sourceforge.net/projects/nagiosql/
13// Version   : 3.4.1
14// GIT Repo  : https://gitlab.com/wizonet/NagiosQL
15//
16///////////////////////////////////////////////////////////////////////////////////////////////
17//
18///////////////////////////////////////////////////////////////////////////////////////////////
19//
20// Class: Configuration class
21//
22///////////////////////////////////////////////////////////////////////////////////////////////
23//
24// Includes all functions used for handling configuration files with NagiosQL
25//
26// Name: NagConfigClass
27//
28///////////////////////////////////////////////////////////////////////////////////////////////
29namespace functions;
30
31class NagConfigClass
32{
33    // Define class variables
34    /** @var resource $resConnectId */
35    public $resConnectId;                       // Connection id for FTP and SSH connections
36    public $resSFTP;                            // SFTP ressource id
37
38    public $arrSession           = array();     // Session content
39    public $strRelTable          = '';          // Relation table name
40    public $strErrorMessage      = '';          // String including error messages
41    public $strInfoMessage       = '';          // String including information messages
42    public $strPicPath           = 'none';      // Picture path string
43    public $intNagVersion        = 0;           // Nagios version id
44    public $intDomainId          = 0;           // Configuration domain ID
45    // PRIVATE
46    private $arrSettings         = array();     // Array includes all global settings
47    private $resConnectServer    = '';          // Connection server name for FTP and SSH connections
48    private $resConnectType      = 'none';      // Connection type for FTP and SSH connections
49    private $arrRelData          = '';          // Relation data
50    // Class includes
51    /** @var MysqliDbClass */
52    public $myDBClass;                          // Database class reference
53    /** @var NagDataClass */
54    public $myDataClass;                        // Data processing class reference
55
56    /**
57     * NagConfigClass constructor.
58     * @param array $arrSession                 PHP Session array
59     */
60    public function __construct($arrSession)
61    {
62        if (isset($arrSession['SETS'])) {
63            // Read global settings
64            $this->arrSettings = $arrSession['SETS'];
65        }
66        if (isset($arrSession['domain'])) {
67            $this->intDomainId = $arrSession['domain'];
68        }
69        $this->arrSession = $arrSession;
70    }
71
72    /**
73     * Get domain configuration parameters.
74     * @param string $strConfigItem             Configuration key
75     * @param string $strValue                  Configuration value (by reference)
76     * @return int                              0 = successful / 1 = error
77     */
78    public function getDomainData($strConfigItem, &$strValue)
79    {
80        // Variable definition
81        $intReturn = 0;
82        // Request domain data from database
83        $strSQL   = 'SELECT `' .$strConfigItem. '` FROM `tbl_datadomain` WHERE `id` = ' .$this->intDomainId;
84        $strValue = $this->myDBClass->getFieldData($strSQL);
85        if ($strValue == '') {
86            $intReturn = 1;
87        }
88        return $intReturn;
89    }
90
91    /**
92     * Get last modification date of a database table and any configuration files inside a directory.
93     * @param string $strTableName              Name of the database table
94     * @param string $strConfigName             Name of the configuration file
95     * @param int $intDataId                    ID of the dataset for service table
96     * @param array $arrTimeData                Array with the timestamps of the files and the DB table (by reference)
97     * @param int $intTimeInfo                  Time status value (by reference)
98     *                                          0 = all files are newer than the database item
99     *                                          1 = some file are older than the database item
100     *                                          2 = one file is missing
101     *                                          3 = any files are missing
102     *                                          4 = no configuration targets defined
103     * @return int                              0 = successful / 1 = error
104     *                                          Status messages are stored in class variables
105     */
106    public function lastModifiedDir($strTableName, $strConfigName, $intDataId, &$arrTimeData, &$intTimeInfo)
107    {
108        // Variable definitions
109        $intReturn       = 0;
110        // Create file name
111        $strFileName  = $strConfigName. '.cfg';
112        // Get table times
113        $strActive            = 0;
114        $arrTimeData          = array();
115        $arrTimeData['table'] = 'unknown';
116        // Clear status cache
117        clearstatcache();
118        // Get last change on dataset
119        if ($strTableName == 'tbl_host') {
120            $strSQL1 = "SELECT DATE_FORMAT(`last_modified`,'%Y-%m-%d %H:%i:%s') FROM `tbl_host` ".
121                "WHERE `host_name`='$strConfigName' AND `config_id`=".$this->intDomainId;
122            $strSQL2 = "SELECT `active` FROM `tbl_host`  WHERE `host_name`='$strConfigName' ".
123                'AND `config_id`=' .$this->intDomainId;
124            $arrTimeData['table'] = $this->myDBClass->getFieldData($strSQL1);
125            $strActive            = $this->myDBClass->getFieldData($strSQL2);
126        } elseif ($strTableName == 'tbl_service') {
127            $strSQL1 = "SELECT DATE_FORMAT(`last_modified`,'%Y-%m-%d %H:%i:%s') FROM `tbl_service` ".
128                "WHERE `id`='$intDataId' AND `config_id`=".$this->intDomainId;
129            $strSQL2 = "SELECT * FROM `$strTableName` WHERE `config_name`='$strConfigName' ".
130                'AND `config_id`=' .$this->intDomainId." AND `active`='1'";
131            $arrTimeData['table'] = $this->myDBClass->getFieldData($strSQL1);
132            $intServiceCount      = $this->myDBClass->countRows($strSQL2);
133            if ($intServiceCount != 0) {
134                $strActive = 1;
135            }
136        } else {
137            $intReturn = 1;
138        }
139        // Get config sets
140        $arrConfigId      = array();
141        $strTarget        = '';
142        $strBaseDir       = '';
143        $intTimeInfo      = -1;
144        $intRetVal2  = $this->getConfigTargets($arrConfigId);
145        if ($intRetVal2 == 0) {
146            foreach ($arrConfigId as $intConfigId) {
147                // Get configuration file data
148                $this->getConfigValues($intConfigId, 'target', $strTarget);
149                // Get last change on dataset
150                if ($strTableName == 'tbl_host') {
151                    $this->getConfigValues($intConfigId, 'hostconfig', $strBaseDir);
152                } elseif ($strTableName == 'tbl_service') {
153                    $this->getConfigValues($intConfigId, 'serviceconfig', $strBaseDir);
154                }
155                $arrTimeData[$strTarget] = 'unknown';
156                $intFileStampTemp        = -1;
157                // Get time data
158                $intReturn = $this->getFileDate(
159                    $intConfigId,
160                    $strFileName,
161                    $strBaseDir,
162                    $intFileStampTemp,
163                    $arrTimeData[$strTarget]
164                );
165                if (($intFileStampTemp == 0) && ($strActive == '1')) {
166                    $intTimeInfo = 2;
167                }
168                if (($strActive == '1') && (strtotime($arrTimeData['table']) > $intFileStampTemp)) {
169                    $intTimeInfo = 1;
170                }
171            }
172            $intItems    = \count($arrTimeData) - 1;
173            $intUnknown  = 0;
174            $intUpToDate = 0;
175            foreach ($arrTimeData as $key) {
176                if ($key == 'unknown') {
177                    $intUnknown++;
178                }
179                if (strtotime($arrTimeData['table']) < strtotime($key)) {
180                    $intUpToDate++;
181                }
182            }
183            if ($intUnknown  == $intItems) {
184                $intTimeInfo = 3;
185            }
186            if ($intUpToDate == $intItems) {
187                $intTimeInfo = 0;
188            }
189        } else {
190            $intTimeInfo = 4;
191        }
192        return $intReturn;
193    }
194
195    /**
196     * Get configuration target IDs
197     * @param array $arrConfigId                Configuration target IDs (by reference)
198     * @return int                              0 = successful / 1 = error
199     */
200    public function getConfigTargets(&$arrConfigId)
201    {
202        // Variable definition
203        $arrData      = array();
204        $arrConfigId  = array();
205        $intDataCount = 0;
206        $intReturn    = 1;
207        // Request target ID
208        $strSQL    = 'SELECT `targets` FROM `tbl_datadomain` WHERE `id`=' .$this->intDomainId;
209        $booReturn = $this->myDBClass->hasDataArray($strSQL, $arrData, $intDataCount);
210        if ($booReturn && ($intDataCount != 0)) {
211            foreach ($arrData as $elem) {
212                $arrConfigId[] = $elem['targets'];
213            }
214            $intReturn = 0;
215        }
216        return $intReturn;
217    }
218
219    /**
220     * Get configuration domain values
221     * @param int $intConfigId                  Configuration ID
222     * @param string $strConfigKey              Configuration key
223     * @param string $strValue                  Configuration value (by reference)
224     * @return int                              0 = successful / 1 = error
225     */
226    public function getConfigValues($intConfigId, $strConfigKey, &$strValue)
227    {
228        // Define variables
229        $intReturn = 1;
230        // Read database
231        $strSQL    = 'SELECT `' .$strConfigKey. '` FROM `tbl_configtarget` WHERE `id`=' .$intConfigId;
232        $strValue  = $this->myDBClass->getFieldData($strSQL);
233        if ($strValue != '') {
234            $intReturn = 0;
235        }
236        return $intReturn;
237    }
238
239    /**
240     * Get last modification date of a configuration file.
241     * @param int $intConfigId                  Configuration ID
242     * @param string $strFile                   Configuration file name
243     * @param string $strBaseDir                Base directory with configuration file
244     * @param int|bool $intFileStamp            File timestamp (by reference)
245     * @param string $strTimeData               Human readable string of file time stamp (by reference)
246     * @return int                              0 = successful / 1 = error
247     */
248    public function getFileDate($intConfigId, $strFile, $strBaseDir, &$intFileStamp, &$strTimeData)
249    {
250        $strMethod  = 1;
251        $intReturn  = 0;
252        // Get configuration file data
253        $this->getConfigValues($intConfigId, 'method', $strMethod);
254        $strTimeData  = 'unknown';
255        $intFileStamp = -1;
256        // Lokal file system
257        if (($strMethod == 1) && file_exists($strBaseDir. '/' .$strFile)) {
258            $intFileStamp = filemtime($strBaseDir. '/' .$strFile);
259            $strTimeData = date('Y-m-d H:i:s', $intFileStamp);
260        } elseif ($strMethod == 2) { // FTP file system
261            // Check connection
262            $intReturn = $this->getFTPConnection($intConfigId);
263            if ($intReturn == 0) {
264                $intFileStamp = ftp_mdtm($this->resConnectId, $strBaseDir . '/' . $strFile);
265                if ($intFileStamp != -1) {
266                    $strTimeData = date('Y-m-d H:i:s', $intFileStamp);
267                }
268            }
269        } elseif ($strMethod == 3) { // SSH file system
270            // Check connection
271            $intReturn = $this->getSSHConnection($intConfigId);
272            // Check file date
273            $strFilePath = str_replace('//', '/', $strBaseDir.'/'.$strFile);
274            $strCommand  = 'ls '.$strFilePath;
275            $arrResult   =  array();
276            if (($intReturn == 0) && ($this->sendSSHCommand($strCommand, $arrResult) == 0) &&
277                isset($arrResult[0]) && ($arrResult[0] == $strFilePath)) {
278                $arrInfo      = ssh2_sftp_stat($this->resSFTP, $strFilePath);
279                $intFileStamp = $arrInfo['mtime'];
280                if ($intFileStamp != -1) {
281                    $strTimeData = date('Y-m-d H:i:s', $intFileStamp);
282                }
283            }
284        }
285        return $intReturn;
286    }
287
288    /**
289     * Open an FTP connection
290     * @param int $intConfigID                  Configuration ID
291     * @return int                              0 = successful / 1 = error
292     *                                          Status messages are stored in class variables
293     */
294    public function getFTPConnection($intConfigID)
295    {
296        // Define variables
297        $intReturn = 0;
298        $arrError  = array();
299        // Already connected?
300        if (empty($this->resConnectId) || !\is_resource($this->resConnectId) || ($this->resConnectType != 'FTP')) {
301            // Define variables
302            $booLogin = false;
303            $this->getConfigValues($intConfigID, 'server', $strServer);
304            $this->getConfigValues($intConfigID, 'ftp_secure', $intFtpSecure);
305            // Set up basic connection
306            $this->resConnectServer = $strServer;
307            $this->resConnectType = 'FTP';
308            // Secure FTP?
309            if ($intFtpSecure == 1) {
310                $this->resConnectId = ftp_ssl_connect($strServer);
311            } else {
312                $this->resConnectId = ftp_connect($strServer);
313            }
314            // Login with username and password
315            if ($this->resConnectId) {
316                $this->getConfigValues($intConfigID, 'user', $strUser);
317                $this->getConfigValues($intConfigID, 'password', $strPasswd);
318                $intErrorReporting = error_reporting();
319                error_reporting('0');
320                $booLogin = ftp_login($this->resConnectId, $strUser, $strPasswd);
321                $arrError = error_get_last();
322                error_reporting($intErrorReporting);
323                if ($booLogin == false) {
324                    ftp_close($this->resConnectId);
325                    $this->resConnectServer = '';
326                    $this->resConnectType   = 'none';
327                    $this->resConnectId     = null;
328                    $intReturn = 1;
329                } else {
330                    // Change to PASV mode
331                    ftp_pasv($this->resConnectId, true);
332                }
333            }
334            // Check connection
335            if ((!$this->resConnectId) || (!$booLogin)) {
336                $this->myDataClass->writeLog(translate('Connection to remote system failed (FTP connection):') .
337                    ' ' . $strServer);
338                $this->processClassMessage(translate('Connection to remote system failed (FTP connection):') .
339                    ' <b>' . $strServer . '</b>::', $this->strErrorMessage);
340                if ($arrError !== null && ($arrError['message'] != '')) {
341                    $this->processClassMessage($arrError['message'] . '::', $this->strErrorMessage);
342                }
343            }
344        }
345        return $intReturn;
346    }
347
348    /**
349     * Open an SSH connection
350     * @param int $intConfigID                  Configuration ID
351     * @return int                              0 = successful / 1 = error
352     *                                          Status messages are stored in class variables
353     */
354    public function getSSHConnection($intConfigID)
355    {
356        // Define variables
357        $intReturn       = 0;
358        $strPasswordNote = '';
359        // Already connected?
360        if (empty($this->resConnectId) || !\is_resource($this->resConnectId) || ($this->resConnectType != 'SSH')) {
361            // SSH Possible
362            if (!\function_exists('ssh2_connect')) {
363                $this->processClassMessage(translate('SSH module not loaded!'). '::', $this->strErrorMessage);
364                return 1;
365            }
366            // Define variables
367            $booLogin = false;
368            $this->getConfigValues($intConfigID, 'server', $strServer);
369            $this->getConfigValues($intConfigID, 'port', $intPort);
370            $this->resConnectServer = $strServer;
371            $this->resConnectType   = 'SSH';
372            $intPort = (int)$intPort;
373            if ($intPort == 0) {
374                $intPort = 22;
375            }
376            $intErrorReporting  = error_reporting();
377            error_reporting(0);
378            $this->resConnectId = ssh2_connect($strServer, $intPort);
379            $arrError = error_get_last();
380            error_reporting($intErrorReporting);
381            // Check connection
382            if ($this->resConnectId) {
383                // Login with username and password
384                $this->getConfigValues($intConfigID, 'user', $strUser);
385                $this->getConfigValues($intConfigID, 'password', $strPasswd);
386                $this->getConfigValues($intConfigID, 'ssh_key_path', $strSSHKeyPath);
387                if ($strSSHKeyPath != '') {
388                    $strPublicKey = str_replace('//', '/', $strSSHKeyPath.'/id_rsa.pub');
389                    $strPrivatKey = str_replace('//', '/', $strSSHKeyPath.'/id_rsa');
390                    // Check if ssh key file are readable
391                    if (!file_exists($strPublicKey) || !is_readable($strPublicKey)) {
392                        $this->myDataClass->writeLog(translate('SSH public key does not exist or is not readable')
393                            . ' ' . $strSSHKeyPath.$strPublicKey);
394                        $this->processClassMessage(translate('SSH public key does not exist or is not readable')
395                            . ' <b>' . $strSSHKeyPath.$strPublicKey. '</b>::', $this->strErrorMessage);
396                        $intReturn = 1;
397                    }
398                    if (!file_exists($strPrivatKey) || !is_readable($strPrivatKey)) {
399                        $this->myDataClass->writeLog(translate('SSH private key does not exist or is not readable')
400                            . ' ' . $strPrivatKey);
401                        $this->processClassMessage(translate('SSH private key does not exist or is not readable'). ' ' .
402                            $strPrivatKey. '::', $this->strErrorMessage);
403                        $intReturn = 1;
404                    }
405                    $intErrorReporting  = error_reporting();
406                    error_reporting(0);
407                    if ($strPasswd == '') {
408                        $booLogin = ssh2_auth_pubkey_file(
409                            $this->resConnectId,
410                            $strUser,
411                            $strSSHKeyPath. '/id_rsa.pub',
412                            $strSSHKeyPath. '/id_rsa'
413                        );
414                    } else {
415                        $booLogin = ssh2_auth_pubkey_file(
416                            $this->resConnectId,
417                            $strUser,
418                            $strSSHKeyPath. '/id_rsa.pub',
419                            $strSSHKeyPath. '/id_rsa',
420                            $strPasswd
421                        );
422                    }
423                    $arrError = error_get_last();
424                    error_reporting($intErrorReporting);
425                } else {
426                    $intErrorReporting  = error_reporting();
427                    error_reporting(0);
428                    $booLogin        = ssh2_auth_password($this->resConnectId, $strUser, $strPasswd);
429                    $arrError        = error_get_last();
430                    $strPasswordNote = 'If you are using ssh2 with user/password - you have to enable ' .
431                        'PasswordAuthentication in your sshd_config';
432                    error_reporting($intErrorReporting);
433                }
434            } else {
435                $this->myDataClass->writeLog(translate('Connection to remote system failed (SSH2 connection):').
436                    ' ' .$strServer. ' / ' . translate('port') . ' : ' .$intPort);
437                $this->processClassMessage(translate('Connection to remote system failed (SSH2 connection):').
438                    ' <b>' .$strServer. ' / ' . translate('port') . ' : ' .$intPort. '</b>::', $this->strErrorMessage);
439                if ($arrError['message'] != '') {
440                    $this->processClassMessage($arrError['message']. '::', $this->strErrorMessage);
441                }
442                $intReturn = 1;
443            }
444            // Check connection
445            if ((!$this->resConnectId) || (!$booLogin)) {
446                $this->myDataClass->writeLog(translate('Connection to remote system failed (SSH2 connection):').
447                    ' ' .$strServer. ' / ' . translate('port') . ' : ' .$intPort);
448                $this->processClassMessage(translate('Connection to remote system failed (SSH2 connection):')
449                    . ' ' .$strServer. ' / ' . translate('port') . ' : ' .$intPort. '::', $this->strErrorMessage);
450                if ($arrError['message'] != '') {
451                    $this->processClassMessage($arrError['message']. '::', $this->strErrorMessage);
452                }
453                if ($strPasswordNote !== null) {
454                    $this->processClassMessage($strPasswordNote. '::', $this->strErrorMessage);
455                }
456                $this->resConnectServer = '';
457                $this->resConnectType   = 'none';
458                $this->resConnectId     = null;
459                $intReturn = 1;
460            } else {
461                // Etablish an SFTP connection ressource
462                $this->resSFTP = ssh2_sftp($this->resConnectId);
463            }
464        }
465        return $intReturn;
466    }
467
468    /**
469     * Sends a command via SSH and stores the result in an array
470     * @param string $strCommand                Command string
471     * @param array $arrResult                  Output as array (by reference)
472     * @param int $intLines                     Maximal length of output to read
473     * @return int                              0 = successful / 1 = error
474     */
475    public function sendSSHCommand($strCommand, &$arrResult, $intLines = 100)
476    {
477        // Define variables
478        $intCount1 = 0; // empty lines
479        $intCount2 = 0; // data lines
480        $booBreak = false;
481        $this->getConfigTargets($arrConfigSet);
482        // Check connection
483        $intReturn = $this->getSSHConnection($arrConfigSet[0]);
484        if (\is_resource($this->resConnectId)) {
485            // Send command
486            $resStream = ssh2_exec($this->resConnectId, $strCommand.'; echo __END__');
487            if ($resStream) {
488                // read result
489                stream_set_blocking($resStream, true);
490                stream_set_timeout($resStream, 2);
491                do {
492                    $strLine = stream_get_line($resStream, 1024, "\n");
493                    if ($strLine == '') {
494                        $intCount1++;
495                    } elseif (substr_count($strLine, '__END__') != 1) {
496                        $arrResult[] = $strLine;
497                        $intReturn   = 0;
498                    } elseif (substr_count($strLine, '__END__') == 1) {
499                        $booBreak = true;
500                    }
501                    $intCount2++;
502                    $arrStatus = stream_get_meta_data($resStream);
503                } while ($resStream && !feof($resStream) && ($intCount1 <= 10) && ($intCount2 <= $intLines) &&
504                ($arrStatus['timed_out'] != true) && $booBreak == false);
505                fclose($resStream);
506                // Close SSH connection because of timing problems
507                unset($this->resConnectId);
508                //sleep(1);
509            }
510        }
511        return $intReturn;
512    }
513
514    /**
515     * Merge message strings and check for duplicate messages
516     * @param string $strNewMessage             New message to add
517     * @param string $strOldMessage             Modified message string (by reference)
518     */
519    public function processClassMessage($strNewMessage, &$strOldMessage)
520    {
521        $strNewMessage = str_replace('::::', '::', $strNewMessage);
522        if (($strOldMessage != '') && ($strNewMessage != '') && (substr_count($strOldMessage, $strNewMessage) == 0)) {
523            $strOldMessage .= $strNewMessage;
524        } elseif ($strOldMessage == '') {
525            $strOldMessage .= $strNewMessage;
526        }
527    }
528
529    /**
530     * Get configuration target IDs
531     * @param array $arrConfigId                Configuration target IDs (by reference)
532     * @return int                              0 = successful / 1 = error
533     */
534    public function getConfigSets(&$arrConfigId)
535    {
536        // Variable definition
537        $arrData      = array();
538        $arrConfigId  = array();
539        $intDataCount = 0;
540        $intReturn    = 1;
541        // Request target ID
542        $strSQL    = 'SELECT `targets` FROM `tbl_datadomain` WHERE `id`=' .$this->intDomainId;
543        $booReturn = $this->myDBClass->hasDataArray($strSQL, $arrData, $intDataCount);
544        if ($booReturn && ($intDataCount != 0)) {
545            foreach ($arrData as $elem) {
546                $arrConfigId[] = $elem['targets'];
547            }
548            $intReturn = 0;
549        }
550        return $intReturn;
551    }
552
553    /**
554     * Moves an existing configuration file to the backup directory and removes then the original file
555     * @param string $strType                   Type of the configuration file
556     * @param string $strName                   Name of the configuration file
557     * @param int $intConfigID                  Configuration target ID
558     * @return int                              0 = successful / 1 = error
559     *                                          Status message is stored in message class variables
560     */
561    public function moveFile($strType, $strName, $intConfigID)
562    {
563        // Variable definitions
564        $strConfigDir = '';
565        $strBackupDir = '';
566        $intReturn    = 0;
567        // Get directories
568        switch ($strType) {
569            case 'host':
570                $this->getConfigData($intConfigID, 'hostconfig', $strConfigDir);
571                $this->getConfigData($intConfigID, 'hostbackup', $strBackupDir);
572                break;
573            case 'service':
574                $this->getConfigData($intConfigID, 'serviceconfig', $strConfigDir);
575                $this->getConfigData($intConfigID, 'servicebackup', $strBackupDir);
576                break;
577            case 'basic':
578                $this->getConfigData($intConfigID, 'basedir', $strConfigDir);
579                $this->getConfigData($intConfigID, 'backupdir', $strBackupDir);
580                break;
581            case 'nagiosbasic':
582                $this->getConfigData($intConfigID, 'nagiosbasedir', $strConfigDir);
583                $this->getConfigData($intConfigID, 'backupdir', $strBackupDir);
584                break;
585            default:
586                $intReturn = 1;
587        }
588        if ($intReturn == 0) {
589            // Variable definition
590            $intMethod          = 1;
591            $strDate            = date('YmdHis');
592            $strSourceFile      = $strConfigDir. '/' .$strName;
593            $strDestinationFile = $strBackupDir. '/' .$strName. '_old_' .$strDate;
594            $booRetVal          = false;
595            // Get connection method
596            $this->getConfigData($intConfigID, 'method', $intMethod);
597            // Local file system
598            if ($intMethod == 1) {
599                // Save configuration file
600                if (file_exists($strSourceFile)) {
601                    if (is_writable($strBackupDir) && is_writable($strConfigDir)) {
602                        copy($strSourceFile, $strDestinationFile);
603                        unlink($strSourceFile);
604                    } else {
605                        $this->processClassMessage(translate('Cannot backup the old file because the permissions are '
606                                .'wrong - destination file: ').$strDestinationFile. '::', $this->strErrorMessage);
607                        $intReturn = 1;
608                    }
609                } else {
610                    $this->processClassMessage(translate('Cannot backup the old file because the source file is '
611                            . 'missing - source file: ') . $strSourceFile . '::', $this->strErrorMessage);
612                    $intReturn = 1;
613                }
614            } elseif ($intMethod == 2) { // Remote file (FTP)
615                // Check connection
616                $intReturn = $this->getFTPConnection($intConfigID);
617                if ($intReturn == 0) {
618                    $strSourceFile      = str_replace('//', '/', $strSourceFile);
619                    $strDestinationFile = str_replace('//', '/', $strDestinationFile);
620                    // Save configuration file
621                    $intFileStamp = ftp_mdtm($this->resConnectId, $strSourceFile);
622                    if ($intFileStamp > -1) {
623                        $intErrorReporting = error_reporting();
624                        error_reporting(0);
625                        $booRetVal = ftp_rename($this->resConnectId, $strSourceFile, $strDestinationFile);
626                        error_reporting($intErrorReporting);
627                    } else {
628                        $this->processClassMessage(translate('Cannot backup the old file because the source file is '
629                                .'missing (remote FTP) - source file: '). $strSourceFile. '::', $this->strErrorMessage);
630                        $intReturn = 1;
631                    }
632                }
633                if (($booRetVal == false) && ($intReturn == 0)) {
634                    $this->processClassMessage(translate('Cannot backup the old file because the permissions are '
635                            .'wrong (remote FTP) - destination file: ').$strDestinationFile. '::', $this->strErrorMessage);
636                    $intReturn = 1;
637                }
638            } elseif ($intMethod == 3) { // Remote file (SFTP)
639                // Check connection
640                $intReturn = $this->getSSHConnection($intConfigID);
641                // Save configuration file
642                $arrResult          = array();
643                $strSourceFile      = str_replace('//', '/', $strSourceFile);
644                $strDestinationFile = str_replace('//', '/', $strDestinationFile);
645                $strCommand         = 'ls '.$strSourceFile;
646                if (($intReturn == 0) && ($this->sendSSHCommand($strCommand, $arrResult) == 0)) {
647                    if (isset($arrResult[0]) && $arrResult[0] == $strSourceFile) {
648                        $arrInfo      = ssh2_sftp_stat($this->resSFTP, $strSourceFile);
649                        if ($arrInfo['mtime'] > -1) {
650                            $booRetVal = ssh2_sftp_rename($this->resSFTP, $strSourceFile, $strDestinationFile);
651                        }
652                    } else {
653                        $this->processClassMessage(translate('Cannot backup the old file because the source file is '
654                                .'missing (remote SFTP) - source file: '). $strSourceFile. '::', $this->strErrorMessage);
655                        $intReturn = 1;
656                    }
657                }
658                if (($booRetVal == false) && ($intReturn == 0)) {
659                    $this->processClassMessage(translate('Cannot backup the old file because the permissions are '
660                            .'wrong (remote SFTP) - destination file: ').$strDestinationFile. '::', $this->strErrorMessage);
661                    $intReturn = 1;
662                }
663            }
664        }
665        return $intReturn;
666    }
667
668    /**
669     * Remove a file
670     * @param string $strFileName               Filename including path to remove
671     * @param int $intConfigID                  Configuration target ID
672     * @return int                              0 = successful / 1 = error
673     *                                          Status message is stored in message class variables
674     */
675    public function removeFile($strFileName, $intConfigID)
676    {
677        // Variable definitions
678        $intMethod = 1;
679        $intReturn = 0;
680        $booRetVal = false;
681        // Get connection method
682        $this->getConfigData($intConfigID, 'method', $intMethod);
683        // Local file system
684        if ($intMethod == 1) {
685            // Save configuration file
686            if (file_exists($strFileName)) {
687                if (is_writable($strFileName)) {
688                    unlink($strFileName);
689                } else {
690                    $this->processClassMessage(translate('Cannot delete the file (wrong permissions)!').'::'.
691                        $strFileName. '::', $this->strErrorMessage);
692                    $intReturn = 1;
693                }
694            } else {
695                $this->processClassMessage(translate('Cannot delete the file (file does not exist)!').'::'.
696                    $strFileName. '::', $this->strErrorMessage);
697                $intReturn = 1;
698            }
699        } elseif ($intMethod == 2) { // Remote file (FTP)
700            // Check connection
701            $intReturn = $this->getFTPConnection($intConfigID);
702            if ($intReturn == 0) {
703                // Save configuration file
704                $intFileStamp = ftp_mdtm($this->resConnectId, $strFileName);
705                if ($intFileStamp > -1) {
706                    $intErrorReporting = error_reporting();
707                    error_reporting(0);
708                    $booRetVal = ftp_delete($this->resConnectId, $strFileName);
709                    error_reporting($intErrorReporting);
710                } else {
711                    $this->processClassMessage(translate('Cannot delete file because it does not exists (remote '
712                            . 'FTP)!'). '::', $this->strErrorMessage);
713                    $intReturn = 1;
714                }
715            }
716            if ($booRetVal == false) {
717                $this->processClassMessage(translate('Cannot delete file because the permissions are incorrect '
718                        . '(remote FTP)!'). '::', $this->strErrorMessage);
719                $intReturn = 1;
720            }
721        } elseif ($intMethod == 3) { // Remote file (SFTP)
722            // Check connection
723            $intReturn = $this->getSSHConnection($intConfigID);
724            // Save configuration file
725            if (($intReturn == 0) && ($this->sendSSHCommand('ls '.$strFileName, $arrResult) == 0)) {
726                if (isset($arrResult[0])) {
727                    $booRetVal = ssh2_sftp_unlink($this->resSFTP, $strFileName);
728                } else {
729                    $this->processClassMessage(translate('Cannot delete file because it does not exists (remote '
730                            . 'SSH/SFTP)!'). '::', $this->strErrorMessage);
731                    $intReturn = 1;
732                }
733            }
734            if (($intReturn == 0) && ($booRetVal == false)) {
735                $this->processClassMessage(translate('Cannot delete file because the permissions are incorrect '
736                        . '(remote SSH/SFTP)!'). '::', $this->strErrorMessage);
737                $intReturn = 1;
738            }
739        }
740        return $intReturn;
741    }
742
743    /**
744     * Get configuration domain parameters
745     * @param int $intConfigId                  Configuration ID
746     * @param string $strConfigItem             Configuration key
747     * @param string $strValue                  Configuration value (by reference)
748     * @return int                              0 = successful / 1 = error
749     */
750    public function getConfigData($intConfigId, $strConfigItem, &$strValue)
751    {
752        $intReturn = 1;
753        $strSQL   = 'SELECT `' .$strConfigItem. '` FROM `tbl_configtarget` WHERE `id` = ' .$intConfigId;
754        $strValue = $this->myDBClass->getFieldData($strSQL);
755        if ($strValue != '') {
756            $intReturn = 0;
757        }
758        return $intReturn;
759    }
760
761    /**
762     * Check a directory for write access
763     * @param string $strPath                   Physical path
764     * @return int                              0 = successful / 1 = error
765     */
766    public function isDirWriteable($strPath)
767    {
768        // Define variables
769        $intReturnFile = 1;
770        $intReturnDir  = 1;
771        $intReturn     = 1;
772        // Is input path a file?
773        if (file_exists($strPath) && is_file($strPath)) {
774            $resFile = fopen($strPath, 'ab');
775            if ($resFile) {
776                $intReturnFile = 0;
777            }
778        } else {
779            $intReturnFile = 0;
780        }
781        if (is_file($strPath)) {
782            $strDirectory = \dirname($strPath);
783        } else {
784            $strDirectory = $strPath;
785        }
786        $strFile = $strDirectory.'/'.uniqid(mt_rand(), true).'.tmp';
787        // Check writing in directory directly
788        if (is_dir($strDirectory) && is_writable($strDirectory)) {
789            $resFile = fopen($strFile, 'wb');
790            if ($resFile) {
791                $intReturnDir = 0;
792                unlink($strFile);
793            }
794        } else {
795            $intReturnDir = 0;
796        }
797        if (($intReturnDir == 0) && ($intReturnFile == 0)) {
798            $intReturn = 0;
799        }
800        return $intReturn;
801    }
802
803    /**
804     * Copy a remote file
805     * @param string $strFileRemote             Remote file name
806     * @param int $intConfigID                  Configuration target id
807     * @param string $strFileLocal              Local file name
808     * @param int $intDirection                 0 = from remote to local / 1 = from local to remote
809     * @return int                              0 = successful / 1 = error
810     *                                          Status message is stored in message class variables
811     */
812    public function remoteFileCopy($strFileRemote, $intConfigID, $strFileLocal, $intDirection = 0)
813    {
814        // Variable definitions
815        $intMethod = 3;
816        $intReturn = 0;
817        $arrTemp   = array();
818        // Get method
819        $this->getConfigData($intConfigID, 'method', $intMethod);
820        if ($intMethod == 2) {
821            // Check connection
822            $intReturn = $this->getFTPConnection($intConfigID);
823            if (($intReturn == 0) && ($intDirection == 0)) {
824                $intErrorReporting = error_reporting();
825                error_reporting(0);
826                if (!ftp_get($this->resConnectId, $strFileLocal, $strFileRemote, FTP_ASCII)) {
827                    $this->processClassMessage(translate('Cannot get the remote file (it does not exist or is not '
828                            . 'readable) - remote file: '). $strFileRemote. '::', $this->strErrorMessage);
829                    $intReturn = 1;
830                }
831                error_reporting($intErrorReporting);
832            } elseif (($intReturn == 0) && ($intDirection == 1)) {
833                $intErrorReporting = error_reporting();
834                error_reporting(0);
835                if (!ftp_put($this->resConnectId, $strFileRemote, $strFileLocal, FTP_ASCII)) {
836                    $this->processClassMessage(translate('Cannot write the remote file (remote file is not writeable)'
837                            . '- remote file: ').$strFileRemote. '::', $this->strErrorMessage);
838                    $intReturn = 1;
839                }
840                error_reporting($intErrorReporting);
841            }
842            ftp_close($this->resConnectId);
843        } elseif ($intMethod == 3) { // Remote file (SFTP)
844            $intReturn = $this->getSSHConnection($intConfigID);
845            if (($intReturn == 0) && ($intDirection == 0)) {
846                // Copy file
847                $intErrorReporting = error_reporting();
848                error_reporting(0);
849                if (!ssh2_scp_recv($this->resConnectId, $strFileRemote, $strFileLocal)) {
850                    if ($this->sendSSHCommand('ls ' . $strFileRemote, $arrTemp) != 0) {
851                        $this->processClassMessage(translate('Cannot get the remote file (it does not exist or is not '
852                                . 'readable) - remote file: ') .$strFileRemote. '::', $this->strErrorMessage);
853                    } else {
854                        $this->processClassMessage(translate('Remote file is not readable - remote file: ')
855                            . $strFileRemote. '::', $this->strErrorMessage);
856                    }
857                    $intReturn = 1;
858                }
859                error_reporting($intErrorReporting);
860            } elseif (($intReturn == 0) && ($intDirection == 1)) {
861                if (file_exists($strFileLocal) && is_readable($strFileLocal)) {
862                    $intErrorReporting = error_reporting();
863                    error_reporting(0);
864                    if (!ssh2_scp_send($this->resConnectId, $strFileLocal, $strFileRemote, 0644)) {
865                        $this->processClassMessage(translate('Cannot write a remote file (remote file is not writeable)'
866                                .' - remote file: '). $strFileRemote . '::', $this->strErrorMessage);
867                        $intReturn = 1;
868                    }
869                    error_reporting($intErrorReporting);
870                } else {
871                    $this->processClassMessage(translate('Cannot copy a local file to remote because the local file '.
872                            'does not exist or is not readable - local file: ').
873                        $strFileLocal . '::', $this->strErrorMessage);
874                    $intReturn = 1;
875                }
876            }
877        }
878        return $intReturn;
879    }
880
881    /**
882     * Add files of a given directory to an array
883     * @param string $strSourceDir              Source directory
884     * @param string $strIncPattern             Include file pattern
885     * @param string $strExcPattern             Exclude file pattern
886     * @param array $arrOutput                  Output array (by reference)
887     * @param string $strErrorMessage           Error messages (by reference)
888     */
889    public function storeDirToArray($strSourceDir, $strIncPattern, $strExcPattern, &$arrOutput, &$strErrorMessage)
890    {
891        // Define variables
892        $arrDir = array();
893        while (substr($strSourceDir, -1) == '/' or substr($strSourceDir, -1) == "\\") {
894            $strSourceDir = substr($strSourceDir, 0, -1);
895        }
896        $resHandle = opendir($strSourceDir);
897        if ($resHandle === false) {
898            if ($this->intDomainId != 0) {
899                $strErrorMessage .= translate('Could not open directory'). ': ' .$strSourceDir;
900            }
901        } else {
902            $booBreak = true;
903            while ($booBreak) {
904                if (!$arrDir[] = readdir($resHandle)) {
905                    $booBreak = false;
906                }
907            }
908            closedir($resHandle);
909            sort($arrDir);
910            /** @var string $file */
911            foreach ($arrDir as $file) {
912                /** @noinspection StrlenInEmptyStringCheckContextInspection */
913                if (!preg_match("/^\.{1,2}/", $file) && \strlen($file)) {
914                    if (is_dir($strSourceDir. '/' .$file)) {
915                        $this->storeDirToArray(
916                            $strSourceDir. '/' .$file,
917                            $strIncPattern,
918                            $strExcPattern,
919                            $arrOutput,
920                            $strErrorMessage
921                        );
922                    } else {
923                        if (preg_match('/' .$strIncPattern. '/', $file) && (($strExcPattern == '') ||
924                                !preg_match('/' .$strExcPattern. '/', $file))) {
925                            if (0 === stripos(PHP_OS, 'WIN')) {
926                                $strSourceDir=str_replace('/', "\\", $strSourceDir);
927                                $arrOutput [] = $strSourceDir."\\".$file;
928                            } else {
929                                $arrOutput [] = $strSourceDir. '/' .$file;
930                            }
931                        }
932                    }
933                }
934            }
935        }
936    }
937
938    /**
939     * Determines the dates of the last data table change and the last modification to the configuration files
940     * @param string $strTableName              Name of the data table
941     * @param array $arrTimeData                Array with time data of table and all config files
942     * @param string $strCheckConfig            Information string (text message)
943     * @return int                              0 = successful / 1 = error
944     *                                          Status message is stored in message class variables
945     */
946    public function lastModifiedFile($strTableName, &$arrTimeData, &$strCheckConfig)
947    {
948        // Variable definitions
949        $intEnableCommon = 0;
950        $arrDataset      = array();
951        $strFileName     = '';
952        $strCheckConfig  = '';
953        $intReturn       = 0;
954        // Get configuration filename based on table name
955        $arrConfigData = $this->getConfData();
956        if (isset($arrConfigData[$strTableName])) {
957            $strFileName   = $arrConfigData[$strTableName]['filename'];
958        } else {
959            $intReturn = 1;
960        }
961        // Get table times
962        $arrTimeData          = array();
963        $arrTimeData['table'] = 'unknown';
964        // Clear status cache
965        clearstatcache();
966        $intRetVal1 = $this->getDomainData('enable_common', $intEnableCommon);
967        // Get last change of date table
968        if ($intRetVal1 == 0) {
969            $strSQLAdd = '';
970            if ($intEnableCommon == 1) {
971                $strSQLAdd = 'OR `domainId`=0';
972            }
973            $strSQL = 'SELECT `updateTime` FROM `tbl_tablestatus` '
974                . 'WHERE (`domainId`=' .$this->intDomainId." $strSQLAdd) AND `tableName`='".$strTableName."' "
975                . 'ORDER BY `updateTime` DESC LIMIT 1';
976            $booReturn = $this->myDBClass->hasSingleDataset($strSQL, $arrDataset);
977            if ($booReturn && isset($arrDataset['updateTime'])) {
978                $arrTimeData['table'] = $arrDataset['updateTime'];
979            } else {
980                $strSQL = 'SELECT `last_modified` FROM `' .$strTableName. '` '
981                    . 'WHERE `config_id`=' .$this->intDomainId. ' ORDER BY `last_modified` DESC LIMIT 1';
982                $booReturn = $this->myDBClass->hasSingleDataset($strSQL, $arrDataset);
983                if (($booReturn == true) && isset($arrDataset['last_modified'])) {
984                    $arrTimeData['table'] = $arrDataset['last_modified'];
985                }
986            }
987        }
988        // Get config sets
989        $arrConfigId      = array();
990        $strTarget        = '';
991        $strBaseDir       = '';
992        $intFileStampTemp = 0;
993        $intRetVal2  = $this->getConfigSets($arrConfigId);
994        if ($intRetVal2 == 0) {
995            foreach ($arrConfigId as $intConfigId) {
996                // Get configuration file data
997                $this->getConfigData($intConfigId, 'target', $strTarget);
998                $this->getConfigData($intConfigId, 'basedir', $strBaseDir);
999                // Get time data
1000                $intReturn = $this->getFileDate(
1001                    $intConfigId,
1002                    $strFileName,
1003                    $strBaseDir,
1004                    $intFileStampTemp,
1005                    $arrTimeData[$strTarget]
1006                );
1007                if ($intFileStampTemp != 0 && strtotime($arrTimeData['table']) > $intFileStampTemp) {
1008                    $strCheckConfig = translate('Warning: configuration file is out of date!');
1009                }
1010                if ($arrTimeData[$strTarget] == 'unknown') {
1011                    $strCheckConfig = translate('Warning: configuration file is out of date!');
1012                }
1013            }
1014        } else {
1015            $strCheckConfig = translate('Warning: no configuration target defined!');
1016        }
1017        return $intReturn;
1018    }
1019
1020    /**
1021     * Writes a configuration file including all datasets of a configuration table or returns the output as a text
1022     * file for download. (Public master function)
1023     * @param string $strTableName              Table name
1024     * @param int $intMode                      0 = Write file to filesystem
1025     *                                          1 = Return Textfile for download test
1026     * @return int                              0 = successful / 1 = error
1027     *                                          Status message is stored in message class variables
1028     */
1029    public function createConfig($strTableName, $intMode = 0)
1030    {
1031        // Define Variables
1032        $intReturn     = 0;
1033        // Do not create configs in common domain
1034        if ($this->intDomainId == 0) {
1035            $this->processClassMessage(translate('It is not possible to write config files directly from the common '
1036                    . 'domain!'). '::', $this->strErrorMessage);
1037            $intReturn = 1;
1038        }
1039        if ($intReturn == 0) {
1040            // Get configuration targets
1041            $this->getConfigSets($arrConfigID);
1042            if (($arrConfigID != 1) && \is_array($arrConfigID)) {
1043                foreach ($arrConfigID as $intConfigID) {
1044                    $intReturn = $this->writeConfTemplate($intConfigID, $strTableName, $intMode);
1045                }
1046            } else {
1047                $this->processClassMessage(translate('Warning: no configuration target defined!').
1048                    '::', $this->strErrorMessage);
1049                $intReturn = 1;
1050            }
1051        }
1052        return $intReturn;
1053    }
1054
1055    /**
1056     * Writes a configuration file including one single datasets of a configuration table or returns the output as
1057     * a text file for download.
1058     * @param string $strTableName              Table name
1059     * @param int $intDbId                      Data ID
1060     * @param int $intMode                      0 = Write file to filesystem
1061     *                                          1 = Return Textfile for download test
1062     * @return int                              0 = successful / 1 = error
1063     *                                          Status message is stored in message class variables
1064     */
1065    public function createConfigSingle($strTableName, $intDbId = 0, $intMode = 0)
1066    {
1067        // Define Variables
1068        $arrData            = array();
1069        $intDataCount       = 0;
1070        $setEnableCommon    = 0;
1071        $intReturn          = 0;
1072        $strDomainWhere     = ' (`config_id`=' .$this->intDomainId. ') ';
1073        // Read some settings and informations
1074        $this->getDomainData('enable_common', $setEnableCommon);
1075        // Variable rewritting
1076        if ($setEnableCommon != 0) {
1077            $strDomainWhere = str_replace(')', ' OR `config_id`=0)', $strDomainWhere);
1078        }
1079        // Do not create configs in common domain
1080        if ($this->intDomainId == 0) {
1081            $this->processClassMessage(translate('It is not possible to write config files directly from the common '
1082                    . 'domain!'). '::', $this->strErrorMessage);
1083            $intReturn = 1;
1084        }
1085        if ($intReturn == 0) {
1086            if ($intDbId == 0) {
1087                $strSQL = 'SELECT * FROM `' .$strTableName."` WHERE $strDomainWhere AND `active`='1' ORDER BY `id`";
1088            } else {
1089                $strSQL = 'SELECT * FROM `' .$strTableName."` WHERE $strDomainWhere AND `active`='1' AND `id`=$intDbId";
1090            }
1091            $booReturn = $this->myDBClass->hasDataArray($strSQL, $arrData, $intDataCount);
1092            if (($booReturn != false) && ($intDataCount != 0)) {
1093                /** @noinspection ForeachInvariantsInspection */
1094                for ($i = 0; $i < $intDataCount; $i++) {
1095                    // Process form POST variable
1096                    $strChbName = 'chbId_' .$arrData[$i]['id'];
1097                    // Check if this POST variable exists or the data ID parameter matches
1098                    if ((($intDbId != 0) && ($intDbId == $arrData[$i]['id'])) ||
1099                        (filter_input(INPUT_POST, $strChbName) !== null)) {
1100                        // Get configuration targets
1101                        $this->getConfigSets($arrConfigID);
1102                        if (($arrConfigID != 1) && \is_array($arrConfigID)) {
1103                            foreach ($arrConfigID as $intConfigID) {
1104                                $intReturn = $this->writeConfTemplate(
1105                                    $intConfigID,
1106                                    $strTableName,
1107                                    $intMode,
1108                                    $arrData,
1109                                    $i
1110                                );
1111                            }
1112                        } else {
1113                            $this->processClassMessage(translate('Warning: no configuration target defined!').
1114                                '::', $this->strErrorMessage);
1115                            $intReturn = 1;
1116                        }
1117                    }
1118                }
1119            } else {
1120                $this->myDataClass->writeLog(translate('Writing of the configuration failed - no dataset or not '
1121                    . 'activated dataset found'));
1122                $this->processClassMessage(translate('Writing of the configuration failed - no dataset or not '
1123                        . 'activated dataset found'). '::', $this->strErrorMessage);
1124                $intReturn = 1;
1125            }
1126        }
1127        return $intReturn;
1128    }
1129
1130
1131    // PRIVATE functions
1132
1133    /**
1134     * Determines the configuration data for each database table
1135     * @return array                            filename (configuration file name)
1136     *                                          order_field (database order field)
1137     */
1138    public function getConfData()
1139    {
1140        $arrConfData['tbl_timeperiod']        = array('filename' => 'timeperiods.cfg',
1141            'order_field' => 'timeperiod_name');
1142        $arrConfData['tbl_command']           = array('filename' => 'commands.cfg',
1143            'order_field' => 'command_name');
1144        $arrConfData['tbl_contact']           = array('filename' => 'contacts.cfg',
1145            'order_field' => 'contact_name');
1146        $arrConfData['tbl_contacttemplate']   = array('filename' => 'contacttemplates.cfg',
1147            'order_field' => 'template_name');
1148        $arrConfData['tbl_contactgroup']      = array('filename' => 'contactgroups.cfg',
1149            'order_field' => 'contactgroup_name');
1150        $arrConfData['tbl_hosttemplate']      = array('filename' => 'hosttemplates.cfg',
1151            'order_field' => 'template_name');
1152        $arrConfData['tbl_servicetemplate']   = array('filename' => 'servicetemplates.cfg',
1153            'order_field' => 'template_name');
1154        $arrConfData['tbl_hostgroup']         = array('filename' => 'hostgroups.cfg',
1155            'order_field' => 'hostgroup_name');
1156        $arrConfData['tbl_servicegroup']      = array('filename' => 'servicegroups.cfg',
1157            'order_field' => 'servicegroup_name');
1158        $arrConfData['tbl_hostdependency']    = array('filename' => 'hostdependencies.cfg',
1159            'order_field' => 'dependent_host_name');
1160        $arrConfData['tbl_servicedependency'] = array('filename' => 'servicedependencies.cfg',
1161            'order_field' => 'config_name');
1162        $arrConfData['tbl_hostescalation']    = array('filename' => 'hostescalations.cfg',
1163            'order_field' => 'host_name`,`hostgroup_name');
1164        $arrConfData['tbl_serviceescalation'] = array('filename' => 'serviceescalations.cfg',
1165            'order_field' => 'config_name');
1166        $arrConfData['tbl_hostextinfo']       = array('filename' => 'hostextinfo.cfg',
1167            'order_field' => 'host_name');
1168        $arrConfData['tbl_serviceextinfo']    = array('filename' => 'serviceextinfo.cfg',
1169            'order_field' => 'host_name');
1170        return $arrConfData;
1171    }
1172
1173    /**
1174     * Writes a configuration file including all datasets of a configuration table or returns the output as a text
1175     * file for download. (Private worker function)
1176     * @param int $intConfigID                  Configuration target ID
1177     * @param string $strTableName              Table name
1178     * @param int $intMode                      0 = Write file to filesystem
1179     *                                          1 = Return Textfile for download test
1180     * @param array $arrTableData               Dataset array for host and services only
1181     * @param int $intID                        Key for dataset array
1182     * @return int                              0 = successful / 1 = error
1183     *                                          Status message is stored in message class variables
1184     */
1185    /** @noinspection ArrayTypeOfParameterByDefaultValueInspection */
1186    private function writeConfTemplate($intConfigID, $strTableName, $intMode, $arrTableData = array(), $intID = 0)
1187    {
1188        // Variable definitions
1189        $strSQL         = '';
1190        $strOrderField  = '';
1191        $strFileString  = '';
1192        $arrTplOptions  = array('use_preg' => false);
1193        $strDomainWhere = ' (`config_id`=' . $this->intDomainId . ') ';
1194        $intType        = 0;
1195        $intReturn      = 0;
1196        // Read some settings and informations
1197        $this->getConfigData($intConfigID, 'utf8_decode', $setUTF8Decode);
1198        $this->getDomainData('enable_common', $setEnableCommon);
1199        $this->getConfigData($intConfigID, 'version', $intNagiosVersion);
1200        $arrConfigData = $this->getConfData();
1201        if (isset($arrConfigData[$strTableName])) {
1202            $strFileString = str_replace('.cfg', '', $arrConfigData[$strTableName]['filename']);
1203            $strOrderField = $arrConfigData[$strTableName]['order_field'];
1204        }
1205        // Variable rewritting
1206        if ($setEnableCommon != 0) {
1207            $strDomainWhere = str_replace(')', ' OR `config_id`=0)', $strDomainWhere);
1208        }
1209        // Special processing for table host and service
1210        $setTemplate = $strFileString. '.tpl.dat';
1211        if (($strTableName == 'tbl_host') || ($strTableName == 'tbl_service')) {
1212            // Define variable names based on table name
1213            switch ($strTableName) {
1214                case 'tbl_host':
1215                    $strFileString = $arrTableData[$intID]['host_name'];
1216                    $intDomainId   = $arrTableData[$intID]['config_id'];
1217                    $setTemplate   = 'hosts.tpl.dat';
1218                    $intType       = 1;
1219                    $strSQL        = 'SELECT * FROM `' . $strTableName . "` WHERE `host_name`='$strFileString' "
1220                        . "AND `active`='1' AND `config_id`=$intDomainId";
1221                    break;
1222                case 'tbl_service':
1223                    $strFileString = $arrTableData[$intID]['config_name'];
1224                    $intDomainId   = $arrTableData[$intID]['config_id'];
1225                    $setTemplate   = 'services.tpl.dat';
1226                    $intType       = 2;
1227                    $strSQL        = 'SELECT * FROM `' . $strTableName . "` WHERE `config_name`='$strFileString' "
1228                        . "AND `active`='1' AND `config_id`=$intDomainId ORDER BY `service_description`";
1229                    break;
1230            }
1231        } else {
1232            $strSQL  = 'SELECT * FROM `' .$strTableName."` WHERE $strDomainWhere AND `active`='1' ".
1233                'ORDER BY `' .$strOrderField. '`';
1234        }
1235        $strFile     = $strFileString. '.cfg';
1236        // Load configuration template file
1237        $tplConf = new \HTML_Template_IT($this->arrSettings['path']['base_path']. '/templates/files/');
1238        $tplConf->loadTemplatefile($setTemplate, true, true);
1239        $tplConf->setOptions($arrTplOptions);
1240        $tplConf->setVariable('CREATE_DATE', date('Y-m-d H:i:s'));
1241        $tplConf->setVariable('NAGIOS_QL_VERSION', $this->arrSettings['db']['version']);
1242        $tplConf->setVariable('VERSION', $this->getVersionString($intConfigID));
1243        // Write data from configuration table
1244        $booReturn = $this->myDBClass->hasDataArray($strSQL, $arrData, $intDataCount);
1245        if ($booReturn && ($intDataCount != 0) && ($strFileString != '')) {
1246            // Process every data set
1247            /** @noinspection ForeachInvariantsInspection */
1248            for ($i = 0; $i < $intDataCount; $i++) {
1249                $intDataId = 0;
1250                /** @noinspection ForeachSourceInspection */
1251                foreach ($arrData[$i] as $key => $value) {
1252                    if ($key == 'id') {
1253                        $intDataId = $value;
1254                    }
1255                    if ($key == 'config_name') {
1256                        $key = '#NAGIOSQL_CONFIG_NAME';
1257                    }
1258                    // UTF8 decoded vaules
1259                    if ($setUTF8Decode == 1) {
1260                        $value = utf8_decode($value);
1261                    }
1262                    // Pass special fields (NagiosQL data fields not used by Nagios itselves)
1263                    if ($this->skipEntries($strTableName, $intNagiosVersion, $key, $value) == 1) {
1264                        continue;
1265                    }
1266                    // Get relation data
1267                    $intSkip = $this->getRelationData($strTableName, $tplConf, $arrData[$i], $key, $value);
1268                    // Rename field names
1269                    $this->renameFields($strTableName, $intConfigID, $intDataId, $key, $value, $intSkip);
1270                    // Inset data field
1271                    if ($intSkip != 1) {
1272                        // Insert fill spaces
1273                        $strFillLen = (30- \strlen($key));
1274                        $strSpace = ' ';
1275                        for ($f = 0; $f < $strFillLen; $f++) {
1276                            $strSpace .= ' ';
1277                        }
1278                        // Write key and value to template
1279                        $tplConf->setVariable('ITEM_TITLE', $key.$strSpace);
1280                        // Short values
1281                        if (($intNagiosVersion != 3) || (\strlen($value) < 800)) {
1282                            $tplConf->setVariable('ITEM_VALUE', $value);
1283                            $tplConf->parse('configline');
1284                        } else { // Long values
1285                            $arrValueTemp = explode(',', $value);
1286                            $strValueNew  = '';
1287                            $intArrCount  = \count($arrValueTemp);
1288                            $intCounter   = 0;
1289                            $strSpace     = ' ';
1290                            for ($f = 0; $f < 30; $f++) {
1291                                $strSpace .= ' ';
1292                            }
1293                            foreach ($arrValueTemp as $elem) {
1294                                if (\strlen($strValueNew) < 800) {
1295                                    $strValueNew .= $elem. ',';
1296                                } else {
1297                                    if (substr($strValueNew, -1) == ',') {
1298                                        $strValueNew = substr($strValueNew, 0, -1);
1299                                    }
1300                                    if ($intCounter < $intArrCount) {
1301                                        $strValueNew .= ",\\";
1302                                        $tplConf->setVariable('ITEM_VALUE', $strValueNew);
1303                                        $tplConf->parse('configline');
1304                                        $tplConf->setVariable('ITEM_TITLE', $strSpace);
1305                                    } else {
1306                                        $tplConf->setVariable('ITEM_VALUE', $strValueNew);
1307                                        $tplConf->parse('configline');
1308                                        $tplConf->setVariable('ITEM_TITLE', $strSpace);
1309                                    }
1310                                    $strValueNew = $elem. ',';
1311                                }
1312                                $intCounter++;
1313                            }
1314                            if ($strValueNew != '') {
1315                                if (substr($strValueNew, -1) == ',') {
1316                                    $strValueNew = substr($strValueNew, 0, -1);
1317                                }
1318                                $tplConf->setVariable('ITEM_VALUE', $strValueNew);
1319                                $tplConf->parse('configline');
1320                            }
1321                        }
1322                    }
1323                }
1324                // Special processing for time periods
1325                if ($strTableName == 'tbl_timeperiod') {
1326                    $arrDataTime = array();
1327                    $strSQLTime = 'SELECT `definition`, `range` '
1328                        . 'FROM `tbl_timedefinition` WHERE `tipId` = ' .$arrData[$i]['id'];
1329                    $booReturn  = $this->myDBClass->hasDataArray($strSQLTime, $arrDataTime, $intDataCountTime);
1330                    if ($booReturn && $intDataCountTime != 0) {
1331                        foreach ($arrDataTime as $data) {
1332                            // Skip other values than weekdays in nagios version below 3
1333                            if ($intNagiosVersion < 3) {
1334                                $arrWeekdays = array('monday','tuesday','wednesday','thursday','friday','saturday',
1335                                    'sunday');
1336                                if (!\in_array($data['definition'], $arrWeekdays, true)) {
1337                                    continue;
1338                                }
1339                            }
1340                            // Insert fill spaces
1341                            $strFillLen = (30- \strlen($data['definition']));
1342                            $strSpace = ' ';
1343                            for ($f = 0; $f < $strFillLen; $f++) {
1344                                $strSpace .= ' ';
1345                            }
1346                            // Write key and value
1347                            $tplConf->setVariable('ITEM_TITLE', $data['definition'].$strSpace);
1348                            $tplConf->setVariable('ITEM_VALUE', $data['range']);
1349                            $tplConf->parse('configline');
1350                        }
1351                    }
1352                }
1353                // Write configuration set
1354                $tplConf->parse('configset');
1355            }
1356        } elseif ($booReturn && ($intDataCount == 0) && ($strFileString != '')) {
1357            $this->processClassMessage(translate('Error while selecting data from database:')
1358                . '::', $this->strErrorMessage);
1359            $this->processClassMessage($this->myDBClass->strErrorMessage, $this->strErrorMessage);
1360            $intReturn = 1;
1361        } else {
1362            $this->myDataClass->writeLog(translate('Writing of the configuration failed - no dataset '
1363                . 'or not activated dataset found'));
1364            $this->processClassMessage(translate('Writing of the configuration failed - no dataset '
1365                    . 'or not activated dataset found'). '::', $this->strErrorMessage);
1366            $intReturn = 1;
1367        }
1368        if ($intMode == 0) {
1369            $intReturn = $this->getConfigFile($strFile, $intConfigID, $intType, $resCfgFile, $strCfgFile);
1370            if ($intReturn == 0) {
1371                $tplConf->parse();
1372                $strContent = $tplConf->get();
1373                $intReturn  = $this->writeConfigFile(
1374                    $strContent,
1375                    $strFile,
1376                    $intType,
1377                    $intConfigID,
1378                    $resCfgFile,
1379                    $strCfgFile
1380                );
1381            }
1382        } elseif ($intMode == 1) {
1383            $tplConf->show();
1384        }
1385        return $intReturn;
1386    }
1387
1388    /**
1389     * Get Nagios version string
1390     * @param int $intConfigID                  Configuration target ID
1391     * @return string                           Version string
1392     */
1393    private function getVersionString($intConfigID)
1394    {
1395        $arrVersion = array(
1396            'Nagios 2.x config file',
1397            'Nagios 2.9 config file',
1398            'Nagios 3.x config file',
1399            'Nagios 4.x config file'
1400        );
1401        $this->getConfigData($intConfigID, 'version', $intVersion);
1402        if (($intVersion >= 1) && ($intVersion <= \count($arrVersion))) {
1403            $strVersion = $arrVersion[$intVersion - 1];
1404        } else {
1405            $strVersion = '';
1406        }
1407        return $strVersion;
1408    }
1409
1410    /**
1411     * Skip database values based on Nagios version
1412     * @param string $strTableName              Table name
1413     * @param int $intVersionValue              Nagios version value
1414     * @param string $key                       Data key
1415     * @param string $value                     Data value
1416     * @return int
1417     */
1418    private function skipEntries($strTableName, $intVersionValue, $key, &$value)
1419    {
1420        // Define variables
1421        $arrOption = array();
1422        $intReturn = 0;
1423        // Skip common fields
1424        $strSpecial  = 'id,active,last_modified,access_rights,access_group,config_id,template,nodelete,command_type,';
1425        $strSpecial .= 'import_hash';
1426
1427        // Skip fields of special tables
1428        if ($strTableName == 'tbl_hosttemplate') {
1429            $strSpecial .= ',parents_tploptions,hostgroups_tploptions,contacts_tploptions';
1430            $strSpecial .= ',contact_groups_tploptions,use_template_tploptions';
1431        }
1432        if ($strTableName == 'tbl_servicetemplate') {
1433            $strSpecial .= ',host_name_tploptions,hostgroup_name_tploptions,parents_tploptions,contacts_tploptions';
1434            $strSpecial .= ',servicegroups_tploptions,contact_groups_tploptions,use_template_tploptions';
1435        }
1436        if ($strTableName == 'tbl_contact') {
1437            $strSpecial .= ',use_template_tploptions,contactgroups_tploptions';
1438            $strSpecial .= ',host_notification_commands_tploptions,service_notification_commands_tploptions';
1439        }
1440        if ($strTableName == 'tbl_contacttemplate') {
1441            $strSpecial .= ',use_template_tploptions,contactgroups_tploptions';
1442            $strSpecial .= ',host_notification_commands_tploptions,service_notification_commands_tploptions';
1443        }
1444        if ($strTableName == 'tbl_host') {
1445            $strSpecial .= ',parents_tploptions,hostgroups_tploptions,contacts_tploptions';
1446            $strSpecial .= ',contact_groups_tploptions,use_template_tploptions';
1447        }
1448        if ($strTableName == 'tbl_service') {
1449            $strSpecial .= ',host_name_tploptions,hostgroup_name_tploptions,parents_tploptions';
1450            $strSpecial .= ',servicegroups_tploptions,contacts_tploptions,contact_groups_tploptions';
1451            $strSpecial .= ',use_template_tploptions';
1452        }
1453        if ($strTableName == 'tbl_command') {
1454            $strSpecial .= ',arg1_info,arg2_info,arg3_info,arg4_info,arg5_info,arg6_info,arg7_info,arg8_info';
1455        }
1456
1457        // Pass fields based on nagios version lower than 3.x
1458        if ($intVersionValue < 3) {
1459            if ($strTableName == 'tbl_timeperiod') {
1460                $strSpecial .= ',use_template,exclude,name';
1461            }
1462            if (($strTableName == 'tbl_contact') || ($strTableName == 'tbl_contacttemplate')) {
1463                $strSpecial .= ',host_notifications_enabled,service_notifications_enabled,can_submit_commands';
1464                $strSpecial .= ',retain_status_information,retain_nonstatus_information';
1465                $arrOption['host_notification_options']    = ',s';
1466                $arrOption['service_notification_options'] = ',s';
1467            }
1468            if ($strTableName == 'tbl_contactgroup') {
1469                $strSpecial .= ',contactgroup_members';
1470            }
1471            if ($strTableName == 'tbl_hostgroup') {
1472                $strSpecial .= ',hostgroup_members,notes,notes_url,action_url';
1473            }
1474            if ($strTableName == 'tbl_servicegroup') {
1475                $strSpecial .= ',servicegroup_members,notes,notes_url,action_url';
1476            }
1477            if ($strTableName == 'tbl_hostdependency') {
1478                $strSpecial .= ',dependent_hostgroup_name,hostgroup_name,dependency_period';
1479            }
1480            if ($strTableName == 'tbl_hostescalation') {
1481                $strSpecial .= ',contacts';
1482            }
1483            if ($strTableName == 'tbl_servicedependency') {
1484                $strSpecial .= ',dependent_hostgroup_name,hostgroup_name,dependency_period,dependent_servicegroup_name';
1485                $strSpecial .= ',servicegroup_name';
1486            }
1487            if ($strTableName == 'tbl_serviceescalation') {
1488                $strSpecial .= ',hostgroup_name,contacts,servicegroup_name';
1489            }
1490            if (($strTableName == 'tbl_host') || ($strTableName == 'tbl_hosttemplate')) {
1491                $strSpecial .= ',initial_state,flap_detection_options,contacts,notes,notes_url,action_url';
1492                $strSpecial .= ',icon_image,icon_image_alt,vrml_image,statusmap_image,2d_coords,3d_coords';
1493                $arrOption['notification_options'] = ',s';
1494            }
1495            // Services
1496            if (($strTableName == 'tbl_service') || ($strTableName == 'tbl_servicetemplate')) {
1497                $strSpecial .= ',initial_state,flap_detection_options,contacts,notes,notes_url,action_url';
1498                $strSpecial .= ',icon_image,icon_image_alt';
1499                $arrOption['notification_options'] = ',s';
1500            }
1501        }
1502        // Pass fields based on nagios version higher than 2.x
1503        if ($intVersionValue > 2) {
1504            if ($strTableName == 'tbl_servicetemplate') {
1505                $strSpecial .= ',parallelize_check ';
1506            }
1507            if ($strTableName == 'tbl_service') {
1508                $strSpecial .= ',parallelize_check';
1509            }
1510        }
1511        // Pass fields based on nagios version lower than 4.x
1512        if ($intVersionValue < 4) {
1513            if (($strTableName == 'tbl_contact') || ($strTableName == 'tbl_contacttemplate')) {
1514                $strSpecial .= ',minimum_importance';
1515            }
1516            if ($strTableName == 'tbl_host') {
1517                $strSpecial .= ',importance';
1518            }
1519            if (($strTableName == 'tbl_service') || ($strTableName == 'tbl_servicetemplate')) {
1520                $strSpecial .= ',importance,parents';
1521            }
1522        }
1523        if ($intVersionValue == 1) {
1524            $strSpecial .= '';
1525        }
1526        // Reduce option values
1527        if (array_key_exists($key, $arrOption) && (\count($arrOption) != 0)) {
1528            $value = str_replace(array($arrOption[$key], str_replace(',', '', $arrOption[$key])), '', $value);
1529            if ($value == '') {
1530                $intReturn = 1;
1531            }
1532        }
1533        if ($intReturn == 0) {
1534            // Skip entries
1535            $arrSpecial = explode(',', $strSpecial);
1536            if (($value == '') || \in_array($key, $arrSpecial, true)) {
1537                $intReturn = 1;
1538            }
1539        }
1540        if ($intReturn == 0) {
1541            // Do not write config data (based on 'skip' option)
1542            $strNoTwo  = 'active_checks_enabled,passive_checks_enabled,obsess_over_host,check_freshness,';
1543            $strNoTwo .= 'event_handler_enabled,flap_detection_enabled,process_perf_data,retain_status_information,';
1544            $strNoTwo .= 'retain_nonstatus_information,notifications_enabled,parallelize_check,is_volatile,';
1545            $strNoTwo .= 'host_notifications_enabled,service_notifications_enabled,can_submit_commands,';
1546            $strNoTwo .= 'obsess_over_service';
1547            foreach (explode(',', $strNoTwo) as $elem) {
1548                if (($key == $elem) && ($value == '2')) {
1549                    $intReturn = 1;
1550                }
1551                if (($intVersionValue < 3) && ($key == $elem) && ($value == '3')) {
1552                    $intReturn = 1;
1553                }
1554            }
1555        }
1556        return $intReturn;
1557    }
1558
1559    /**
1560     * Get related data
1561     * @param string $strTableName              Table name
1562     * @param \HTML_Template_IT $resTemplate    Template ressource
1563     * @param array $arrData                    Dataset array
1564     * @param string $strDataKey                Data key
1565     * @param string $strDataValue              Data value
1566     * @return int                              0 = use data / 1 = skip data
1567     *                                          Status message is stored in message class variables
1568     */
1569    private function getRelationData($strTableName, $resTemplate, $arrData, $strDataKey, &$strDataValue)
1570    {
1571        // Define Variables
1572        $intReturn    = 0;
1573        $intSkipProc  = 0;
1574        $arrRelations = array();
1575        // Pass function for tbl_command
1576        if ($strTableName == 'tbl_command') {
1577            $intSkipProc = 1;
1578        }
1579        // Get relation info and store the value in a class variable (speedup export)
1580        if (($intSkipProc == 0) && ($this->strRelTable != $strTableName)) {
1581            $intReturn = $this->myDataClass->tableRelations($strTableName, $arrRelations);
1582            $this->strRelTable = $strTableName;
1583            $this->arrRelData  = $arrRelations;
1584        } elseif ($intSkipProc == 0) {
1585            $arrRelations = $this->arrRelData;
1586            $intReturn   = 0;
1587        }
1588        if (($intSkipProc == 0) && (!\is_array($arrRelations)) && (\count($arrRelations) == 0)) {
1589            $intSkipProc = 1;
1590            $intReturn   = 1;
1591        }
1592        if ($intSkipProc == 0) {
1593            // Common domain is enabled?
1594            $this->getDomainData('enable_common', $intCommonEnable);
1595            if ($intCommonEnable == 1) {
1596                $strDomainWhere1 = ' (`config_id`=' . $this->intDomainId . ' OR `config_id`=0) ';
1597            } else {
1598                $strDomainWhere1 = ' `config_id`=' . $this->intDomainId . ' ';
1599            }
1600            // Process relations
1601            foreach ($arrRelations as $elem) {
1602                if ($elem['fieldName'] == $strDataKey) {
1603                    // Process normal 1:n relations (1 = only data / 2 = including a * value)
1604                    if (($elem['type'] == 2) && (($strDataValue == 1) || ($strDataValue == 2))) {
1605                        $intReturn = $this->processRelation1($arrData, $strDataValue, $elem, $strDomainWhere1);
1606                        // Process normal 1:1 relations
1607                    } elseif ($elem['type'] == 1) {
1608                        $intReturn = $this->processRelation2($arrData, $strDataValue, $elem, $strDomainWhere1);
1609                        // Process normal 1:n relations with special table and idSort (template tables)
1610                    } elseif (($elem['type'] == 3) && ($strDataValue == 1)) {
1611                        $intReturn = $this->processRelation3($arrData, $strDataValue, $elem, $strDomainWhere1);
1612                        // Process special 1:n:str relations with string values (servicedependencies)
1613                    } elseif (($elem['type'] == 6) && (($strDataValue == 1) || ($strDataValue == 2))) {
1614                        $intReturn = $this->processRelation4($arrData, $strDataValue, $elem, $strDomainWhere1);
1615                        // Process special relations for free variables
1616                    } elseif (($elem['type'] == 4) && ($strDataValue == 1) && ($this->intNagVersion >= 3)) {
1617                        $intReturn = $this->processRelation5($resTemplate, $arrData, $elem);
1618                        // Process special relations for service groups
1619                    } elseif (($elem['type'] == 5) && ($strDataValue == 1)) {
1620                        $intReturn = $this->processRelation6($arrData, $strDataValue, $elem, $strDomainWhere1);
1621                        // Process special relations for service parents
1622                    } elseif (($elem['type'] == 7) && ($strDataValue == 1)) {
1623                        $intReturn = $this->processRelation7($arrData, $strDataValue, $elem);
1624                        // Process "*"
1625                    } elseif ($strDataValue == 2) {
1626                        $strDataValue = '*';
1627                    } else {
1628                        $intReturn = 1;
1629                    }
1630                }
1631            }
1632        }
1633        return $intReturn;
1634    }
1635
1636    /**
1637     * Rename field names
1638     * @param string $strTableName              Table name
1639     * @param int $intConfigID                  Configuration target ID
1640     * @param int $intDataId                    Data ID
1641     * @param string $key                       Data key (by reference)
1642     * @param string $value                     Data value (by reference)
1643     * @param int $intSkip                      Skip value (by reference) 1 = skip / 0 = pass
1644     */
1645    private function renameFields($strTableName, $intConfigID, $intDataId, &$key, &$value, &$intSkip)
1646    {
1647        if ($this->intNagVersion == 0) {
1648            $this->getConfigData($intConfigID, 'version', $this->intNagVersion);
1649        }
1650        // Picture path
1651        if ($this->strPicPath == 'none') {
1652            $this->getConfigData($intConfigID, 'picturedir', $this->strPicPath);
1653        }
1654        if ($key == 'icon_image') {
1655            $value = $this->strPicPath.$value;
1656        }
1657        if ($key == 'vrml_image') {
1658            $value = $this->strPicPath.$value;
1659        }
1660        if ($key == 'statusmap_image') {
1661            $value = $this->strPicPath.$value;
1662        }
1663        // Tables
1664        if ($strTableName == 'tbl_host') {
1665            if ($key == 'use_template') {
1666                $key = 'use';
1667            }
1668            $strVIValues  = 'active_checks_enabled,passive_checks_enabled,check_freshness,obsess_over_host,';
1669            $strVIValues .= 'event_handler_enabled,flap_detection_enabled,process_perf_data,retain_status_information,';
1670            $strVIValues .= 'retain_nonstatus_information,notifications_enabled';
1671            if (\in_array($key, explode(',', $strVIValues), true)) {
1672                if ($value == -1) {
1673                    $value = 'null';
1674                }
1675                if ($value == 3) {
1676                    $value = 'null';
1677                }
1678            }
1679            if ($key == 'parents') {
1680                $value = $this->checkTpl($value, 'parents_tploptions', 'tbl_host', $intDataId, $intSkip);
1681            }
1682            if ($key == 'hostgroups') {
1683                $value = $this->checkTpl($value, 'hostgroups_tploptions', 'tbl_host', $intDataId, $intSkip);
1684            }
1685            if ($key == 'contacts') {
1686                $value = $this->checkTpl($value, 'contacts_tploptions', 'tbl_host', $intDataId, $intSkip);
1687            }
1688            if ($key == 'contact_groups') {
1689                $value = $this->checkTpl($value, 'contact_groups_tploptions', 'tbl_host', $intDataId, $intSkip);
1690            }
1691            if ($key == 'use') {
1692                $value = $this->checkTpl($value, 'use_template_tploptions', 'tbl_host', $intDataId, $intSkip);
1693            }
1694            if ($key == 'check_command') {
1695                $value = str_replace("\::bang::", "\!", $value);
1696            }
1697            if ($key == 'check_command') {
1698                $value = str_replace('::bang::', "\!", $value);
1699            }
1700        }
1701        if ($strTableName == 'tbl_service') {
1702            if ($key == 'use_template') {
1703                $key = 'use';
1704            }
1705            if ($this->intNagVersion < 2) {
1706                if ($key == 'check_interval') {
1707                    $key = 'normal_check_interval';
1708                }
1709                if ($key == 'retry_interval') {
1710                    $key = 'retry_check_interval';
1711                }
1712            }
1713            $strVIValues  = 'is_volatile,active_checks_enabled,passive_checks_enabled,parallelize_check,';
1714            $strVIValues .= 'obsess_over_service,check_freshness,event_handler_enabled,flap_detection_enabled,';
1715            $strVIValues .= 'process_perf_data,retain_status_information,retain_nonstatus_information,';
1716            $strVIValues .= 'notifications_enabled';
1717            if (\in_array($key, explode(',', $strVIValues), true)) {
1718                if ($value == -1) {
1719                    $value = 'null';
1720                }
1721                if ($value == 3) {
1722                    $value = 'null';
1723                }
1724            }
1725            if ($key == 'host_name') {
1726                $value = $this->checkTpl($value, 'host_name_tploptions', 'tbl_service', $intDataId, $intSkip);
1727            }
1728            if ($key == 'hostgroup_name') {
1729                $value = $this->checkTpl($value, 'hostgroup_name_tploptions', 'tbl_service', $intDataId, $intSkip);
1730            }
1731            if ($key == 'parents') {
1732                $value = $this->checkTpl($value, 'parents_tploptions', 'tbl_service', $intDataId, $intSkip);
1733            }
1734            if ($key == 'servicegroups') {
1735                $value = $this->checkTpl($value, 'servicegroups_tploptions', 'tbl_service', $intDataId, $intSkip);
1736            }
1737            if ($key == 'contacts') {
1738                $value = $this->checkTpl($value, 'contacts_tploptions', 'tbl_service', $intDataId, $intSkip);
1739            }
1740            if ($key == 'contact_groups') {
1741                $value = $this->checkTpl($value, 'contact_groups_tploptions', 'tbl_service', $intDataId, $intSkip);
1742            }
1743            if ($key == 'use') {
1744                $value = $this->checkTpl($value, 'use_template_tploptions', 'tbl_service', $intDataId, $intSkip);
1745            }
1746            if ($key == 'check_command') {
1747                $value = str_replace("\::bang::", "\!", $value);
1748            }
1749            if ($key == 'check_command') {
1750                $value = str_replace('::bang::', "\!", $value);
1751            }
1752        }
1753        if ($strTableName == 'tbl_hosttemplate') {
1754            if ($key == 'template_name') {
1755                $key = 'name';
1756            }
1757            if ($key == 'use_template') {
1758                $key = 'use';
1759            }
1760            $strVIValues  = 'active_checks_enabled,passive_checks_enabled,check_freshness,obsess_over_host,';
1761            $strVIValues .= 'event_handler_enabled,flap_detection_enabled,process_perf_data,retain_status_information,';
1762            $strVIValues .= 'retain_nonstatus_information,notifications_enabled';
1763            if (\in_array($key, explode(',', $strVIValues), true)) {
1764                if ($value == -1) {
1765                    $value = 'null';
1766                }
1767                if ($value == 3) {
1768                    $value = 'null';
1769                }
1770            }
1771            if ($key == 'parents') {
1772                $value = $this->checkTpl($value, 'parents_tploptions', 'tbl_hosttemplate', $intDataId, $intSkip);
1773            }
1774            if ($key == 'hostgroups') {
1775                $value = $this->checkTpl($value, 'hostgroups_tploptions', 'tbl_hosttemplate', $intDataId, $intSkip);
1776            }
1777            if ($key == 'contacts') {
1778                $value = $this->checkTpl($value, 'contacts_tploptions', 'tbl_hosttemplate', $intDataId, $intSkip);
1779            }
1780            if ($key == 'contact_groups') {
1781                $value = $this->checkTpl($value, 'contact_groups_tploptions', 'tbl_hosttemplate', $intDataId, $intSkip);
1782            }
1783            if ($key == 'use') {
1784                $value = $this->checkTpl($value, 'use_template_tploptions', 'tbl_hosttemplate', $intDataId, $intSkip);
1785            }
1786        }
1787        if ($strTableName == 'tbl_servicetemplate') {
1788            if ($key == 'template_name') {
1789                $key = 'name';
1790            }
1791            if ($key == 'use_template') {
1792                $key = 'use';
1793            }
1794            if ($this->intNagVersion < 2) {
1795                if ($key == 'check_interval') {
1796                    $key = 'normal_check_interval';
1797                }
1798                if ($key == 'retry_interval') {
1799                    $key = 'retry_check_interval';
1800                }
1801            }
1802            $strVIValues  = 'is_volatile,active_checks_enabled,passive_checks_enabled,parallelize_check,';
1803            $strVIValues .= 'obsess_over_service,check_freshness,event_handler_enabled,flap_detection_enabled,';
1804            $strVIValues .= 'process_perf_data,retain_status_information,retain_nonstatus_information,';
1805            $strVIValues .= 'notifications_enabled';
1806            if (\in_array($key, explode(',', $strVIValues), true)) {
1807                if ($value == -1) {
1808                    $value = 'null';
1809                }
1810                if ($value == 3) {
1811                    $value = 'null';
1812                }
1813            }
1814            if ($key == 'host_name') {
1815                $value = $this->checkTpl($value, 'host_name_tploptions', 'tbl_servicetemplate', $intDataId, $intSkip);
1816            }
1817            if ($key == 'hostgroup_name') {
1818                $value = $this->checkTpl(
1819                    $value,
1820                    'hostgroup_name_tploptions',
1821                    'tbl_servicetemplate',
1822                    $intDataId,
1823                    $intSkip
1824                );
1825            }
1826            if ($key == 'parents') {
1827                $value = $this->checkTpl($value, 'parents_tploptions', 'tbl_servicetemplate', $intDataId, $intSkip);
1828            }
1829            if ($key == 'servicegroups') {
1830                $value = $this->checkTpl(
1831                    $value,
1832                    'servicegroups_tploptions',
1833                    'tbl_servicetemplate',
1834                    $intDataId,
1835                    $intSkip
1836                );
1837            }
1838            if ($key == 'contacts') {
1839                $value = $this->checkTpl($value, 'contacts_tploptions', 'tbl_servicetemplate', $intDataId, $intSkip);
1840            }
1841            if ($key == 'contact_groups') {
1842                $value = $this->checkTpl(
1843                    $value,
1844                    'contact_groups_tploptions',
1845                    'tbl_servicetemplate',
1846                    $intDataId,
1847                    $intSkip
1848                );
1849            }
1850            if ($key == 'use') {
1851                $value = $this->checkTpl(
1852                    $value,
1853                    'use_template_tploptions',
1854                    'tbl_servicetemplate',
1855                    $intDataId,
1856                    $intSkip
1857                );
1858            }
1859        }
1860        if ($strTableName == 'tbl_contact') {
1861            if ($key == 'use_template') {
1862                $key = 'use';
1863            }
1864            $strVIValues  = 'host_notifications_enabled,service_notifications_enabled,can_submit_commands,';
1865            $strVIValues .= 'retain_status_information,retain_nonstatus_information';
1866            if (\in_array($key, explode(',', $strVIValues), true)) {
1867                if ($value == -1) {
1868                    $value = 'null';
1869                }
1870                if ($value == 3) {
1871                    $value = 'null';
1872                }
1873            }
1874            if ($key == 'contactgroups') {
1875                $value = $this->checkTpl($value, 'contactgroups_tploptions', 'tbl_contact', $intDataId, $intSkip);
1876            }
1877            if ($key == 'host_notification_commands') {
1878                $value = $this->checkTpl(
1879                    $value,
1880                    'host_notification_commands_tploptions',
1881                    'tbl_contact',
1882                    $intDataId,
1883                    $intSkip
1884                );
1885            }
1886            if ($key == 'service_notification_commands') {
1887                $value = $this->checkTpl(
1888                    $value,
1889                    'service_notification_commands_tploptions',
1890                    'tbl_contact',
1891                    $intDataId,
1892                    $intSkip
1893                );
1894            }
1895            if ($key == 'use') {
1896                $value = $this->checkTpl($value, 'use_template_tploptions', 'tbl_contact', $intDataId, $intSkip);
1897            }
1898        }
1899        if ($strTableName == 'tbl_contacttemplate') {
1900            if ($key == 'template_name') {
1901                $key = 'name';
1902            }
1903            if ($key == 'use_template') {
1904                $key = 'use';
1905            }
1906            $strVIValues  = 'host_notifications_enabled,service_notifications_enabled,can_submit_commands,';
1907            $strVIValues .= 'retain_status_information,retain_nonstatus_information';
1908            if (in_array($key, explode(',', $strVIValues), true)) {
1909                if ($value == -1) {
1910                    $value = 'null';
1911                }
1912                if ($value == 3) {
1913                    $value = 'null';
1914                }
1915            }
1916            if ($key == 'contactgroups') {
1917                $value = $this->checkTpl(
1918                    $value,
1919                    'contactgroups_tploptions',
1920                    'tbl_contacttemplate',
1921                    $intDataId,
1922                    $intSkip
1923                );
1924            }
1925            if ($key == 'host_notification_commands') {
1926                $value = $this->checkTpl(
1927                    $value,
1928                    'host_notification_commands_tploptions',
1929                    'tbl_contacttemplate',
1930                    $intDataId,
1931                    $intSkip
1932                );
1933            }
1934            if ($key == 'service_notification_commands') {
1935                $value = $this->checkTpl(
1936                    $value,
1937                    'service_notification_commands_tploptions',
1938                    'tbl_contacttemplate',
1939                    $intDataId,
1940                    $intSkip
1941                );
1942            }
1943            if ($key == 'use') {
1944                $value = $this->checkTpl(
1945                    $value,
1946                    'use_template_tploptions',
1947                    'tbl_contacttemplate',
1948                    $intDataId,
1949                    $intSkip
1950                );
1951            }
1952        }
1953        if ((($strTableName == 'tbl_hosttemplate') || ($strTableName == 'tbl_servicetemplate') ||
1954                ($strTableName == 'tbl_contacttemplate')) && $key == 'register') {
1955            $value = '0';
1956        }
1957        if ($strTableName == 'tbl_timeperiod' && $key == 'use_template') {
1958            $key = 'use';
1959        }
1960    }
1961
1962    /**
1963     * Open configuration file
1964     * @param string $strFile                   File name
1965     * @param int $intConfigID                  Configuration ID
1966     * @param int $intType                      Type ID
1967     * @param resource|bool $resConfigFile      Temporary or configuration file ressource (by reference)
1968     * @param string $strConfigFile             Configuration file name (by reference)
1969     * @return int                              0 = successful / 1 = error
1970     */
1971    private function getConfigFile($strFile, $intConfigID, $intType, &$resConfigFile, &$strConfigFile)
1972    {
1973        // Variable definitions
1974        $strBaseDir   = '';
1975        $intMethod    = 1;
1976        $intReturn    = 0;
1977        // Get config data
1978        if ($intType == 1) {
1979            $this->getConfigData($intConfigID, 'hostconfig', $strBaseDir);
1980            $strType = 'host';
1981        } elseif ($intType == 2) {
1982            $this->getConfigData($intConfigID, 'serviceconfig', $strBaseDir);
1983            $strType = 'service';
1984        } else {
1985            $this->getConfigData($intConfigID, 'basedir', $strBaseDir);
1986            $strType = 'basic';
1987        }
1988        $this->getConfigData($intConfigID, 'method', $intMethod);
1989        // Backup config file
1990        $this->moveFile($strType, $strFile, $intConfigID);
1991        // Variable definition
1992        $strConfigFile = $strBaseDir. '/' .$strFile;
1993        // Local file system
1994        if ($intMethod == 1) {
1995            // Save configuration file
1996            if (is_writable($strConfigFile) || (!file_exists($strConfigFile) && is_writable($strBaseDir))) {
1997                $resConfigFile = fopen($strConfigFile, 'wb');
1998                chmod($strConfigFile, 0644);
1999            } else {
2000                $this->myDataClass->writeLog(translate('Configuration write failed:'). ' ' .$strFile);
2001                $this->processClassMessage(translate('Cannot open/overwrite the configuration file (check the '
2002                        .'permissions)!'). '::', $this->strErrorMessage);
2003                $intReturn = 1;
2004            }
2005        } elseif ($intMethod == 2) { // Remote file (FTP)
2006            // Check connection
2007            if (empty($this->resConnectId) || !\is_resource($this->resConnectId) ||
2008                ($this->resConnectType != 'FTP')) {
2009                $intReturn = $this->getFTPConnection($intConfigID);
2010            }
2011            if ($intReturn == 0) {
2012                // Open the config file
2013                if (isset($this->arrSettings['path']) && isset($this->arrSettings['path']['tempdir'])) {
2014                    $strConfigFile = tempnam($this->arrSettings['path']['tempdir'], 'nagiosql');
2015                } else {
2016                    $strConfigFile = tempnam(sys_get_temp_dir(), 'nagiosql');
2017                }
2018                $resConfigFile = fopen($strConfigFile, 'wb');
2019            }
2020        } elseif ($intMethod == 3) { // Remote file (SFTP)
2021            // Check connection
2022            if (empty($this->resConnectId) || !\is_resource($this->resConnectId) ||
2023                ($this->resConnectType != 'SSH')) {
2024                $intReturn = $this->getSSHConnection($intConfigID);
2025            }
2026            if ($intReturn == 0) {
2027                if (isset($this->arrSettings['path']) && isset($this->arrSettings['path']['tempdir'])) {
2028                    $strConfigFile = tempnam($this->arrSettings['path']['tempdir'], 'nagiosql');
2029                } else {
2030                    $strConfigFile = tempnam(sys_get_temp_dir(), 'nagiosql');
2031                }
2032                $resConfigFile = fopen($strConfigFile, 'wb');
2033            }
2034        }
2035        return $intReturn;
2036    }
2037
2038    /**
2039     * Write configuration file
2040     * @param string $strData               Data string
2041     * @param string $strFile               File name
2042     * @param int $intType                  Type ID
2043     * @param int $intConfigID              Configuration target ID
2044     * @param resource $resConfigFile       Temporary or configuration file ressource
2045     * @param string $strConfigFile         Configuration file name
2046     * @return int                          0 = successful / 1 = error
2047     */
2048    private function writeConfigFile($strData, $strFile, $intType, $intConfigID, $resConfigFile, $strConfigFile)
2049    {
2050        // Variable definitions
2051        $intReturn = 0;
2052        // Get config data
2053        if ($intType == 1) {
2054            $this->getConfigData($intConfigID, 'hostconfig', $strBaseDir);
2055        } elseif ($intType == 2) {
2056            $this->getConfigData($intConfigID, 'serviceconfig', $strBaseDir);
2057        } else {
2058            $this->getConfigData($intConfigID, 'basedir', $strBaseDir);
2059        }
2060        $this->getConfigData($intConfigID, 'method', $intMethod);
2061        $strData  = str_replace("\r\n", "\n", $strData);
2062        fwrite($resConfigFile, $strData);
2063        // Local filesystem
2064        if ($intMethod == 1) {
2065            fclose($resConfigFile);
2066        } elseif ($intMethod == 2) { // FTP access
2067            // SSH Possible
2068            if (!\function_exists('ftp_put')) {
2069                $this->processClassMessage(translate('FTP module not loaded!'). '::', $this->strErrorMessage);
2070                $intReturn = 1;
2071            } else {
2072                $intErrorReporting = error_reporting();
2073                error_reporting(0);
2074                if (!ftp_put($this->resConnectId, $strBaseDir . '/' . $strFile, $strConfigFile, FTP_ASCII)) {
2075                    $arrError = error_get_last();
2076                    error_reporting($intErrorReporting);
2077                    $this->processClassMessage(translate('Cannot open/overwrite the configuration file (FTP connection '
2078                            .'failed)!') . '::', $this->strErrorMessage);
2079                    if ($arrError['message'] != '') {
2080                        $this->processClassMessage($arrError['message'] . '::', $this->strErrorMessage);
2081                    }
2082                    $intReturn = 1;
2083                }
2084                error_reporting($intErrorReporting);
2085                ftp_close($this->resConnectId);
2086                fclose($resConfigFile);
2087            }
2088        } elseif ($intMethod == 3) { // SSH access
2089            // SSH Possible
2090            if (!\function_exists('ssh2_scp_send')) {
2091                $this->processClassMessage(translate('SSH module not loaded!'). '::', $this->strErrorMessage);
2092                $intReturn = 1;
2093            } else {
2094                $intErrorReporting = error_reporting();
2095                error_reporting(0);
2096                if (!ssh2_scp_send($this->resConnectId, $strConfigFile, $strBaseDir . '/' . $strFile, 0644)) {
2097                    $arrError = error_get_last();
2098                    error_reporting($intErrorReporting);
2099                    $this->processClassMessage(translate('Cannot open/overwrite the configuration file (remote SFTP)!').
2100                        '::', $this->strErrorMessage);
2101                    if ($arrError['message'] != '') {
2102                        $this->processClassMessage($arrError['message'] . '::', $this->strErrorMessage);
2103                    }
2104                    $this->resConnectId = null;
2105                    $intReturn = 1;
2106                }
2107                error_reporting($intErrorReporting);
2108                fclose($resConfigFile);
2109                unlink($strConfigFile);
2110                $this->resConnectId = null;
2111            }
2112        }
2113        if ($intReturn == 0) {
2114            $this->myDataClass->writeLog(translate('Configuration successfully written:') . ' ' . $strFile);
2115            $this->processClassMessage(translate('Configuration file successfully written!').
2116                '::', $this->strInfoMessage);
2117        }
2118        return $intReturn;
2119    }
2120
2121    /**
2122     * Process special settings based on template option
2123     * @param string $strValue              Original data value
2124     * @param string $strKeyField           Template option field name
2125     * @param string $strTable              Table name
2126     * @param int $intId                    Dataset ID
2127     * @param int $intSkip                  Skip value (by reference)
2128     * @return string                       Manipulated data value
2129     */
2130    public function checkTpl($strValue, $strKeyField, $strTable, $intId, &$intSkip)
2131    {
2132        if ($this->intNagVersion < 3) {
2133            return $strValue;
2134        }
2135        $strSQL   = 'SELECT `' .$strKeyField. '` FROM `' .$strTable."` WHERE `id` = $intId";
2136        $intValue = $this->myDBClass->getFieldData($strSQL);
2137        if ($intValue == 0) {
2138            return('+' .$strValue);
2139        }
2140        if ($intValue == 1) {
2141            $intSkip = 0;
2142            return 'null';
2143        }
2144        return $strValue;
2145    }
2146
2147    /**
2148     * @param array $arrData                    Dataset array
2149     * @param string $strDataValue              Data value
2150     * @param array $elem                       Relation data array
2151     * @param string $strDomainWhere1           SQL WHERE add-in
2152     * @return int                              0 = use data / 1 = skip data
2153     */
2154    private function processRelation1($arrData, &$strDataValue, $elem, $strDomainWhere1)
2155    {
2156        // Define variables
2157        $arrDataRel      = array();
2158        $intDataCountRel = 0;
2159        $intReturn       = 0;
2160        // Get relation data
2161        $strSQLRel = 'SELECT `' . $elem['tableName1'] . '`.`' . $elem['target1'] . '`, `' . $elem['linkTable'] .
2162            '`.`exclude` FROM `' . $elem['linkTable'] . '` LEFT JOIN `' . $elem['tableName1'] .
2163            '` ON `' . $elem['linkTable'] . '`.`idSlave` = `' . $elem['tableName1'] . '`.`id`' .
2164            'WHERE `idMaster`=' . $arrData['id'] . " AND `active`='1' AND $strDomainWhere1" .
2165            'ORDER BY `' . $elem['tableName1'] . '`.`' . $elem['target1'] . '`';
2166        $booReturn = $this->myDBClass->hasDataArray($strSQLRel, $arrDataRel, $intDataCountRel);
2167        if ($booReturn && ($intDataCountRel != 0)) {
2168            // Rewrite $strDataValue with returned relation data
2169            if ($strDataValue == 2) {
2170                $strDataValue = '*,';
2171            } else {
2172                $strDataValue = '';
2173            }
2174            foreach ($arrDataRel as $data) {
2175                if ($data['exclude'] == 0) {
2176                    $strDataValue .= $data[$elem['target1']] . ',';
2177                } elseif ($this->intNagVersion >= 3) {
2178                    $strDataValue .= '!' . $data[$elem['target1']] . ',';
2179                }
2180            }
2181            $strDataValue = substr($strDataValue, 0, -1);
2182            if ($strDataValue == '') {
2183                $intReturn = 1;
2184            }
2185        } else {
2186            if ($strDataValue == 2) {
2187                $strDataValue = '*';
2188            } else {
2189                $intReturn = 1;
2190            }
2191        }
2192        return $intReturn;
2193    }
2194
2195    /**
2196     * @param array $arrData                    Dataset array
2197     * @param string $strDataValue              Data value
2198     * @param array $elem                       Relation data array
2199     * @param string $strDomainWhere1           SQL WHERE add-in
2200     * @return int                              0 = use data / 1 = skip data
2201     */
2202    private function processRelation2($arrData, &$strDataValue, $elem, $strDomainWhere1)
2203    {
2204        // Define variables
2205        $arrDataRel      = array();
2206        $arrField        = array();
2207        $intDataCountRel = 0;
2208        $intReturn       = 0;
2209        $strCommand      = '';
2210        // Get relation data
2211        if (($elem['tableName1'] == 'tbl_command') &&
2212            (substr_count($arrData[$elem['fieldName']], '!') != 0)) {
2213            $arrField = explode('!', $arrData[$elem['fieldName']]);
2214            $strCommand = strstr($arrData[$elem['fieldName']], '!');
2215            $strSQLRel = 'SELECT `' . $elem['target1'] . '` FROM `' . $elem['tableName1'] . '`' .
2216                'WHERE `id`=' . $arrField[0] . "  AND `active`='1' AND $strDomainWhere1";
2217        } else {
2218            $strSQLRel = 'SELECT `' . $elem['target1'] . '` FROM `' . $elem['tableName1'] . '`' .
2219                'WHERE `id`=' . $arrData[$elem['fieldName']] . "  AND `active`='1' AND $strDomainWhere1";
2220        }
2221        $booReturn = $this->myDBClass->hasDataArray($strSQLRel, $arrDataRel, $intDataCountRel);
2222        if ($booReturn && ($intDataCountRel != 0)) {
2223            // Rewrite $strDataValue with returned relation data
2224            if (($elem['tableName1'] == 'tbl_command') && (substr_count($strDataValue, '!') != 0)) {
2225                $strDataValue = $arrDataRel[0][$elem['target1']] . $strCommand;
2226            } else {
2227                $strDataValue = $arrDataRel[0][$elem['target1']];
2228            }
2229        } else {
2230            if (($elem['tableName1'] == 'tbl_command') && (substr_count($strDataValue, '!') != 0) &&
2231                ($arrField[0] == -1)) {
2232                $strDataValue = 'null';
2233            } else {
2234                $intReturn = 1;
2235            }
2236        }
2237        return $intReturn;
2238    }
2239
2240    /**
2241     * @param array $arrData                    Dataset array
2242     * @param string $strDataValue              Data value
2243     * @param array $elem                       Relation data array
2244     * @param string $strDomainWhere1           SQL WHERE add-in
2245     * @return int                              0 = use data / 1 = skip data
2246     */
2247    private function processRelation3($arrData, &$strDataValue, $elem, $strDomainWhere1)
2248    {
2249        // Define variables
2250        $arrDataRel      = array();
2251        $intDataCountRel = 0;
2252        $intReturn       = 0;
2253        // Get relation data
2254        $strSQLRel = 'SELECT * FROM `' .$elem['linkTable']. '` WHERE `idMaster`=' .$arrData['id']. ' ORDER BY idSort';
2255        $booReturn = $this->myDBClass->hasDataArray($strSQLRel, $arrDataRel, $intDataCountRel);
2256        if ($booReturn && ($intDataCountRel != 0)) {
2257            // Rewrite $strDataValue with returned relation data
2258            $strDataValue = '';
2259            foreach ($arrDataRel as $data) {
2260                if ($data['idTable'] == 1) {
2261                    $strSQLName = 'SELECT `' .$elem['target1']. '` FROM `' .$elem['tableName1']. '`' .
2262                        "WHERE `active`='1' AND $strDomainWhere1 AND `id`=".$data['idSlave'];
2263                } else {
2264                    $strSQLName = 'SELECT `' .$elem['target2']. '` FROM `' .$elem['tableName2']. '`' .
2265                        "WHERE `active`='1' AND $strDomainWhere1 AND `id`=".$data['idSlave'];
2266                }
2267                $strDataValue .= $this->myDBClass->getFieldData($strSQLName) . ',';
2268            }
2269            $strDataValue = substr($strDataValue, 0, -1);
2270        } else {
2271            $intReturn = 1;
2272        }
2273        return $intReturn;
2274    }
2275
2276    /**
2277     * @param array $arrData                    Dataset array
2278     * @param string $strDataValue              Data value
2279     * @param array $elem                       Relation data array
2280     * @param string $strDomainWhere1           SQL WHERE add-in
2281     * @return int                              0 = use data / 1 = skip data
2282     */
2283    private function processRelation4($arrData, &$strDataValue, $elem, $strDomainWhere1)
2284    {
2285        // Define variables
2286        $arrDataRel      = array();
2287        $intDataCountRel = 0;
2288        $intReturn       = 0;
2289        // Get relation data
2290        $strSQLRel = 'SELECT `' .$elem['linkTable']. '`.`strSlave`, `' .$elem['linkTable']. '`.`exclude` ' .
2291            'FROM `' .$elem['linkTable']. '` ' .
2292            'LEFT JOIN `tbl_service` ON `' .$elem['linkTable']. '`.`idSlave`=`tbl_service`.`id` ' .
2293            'WHERE `' .$elem['linkTable']. '`.`idMaster`=' .$arrData['id']." AND `active`='1' AND ".
2294            $strDomainWhere1. ' ' .
2295            'ORDER BY `' .$elem['linkTable']. '`.`strSlave`';
2296        $booReturn = $this->myDBClass->hasDataArray($strSQLRel, $arrDataRel, $intDataCountRel);
2297        if ($booReturn && ($intDataCountRel != 0)) {
2298            // Rewrite $strDataValue with returned relation data
2299            if ($strDataValue == 2) {
2300                $strDataValue = '*,';
2301            } else {
2302                $strDataValue = '';
2303            }
2304            foreach ($arrDataRel as $data) {
2305                if ($data['exclude'] == 0) {
2306                    $strDataValue .= $data['strSlave'] . ',';
2307                } elseif ($this->intNagVersion >= 3) {
2308                    $strDataValue .= '!' . $data['strSlave'] . ',';
2309                }
2310            }
2311            $strDataValue = substr($strDataValue, 0, -1);
2312            if ($strDataValue == '') {
2313                $intReturn = 1;
2314            }
2315        } else {
2316            if ($strDataValue == 2) {
2317                $strDataValue = '*';
2318            } else {
2319                $intReturn = 1;
2320            }
2321        }
2322        return $intReturn;
2323    }
2324
2325    /**
2326     * @param \HTML_Template_IT $resTemplate    Template object
2327     * @param array $arrData                    Dataset array
2328     * @param array $elem                       Relation data array
2329     * @return int                              0 = use data / 1 = skip data
2330     */
2331    private function processRelation5($resTemplate, $arrData, $elem)
2332    {
2333        // Define variables
2334        $arrDataRel      = array();
2335        $intDataCountRel = 0;
2336        $strSQLRel = 'SELECT * FROM `tbl_variabledefinition` LEFT JOIN `' .$elem['linkTable']. '` ' .
2337            'ON `id`=`idSlave` WHERE `idMaster`=' .$arrData['id']. ' ORDER BY `name`';
2338        $booReturn = $this->myDBClass->hasDataArray($strSQLRel, $arrDataRel, $intDataCountRel);
2339        if ($booReturn && ($intDataCountRel != 0)) {
2340            foreach ($arrDataRel as $vardata) {
2341                // Insert fill spaces
2342                $strFillLen = (30 - \strlen($vardata['name']));
2343                $strSpace = ' ';
2344                for ($f = 0; $f < $strFillLen; $f++) {
2345                    $strSpace .= ' ';
2346                }
2347                $resTemplate->setVariable('ITEM_TITLE', $vardata['name'] . $strSpace);
2348                $resTemplate->setVariable('ITEM_VALUE', html_entity_decode($vardata['value'], ENT_QUOTES | ENT_XML1, 'UTF-8'));
2349                $resTemplate->parse('configline');
2350            }
2351        }
2352        return 1;
2353    }
2354
2355    /**
2356     * @param array $arrData                    Dataset array
2357     * @param string $strDataValue              Data value
2358     * @param array $elem                       Relation data array
2359     * @param string $strDomainWhere1           SQL WHERE add-in
2360     * @return int                              0 = use data / 1 = skip data
2361     */
2362    private function processRelation6($arrData, &$strDataValue, $elem, $strDomainWhere1)
2363    {
2364        // Define variables
2365        $arrDataRel = array();
2366        $arrHG1 = array();
2367        $arrHG2 = array();
2368        $intDataCountRel = 0;
2369        $intHG1 = 0;
2370        $intHG2 = 0;
2371        $intReturn = 0;
2372        // Get relation data
2373        $strSQLMaster = 'SELECT * FROM `' . $elem['linkTable'] . '` WHERE `idMaster`=' . $arrData['id'];
2374        $booReturn = $this->myDBClass->hasDataArray($strSQLMaster, $arrDataRel, $intDataCountRel);
2375        if ($booReturn && ($intDataCountRel != 0)) {
2376            // Rewrite $strDataValue with returned relation data
2377            $strDataValue = '';
2378            foreach ($arrDataRel as $data) {
2379                // Get excluded hosts
2380                $arrExclude = array();
2381                $strSQLEx   = 'SELECT `idSlave` FROM `tbl_lnkServiceToHost` WHERE `exclude`=1 AND `idMaster`=' .
2382                    $data['idSlaveS'];
2383                $booReturn = $this->myDBClass->hasDataArray($strSQLEx, $arrEx, $intEx);
2384                if ($booReturn && ($intEx != 0)) {
2385                    foreach ($arrEx as $elemEx) {
2386                        $arrExclude[] = $elemEx['idSlave'];
2387                    }
2388                }
2389                if ($data['idSlaveHG'] != 0) {
2390                    // Get Sevices
2391                    $strSQLSrv = 'SELECT `' . $elem['target2'] . '` FROM `' . $elem['tableName2'] .
2392                        '` WHERE `id`=' . $data['idSlaveS'];
2393                    $strService = $this->myDBClass->getFieldData($strSQLSrv);
2394                    $strSQLHG1 = 'SELECT `host_name`, `idSlave` FROM `tbl_host` ' .
2395                        'LEFT JOIN `tbl_lnkHostgroupToHost` ON `id`=`idSlave` ' .
2396                        'WHERE `idMaster`=' . $data['idSlaveHG'] . "  AND `active`='1' AND `exclude`=0 " .
2397                        "AND $strDomainWhere1";
2398                    $booReturn = $this->myDBClass->hasDataArray($strSQLHG1, $arrHG1, $intHG1);
2399                    if ($booReturn && ($intHG1 != 0)) {
2400                        foreach ($arrHG1 as $elemHG1) {
2401                            if (!in_array($elemHG1['idSlave'], $arrExclude, true) &&
2402                                substr_count($strDataValue, $elemHG1['host_name'] . ',' . $strService) == 0) {
2403                                $strDataValue .= $elemHG1['host_name'] . ',' . $strService . ',';
2404                            }
2405                        }
2406                    }
2407                    $strSQLHG2 = 'SELECT `host_name`, `idMaster` FROM `tbl_host` ' .
2408                        'LEFT JOIN `tbl_lnkHostToHostgroup` ON `id`=`idMaster` ' .
2409                        'WHERE `idSlave`=' . $data['idSlaveHG'] . " AND `active`='1' AND  `exclude`=0 " .
2410                        "AND $strDomainWhere1";
2411                    $booReturn = $this->myDBClass->hasDataArray($strSQLHG2, $arrHG2, $intHG2);
2412                    if ($booReturn && ($intHG2 != 0)) {
2413                        foreach ($arrHG2 as $elemHG2) {
2414                            if (!in_array($elemHG2['idMaster'], $arrExclude, true) &&
2415                                substr_count($strDataValue, $elemHG2['host_name'] . ',' . $strService) == 0) {
2416                                $strDataValue .= $elemHG2['host_name'] . ',' . $strService . ',';
2417                            }
2418                        }
2419                    }
2420                } else {
2421                    $strSQLHost = 'SELECT `' . $elem['target1'] . '` FROM `' . $elem['tableName1'] . '` ' .
2422                        'WHERE `id`=' . $data['idSlaveH'] . "  AND `active`='1' AND $strDomainWhere1";
2423                    $strHost = $this->myDBClass->getFieldData($strSQLHost);
2424                    $strSQLSrv = 'SELECT `' . $elem['target2'] . '` FROM `' . $elem['tableName2'] . '` ' .
2425                        'WHERE `id`=' . $data['idSlaveS'] . "  AND `active`='1' AND $strDomainWhere1";
2426                    $strService = $this->myDBClass->getFieldData($strSQLSrv);
2427                    if (($strHost != '') && ($strService != '') &&
2428                        substr_count($strDataValue, $strHost . ',' . $strService) == 0 &&
2429                        !in_array($data['idSlaveH'], $arrExclude, true)) {
2430                        $strDataValue .= $strHost . ',' . $strService . ',';
2431                    }
2432                }
2433            }
2434            $strDataValue = substr($strDataValue, 0, -1);
2435            if ($strDataValue == '') {
2436                $intReturn = 1;
2437            }
2438        } else {
2439            $intReturn = 1;
2440        }
2441        return $intReturn;
2442    }
2443
2444    /**
2445     * @param array $arrData                    Dataset array
2446     * @param string $strDataValue              Data value
2447     * @param array $elem                       Relation data array
2448     * @return int                              0 = use data / 1 = skip data
2449     */
2450    private function processRelation7($arrData, &$strDataValue, $elem)
2451    {
2452        $intReturn = 1;
2453        // Get relation data
2454        $strSQLMaster = 'SELECT * FROM `' . $elem['linkTable'] . '` WHERE `idMaster`=' . $arrData['id'];
2455        $booReturn = $this->myDBClass->hasDataArray($strSQLMaster, $arrDataRel, $intDataCountRel);
2456        if ($booReturn && ($intDataCountRel != 0)) {
2457            // Rewrite $strDataValue with returned relation data
2458            $strDataValue = '';
2459            /** @var array $arrDataRel */
2460            foreach ($arrDataRel as $data) {
2461                $strSQL = 'SELECT host_name FROM tbl_host WHERE id=' .$data['idHost'];
2462                $strHost = $this->myDBClass->getFieldData($strSQL);
2463                $strSQL = 'SELECT service_description FROM tbl_service WHERE id=' .$data['idSlave'];
2464                $strService = $this->myDBClass->getFieldData($strSQL);
2465                $strDataValue .= $strHost . ',' . $strService . ',';
2466                $intReturn = 0;
2467            }
2468            $strDataValue = substr($strDataValue, 0, -1);
2469        }
2470        return $intReturn;
2471    }
2472}
2473