Completed
Push — master ( 66be91...54ba87 )
by Kris
18s queued 12s
created

AbstractClient::extractNumericFromConf()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 5
c 0
b 0
f 0
nc 3
nop 4
dl 0
loc 11
rs 9.6111
1
<?php declare(strict_types=1);
2
3
/**
4
 *       _                 ___ ___ ___  ___
5
 *  __ _| |__ _  _ ___ ___|_ _| _ \   \| _ )
6
 * / _` | '_ \ || (_-</ -_)| ||  _/ |) | _ \
7
 * \__,_|_.__/\_,_/__/\___|___|_| |___/|___/
8
 * 
9
 * This file is part of Kristuff\AbuseIPDB.
10
 *
11
 * (c) Kristuff <[email protected]>
12
 *
13
 * For the full copyright and license information, please view the LICENSE
14
 * file that was distributed with this source code.
15
 *
16
 * @version    0.9.17
17
 * @copyright  2020-2021 Kristuff
18
 */
19
namespace Kristuff\AbuseIPDB;
20
21
use Kristuff\AbuseIPDB\QuietApiHandler;
22
use Kristuff\Mishell\Program;
23
24
/**
25
 * Class AbstractClient
26
 * 
27
 * Abstract base class for main program
28
 */
29
abstract class AbstractClient extends ShellErrorHandler
30
{
31
    /**
32
     * @var string      
33
     */
34
    const SHORT_ARGUMENTS = "o:GLBK:C:d:R:c:m:l:E:V:hvs:t:";
35
36
    /**
37
     * @var string      
38
     */
39
    const LONG_ARGUMENTS = ['output:', 'config', 'list', 'blacklist', 'check:', 'check-block:', 'days:', 'report:', 'categories:', 'message:', 'limit:', 'clear:',' bulk-report:', 'help', 'verbose', 'score:', 'version', 'timeout:'];
40
    
41
    /**
42
     * @var string
43
     */
44
    const VERSION = 'v0.9.17'; 
45
46
    /**
47
     * @var QuietApiHandler
48
     */
49
    protected static $api = null; 
50
51
    /**
52
     * @var string
53
     */
54
    protected static $configPath = __DIR__.'/../config';
55
56
    /**
57
     * @var array
58
     */
59
    protected static $basicCommands = [
60
        ['h',           'help',         'printHelp'],
61
        ['version',     'version',      'printVersion'],    // no short arg
62
        ['L',           'list',         'printCategories'],
63
    ];
64
    
65
    /**
66
     * @var array
67
     */
68
    protected static $mainCommands = [
69
        ['G',           'config',       'printConfig'], // require handler 
70
        ['C',           'check',        'checkIP'],
71
        ['K',           'check-block',  'checkBlock'],
72
        ['R',           'report',       'reportIP'],
73
        ['V',           'bulk-report',  'bulkReport'],
74
        ['B',           'blacklist',    'getBlacklist'],
75
        ['E',           'clear',        'clearIP'],
76
    ];
77
78
    /**
79
     * Parse command 
80
     * 
81
     * @access public 
82
     * @static
83
     * @param array     $arguments   
84
     * 
85
     * @return bool     true if the command has been found, otherwise false
86
     */
87
    protected static function parseCommand(array $arguments): bool
88
    {
89
        foreach(self::$basicCommands as $cmd){
90
            if (self::inArguments($arguments, $cmd[0], $cmd[1])){
91
                call_user_func(__NAMESPACE__.'\AbuseIPDBClient::'.$cmd[2], null);
92
                return true;
93
            }
94
        }
95
        foreach(self::$mainCommands as $cmd){
96
            if (self::inArguments($arguments, $cmd[0], $cmd[1])){
97
                self::createHandler($arguments);
98
                self::setOutputFormat($arguments);                    
99
                call_user_func(__NAMESPACE__.'\AbuseIPDBClient::'.$cmd[2], $arguments);
100
                return true;
101
            }
102
        }
103
        return false;
104
    }
105
106
    /**
107
     * Get and register output format
108
     *  
109
     * @access protected
110
     * @static
111
     * @param array         $arguments      The list of arguments     
112
     * 
113
     * @return void   
114
     */
115
    protected static function setOutputFormat(array $arguments): void
116
    {
117
        $given = self::getArgumentValue($arguments, 'o', 'output') ?? 'default';
118
        $output = empty($given) ? 'default' : $given; 
119
        self::validate(in_array($output, ['default', 'json', 'plaintext']), 'Invalid output argument given.');
120
        self::$outputFormat = $output;
121
    }
122
123
    /**
124
     * Create and register ApiHandler
125
     * 
126
     * @access protected 
127
     * @static
128
     * @param array     $arguments   
129
     * 
130
     * @return void
131
     */
132
    protected static function createHandler(array $arguments): void
133
    {
134
        try {
135
            $mainConfPath  = self::$configPath . DIRECTORY_SEPARATOR . 'conf.ini';
136
            $localConfPath = self::$configPath . DIRECTORY_SEPARATOR . 'local.ini';
137
138
            // Check main file exists and is readable
139
            // Even if a local file exists, main file must be here (throws ex otherwise)
140
            $mainConfigArray  = self::loadConfigFile($mainConfPath, true);
141
            $localConfigArray = self::loadConfigFile($localConfPath);
142
143
            $selfIps = self::extractSelfIpsFromConf($mainConfigArray, $localConfigArray);
144
            $apiKey  = self::extractApiKeyFromConf($mainConfigArray, $localConfigArray);
145
            $timeout = self::extractNumericFromConf('timeout',$mainConfigArray, $localConfigArray, 0);
146
            
147
            // look into arguments for possible overwrite for timeout 
148
            if (self::inArguments($arguments, 't', 'timeout')){
149
                $timeout = self::getArgumentValue($arguments, 't', 'timeout');
150
            }
151
152
            if (!is_numeric($timeout)){
153
                throw new \RuntimeException('Invalid timeout argument, must be numeric.');
154
            }            
155
156
            self::$api =  new QuietApiHandler($apiKey, $selfIps, intval($timeout));
157
        } catch (\Exception $e) {
158
            self::error($e->getMessage());
159
            self::printFooter();
160
            Program::exit(1);
161
        }
162
    }
163
164
    /**
165
     * Extract self ip list from configuration array
166
     * 
167
     * @access protected 
168
     * @static
169
     * @param array    $conf        The main configuration array
170
     * @param array    $localConf   The local configuration array
171
     * 
172
     * @return array
173
     */
174
    protected static function extractSelfIpsFromConf(array $conf, array $localConf): array
175
    {
176
        if (array_key_exists('self_ips', $localConf) && !empty($localConf['self_ips'])){
177
            return array_map('trim', explode(',', $localConf['self_ips']));
178
        }
179
        if (array_key_exists('self_ips', $conf) && !empty($conf['self_ips'])){
180
            return array_map('trim', explode(',', $conf['self_ips']));
181
        }
182
        return [];
183
    }
184
185
    /**
186
     * Extract the api key from configuration array
187
     * 
188
     * @access protected 
189
     * @static
190
     * @param array    $conf        The main configuration array
191
     * @param array    $localConf   The local configuration array
192
     * 
193
     * @return string
194
     * @throws \RuntimeException                                
195
     */
196
    protected static function extractApiKeyFromConf(array $conf, array $localConf): string
197
    {
198
        $key = '';
199
200
        if (array_key_exists('api_key', $localConf)){
201
            $key = $localConf['api_key'];
202
        }
203
        
204
        if (empty($key) && array_key_exists('api_key', $conf)){
205
            $key = $conf['api_key'];
206
        }
207
208
        if (empty($key)){
209
            throw new \RuntimeException('Api key is missing.');
210
        }
211
212
        return $key;
213
    }
214
215
    /**
216
     * Extract numeric value from configuration array
217
     * 
218
     * @access protected 
219
     * @static
220
     * @param string   $key         The config key 
221
     * @param array    $conf        The main configuration array
222
     * @param array    $localConf   The local configuration array
223
     * @param int      $default     The default value if empty
224
     *  
225
     * @return int
226
     */
227
    protected static function extractNumericFromConf(string $key, array $conf, array $localConf, int $default): int
228
    {
229
        if (array_key_exists($key, $localConf) && is_numeric($localConf[$key])){
230
            return intval($localConf[$key]);
231
        }
232
        
233
        if (array_key_exists($key, $conf) && is_numeric($conf[$key])){
234
            return intval($conf[$key]);
235
        }
236
237
        return $default;
238
    }
239
240
    /**
241
     * Load a config file
242
     * 
243
     * @access protected 
244
     * @static
245
     * @param string    $path        The configuration file path
246
     * @param bool      $mandatory   If true, throw ex when the file does not exist.
247
     * 
248
     * @return array
249
     * @throws \RuntimeException                                
250
     */
251
    protected static function loadConfigFile(string $path, bool $mandatory = false): array
252
    {
253
        if (file_exists($path) && is_file($path)){
254
255
            // If main file or a local file is not readable then throws ex.
256
            if (!is_readable($path)){
257
                throw new \RuntimeException('The configuration file ['.$path.'] is not readable.');
258
            }
259
260
            $conf = parse_ini_file($path, false);  // load without sections...
261
            if ($conf === false){
262
                throw new \RuntimeException('Unable to read configuration file ['.$path.'].');
263
            }
264
            return $conf;
265
        }
266
267
        if ($mandatory){
268
            throw new \RuntimeException('The configuration file ['.$path.'] does not exist.');
269
        }
270
        return [];
271
    }
272
}