Issues (48)

library/Trapdirector/TrapsProcess/Database.php (1 issue)

1
<?php
2
3
namespace Trapdirector;
4
5
use Exception;
6
use PDO;
7
use PDOException;
8
9
class Database
10
{
11
12
    // Databases
13
    /** @var \PDO $trapDB trap database */
14
    protected $trapDB=null; 
15
    protected $idoDB=null; //< ido database
16
    public $trapDBType; //< Type of database for traps (mysql, pgsql)
17
    public $idoDBType; //< Type of database for ido (mysql, pgsql)
18
    
19
    protected $trapDSN; //< trap database connection params
20
    protected $trapUsername; //< trap database connection params
21
    protected $trapPass; //< trap database connection params
22
    public $dbPrefix; //< database tables prefix
23
    
24
    protected $idoSet; //< bool true is ido database set
25
    protected $idoDSN; //< trap database connection params
26
    protected $idoUsername; //< trap database connection params
27
    protected $idoPass; //< trap database connection params
28
    
29
    // Logging function
30
    
31
    protected $logging; //< logging class
32
    
33
    /**
34
     * @param Logging $logClass : where to log
35
     * @param array $dbParam : array of named params  type,host,dbname,username,[port],[password]
36
     */
37
    function __construct($logClass,$dbParam,$dbPrefix)
38
    {
39
        $this->logging=$logClass;
40
        $this->dbPrefix=$dbPrefix;
41
        
42
        $this->trapDSN=$this->setupDSN($dbParam);
43
        $this->trapUsername = $dbParam['username'];
44
        $this->trapPass = (array_key_exists('password', $dbParam)) ? $dbParam['password']:'';
45
        $this->trapDBType=$dbParam['db'];
46
        $this->logging->log('DSN : '.$this->trapDSN. ';user '.$this->trapUsername.' / prefix : '. $this->dbPrefix,INFO);
47
        $this->db_connect_trap();
48
        
49
    }
50
    
51
    /**
52
     * Setup and connect to IDO database
53
     * @param array $dbParam : array of named params
54
     */
55
    public function setupIDO($dbParam)
56
    {
57
        $this->idoDSN=$this->setupDSN($dbParam);
58
        $this->idoUsername = $dbParam['username'];
59
        $this->idoPass = (array_key_exists('password', $dbParam)) ? $dbParam['password']:'';
60
        $this->logging->log('DSN : '.$this->idoDSN. ';user '.$this->idoUsername,INFO);
61
        $this->idoDBType=$dbParam['db'];
62
        $this->db_connect_ido();
63
    }
64
    
65
    /**
66
     * Connect to IDO database
67
     * @return \PDO
68
     */
69
    public function db_connect_ido()
70
    {
71
        if ($this->idoDB != null) {
72
            // Check if connection is still alive
73
            try {
74
                $this->idoDB->query('select 1')->fetchColumn();
75
                return $this->idoDB;
76
            } catch (Exception $e) {
77
                // select 1 failed, try to reconnect.
78
                $this->logging->log('Database IDO connection lost, reconnecting',WARN);
79
            }
80
        }
81
        try {
82
            $this->idoDB = new PDO($this->idoDSN,$this->idoUsername,$this->idoPass);
83
        } catch (PDOException $e) {
84
            $this->logging->log('Connection failed to IDO : ' . $e->getMessage(),ERROR,'');
85
        }
86
        return $this->idoDB;
87
    }
88
    
89
    /**
90
     * Connect to Trap database
91
     * @return \PDO
92
     */
93
    public function db_connect_trap()
94
    {
95
        if ($this->trapDB != null) {
96
            // Check if connection is still alive
97
            try {
98
                $this->trapDB->query('select 1')->fetchColumn();
99
                return $this->trapDB;
100
            } catch (Exception $e) {
101
                // select 1 failed, try to reconnect.
102
                $this->logging->log('Database connection lost, reconnecting',WARN);
103
            }           
104
        }       
105
        try {
106
            $this->trapDB = new PDO($this->trapDSN,$this->trapUsername,$this->trapPass);
107
        } catch (PDOException $e) {
108
            $this->logging->log('Connection failed : ' . $e->getMessage(),ERROR,'');
109
        }
110
        return $this->trapDB;
111
    }
112
    
113
    /**
114
     * Setup dsn and check parameters
115
     * @param array $configElmt
116
     * @return string
117
     */
118
    protected function setupDSN($configElmt)  
119
    {
120
        if (!array_key_exists('db',$configElmt) ||
121
            !array_key_exists('host',$configElmt) ||
122
            !array_key_exists('dbname',$configElmt) ||
123
            !array_key_exists('username',$configElmt))
124
        {
125
            $this->logging->log('Missing DB params',ERROR);
126
            return ''; 
127
        }
128
        
129
        //	$dsn = 'mysql:dbname=traps;host=127.0.0.1';
130
        $dsn= $configElmt['db'].':dbname='.$configElmt['dbname'].';host='.$configElmt['host'];
131
        
132
        if (array_key_exists('port', $configElmt))
133
        {
134
            $dsn .= ';port='.$configElmt['port'];
135
        }
136
        return $dsn;
137
    }
138
139
    /** Set name=element in database config table
140
     * @param string $name
141
     * @param string $element
142
     * @return boolean true on success, else false (error logged)
143
     */
144
    public function setDBConfig($name,$element)
145
    {
146
        $db_conn=$this->db_connect_trap();
147
        $sql='SELECT id from '.$this->dbPrefix.'db_config WHERE ( name=\''.$name.'\' )';
148
        if (($ret_code=$db_conn->query($sql)) === false) {
149
            $this->logging->log('Error setting config element : ' . $sql,WARN,'');           
150
            return false;
151
        }
152
        $value=$ret_code->fetch();
153
        if ($value != null && isset($value['id']))
154
        {   // Entry exists -> update
155
            $sql='UPDATE '.$this->dbPrefix.'db_config SET value = \''.$element.'\' WHERE (id = '.$value['id'].')';
156
        }
157
        else
158
        {   // Entry does no exists -> create
159
            $sql='INSERT INTO '.$this->dbPrefix.'db_config (name,value) VALUES (\''.$name.'\' , \''.$element.'\' )';
160
        }
161
        if (($ret_code=$db_conn->query($sql)) === false) {
0 ignored issues
show
The assignment to $ret_code is dead and can be removed.
Loading history...
162
            $this->logging->log('Error setting config element : ' . $sql,WARN,'');
163
            return false;
164
        }
165
        $this->logging->log('Setting config '.$name.' = '.$element.' in database',INFO);
166
        return true;
167
    }
168
169
    /**
170
     *   Get data from db_config
171
     *	@param $element string name of param
172
     *	@return mixed : value (or null)
173
     */
174
    public function getDBConfig($element)
175
    {
176
        $db_conn=$this->db_connect_trap();
177
        $sql='SELECT value from '.$this->dbPrefix.'db_config WHERE ( name=\''.$element.'\' )';
178
        if (($ret_code=$db_conn->query($sql)) === false) {
179
            $this->logging->log('No result in query : ' . $sql,WARN,'');
180
            return null;
181
        }
182
        $value=$ret_code->fetch();
183
        if ($value != null && isset($value['value']))
184
        {
185
            return $value['value'];
186
        }
187
        return null;
188
    }
189
    
190
    
191
    //*********    Schema Management *********************/
192
193
    /** Create database schema
194
     *	@param $schema_file	string File to read schema from
195
     *	@param $table_prefix string to replace #PREFIX# in schema file by this
196
     */
197
    public function create_schema($schema_file,$table_prefix)
198
    {
199
        //Read data from snmptrapd from stdin
200
        $input_stream=fopen($schema_file, 'r');
201
        
202
        if ($input_stream=== false)
203
        {
204
            $this->logging->log("Error reading schema !",ERROR,'');
205
            return;
206
        }
207
        $newline='';
208
        $cur_table='';
209
        $cur_table_array=array();
210
        $db_conn=$this->db_connect_trap();
211
        
212
        while (($line=fgets($input_stream)) !== false)
213
        {
214
            $newline.=chop(preg_replace('/#PREFIX#/',$table_prefix,$line));
215
            if (preg_match('/; *$/', $newline))
216
            {
217
                $sql= $newline;
218
                if ($db_conn->query($sql) === false) {
219
                    $this->logging->log('Error create schema : '.$sql,ERROR,'');
220
                    return;
221
                }
222
                if (preg_match('/^ *CREATE TABLE ([^ ]+)/',$newline,$cur_table_array))
223
                {
224
                    $cur_table='table '.$cur_table_array[1];
225
                }
226
                else
227
                {
228
                    $cur_table='secret SQL stuff :-)';
229
                }
230
                $this->logging->log('Creating : ' . $cur_table,INFO );
231
                $newline='';
232
            }
233
        }
234
        
235
        $sql= $newline;
236
        if ($sql != '' )
237
        {
238
            if ($db_conn->query($sql) === false) {
239
                $this->logging->log('Error create schema : '.$sql,ERROR,'');
240
                return;
241
            }
242
        }
243
        $this->logging->log('Schema created',INFO);
244
    }
245
    
246
    /**
247
     * Update database schema from current (as set in db) to $target_version
248
     *     @param $prefix string file prefix of sql update File
249
     *     @param $target_version int target db version number
250
     *     @param $table_prefix string to replace #PREFIX# in schema file by this
251
     *     @param bool $getmsg : only get messages from version upgrades
252
     *     @return string : if $getmsg=true, return messages or 'ERROR' on error.
253
     */
254
    public function update_schema($prefix,$target_version,$table_prefix,$getmsg=false)
255
    {
256
        // Get current db number
257
        $db_conn=$this->db_connect_trap();
258
        $sql='SELECT value from '.$this->dbPrefix.'db_config WHERE name=\'db_version\' ';
259
        $this->logging->log('SQL query : '.$sql,DEBUG );
260
        if (($ret_code=$db_conn->query($sql)) === false) {
261
            $this->logging->log('Cannot get db version. Query : ' . $sql,2,'');
262
            return 'ERROR';
263
        }
264
        $version=$ret_code->fetchAll();
265
        $cur_version=$version[0]['value'];
266
        
267
        if ($this->trapDBType == 'pgsql')
268
        {
269
            $prefix .= 'update_pgsql/schema_';
270
        }
271
        else
272
        {
273
            $prefix .= 'update_sql/schema_';
274
        }
275
        //echo "version all :\n";print_r($version);echo " \n $cur_ver \n";
276
        if ($getmsg === true)
277
        {
278
            return $this->update_schema_message($prefix, $cur_version, $target_version);
279
        }
280
        
281
        if ($this->update_schema_do($prefix, $cur_version, $target_version, $table_prefix) === true)
282
        {
283
            return 'ERROR';
284
        }
285
        return '';
286
287
    }
288
289
    /**
290
     * Update database schema from current (as set in db) to $target_version
291
     *     @param string $prefix  file prefix of sql update File
292
     *     @param int $cur_version  current db version number
293
     *     @param int $target_version  target db version number
294
     *     @param string $table_prefix   to replace #PREFIX# in schema file by this
295
     *     @return bool : true on error
296
     */
297
    public function update_schema_do($prefix,$cur_version,$target_version,$table_prefix)
298
    {
299
        while($cur_version<$target_version)
300
        { // TODO : execute pre & post scripts
301
            $cur_version++;
302
            $this->logging->log('Updating to version : ' .$cur_version ,INFO );
303
            $updateFile=$prefix.'v'.($cur_version-1).'_v'.$cur_version.'.sql';
304
            $input_stream=fopen($updateFile, 'r');
305
            if ($input_stream=== false)
306
            {
307
                $this->logging->log("Error reading update file ". $updateFile,ERROR);
308
                return true;
309
            }
310
            $newline='';
311
            $db_conn=$this->db_connect_trap();
312
            $db_conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
313
            while (($line=fgets($input_stream)) !== false)
314
            {
315
                if (preg_match('/^#/', $line)) continue; // ignore comment lines
316
                $newline.=chop(preg_replace('/#PREFIX#/',$table_prefix,$line));
317
                if (preg_match('/; *$/', $newline))
318
                {
319
                    $sql_req=$db_conn->prepare($newline);
320
                    if ($sql_req->execute() === false) {
321
                        $this->logging->log('Error create schema : '.$newline,ERROR);
322
                        return true;
323
                    }
324
                    $cur_table_array=array();
325
                    if (preg_match('/^ *([^ ]+) TABLE ([^ ]+)/',$newline,$cur_table_array))
326
                    {
327
                        $cur_table=$cur_table_array[1] . ' SQL table '.$cur_table_array[2];
328
                    }
329
                    else
330
                    {
331
                        $cur_table='secret SQL stuff :-)';
332
                        //$cur_table=$newline;
333
                    }
334
                    $this->logging->log('Doing : ' . $cur_table,INFO );
335
                    
336
                    $newline='';
337
                }
338
            }
339
            fclose($input_stream);
340
            
341
            $sql='UPDATE '.$this->dbPrefix.'db_config SET value='.$cur_version.' WHERE ( name=\'db_version\' )';
342
            $this->logging->log('SQL query : '.$sql,DEBUG );
343
            if ($db_conn->query($sql) === false) {
344
                $this->logging->log('Cannot update db version. Query : ' . $sql,WARN);
345
                return true;
346
            }
347
            
348
            $this->logging->log('Schema updated to version : '.$cur_version ,INFO);
349
        }
350
        return false;
351
    }
352
    
353
    /**
354
     * Get database message for update to $target_version
355
     *     @param string $prefix  file prefix of sql update File
356
     *     @param int $cur_version  current db version number
357
     *     @param int $target_version  target db version number
358
     *     @return string : return messages or 'ERROR'.
359
     */
360
    private function update_schema_message($prefix,$cur_version,$target_version)
361
    {
362
 
363
        $message='';
364
        $this->logging->log('getting message for upgrade',DEBUG );
365
        while($cur_version<$target_version)
366
        {
367
            $cur_version++;
368
            $updateFile=$prefix.'v'.($cur_version-1).'_v'.$cur_version.'.sql';
369
            $input_stream=fopen($updateFile, 'r');
370
            if ($input_stream=== false)
371
            {
372
                $this->logging->log("Error reading update file ". $updateFile,2,'');
373
                return 'ERROR';
374
            }
375
            do 
376
            { 
377
                $line=fgets($input_stream); 
378
            }
379
            while ($line !== false && !preg_match('/#MESSAGE/',$line));
380
            fclose($input_stream);
381
            if ($line === false)
382
            {
383
                $this->logging->log("No message in file ". $updateFile,2,'');
384
                return '';
385
            }
386
            $message .= ($cur_version-1) . '->' . $cur_version. ' : ' . preg_replace('/#MESSAGE : /','',$line)."\n";
387
        }
388
        return $message;
389
    }
390
    
391
}