Passed
Push — master ( 5fe26f...4261d0 )
by Patrick
01:54
created

Database::db_connect_trap()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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