Subversion Repositories vnag

Rev

Rev 52 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 52 Rev 55
1
<?php /* <ViaThinkSoftSignature>
1
<?php /* <ViaThinkSoftSignature>
2
Wg+EYgkO45tkUYzHp3wFsbyVVQadb07ttd04MjjH7C7i7UygR0ZiFQfpqQ5pc6i6M
2
ogeU7sU9og0Wo32ZGa8L9wIY+V280zVqPOo8/wFGNLcjhWISQDQiY/6hyvIb0IODQ
3
bd+RpyfWYxeMRU8KLRO/I2CymXtB/L11tisWnZRRVSBBsoVr73xZFIDrZiMC+Amxs
3
7GQ2eU7C0QiTPiaMy7C1H9EXqhoCyKtDqTtkXso2KCYTNqkUtcna/UjX12mZwvQ89
4
/WqnIRJIVCCniLDPPzp+WlIq7/e8djQukSglqSsL4Dhvk37k7iWJuAkyoFodffOVQ
4
ltvtnRJeC1OXO1XcwE0/L1XZlo68dYSvgmufJQheVYAj9uU7PW9sb2YH+WTK8BM2M
5
FHLvcfvw/yjzSvLzE/3kAOToZ7OmNBfVhJKcUOYouYINCrxrqvY7FfOWz/GftnHkV
5
JUHn+JdLnY9QUlOLp6bVYXJqDxqzj81uHGH5oXnhrqvsKvd8CrhUwy2X6fCpWgyId
6
5vjYJrTaoKpYW3N4Xoi0HBVfzTKQjND4ihulrkV4p6PhHdbdD5dXNaXUERgjAqeED
6
S46OaEpBykHYdPIwFo04G3HfIyeWCQxnOIcxBbeuz1jee48I5BHFJczmkpYerE/Ao
7
tvpQzPHqA25Q74llkjFDeyNFHkEMKmiqdVbO/LcWHetROqMRu2on6Eghy7BCgqsfD
7
V0zlIF7cXWvSNn2XVC9+AyfDIA/BmtafqkOnDKHNrVmsQHx0QBL++C6ZoooE78ArT
8
lPXeHS2EN+AhcfPpFBZ59crM/qWw+LSrbQfvI/SScwlT3z0+vjKRuLOBvz2US3Mce
8
rkmjPLr8uK896O1qEppZ67rWDRdsZNMQIpk9QDS4PM6SQn6dfawxYxWA12h6+iFOB
9
UMwSkE+BGNW5LEup7RatyapYEa6ueanzzPMMv+DUvBxTfVV0l6JXteQCbWURMBSOg
9
vuYVdNL17sZABPbpGqhnJCNS6e/nHgeym6b5XVuN+d8u+R6Fm7SPj6VttIDgF9Ux6
10
CxmMT5ewI4xaGn94yLmW95YIKdsF6upDLkG+Fqpjya0so0wKOyVc4RYgmAuo5zJvR
10
vBgpF+v9hSdgbup9ClFX1XJGsTmwS4PWB667oJdBCyHpzyvkpvw8VY/wAIKlkEdD+
11
7n89KCF4Z4Gl8AYyNnlKWDYHi2CYdxmfngr0eY5GyHor9qIN8wNdMerTkYQ6R1iG3
11
O2lRasjrVrvNGp8LlBWlheMwEexhS2tmCZ6W+oP21puOsKhtCZD5a0PWjd/Oyo5bD
12
ZGv0KPFfTdQyVOuiVnVDk5rcGwxMEgckIJSuBu7cy8oGq/wMPjdwGlEXWv2dGe7dY
12
DKlbuNs4pXokF5C0nVyHH8H/6BGGdRmTwUc64dE5RrSZlRi+2PvCJsAGzJeIagsVc
13
KxtB4m4lOeW3izrPyS9LppBFhjQ0CL9KZ4VJHpyZcZJ0LYGA8wX3bCRyaXRzjbDUS
13
BrDl7uNe84b9sBJlJtIiWulE7pxg6wwk9dcSznUEzEsq/LnpKANxv4l8kCckP1BoI
14
blT9mRURn6gLOmn1u0bjPqEV2GpZte1XaSB109vmgsdjCc07Wek3ItAw4KrKN29/j
14
yA4FahIjnsByB4vpV+zwX59DxVtmZH4nNigtZIL9j5cEjgb5XHwYDyh/nlStEj8FL
15
8ZKHvpamQoN6oGLr3aMzkuNhYmrNuJBJt1m7PsqTA4ZoB1JvJ3AzTBaBjYcAIt+tq
15
wHJ0YMnYuItDuiW2j1ZBCj/ZemKJNHDjLtlo9QOsIWrcKgm/CRO/08WMt62CL4GvJ
16
QE9XHcjudqlECrbApzMmRzCBb2MVRnuIgaMZ6dizCPWJl/bkuqCjizMV2TbLLUnIx
16
gqvRGbkZKuJMQTBkSxR9Ex6MyzhknWokHVV3xAWAb62B6wILFtWAYVgAgzcERr+Qd
17
/fRb2YX98uPNsdWRTt8kZJit6QmwPi6YKJO3YKZUkaCtaM7mwjVZ0g/ZNkX2VBZ8k
17
suffXc41q5xjx1jpBkgCN26wj96fPu+jeKHS3/m/ck4PLNsWwicNGOS/uppJTb8d+
18
OW0JumHLXOcbQLCi6dVjsyp4fsEXmiQYLksGQtyhDtGVj/MVDz0MZMJosClcqjfCa
18
FvNy7yTk4E91H9ui4Us6RzoqbRT+Z8EQQqBl5nLkzqNzNN4gMgBNvICfsWBNJbHpY
19
M3DD8exxuvwFLIj9+y52IZKxOlsW/fB/fQiBmay/OOsyYHGMfVEpFZNnOMweB13xR
19
enq7LIYYfqBISDJ5WcWw/Z51e3z8Uk9TOOBNkcpRyjUe/F1Q3bhRLrz/eeXnBzkG0
20
SpB8NaUON7MUCKwG1PfdmQcMZpwA01QREkVW4/u75qPr3OoyyeJ3/zYJhJXSv3md6
20
7Cji5xIasOO6qkgZSbcNqqvQ0chkrfOgB2FnsT8WUFIYtLaJOXHV/r0VGbTFhOTSv
21
V6V53FLy2SG13eHajqVQDLrYDqu56V/GL/tI4JLIoFhKr2gzj2lFJFGyr4peCipRD
21
2968Q3wsFxstk8DlKtWgl3LeYb2ECvNPFM5iZrisvx8EGcZNp2xJDniE9xorfKJTl
22
ijdZWqbFUcDFJS8c0lJ1P68D1ATEB0m92CDen1ttVUCOUO5CK0+Qc5MbKCTXlr2OY
22
Gh43qnLC0djTq+mIp8V2fP8QqK8MoSxPiowJIyzXUCD2YOppdiYeaFdqXyZioy9wJ
23
A==
23
Q==
24
</ViaThinkSoftSignature> */ ?>
24
</ViaThinkSoftSignature> */ ?>
25
<?php
25
<?php
26
 
26
 
27
/*
27
/*
28
 
28
 
29
      VNag - Nagios Framework for PHP                  (C) 2014-2022
29
      VNag - Nagios Framework for PHP                  (C) 2014-2022
30
      __     ___      _____ _     _       _     ____         __ _
30
      __     ___      _____ _     _       _     ____         __ _
31
      \ \   / (_) __ |_   _| |__ (_)_ __ | | __/ ___|  ___  / _| |_
31
      \ \   / (_) __ |_   _| |__ (_)_ __ | | __/ ___|  ___  / _| |_
32
       \ \ / /| |/ _` || | | '_ \| | '_ \| |/ /\___ \ / _ \| |_| __|
32
       \ \ / /| |/ _` || | | '_ \| | '_ \| |/ /\___ \ / _ \| |_| __|
33
        \ V / | | (_| || | | | | | | | | |   <  ___) | (_) |  _| |_
33
        \ V / | | (_| || | | | | | | | | |   <  ___) | (_) |  _| |_
34
         \_/  |_|\__,_||_| |_| |_|_|_| |_|_|\_\|____/ \___/|_|  \__|
34
         \_/  |_|\__,_||_| |_| |_|_|_| |_|_|\_\|____/ \___/|_|  \__|
35
 
35
 
36
      Developed by Daniel Marschall             www.viathinksoft.com
36
      Developed by Daniel Marschall             www.viathinksoft.com
37
      Licensed under the terms of the Apache 2.0 license
37
      Licensed under the terms of the Apache 2.0 license
38
      Revision 2022-06-06
38
      Revision 2022-06-06
39
 
39
 
40
*/
40
*/
41
 
41
 
42
/****************************************************************************************************
42
/****************************************************************************************************
43
 
43
 
44
Introduction:
44
Introduction:
45
 
45
 
46
        VNag is a small framework for Nagios Plugin Developers who use PHP CLI scripts.
46
        VNag is a small framework for Nagios Plugin Developers who use PHP CLI scripts.
47
        The main purpose of VNag is to make the development of plugins as easy as possible, so that
47
        The main purpose of VNag is to make the development of plugins as easy as possible, so that
48
        the developer can concentrate on the actual work. VNag will try to automate as much
48
        the developer can concentrate on the actual work. VNag will try to automate as much
49
        as possible.
49
        as possible.
50
 
50
 
51
        Please note that your script should include the +x chmod flag:
51
        Please note that your script should include the +x chmod flag:
52
                chmod +x myscript.php
52
                chmod +x myscript.php
53
 
53
 
54
        Please see the the demo/ folder for a few examples how to use this framework.
54
        Please see the the demo/ folder for a few examples how to use this framework.
55
 
55
 
56
Arguments:
56
Arguments:
57
 
57
 
58
        Example:
58
        Example:
59
                $this->addExpectedArgument($argSilent = new VNagArgument('s', 'silent', VNagArgument::VALUE_FORBIDDEN, null,       'Description for the --silent output', $defaultValue));
59
                $this->addExpectedArgument($argSilent = new VNagArgument('s', 'silent', VNagArgument::VALUE_FORBIDDEN, null,       'Description for the --silent output', $defaultValue));
60
                $this->addExpectedArgument($argHost   = new VNagArgument('H', 'host',   VNagArgument::VALUE_REQUIRED,  'hostname', 'Description for the --host output',   $defaultValue));
60
                $this->addExpectedArgument($argHost   = new VNagArgument('H', 'host',   VNagArgument::VALUE_REQUIRED,  'hostname', 'Description for the --host output',   $defaultValue));
61
 
61
 
62
        In the example above, the two argument objects $argSilent and $argHost were created.
62
        In the example above, the two argument objects $argSilent and $argHost were created.
63
        With these objects of the type VNagArgument, you can query the argument's value,
63
        With these objects of the type VNagArgument, you can query the argument's value,
64
        how often the argument was passed and if it is set:
64
        how often the argument was passed and if it is set:
65
 
65
 
66
                $argSilent->count();      // 1 if "-s" is passed, 2 if "-s -s" is passed etc.
66
                $argSilent->count();      // 1 if "-s" is passed, 2 if "-s -s" is passed etc.
67
                $argSilent->available();  // true if "-s" is passed, false otherwise
67
                $argSilent->available();  // true if "-s" is passed, false otherwise
68
                $argHost->getValue();     // "example.com" if "-h example.com" is passed
68
                $argHost->getValue();     // "example.com" if "-h example.com" is passed
69
 
69
 
70
        It is recommended that you pass every argument to $this->addExpectedArgument() .
70
        It is recommended that you pass every argument to $this->addExpectedArgument() .
71
        Using this way, VNag can generate a --help page for you, which lists all your arguments.
71
        Using this way, VNag can generate a --help page for you, which lists all your arguments.
72
        Future version of VNag may also require to have a complete list of all valid arguments,
72
        Future version of VNag may also require to have a complete list of all valid arguments,
73
        since the Nagios Development Guidelines recommend to output the usage information if an illegal
73
        since the Nagios Development Guidelines recommend to output the usage information if an illegal
74
        argument is passed. Due to PHP's horrible bad implementation of GNU's getopt(), this check for
74
        argument is passed. Due to PHP's horrible bad implementation of GNU's getopt(), this check for
75
        unknown arguments is currently not possible, and the developer of VNag does not want to use
75
        unknown arguments is currently not possible, and the developer of VNag does not want to use
76
        dirty hacks/workarounds, which would not match to all argument notation variations/styles.
76
        dirty hacks/workarounds, which would not match to all argument notation variations/styles.
77
        See: https://bugs.php.net/bug.php?id=68806
77
        See: https://bugs.php.net/bug.php?id=68806
78
             https://bugs.php.net/bug.php?id=65673
78
             https://bugs.php.net/bug.php?id=65673
79
             https://bugs.php.net/bug.php?id=26818
79
             https://bugs.php.net/bug.php?id=26818
80
 
80
 
81
Setting the status:
81
Setting the status:
82
 
82
 
83
        You can set the status with:
83
        You can set the status with:
84
                $this->setStatus(VNag::STATUS_OK);
84
                $this->setStatus(VNag::STATUS_OK);
85
        If you don't set a status, the script will return Unknown instead.
85
        If you don't set a status, the script will return Unknown instead.
86
        setStatus($status) will keep the most severe status, e.g.
86
        setStatus($status) will keep the most severe status, e.g.
87
                $this->setStatus(VNag::STATUS_CRITICAL);
87
                $this->setStatus(VNag::STATUS_CRITICAL);
88
                $this->setStatus(VNag::STATUS_OK);
88
                $this->setStatus(VNag::STATUS_OK);
89
        will result in a status "Critical".
89
        will result in a status "Critical".
90
        If you want to completely overwrite the status, use $force=true:
90
        If you want to completely overwrite the status, use $force=true:
91
                $this->setStatus(VNag::STATUS_CRITICAL);
91
                $this->setStatus(VNag::STATUS_CRITICAL);
92
                $this->setStatus(VNag::STATUS_OK, true);
92
                $this->setStatus(VNag::STATUS_OK, true);
93
        The status will now be "OK".
93
        The status will now be "OK".
94
 
94
 
95
        Possible status codes are:
95
        Possible status codes are:
96
                (For service plugins:)
96
                (For service plugins:)
97
                VNag::STATUS_OK       = 0;
97
                VNag::STATUS_OK       = 0;
98
                VNag::STATUS_WARNING  = 1;
98
                VNag::STATUS_WARNING  = 1;
99
                VNag::STATUS_CRITICAL = 2;
99
                VNag::STATUS_CRITICAL = 2;
100
                VNag::STATUS_UNKNOWN  = 3;
100
                VNag::STATUS_UNKNOWN  = 3;
101
 
101
 
102
                (For host plugins:)
102
                (For host plugins:)
103
                VNag::STATUS_UP       = 0;
103
                VNag::STATUS_UP       = 0;
104
                VNag::STATUS_DOWN     = 1;
104
                VNag::STATUS_DOWN     = 1;
105
 
105
 
106
Output:
106
Output:
107
 
107
 
108
        After the callback function cbRun() of your job has finished,
108
        After the callback function cbRun() of your job has finished,
109
        the framework will automatically output the results in the Nagios console output format,
109
        the framework will automatically output the results in the Nagios console output format,
110
        the visual HTML output and/or the invisible HTML output.
110
        the visual HTML output and/or the invisible HTML output.
111
 
111
 
112
        In case of CLI invokation, the Shell exit code will be remembered and
112
        In case of CLI invokation, the Shell exit code will be remembered and
113
        automatically returned by the shutdown handler once the script normally
113
        automatically returned by the shutdown handler once the script normally
114
        terminates. (In case you run different jobs, which is not recommended, the
114
        terminates. (In case you run different jobs, which is not recommended, the
115
        shutdown handler will output the baddest exit code).
115
        shutdown handler will output the baddest exit code).
116
 
116
 
117
        The Shell output format will be:
117
        The Shell output format will be:
118
                <Service status text>: <Comma separates messages> | <whitespace separated primary performance data>
118
                <Service status text>: <Comma separates messages> | <whitespace separated primary performance data>
119
                "Verbose information:"
119
                "Verbose information:"
120
                <Multiline verbose output> | <Multiline secondary performance data>
120
                <Multiline verbose output> | <Multiline secondary performance data>
121
 
121
 
122
        <Service status text> will be automatically created by VNag.
122
        <Service status text> will be automatically created by VNag.
123
 
123
 
124
        Verbose information are printed below the first line. Most Nagios clients will only print the first line.
124
        Verbose information are printed below the first line. Most Nagios clients will only print the first line.
125
        If you have important output, use $this->setHeadline() instead.
125
        If you have important output, use $this->setHeadline() instead.
126
        You can add verbose information with following method:
126
        You can add verbose information with following method:
127
                $this->addVerboseMessage('foobar', $verbosity);
127
                $this->addVerboseMessage('foobar', $verbosity);
128
 
128
 
129
        Following verbosity levels are defined:
129
        Following verbosity levels are defined:
130
                VNag::VERBOSITY_SUMMARY                = 0; // always printed
130
                VNag::VERBOSITY_SUMMARY                = 0; // always printed
131
                VNag::VERBOSITY_ADDITIONAL_INFORMATION = 1; // requires at least -v
131
                VNag::VERBOSITY_ADDITIONAL_INFORMATION = 1; // requires at least -v
132
                VNag::VERBOSITY_CONFIGURATION_DEBUG    = 2; // requiers at least -vv
132
                VNag::VERBOSITY_CONFIGURATION_DEBUG    = 2; // requiers at least -vv
133
                VNag::VERBOSITY_PLUGIN_DEBUG           = 3; // requiers at least -vvv
133
                VNag::VERBOSITY_PLUGIN_DEBUG           = 3; // requiers at least -vvv
134
 
134
 
135
        All STDOUT outputs of your script (e.g. by echo) will be interpreted as "verbose" output
135
        All STDOUT outputs of your script (e.g. by echo) will be interpreted as "verbose" output
136
        and is automatically collected, so
136
        and is automatically collected, so
137
                echo "foobar";
137
                echo "foobar";
138
        has the same functionality as
138
        has the same functionality as
139
                $this->addVerboseMessage('foobar', VNag::VERBOSITY_SUMMARY);
139
                $this->addVerboseMessage('foobar', VNag::VERBOSITY_SUMMARY);
140
 
140
 
141
        You can set messages (which will be added into the first line, which is preferred for plugin outputs)
141
        You can set messages (which will be added into the first line, which is preferred for plugin outputs)
142
        using
142
        using
143
                $this->setHeadline($msg, $append, $verbosity);
143
                $this->setHeadline($msg, $append, $verbosity);
144
        Using the flag $append, you can choose if you want to append or replace the message.
144
        Using the flag $append, you can choose if you want to append or replace the message.
145
 
145
 
146
        VNag will catch Exceptions of your script and will automatically end the plugin,
146
        VNag will catch Exceptions of your script and will automatically end the plugin,
147
        returning a valid Nagios output.
147
        returning a valid Nagios output.
148
 
148
 
149
Automatic handling of basic arguments:
149
Automatic handling of basic arguments:
150
 
150
 
151
        VNag will automatic handle of following CLI arguments:
151
        VNag will automatic handle of following CLI arguments:
152
                -?
152
                -?
153
                -V --version
153
                -V --version
154
                -h --help
154
                -h --help
155
                -v --verbose
155
                -v --verbose
156
                -t --timeout   (only works if you set declare(ticks=1) at the beginning of each of your scripts)
156
                -t --timeout   (only works if you set declare(ticks=1) at the beginning of each of your scripts)
157
                -w --warning
157
                -w --warning
158
                -c --critical
158
                -c --critical
159
 
159
 
160
        You can performe range checking by using:
160
        You can performe range checking by using:
161
                $example_value = '10MB';
161
                $example_value = '10MB';
162
                $this->checkAgainstWarningRange($example_value);
162
                $this->checkAgainstWarningRange($example_value);
163
        this is more or less the same as:
163
        this is more or less the same as:
164
                $example_value = '10MB';
164
                $example_value = '10MB';
165
                $wr = $this->getWarningRange();
165
                $wr = $this->getWarningRange();
166
                if (isset($wr) && $wr->checkAlert($example_value)) {
166
                if (isset($wr) && $wr->checkAlert($example_value)) {
167
                        $this->setStatus(VNag::STATUS_WARNING);
167
                        $this->setStatus(VNag::STATUS_WARNING);
168
                }
168
                }
169
 
169
 
170
        In case that your script allows ranges which can be relative and absolute, you can provide multiple arguments;
170
        In case that your script allows ranges which can be relative and absolute, you can provide multiple arguments;
171
        $wr->checkAlert() will be true, as soon as one of the arguments is in the warning range.
171
        $wr->checkAlert() will be true, as soon as one of the arguments is in the warning range.
172
        The check will be done in this way:
172
        The check will be done in this way:
173
                $example_values = array('10MB', '5%');
173
                $example_values = array('10MB', '5%');
174
                $this->checkAgainstWarningRange($example_values);
174
                $this->checkAgainstWarningRange($example_values);
175
        this is more or less the same as:
175
        this is more or less the same as:
176
                $example_values = array('10MB', '5%');
176
                $example_values = array('10MB', '5%');
177
                $wr = $this->getWarningRange();
177
                $wr = $this->getWarningRange();
178
                if (isset($wr) && $wr->checkAlert($example_values)) {
178
                if (isset($wr) && $wr->checkAlert($example_values)) {
179
                        $this->setStatus(VNag::STATUS_WARNING);
179
                        $this->setStatus(VNag::STATUS_WARNING);
180
                }
180
                }
181
 
181
 
182
        Note that VNag will automatically detect the UOM (Unit of Measurement) and is also able to convert them,
182
        Note that VNag will automatically detect the UOM (Unit of Measurement) and is also able to convert them,
183
        e.g. if you use the range "-w 20MB:40MB", your script will be able to use $wr->checkAlert('3000KB')
183
        e.g. if you use the range "-w 20MB:40MB", your script will be able to use $wr->checkAlert('3000KB')
184
 
184
 
185
        Please note that only following UOMs are accepted (as defined in the Plugin Development Guidelines):
185
        Please note that only following UOMs are accepted (as defined in the Plugin Development Guidelines):
186
        - no unit specified: assume a number (int or float) of things (eg, users, processes, load averages)
186
        - no unit specified: assume a number (int or float) of things (eg, users, processes, load averages)
187
        - s, ms, us: seconds
187
        - s, ms, us: seconds
188
        - %: percentage
188
        - %: percentage
189
        - B, KB, MB, TB: bytes  // NOTE: GB is not in the official development guidelines,probably due to an error, so I've added them anyway
189
        - B, KB, MB, TB: bytes  // NOTE: GB is not in the official development guidelines,probably due to an error, so I've added them anyway
190
        - c: a continous counter (such as bytes transmitted on an interface)
190
        - c: a continous counter (such as bytes transmitted on an interface)
191
 
191
 
192
Multiple warning/critical ranges:
192
Multiple warning/critical ranges:
193
 
193
 
194
        The arguments -w and -c can have many different values, separated by comma.
194
        The arguments -w and -c can have many different values, separated by comma.
195
        We can see this feature e.g. with the official plugin /usr/lib/nagios/plugins/check_ping:
195
        We can see this feature e.g. with the official plugin /usr/lib/nagios/plugins/check_ping:
196
        It has following syntax for the arguments -w and -c: <latency>,<packetloss>%
196
        It has following syntax for the arguments -w and -c: <latency>,<packetloss>%
197
 
197
 
198
        When you are using checkAgainstWarningRange, you can set the fourth argument to the range number
198
        When you are using checkAgainstWarningRange, you can set the fourth argument to the range number
199
        you would like to check (beginning with 0).
199
        you would like to check (beginning with 0).
200
 
200
 
201
        Example:
201
        Example:
202
                // -w 1MB:5MB,5%:10%
202
                // -w 1MB:5MB,5%:10%
203
                $this->checkAgainstWarningRange('4MB', true, true, 0); // check value 4MB against range "1MB:5MB" (no warning)
203
                $this->checkAgainstWarningRange('4MB', true, true, 0); // check value 4MB against range "1MB:5MB" (no warning)
204
                $this->checkAgainstWarningRange('15%', true, true, 1); // check value 15% gainst range "5%:10%" (gives warning)
204
                $this->checkAgainstWarningRange('15%', true, true, 1); // check value 15% gainst range "5%:10%" (gives warning)
205
 
205
 
206
Visual HTTP output:
206
Visual HTTP output:
207
 
207
 
208
        Can be enabled/disabled with $this->http_visual_output
208
        Can be enabled/disabled with $this->http_visual_output
209
 
209
 
210
        Valid values:
210
        Valid values:
211
 
211
 
212
        VNag::OUTPUT_SPECIAL   = 1; // illegal usage / help page, version page
212
        VNag::OUTPUT_SPECIAL   = 1; // illegal usage / help page, version page
213
        VNag::OUTPUT_NORMAL    = 2;
213
        VNag::OUTPUT_NORMAL    = 2;
214
        VNag::OUTPUT_EXCEPTION = 4;
214
        VNag::OUTPUT_EXCEPTION = 4;
215
        VNag::OUTPUT_ALWAYS    = 7;
215
        VNag::OUTPUT_ALWAYS    = 7;
216
        VNag::OUTPUT_NEVER     = 0;
216
        VNag::OUTPUT_NEVER     = 0;
217
 
217
 
218
Encryption and Decryption:
218
Encryption and Decryption:
219
 
219
 
220
        In case you are emitting machine-readable code in your HTTP output
220
        In case you are emitting machine-readable code in your HTTP output
221
        (can be enabled/disabled by $this->http_invisible_output),
221
        (can be enabled/disabled by $this->http_invisible_output),
222
        you can encrypt the machine-readable part of your HTTP output by
222
        you can encrypt the machine-readable part of your HTTP output by
223
        setting $this->password_out . If you want to read the information,
223
        setting $this->password_out . If you want to read the information,
224
        you need to set $this->password_in at the web-reader plugin.
224
        you need to set $this->password_in at the web-reader plugin.
225
        The visual output is not encrypted. So, if you want to hide the information,
225
        The visual output is not encrypted. So, if you want to hide the information,
226
        then you must not enable visual HTML output.
226
        then you must not enable visual HTML output.
227
        If you don't want to encrypt the machine-readable output,
227
        If you don't want to encrypt the machine-readable output,
228
        please set $this->password_out to null or empty string.
228
        please set $this->password_out to null or empty string.
229
 
229
 
230
        Attention!
230
        Attention!
231
        - Encryption and decryption require the OpenSSL extension in PHP.
231
        - Encryption and decryption require the OpenSSL extension in PHP.
232
 
232
 
233
Digital signature:
233
Digital signature:
234
 
234
 
235
        You can sign the output by setting $this->privkey with a filename containing
235
        You can sign the output by setting $this->privkey with a filename containing
236
        a private key created by OpenSSL. If it is encrypted, please also set
236
        a private key created by OpenSSL. If it is encrypted, please also set
237
        $this->privkey_password .
237
        $this->privkey_password .
238
        To check the signature, set $this->pubkey at your web-reader plugin with
238
        To check the signature, set $this->pubkey at your web-reader plugin with
239
        the filename of the public key file.
239
        the filename of the public key file.
240
 
240
 
241
        Attention!
241
        Attention!
242
        - Signatures require the OpenSSL extension in PHP.
242
        - Signatures require the OpenSSL extension in PHP.
243
 
243
 
244
Performance data:
244
Performance data:
245
 
245
 
246
        You can add performance data using
246
        You can add performance data using
247
                $this->addPerformanceData(new VNagPerformanceData($label, $value, $warn, $crit, $min, $max));
247
                $this->addPerformanceData(new VNagPerformanceData($label, $value, $warn, $crit, $min, $max));
248
        or by the alternative constructor
248
        or by the alternative constructor
249
                $this->addPerformanceData(VNagPerformanceData::createByString("'XYZ'=100;120;130;0;500"));
249
                $this->addPerformanceData(VNagPerformanceData::createByString("'XYZ'=100;120;130;0;500"));
250
        $value may contain an UOM, e.g. "10MB". All other parameters may not contain an UOM.
250
        $value may contain an UOM, e.g. "10MB". All other parameters may not contain an UOM.
251
 
251
 
252
Guidelines:
252
Guidelines:
253
 
253
 
254
        This framework currently supports meets following guidelines:
254
        This framework currently supports meets following guidelines:
255
        - https://nagios-plugins.org/doc/guidelines.html#PLUGOUTPUT (Plugin Output for Nagios)
255
        - https://nagios-plugins.org/doc/guidelines.html#PLUGOUTPUT (Plugin Output for Nagios)
256
        - https://nagios-plugins.org/doc/guidelines.html#AEN33 (Print only one line of text)
256
        - https://nagios-plugins.org/doc/guidelines.html#AEN33 (Print only one line of text)
257
        - https://nagios-plugins.org/doc/guidelines.html#AEN41 (Verbose output)
257
        - https://nagios-plugins.org/doc/guidelines.html#AEN41 (Verbose output)
258
        - https://nagios-plugins.org/doc/guidelines.html#AEN78 (Plugin Return Codes)
258
        - https://nagios-plugins.org/doc/guidelines.html#AEN78 (Plugin Return Codes)
259
        - https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT (Threshold and ranges)
259
        - https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT (Threshold and ranges)
260
        - https://nagios-plugins.org/doc/guidelines.html#AEN200 (Performance data)
260
        - https://nagios-plugins.org/doc/guidelines.html#AEN200 (Performance data)
261
        - https://nagios-plugins.org/doc/guidelines.html#PLUGOPTIONS (Plugin Options)
261
        - https://nagios-plugins.org/doc/guidelines.html#PLUGOPTIONS (Plugin Options)
262
        - https://nagios-plugins.org/doc/guidelines.html#AEN302 (Option Processing)
262
        - https://nagios-plugins.org/doc/guidelines.html#AEN302 (Option Processing)
263
          Note: The screen output of the help page will (mostly) be limited to 80 characters width; but the max recommended length of 23 lines cannot be guaranteed.
263
          Note: The screen output of the help page will (mostly) be limited to 80 characters width; but the max recommended length of 23 lines cannot be guaranteed.
264
 
264
 
265
        This framework does currently NOT support following guidelines:
265
        This framework does currently NOT support following guidelines:
266
        - https://nagios-plugins.org/doc/guidelines.html#AEN74 (Screen Output)
266
        - https://nagios-plugins.org/doc/guidelines.html#AEN74 (Screen Output)
267
        - https://nagios-plugins.org/doc/guidelines.html#AEN239 (Translations)
267
        - https://nagios-plugins.org/doc/guidelines.html#AEN239 (Translations)
268
        - https://nagios-plugins.org/doc/guidelines.html#AEN293 (Use DEFAULT_SOCKET_TIMEOUT)
268
        - https://nagios-plugins.org/doc/guidelines.html#AEN293 (Use DEFAULT_SOCKET_TIMEOUT)
269
        - https://nagios-plugins.org/doc/guidelines.html#AEN296 (Add alarms to network plugins)
269
        - https://nagios-plugins.org/doc/guidelines.html#AEN296 (Add alarms to network plugins)
270
        - https://nagios-plugins.org/doc/guidelines.html#AEN245 (Don't execute system commands without specifying their full path)
270
        - https://nagios-plugins.org/doc/guidelines.html#AEN245 (Don't execute system commands without specifying their full path)
271
        - https://nagios-plugins.org/doc/guidelines.html#AEN249 (Use spopen() if external commands must be executed)
271
        - https://nagios-plugins.org/doc/guidelines.html#AEN249 (Use spopen() if external commands must be executed)
272
        - https://nagios-plugins.org/doc/guidelines.html#AEN253 (Don't make temp files unless absolutely required)
272
        - https://nagios-plugins.org/doc/guidelines.html#AEN253 (Don't make temp files unless absolutely required)
273
        - https://nagios-plugins.org/doc/guidelines.html#AEN259 (Validate all input)
273
        - https://nagios-plugins.org/doc/guidelines.html#AEN259 (Validate all input)
274
        - https://nagios-plugins.org/doc/guidelines.html#AEN317 (Plugins with more than one type of threshold, or with threshold ranges)
274
        - https://nagios-plugins.org/doc/guidelines.html#AEN317 (Plugins with more than one type of threshold, or with threshold ranges)
275
 
275
 
276
        We will intentionally NOT follow the following guidelines:
276
        We will intentionally NOT follow the following guidelines:
277
        - https://nagios-plugins.org/doc/guidelines.html#AEN256 (Don't be tricked into following symlinks)
277
        - https://nagios-plugins.org/doc/guidelines.html#AEN256 (Don't be tricked into following symlinks)
278
          Reason: We believe that this guideline is contraproductive.
278
          Reason: We believe that this guideline is contraproductive.
279
                  Nagios plugins usually run as user 'nagios'. It is the task of the system administrator
279
                  Nagios plugins usually run as user 'nagios'. It is the task of the system administrator
280
                  to ensure that the user 'nagios' must not read/write to files which are not intended
280
                  to ensure that the user 'nagios' must not read/write to files which are not intended
281
                  for access by the Nagios service. Instead, symlinks are useful for several tasks.
281
                  for access by the Nagios service. Instead, symlinks are useful for several tasks.
282
                  See also http://stackoverflow.com/questions/27112949/nagios-plugins-why-not-following-symlinks
282
                  See also http://stackoverflow.com/questions/27112949/nagios-plugins-why-not-following-symlinks
283
 
283
 
284
VNag over HTTP:
284
VNag over HTTP:
285
 
285
 
286
        A script that uses the VNag framework can run as CLI script (normal Nagios plugin) or as web site (or both).
286
        A script that uses the VNag framework can run as CLI script (normal Nagios plugin) or as web site (or both).
287
        Having the script run as website, you can include a Nagios information combined with a human friendly HTML output which can
287
        Having the script run as website, you can include a Nagios information combined with a human friendly HTML output which can
288
        include colors, graphics (like charts) etc.
288
        include colors, graphics (like charts) etc.
289
 
289
 
290
        For example:
290
        For example:
291
        A script that measures traffic can have a website which shows graphs,
291
        A script that measures traffic can have a website which shows graphs,
292
        and has a hidden Nagios output included, which can be read by a Nagios plugin that
292
        and has a hidden Nagios output included, which can be read by a Nagios plugin that
293
        converts the hidden information on that website into an output that Nagios can evaluate.
293
        converts the hidden information on that website into an output that Nagios can evaluate.
294
 
294
 
295
        Here is a comparison of the usage and behavior of VNag in regards to CLI and HTTP calls:
295
        Here is a comparison of the usage and behavior of VNag in regards to CLI and HTTP calls:
296
 
296
 
297
        ------------------------------------------------------------------------------------------
297
        ------------------------------------------------------------------------------------------
298
          CLI script                                 HTTP script
298
          CLI script                                 HTTP script
299
        ------------------------------------------------------------------------------------------
299
        ------------------------------------------------------------------------------------------
300
        * "echo" will be discarded.                  * "echo" output will be discarded.
300
        * "echo" will be discarded.                  * "echo" output will be discarded.
301
 
301
 
302
        * Exceptions will be handled.                * Exceptions will be handled.
302
        * Exceptions will be handled.                * Exceptions will be handled.
303
 
303
 
304
        * outputHTML() will be ignored.              * outputHTML() will be handled.
304
        * outputHTML() will be ignored.              * outputHTML() will be handled.
305
          (This allows you to have the same script
305
          (This allows you to have the same script
306
          running as CLI and HTML)
306
          running as CLI and HTML)
307
 
307
 
308
        * Arguments are passed via CLI.              * Arguments are passed via $_REQUEST
308
        * Arguments are passed via CLI.              * Arguments are passed via $_REQUEST
309
                                                       (i.e. GET or POST)
309
                                                       (i.e. GET or POST)
310
 
310
 
311
        * Arguments: "-vvv"                          * Arguments: GET ?v[]=&v[]=&v[]= or POST
311
        * Arguments: "-vvv"                          * Arguments: GET ?v[]=&v[]=&v[]= or POST
312
 
312
 
313
        * When run() has finished, the program       * When run() has finished, the program
313
        * When run() has finished, the program       * When run() has finished, the program
314
          flow continues, although it is not           flow continues.
314
          flow continues, although it is not           flow continues.
315
          recommended that you do anything after it.
315
          recommended that you do anything after it.
316
          (The exit code is remembered for the
316
          (The exit code is remembered for the
317
           shutdown handler)
317
           shutdown handler)
318
 
318
 
319
        * Exactly 1 job must be called, resulting     * You can call as many jobs as you want.
319
        * Exactly 1 job must be called, resulting     * You can call as many jobs as you want.
320
          in a single output of that job.               A website can include more than one
320
          in a single output of that job.               A website can include more than one
321
                                                        Nagios output which are enumerated with
321
                                                        Nagios output which are enumerated with
322
                                                        a serial number (0,1,2,3,...) or manual ID.
322
                                                        a serial number (0,1,2,3,...) or manual ID.
323
        ------------------------------------------------------------------------------------------
323
        ------------------------------------------------------------------------------------------
324
 
324
 
325
****************************************************************************************************/
325
****************************************************************************************************/
326
 
326
 
327
if (!VNag::is_http_mode()) error_reporting(E_ALL);
327
if (!VNag::is_http_mode()) error_reporting(E_ALL);
328
 
328
 
329
# If you want to use -t/--timeout with your module, you must add following line in your module code:
329
# If you want to use -t/--timeout with your module, you must add following line in your module code:
330
// WONTFIX: declare(ticks=1) is deprecated? http://www.hackingwithphp.com/4/21/0/the-declare-function-and-ticks
330
// WONTFIX: declare(ticks=1) is deprecated? http://www.hackingwithphp.com/4/21/0/the-declare-function-and-ticks
331
// WONTFIX: check is the main script used declare(ticks=1). (Not possible in PHP)
331
// WONTFIX: check is the main script used declare(ticks=1). (Not possible in PHP)
332
declare(ticks=1);
332
declare(ticks=1);
333
 
333
 
334
# Attention: The -t/--timeout parameter does not respect the built-in set_time_limit() of PHP.
334
# Attention: The -t/--timeout parameter does not respect the built-in set_time_limit() of PHP.
335
# PHP should set this time limit to infinite.
335
# PHP should set this time limit to infinite.
336
set_time_limit(0);
336
set_time_limit(0);
337
 
337
 
338
define('VNAG_JSONDATA_V1', 'oid:1.3.6.1.4.1.37476.2.3.1.1'); // {iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) 37476 products(2) vnag(3) jsondata(1) v1(1)}
338
define('VNAG_JSONDATA_V1', 'oid:1.3.6.1.4.1.37476.2.3.1.1'); // {iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) 37476 products(2) vnag(3) jsondata(1) v1(1)}
339
 
339
 
340
// Set this to an array to overwrite getopt() and $_REQUEST[], respectively.
340
// Set this to an array to overwrite getopt() and $_REQUEST[], respectively.
341
// Useful for mock tests.
341
// Useful for mock tests.
342
$OVERWRITE_ARGUMENTS = null;
342
$OVERWRITE_ARGUMENTS = null;
343
 
343
 
344
function _empty($x) {
344
function _empty($x) {
345
        // Returns true for '' or null. Does not return true for value 0 or '0' (like empty() does)
345
        // Returns true for '' or null. Does not return true for value 0 or '0' (like empty() does)
346
        return trim($x) == '';
346
        return trim($x) == '';
347
}
347
}
348
 
348
 
349
abstract class VNag {
349
abstract class VNag {
350
        /*public*/ const VNAG_VERSION = '2022-06-06';
350
        /*public*/ const VNAG_VERSION = '2022-06-06';
351
 
351
 
352
        // Status 0..3 for STATUSMODEL_SERVICE (the default status model):
352
        // Status 0..3 for STATUSMODEL_SERVICE (the default status model):
353
        # The guideline states: "Higher-level errors (such as name resolution errors, socket timeouts, etc) are outside of the control of plugins and should generally NOT be reported as UNKNOWN states."
353
        # The guideline states: "Higher-level errors (such as name resolution errors, socket timeouts, etc) are outside of the control of plugins and should generally NOT be reported as UNKNOWN states."
354
        # We choose 4 as exitcode. The plugin developer is free to return any other status.
354
        # We choose 4 as exitcode. The plugin developer is free to return any other status.
355
        /*public*/ const STATUS_OK       = 0;
355
        /*public*/ const STATUS_OK       = 0;
356
        /*public*/ const STATUS_WARNING  = 1;
356
        /*public*/ const STATUS_WARNING  = 1;
357
        /*public*/ const STATUS_CRITICAL = 2;
357
        /*public*/ const STATUS_CRITICAL = 2;
358
        /*public*/ const STATUS_UNKNOWN  = 3;
358
        /*public*/ const STATUS_UNKNOWN  = 3;
359
        /*public*/ const STATUS_ERROR    = 4; // and upwards
359
        /*public*/ const STATUS_ERROR    = 4; // and upwards
360
 
360
 
361
        // Status 0..1 for STATUSMODEL_HOST:
361
        // Status 0..1 for STATUSMODEL_HOST:
362
        // The page https://blog.centreon.com/good-practices-how-to-develop-monitoring-plugin-nagios/
362
        // The page https://blog.centreon.com/good-practices-how-to-develop-monitoring-plugin-nagios/
363
        // states that host plugins may return following status codes:
363
        // states that host plugins may return following status codes:
364
        // 0=UP, 1=DOWN, Other=Maintains last known state
364
        // 0=UP, 1=DOWN, Other=Maintains last known state
365
        /*public*/ const STATUS_UP       = 0;
365
        /*public*/ const STATUS_UP       = 0;
366
        /*public*/ const STATUS_DOWN     = 1;
366
        /*public*/ const STATUS_DOWN     = 1;
367
        /*public*/ const STATUS_MAINTAIN = 2; // and upwards
367
        /*public*/ const STATUS_MAINTAIN = 2; // and upwards
368
 
368
 
369
        /*public*/ const VERBOSITY_SUMMARY                = 0;
369
        /*public*/ const VERBOSITY_SUMMARY                = 0;
370
        /*public*/ const VERBOSITY_ADDITIONAL_INFORMATION = 1;
370
        /*public*/ const VERBOSITY_ADDITIONAL_INFORMATION = 1;
371
        /*public*/ const VERBOSITY_CONFIGURATION_DEBUG    = 2;
371
        /*public*/ const VERBOSITY_CONFIGURATION_DEBUG    = 2;
372
        /*public*/ const VERBOSITY_PLUGIN_DEBUG           = 3;
372
        /*public*/ const VERBOSITY_PLUGIN_DEBUG           = 3;
373
        /*public*/ const MAX_VERBOSITY = self::VERBOSITY_PLUGIN_DEBUG;
373
        /*public*/ const MAX_VERBOSITY = self::VERBOSITY_PLUGIN_DEBUG;
374
 
374
 
375
        /*public*/ const STATUSMODEL_SERVICE = 0;
375
        /*public*/ const STATUSMODEL_SERVICE = 0;
376
        /*public*/ const STATUSMODEL_HOST    = 1;
376
        /*public*/ const STATUSMODEL_HOST    = 1;
377
 
377
 
378
        private $initialized = false;
378
        private $initialized = false;
379
 
379
 
380
        private $status = null;
380
        private $status = null;
381
        private $messages = array(); // array of messages which are all put together into the headline, comma separated
381
        private $messages = array(); // array of messages which are all put together into the headline, comma separated
382
        private $verbose_info = ''; // all other lines
382
        private $verbose_info = ''; // all other lines
383
        private $warningRanges = array();
383
        private $warningRanges = array();
384
        private $criticalRanges = array();
384
        private $criticalRanges = array();
385
        private $performanceDataObjects = array();
385
        private $performanceDataObjects = array();
386
        private static $exitcode = 0;
386
        private static $exitcode = 0;
387
 
387
 
388
        private $helpObj = null;
388
        private $helpObj = null;
389
        private $argHandler = null;
389
        private $argHandler = null;
390
 
390
 
391
        /*public*/ const OUTPUT_NEVER     = 0;
391
        /*public*/ const OUTPUT_NEVER     = 0;
392
        /*public*/ const OUTPUT_SPECIAL   = 1; // illegal usage / help page, version page
392
        /*public*/ const OUTPUT_SPECIAL   = 1; // illegal usage / help page, version page
393
        /*public*/ const OUTPUT_NORMAL    = 2;
393
        /*public*/ const OUTPUT_NORMAL    = 2;
394
        /*public*/ const OUTPUT_EXCEPTION = 4;
394
        /*public*/ const OUTPUT_EXCEPTION = 4;
395
        /*public*/ const OUTPUT_ALWAYS    = 7; // = OUTPUT_SPECIAL+OUTPUT_NORMAL+OUTPUT_EXCEPTION
395
        /*public*/ const OUTPUT_ALWAYS    = 7; // = OUTPUT_SPECIAL+OUTPUT_NORMAL+OUTPUT_EXCEPTION
396
 
396
 
397
        public $http_visual_output    = self::OUTPUT_ALWAYS; // show a human-readable panel? ...
397
        public $http_visual_output    = self::OUTPUT_ALWAYS; // show a human-readable panel? ...
398
        public $http_invisible_output = self::OUTPUT_ALWAYS; // ... and/or show an invisible machine-readable tag?
398
        public $http_invisible_output = self::OUTPUT_ALWAYS; // ... and/or output an invisible machine-readable tag?
399
 
399
 
400
        // $html_before and $html_after contain the output HTML which were sent by the user
400
        // $html_before and $html_after contain the output HTML which were sent by the user
401
 
401
 
402
        // before and after the visual output
402
        // before and after the visual output
403
        protected $html_before = '';
403
        protected $html_before = '';
404
        protected $html_after = '';
404
        protected $html_after = '';
405
 
405
 
406
        protected $statusmodel = self::STATUSMODEL_SERVICE;
406
        protected $statusmodel = self::STATUSMODEL_SERVICE;
407
 
407
 
408
        protected $show_status_in_headline = true;
408
        protected $show_status_in_headline = true;
409
 
409
 
410
        protected $default_status = self::STATUS_UNKNOWN;
410
        protected $default_status = self::STATUS_UNKNOWN;
411
        protected $default_warning_range = null;
411
        protected $default_warning_range = null;
412
        protected $default_critical_range = null;
412
        protected $default_critical_range = null;
413
 
413
 
414
        protected $argWarning;
414
        protected $argWarning;
415
        protected $argCritical;
415
        protected $argCritical;
416
        protected $argVersion;
416
        protected $argVersion;
417
        protected $argVerbosity;
417
        protected $argVerbosity;
418
        protected $argTimeout;
418
        protected $argTimeout;
419
        protected $argHelp;
419
        protected $argHelp;
420
        protected $argUsage;
420
        protected $argUsage;
421
 
421
 
422
        // -----------------------------------------------------------
422
        // -----------------------------------------------------------
423
 
423
 
424
        // The ID will be used for writing AND reading of the machine-readable
424
        // The ID will be used for writing AND reading of the machine-readable
425
        // Nagios output embedded in a website. (A web-reader acts as proxy, so the
425
        // Nagios output embedded in a website. (A web-reader acts as proxy, so the
426
        // input and output ID will be equal)
426
        // input and output ID will be equal)
427
        // Attention: Once you run run(), $id will be "used" and resetted to null.
427
        // Attention: Once you run run(), $id will be "used" and resetted to null.
428
        // The ID can be any string, e.g. a GUID, an OID, a package name or something else.
428
        // The ID can be any string, e.g. a GUID, an OID, a package name or something else.
429
        // It should be unique. If you don't set an ID, a serial number (0, 1, 2, 3, ...) will be
429
        // It should be unique. If you don't set an ID, a serial number (0, 1, 2, 3, ...) will be
430
        // used for your outputs.
430
        // used for your outputs.
431
        public $id = null;
431
        public $id = null;
432
        protected static $http_serial_number = 0;
432
        protected static $http_serial_number = 0;
433
 
433
 
434
        // -----------------------------------------------------------
434
        // -----------------------------------------------------------
435
 
435
 
436
        // Private key: Optional feature used in writeInvisibleHTML (called by run in HTTP mode) in order to sign/encrypt the output
436
        // Private key: Optional feature used in writeInvisibleHTML (called by run in HTTP mode) in order to sign/encrypt the output
437
        public $privkey = null;
437
        public $privkey = null;
438
        public $privkey_password = null;
438
        public $privkey_password = null;
439
        public $sign_algo = null; // default: OPENSSL_ALGO_SHA256
439
        public $sign_algo = null; // default: OPENSSL_ALGO_SHA256
440
 
440
 
441
        // Public key: Optional feature used in a web-reader [readInvisibleHTML) to check the integrity of a message
441
        // Public key: Optional feature used in a web-reader [readInvisibleHTML) to check the integrity of a message
442
        public $pubkey = null;
442
        public $pubkey = null;
443
 
443
 
444
        // -----------------------------------------------------------
444
        // -----------------------------------------------------------
445
 
445
 
446
        // These settings should be set by derivated classes where the user intuitively expects the
446
        // These settings should be set by derivated classes where the user intuitively expects the
447
        // warning (w) or critical (c) parameter to mean something else than defined in the development guidelines.
447
        // warning (w) or critical (c) parameter to mean something else than defined in the development guidelines.
448
        // Usually, the single value "-w X" means the same like "-w X:X", which means everything except X is bad.
448
        // Usually, the single value "-w X" means the same like "-w X:X", which means everything except X is bad.
449
        // This behavior is VNag::SINGLEVALUE_RANGE_DEFAULT.
449
        // This behavior is VNag::SINGLEVALUE_RANGE_DEFAULT.
450
        // But for plugins e.g. for checking disk space, the user expects the argument "-w X" to mean
450
        // But for plugins e.g. for checking disk space, the user expects the argument "-w X" to mean
451
        // "everything below X is bad" (if X is defined as free disk space).
451
        // "everything below X is bad" (if X is defined as free disk space).
452
        // So we would choose the setting VNag::SINGLEVALUE_RANGE_VAL_LT_X_BAD.
452
        // So we would choose the setting VNag::SINGLEVALUE_RANGE_VAL_LT_X_BAD.
453
        // Note: This setting is implemented as array, so that each range number (in case you want to have more
453
        // Note: This setting is implemented as array, so that each range number (in case you want to have more
454
        //       than one range, like in the PING plugin that checks latency and package loss)
454
        //       than one range, like in the PING plugin that checks latency and package loss)
455
        //       can have its individual behavior for single values.
455
        //       can have its individual behavior for single values.
456
        protected $warningSingleValueRangeBehaviors  = array(self::SINGLEVALUE_RANGE_DEFAULT);
456
        protected $warningSingleValueRangeBehaviors  = array(self::SINGLEVALUE_RANGE_DEFAULT);
457
        protected $criticalSingleValueRangeBehaviors = array(self::SINGLEVALUE_RANGE_DEFAULT);
457
        protected $criticalSingleValueRangeBehaviors = array(self::SINGLEVALUE_RANGE_DEFAULT);
458
 
458
 
459
        // Default behavior according to the development guidelines:
459
        // Default behavior according to the development guidelines:
460
        //  x means  x:x, which means, everything except x% is bad.
460
        //  x means  x:x, which means, everything except x% is bad.
461
        // @x means @x:x, which means, x is bad and everything else is good.
461
        // @x means @x:x, which means, x is bad and everything else is good.
462
        const SINGLEVALUE_RANGE_DEFAULT = 0;
462
        const SINGLEVALUE_RANGE_DEFAULT = 0;
463
 
463
 
464
        // The single value x means, everything > x is bad. @x is not defined.
464
        // The single value x means, everything > x is bad. @x is not defined.
465
        const SINGLEVALUE_RANGE_VAL_GT_X_BAD = 1;
465
        const SINGLEVALUE_RANGE_VAL_GT_X_BAD = 1;
466
 
466
 
467
        // The single value x means, everything >= x is bad. @x is not defined.
467
        // The single value x means, everything >= x is bad. @x is not defined.
468
        const SINGLEVALUE_RANGE_VAL_GE_X_BAD = 2;
468
        const SINGLEVALUE_RANGE_VAL_GE_X_BAD = 2;
469
 
469
 
470
        // The single value x means, everything < x is bad. @x is not defined.
470
        // The single value x means, everything < x is bad. @x is not defined.
471
        const SINGLEVALUE_RANGE_VAL_LT_X_BAD = 3;
471
        const SINGLEVALUE_RANGE_VAL_LT_X_BAD = 3;
472
 
472
 
473
        // The single value x means, everything <= x is bad. @x is not defined.
473
        // The single value x means, everything <= x is bad. @x is not defined.
474
        const SINGLEVALUE_RANGE_VAL_LE_X_BAD = 4;
474
        const SINGLEVALUE_RANGE_VAL_LE_X_BAD = 4;
475
 
475
 
476
        // -----------------------------------------------------------
476
        // -----------------------------------------------------------
477
 
477
 
478
        // Encryption password: Optional feature used in writeInvisibleHTML (called by run in HTTP mode)
478
        // Encryption password: Optional feature used in writeInvisibleHTML (called by run in HTTP mode)
479
        public $password_out = null;
479
        public $password_out = null;
480
 
480
 
481
        // Decryption password: Used in readInvisibleHTML to decrypt an encrypted machine-readable info
481
        // Decryption password: Used in readInvisibleHTML to decrypt an encrypted machine-readable info
482
        public $password_in = null;
482
        public $password_in = null;
483
 
483
 
484
        // -----------------------------------------------------------
484
        // -----------------------------------------------------------
485
 
485
 
486
        public static function is_http_mode() {
486
        public static function is_http_mode() {
487
                return php_sapi_name() !== 'cli';
487
                return php_sapi_name() !== 'cli';
488
        }
488
        }
489
 
489
 
490
        public function getHelpManager() {
490
        public function getHelpManager() {
491
                return $this->helpObj;
491
                return $this->helpObj;
492
        }
492
        }
493
 
493
 
494
        public function getArgumentHandler() {
494
        public function getArgumentHandler() {
495
                return $this->argHandler;
495
                return $this->argHandler;
496
        }
496
        }
497
 
497
 
498
        public function outputHTML($text, $after_visual_output=true) {
498
        public function outputHTML($text, $after_visual_output=true) {
499
                if ($this->is_http_mode()) {
499
                if ($this->is_http_mode()) {
500
                        if ($this->initialized) {
500
                        if ($this->initialized) {
501
                                if ($after_visual_output) {
501
                                if ($after_visual_output) {
502
                                        $this->html_after .= $text;
502
                                        $this->html_after .= $text;
503
                                } else {
503
                                } else {
504
                                        $this->html_before .= $text;
504
                                        $this->html_before .= $text;
505
                                }
505
                                }
506
                        } else {
506
                        } else {
507
                                echo $text;
507
                                echo $text;
508
                        }
508
                        }
509
                }
509
                }
510
        }
510
        }
511
 
511
 
512
        protected function resetArguments() {
512
        protected function resetArguments() {
513
                $this->argWarning   = null;
513
                $this->argWarning   = null;
514
                $this->argCritical  = null;
514
                $this->argCritical  = null;
515
                $this->argVersion   = null;
515
                $this->argVersion   = null;
516
                $this->argVerbosity = null;
516
                $this->argVerbosity = null;
517
                $this->argTimeout   = null;
517
                $this->argTimeout   = null;
518
                $this->argHelp      = null;
518
                $this->argHelp      = null;
519
                // $this->argUsage  = null;
519
                // $this->argUsage  = null;
520
 
520
 
521
                // Also remove cache
521
                // Also remove cache
522
                $this->argWarning   = null;
522
                $this->argWarning   = null;
523
                $this->argCritical  = null;
523
                $this->argCritical  = null;
524
        }
524
        }
525
 
525
 
526
        // e.g. $args = "wcVvht"
526
        // e.g. $args = "wcVvht"
527
        public function registerExpectedStandardArguments($args) {
527
        public function registerExpectedStandardArguments($args) {
528
                $this->resetArguments();
528
                $this->resetArguments();
529
 
529
 
530
                for ($i=0; $i<strlen($args); $i++) {
530
                for ($i=0; $i<strlen($args); $i++) {
531
                        switch ($args[$i]) {
531
                        switch ($args[$i]) {
532
                                case 'w':
532
                                case 'w':
533
                                        $this->addExpectedArgument($this->argWarning   = new VNagArgument('w', 'warning',  VNagArgument::VALUE_REQUIRED,  VNagLang::$argname_value, VNagLang::$warning_range));
533
                                        $this->addExpectedArgument($this->argWarning   = new VNagArgument('w', 'warning',  VNagArgument::VALUE_REQUIRED,  VNagLang::$argname_value, VNagLang::$warning_range));
534
                                        break;
534
                                        break;
535
                                case 'c':
535
                                case 'c':
536
                                        $this->addExpectedArgument($this->argCritical  = new VNagArgument('c', 'critical', VNagArgument::VALUE_REQUIRED,  VNagLang::$argname_value, VNagLang::$critical_range));
536
                                        $this->addExpectedArgument($this->argCritical  = new VNagArgument('c', 'critical', VNagArgument::VALUE_REQUIRED,  VNagLang::$argname_value, VNagLang::$critical_range));
537
                                        break;
537
                                        break;
538
                                case 'V':
538
                                case 'V':
539
                                        $this->addExpectedArgument($this->argVersion   = new VNagArgument('V', 'version',  VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$prints_version));
539
                                        $this->addExpectedArgument($this->argVersion   = new VNagArgument('V', 'version',  VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$prints_version));
540
                                        break;
540
                                        break;
541
                                case 'v':
541
                                case 'v':
542
                                        // In HTTP: -vvv is &v[]=&v[]=&v[]=
542
                                        // In HTTP: -vvv is &v[]=&v[]=&v[]=
543
                                        $this->addExpectedArgument($this->argVerbosity = new VNagArgument('v', 'verbose',  VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$verbosity_helptext));
543
                                        $this->addExpectedArgument($this->argVerbosity = new VNagArgument('v', 'verbose',  VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$verbosity_helptext));
544
                                        break;
544
                                        break;
545
                                case 't':
545
                                case 't':
546
                                        // Attention: not every plugin supports it because of declare(ticks=1) needs to be written in the main script
546
                                        // Attention: not every plugin supports it because of declare(ticks=1) needs to be written in the main script
547
                                        $this->addExpectedArgument($this->argTimeout   = new VNagArgument('t', 'timeout',  VNagArgument::VALUE_REQUIRED,  VNagLang::$argname_seconds, VNagLang::$timeout_helptext));
547
                                        $this->addExpectedArgument($this->argTimeout   = new VNagArgument('t', 'timeout',  VNagArgument::VALUE_REQUIRED,  VNagLang::$argname_seconds, VNagLang::$timeout_helptext));
548
                                        break;
548
                                        break;
549
                                // case '?':
549
                                // case '?':
550
                                case 'h':
550
                                case 'h':
551
                                        $this->addExpectedArgument($this->argHelp      = new VNagArgument('h', 'help',     VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$help_helptext));
551
                                        $this->addExpectedArgument($this->argHelp      = new VNagArgument('h', 'help',     VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$help_helptext));
552
                                        break;
552
                                        break;
553
                                default:
553
                                default:
554
                                        $letter = $args[$i];
554
                                        $letter = $args[$i];
555
                                        throw new VNagInvalidStandardArgument(sprintf(VNagLang::$no_standard_arguments_with_letter, $letter));
555
                                        throw new VNagInvalidStandardArgument(sprintf(VNagLang::$no_standard_arguments_with_letter, $letter));
556
                                        #break;
556
                                        #break;
557
                        }
557
                        }
558
                }
558
                }
559
        }
559
        }
560
 
560
 
561
        public function addExpectedArgument($argObj) {
561
        public function addExpectedArgument($argObj) {
562
                // Emulate C++ "friend" access to hidden functions
562
                // Emulate C++ "friend" access to hidden functions
563
 
563
 
564
                // $this->helpObj->_addOption($argObj);
564
                // $this->helpObj->_addOption($argObj);
565
                $helpObjAddEntryMethod = new ReflectionMethod($this->helpObj, '_addOption');
565
                $helpObjAddEntryMethod = new ReflectionMethod($this->helpObj, '_addOption');
566
                $helpObjAddEntryMethod->setAccessible(true);
566
                $helpObjAddEntryMethod->setAccessible(true);
567
                $helpObjAddEntryMethod->invoke($this->helpObj, $argObj);
567
                $helpObjAddEntryMethod->invoke($this->helpObj, $argObj);
568
 
568
 
569
                // $this->argHandler->_addExpectedArgument($argObj);
569
                // $this->argHandler->_addExpectedArgument($argObj);
570
                $argHandlerAddEntryMethod = new ReflectionMethod($this->argHandler, '_addExpectedArgument');
570
                $argHandlerAddEntryMethod = new ReflectionMethod($this->argHandler, '_addExpectedArgument');
571
                $argHandlerAddEntryMethod->setAccessible(true);
571
                $argHandlerAddEntryMethod->setAccessible(true);
572
                $argHandlerAddEntryMethod->invoke($this->argHandler, $argObj);
572
                $argHandlerAddEntryMethod->invoke($this->argHandler, $argObj);
573
        }
573
        }
574
 
574
 
575
        protected function createArgumentHandler() {
575
        protected function createArgumentHandler() {
576
                $this->argHandler = new VNagArgumentHandler();
576
                $this->argHandler = new VNagArgumentHandler();
577
        }
577
        }
578
 
578
 
579
        protected function createHelpObject() {
579
        protected function createHelpObject() {
580
                $this->helpObj = new VNagHelp();
580
                $this->helpObj = new VNagHelp();
581
        }
581
        }
582
 
582
 
583
        protected function checkInitialized() {
583
        protected function checkInitialized() {
584
                if (!$this->initialized) throw new VNagFunctionCallOutsideSession();
584
                if (!$this->initialized) throw new VNagFunctionCallOutsideSession();
585
        }
585
        }
586
 
586
 
587
        protected function getVerbosityLevel() {
587
        protected function getVerbosityLevel() {
588
                $this->checkInitialized(); // if (!$this->initialized) return false;
588
                $this->checkInitialized(); // if (!$this->initialized) return false;
589
 
589
 
590
                if (!isset($this->argVerbosity)) {
590
                if (!isset($this->argVerbosity)) {
591
                        //The verbose argument is always optional
591
                        //The verbose argument is always optional
592
                        //throw new VNagRequiredArgumentNotRegistered('-v');
592
                        //throw new VNagRequiredArgumentNotRegistered('-v');
593
                        return self::VERBOSITY_SUMMARY;
593
                        return self::VERBOSITY_SUMMARY;
594
                } else {
594
                } else {
595
                        $level = $this->argVerbosity->count();
595
                        $level = $this->argVerbosity->count();
596
                        if ($level > self::MAX_VERBOSITY) $level = self::MAX_VERBOSITY;
596
                        if ($level > self::MAX_VERBOSITY) $level = self::MAX_VERBOSITY;
597
                        return $level;
597
                        return $level;
598
                }
598
                }
599
        }
599
        }
600
 
600
 
601
        public function getWarningRange($argumentNumber=0) {
601
        public function getWarningRange($argumentNumber=0) {
602
                $this->checkInitialized(); // if (!$this->initialized) return false;
602
                $this->checkInitialized(); // if (!$this->initialized) return false;
603
 
603
 
604
                if (!isset($this->warningRanges[$argumentNumber])) {
604
                if (!isset($this->warningRanges[$argumentNumber])) {
605
                        if (!is_null($this->argWarning)) {
605
                        if (!is_null($this->argWarning)) {
606
                                $warning = $this->argWarning->getValue();
606
                                $warning = $this->argWarning->getValue();
607
                                if (!is_null($warning)) {
607
                                if (!is_null($warning)) {
608
                                        $vals = explode(',',$warning);
608
                                        $vals = explode(',',$warning);
609
                                        foreach ($vals as $number => $val) {
609
                                        foreach ($vals as $number => $val) {
610
                                                if (_empty($val)) {
610
                                                if (_empty($val)) {
611
                                                        $this->warningRanges[$number] = null;
611
                                                        $this->warningRanges[$number] = null;
612
                                                } else {
612
                                                } else {
613
                                                        $singleValueBehavior = isset($this->warningSingleValueRangeBehaviors[$number]) ? $this->warningSingleValueRangeBehaviors[$number] : VNag::SINGLEVALUE_RANGE_DEFAULT;
613
                                                        $singleValueBehavior = isset($this->warningSingleValueRangeBehaviors[$number]) ? $this->warningSingleValueRangeBehaviors[$number] : VNag::SINGLEVALUE_RANGE_DEFAULT;
614
                                                        $this->warningRanges[$number] = new VNagRange($val, $singleValueBehavior);
614
                                                        $this->warningRanges[$number] = new VNagRange($val, $singleValueBehavior);
615
                                                }
615
                                                }
616
                                        }
616
                                        }
617
                                } else {
617
                                } else {
618
                                        $this->warningRanges[0] = $this->default_warning_range;
618
                                        $this->warningRanges[0] = $this->default_warning_range;
619
                                }
619
                                }
620
                        } else {
620
                        } else {
621
                                return null;
621
                                return null;
622
                        }
622
                        }
623
                }
623
                }
624
 
624
 
625
                if (isset($this->warningRanges[$argumentNumber])) {
625
                if (isset($this->warningRanges[$argumentNumber])) {
626
                        return $this->warningRanges[$argumentNumber];
626
                        return $this->warningRanges[$argumentNumber];
627
                } else {
627
                } else {
628
                        return null;
628
                        return null;
629
                }
629
                }
630
        }
630
        }
631
 
631
 
632
        public function getCriticalRange($argumentNumber=0) {
632
        public function getCriticalRange($argumentNumber=0) {
633
                $this->checkInitialized(); // if (!$this->initialized) return false;
633
                $this->checkInitialized(); // if (!$this->initialized) return false;
634
 
634
 
635
                if (!isset($this->criticalRanges[$argumentNumber])) {
635
                if (!isset($this->criticalRanges[$argumentNumber])) {
636
                        if (!is_null($this->argCritical)) {
636
                        if (!is_null($this->argCritical)) {
637
                                $critical = $this->argCritical->getValue();
637
                                $critical = $this->argCritical->getValue();
638
                                if (!is_null($critical)) {
638
                                if (!is_null($critical)) {
639
                                        $vals = explode(',',$critical);
639
                                        $vals = explode(',',$critical);
640
                                        foreach ($vals as $number => $val) {
640
                                        foreach ($vals as $number => $val) {
641
                                                $singleValueBehavior = isset($this->criticalSingleValueRangeBehaviors[$number]) ? $this->criticalSingleValueRangeBehaviors[$number] : VNag::SINGLEVALUE_RANGE_DEFAULT;
641
                                                $singleValueBehavior = isset($this->criticalSingleValueRangeBehaviors[$number]) ? $this->criticalSingleValueRangeBehaviors[$number] : VNag::SINGLEVALUE_RANGE_DEFAULT;
642
                                                $this->criticalRanges[$number] = new VNagRange($val, $singleValueBehavior);
642
                                                $this->criticalRanges[$number] = new VNagRange($val, $singleValueBehavior);
643
                                        }
643
                                        }
644
                                } else {
644
                                } else {
645
                                        $this->criticalRanges[0] = $this->default_critical_range;
645
                                        $this->criticalRanges[0] = $this->default_critical_range;
646
                                }
646
                                }
647
                        } else {
647
                        } else {
648
                                return null;
648
                                return null;
649
                        }
649
                        }
650
                }
650
                }
651
 
651
 
652
                if (isset($this->criticalRanges[$argumentNumber])) {
652
                if (isset($this->criticalRanges[$argumentNumber])) {
653
                        return $this->criticalRanges[$argumentNumber];
653
                        return $this->criticalRanges[$argumentNumber];
654
                } else {
654
                } else {
655
                        return null;
655
                        return null;
656
                }
656
                }
657
        }
657
        }
658
 
658
 
659
        public function checkAgainstWarningRange($values, $force=true, $autostatus=true, $argumentNumber=0) {
659
        public function checkAgainstWarningRange($values, $force=true, $autostatus=true, $argumentNumber=0) {
660
                $this->checkInitialized(); // if (!$this->initialized) return;
660
                $this->checkInitialized(); // if (!$this->initialized) return;
661
 
661
 
662
                if (!$this->getArgumentHandler()->isArgRegistered('w')) {
662
                if (!$this->getArgumentHandler()->isArgRegistered('w')) {
663
                        // Developer's mistake: The argument is not in the list of expected arguments
663
                        // Developer's mistake: The argument is not in the list of expected arguments
664
                        throw new VNagRequiredArgumentNotRegistered('-w');
664
                        throw new VNagRequiredArgumentNotRegistered('-w');
665
                }
665
                }
666
 
666
 
667
                $wr = $this->getWarningRange($argumentNumber);
667
                $wr = $this->getWarningRange($argumentNumber);
668
                if (isset($wr)) {
668
                if (isset($wr)) {
669
                        if ($wr->checkAlert($values)) {
669
                        if ($wr->checkAlert($values)) {
670
                                if ($autostatus) $this->setStatus(VNag::STATUS_WARNING);
670
                                if ($autostatus) $this->setStatus(VNag::STATUS_WARNING);
671
                                return true;
671
                                return true;
672
                        } else {
672
                        } else {
673
                                if ($autostatus) $this->setStatus(VNag::STATUS_OK);
673
                                if ($autostatus) $this->setStatus(VNag::STATUS_OK);
674
                                return false;
674
                                return false;
675
                        }
675
                        }
676
                } else {
676
                } else {
677
                        if ($force) {
677
                        if ($force) {
678
                                // User's mistake: They did not pass the argument to the plugin
678
                                // User's mistake: They did not pass the argument to the plugin
679
                                if (($argumentNumber > 0) && (count($this->warningRanges) > 0)) {
679
                                if (($argumentNumber > 0) && (count($this->warningRanges) > 0)) {
680
                                        throw new VNagInvalidArgumentException(sprintf(VNagLang::$too_few_warning_ranges, $argumentNumber+1));
680
                                        throw new VNagInvalidArgumentException(sprintf(VNagLang::$too_few_warning_ranges, $argumentNumber+1));
681
                                } else {
681
                                } else {
682
                                        throw new VNagRequiredArgumentMissing('-w');
682
                                        throw new VNagRequiredArgumentMissing('-w');
683
                                }
683
                                }
684
                        }
684
                        }
685
                }
685
                }
686
        }
686
        }
687
 
687
 
688
        public function checkAgainstCriticalRange($values, $force=true, $autostatus=true, $argumentNumber=0) {
688
        public function checkAgainstCriticalRange($values, $force=true, $autostatus=true, $argumentNumber=0) {
689
                $this->checkInitialized(); // if (!$this->initialized) return;
689
                $this->checkInitialized(); // if (!$this->initialized) return;
690
 
690
 
691
                if (!$this->getArgumentHandler()->isArgRegistered('c')) {
691
                if (!$this->getArgumentHandler()->isArgRegistered('c')) {
692
                        // Developer's mistake: The argument is not in the list of expected arguments
692
                        // Developer's mistake: The argument is not in the list of expected arguments
693
                        throw new VNagRequiredArgumentNotRegistered('-c');
693
                        throw new VNagRequiredArgumentNotRegistered('-c');
694
                }
694
                }
695
 
695
 
696
                $cr = $this->getCriticalRange($argumentNumber);
696
                $cr = $this->getCriticalRange($argumentNumber);
697
                if (isset($cr)) {
697
                if (isset($cr)) {
698
                        if ($cr->checkAlert($values)) {
698
                        if ($cr->checkAlert($values)) {
699
                                if ($autostatus) $this->setStatus(VNag::STATUS_CRITICAL);
699
                                if ($autostatus) $this->setStatus(VNag::STATUS_CRITICAL);
700
                                return true;
700
                                return true;
701
                        } else {
701
                        } else {
702
                                if ($autostatus) $this->setStatus(VNag::STATUS_OK);
702
                                if ($autostatus) $this->setStatus(VNag::STATUS_OK);
703
                                return false;
703
                                return false;
704
                        }
704
                        }
705
                } else {
705
                } else {
706
                        if ($force) {
706
                        if ($force) {
707
                                // User's mistake: They did not pass the argument to the plugin
707
                                // User's mistake: They did not pass the argument to the plugin
708
                                if (($argumentNumber > 0) && (count($this->warningRanges) > 0)) {
708
                                if (($argumentNumber > 0) && (count($this->warningRanges) > 0)) {
709
                                        throw new VNagInvalidArgumentException(sprintf(VNagLang::$too_few_critical_ranges, $argumentNumber+1));
709
                                        throw new VNagInvalidArgumentException(sprintf(VNagLang::$too_few_critical_ranges, $argumentNumber+1));
710
                                } else {
710
                                } else {
711
                                        throw new VNagRequiredArgumentMissing('-c');
711
                                        throw new VNagRequiredArgumentMissing('-c');
712
                                }
712
                                }
713
                        }
713
                        }
714
                }
714
                }
715
        }
715
        }
716
 
716
 
717
        protected static function getBaddestExitcode($code1, $code2) {
717
        protected static function getBaddestExitcode($code1, $code2) {
718
                return max($code1, $code2);
718
                return max($code1, $code2);
719
        }
719
        }
720
 
720
 
721
        # DO NOT CALL MANUALLY
721
        # DO NOT CALL MANUALLY
722
        # Unfortunately, this function has to be public, otherwise register_shutdown_function() wouldn't work
722
        # Unfortunately, this function has to be public, otherwise register_shutdown_function() wouldn't work
723
        public static function _shutdownHandler() {
723
        public static function _shutdownHandler() {
724
                if (!self::is_http_mode()) {
724
                if (!self::is_http_mode()) {
725
                        exit((int)self::$exitcode);
725
                        exit((int)self::$exitcode);
726
                }
726
                }
727
        }
727
        }
728
 
728
 
729
        protected function _exit($code) {
729
        protected function _exit($code) {
730
                self::$exitcode = $this->getBaddestExitcode($code, self::$exitcode);
730
                self::$exitcode = $this->getBaddestExitcode($code, self::$exitcode);
731
        }
731
        }
732
 
732
 
733
        private $constructed = false;
733
        private $constructed = false;
734
        function __construct() {
734
        function __construct() {
735
                $this->createHelpObject();
735
                $this->createHelpObject();
736
                $this->createArgumentHandler();
736
                $this->createArgumentHandler();
737
 
737
 
738
                $this->addExpectedArgument($this->argUsage = new VNagArgument('?', '', VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$prints_usage));
738
                $this->addExpectedArgument($this->argUsage = new VNagArgument('?', '', VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$prints_usage));
739
 
739
 
740
                $this->constructed = true;
740
                $this->constructed = true;
741
        }
741
        }
742
 
742
 
743
        function __destruct() {
743
        function __destruct() {
744
                if (Timeouter::started()) {
744
                if (Timeouter::started()) {
745
                        Timeouter::end();
745
                        Timeouter::end();
746
                }
746
                }
747
        }
747
        }
748
 
748
 
749
        public function run() {
749
        public function run() {
750
                global $inside_vnag_run;
750
                global $inside_vnag_run;
751
 
751
 
752
                $inside_vnag_run = true;
752
                $inside_vnag_run = true;
753
                try {
753
                try {
754
                        if (!$this->constructed) {
754
                        if (!$this->constructed) {
755
                                throw new VNagNotConstructed(VNagLang::$notConstructed);
755
                                throw new VNagNotConstructed(VNagLang::$notConstructed);
756
                        }
756
                        }
757
 
757
 
758
                        try {
758
                        try {
759
                                $this->initialized = true;
759
                                $this->initialized = true;
760
                                $this->html_before = '';
760
                                $this->html_before = '';
761
                                $this->html_after = '';
761
                                $this->html_after = '';
762
                                $this->setStatus(null, true);
762
                                $this->setStatus(null, true);
763
                                $this->messages = array();
763
                                $this->messages = array();
764
 
764
 
765
                                register_shutdown_function(array($this, '_shutdownHandler'));
765
                                register_shutdown_function(array($this, '_shutdownHandler'));
766
 
766
 
767
                                if ($this->argHandler->illegalUsage()) {
767
                                if ($this->argHandler->illegalUsage()) {
768
                                        $content = $this->helpObj->printUsagePage();
768
                                        $content = $this->helpObj->printUsagePage();
769
                                        $this->setStatus(VNag::STATUS_UNKNOWN);
769
                                        $this->setStatus(VNag::STATUS_UNKNOWN);
770
 
770
 
771
                                        if ($this->is_http_mode()) {
771
                                        if ($this->is_http_mode()) {
772
                                                echo $this->html_before;
772
                                                echo $this->html_before;
773
                                                if ($this->http_visual_output    & VNag::OUTPUT_SPECIAL) echo $this->writeVisualHTML($content);
773
                                                if ($this->http_visual_output    & VNag::OUTPUT_SPECIAL) echo $this->writeVisualHTML($content);
774
                                                if ($this->http_invisible_output & VNag::OUTPUT_SPECIAL) echo $this->writeInvisibleHTML($content);
774
                                                if ($this->http_invisible_output & VNag::OUTPUT_SPECIAL) echo $this->writeInvisibleHTML($content);
775
                                                echo $this->html_after;
775
                                                echo $this->html_after;
776
                                                return; // cancel
776
                                                return; // cancel
777
                                        } else {
777
                                        } else {
778
                                                echo $content;
778
                                                echo $content;
779
                                                return $this->_exit($this->status);
779
                                                return $this->_exit($this->status);
780
                                        }
780
                                        }
781
                                }
781
                                }
782
 
782
 
783
                                if (!is_null($this->argVersion) && ($this->argVersion->available())) {
783
                                if (!is_null($this->argVersion) && ($this->argVersion->available())) {
784
                                        $content = $this->helpObj->printVersionPage();
784
                                        $content = $this->helpObj->printVersionPage();
785
                                        $this->setStatus(VNag::STATUS_UNKNOWN);
785
                                        $this->setStatus(VNag::STATUS_UNKNOWN);
786
 
786
 
787
                                        if ($this->is_http_mode()) {
787
                                        if ($this->is_http_mode()) {
788
                                                echo $this->html_before;
788
                                                echo $this->html_before;
789
                                                if ($this->http_visual_output    & VNag::OUTPUT_SPECIAL) echo $this->writeVisualHTML($content);
789
                                                if ($this->http_visual_output    & VNag::OUTPUT_SPECIAL) echo $this->writeVisualHTML($content);
790
                                                if ($this->http_invisible_output & VNag::OUTPUT_SPECIAL) echo $this->writeInvisibleHTML($content);
790
                                                if ($this->http_invisible_output & VNag::OUTPUT_SPECIAL) echo $this->writeInvisibleHTML($content);
791
                                                echo $this->html_after;
791
                                                echo $this->html_after;
792
                                                return; // cancel
792
                                                return; // cancel
793
                                        } else {
793
                                        } else {
794
                                                echo $content;
794
                                                echo $content;
795
                                                return $this->_exit($this->status);
795
                                                return $this->_exit($this->status);
796
                                        }
796
                                        }
797
                                }
797
                                }
798
 
798
 
799
                                if (!is_null($this->argHelp) && ($this->argHelp->available())) {
799
                                if (!is_null($this->argHelp) && ($this->argHelp->available())) {
800
                                        $content = $this->helpObj->printHelpPage();
800
                                        $content = $this->helpObj->printHelpPage();
801
                                        $this->setStatus(VNag::STATUS_UNKNOWN);
801
                                        $this->setStatus(VNag::STATUS_UNKNOWN);
802
 
802
 
803
                                        if ($this->is_http_mode()) {
803
                                        if ($this->is_http_mode()) {
804
                                                echo $this->html_before;
804
                                                echo $this->html_before;
805
                                                if ($this->http_visual_output    & VNag::OUTPUT_SPECIAL) echo $this->writeVisualHTML($content);
805
                                                if ($this->http_visual_output    & VNag::OUTPUT_SPECIAL) echo $this->writeVisualHTML($content);
806
                                                if ($this->http_invisible_output & VNag::OUTPUT_SPECIAL) echo $this->writeInvisibleHTML($content);
806
                                                if ($this->http_invisible_output & VNag::OUTPUT_SPECIAL) echo $this->writeInvisibleHTML($content);
807
                                                echo $this->html_after;
807
                                                echo $this->html_after;
808
                                                return; // cancel
808
                                                return; // cancel
809
                                        } else {
809
                                        } else {
810
                                                echo $content;
810
                                                echo $content;
811
                                                return $this->_exit($this->status);
811
                                                return $this->_exit($this->status);
812
                                        }
812
                                        }
813
                                }
813
                                }
814
 
814
 
815
                                // Initialize ranges (and check their validity)
815
                                // Initialize ranges (and check their validity)
816
                                $this->getWarningRange();
816
                                $this->getWarningRange();
817
                                $this->getCriticalRange();
817
                                $this->getCriticalRange();
818
 
818
 
819
                                if (!is_null($this->argTimeout)) {
819
                                if (!is_null($this->argTimeout)) {
820
                                        $timeout = $this->argTimeout->getValue();
820
                                        $timeout = $this->argTimeout->getValue();
821
                                        if (!is_null($timeout)) {
821
                                        if (!is_null($timeout)) {
822
                                                Timeouter::start($timeout);
822
                                                Timeouter::start($timeout);
823
                                        }
823
                                        }
824
                                }
824
                                }
825
 
825
 
826
                                ob_start();
826
                                ob_start();
827
                                $init_ob_level = ob_get_level();
827
                                $init_ob_level = ob_get_level();
828
                                try {
828
                                try {
829
                                        $this->cbRun();
829
                                        $this->cbRun();
830
 
830
 
831
                                        // This will NOT be put in the 'finally' block, because otherwise it would trigger if an Exception happened (Which clears the OB)
831
                                        // This will NOT be put in the 'finally' block, because otherwise it would trigger if an Exception happened (Which clears the OB)
832
                                        if (ob_get_level() < $init_ob_level) throw new VNagImplementationErrorException(VNagLang::$output_level_lowered);
832
                                        if (ob_get_level() < $init_ob_level) throw new VNagImplementationErrorException(VNagLang::$output_level_lowered);
833
                                } finally {
833
                                } finally {
834
                                        while (ob_get_level() > $init_ob_level) @ob_end_clean();
834
                                        while (ob_get_level() > $init_ob_level) @ob_end_clean();
835
                                }
835
                                }
836
 
836
 
837
                                if (is_null($this->status)) $this->setStatus($this->default_status,true);
837
                                if (is_null($this->status)) $this->setStatus($this->default_status,true);
838
 
838
 
839
                                $outputType = VNag::OUTPUT_NORMAL;
839
                                $outputType = VNag::OUTPUT_NORMAL;
840
                        } catch (Exception $e) {
840
                        } catch (Exception $e) {
841
                                $this->handleException($e);
841
                                $this->handleException($e);
842
                                $outputType = VNag::OUTPUT_EXCEPTION;
842
                                $outputType = VNag::OUTPUT_EXCEPTION;
843
                        }
843
                        }
844
 
844
 
845
                        if ($this->is_http_mode()) {
845
                        if ($this->is_http_mode()) {
846
                                echo $this->html_before;
846
                                echo $this->html_before;
847
                                if ($this->http_invisible_output & $outputType) {
847
                                if ($this->http_invisible_output & $outputType) {
848
                                        echo $this->writeInvisibleHTML();
848
                                        echo $this->writeInvisibleHTML();
849
                                }
849
                                }
850
                                if ($this->http_visual_output & $outputType) {
850
                                if ($this->http_visual_output & $outputType) {
851
                                        echo $this->writeVisualHTML();
851
                                        echo $this->writeVisualHTML();
852
                                }
852
                                }
853
                                echo $this->html_after;
853
                                echo $this->html_after;
854
                        } else {
854
                        } else {
855
                                echo $this->getNagiosConsoleText();
855
                                echo $this->getNagiosConsoleText();
856
                                return $this->_exit($this->status);
856
                                return $this->_exit($this->status);
857
                        }
857
                        }
858
 
858
 
859
                        Timeouter::end();
859
                        Timeouter::end();
860
                } finally {
860
                } finally {
861
                        $inside_vnag_run = false;
861
                        $inside_vnag_run = false;
862
                }
862
                }
863
        }
863
        }
864
 
864
 
865
        private function getNagiosConsoleText() {
865
        private function getNagiosConsoleText() {
866
                // see https://nagios-plugins.org/doc/guidelines.html#AEN200
866
                // see https://nagios-plugins.org/doc/guidelines.html#AEN200
867
                // 1. space separated list of label/value pairs
867
                // 1. space separated list of label/value pairs
868
                $ary_perfdata = $this->getPerformanceData();
868
                $ary_perfdata = $this->getPerformanceData();
869
                $performancedata_first = array_shift($ary_perfdata);
869
                $performancedata_first = array_shift($ary_perfdata);
870
                $performancedata_rest  = implode(' ', $ary_perfdata);
870
                $performancedata_rest  = implode(' ', $ary_perfdata);
871
 
871
 
872
                $status_text = VNagLang::status($this->status, $this->statusmodel);
872
                $status_text = VNagLang::status($this->status, $this->statusmodel);
873
                if (_empty($this->getHeadline())) {
873
                if (_empty($this->getHeadline())) {
874
                        $content = $status_text;
874
                        $content = $status_text;
875
                } else {
875
                } else {
876
                        if ($this->show_status_in_headline) {
876
                        if ($this->show_status_in_headline) {
877
                                $content = $status_text.': '.$this->getHeadline();
877
                                $content = $status_text.': '.$this->getHeadline();
878
                        } else {
878
                        } else {
879
                                $content = $this->getHeadline();
879
                                $content = $this->getHeadline();
880
                        }
880
                        }
881
                }
881
                }
882
 
882
 
883
                if (!_empty($performancedata_first)) $content .= '|'.trim($performancedata_first);
883
                if (!_empty($performancedata_first)) $content .= '|'.trim($performancedata_first);
884
                $content .= "\n";
884
                $content .= "\n";
885
                if (!_empty($this->verbose_info)) {
885
                if (!_empty($this->verbose_info)) {
886
                        //$content .= "\n".VNagLang::$verbose_info.":\n\n";
886
                        //$content .= "\n".VNagLang::$verbose_info.":\n\n";
887
                        $content .= trim($this->verbose_info);
887
                        $content .= trim($this->verbose_info);
888
                }
888
                }
889
                if (!_empty($performancedata_rest)) $content .= '|'.trim($performancedata_rest);
889
                if (!_empty($performancedata_rest)) $content .= '|'.trim($performancedata_rest);
890
                $content .= "\n";
890
                $content .= "\n";
891
 
891
 
892
                return trim($content)."\n";
892
                return trim($content)."\n";
893
        }
893
        }
894
 
894
 
895
        abstract protected function cbRun();
895
        abstract protected function cbRun();
896
 
896
 
897
        public function addPerformanceData($prefDataObj, $move_to_font=false, $verbosityLevel=VNag::VERBOSITY_SUMMARY) {
897
        public function addPerformanceData($prefDataObj, $move_to_font=false, $verbosityLevel=VNag::VERBOSITY_SUMMARY) {
898
                $this->checkInitialized(); // if (!$this->initialized) return;
898
                $this->checkInitialized(); // if (!$this->initialized) return;
899
 
899
 
900
                if ((!isset($this->argVerbosity)) && ($verbosityLevel > VNag::VERBOSITY_SUMMARY)) throw new VNagRequiredArgumentNotRegistered('-v');
900
                if ((!isset($this->argVerbosity)) && ($verbosityLevel > VNag::VERBOSITY_SUMMARY)) throw new VNagRequiredArgumentNotRegistered('-v');
901
                if (self::getVerbosityLevel() < $verbosityLevel) return false;
901
                if (self::getVerbosityLevel() < $verbosityLevel) return false;
902
 
902
 
903
                if ($move_to_font) {
903
                if ($move_to_font) {
904
                        array_unshift($this->performanceDataObjects, $prefDataObj);
904
                        array_unshift($this->performanceDataObjects, $prefDataObj);
905
                } else {
905
                } else {
906
                        $this->performanceDataObjects[] = $prefDataObj;
906
                        $this->performanceDataObjects[] = $prefDataObj;
907
                }
907
                }
908
 
908
 
909
                return true;
909
                return true;
910
        }
910
        }
911
 
911
 
912
        public function getPerformanceData() {
912
        public function getPerformanceData() {
913
                $this->checkInitialized(); // if (!$this->initialized) return null;
913
                $this->checkInitialized(); // if (!$this->initialized) return null;
914
 
914
 
915
                // see https://nagios-plugins.org/doc/guidelines.html#AEN200
915
                // see https://nagios-plugins.org/doc/guidelines.html#AEN200
916
                // 1. space separated list of label/value pairs
916
                // 1. space separated list of label/value pairs
917
                return $this->performanceDataObjects;
917
                return $this->performanceDataObjects;
918
        }
918
        }
919
 
919
 
920
        public function removePerformanceData($prefDataObj) {
920
        public function removePerformanceData($prefDataObj) {
921
                if (($key = array_search($prefDataObj, $this->performanceDataObjects, true)) !== false) {
921
                if (($key = array_search($prefDataObj, $this->performanceDataObjects, true)) !== false) {
922
                        unset($this->performanceDataObjects[$key]);
922
                        unset($this->performanceDataObjects[$key]);
923
                        return true;
923
                        return true;
924
                } else {
924
                } else {
925
                        return false;
925
                        return false;
926
                }
926
                }
927
        }
927
        }
928
 
928
 
929
        public function clearPerformanceData() {
929
        public function clearPerformanceData() {
930
                $this->performanceDataObjects = array();
930
                $this->performanceDataObjects = array();
931
        }
931
        }
932
 
932
 
933
        public function getVerboseInfo() {
933
        public function getVerboseInfo() {
934
                return $this->verbose_info;
934
                return $this->verbose_info;
935
        }
935
        }
936
 
936
 
937
        public function clearVerboseInfo() {
937
        public function clearVerboseInfo() {
938
                $this->verbose_info = '';
938
                $this->verbose_info = '';
939
        }
939
        }
940
 
940
 
941
        private function writeVisualHTML($special_content=null) {
941
        private function writeVisualHTML($special_content=null) {
942
                if (!_empty($special_content)) {
942
                if (!_empty($special_content)) {
943
                        $content = $special_content;
943
                        $content = $special_content;
944
                } else {
944
                } else {
945
                        $content = strtoupper(VNagLang::$status.': '.VNagLang::status($this->status, $this->statusmodel))."\n\n";
945
                        $content = strtoupper(VNagLang::$status.': '.VNagLang::status($this->status, $this->statusmodel))."\n\n";
946
 
946
 
947
                        $content .= strtoupper(VNagLang::$message).":\n";
947
                        $content .= strtoupper(VNagLang::$message).":\n";
948
                        $status_text = VNagLang::status($this->status, $this->statusmodel);
948
                        $status_text = VNagLang::status($this->status, $this->statusmodel);
949
                        if (_empty($this->getHeadline())) {
949
                        if (_empty($this->getHeadline())) {
950
                                $content .= $status_text;
950
                                $content .= $status_text;
951
                        } else {
951
                        } else {
952
                                if ($this->show_status_in_headline) {
952
                                if ($this->show_status_in_headline) {
953
                                        $content .= $status_text.': '.trim($this->getHeadline());
953
                                        $content .= $status_text.': '.trim($this->getHeadline());
954
                                } else {
954
                                } else {
955
                                        $content .= trim($this->getHeadline());
955
                                        $content .= trim($this->getHeadline());
956
                                }
956
                                }
957
                        }
957
                        }
958
                        $content .= "\n\n";
958
                        $content .= "\n\n";
959
 
959
 
960
                        if (!_empty($this->verbose_info)) {
960
                        if (!_empty($this->verbose_info)) {
961
                                $content .= strtoupper(VNagLang::$verbose_info).":\n".trim($this->verbose_info)."\n\n";
961
                                $content .= strtoupper(VNagLang::$verbose_info).":\n".trim($this->verbose_info)."\n\n";
962
                        }
962
                        }
963
 
963
 
964
                        $perfdata = $this->getPerformanceData();
964
                        $perfdata = $this->getPerformanceData();
965
                        if (count($perfdata) > 0) {
965
                        if (count($perfdata) > 0) {
966
                                $content .= strtoupper(VNagLang::$performance_data).":\n";
966
                                $content .= strtoupper(VNagLang::$performance_data).":\n";
967
                                foreach ($perfdata as $pd) {
967
                                foreach ($perfdata as $pd) {
968
                                        $content .= trim($pd)."\n";
968
                                        $content .= trim($pd)."\n";
969
                                }
969
                                }
970
                                $content .= "\n";
970
                                $content .= "\n";
971
                        }
971
                        }
972
                }
972
                }
973
 
973
 
974
                $colorinfo = '';
974
                $colorinfo = '';
975
                $status = $this->getStatus();
975
                $status = $this->getStatus();
976
 
976
 
977
                if ($status == VNag::STATUS_OK)                 $colorinfo = ' style="background-color:green;color:white;font-weight:bold"';
977
                if ($status == VNag::STATUS_OK)                 $colorinfo = ' style="background-color:green;color:white;font-weight:bold"';
978
                else if ($status == VNag::STATUS_WARNING)       $colorinfo = ' style="background-color:yellow;color:black;font-weight:bold"';
978
                else if ($status == VNag::STATUS_WARNING)       $colorinfo = ' style="background-color:yellow;color:black;font-weight:bold"';
979
                else if ($status == VNag::STATUS_CRITICAL)      $colorinfo = ' style="background-color:red;color:white;font-weight:bold"';
979
                else if ($status == VNag::STATUS_CRITICAL)      $colorinfo = ' style="background-color:red;color:white;font-weight:bold"';
980
                else if ($status == VNag::STATUS_ERROR)         $colorinfo = ' style="background-color:purple;color:white;font-weight:bold"';
980
                else if ($status == VNag::STATUS_ERROR)         $colorinfo = ' style="background-color:purple;color:white;font-weight:bold"';
981
                else /* if ($status == VNag::STATUS_UNKNOWN) */ $colorinfo = ' style="background-color:lightgray;color:black;font-weight:bold"';
981
                else /* if ($status == VNag::STATUS_UNKNOWN) */ $colorinfo = ' style="background-color:lightgray;color:black;font-weight:bold"';
982
 
982
 
983
                $html_content = trim($content);
983
                $html_content = trim($content);
984
                $html_content = htmlentities($html_content);
984
                $html_content = htmlentities($html_content);
985
                $html_content = str_replace(' ', '&nbsp;', $html_content);
985
                $html_content = str_replace(' ', '&nbsp;', $html_content);
986
                $html_content = nl2br($html_content);
986
                $html_content = nl2br($html_content);
987
 
987
 
988
                // FUT: Allow individual design via CSS
988
                // FUT: Allow individual design via CSS
989
                return '<table border="1" cellspacing="2" cellpadding="2" style="width:100%" class="vnag_table">'.
989
                return '<table border="1" cellspacing="2" cellpadding="2" style="width:100%" class="vnag_table">'.
990
                        '<tr'.$colorinfo.' class="vnag_title_row">'.
990
                        '<tr'.$colorinfo.' class="vnag_title_row">'.
991
                        '<td>'.VNagLang::$nagios_output.'</td>'.
991
                        '<td>'.VNagLang::$nagios_output.'</td>'.
992
                        '</tr>'.
992
                        '</tr>'.
993
                        '<tr class="vnag_message_row">'.
993
                        '<tr class="vnag_message_row">'.
994
                        '<td><code>'.
994
                        '<td><code>'.
995
                        $html_content.
995
                        $html_content.
996
                        '</code></td>'.
996
                        '</code></td>'.
997
                        '</tr>'.
997
                        '</tr>'.
998
                        '</table>';
998
                        '</table>';
999
        }
999
        }
1000
 
1000
 
1001
        protected function readInvisibleHTML($html) {
1001
        protected function readInvisibleHTML($html) {
1002
                $this->checkInitialized(); // if (!$this->initialized) return;
1002
                $this->checkInitialized(); // if (!$this->initialized) return;
1003
 
1003
 
1004
                $doc = new DOMDocument(); // Requires: aptitude install php-dom
1004
                $doc = new DOMDocument(); // Requires: aptitude install php-dom
1005
                @$doc->loadHTML($html);   // added '@' because we don't want a warning for the non-standard <vnag> tag
1005
                @$doc->loadHTML($html);   // added '@' because we don't want a warning for the non-standard <vnag> tag
1006
 
1006
 
1007
                $tags = $doc->getElementsByTagName('script');
1007
                $tags = $doc->getElementsByTagName('script');
1008
                foreach ($tags as $tag) {
1008
                foreach ($tags as $tag) {
1009
                        $type = $tag->getAttribute('type');
1009
                        $type = $tag->getAttribute('type');
1010
                        if ($type !== 'application/json') continue;
1010
                        if ($type !== 'application/json') continue;
1011
 
1011
 
1012
                        $json = $tag->nodeValue;
1012
                        $json = $tag->nodeValue;
1013
                        if (!$json) continue;
1013
                        if (!$json) continue;
1014
 
1014
 
1015
                        $data = @json_decode($json,true);
1015
                        $data = @json_decode($json,true);
1016
                        if (!is_array($data)) continue;
1016
                        if (!is_array($data)) continue;
1017
 
1017
 
1018
                        if (!isset($data['type'])) continue;
1018
                        if (!isset($data['type'])) continue;
1019
                        if ($data['type'] === VNAG_JSONDATA_V1) {
1019
                        if ($data['type'] === VNAG_JSONDATA_V1) {
1020
                                if (!isset($data['datasets'])) throw new VNagWebInfoException(VNagLang::$dataset_missing);
1020
                                if (!isset($data['datasets'])) throw new VNagWebInfoException(VNagLang::$dataset_missing);
1021
                                foreach ($data['datasets'] as $dataset) {
1021
                                foreach ($data['datasets'] as $dataset) {
1022
                                        $payload = base64_decode($dataset['payload']);
1022
                                        $payload = base64_decode($dataset['payload']);
1023
                                        if (!$payload) {
1023
                                        if (!$payload) {
1024
                                                throw new VNagWebInfoException(VNagLang::$payload_not_base64);
1024
                                                throw new VNagWebInfoException(VNagLang::$payload_not_base64);
1025
                                        }
1025
                                        }
1026
 
1026
 
1027
                                        if (isset($dataset['encryption'])) {
1027
                                        if (isset($dataset['encryption'])) {
1028
                                                // The dataset is encrypted. We need to decrypt it first.
1028
                                                // The dataset is encrypted. We need to decrypt it first.
1029
 
1029
 
1030
                                                $cryptInfo = $dataset['encryption'];
1030
                                                $cryptInfo = $dataset['encryption'];
1031
                                                if (!is_array($cryptInfo)) {
1031
                                                if (!is_array($cryptInfo)) {
1032
                                                        throw new VNagWebInfoException(VNagLang::$dataset_encryption_no_array);
1032
                                                        throw new VNagWebInfoException(VNagLang::$dataset_encryption_no_array);
1033
                                                }
1033
                                                }
1034
 
1034
 
1035
                                                $password = is_null($this->password_in) ? '' : $this->password_in;
1035
                                                $password = is_null($this->password_in) ? '' : $this->password_in;
1036
 
1036
 
1037
                                                $salt = base64_decode($cryptInfo['salt']);
1037
                                                $salt = base64_decode($cryptInfo['salt']);
1038
 
1038
 
1039
                                                if ($cryptInfo['hash'] != hash('sha256',$salt.$password)) {
1039
                                                if ($cryptInfo['hash'] != hash('sha256',$salt.$password)) {
1040
                                                        if ($password == '') {
1040
                                                        if ($password == '') {
1041
                                                                throw new VNagWebInfoException(VNagLang::$require_password);
1041
                                                                throw new VNagWebInfoException(VNagLang::$require_password);
1042
                                                        } else {
1042
                                                        } else {
1043
                                                                throw new VNagWebInfoException(VNagLang::$wrong_password);
1043
                                                                throw new VNagWebInfoException(VNagLang::$wrong_password);
1044
                                                        }
1044
                                                        }
1045
                                                }
1045
                                                }
1046
 
1046
 
1047
                                                if (!function_exists('openssl_decrypt')) {
1047
                                                if (!function_exists('openssl_decrypt')) {
1048
                                                        throw new VNagException(VNagLang::$openssl_missing);
1048
                                                        throw new VNagException(VNagLang::$openssl_missing);
1049
                                                }
1049
                                                }
1050
 
1050
 
1051
                                                $payload = openssl_decrypt($payload, $cryptInfo['method'], $password, 0, $cryptInfo['iv']);
1051
                                                $payload = openssl_decrypt($payload, $cryptInfo['method'], $password, 0, $cryptInfo['iv']);
1052
                                        }
1052
                                        }
1053
 
1053
 
1054
                                        if (!is_null($this->pubkey) && ($this->pubkey !== '')) {
1054
                                        if (!is_null($this->pubkey) && ($this->pubkey !== '')) {
1055
                                                if (substr($this->pubkey,0,3) === '---') {
1055
                                                if (substr($this->pubkey,0,3) === '---') {
1056
                                                        $public_key = $this->pubkey;
1056
                                                        $public_key = $this->pubkey;
1057
                                                } else {
1057
                                                } else {
1058
                                                        if (!file_exists($this->pubkey)) {
1058
                                                        if (!file_exists($this->pubkey)) {
1059
                                                                throw new VNagInvalidArgumentException(sprintf(VNagLang::$pubkey_file_not_found, $this->pubkey));
1059
                                                                throw new VNagInvalidArgumentException(sprintf(VNagLang::$pubkey_file_not_found, $this->pubkey));
1060
                                                        }
1060
                                                        }
1061
 
1061
 
1062
                                                        $public_key = @file_get_contents($this->pubkey);
1062
                                                        $public_key = @file_get_contents($this->pubkey);
1063
                                                        if (!$public_key) {
1063
                                                        if (!$public_key) {
1064
                                                                throw new VNagPublicKeyException(sprintf(VNagLang::$pubkey_file_not_readable, $this->pubkey));
1064
                                                                throw new VNagPublicKeyException(sprintf(VNagLang::$pubkey_file_not_readable, $this->pubkey));
1065
                                                        }
1065
                                                        }
1066
                                                }
1066
                                                }
1067
 
1067
 
1068
                                                if (!isset($dataset['signature'])) {
1068
                                                if (!isset($dataset['signature'])) {
1069
                                                        throw new VNagSignatureException(VNagLang::$signature_missing);
1069
                                                        throw new VNagSignatureException(VNagLang::$signature_missing);
1070
                                                }
1070
                                                }
1071
 
1071
 
1072
                                                $signature = base64_decode($dataset['signature']);
1072
                                                $signature = base64_decode($dataset['signature']);
1073
                                                if (!$signature) {
1073
                                                if (!$signature) {
1074
                                                        throw new VNagSignatureException(VNagLang::$signature_not_bas64);
1074
                                                        throw new VNagSignatureException(VNagLang::$signature_not_bas64);
1075
                                                }
1075
                                                }
1076
 
1076
 
1077
                                                if (!function_exists('openssl_verify')) {
1077
                                                if (!function_exists('openssl_verify')) {
1078
                                                        throw new VNagException(VNagLang::$openssl_missing);
1078
                                                        throw new VNagException(VNagLang::$openssl_missing);
1079
                                                }
1079
                                                }
1080
 
1080
 
1081
                                                $sign_algo = is_null($this->sign_algo) ? OPENSSL_ALGO_SHA256 : $this->sign_algo;
1081
                                                $sign_algo = is_null($this->sign_algo) ? OPENSSL_ALGO_SHA256 : $this->sign_algo;
1082
                                                if (!openssl_verify($payload, $signature, $public_key, $sign_algo)) {
1082
                                                if (!openssl_verify($payload, $signature, $public_key, $sign_algo)) {
1083
                                                        throw new VNagSignatureException(VNagLang::$signature_invalid);
1083
                                                        throw new VNagSignatureException(VNagLang::$signature_invalid);
1084
                                                }
1084
                                                }
1085
                                        }
1085
                                        }
1086
 
1086
 
1087
                                        $payload = @json_decode($payload,true);
1087
                                        $payload = @json_decode($payload,true);
1088
                                        if (!$payload) {
1088
                                        if (!$payload) {
1089
                                                throw new VNagWebInfoException(VNagLang::$payload_not_json);
1089
                                                throw new VNagWebInfoException(VNagLang::$payload_not_json);
1090
                                        }
1090
                                        }
1091
 
1091
 
1092
                                        if ($payload['id'] == $this->id) {
1092
                                        if ($payload['id'] == $this->id) {
1093
                                                return $payload;
1093
                                                return $payload;
1094
                                        }
1094
                                        }
1095
                                }
1095
                                }
1096
                        }
1096
                        }
1097
                }
1097
                }
1098
 
1098
 
1099
                return null;
1099
                return null;
1100
        }
1100
        }
1101
 
1101
 
1102
        private function getNextMonitorID($peek=false) {
1102
        private function getNextMonitorID($peek=false) {
1103
                $result = is_null($this->id) ? self::$http_serial_number : $this->id;
1103
                $result = is_null($this->id) ? self::$http_serial_number : $this->id;
1104
 
1104
 
1105
                if (!$peek) {
1105
                if (!$peek) {
1106
                        $this->id = null; // use manual ID only once
1106
                        $this->id = null; // use manual ID only once
1107
                        self::$http_serial_number++;
1107
                        self::$http_serial_number++;
1108
                }
1108
                }
1109
 
1109
 
1110
                return $result;
1110
                return $result;
1111
        }
1111
        }
1112
 
1112
 
1113
        private function writeInvisibleHTML($special_content=null) {
1113
        private function writeInvisibleHTML($special_content=null) {
1114
                // 1. Create the payload
1114
                // 1. Create the payload
1115
 
1115
 
1116
                $payload['id'] = $this->getNextMonitorID();
1116
                $payload['id'] = $this->getNextMonitorID();
1117
 
1117
 
1118
                $payload['status'] = $this->getStatus();
1118
                $payload['status'] = $this->getStatus();
1119
 
1119
 
1120
                if (!_empty($special_content)) {
1120
                if (!_empty($special_content)) {
1121
                        $payload['text'] = $special_content;
1121
                        $payload['text'] = $special_content;
1122
                } else {
1122
                } else {
1123
                        $payload['headline'] = $this->getHeadline();
1123
                        $payload['headline'] = $this->getHeadline();
1124
                        $payload['verbose_info'] = $this->verbose_info;
1124
                        $payload['verbose_info'] = $this->verbose_info;
1125
 
1125
 
1126
                        $payload['performance_data'] = array();
1126
                        $payload['performance_data'] = array();
1127
                        foreach ($this->performanceDataObjects as $perfdata) {
1127
                        foreach ($this->performanceDataObjects as $perfdata) {
1128
                                $payload['performance_data'][] = (string)$perfdata;
1128
                                $payload['performance_data'][] = (string)$perfdata;
1129
                        }
1129
                        }
1130
                }
1130
                }
1131
 
1131
 
1132
                $payload = json_encode($payload);
1132
                $payload = json_encode($payload);
1133
 
1133
 
1134
                // 2. Encode the payload as JSON and optionally sign and/or encrypt it
1134
                // 2. Encode the payload as JSON and optionally sign and/or encrypt it
1135
 
1135
 
1136
                $dataset = array();
1136
                $dataset = array();
1137
 
1137
 
1138
                if (!is_null($this->privkey) && ($this->privkey !== '')) {
1138
                if (!is_null($this->privkey) && ($this->privkey !== '')) {
1139
                        if (!function_exists('openssl_pkey_get_private') || !function_exists('openssl_sign')) {
1139
                        if (!function_exists('openssl_pkey_get_private') || !function_exists('openssl_sign')) {
1140
                                throw new VNagException(VNagLang::$openssl_missing);
1140
                                throw new VNagException(VNagLang::$openssl_missing);
1141
                        }
1141
                        }
1142
 
1142
 
1143
                        if (substr($this->privkey,0,3) === '---') {
1143
                        if (substr($this->privkey,0,3) === '---') {
1144
                                $pkeyid = @openssl_pkey_get_private($this->privkey, $this->privkey_password);
1144
                                $pkeyid = @openssl_pkey_get_private($this->privkey, $this->privkey_password);
1145
                                if (!$pkeyid) {
1145
                                if (!$pkeyid) {
1146
                                        throw new VNagPrivateKeyException(sprintf(VNagLang::$privkey_not_readable));
1146
                                        throw new VNagPrivateKeyException(sprintf(VNagLang::$privkey_not_readable));
1147
                                }
1147
                                }
1148
                        } else {
1148
                        } else {
1149
                                if (!file_exists($this->privkey)) {
1149
                                if (!file_exists($this->privkey)) {
1150
                                        throw new VNagInvalidArgumentException(sprintf(VNagLang::$privkey_file_not_found, $this->privkey));
1150
                                        throw new VNagInvalidArgumentException(sprintf(VNagLang::$privkey_file_not_found, $this->privkey));
1151
                                }
1151
                                }
1152
                                $pkeyid = @openssl_pkey_get_private('file://'.$this->privkey, $this->privkey_password);
1152
                                $pkeyid = @openssl_pkey_get_private('file://'.$this->privkey, $this->privkey_password);
1153
                                if (!$pkeyid) {
1153
                                if (!$pkeyid) {
1154
                                        throw new VNagPrivateKeyException(sprintf(VNagLang::$privkey_file_not_readable, $this->privkey));
1154
                                        throw new VNagPrivateKeyException(sprintf(VNagLang::$privkey_file_not_readable, $this->privkey));
1155
                                }
1155
                                }
1156
                        }
1156
                        }
1157
 
1157
 
1158
                        $signature = '';
1158
                        $signature = '';
1159
                        $sign_algo = is_null($this->sign_algo) ? OPENSSL_ALGO_SHA256 : $this->sign_algo;
1159
                        $sign_algo = is_null($this->sign_algo) ? OPENSSL_ALGO_SHA256 : $this->sign_algo;
1160
                        if (@openssl_sign($payload, $signature, $pkeyid, $sign_algo)) {
1160
                        if (@openssl_sign($payload, $signature, $pkeyid, $sign_algo)) {
1161
                                if (version_compare(PHP_VERSION, '8.0.0') < 0) {
1161
                                if (version_compare(PHP_VERSION, '8.0.0') < 0) {
1162
                                        openssl_free_key($pkeyid);
1162
                                        openssl_free_key($pkeyid);
1163
                                }
1163
                                }
1164
 
1164
 
1165
                                $dataset['signature'] = base64_encode($signature);
1165
                                $dataset['signature'] = base64_encode($signature);
1166
                        } else {
1166
                        } else {
1167
                                throw new VNagPrivateKeyException(sprintf(VNagLang::$signature_failed));
1167
                                throw new VNagPrivateKeyException(sprintf(VNagLang::$signature_failed));
1168
                        }
1168
                        }
1169
                }
1169
                }
1170
 
1170
 
1171
                if (!is_null($this->password_out) && ($this->password_out !== '')) {
1171
                if (!is_null($this->password_out) && ($this->password_out !== '')) {
1172
                        if (!function_exists('openssl_encrypt')) {
1172
                        if (!function_exists('openssl_encrypt')) {
1173
                                throw new VNagException(VNagLang::$openssl_missing);
1173
                                throw new VNagException(VNagLang::$openssl_missing);
1174
                        }
1174
                        }
1175
 
1175
 
1176
                        $password = $this->password_out;
1176
                        $password = $this->password_out;
1177
 
1177
 
1178
                        $method = 'aes-256-ofb';
1178
                        $method = 'aes-256-ofb';
1179
                        $iv = substr(hash('sha256', openssl_random_pseudo_bytes(32)), 0, 16);
1179
                        $iv = substr(hash('sha256', openssl_random_pseudo_bytes(32)), 0, 16);
1180
                        $salt = openssl_random_pseudo_bytes(32);
1180
                        $salt = openssl_random_pseudo_bytes(32);
1181
 
1181
 
1182
                        $cryptInfo = array();
1182
                        $cryptInfo = array();
1183
                        $cryptInfo['method'] = $method;
1183
                        $cryptInfo['method'] = $method;
1184
                        $cryptInfo['iv'] = $iv;
1184
                        $cryptInfo['iv'] = $iv;
1185
                        $cryptInfo['salt'] = base64_encode($salt);
1185
                        $cryptInfo['salt'] = base64_encode($salt);
1186
                        $cryptInfo['hash'] = hash('sha256', $salt.$password);
1186
                        $cryptInfo['hash'] = hash('sha256', $salt.$password);
1187
 
1187
 
1188
                        $payload = openssl_encrypt($payload, $method, $password, 0, $iv);
1188
                        $payload = openssl_encrypt($payload, $method, $password, 0, $iv);
1189
                        $dataset['encryption'] = $cryptInfo;
1189
                        $dataset['encryption'] = $cryptInfo;
1190
                }
1190
                }
1191
 
1191
 
1192
                $dataset['payload'] = base64_encode($payload);
1192
                $dataset['payload'] = base64_encode($payload);
1193
 
1193
 
1194
                // 3. Encode everything as JSON+Base64 (again) and put it into the data block
1194
                // 3. Encode everything as JSON+Base64 (again) and put it into the data block
1195
 
1195
 
1196
                $json = array();
1196
                $json = array();
1197
                $json['type'] = VNAG_JSONDATA_V1;
1197
                $json['type'] = VNAG_JSONDATA_V1;
1198
                $json['datasets'] = array($dataset); // we only output 1 dataset. We could technically output more than one into this data block.
1198
                $json['datasets'] = array($dataset); // we only output 1 dataset. We could technically output more than one into this data block.
1199
 
1199
 
1200
                // Include the machine-readable information as data block
1200
                // Include the machine-readable information as data block
1201
                // This method was chosen to support HTML 4.01, XHTML and HTML5 as well without breaking the standards
1201
                // This method was chosen to support HTML 4.01, XHTML and HTML5 as well without breaking the standards
1202
                // see https://stackoverflow.com/questions/51222713/using-an-individual-tag-without-breaking-the-standards/51223609#51223609
1202
                // see https://stackoverflow.com/questions/51222713/using-an-individual-tag-without-breaking-the-standards/51223609#51223609
1203
                return '<script type="application/json">'.
1203
                return '<script type="application/json">'.
1204
                       json_encode($json).
1204
                       json_encode($json).
1205
                       '</script>';
1205
                       '</script>';
1206
        }
1206
        }
1207
 
1207
 
1208
        protected function appendHeadline($msg) {
1208
        protected function appendHeadline($msg) {
1209
                $this->checkInitialized(); // if (!$this->initialized) return;
1209
                $this->checkInitialized(); // if (!$this->initialized) return;
1210
 
1210
 
1211
                if (_empty($msg)) return false;
1211
                if (_empty($msg)) return false;
1212
                $this->messages[] = $msg;
1212
                $this->messages[] = $msg;
1213
 
1213
 
1214
                return true;
1214
                return true;
1215
        }
1215
        }
1216
 
1216
 
1217
        protected function changeHeadline($msg) {
1217
        protected function changeHeadline($msg) {
1218
                $this->checkInitialized(); // if (!$this->initialized) return;
1218
                $this->checkInitialized(); // if (!$this->initialized) return;
1219
 
1219
 
1220
                if (_empty($msg)) {
1220
                if (_empty($msg)) {
1221
                        $this->messages = array();
1221
                        $this->messages = array();
1222
                } else {
1222
                } else {
1223
                        $this->messages = array($msg);
1223
                        $this->messages = array($msg);
1224
                }
1224
                }
1225
 
1225
 
1226
                return true;
1226
                return true;
1227
        }
1227
        }
1228
 
1228
 
1229
        public function setHeadline($msg, $append=false, $verbosityLevel=VNag::VERBOSITY_SUMMARY) {
1229
        public function setHeadline($msg, $append=false, $verbosityLevel=VNag::VERBOSITY_SUMMARY) {
1230
                $this->checkInitialized(); // if (!$this->initialized) return;
1230
                $this->checkInitialized(); // if (!$this->initialized) return;
1231
 
1231
 
1232
                if ((!isset($this->argVerbosity)) && ($verbosityLevel > VNag::VERBOSITY_SUMMARY)) throw new VNagRequiredArgumentNotRegistered('-v');
1232
                if ((!isset($this->argVerbosity)) && ($verbosityLevel > VNag::VERBOSITY_SUMMARY)) throw new VNagRequiredArgumentNotRegistered('-v');
1233
                if (self::getVerbosityLevel() < $verbosityLevel) $msg = '';
1233
                if (self::getVerbosityLevel() < $verbosityLevel) $msg = '';
1234
 
1234
 
1235
                if ($append) {
1235
                if ($append) {
1236
                        return $this->appendHeadline($msg);
1236
                        return $this->appendHeadline($msg);
1237
                } else {
1237
                } else {
1238
                        return $this->changeHeadline($msg);
1238
                        return $this->changeHeadline($msg);
1239
                }
1239
                }
1240
        }
1240
        }
1241
 
1241
 
1242
        public function getHeadline() {
1242
        public function getHeadline() {
1243
                $this->checkInitialized(); // if (!$this->initialized) return '';
1243
                $this->checkInitialized(); // if (!$this->initialized) return '';
1244
 
1244
 
1245
                return implode(', ', $this->messages);
1245
                return implode(', ', $this->messages);
1246
        }
1246
        }
1247
 
1247
 
1248
        public function addVerboseMessage($msg, $verbosityLevel=VNag::VERBOSITY_SUMMARY) {
1248
        public function addVerboseMessage($msg, $verbosityLevel=VNag::VERBOSITY_SUMMARY) {
1249
                $this->checkInitialized(); // if (!$this->initialized) return;
1249
                $this->checkInitialized(); // if (!$this->initialized) return;
1250
 
1250
 
1251
                if (self::getVerbosityLevel() >= $verbosityLevel) {
1251
                if (self::getVerbosityLevel() >= $verbosityLevel) {
1252
                        $this->verbose_info .= $msg."\n";
1252
                        $this->verbose_info .= $msg."\n";
1253
                }
1253
                }
1254
        }
1254
        }
1255
 
1255
 
1256
        public function setStatus($status, $force=false) {
1256
        public function setStatus($status, $force=false) {
1257
                $this->checkInitialized(); // if (!$this->initialized) return;
1257
                $this->checkInitialized(); // if (!$this->initialized) return;
1258
 
1258
 
1259
                if (($force) || is_null($this->status) || ($status > $this->status)) {
1259
                if (($force) || is_null($this->status) || ($status > $this->status)) {
1260
                        $this->status = $status;
1260
                        $this->status = $status;
1261
                }
1261
                }
1262
        }
1262
        }
1263
 
1263
 
1264
        public function getStatus() {
1264
        public function getStatus() {
1265
                $this->checkInitialized(); // if (!$this->initialized) return;
1265
                $this->checkInitialized(); // if (!$this->initialized) return;
1266
 
1266
 
1267
                return $this->status;
1267
                return $this->status;
1268
        }
1268
        }
1269
 
1269
 
1270
        protected static function exceptionText($exception) {
1270
        protected static function exceptionText($exception) {
1271
                // $this->checkInitialized(); // if (!$this->initialized) return false;
1271
                // $this->checkInitialized(); // if (!$this->initialized) return false;
1272
 
1272
 
1273
                $class = get_class($exception);
1273
                $class = get_class($exception);
1274
                $msg = $exception->getMessage();
1274
                $msg = $exception->getMessage();
1275
 
1275
 
1276
                if (!_empty($msg)) {
1276
                if (!_empty($msg)) {
1277
                        return sprintf(VNagLang::$exception_x, $msg, $class);
1277
                        return sprintf(VNagLang::$exception_x, $msg, $class);
1278
                } else {
1278
                } else {
1279
                        return sprintf(VNagLang::$unhandled_exception_without_msg, $class);
1279
                        return sprintf(VNagLang::$unhandled_exception_without_msg, $class);
1280
                }
1280
                }
1281
        }
1281
        }
1282
 
1282
 
1283
        protected function handleException($exception) {
1283
        protected function handleException($exception) {
1284
                $this->checkInitialized(); // if (!$this->initialized) return;
1284
                $this->checkInitialized(); // if (!$this->initialized) return;
1285
 
1285
 
1286
                if (!VNag::is_http_mode()) {
1286
                if (!VNag::is_http_mode()) {
1287
                        // On console output, remove anything we have written so far!
1287
                        // On console output, remove anything we have written so far!
1288
                        while (ob_get_level() > 0) @ob_end_clean();
1288
                        while (ob_get_level() > 0) @ob_end_clean();
1289
                }
1289
                }
1290
                $this->clearVerboseInfo();
1290
                $this->clearVerboseInfo();
1291
                $this->clearPerformanceData();
1291
                $this->clearPerformanceData();
1292
 
1292
 
1293
                if ($exception instanceof VNagException) {
1293
                if ($exception instanceof VNagException) {
1294
                        $this->setStatus($exception->getStatus());
1294
                        $this->setStatus($exception->getStatus());
1295
                } else {
1295
                } else {
1296
                        $this->setStatus(self::STATUS_ERROR);
1296
                        $this->setStatus(self::STATUS_ERROR);
1297
                }
1297
                }
1298
 
1298
 
1299
                $this->setHeadline($this->exceptionText($exception), false);
1299
                $this->setHeadline($this->exceptionText($exception), false);
1300
 
1300
 
1301
                if ($exception instanceof VNagImplementationErrorException) {
1301
                if ($exception instanceof VNagImplementationErrorException) {
1302
                        $this->addVerboseMessage($exception->getTraceAsString(), VNag::VERBOSITY_SUMMARY);
1302
                        $this->addVerboseMessage($exception->getTraceAsString(), VNag::VERBOSITY_SUMMARY);
1303
                } else {
1303
                } else {
1304
                        if (isset($this->argVerbosity)) {
1304
                        if (isset($this->argVerbosity)) {
1305
                                $this->addVerboseMessage($exception->getTraceAsString(), VNag::VERBOSITY_ADDITIONAL_INFORMATION);
1305
                                $this->addVerboseMessage($exception->getTraceAsString(), VNag::VERBOSITY_ADDITIONAL_INFORMATION);
1306
                        } else {
1306
                        } else {
1307
                                // $this->addVerboseMessage($exception->getTraceAsString(), VNag::VERBOSITY_SUMMARY);
1307
                                // $this->addVerboseMessage($exception->getTraceAsString(), VNag::VERBOSITY_SUMMARY);
1308
                        }
1308
                        }
1309
                }
1309
                }
1310
        }
1310
        }
1311
}
1311
}
1312
 
1312
 
1313
 
1313
 
1314
class VNagException extends Exception {
1314
class VNagException extends Exception {
1315
        public function getStatus() {
1315
        public function getStatus() {
1316
                return VNag::STATUS_ERROR;
1316
                return VNag::STATUS_ERROR;
1317
        }
1317
        }
1318
}
1318
}
1319
 
1319
 
1320
class VNagTimeoutException extends VNagException {}
1320
class VNagTimeoutException extends VNagException {}
1321
 
1321
 
1322
class VNagWebInfoException extends VNagException {}
1322
class VNagWebInfoException extends VNagException {}
1323
class VNagSignatureException extends VNagException {}
1323
class VNagSignatureException extends VNagException {}
1324
class VNagPublicKeyException extends VNagException {}
1324
class VNagPublicKeyException extends VNagException {}
1325
class VNagPrivateKeyException extends VNagException {}
1325
class VNagPrivateKeyException extends VNagException {}
1326
 
1326
 
1327
// VNagInvalidArgumentException are exceptions which result from a wrong use
1327
// VNagInvalidArgumentException are exceptions which result from a wrong use
1328
// of arguments by the USER (CLI arguments or HTTP parameters)
1328
// of arguments by the USER (CLI arguments or HTTP parameters)
1329
class VNagInvalidArgumentException extends VNagException {
1329
class VNagInvalidArgumentException extends VNagException {
1330
        public function getStatus() {
1330
        public function getStatus() {
1331
                return VNag::STATUS_UNKNOWN;
1331
                return VNag::STATUS_UNKNOWN;
1332
        }
1332
        }
1333
}
1333
}
1334
 
1334
 
1335
class VNagValueUomPairSyntaxException extends VNagInvalidArgumentException {
1335
class VNagValueUomPairSyntaxException extends VNagInvalidArgumentException {
1336
        public function __construct($str) {
1336
        public function __construct($str) {
1337
                $e_msg = sprintf(VNagLang::$valueUomPairSyntaxError, $str);
1337
                $e_msg = sprintf(VNagLang::$valueUomPairSyntaxError, $str);
1338
                parent::__construct($e_msg);
1338
                parent::__construct($e_msg);
1339
        }
1339
        }
1340
}
1340
}
1341
 
1341
 
1342
class VNagInvalidTimeoutException extends VNagInvalidArgumentException {}
1342
class VNagInvalidTimeoutException extends VNagInvalidArgumentException {}
1343
 
1343
 
1344
class VNagInvalidRangeException extends VNagInvalidArgumentException {
1344
class VNagInvalidRangeException extends VNagInvalidArgumentException {
1345
        public function __construct($msg) {
1345
        public function __construct($msg) {
1346
                $e_msg = VNagLang::$range_is_invalid;
1346
                $e_msg = VNagLang::$range_is_invalid;
1347
                if (!_empty($msg)) $e_msg .= ': '.trim($msg);
1347
                if (!_empty($msg)) $e_msg .= ': '.trim($msg);
1348
                parent::__construct($e_msg);
1348
                parent::__construct($e_msg);
1349
        }
1349
        }
1350
}
1350
}
1351
 
1351
 
1352
class VNagInvalidShortOpt extends VNagImplementationErrorException {}
1352
class VNagInvalidShortOpt extends VNagImplementationErrorException {}
1353
class VNagInvalidLongOpt extends VNagImplementationErrorException {}
1353
class VNagInvalidLongOpt extends VNagImplementationErrorException {}
1354
class VNagInvalidValuePolicy extends VNagImplementationErrorException {}
1354
class VNagInvalidValuePolicy extends VNagImplementationErrorException {}
1355
class VNagIllegalStatusModel extends VNagImplementationErrorException {}
1355
class VNagIllegalStatusModel extends VNagImplementationErrorException {}
1356
class VNagNotConstructed extends VNagImplementationErrorException {}
1356
class VNagNotConstructed extends VNagImplementationErrorException {}
1357
 
1357
 
1358
// To enforce that people use the API correctly, we report flaws in the implementation
1358
// To enforce that people use the API correctly, we report flaws in the implementation
1359
// as Exception.
1359
// as Exception.
1360
class VNagImplementationErrorException extends VNagException {}
1360
class VNagImplementationErrorException extends VNagException {}
1361
 
1361
 
1362
class VNagInvalidStandardArgument extends VNagImplementationErrorException  {}
1362
class VNagInvalidStandardArgument extends VNagImplementationErrorException  {}
1363
class VNagFunctionCallOutsideSession extends VNagImplementationErrorException {}
1363
class VNagFunctionCallOutsideSession extends VNagImplementationErrorException {}
1364
class VNagIllegalArgumentValuesException extends VNagImplementationErrorException {}
1364
class VNagIllegalArgumentValuesException extends VNagImplementationErrorException {}
1365
 
1365
 
1366
class VNagRequiredArgumentNotRegistered extends VNagImplementationErrorException {
1366
class VNagRequiredArgumentNotRegistered extends VNagImplementationErrorException {
1367
        // Developer's mistake: The argument is not in the list of expected arguments
1367
        // Developer's mistake: The argument is not in the list of expected arguments
1368
        public function __construct($required_argument) {
1368
        public function __construct($required_argument) {
1369
                $e_msg = sprintf(VNagLang::$query_without_expected_argument, $required_argument);
1369
                $e_msg = sprintf(VNagLang::$query_without_expected_argument, $required_argument);
1370
                parent::__construct($e_msg);
1370
                parent::__construct($e_msg);
1371
        }
1371
        }
1372
}
1372
}
1373
 
1373
 
1374
class VNagRequiredArgumentMissing extends VNagInvalidArgumentException {
1374
class VNagRequiredArgumentMissing extends VNagInvalidArgumentException {
1375
        // User's mistake: They did not pass the argument to the plugin
1375
        // User's mistake: They did not pass the argument to the plugin
1376
        public function __construct($required_argument) {
1376
        public function __construct($required_argument) {
1377
                $e_msg = sprintf(VNagLang::$required_argument_missing, $required_argument);
1377
                $e_msg = sprintf(VNagLang::$required_argument_missing, $required_argument);
1378
                parent::__construct($e_msg);
1378
                parent::__construct($e_msg);
1379
        }
1379
        }
1380
}
1380
}
1381
 
1381
 
1382
class VNagUnknownUomException extends VNagInvalidArgumentException {
1382
class VNagUnknownUomException extends VNagInvalidArgumentException {
1383
        public function __construct($uom) {
1383
        public function __construct($uom) {
1384
                $e_msg = sprintf(VNagLang::$perfdata_uom_not_recognized, $uom);
1384
                $e_msg = sprintf(VNagLang::$perfdata_uom_not_recognized, $uom);
1385
                parent::__construct($e_msg);
1385
                parent::__construct($e_msg);
1386
        }
1386
        }
1387
}
1387
}
1388
 
1388
 
1389
class VNagNoCompatibleRangeUomFoundException extends VNagException {}
1389
class VNagNoCompatibleRangeUomFoundException extends VNagException {}
1390
 
1390
 
1391
class VNagMixedUomsNotImplemented extends VNagInvalidArgumentException {
1391
class VNagMixedUomsNotImplemented extends VNagInvalidArgumentException {
1392
        public function __construct($uom1, $uom2) {
1392
        public function __construct($uom1, $uom2) {
1393
                if (_empty($uom1)) $uom1 = VNagLang::$none;
1393
                if (_empty($uom1)) $uom1 = VNagLang::$none;
1394
                if (_empty($uom2)) $uom2 = VNagLang::$none;
1394
                if (_empty($uom2)) $uom2 = VNagLang::$none;
1395
                $e_msg = sprintf(VNagLang::$perfdata_mixed_uom_not_implemented, $uom1, $uom2);
1395
                $e_msg = sprintf(VNagLang::$perfdata_mixed_uom_not_implemented, $uom1, $uom2);
1396
                parent::__construct($e_msg);
1396
                parent::__construct($e_msg);
1397
        }
1397
        }
1398
}
1398
}
1399
 
1399
 
1400
class VNagUomConvertException extends VNagInvalidArgumentException {
1400
class VNagUomConvertException extends VNagInvalidArgumentException {
1401
        // It is unknown where the invalid UOM that was passed to the normalize() function came from,
1401
        // It is unknown where the invalid UOM that was passed to the normalize() function came from,
1402
        // so it is not clear what parent this Exception class should have...
1402
        // so it is not clear what parent this Exception class should have...
1403
        // If the value comes from the developer: VNagImplementationErrorException
1403
        // If the value comes from the developer: VNagImplementationErrorException
1404
        // If the value came from the user: VNagInvalidArgumentException
1404
        // If the value came from the user: VNagInvalidArgumentException
1405
 
1405
 
1406
        public function __construct($uom1, $uom2) {
1406
        public function __construct($uom1, $uom2) {
1407
                if (_empty($uom1)) $uom1 = VNagLang::$none;
1407
                if (_empty($uom1)) $uom1 = VNagLang::$none;
1408
                if (_empty($uom2)) $uom2 = VNagLang::$none;
1408
                if (_empty($uom2)) $uom2 = VNagLang::$none;
1409
                $e_msg = sprintf(VNagLang::$convert_x_y_error, $uom1, $uom2);
1409
                $e_msg = sprintf(VNagLang::$convert_x_y_error, $uom1, $uom2);
1410
                parent::__construct($e_msg);
1410
                parent::__construct($e_msg);
1411
        }
1411
        }
1412
}
1412
}
1413
 
1413
 
1414
class VNagInvalidPerformanceDataException extends VNagInvalidArgumentException {
1414
class VNagInvalidPerformanceDataException extends VNagInvalidArgumentException {
1415
        public function __construct($msg) {
1415
        public function __construct($msg) {
1416
                $e_msg = VNagLang::$performance_data_invalid;
1416
                $e_msg = VNagLang::$performance_data_invalid;
1417
                if (!_empty($msg)) $e_msg .= ': '.trim($msg);
1417
                if (!_empty($msg)) $e_msg .= ': '.trim($msg);
1418
                parent::__construct($e_msg);
1418
                parent::__construct($e_msg);
1419
        }
1419
        }
1420
}
1420
}
1421
 
1421
 
1422
class Timeouter {
1422
class Timeouter {
1423
        // based on http://stackoverflow.com/questions/7493676/detecting-a-timeout-for-a-block-of-code-in-php
1423
        // based on http://stackoverflow.com/questions/7493676/detecting-a-timeout-for-a-block-of-code-in-php
1424
 
1424
 
1425
        private static $start_time = false;
1425
        private static $start_time = false;
1426
        private static $timeout;
1426
        private static $timeout;
1427
        private static $fired      = false;
1427
        private static $fired      = false;
1428
        private static $registered = false;
1428
        private static $registered = false;
1429
 
1429
 
1430
        private function __construct() {
1430
        private function __construct() {
1431
        }
1431
        }
1432
 
1432
 
1433
        public static function start($timeout) {
1433
        public static function start($timeout) {
1434
                if (!is_numeric($timeout) || ($timeout <= 0)) {
1434
                if (!is_numeric($timeout) || ($timeout <= 0)) {
1435
                        throw new VNagInvalidTimeoutException(sprintf(VNagLang::$timeout_value_invalid, $timeout));
1435
                        throw new VNagInvalidTimeoutException(sprintf(VNagLang::$timeout_value_invalid, $timeout));
1436
                }
1436
                }
1437
 
1437
 
1438
                self::$start_time = microtime(true);
1438
                self::$start_time = microtime(true);
1439
                self::$timeout    = (float) $timeout;
1439
                self::$timeout    = (float) $timeout;
1440
                self::$fired      = false;
1440
                self::$fired      = false;
1441
                if (!self::$registered) {
1441
                if (!self::$registered) {
1442
                        self::$registered = true;
1442
                        self::$registered = true;
1443
                        register_tick_function(array('Timeouter', 'tick'));
1443
                        register_tick_function(array('Timeouter', 'tick'));
1444
                }
1444
                }
1445
        }
1445
        }
1446
 
1446
 
1447
        public static function started() {
1447
        public static function started() {
1448
                return self::$registered;
1448
                return self::$registered;
1449
        }
1449
        }
1450
 
1450
 
1451
        public static function end() {
1451
        public static function end() {
1452
                if (self::$registered) {
1452
                if (self::$registered) {
1453
                        unregister_tick_function(array('Timeouter', 'tick'));
1453
                        unregister_tick_function(array('Timeouter', 'tick'));
1454
                        self::$registered = false;
1454
                        self::$registered = false;
1455
                }
1455
                }
1456
        }
1456
        }
1457
 
1457
 
1458
        public static function tick() {
1458
        public static function tick() {
1459
                if ((!self::$fired) && ((microtime(true) - self::$start_time) > self::$timeout)) {
1459
                if ((!self::$fired) && ((microtime(true) - self::$start_time) > self::$timeout)) {
1460
                        self::$fired = true; // do not fire again
1460
                        self::$fired = true; // do not fire again
1461
                        throw new VNagTimeoutException(VNagLang::$timeout_exception);
1461
                        throw new VNagTimeoutException(VNagLang::$timeout_exception);
1462
                }
1462
                }
1463
        }
1463
        }
1464
}
1464
}
1465
 
1465
 
1466
class VNagArgument {
1466
class VNagArgument {
1467
        const VALUE_FORBIDDEN = 0;
1467
        const VALUE_FORBIDDEN = 0;
1468
        const VALUE_REQUIRED  = 1;
1468
        const VALUE_REQUIRED  = 1;
1469
        const VALUE_OPTIONAL  = 2;
1469
        const VALUE_OPTIONAL  = 2;
1470
 
1470
 
1471
        protected $shortopt;
1471
        protected $shortopt;
1472
        protected $longopts;
1472
        protected $longopts;
1473
        protected $valuePolicy;
1473
        protected $valuePolicy;
1474
        protected $valueName;
1474
        protected $valueName;
1475
        protected $helpText;
1475
        protected $helpText;
1476
        protected $defaultValue = null;
1476
        protected $defaultValue = null;
1477
 
1477
 
1478
        protected static $all_short = '';
1478
        protected static $all_short = '';
1479
        protected static $all_long = array();
1479
        protected static $all_long = array();
1480
 
1480
 
1481
        public function getShortOpt() {
1481
        public function getShortOpt() {
1482
                return $this->shortopt;
1482
                return $this->shortopt;
1483
        }
1483
        }
1484
 
1484
 
1485
        public function getLongOpts() {
1485
        public function getLongOpts() {
1486
                return $this->longopts;
1486
                return $this->longopts;
1487
        }
1487
        }
1488
 
1488
 
1489
        public function getValuePolicy() {
1489
        public function getValuePolicy() {
1490
                return $this->valuePolicy;
1490
                return $this->valuePolicy;
1491
        }
1491
        }
1492
 
1492
 
1493
        public function getValueName() {
1493
        public function getValueName() {
1494
                return $this->valueName;
1494
                return $this->valueName;
1495
        }
1495
        }
1496
 
1496
 
1497
        public function getHelpText() {
1497
        public function getHelpText() {
1498
                return $this->helpText;
1498
                return $this->helpText;
1499
        }
1499
        }
1500
 
1500
 
1501
        static private function validateShortOpt($shortopt) {
1501
        static private function validateShortOpt($shortopt) {
1502
                $m = array();
1502
                $m = array();
1503
                return preg_match('@^[a-zA-Z0-9\\+\\-\\?]$@', $shortopt, $m);
1503
                return preg_match('@^[a-zA-Z0-9\\+\\-\\?]$@', $shortopt, $m);
1504
        }
1504
        }
1505
 
1505
 
1506
        static private function validateLongOpt($longopt) {
1506
        static private function validateLongOpt($longopt) {
1507
                // FUT: Check if this is accurate
1507
                // FUT: Check if this is accurate
1508
                $m = array();
1508
                $m = array();
1509
                return preg_match('@^[a-zA-Z0-9\\+\\-\\?]+$@', $longopt, $m);
1509
                return preg_match('@^[a-zA-Z0-9\\+\\-\\?]+$@', $longopt, $m);
1510
        }
1510
        }
1511
 
1511
 
1512
        // Note: Currently, we do not support following:
1512
        // Note: Currently, we do not support following:
1513
        // 1. How many times may a value be defined (it needs to be manually described in $helpText)
1513
        // 1. How many times may a value be defined (it needs to be manually described in $helpText)
1514
        // 2. Is this argument mandatory? (No exception will be thrown if the plugin will be started without this argument)
1514
        // 2. Is this argument mandatory? (No exception will be thrown if the plugin will be started without this argument)
1515
        public function __construct($shortopt, $longopts, $valuePolicy, $valueName, $helpText, $defaultValue=null) {
1515
        public function __construct($shortopt, $longopts, $valuePolicy, $valueName, $helpText, $defaultValue=null) {
1516
                // Check if $valueName is defined correctly in regards to the policy $valuePolicy
1516
                // Check if $valueName is defined correctly in regards to the policy $valuePolicy
1517
                switch ($valuePolicy) {
1517
                switch ($valuePolicy) {
1518
                        case VNagArgument::VALUE_FORBIDDEN:
1518
                        case VNagArgument::VALUE_FORBIDDEN:
1519
                                if (!_empty($valueName)) {
1519
                                if (!_empty($valueName)) {
1520
                                        throw new VNagImplementationErrorException(sprintf(VNagLang::$value_name_forbidden));
1520
                                        throw new VNagImplementationErrorException(sprintf(VNagLang::$value_name_forbidden));
1521
                                }
1521
                                }
1522
                                break;
1522
                                break;
1523
                        case VNagArgument::VALUE_REQUIRED:
1523
                        case VNagArgument::VALUE_REQUIRED:
1524
                                if (_empty($valueName)) {
1524
                                if (_empty($valueName)) {
1525
                                        throw new VNagImplementationErrorException(sprintf(VNagLang::$value_name_required));
1525
                                        throw new VNagImplementationErrorException(sprintf(VNagLang::$value_name_required));
1526
                                }
1526
                                }
1527
                                break;
1527
                                break;
1528
                        case VNagArgument::VALUE_OPTIONAL:
1528
                        case VNagArgument::VALUE_OPTIONAL:
1529
                                if (_empty($valueName)) {
1529
                                if (_empty($valueName)) {
1530
                                        throw new VNagImplementationErrorException(sprintf(VNagLang::$value_name_required));
1530
                                        throw new VNagImplementationErrorException(sprintf(VNagLang::$value_name_required));
1531
                                }
1531
                                }
1532
                                break;
1532
                                break;
1533
                        default:
1533
                        default:
1534
                                throw new VNagInvalidValuePolicy(sprintf(VNagLang::$illegal_valuepolicy, $valuePolicy));
1534
                                throw new VNagInvalidValuePolicy(sprintf(VNagLang::$illegal_valuepolicy, $valuePolicy));
1535
                }
1535
                }
1536
 
1536
 
1537
                // We'll check: Does the shortopt contain illegal characters?
1537
                // We'll check: Does the shortopt contain illegal characters?
1538
                // http://stackoverflow.com/questions/28522387/which-chars-are-valid-shortopts-for-gnu-getopt
1538
                // http://stackoverflow.com/questions/28522387/which-chars-are-valid-shortopts-for-gnu-getopt
1539
                // We do not filter +, - and ?, since we might need it for other methods, e.g. VNagArgumentHandler::_addExpectedArgument
1539
                // We do not filter +, - and ?, since we might need it for other methods, e.g. VNagArgumentHandler::_addExpectedArgument
1540
                if (!_empty($shortopt)) {
1540
                if (!_empty($shortopt)) {
1541
                        if (!self::validateShortOpt($shortopt)) {
1541
                        if (!self::validateShortOpt($shortopt)) {
1542
                                throw new VNagInvalidShortOpt(sprintf(VNagLang::$illegal_shortopt, $shortopt));
1542
                                throw new VNagInvalidShortOpt(sprintf(VNagLang::$illegal_shortopt, $shortopt));
1543
                        }
1543
                        }
1544
                }
1544
                }
1545
 
1545
 
1546
                if (is_array($longopts)) { // $longopts is an array
1546
                if (is_array($longopts)) { // $longopts is an array
1547
                        foreach ($longopts as $longopt) {
1547
                        foreach ($longopts as $longopt) {
1548
                                if (!self::validateLongOpt($longopt)) {
1548
                                if (!self::validateLongOpt($longopt)) {
1549
                                        throw new VNagInvalidLongOpt(sprintf(VNagLang::$illegal_longopt, $longopt));
1549
                                        throw new VNagInvalidLongOpt(sprintf(VNagLang::$illegal_longopt, $longopt));
1550
                                }
1550
                                }
1551
                        }
1551
                        }
1552
                } else if (!_empty($longopts)) { // $longopts is a string
1552
                } else if (!_empty($longopts)) { // $longopts is a string
1553
                        if (!self::validateLongOpt($longopts)) {
1553
                        if (!self::validateLongOpt($longopts)) {
1554
                                throw new VNagInvalidLongOpt(sprintf(VNagLang::$illegal_longopt, $longopts));
1554
                                throw new VNagInvalidLongOpt(sprintf(VNagLang::$illegal_longopt, $longopts));
1555
                        }
1555
                        }
1556
                        $longopts = array($longopts);
1556
                        $longopts = array($longopts);
1557
                } else {
1557
                } else {
1558
                        $longopts = array();
1558
                        $longopts = array();
1559
                }
1559
                }
1560
 
1560
 
1561
                # valuePolicy must be between 0..2 and being int
1561
                # valuePolicy must be between 0..2 and being int
1562
                switch ($valuePolicy) {
1562
                switch ($valuePolicy) {
1563
                        case VNagArgument::VALUE_FORBIDDEN:
1563
                        case VNagArgument::VALUE_FORBIDDEN:
1564
                                $policyApdx = '';
1564
                                $policyApdx = '';
1565
                                break;
1565
                                break;
1566
                        case VNagArgument::VALUE_REQUIRED:
1566
                        case VNagArgument::VALUE_REQUIRED:
1567
                                $policyApdx = ':';
1567
                                $policyApdx = ':';
1568
                                break;
1568
                                break;
1569
                        case VNagArgument::VALUE_OPTIONAL:
1569
                        case VNagArgument::VALUE_OPTIONAL:
1570
                                $policyApdx = '::';
1570
                                $policyApdx = '::';
1571
                                break;
1571
                                break;
1572
                        default:
1572
                        default:
1573
                                throw new VNagInvalidValuePolicy(sprintf(VNagLang::$illegal_valuepolicy, $valuePolicy));
1573
                                throw new VNagInvalidValuePolicy(sprintf(VNagLang::$illegal_valuepolicy, $valuePolicy));
1574
                }
1574
                }
1575
 
1575
 
1576
                if ((!is_null($shortopt)) && ($shortopt != '?')) self::$all_short .= $shortopt.$policyApdx;
1576
                if ((!is_null($shortopt)) && ($shortopt != '?')) self::$all_short .= $shortopt.$policyApdx;
1577
                if (is_array($longopts)) {
1577
                if (is_array($longopts)) {
1578
                        foreach ($longopts as $longopt) {
1578
                        foreach ($longopts as $longopt) {
1579
                                self::$all_long[] = $longopt.$policyApdx;
1579
                                self::$all_long[] = $longopt.$policyApdx;
1580
                        }
1580
                        }
1581
                }
1581
                }
1582
 
1582
 
1583
                $this->shortopt     = $shortopt;
1583
                $this->shortopt     = $shortopt;
1584
                $this->longopts     = $longopts;
1584
                $this->longopts     = $longopts;
1585
                $this->valuePolicy  = $valuePolicy;
1585
                $this->valuePolicy  = $valuePolicy;
1586
                $this->valueName    = $valueName;
1586
                $this->valueName    = $valueName;
1587
                $this->helpText     = $helpText;
1587
                $this->helpText     = $helpText;
1588
                $this->defaultValue = $defaultValue;
1588
                $this->defaultValue = $defaultValue;
1589
        }
1589
        }
1590
 
1590
 
1591
        protected static function getOptions() {
1591
        protected static function getOptions() {
1592
                // Attention: In PHP 5.6.19-0+deb8u1 (cli), $_REQUEST is always set, so we need is_http_mode() instead of isset($_REQUEST)!
1592
                // Attention: In PHP 5.6.19-0+deb8u1 (cli), $_REQUEST is always set, so we need is_http_mode() instead of isset($_REQUEST)!
1593
                global $OVERWRITE_ARGUMENTS;
1593
                global $OVERWRITE_ARGUMENTS;
1594
 
1594
 
1595
                if (!is_null($OVERWRITE_ARGUMENTS)) {
1595
                if (!is_null($OVERWRITE_ARGUMENTS)) {
1596
                        return $OVERWRITE_ARGUMENTS;
1596
                        return $OVERWRITE_ARGUMENTS;
1597
                } else if (VNag::is_http_mode()) {
1597
                } else if (VNag::is_http_mode()) {
1598
                        return $_REQUEST;
1598
                        return $_REQUEST;
1599
                } else {
1599
                } else {
1600
                        return getopt(self::$all_short, self::$all_long);
1600
                        return getopt(self::$all_short, self::$all_long);
1601
                }
1601
                }
1602
        }
1602
        }
1603
 
1603
 
1604
        public function count() {
1604
        public function count() {
1605
                $options = self::getOptions();
1605
                $options = self::getOptions();
1606
 
1606
 
1607
                $count = 0;
1607
                $count = 0;
1608
 
1608
 
1609
                if (isset($options[$this->shortopt])) {
1609
                if (isset($options[$this->shortopt])) {
1610
                        if (is_array($options[$this->shortopt])) {
1610
                        if (is_array($options[$this->shortopt])) {
1611
                                // e.g. -vvv
1611
                                // e.g. -vvv
1612
                                $count += count($options[$this->shortopt]);
1612
                                $count += count($options[$this->shortopt]);
1613
                        } else {
1613
                        } else {
1614
                                // e.g. -v
1614
                                // e.g. -v
1615
                                $count += 1;
1615
                                $count += 1;
1616
                        }
1616
                        }
1617
                }
1617
                }
1618
 
1618
 
1619
                if (!is_null($this->longopts)) {
1619
                if (!is_null($this->longopts)) {
1620
                        foreach ($this->longopts as $longopt) {
1620
                        foreach ($this->longopts as $longopt) {
1621
                                if (isset($options[$longopt])) {
1621
                                if (isset($options[$longopt])) {
1622
                                        if (is_array($options[$longopt])) {
1622
                                        if (is_array($options[$longopt])) {
1623
                                                // e.g. --verbose --verbose --verbose
1623
                                                // e.g. --verbose --verbose --verbose
1624
                                                $count += count($options[$longopt]);
1624
                                                $count += count($options[$longopt]);
1625
                                        } else {
1625
                                        } else {
1626
                                                // e.g. --verbose
1626
                                                // e.g. --verbose
1627
                                                $count += 1;
1627
                                                $count += 1;
1628
                                        }
1628
                                        }
1629
                                }
1629
                                }
1630
                        }
1630
                        }
1631
                }
1631
                }
1632
 
1632
 
1633
                return $count;
1633
                return $count;
1634
        }
1634
        }
1635
 
1635
 
1636
        public function available() {
1636
        public function available() {
1637
                $options = self::getOptions();
1637
                $options = self::getOptions();
1638
 
1638
 
1639
                if (isset($options[$this->shortopt])) return true;
1639
                if (isset($options[$this->shortopt])) return true;
1640
                if (!is_null($this->longopts)) {
1640
                if (!is_null($this->longopts)) {
1641
                        foreach ($this->longopts as $longopt) {
1641
                        foreach ($this->longopts as $longopt) {
1642
                                if (isset($options[$longopt])) return true;
1642
                                if (isset($options[$longopt])) return true;
1643
                        }
1643
                        }
1644
                }
1644
                }
1645
                return false;
1645
                return false;
1646
        }
1646
        }
1647
 
1647
 
1648
        public function require() {
1648
        public function require() {
1649
                if (!$this->available() && is_null($this->defaultValue)) {
1649
                if (!$this->available() && is_null($this->defaultValue)) {
1650
                        $opt = $this->shortopt;
1650
                        $opt = $this->shortopt;
1651
                        $opt = !_empty($opt) ? '-'.$opt : (isset($this->longopts[0]) ? '--'.$this->longopts[0] : '?');
1651
                        $opt = !_empty($opt) ? '-'.$opt : (isset($this->longopts[0]) ? '--'.$this->longopts[0] : '?');
1652
                        throw new VNagRequiredArgumentMissing($opt);
1652
                        throw new VNagRequiredArgumentMissing($opt);
1653
                }
1653
                }
1654
        }
1654
        }
1655
 
1655
 
1656
        public function getValue() {
1656
        public function getValue() {
1657
                $options = self::getOptions();
1657
                $options = self::getOptions();
1658
 
1658
 
1659
                if (isset($options[$this->shortopt])) {
1659
                if (isset($options[$this->shortopt])) {
1660
                        $x = $options[$this->shortopt];
1660
                        $x = $options[$this->shortopt];
1661
                        if (is_array($x) && (count($x) <= 1)) $options[$this->shortopt] = $options[$this->shortopt][0];
1661
                        if (is_array($x) && (count($x) <= 1)) $options[$this->shortopt] = $options[$this->shortopt][0];
1662
                        return $options[$this->shortopt];
1662
                        return $options[$this->shortopt];
1663
                }
1663
                }
1664
 
1664
 
1665
                if (!is_null($this->longopts)) {
1665
                if (!is_null($this->longopts)) {
1666
                        foreach ($this->longopts as $longopt) {
1666
                        foreach ($this->longopts as $longopt) {
1667
                                if (isset($options[$longopt])) {
1667
                                if (isset($options[$longopt])) {
1668
                                        $x = $options[$longopt];
1668
                                        $x = $options[$longopt];
1669
                                        if (is_array($x) && (count($x) <= 1)) $options[$longopt] = $options[$longopt][0];
1669
                                        if (is_array($x) && (count($x) <= 1)) $options[$longopt] = $options[$longopt][0];
1670
                                        return $options[$longopt];
1670
                                        return $options[$longopt];
1671
                                }
1671
                                }
1672
                        }
1672
                        }
1673
                }
1673
                }
1674
 
1674
 
1675
                return $this->defaultValue;
1675
                return $this->defaultValue;
1676
        }
1676
        }
1677
}
1677
}
1678
 
1678
 
1679
class VNagArgumentHandler {
1679
class VNagArgumentHandler {
1680
        protected $expectedArgs = array();
1680
        protected $expectedArgs = array();
1681
 
1681
 
1682
        // Will be called by VNag via ReflectionMethod (like C++ style friends), because it should not be called manually.
1682
        // Will be called by VNag via ReflectionMethod (like C++ style friends), because it should not be called manually.
1683
        // Use VNag's function instead (since it adds to the helpObj too)
1683
        // Use VNag's function instead (since it adds to the helpObj too)
1684
        protected function _addExpectedArgument($argObj) {
1684
        protected function _addExpectedArgument($argObj) {
1685
                // -? is always illegal, so it will trigger illegalUsage(). So we don't add it to the list of
1685
                // -? is always illegal, so it will trigger illegalUsage(). So we don't add it to the list of
1686
                // expected arguments, otherwise illegalUsage() would be true.
1686
                // expected arguments, otherwise illegalUsage() would be true.
1687
                if ($argObj->getShortOpt() == '?') return false;
1687
                if ($argObj->getShortOpt() == '?') return false;
1688
 
1688
 
1689
                // GNU extensions with a special meaning
1689
                // GNU extensions with a special meaning
1690
                if ($argObj->getShortOpt() == '-') return false; // cancel parsing
1690
                if ($argObj->getShortOpt() == '-') return false; // cancel parsing
1691
                if ($argObj->getShortOpt() == '+') return false; // enable POSIXLY_CORRECT
1691
                if ($argObj->getShortOpt() == '+') return false; // enable POSIXLY_CORRECT
1692
 
1692
 
1693
                $this->expectedArgs[] = $argObj;
1693
                $this->expectedArgs[] = $argObj;
1694
                return true;
1694
                return true;
1695
        }
1695
        }
1696
 
1696
 
1697
        public function getArgumentObj($shortopt) {
1697
        public function getArgumentObj($shortopt) {
1698
                foreach ($this->expectedArgs as $argObj) {
1698
                foreach ($this->expectedArgs as $argObj) {
1699
                        if ($argObj->getShortOpt() == $shortopt) return $argObj;
1699
                        if ($argObj->getShortOpt() == $shortopt) return $argObj;
1700
                }
1700
                }
1701
                return null;
1701
                return null;
1702
        }
1702
        }
1703
 
1703
 
1704
        public function isArgRegistered($shortopt) {
1704
        public function isArgRegistered($shortopt) {
1705
                return !is_null($this->getArgumentObj($shortopt));
1705
                return !is_null($this->getArgumentObj($shortopt));
1706
        }
1706
        }
1707
 
1707
 
1708
        public function illegalUsage() {
1708
        public function illegalUsage() {
1709
                // In this function, we should check if $argv (resp. getopts) contains stuff which is not expected or illegal,
1709
                // In this function, we should check if $argv (resp. getopts) contains stuff which is not expected or illegal,
1710
                // so the script can show an usage information and quit the program.
1710
                // so the script can show a usage information and quit the program.
1711
 
1711
 
1712
                // WONTFIX: PHP's horrible implementation of GNU's getopt does not allow following intended tasks:
1712
                // WONTFIX: PHP's horrible implementation of GNU's getopt does not allow following intended tasks:
1713
                // - check for illegal values/arguments (e.g. the argument -? which is always illegal)
1713
                // - check for illegal values/arguments (e.g. the argument -? which is always illegal)
1714
                // - check for missing values (e.g. -H instead of -H localhost )
1714
                // - check for missing values (e.g. -H instead of -H localhost )
1715
                // - check for unexpected arguments (e.g. -x if only -a -b -c are defined in $expectedArgs as expected arguments)
1715
                // - check for unexpected arguments (e.g. -x if only -a -b -c are defined in $expectedArgs as expected arguments)
1716
                // - Of course, everything behind "--" may not be evaluated
1716
                // - Of course, everything behind "--" may not be evaluated
1717
                // see also http://stackoverflow.com/questions/25388130/catch-unexpected-options-with-getopt
1717
                // see also http://stackoverflow.com/questions/25388130/catch-unexpected-options-with-getopt
1718
 
1718
 
1719
                // So the only way is to do this stupid hard coded check for '-?'
1719
                // So the only way is to do this stupid hard coded check for '-?'
1720
                // PHP sucks...
1720
                // PHP sucks...
1721
                global $argv;
1721
                global $argv;
1722
                return (isset($argv[1])) && (($argv[1] == '-?') || ($argv[1] == '/?'));
1722
                return (isset($argv[1])) && (($argv[1] == '-?') || ($argv[1] == '/?'));
1723
        }
1723
        }
1724
}
1724
}
1725
 
1725
 
1726
class VNagRange {
1726
class VNagRange {
1727
        // see https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT
1727
        // see https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT
1728
        // We allow UOMs inside the range definition, e.g. "-w @10M:50M"
1728
        // We allow UOMs inside the range definition, e.g. "-w @10M:50M"
1729
 
1729
 
1730
        public /*VNagValueUomPair|'-inf'*/ $start;
1730
        public /*VNagValueUomPair|'-inf'*/ $start;
1731
        public /*VNagValueUomPair|'inf'*/ $end;
1731
        public /*VNagValueUomPair|'inf'*/ $end;
1732
        public /*boolean*/ $warnInsideRange;
1732
        public /*boolean*/ $warnInsideRange;
1733
 
1733
 
1734
        public function __construct($rangeDef, $singleValueBehavior=VNag::SINGLEVALUE_RANGE_DEFAULT) {
1734
        public function __construct($rangeDef, $singleValueBehavior=VNag::SINGLEVALUE_RANGE_DEFAULT) {
1735
                $m = array();
1735
                $m = array();
1736
                //if (!preg_match('|(@){0,1}(\d+)(:){0,1}(\d+){0,1}|', $rangeDef, $m)) {
1736
                //if (!preg_match('|(@){0,1}(\d+)(:){0,1}(\d+){0,1}|', $rangeDef, $m)) {
1737
                if (!preg_match('|^(@){0,1}([^:]+)(:){0,1}(.*)$|', $rangeDef, $m)) {
1737
                if (!preg_match('|^(@){0,1}([^:]+)(:){0,1}(.*)$|', $rangeDef, $m)) {
1738
                        throw new VNagInvalidRangeException(sprintf(VNagLang::$range_invalid_syntax, $rangeDef));
1738
                        throw new VNagInvalidRangeException(sprintf(VNagLang::$range_invalid_syntax, $rangeDef));
1739
                }
1739
                }
1740
 
1740
 
1741
                $this->warnInsideRange = $m[1] === '@';
1741
                $this->warnInsideRange = $m[1] === '@';
1742
 
1742
 
1743
                $this->start = null;
1743
                $this->start = null;
1744
                $this->end   = null;
1744
                $this->end   = null;
1745
 
1745
 
1746
                if ($m[3] === ':') {
1746
                if ($m[3] === ':') {
1747
                        if ($m[2] === '~') {
1747
                        if ($m[2] === '~') {
1748
                                $this->start = '-inf';
1748
                                $this->start = '-inf';
1749
                        } else {
1749
                        } else {
1750
                                $this->start = new VNagValueUomPair($m[2]);
1750
                                $this->start = new VNagValueUomPair($m[2]);
1751
                        }
1751
                        }
1752
 
1752
 
1753
                        if (_empty($m[4])) {
1753
                        if (_empty($m[4])) {
1754
                                $this->end = 'inf';
1754
                                $this->end = 'inf';
1755
                        } else {
1755
                        } else {
1756
                                $this->end = new VNagValueUomPair($m[4]);
1756
                                $this->end = new VNagValueUomPair($m[4]);
1757
                        }
1757
                        }
1758
                } else {
1758
                } else {
1759
                        assert(_empty($m[4]));
1759
                        assert(_empty($m[4]));
1760
                        assert(!_empty($m[2]));
1760
                        assert(!_empty($m[2]));
1761
 
1761
 
1762
                        $x = $m[2];
1762
                        $x = $m[2];
1763
 
1763
 
1764
                        if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_DEFAULT) {
1764
                        if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_DEFAULT) {
1765
                                // Default behavior according to the development guidelines:
1765
                                // Default behavior according to the development guidelines:
1766
                                //  x means  0:x, which means, x>10 is bad
1766
                                //  x means  0:x, which means, x>10 is bad
1767
                                // @x means @0:x, which means, x<=10 is bad
1767
                                // @x means @0:x, which means, x<=10 is bad
1768
                                $this->start = new VNagValueUomPair('0'.((new VNagValueUomPair($x))->getUom()));
1768
                                $this->start = new VNagValueUomPair('0'.((new VNagValueUomPair($x))->getUom()));
1769
                                $this->end   = new VNagValueUomPair($x);
1769
                                $this->end   = new VNagValueUomPair($x);
1770
                        } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_GT_X_BAD) {
1770
                        } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_GT_X_BAD) {
1771
                                // The single value x means, everything > x is bad. @x is not defined.
1771
                                // The single value x means, everything > x is bad. @x is not defined.
1772
                                if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol);
1772
                                if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol);
1773
                                $this->warnInsideRange = 0;
1773
                                $this->warnInsideRange = 0;
1774
                                $this->start = '-inf';
1774
                                $this->start = '-inf';
1775
                                $this->end   = new VNagValueUomPair($x);
1775
                                $this->end   = new VNagValueUomPair($x);
1776
                        } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_GE_X_BAD) {
1776
                        } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_GE_X_BAD) {
1777
                                // The single value x means, everything >= x is bad. @x is not defined.
1777
                                // The single value x means, everything >= x is bad. @x is not defined.
1778
                                if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol);
1778
                                if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol);
1779
                                $this->warnInsideRange = 1;
1779
                                $this->warnInsideRange = 1;
1780
                                $this->start = new VNagValueUomPair($x);
1780
                                $this->start = new VNagValueUomPair($x);
1781
                                $this->end   = 'inf';
1781
                                $this->end   = 'inf';
1782
                        } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_LT_X_BAD) {
1782
                        } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_LT_X_BAD) {
1783
                                // The single value x means, everything < x is bad. @x is not defined.
1783
                                // The single value x means, everything < x is bad. @x is not defined.
1784
                                if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol);
1784
                                if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol);
1785
                                $this->warnInsideRange = 0;
1785
                                $this->warnInsideRange = 0;
1786
                                $this->start = new VNagValueUomPair($x);
1786
                                $this->start = new VNagValueUomPair($x);
1787
                                $this->end   = 'inf';
1787
                                $this->end   = 'inf';
1788
                        } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_LE_X_BAD) {
1788
                        } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_LE_X_BAD) {
1789
                                // The single value x means, everything <= x is bad. @x is not defined.
1789
                                // The single value x means, everything <= x is bad. @x is not defined.
1790
                                if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol);
1790
                                if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol);
1791
                                $this->warnInsideRange = 1;
1791
                                $this->warnInsideRange = 1;
1792
                                $this->start = '-inf';
1792
                                $this->start = '-inf';
1793
                                $this->end   = new VNagValueUomPair($x);
1793
                                $this->end   = new VNagValueUomPair($x);
1794
                        } else {
1794
                        } else {
1795
                                throw new VNagException(VNagLang::$illegalSingleValueBehavior);
1795
                                throw new VNagException(VNagLang::$illegalSingleValueBehavior);
1796
                        }
1796
                        }
1797
                }
1797
                }
1798
 
1798
 
1799
                // Check if range is valid
1799
                // Check if range is valid
1800
                if (is_null($this->start)) {
1800
                if (is_null($this->start)) {
1801
                        throw new VNagInvalidRangeException(VNagLang::$invalid_start_value);
1801
                        throw new VNagInvalidRangeException(VNagLang::$invalid_start_value);
1802
                }
1802
                }
1803
                if (is_null($this->end)) {
1803
                if (is_null($this->end)) {
1804
                        throw new VNagInvalidRangeException(VNagLang::$invalid_end_value);
1804
                        throw new VNagInvalidRangeException(VNagLang::$invalid_end_value);
1805
                }
1805
                }
1806
                if (($this->start instanceof VNagValueUomPair) && ($this->end instanceof VNagValueUomPair) &&
1806
                if (($this->start instanceof VNagValueUomPair) && ($this->end instanceof VNagValueUomPair) &&
1807
                    (VNagValueUomPair::compare($this->start,$this->end) > 0)) {
1807
                    (VNagValueUomPair::compare($this->start,$this->end) > 0)) {
1808
                        throw new VNagInvalidRangeException(VNagLang::$start_is_greater_than_end);
1808
                        throw new VNagInvalidRangeException(VNagLang::$start_is_greater_than_end);
1809
                }
1809
                }
1810
        }
1810
        }
1811
 
1811
 
1812
        public function __toString() {
1812
        public function __toString() {
1813
                // Attention:
1813
                // Attention:
1814
                // - this function assumes that $start and $end are valid.
1814
                // - this function assumes that $start and $end are valid.
1815
                // - not the shortest result will be chosen
1815
                // - not the shortest result will be chosen
1816
 
1816
 
1817
                $ret = '';
1817
                $ret = '';
1818
                if ($this->warnInsideRange) {
1818
                if ($this->warnInsideRange) {
1819
                        $ret = '@';
1819
                        $ret = '@';
1820
                }
1820
                }
1821
 
1821
 
1822
                if ($this->start === '-inf') {
1822
                if ($this->start === '-inf') {
1823
                        $ret .= '~';
1823
                        $ret .= '~';
1824
                } else {
1824
                } else {
1825
                        $ret .= $this->start;
1825
                        $ret .= $this->start;
1826
                }
1826
                }
1827
 
1827
 
1828
                $ret .= ':';
1828
                $ret .= ':';
1829
 
1829
 
1830
                if ($this->end !== 'inf') {
1830
                if ($this->end !== 'inf') {
1831
                        $ret .= $this->end;
1831
                        $ret .= $this->end;
1832
                }
1832
                }
1833
 
1833
 
1834
                return $ret;
1834
                return $ret;
1835
        }
1835
        }
1836
 
1836
 
1837
        public function checkAlert($values) {
1837
        public function checkAlert($values) {
1838
                $compatibleCount = 0;
1838
                $compatibleCount = 0;
1839
 
1839
 
1840
                if (!is_array($values)) $values = array($values);
1840
                if (!is_array($values)) $values = array($values);
1841
                foreach ($values as $value) {
1841
                foreach ($values as $value) {
1842
                        if (!($value instanceof VNagValueUomPair)) $value = new VNagValueUomPair($value);
1842
                        if (!($value instanceof VNagValueUomPair)) $value = new VNagValueUomPair($value);
1843
 
1843
 
1844
                        assert(($this->start === '-inf') || ($this->start instanceof VNagValueUomPair));
1844
                        assert(($this->start === '-inf') || ($this->start instanceof VNagValueUomPair));
1845
                        assert(($this->end   === 'inf' ) || ($this->end   instanceof VNagValueUomPair));
1845
                        assert(($this->end   === 'inf' ) || ($this->end   instanceof VNagValueUomPair));
1846
 
1846
 
1847
                        if (($this->start !== '-inf') && (!$this->start->compatibleWith($value))) continue;
1847
                        if (($this->start !== '-inf') && (!$this->start->compatibleWith($value))) continue;
1848
                        if (($this->end   !== 'inf')  && (!$this->end->compatibleWith($value)))   continue;
1848
                        if (($this->end   !== 'inf')  && (!$this->end->compatibleWith($value)))   continue;
1849
                        $compatibleCount++;
1849
                        $compatibleCount++;
1850
 
1850
 
1851
                        if ($this->warnInsideRange) {
1851
                        if ($this->warnInsideRange) {
1852
                                return (($this->start === '-inf') || (VNagValueUomPair::compare($value,$this->start) >= 0)) &&
1852
                                return (($this->start === '-inf') || (VNagValueUomPair::compare($value,$this->start) >= 0)) &&
1853
                                       (($this->end   === 'inf')  || (VNagValueUomPair::compare($value,$this->end)   <= 0));
1853
                                       (($this->end   === 'inf')  || (VNagValueUomPair::compare($value,$this->end)   <= 0));
1854
                        } else {
1854
                        } else {
1855
                                return (($this->start !== '-inf') && (VNagValueUomPair::compare($value,$this->start) <  0)) ||
1855
                                return (($this->start !== '-inf') && (VNagValueUomPair::compare($value,$this->start) <  0)) ||
1856
                                       (($this->end   !== 'inf')  && (VNagValueUomPair::compare($value,$this->end)   >  0));
1856
                                       (($this->end   !== 'inf')  && (VNagValueUomPair::compare($value,$this->end)   >  0));
1857
                        }
1857
                        }
1858
                }
1858
                }
1859
 
1859
 
1860
                if ((count($values) > 0) and ($compatibleCount == 0)) {
1860
                if ((count($values) > 0) and ($compatibleCount == 0)) {
1861
                        throw new VNagNoCompatibleRangeUomFoundException(VNagLang::$no_compatible_range_uom_found);
1861
                        throw new VNagNoCompatibleRangeUomFoundException(VNagLang::$no_compatible_range_uom_found);
1862
                }
1862
                }
1863
 
1863
 
1864
                return false;
1864
                return false;
1865
        }
1865
        }
1866
}
1866
}
1867
 
1867
 
1868
class VNagValueUomPair {
1868
class VNagValueUomPair {
1869
        protected $value;
1869
        protected $value;
1870
        protected $uom;
1870
        protected $uom;
1871
        public $roundTo = -1;
1871
        public $roundTo = -1;
1872
 
1872
 
1873
        public function isRelative() {
1873
        public function isRelative() {
1874
                return $this->uom === '%';
1874
                return $this->uom === '%';
1875
        }
1875
        }
1876
 
1876
 
1877
        public function getValue() {
1877
        public function getValue() {
1878
                return $this->value;
1878
                return $this->value;
1879
        }
1879
        }
1880
 
1880
 
1881
        public function getUom() {
1881
        public function getUom() {
1882
                return $this->uom;
1882
                return $this->uom;
1883
        }
1883
        }
1884
 
1884
 
1885
        public function __toString() {
1885
        public function __toString() {
1886
                if ($this->roundTo == -1) {
1886
                if ($this->roundTo == -1) {
1887
                        return $this->value.$this->uom;
1887
                        return $this->value.$this->uom;
1888
                } else {
1888
                } else {
1889
                        return round($this->value,$this->roundTo).$this->uom;
1889
                        return round($this->value,$this->roundTo).$this->uom;
1890
                }
1890
                }
1891
        }
1891
        }
1892
 
1892
 
1893
        public function __construct($str) {
1893
        public function __construct($str) {
1894
                $m = array();
1894
                $m = array();
1895
                if (!preg_match('/^([\d\.]+)(.*)$/ism', $str, $m)) {
1895
                if (!preg_match('/^([\d\.]+)(.*)$/ism', $str, $m)) {
1896
                        throw new VNagValueUomPairSyntaxException($str);
1896
                        throw new VNagValueUomPairSyntaxException($str);
1897
                }
1897
                }
1898
                $this->value = $m[1];
1898
                $this->value = $m[1];
1899
                $this->uom = isset($m[2]) ? $m[2] : '';
1899
                $this->uom = isset($m[2]) ? $m[2] : '';
1900
 
1900
 
1901
                if (!self::isKnownUOM($this->uom)) {
1901
                if (!self::isKnownUOM($this->uom)) {
1902
                        throw new VNagUnknownUomException($this->uom);
1902
                        throw new VNagUnknownUomException($this->uom);
1903
                }
1903
                }
1904
        }
1904
        }
1905
 
1905
 
1906
        public static function isKnownUOM(string $uom) {
1906
        public static function isKnownUOM(string $uom) {
1907
                // see https://nagios-plugins.org/doc/guidelines.html#AEN200
1907
                // see https://nagios-plugins.org/doc/guidelines.html#AEN200
1908
                // 10. UOM (unit of measurement) is one of:
1908
                // 10. UOM (unit of measurement) is one of:
1909
 
1909
 
1910
                // no unit specified - assume a number (int or float) of things (eg, users, processes, load averages)
1910
                // no unit specified - assume a number (int or float) of things (eg, users, processes, load averages)
1911
                $no_unit = ($uom === '');
1911
                $no_unit = ($uom === '');
1912
                // s - seconds (also us, ms)
1912
                // s - seconds (also us, ms)
1913
                $seconds = ($uom === 's') || ($uom === 'ms') || ($uom === 'us');
1913
                $seconds = ($uom === 's') || ($uom === 'ms') || ($uom === 'us');
1914
                // % - percentage
1914
                // % - percentage
1915
                $percentage = ($uom === '%');
1915
                $percentage = ($uom === '%');
1916
                // B - bytes (also KB, MB, TB)
1916
                // B - bytes (also KB, MB, TB)
1917
                // NOTE: GB is not in the official development guidelines,probably due to an error, so I've added them anyway
1917
                // NOTE: GB is not in the official development guidelines,probably due to an error, so I've added them anyway
1918
                $bytes = ($uom === 'B') || ($uom === 'KB') || ($uom === 'MB') || ($uom === 'GB') || ($uom === 'TB');
1918
                $bytes = ($uom === 'B') || ($uom === 'KB') || ($uom === 'MB') || ($uom === 'GB') || ($uom === 'TB');
1919
                // c - a continous counter (such as bytes transmitted on an interface)
1919
                // c - a continous counter (such as bytes transmitted on an interface)
1920
                $counter = ($uom === 'c');
1920
                $counter = ($uom === 'c');
1921
 
1921
 
1922
                return ($no_unit || $seconds || $percentage || $bytes || $counter);
1922
                return ($no_unit || $seconds || $percentage || $bytes || $counter);
1923
        }
1923
        }
1924
 
1924
 
1925
        public function normalize($target=null) {
1925
        public function normalize($target=null) {
1926
                $res = clone $this;
1926
                $res = clone $this;
1927
 
1927
 
1928
                // The value is normalized to seconds or megabytes
1928
                // The value is normalized to seconds or megabytes
1929
                if ($res->uom === 'ms') {
1929
                if ($res->uom === 'ms') {
1930
                        $res->uom = 's';
1930
                        $res->uom = 's';
1931
                        $res->value /= 1000;
1931
                        $res->value /= 1000;
1932
                }
1932
                }
1933
                if ($res->uom === 'us') {
1933
                if ($res->uom === 'us') {
1934
                        $res->uom = 's';
1934
                        $res->uom = 's';
1935
                        $res->value /= 1000 * 1000;
1935
                        $res->value /= 1000 * 1000;
1936
                }
1936
                }
1937
                if ($res->uom === 'B') {
1937
                if ($res->uom === 'B') {
1938
                        $res->uom = 'MB';
1938
                        $res->uom = 'MB';
1939
                        $res->value /= 1024 * 1024;
1939
                        $res->value /= 1024 * 1024;
1940
                }
1940
                }
1941
                if ($res->uom === 'KB') {
1941
                if ($res->uom === 'KB') {
1942
                        $res->uom = 'MB';
1942
                        $res->uom = 'MB';
1943
                        $res->value /= 1024;
1943
                        $res->value /= 1024;
1944
                }
1944
                }
1945
                if ($res->uom === 'GB') {
1945
                if ($res->uom === 'GB') {
1946
                        $res->uom = 'MB';
1946
                        $res->uom = 'MB';
1947
                        $res->value *= 1024;
1947
                        $res->value *= 1024;
1948
                }
1948
                }
1949
                if ($res->uom === 'TB') {
1949
                if ($res->uom === 'TB') {
1950
                        $res->uom = 'MB';
1950
                        $res->uom = 'MB';
1951
                        $res->value *= 1024 * 1024;
1951
                        $res->value *= 1024 * 1024;
1952
                }
1952
                }
1953
                if ($res->uom === 'c') {
1953
                if ($res->uom === 'c') {
1954
                        $res->uom = '';
1954
                        $res->uom = '';
1955
                }
1955
                }
1956
 
1956
 
1957
                // Now, if the user wishes, convert to another unit
1957
                // Now, if the user wishes, convert to another unit
1958
                if (!is_null($target)) {
1958
                if (!is_null($target)) {
1959
                        if ($res->uom == 'MB') {
1959
                        if ($res->uom == 'MB') {
1960
                                if ($target == 'B') {
1960
                                if ($target == 'B') {
1961
                                        $res->uom = 'B';
1961
                                        $res->uom = 'B';
1962
                                        $res->value *= 1024 * 1024;
1962
                                        $res->value *= 1024 * 1024;
1963
                                } else if ($target == 'KB') {
1963
                                } else if ($target == 'KB') {
1964
                                        $res->uom = 'KB';
1964
                                        $res->uom = 'KB';
1965
                                        $res->value *= 1024;
1965
                                        $res->value *= 1024;
1966
                                } else if ($target == 'MB') {
1966
                                } else if ($target == 'MB') {
1967
                                        $res->uom = 'MB';
1967
                                        $res->uom = 'MB';
1968
                                        $res->value *= 1;
1968
                                        $res->value *= 1;
1969
                                } else if ($target == 'GB') {
1969
                                } else if ($target == 'GB') {
1970
                                        $res->uom = 'GB';
1970
                                        $res->uom = 'GB';
1971
                                        $res->value /= 1024;
1971
                                        $res->value /= 1024;
1972
                                } else if ($target == 'TB') {
1972
                                } else if ($target == 'TB') {
1973
                                        $res->uom = 'TB';
1973
                                        $res->uom = 'TB';
1974
                                        $res->value /= 1024 * 1024;
1974
                                        $res->value /= 1024 * 1024;
1975
                                } else {
1975
                                } else {
1976
                                        throw new VNagUomConvertException($res->uom, $target);
1976
                                        throw new VNagUomConvertException($res->uom, $target);
1977
                                }
1977
                                }
1978
                        } else if ($res->uom == 's') {
1978
                        } else if ($res->uom == 's') {
1979
                                if ($target == 's') {
1979
                                if ($target == 's') {
1980
                                        $res->uom = 's';
1980
                                        $res->uom = 's';
1981
                                        $res->value /= 1;
1981
                                        $res->value /= 1;
1982
                                } else if ($target == 'ms') {
1982
                                } else if ($target == 'ms') {
1983
                                        $res->uom = 'ms';
1983
                                        $res->uom = 'ms';
1984
                                        $res->value /= 1000;
1984
                                        $res->value /= 1000;
1985
                                } else if ($target == 'us') {
1985
                                } else if ($target == 'us') {
1986
                                        $res->uom = 'us';
1986
                                        $res->uom = 'us';
1987
                                        $res->value /= 1000 * 1000;
1987
                                        $res->value /= 1000 * 1000;
1988
                                } else {
1988
                                } else {
1989
                                        throw new VNagUomConvertException($res->uom, $target);
1989
                                        throw new VNagUomConvertException($res->uom, $target);
1990
                                }
1990
                                }
1991
                        } else {
1991
                        } else {
1992
                                throw new VNagUomConvertException($res->uom, $target);
1992
                                throw new VNagUomConvertException($res->uom, $target);
1993
                        }
1993
                        }
1994
                }
1994
                }
1995
 
1995
 
1996
                return $res;
1996
                return $res;
1997
        }
1997
        }
1998
 
1998
 
1999
        public function compatibleWith(VNagValueUomPair $other) {
1999
        public function compatibleWith(VNagValueUomPair $other) {
2000
                $a = $this->normalize();
2000
                $a = $this->normalize();
2001
                $b = $other->normalize();
2001
                $b = $other->normalize();
2002
 
2002
 
2003
                return ($a->uom == $b->uom);
2003
                return ($a->uom == $b->uom);
2004
        }
2004
        }
2005
 
2005
 
2006
        public static function compare(VNagValueUomPair $left, VNagValueUomPair $right) {
2006
        public static function compare(VNagValueUomPair $left, VNagValueUomPair $right) {
2007
                $a = $left->normalize();
2007
                $a = $left->normalize();
2008
                $b = $right->normalize();
2008
                $b = $right->normalize();
2009
 
2009
 
2010
                // FUT: Also accept mixed UOMs, e.g. MB and %
2010
                // FUT: Also accept mixed UOMs, e.g. MB and %
2011
                //      To translate between an absolute and a relative value, the
2011
                //      To translate between an absolute and a relative value, the
2012
                //      reference value (100%=?) needs to be passed through this comparison
2012
                //      reference value (100%=?) needs to be passed through this comparison
2013
                //      function somehow.
2013
                //      function somehow.
2014
                if ($a->uom != $b->uom) throw new VNagMixedUomsNotImplemented($a->uom, $b->uom);
2014
                if ($a->uom != $b->uom) throw new VNagMixedUomsNotImplemented($a->uom, $b->uom);
2015
 
2015
 
2016
                if ($a->value  > $b->value) return  1;
2016
                if ($a->value  > $b->value) return  1;
2017
                if ($a->value == $b->value) return  0;
2017
                if ($a->value == $b->value) return  0;
2018
                if ($a->value  < $b->value) return -1;
2018
                if ($a->value  < $b->value) return -1;
2019
        }
2019
        }
2020
}
2020
}
2021
 
2021
 
2022
class VNagPerformanceData {
2022
class VNagPerformanceData {
2023
        // see https://nagios-plugins.org/doc/guidelines.html#AEN200
2023
        // see https://nagios-plugins.org/doc/guidelines.html#AEN200
2024
        //     https://www.icinga.com/docs/icinga1/latest/en/perfdata.html#formatperfdata
2024
        //     https://www.icinga.com/docs/icinga1/latest/en/perfdata.html#formatperfdata
2025
 
2025
 
2026
        protected $label;
2026
        protected $label;
2027
        protected /*VNagValueUomPair*/ $value;
2027
        protected /*VNagValueUomPair*/ $value;
2028
        protected $warn = null;
2028
        protected $warn = null;
2029
        protected $crit = null;
2029
        protected $crit = null;
2030
        protected $min = null;
2030
        protected $min = null;
2031
        protected $max = null;
2031
        protected $max = null;
2032
 
2032
 
2033
        public static function createByString($perfdata) {
2033
        public static function createByString($perfdata) {
2034
                $perfdata = trim($perfdata);
2034
                $perfdata = trim($perfdata);
2035
 
2035
 
2036
                $ary = explode('=',$perfdata);
2036
                $ary = explode('=',$perfdata);
2037
                if (count($ary) != 2) {
2037
                if (count($ary) != 2) {
2038
                        throw new VNagInvalidPerformanceDataException(sprintf(VNagLang::$perfdata_line_invalid, $perfdata));
2038
                        throw new VNagInvalidPerformanceDataException(sprintf(VNagLang::$perfdata_line_invalid, $perfdata));
2039
                }
2039
                }
2040
                $label = $ary[0];
2040
                $label = $ary[0];
2041
                $bry = explode(';',$ary[1]);
2041
                $bry = explode(';',$ary[1]);
2042
                if (substr($label,0,1) === "'") $label = substr($label, 1, strlen($label)-2);
2042
                if (substr($label,0,1) === "'") $label = substr($label, 1, strlen($label)-2);
2043
                $value = $bry[0];
2043
                $value = $bry[0];
2044
                $warn  = isset($bry[1]) ? $bry[1] : null;
2044
                $warn  = isset($bry[1]) ? $bry[1] : null;
2045
                $crit  = isset($bry[2]) ? $bry[2] : null;
2045
                $crit  = isset($bry[2]) ? $bry[2] : null;
2046
                $min   = isset($bry[3]) ? $bry[3] : null;
2046
                $min   = isset($bry[3]) ? $bry[3] : null;
2047
                $max   = isset($bry[4]) ? $bry[4] : null;
2047
                $max   = isset($bry[4]) ? $bry[4] : null;
2048
 
2048
 
2049
                // Guideline "7. min and max are not required if UOM=%" makes no sense, because
2049
                // Guideline "7. min and max are not required if UOM=%" makes no sense, because
2050
                // actually, all fields (except label and value) are optional.
2050
                // actually, all fields (except label and value) are optional.
2051
 
2051
 
2052
                return new self($label, $value, $warn, $crit, $min, $max);
2052
                return new self($label, $value, $warn, $crit, $min, $max);
2053
        }
2053
        }
2054
 
2054
 
2055
        public function __construct($label, $value/*may include UOM*/, $warn=null, $crit=null, $min=null, $max=null) {
2055
        public function __construct($label, $value/*may include UOM*/, $warn=null, $crit=null, $min=null, $max=null) {
2056
                // Not checked / Nothing to check:
2056
                // Not checked / Nothing to check:
2057
                // - 4. label length is arbitrary, but ideally the first 19 characters are unique (due to a limitation in RRD). Be aware of a limitation in the amount of data that NRPE returns to Nagios
2057
                // - 4. label length is arbitrary, but ideally the first 19 characters are unique (due to a limitation in RRD). Be aware of a limitation in the amount of data that NRPE returns to Nagios
2058
                // - 6. warn, crit, min or max may be null (for example, if the threshold is not defined or min and max do not apply). Trailing unfilled semicolons can be dropped
2058
                // - 6. warn, crit, min or max may be null (for example, if the threshold is not defined or min and max do not apply). Trailing unfilled semicolons can be dropped
2059
                // - 9. warn and crit are in the range format (see the Section called Threshold and ranges). Must be the same UOM
2059
                // - 9. warn and crit are in the range format (see the Section called Threshold and ranges). Must be the same UOM
2060
                // - 7. min and max are not required if UOM=%
2060
                // - 7. min and max are not required if UOM=%
2061
 
2061
 
2062
                // 2. label can contain any characters except the equals sign or single quote (')
2062
                // 2. label can contain any characters except the equals sign or single quote (')
2063
                if (strpos($label, '=') !== false) throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_label_equal_sign_forbidden);
2063
                if (strpos($label, '=') !== false) throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_label_equal_sign_forbidden);
2064
 
2064
 
2065
                // 5. to specify a quote character, use two single quotes
2065
                // 5. to specify a quote character, use two single quotes
2066
                $label = str_replace("'", "''", $label);
2066
                $label = str_replace("'", "''", $label);
2067
 
2067
 
2068
                // 8. value, min and max in class [-0-9.]. Must all be the same UOM.
2068
                // 8. value, min and max in class [-0-9.]. Must all be the same UOM.
2069
                //    value may be a literal "U" instead, this would indicate that the actual value couldn't be determined
2069
                //    value may be a literal "U" instead, this would indicate that the actual value couldn't be determined
2070
                /*
2070
                /*
2071
                if (($value != 'U') && (!preg_match('|^[-0-9\\.]+$|', $value, $m))) {
2071
                if (($value != 'U') && (!preg_match('|^[-0-9\\.]+$|', $value, $m))) {
2072
                        throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_value_must_be_in_class);
2072
                        throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_value_must_be_in_class);
2073
                }
2073
                }
2074
                */
2074
                */
2075
                $m = array();
2075
                $m = array();
2076
                if ((!_empty($min)) && (!preg_match('|^[-0-9\\.]+$|', $min, $m))) {
2076
                if ((!_empty($min)) && (!preg_match('|^[-0-9\\.]+$|', $min, $m))) {
2077
                        throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_min_must_be_in_class);
2077
                        throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_min_must_be_in_class);
2078
                }
2078
                }
2079
                if ((!_empty($max)) && (!preg_match('|^[-0-9\\.]+$|', $max, $m))) {
2079
                if ((!_empty($max)) && (!preg_match('|^[-0-9\\.]+$|', $max, $m))) {
2080
                        throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_max_must_be_in_class);
2080
                        throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_max_must_be_in_class);
2081
                }
2081
                }
2082
 
2082
 
2083
                // 10. UOM (unit of measurement) is one of ....
2083
                // 10. UOM (unit of measurement) is one of ....
2084
                //     => This rule is checked in the VNagValueUomPair constructor.
2084
                //     => This rule is checked in the VNagValueUomPair constructor.
2085
 
2085
 
2086
                $this->label = $label;
2086
                $this->label = $label;
2087
                $this->value = ($value == 'U') ? 'U' : new VNagValueUomPair($value);
2087
                $this->value = ($value == 'U') ? 'U' : new VNagValueUomPair($value);
2088
                $this->warn  = $warn;
2088
                $this->warn  = $warn;
2089
                $this->crit  = $crit;
2089
                $this->crit  = $crit;
2090
                $this->min   = $min;
2090
                $this->min   = $min;
2091
                $this->max   = $max;
2091
                $this->max   = $max;
2092
        }
2092
        }
2093
 
2093
 
2094
        public function __toString() {
2094
        public function __toString() {
2095
                $label = $this->label;
2095
                $label = $this->label;
2096
                $value = $this->value;
2096
                $value = $this->value;
2097
                $warn  = $this->warn;
2097
                $warn  = $this->warn;
2098
                $crit  = $this->crit;
2098
                $crit  = $this->crit;
2099
                $min   = $this->min;
2099
                $min   = $this->min;
2100
                $max   = $this->max;
2100
                $max   = $this->max;
2101
 
2101
 
2102
                // 5. to specify a quote character, use two single quotes
2102
                // 5. to specify a quote character, use two single quotes
2103
                $label = str_replace("''", "'", $label);
2103
                $label = str_replace("''", "'", $label);
2104
 
2104
 
2105
                // 'label'=value[UOM];[warn];[crit];[min];[max]
2105
                // 'label'=value[UOM];[warn];[crit];[min];[max]
2106
                // 3. the single quotes for the label are optional. Required if spaces are in the label
2106
                // 3. the single quotes for the label are optional. Required if spaces are in the label
2107
                return "'$label'=$value".
2107
                return "'$label'=$value".
2108
                       ';'.(is_null($warn) ? '' : $warn).
2108
                       ';'.(is_null($warn) ? '' : $warn).
2109
                       ';'.(is_null($crit) ? '' : $crit).
2109
                       ';'.(is_null($crit) ? '' : $crit).
2110
                       ';'.(is_null($min)  ? '' : $min).
2110
                       ';'.(is_null($min)  ? '' : $min).
2111
                       ';'.(is_null($max)  ? '' : $max);
2111
                       ';'.(is_null($max)  ? '' : $max);
2112
        }
2112
        }
2113
}
2113
}
2114
 
2114
 
2115
class VNagHelp {
2115
class VNagHelp {
2116
        public $word_wrap_width = 80; // -1 = disable
2116
        public $word_wrap_width = 80; // -1 = disable
2117
        public $argument_indent = 7;
2117
        public $argument_indent = 7;
2118
 
2118
 
2119
        public function printUsagePage() {
2119
        public function printUsagePage() {
2120
                $usage = $this->getUsage();
2120
                $usage = $this->getUsage();
2121
 
2121
 
2122
                if (_empty($usage)) {
2122
                if (_empty($usage)) {
2123
                        $usage = VNagLang::$no_syntax_defined;
2123
                        $usage = VNagLang::$no_syntax_defined;
2124
                }
2124
                }
2125
 
2125
 
2126
                return trim($usage)."\n";
2126
                return trim($usage)."\n";
2127
        }
2127
        }
2128
 
2128
 
2129
        public function printVersionPage() {
2129
        public function printVersionPage() {
2130
                $out = trim($this->getNameAndVersion())."\n";
2130
                $out = trim($this->getNameAndVersion())."\n";
2131
 
2131
 
2132
                if ($this->word_wrap_width > 0) $out = wordwrap($out, $this->word_wrap_width, "\n", false);
2132
                if ($this->word_wrap_width > 0) $out = wordwrap($out, $this->word_wrap_width, "\n", false);
2133
 
2133
 
2134
                return $out;
2134
                return $out;
2135
        }
2135
        }
2136
 
2136
 
2137
        static private function _conditionalLine($line, $terminator='', $prefix='') {
2137
        static private function _conditionalLine($line, $terminator='', $prefix='') {
2138
                if (!_empty($line)) {
2138
                if (!_empty($line)) {
2139
                        return trim($line).$terminator;
2139
                        return trim($line).$terminator;
2140
                }
2140
                }
2141
                return '';
2141
                return '';
2142
        }
2142
        }
2143
 
2143
 
2144
        public function printHelpPage() {
2144
        public function printHelpPage() {
2145
                $out  = '';
2145
                $out  = '';
2146
                $out .= self::_conditionalLine($this->getNameAndVersion(), "\n");
2146
                $out .= self::_conditionalLine($this->getNameAndVersion(), "\n");
2147
                $out .= self::_conditionalLine($this->getCopyright(), "\n");
2147
                $out .= self::_conditionalLine($this->getCopyright(), "\n");
2148
                $out .= ($out != '') ? "\n" : '';
2148
                $out .= ($out != '') ? "\n" : '';
2149
                $out .= self::_conditionalLine($this->getShortDescription(), "\n\n\n");
2149
                $out .= self::_conditionalLine($this->getShortDescription(), "\n\n\n");
2150
                $out .= self::_conditionalLine($this->getUsage(), "\n\n");
2150
                $out .= self::_conditionalLine($this->getUsage(), "\n\n");
2151
 
2151
 
2152
                $out .= VNagLang::$options."\n";
2152
                $out .= VNagLang::$options."\n";
2153
                foreach ($this->options as $argObj) {
2153
                foreach ($this->options as $argObj) {
2154
                        $out .= $this->printArgumentHelp($argObj);
2154
                        $out .= $this->printArgumentHelp($argObj);
2155
                }
2155
                }
2156
 
2156
 
2157
                $out .= self::_conditionalLine($this->getFootNotes(), "\n\n", "\n");
2157
                $out .= self::_conditionalLine($this->getFootNotes(), "\n\n", "\n");
2158
 
2158
 
2159
                if ($this->word_wrap_width > 0) $out = wordwrap($out, $this->word_wrap_width, "\n", false);
2159
                if ($this->word_wrap_width > 0) $out = wordwrap($out, $this->word_wrap_width, "\n", false);
2160
 
2160
 
2161
                return $out;
2161
                return $out;
2162
        }
2162
        }
2163
 
2163
 
2164
        protected /* VNagArgument[] */ $options = array();
2164
        protected /* VNagArgument[] */ $options = array();
2165
 
2165
 
2166
        // Will be called by VNag via ReflectionMethod (like C++ style friends), because it should not be called manually.
2166
        // Will be called by VNag via ReflectionMethod (like C++ style friends), because it should not be called manually.
2167
        // Use VNag's function instead (since it adds to the argHandler too)
2167
        // Use VNag's function instead (since it adds to the argHandler too)
2168
        protected function _addOption($argObj) {
2168
        protected function _addOption($argObj) {
2169
                $this->options[] = $argObj;
2169
                $this->options[] = $argObj;
2170
        }
2170
        }
2171
 
2171
 
2172
        # FUT: Automatic creation of usage page. Which arguments are necessary?
2172
        # FUT: Automatic creation of usage page. Which arguments are necessary?
2173
        protected function printArgumentHelp($argObj) {
2173
        protected function printArgumentHelp($argObj) {
2174
                $identifiers = array();
2174
                $identifiers = array();
2175
 
2175
 
2176
                $shortopt = $argObj->getShortopt();
2176
                $shortopt = $argObj->getShortopt();
2177
                if (!_empty($shortopt)) $identifiers[] = '-'.$shortopt;
2177
                if (!_empty($shortopt)) $identifiers[] = '-'.$shortopt;
2178
 
2178
 
2179
                $longopts = $argObj->getLongopts();
2179
                $longopts = $argObj->getLongopts();
2180
                if (!is_null($longopts)) {
2180
                if (!is_null($longopts)) {
2181
                        foreach ($longopts as $longopt) {
2181
                        foreach ($longopts as $longopt) {
2182
                                if (!_empty($longopt)) $identifiers[] = '--'.$longopt;
2182
                                if (!_empty($longopt)) $identifiers[] = '--'.$longopt;
2183
                        }
2183
                        }
2184
                }
2184
                }
2185
 
2185
 
2186
                if (count($identifiers) == 0) return;
2186
                if (count($identifiers) == 0) return;
2187
 
2187
 
2188
                $valueName = $argObj->getValueName();
2188
                $valueName = $argObj->getValueName();
2189
 
2189
 
2190
                $arginfo = '';
2190
                $arginfo = '';
2191
                switch ($argObj->getValuePolicy()) {
2191
                switch ($argObj->getValuePolicy()) {
2192
                        case VNagArgument::VALUE_FORBIDDEN:
2192
                        case VNagArgument::VALUE_FORBIDDEN:
2193
                                $arginfo = '';
2193
                                $arginfo = '';
2194
                                break;
2194
                                break;
2195
                        case VNagArgument::VALUE_REQUIRED:
2195
                        case VNagArgument::VALUE_REQUIRED:
2196
                                $arginfo = '='.$valueName;
2196
                                $arginfo = '='.$valueName;
2197
                                break;
2197
                                break;
2198
                        case VNagArgument::VALUE_OPTIONAL:
2198
                        case VNagArgument::VALUE_OPTIONAL:
2199
                                $arginfo = '[='.$valueName.']';
2199
                                $arginfo = '[='.$valueName.']';
2200
                                break;
2200
                                break;
2201
                }
2201
                }
2202
 
2202
 
2203
                $out = '';
2203
                $out = '';
2204
                $out .= implode(', ', $identifiers).$arginfo."\n";
2204
                $out .= implode(', ', $identifiers).$arginfo."\n";
2205
 
2205
 
2206
                // https://nagios-plugins.org/doc/guidelines.html#AEN302 recommends supporting a 80x23 screen resolution.
2206
                // https://nagios-plugins.org/doc/guidelines.html#AEN302 recommends supporting a 80x23 screen resolution.
2207
                // While we cannot guarantee the vertical height, we can limit the width at least...
2207
                // While we cannot guarantee the vertical height, we can limit the width at least...
2208
 
2208
 
2209
                $content = trim($argObj->getHelpText());
2209
                $content = trim($argObj->getHelpText());
2210
                if ($this->word_wrap_width > 0) $content = wordwrap($content, $this->word_wrap_width-$this->argument_indent, "\n", false);
2210
                if ($this->word_wrap_width > 0) $content = wordwrap($content, $this->word_wrap_width-$this->argument_indent, "\n", false);
2211
                $lines = explode("\n", $content);
2211
                $lines = explode("\n", $content);
2212
 
2212
 
2213
                foreach ($lines as $line) {
2213
                foreach ($lines as $line) {
2214
                        $out .= str_repeat(' ', $this->argument_indent).$line."\n";
2214
                        $out .= str_repeat(' ', $this->argument_indent).$line."\n";
2215
                }
2215
                }
2216
                $out .= "\n";
2216
                $out .= "\n";
2217
 
2217
 
2218
                return $out;
2218
                return $out;
2219
        }
2219
        }
2220
 
2220
 
2221
        // $pluginName should contain the name of the plugin, without version.
2221
        // $pluginName should contain the name of the plugin, without version.
2222
        protected $pluginName;
2222
        protected $pluginName;
2223
        public function setPluginName($pluginName) {
2223
        public function setPluginName($pluginName) {
2224
                $this->pluginName = $this->replaceStuff($pluginName);
2224
                $this->pluginName = $this->replaceStuff($pluginName);
2225
        }
2225
        }
2226
        public function getPluginName() {
2226
        public function getPluginName() {
2227
                if (_empty($this->pluginName)) {
2227
                if (_empty($this->pluginName)) {
2228
                        global $argv;
2228
                        global $argv;
2229
                        return basename($argv[0]);
2229
                        return basename($argv[0]);
2230
                } else {
2230
                } else {
2231
                        return $this->pluginName;
2231
                        return $this->pluginName;
2232
                }
2232
                }
2233
        }
2233
        }
2234
 
2234
 
2235
        private static function isCertified($file) {
2235
        private static function isCertified($file) {
2236
                $cont = file_get_contents($file);
2236
                $cont = file_get_contents($file);
2237
 
2237
 
2238
                $regex = '@<\?php /\* <ViaThinkSoftSignature>(.+)</ViaThinkSoftSignature> \*/ \?>\n@ismU';
2238
                $regex = '@<\?php /\* <ViaThinkSoftSignature>(.+)</ViaThinkSoftSignature> \*/ \?>\n@ismU';
2239
 
2239
 
2240
                $m = array();
2240
                $m = array();
2241
                if (!preg_match($regex, $cont, $m)) {
2241
                if (!preg_match($regex, $cont, $m)) {
2242
                        return false;
2242
                        return false;
2243
                }
2243
                }
2244
                $signature = base64_decode($m[1]);
2244
                $signature = base64_decode($m[1]);
2245
 
2245
 
2246
                $naked = preg_replace($regex, '', $cont);
2246
                $naked = preg_replace($regex, '', $cont);
2247
                $hash = hash("sha256", $naked.basename($file));
2247
                $hash = hash("sha256", $naked.basename($file));
2248
 
2248
 
2249
                $public_key = <<<'VTSKEY'
2249
                $public_key = <<<'VTSKEY'
2250
-----BEGIN PUBLIC KEY-----
2250
-----BEGIN PUBLIC KEY-----
2251
MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEA4UEmad2KHWzfGLcAzbOD
2251
MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEA4UEmad2KHWzfGLcAzbOD
2252
IhqWyoPA1Cg4zN5YK/CWUiE7sh2CNinIwYqGnIOhZLp54/Iyv3H05QeWJU7kD+jQ
2252
IhqWyoPA1Cg4zN5YK/CWUiE7sh2CNinIwYqGnIOhZLp54/Iyv3H05QeWJU7kD+jQ
2253
5JwR8+pqk8ZGBfqlxXUBJ2bZhYIBJZYfilSROa7jgPPrrw0CjdGLmM3wmc8ztQRv
2253
5JwR8+pqk8ZGBfqlxXUBJ2bZhYIBJZYfilSROa7jgPPrrw0CjdGLmM3wmc8ztQRv
2254
4GpP7MaKVyVOsRz5xEcpzghWZ+Cl8Nxq1Vo02RkMYOOPA16abxZ65lVM8Vv2EKGf
2254
4GpP7MaKVyVOsRz5xEcpzghWZ+Cl8Nxq1Vo02RkMYOOPA16abxZ65lVM8Vv2EKGf
2255
/VAVViTFvLWPxggvt1fbJJniC0cwt8gjzFXt6IJJSRlqc1lOO9ZIa/EWDKuHKQ1n
2255
/VAVViTFvLWPxggvt1fbJJniC0cwt8gjzFXt6IJJSRlqc1lOO9ZIa/EWDKuHKQ1n
2256
ENQCqnuVPFDZU3lU20Z+6+EA0YngcvNYi3ucdIvgBd4Yv5FetzuxiOZUoDRfh/3R
2256
ENQCqnuVPFDZU3lU20Z+6+EA0YngcvNYi3ucdIvgBd4Yv5FetzuxiOZUoDRfh/3R
2257
6dCJ8CvRiq0BSZcynTIWNmF3AVsH7vjxZe8kMDbwZNnR0suZ5MfBh6L/s1lCEWlS
2257
6dCJ8CvRiq0BSZcynTIWNmF3AVsH7vjxZe8kMDbwZNnR0suZ5MfBh6L/s1lCEWlS
2258
GwmCLc3MnOLxq3JLnfmbVa509YxlUamdSswnvzes28AjnzQ3LQchspP2a8bSXH6/
2258
GwmCLc3MnOLxq3JLnfmbVa509YxlUamdSswnvzes28AjnzQ3LQchspP2a8bSXH6/
2259
qpbwvmV5WiNgwJck04VhaXrRRy3XFSwuk7KU/L4aqadXP26kgDqIYNvPXSa9JyGc
2259
qpbwvmV5WiNgwJck04VhaXrRRy3XFSwuk7KU/L4aqadXP26kgDqIYNvPXSa9JyGc
2260
14zwdmAtn36o8vpXM/A7GhdWqgPLlJbdTdK6IfwpBs8P/JB6y3t6RzAGiEOITdj9
2260
14zwdmAtn36o8vpXM/A7GhdWqgPLlJbdTdK6IfwpBs8P/JB6y3t6RzAGiEOITdj9
2261
QUhW+sAoKno0j4WT7s80vWNWz37WoFJcvVLnVEYitnW6DqM+GOt2od3g6WgI6dOa
2261
QUhW+sAoKno0j4WT7s80vWNWz37WoFJcvVLnVEYitnW6DqM+GOt2od3g6WgI6dOa
2262
MESA4J44Y4x1gXBw/M6F/ZngP4EJoAUG0GbzsaZ6HKLt4pDTZmw8PnNcXrOMYkr/
2262
MESA4J44Y4x1gXBw/M6F/ZngP4EJoAUG0GbzsaZ6HKLt4pDTZmw8PnNcXrOMYkr/
2263
N5EliTXil45DCaLkgNJmpdXjNpIvShW4ogq2osw+SQUalnAbW8ddiaOVCdgXkDFq
2263
N5EliTXil45DCaLkgNJmpdXjNpIvShW4ogq2osw+SQUalnAbW8ddiaOVCdgXkDFq
2264
gvnl5QSeUrKPF5v+vlnwWar6Rp7iInQpnA+PTSbAlO3Dd9WqbWx+uNoI/kXUlN0O
2264
gvnl5QSeUrKPF5v+vlnwWar6Rp7iInQpnA+PTSbAlO3Dd9WqbWx+uNoI/kXUlN0O
2265
a/vi5Uwat2Bz3N+jIpnBqg4+O+SG0z3UCVmT6Leg+kqO/rXbzoVv/DV7E30vTqdo
2265
a/vi5Uwat2Bz3N+jIpnBqg4+O+SG0z3UCVmT6Leg+kqO/rXbzoVv/DV7E30vTqdo
2266
wsswdJEM1BI7Wyid6HPwBek+rdv77gUg3W37vUcdfKxsYRcoHriXLHpmENznJcEx
2266
wsswdJEM1BI7Wyid6HPwBek+rdv77gUg3W37vUcdfKxsYRcoHriXLHpmENznJcEx
2267
/nvilw6To1zx2LKmM/p56MQriKkXnqoOBpkpn3PaWyXZKY9xJNTAbcSP3haE7z9p
2267
/nvilw6To1zx2LKmM/p56MQriKkXnqoOBpkpn3PaWyXZKY9xJNTAbcSP3haE7z9p
2268
PzJw88KI8dnYuFg4yS/AgmVGAUtu3bhDG4qF9URu2ck868zViH996lraYkmFIWJG
2268
PzJw88KI8dnYuFg4yS/AgmVGAUtu3bhDG4qF9URu2ck868zViH996lraYkmFIWJG
2269
r7h1LImhrwDEJvb/rOW8QvOZBX9H6pcSKs/LQbeoy6HMIOTlny+S15xtiS4t6Ayv
2269
r7h1LImhrwDEJvb/rOW8QvOZBX9H6pcSKs/LQbeoy6HMIOTlny+S15xtiS4t6Ayv
2270
3m0ry5c0qkl/mgKvGpeRnNlrcr6mb2fzxxGvcuBzi25wgIbRLPgJoqsmeBvW1OLU
2270
3m0ry5c0qkl/mgKvGpeRnNlrcr6mb2fzxxGvcuBzi25wgIbRLPgJoqsmeBvW1OLU
2271
+9DpkNvitEJnPRo86v0VF86aou12Sm8Wb4mtrQ7h3qLIYvw2LN2mYh4WlgrSwPpx
2271
+9DpkNvitEJnPRo86v0VF86aou12Sm8Wb4mtrQ7h3qLIYvw2LN2mYh4WlgrSwPpx
2272
YvE2+vWapilnnDWoiu2ZmDWa7WW/ihqvX9fmp/qzxQvJmBYIN8dFpgcNLqSx526N
2272
YvE2+vWapilnnDWoiu2ZmDWa7WW/ihqvX9fmp/qzxQvJmBYIN8dFpgcNLqSx526N
2273
bwIDAQAB
2273
bwIDAQAB
2274
-----END PUBLIC KEY-----
2274
-----END PUBLIC KEY-----
2275
VTSKEY;
2275
VTSKEY;
2276
 
2276
 
2277
                if (!function_exists('openssl_verify')) return null;
2277
                if (!function_exists('openssl_verify')) return null;
2278
 
2278
 
2279
                if (!openssl_verify($hash, $signature, $public_key, OPENSSL_ALGO_SHA256)) {
2279
                if (!openssl_verify($hash, $signature, $public_key, OPENSSL_ALGO_SHA256)) {
2280
                        return false;
2280
                        return false;
2281
                }
2281
                }
2282
 
2282
 
2283
                return true;
2283
                return true;
2284
        }
2284
        }
2285
 
2285
 
2286
        // $version should contain the version, not the program name or copyright.
2286
        // $version should contain the version, not the program name or copyright.
2287
        protected $version;
2287
        protected $version;
2288
        public function setVersion($version) {
2288
        public function setVersion($version) {
2289
                $this->version = $this->replaceStuff($version);
2289
                $this->version = $this->replaceStuff($version);
2290
        }
2290
        }
2291
        public function getVersion() {
2291
        public function getVersion() {
2292
                return $this->version;
2292
                return $this->version;
2293
        }
2293
        }
2294
        public function getNameAndVersion() {
2294
        public function getNameAndVersion() {
2295
                $ret = $this->getPluginName();
2295
                $ret = $this->getPluginName();
2296
                if (_empty($ret)) return null;
2296
                if (_empty($ret)) return null;
2297
 
2297
 
2298
                $ver = $this->getVersion();
2298
                $ver = $this->getVersion();
2299
                if (!_empty($ver)) {
2299
                if (!_empty($ver)) {
2300
                        $ret = sprintf(VNagLang::$x_version_x, $ret, $ver);
2300
                        $ret = sprintf(VNagLang::$x_version_x, $ret, $ver);
2301
                }
2301
                }
2302
                $ret = trim($ret);
2302
                $ret = trim($ret);
2303
 
2303
 
2304
                $certified = true;
2304
                $certified = true;
2305
                foreach (get_included_files() as $file) {
2305
                foreach (get_included_files() as $file) {
2306
                        $certified &= self::isCertified($file);
2306
                        $certified &= self::isCertified($file);
2307
                }
2307
                }
2308
                if ($certified) {
2308
                if ($certified) {
2309
                        $ret .= ' (' . VNagLang::$certified . ')';
2309
                        $ret .= ' (' . VNagLang::$certified . ')';
2310
                }
2310
                }
2311
 
2311
 
2312
                return $ret;
2312
                return $ret;
2313
        }
2313
        }
2314
 
2314
 
2315
        // $copyright should contain the copyright only, no program name or version.
2315
        // $copyright should contain the copyright only, no program name or version.
2316
        // $CURYEAR$ will be replaced by the current year
2316
        // $CURYEAR$ will be replaced by the current year
2317
        protected $copyright;
2317
        protected $copyright;
2318
        public function setCopyright($copyright) {
2318
        public function setCopyright($copyright) {
2319
                $this->copyright = $this->replaceStuff($copyright);
2319
                $this->copyright = $this->replaceStuff($copyright);
2320
        }
2320
        }
2321
 
2321
 
2322
        private function getVNagCopyright() {
2322
        private function getVNagCopyright() {
2323
                if (VNag::is_http_mode()) {
2323
                if (VNag::is_http_mode()) {
2324
                        $vts_email = 'www.viathinksoft.com'; // don't publish email address at web services because of spam bots
2324
                        $vts_email = 'www.viathinksoft.com'; // don't publish email address at web services because of spam bots
2325
                } else {
2325
                } else {
2326
                        $vts_email = base64_decode('aW5mb0B2aWF0aGlua3NvZnQuZGU='); // protect email address from spambots which might parse this code
2326
                        $vts_email = base64_decode('aW5mb0B2aWF0aGlua3NvZnQuZGU='); // protect email address from spambots which might parse this code
2327
                }
2327
                }
2328
                return "VNag Framework ".VNag::VNAG_VERSION." (C) 2014-".date('Y')." ViaThinkSoft <$vts_email>";
2328
                return "VNag Framework ".VNag::VNAG_VERSION." (C) 2014-".date('Y')." ViaThinkSoft <$vts_email>";
2329
        }
2329
        }
2330
 
2330
 
2331
        public function getCopyright() {
2331
        public function getCopyright() {
2332
                if (_empty($this->copyright)) {
2332
                if (_empty($this->copyright)) {
2333
                        return sprintf(VNagLang::$plugin_uses, $this->getVNagCopyright());
2333
                        return sprintf(VNagLang::$plugin_uses, $this->getVNagCopyright());
2334
                } else {
2334
                } else {
2335
                        return trim($this->copyright)."\n".sprintf(VNagLang::$uses, $this->getVNagCopyright());
2335
                        return trim($this->copyright)."\n".sprintf(VNagLang::$uses, $this->getVNagCopyright());
2336
                }
2336
                }
2337
        }
2337
        }
2338
 
2338
 
2339
        // $shortDescription should describe what this plugin does.
2339
        // $shortDescription should describe what this plugin does.
2340
        protected $shortDescription;
2340
        protected $shortDescription;
2341
        public function setShortDescription($shortDescription) {
2341
        public function setShortDescription($shortDescription) {
2342
                $this->shortDescription = $this->replaceStuff($shortDescription);
2342
                $this->shortDescription = $this->replaceStuff($shortDescription);
2343
        }
2343
        }
2344
        public function getShortDescription() {
2344
        public function getShortDescription() {
2345
                if (_empty($this->shortDescription)) {
2345
                if (_empty($this->shortDescription)) {
2346
                        return null;
2346
                        return null;
2347
                } else {
2347
                } else {
2348
                        $content = $this->shortDescription;
2348
                        $content = $this->shortDescription;
2349
                        if ($this->word_wrap_width > 0) $content = wordwrap($content, $this->word_wrap_width, "\n", false);
2349
                        if ($this->word_wrap_width > 0) $content = wordwrap($content, $this->word_wrap_width, "\n", false);
2350
                        return $content;
2350
                        return $content;
2351
                }
2351
                }
2352
        }
2352
        }
2353
 
2353
 
2354
        protected function replaceStuff($text) {
2354
        protected function replaceStuff($text) {
2355
                global $argv;
2355
                global $argv;
2356
                $text = str_replace('$SCRIPTNAME$', $argv[0], $text);
2356
                $text = str_replace('$SCRIPTNAME$', $argv[0], $text);
2357
                $text = str_replace('$CURYEAR$', date('Y'), $text);
2357
                $text = str_replace('$CURYEAR$', date('Y'), $text);
2358
                return $text;
2358
                return $text;
2359
        }
2359
        }
2360
 
2360
 
2361
        // $syntax should contain the option syntax only, no explanations.
2361
        // $syntax should contain the option syntax only, no explanations.
2362
        // $SCRIPTNAME$ will be replaced by the actual script name
2362
        // $SCRIPTNAME$ will be replaced by the actual script name
2363
        // $CURYEAR$ will be replaced by the current year
2363
        // $CURYEAR$ will be replaced by the current year
2364
        # FUT: Automatically generate syntax?
2364
        # FUT: Automatically generate syntax?
2365
        protected $syntax;
2365
        protected $syntax;
2366
        public function setSyntax($syntax) {
2366
        public function setSyntax($syntax) {
2367
                $syntax = $this->replaceStuff($syntax);
2367
                $syntax = $this->replaceStuff($syntax);
2368
                $this->syntax = $syntax;
2368
                $this->syntax = $syntax;
2369
        }
2369
        }
2370
        public function getUsage() {
2370
        public function getUsage() {
2371
                if (_empty($this->syntax)) {
2371
                if (_empty($this->syntax)) {
2372
                        return null;
2372
                        return null;
2373
                } else {
2373
                } else {
2374
                        return sprintf(VNagLang::$usage_x, $this->syntax);
2374
                        return sprintf(VNagLang::$usage_x, $this->syntax);
2375
                }
2375
                }
2376
        }
2376
        }
2377
 
2377
 
2378
        // $footNotes can be contact information or other notes which should appear in --help
2378
        // $footNotes can be contact information or other notes which should appear in --help
2379
        protected $footNotes;
2379
        protected $footNotes;
2380
        public function setFootNotes($footNotes) {
2380
        public function setFootNotes($footNotes) {
2381
                $this->footNotes = $this->replaceStuff($footNotes);
2381
                $this->footNotes = $this->replaceStuff($footNotes);
2382
        }
2382
        }
2383
        public function getFootNotes() {
2383
        public function getFootNotes() {
2384
                return $this->footNotes;
2384
                return $this->footNotes;
2385
        }
2385
        }
2386
}
2386
}
2387
 
2387
 
2388
class VNagLang {
2388
class VNagLang {
2389
        public static function status($code, $statusmodel) {
2389
        public static function status($code, $statusmodel) {
2390
                switch ($statusmodel) {
2390
                switch ($statusmodel) {
2391
                        case VNag::STATUSMODEL_SERVICE:
2391
                        case VNag::STATUSMODEL_SERVICE:
2392
                                switch ($code) {
2392
                                switch ($code) {
2393
                                        case VNag::STATUS_OK:
2393
                                        case VNag::STATUS_OK:
2394
                                                return 'OK';
2394
                                                return 'OK';
2395
                                                #break;
2395
                                                #break;
2396
                                        case VNag::STATUS_WARNING:
2396
                                        case VNag::STATUS_WARNING:
2397
                                                return 'Warning';
2397
                                                return 'Warning';
2398
                                                #break;
2398
                                                #break;
2399
                                        case VNag::STATUS_CRITICAL:
2399
                                        case VNag::STATUS_CRITICAL:
2400
                                                return 'Critical';
2400
                                                return 'Critical';
2401
                                                #break;
2401
                                                #break;
2402
                                        case VNag::STATUS_UNKNOWN:
2402
                                        case VNag::STATUS_UNKNOWN:
2403
                                                return 'Unknown';
2403
                                                return 'Unknown';
2404
                                                #break;
2404
                                                #break;
2405
                                        default:
2405
                                        default:
2406
                                                return sprintf('Error (%d)', $code);
2406
                                                return sprintf('Error (%d)', $code);
2407
                                                #break;
2407
                                                #break;
2408
                                }
2408
                                }
2409
                                #break;
2409
                                #break;
2410
                        case VNag::STATUSMODEL_HOST:
2410
                        case VNag::STATUSMODEL_HOST:
2411
                                switch ($code) {
2411
                                switch ($code) {
2412
                                        case VNag::STATUS_UP:
2412
                                        case VNag::STATUS_UP:
2413
                                                return 'Up';
2413
                                                return 'Up';
2414
                                                #break;
2414
                                                #break;
2415
                                        case VNag::STATUS_DOWN:
2415
                                        case VNag::STATUS_DOWN:
2416
                                                return 'Down';
2416
                                                return 'Down';
2417
                                                #break;
2417
                                                #break;
2418
                                        default:
2418
                                        default:
2419
                                                return sprintf('Maintain last state (%d)', $code);
2419
                                                return sprintf('Maintain last state (%d)', $code);
2420
                                                #break;
2420
                                                #break;
2421
                                }
2421
                                }
2422
                                #break;
2422
                                #break;
2423
                        default:
2423
                        default:
2424
                                throw new VNagIllegalStatusModel(sprintf(self::$illegal_statusmodel, $statusmodel));
2424
                                throw new VNagIllegalStatusModel(sprintf(self::$illegal_statusmodel, $statusmodel));
2425
                                #break;
2425
                                #break;
2426
                }
2426
                }
2427
        }
2427
        }
2428
 
2428
 
2429
        static $nagios_output = 'VNag-Output';
2429
        static $nagios_output = 'VNag-Output';
2430
        static $verbose_info = 'Verbose information';
2430
        static $verbose_info = 'Verbose information';
2431
        static $status = 'Status';
2431
        static $status = 'Status';
2432
        static $message = 'Message';
2432
        static $message = 'Message';
2433
        static $performance_data = 'Performance data';
2433
        static $performance_data = 'Performance data';
2434
        static $status_ok = 'OK';
2434
        static $status_ok = 'OK';
2435
        static $status_warn = 'Warning';
2435
        static $status_warn = 'Warning';
2436
        static $status_critical = 'Critical';
2436
        static $status_critical = 'Critical';
2437
        static $status_unknown = 'Unknown';
2437
        static $status_unknown = 'Unknown';
2438
        static $status_error = 'Error';
2438
        static $status_error = 'Error';
2439
        static $unhandled_exception_without_msg = "Unhandled exception of type %s";
2439
        static $unhandled_exception_without_msg = "Unhandled exception of type %s";
2440
        static $plugin_uses = 'This plugin uses %s';
2440
        static $plugin_uses = 'This plugin uses %s';
2441
        static $uses = 'uses %s';
2441
        static $uses = 'uses %s';
2442
        static $x_version_x = '%s, version %s';
2442
        static $x_version_x = '%s, version %s';
2443
 
2443
 
2444
        // Argument names (help page)
2444
        // Argument names (help page)
2445
        static $argname_value = 'value';
2445
        static $argname_value = 'value';
2446
        static $argname_seconds = 'seconds';
2446
        static $argname_seconds = 'seconds';
2447
        static $certified = 'Certified by ViaThinkSoft';
2447
        static $certified = 'Certified by ViaThinkSoft';
2448
 
2448
 
2449
        // Exceptions
2449
        // Exceptions
2450
        static $query_without_expected_argument = "The argument '%s' is queried, but was not added to the list of expected arguments. Please contact the plugin author.";
2450
        static $query_without_expected_argument = "The argument '%s' is queried, but was not added to the list of expected arguments. Please contact the plugin author.";
2451
        static $required_argument_missing = "The argument '%s' is required.";
2451
        static $required_argument_missing = "The argument '%s' is required.";
2452
        static $performance_data_invalid = 'Performance data invalid.';
2452
        static $performance_data_invalid = 'Performance data invalid.';
2453
        static $no_standard_arguments_with_letter = "No standard argument with letter '%s' exists.";
2453
        static $no_standard_arguments_with_letter = "No standard argument with letter '%s' exists.";
2454
        static $invalid_start_value = 'Invalid start value.';
2454
        static $invalid_start_value = 'Invalid start value.';
2455
        static $invalid_end_value = 'Invalid end value.';
2455
        static $invalid_end_value = 'Invalid end value.';
2456
        static $start_is_greater_than_end = 'Start is greater than end value.';
2456
        static $start_is_greater_than_end = 'Start is greater than end value.';
2457
        static $value_name_forbidden = "Implementation error: You may not define a value name for the argument, because the value policy is VALUE_FORBIDDEN.";
2457
        static $value_name_forbidden = "Implementation error: You may not define a value name for the argument, because the value policy is VALUE_FORBIDDEN.";
2458
        static $value_name_required = "Implementation error: Please define a name for the argument (so it can be shown in the help page).";
2458
        static $value_name_required = "Implementation error: Please define a name for the argument (so it can be shown in the help page).";
2459
        static $illegal_shortopt = "Illegal shortopt '-%s'.";
2459
        static $illegal_shortopt = "Illegal shortopt '-%s'.";
2460
        static $illegal_longopt = "Illegal longopt '--%s'.";
2460
        static $illegal_longopt = "Illegal longopt '--%s'.";
2461
        static $illegal_valuepolicy = "valuePolicy has illegal value '%s'.";
2461
        static $illegal_valuepolicy = "valuePolicy has illegal value '%s'.";
2462
        static $range_invalid_syntax = "Syntax error in range '%s'.";
2462
        static $range_invalid_syntax = "Syntax error in range '%s'.";
2463
        static $timeout_value_invalid = "Timeout value '%s' is invalid.";
2463
        static $timeout_value_invalid = "Timeout value '%s' is invalid.";
2464
        static $range_is_invalid = 'Range is invalid.';
2464
        static $range_is_invalid = 'Range is invalid.';
2465
        static $timeout_exception = 'Timeout!';
2465
        static $timeout_exception = 'Timeout!';
2466
        static $perfdata_label_equal_sign_forbidden = 'Label may not contain an equal sign.';
2466
        static $perfdata_label_equal_sign_forbidden = 'Label may not contain an equal sign.';
2467
        static $perfdata_value_must_be_in_class = 'Value must be in class [-0-9.] or be \'U\' if the actual value can\'t be determined.';
2467
        static $perfdata_value_must_be_in_class = 'Value must be in class [-0-9.] or be \'U\' if the actual value can\'t be determined.';
2468
        static $perfdata_min_must_be_in_class = 'Min must be in class [-0-9.] or empty.';
2468
        static $perfdata_min_must_be_in_class = 'Min must be in class [-0-9.] or empty.';
2469
        static $perfdata_max_must_be_in_class = 'Max must be in class [-0-9.] or empty.';
2469
        static $perfdata_max_must_be_in_class = 'Max must be in class [-0-9.] or empty.';
2470
        static $perfdata_uom_not_recognized = 'UOM (unit of measurement) "%s" is not recognized.';
2470
        static $perfdata_uom_not_recognized = 'UOM (unit of measurement) "%s" is not recognized.';
2471
        static $perfdata_mixed_uom_not_implemented = 'Mixed UOMs (%s and %s) are currently not supported.';
2471
        static $perfdata_mixed_uom_not_implemented = 'Mixed UOMs (%s and %s) are currently not supported.';
2472
        static $no_compatible_range_uom_found = 'Measured values are not compatible with the provided warning/critical parameter. Most likely, the UOM is incompatible.';
2472
        static $no_compatible_range_uom_found = 'Measured values are not compatible with the provided warning/critical parameter. Most likely, the UOM is incompatible.';
2473
        static $exception_x = '%s (%s)';
2473
        static $exception_x = '%s (%s)';
2474
        static $no_syntax_defined = 'The author of this plugin has not defined a syntax for this plugin.';
2474
        static $no_syntax_defined = 'The author of this plugin has not defined a syntax for this plugin.';
2475
        static $usage_x = "Usage:\n%s";
2475
        static $usage_x = "Usage:\n%s";
2476
        static $options = "Options:";
2476
        static $options = "Options:";
2477
        static $illegal_statusmodel = "Invalid statusmodel %d.";
2477
        static $illegal_statusmodel = "Invalid statusmodel %d.";
2478
        static $none = '[none]';
2478
        static $none = '[none]';
2479
        static $valueUomPairSyntaxError = 'Syntax error at "%s". Syntax must be Value[UOM].';
2479
        static $valueUomPairSyntaxError = 'Syntax error at "%s". Syntax must be Value[UOM].';
2480
        static $too_few_warning_ranges = "You have too few warning ranges (currently trying to get element %d).";
2480
        static $too_few_warning_ranges = "You have too few warning ranges (currently trying to get element %d).";
2481
        static $too_few_critical_ranges = "You have too few critical ranges (currently trying to get element %d).";
2481
        static $too_few_critical_ranges = "You have too few critical ranges (currently trying to get element %d).";
2482
        static $dataset_missing = 'Dataset missing.';
2482
        static $dataset_missing = 'Dataset missing.';
2483
        static $payload_not_base64 = 'The payload is not valid Base64.';
2483
        static $payload_not_base64 = 'The payload is not valid Base64.';
2484
        static $payload_not_json = 'The payload is not valid JSON.';
2484
        static $payload_not_json = 'The payload is not valid JSON.';
2485
        static $signature_missing = 'The signature is missing.';
2485
        static $signature_missing = 'The signature is missing.';
2486
        static $signature_not_bas64 = 'The signature is not valid Base64.';
2486
        static $signature_not_bas64 = 'The signature is not valid Base64.';
2487
        static $signature_invalid = 'The signature is invalid. The connection might have been tampered, or a different key is used.';
2487
        static $signature_invalid = 'The signature is invalid. The connection might have been tampered, or a different key is used.';
2488
        static $pubkey_file_not_found = "Public key file %s was not found.";
2488
        static $pubkey_file_not_found = "Public key file %s was not found.";
2489
        static $pubkey_file_not_readable = "Public key file %s is not readable.";
2489
        static $pubkey_file_not_readable = "Public key file %s is not readable.";
2490
        static $privkey_file_not_found = "Private key file %s was not found.";
2490
        static $privkey_file_not_found = "Private key file %s was not found.";
2491
        static $privkey_not_readable = "Private key is not readable.";
2491
        static $privkey_not_readable = "Private key is not readable.";
2492
        static $privkey_file_not_readable = "Private key file %s is not readable.";
2492
        static $privkey_file_not_readable = "Private key file %s is not readable.";
2493
        static $signature_failed = "Signature failed.";
2493
        static $signature_failed = "Signature failed.";
2494
        static $perfdata_line_invalid = "Performance data line %s is invalid.";
2494
        static $perfdata_line_invalid = "Performance data line %s is invalid.";
2495
        static $singlevalue_unexpected_at_symbol = 'This plugin does not allow the @-symbol at ranges for single values.';
2495
        static $singlevalue_unexpected_at_symbol = 'This plugin does not allow the @-symbol at ranges for single values.';
2496
        static $illegalSingleValueBehavior = "Illegal value for 'singleValueBehavior'. Please contact the creator of the plugin.";
2496
        static $illegalSingleValueBehavior = "Illegal value for 'singleValueBehavior'. Please contact the creator of the plugin.";
2497
        static $dataset_encryption_no_array = 'Dataset encryption information invalid.';
2497
        static $dataset_encryption_no_array = 'Dataset encryption information invalid.';
2498
        static $require_password = 'This resource is protected with a password. Please provide a password.';
2498
        static $require_password = 'This resource is protected with a password. Please provide a password.';
2499
        static $wrong_password = 'This resource is protected with a password. You have provided the wrong password, or it was changed.';
2499
        static $wrong_password = 'This resource is protected with a password. You have provided the wrong password, or it was changed.';
2500
        static $convert_x_y_error = 'Cannot convert from UOM %s to UOM %s.';
2500
        static $convert_x_y_error = 'Cannot convert from UOM %s to UOM %s.';
2501
        static $php_error = 'PHP has detected an error in the plugin. Please contact the plugin author.';
2501
        static $php_error = 'PHP has detected an error in the plugin. Please contact the plugin author.';
2502
        static $output_level_lowered = "Output Buffer level lowered during cbRun(). Please contact the plugin author.";
2502
        static $output_level_lowered = "Output Buffer level lowered during cbRun(). Please contact the plugin author.";
2503
        static $openssl_missing = "OpenSSL is missing. Therefore, encryption and signatures are not available.";
2503
        static $openssl_missing = "OpenSSL is missing. Therefore, encryption and signatures are not available.";
2504
 
2504
 
2505
        // Help texts
2505
        // Help texts
2506
        static $warning_range = 'Warning range';
2506
        static $warning_range = 'Warning range';
2507
        static $critical_range = 'Critical range';
2507
        static $critical_range = 'Critical range';
2508
        static $prints_version = 'Prints version';
2508
        static $prints_version = 'Prints version';
2509
        static $verbosity_helptext = 'Verbosity -v, -vv or -vvv';
2509
        static $verbosity_helptext = 'Verbosity -v, -vv or -vvv';
2510
        static $timeout_helptext = 'Sets timeout in seconds';
2510
        static $timeout_helptext = 'Sets timeout in seconds';
2511
        static $help_helptext = 'Prints help page';
2511
        static $help_helptext = 'Prints help page';
2512
        static $prints_usage = 'Prints usage';
2512
        static $prints_usage = 'Prints usage';
2513
 
2513
 
2514
        static $notConstructed = 'Parent constructor not called with parent::__construct().';
2514
        static $notConstructed = 'Parent constructor not called with parent::__construct().';
2515
}
2515
}
2516
 
2516
 
2517
function vnagErrorHandler($errorkind, $errortext, $file, $line) {
2517
function vnagErrorHandler($errorkind, $errortext, $file, $line) {
2518
        // This function "converts" PHP runtime errors into Exceptions, which can then be handled by VNag::handleException()
2518
        // This function "converts" PHP runtime errors into Exceptions, which can then be handled by VNag::handleException()
2519
        global $inside_vnag_run;
2519
        global $inside_vnag_run;
2520
 
2520
 
2521
        if (!$inside_vnag_run && VNag::is_http_mode()) {
2521
        if (!$inside_vnag_run && VNag::is_http_mode()) {
2522
                // We want to avoid that the VNag-Exception will show up in a website that contains
2522
                // We want to avoid that the VNag-Exception will show up in a website that contains
2523
                // an embedded VNag monitor, so if we are not inside a running VNag code,
2523
                // an embedded VNag monitor, so if we are not inside a running VNag code,
2524
                // we will call the normal PHP error handler.
2524
                // we will call the normal PHP error handler.
2525
                return false;
2525
                return false;
2526
        }
2526
        }
2527
 
2527
 
2528
        if (!(error_reporting() & $errorkind)) {
2528
        if (!(error_reporting() & $errorkind)) {
2529
                // Code is not included in error_reporting. Don't do anything.
2529
                // Code is not included in error_reporting. Don't do anything.
2530
                return true;
2530
                return true;
2531
        }
2531
        }
2532
 
2532
 
2533
        // We want 100% clean scripts, so any error, warning or notice will shutdown the script
2533
        // We want 100% clean scripts, so any error, warning or notice will shutdown the script
2534
        // This also fixes the issue that PHP will end with result code 0, showing an error.
2534
        // This also fixes the issue that PHP will end with result code 0, showing an error.
2535
 
2535
 
2536
        // Error kinds see http://php.net/manual/en/errorfunc.constants.php
2536
        // Error kinds see http://php.net/manual/en/errorfunc.constants.php
2537
        if (defined('E_ERROR') && ($errorkind == E_ERROR)) $errorkind = 'Error';
2537
        if (defined('E_ERROR') && ($errorkind == E_ERROR)) $errorkind = 'Error';
2538
        if (defined('E_WARNING') && ($errorkind == E_WARNING)) $errorkind = 'Warning';
2538
        if (defined('E_WARNING') && ($errorkind == E_WARNING)) $errorkind = 'Warning';
2539
        if (defined('E_PARSE') && ($errorkind == E_PARSE)) $errorkind = 'Parse';
2539
        if (defined('E_PARSE') && ($errorkind == E_PARSE)) $errorkind = 'Parse';
2540
        if (defined('E_NOTICE') && ($errorkind == E_NOTICE)) $errorkind = 'Notice';
2540
        if (defined('E_NOTICE') && ($errorkind == E_NOTICE)) $errorkind = 'Notice';
2541
        if (defined('E_CORE_ERROR') && ($errorkind == E_CORE_ERROR)) $errorkind = 'Core Error';
2541
        if (defined('E_CORE_ERROR') && ($errorkind == E_CORE_ERROR)) $errorkind = 'Core Error';
2542
        if (defined('E_CORE_WARNING') && ($errorkind == E_CORE_WARNING)) $errorkind = 'Core Warning';
2542
        if (defined('E_CORE_WARNING') && ($errorkind == E_CORE_WARNING)) $errorkind = 'Core Warning';
2543
        if (defined('E_COMPILE_ERROR') && ($errorkind == E_COMPILE_ERROR)) $errorkind = 'Compile Error';
2543
        if (defined('E_COMPILE_ERROR') && ($errorkind == E_COMPILE_ERROR)) $errorkind = 'Compile Error';
2544
        if (defined('E_COMPILE_WARNING') && ($errorkind == E_COMPILE_WARNING)) $errorkind = 'Compile Warning';
2544
        if (defined('E_COMPILE_WARNING') && ($errorkind == E_COMPILE_WARNING)) $errorkind = 'Compile Warning';
2545
        if (defined('E_USER_ERROR') && ($errorkind == E_USER_ERROR)) $errorkind = 'User Error';
2545
        if (defined('E_USER_ERROR') && ($errorkind == E_USER_ERROR)) $errorkind = 'User Error';
2546
        if (defined('E_USER_WARNING') && ($errorkind == E_USER_WARNING)) $errorkind = 'User Warning';
2546
        if (defined('E_USER_WARNING') && ($errorkind == E_USER_WARNING)) $errorkind = 'User Warning';
2547
        if (defined('E_USER_NOTICE') && ($errorkind == E_USER_NOTICE)) $errorkind = 'User Notice';
2547
        if (defined('E_USER_NOTICE') && ($errorkind == E_USER_NOTICE)) $errorkind = 'User Notice';
2548
        if (defined('E_STRICT') && ($errorkind == E_STRICT)) $errorkind = 'Strict';
2548
        if (defined('E_STRICT') && ($errorkind == E_STRICT)) $errorkind = 'Strict';
2549
        if (defined('E_RECOVERABLE_ERROR') && ($errorkind == E_RECOVERABLE_ERROR)) $errorkind = 'Recoverable Error';
2549
        if (defined('E_RECOVERABLE_ERROR') && ($errorkind == E_RECOVERABLE_ERROR)) $errorkind = 'Recoverable Error';
2550
        if (defined('E_DEPRECATED') && ($errorkind == E_DEPRECATED)) $errorkind = 'Deprecated';
2550
        if (defined('E_DEPRECATED') && ($errorkind == E_DEPRECATED)) $errorkind = 'Deprecated';
2551
        if (defined('E_USER_DEPRECATED') && ($errorkind == E_USER_DEPRECATED)) $errorkind = 'User Deprecated';
2551
        if (defined('E_USER_DEPRECATED') && ($errorkind == E_USER_DEPRECATED)) $errorkind = 'User Deprecated';
2552
        throw new VNagException(VNagLang::$php_error . " $errortext at $file:$line (kind $errorkind)");
2552
        throw new VNagException(VNagLang::$php_error . " $errortext at $file:$line (kind $errorkind)");
2553
 
2553
 
2554
        // true = the PHP internal error handling will NOT be called.
2554
        // true = the PHP internal error handling will NOT be called.
2555
        #return true;
2555
        #return true;
2556
}
2556
}
2557
 
2557
 
2558
$inside_vnag_run = false;
2558
$inside_vnag_run = false;
2559
$old_error_handler = set_error_handler("vnagErrorHandler");
2559
$old_error_handler = set_error_handler("vnagErrorHandler");
2560
 
2560
 
2561
// === End of document ===
2561
// === End of document ===
2562
 
2562