mcramer
2012-06-18 a932880cc9dcd6da7e42f5a69534322c79f75953
commit | author | age
b5a2f8 1 <?php
T 2 /*
f5b0ca 3    Copyright (c) 2005, Till Brehm, projektfarm Gmbh
N 4    All rights reserved.
b5a2f8 5
f5b0ca 6    Redistribution and use in source and binary forms, with or without modification,
N 7    are permitted provided that the following conditions are met:
b5a2f8 8
f5b0ca 9  * Redistributions of source code must retain the above copyright notice,
N 10  this list of conditions and the following disclaimer.
11  * Redistributions in binary form must reproduce the above copyright notice,
12  this list of conditions and the following disclaimer in the documentation
13  and/or other materials provided with the distribution.
14  * Neither the name of ISPConfig nor the names of its contributors
15  may be used to endorse or promote products derived from this software without
16  specific prior written permission.
b5a2f8 17
f5b0ca 18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
N 19  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
b5a2f8 29
f5b0ca 30 class db extends mysqli
N 31 {
32   private $dbHost = '';        // hostname of the MySQL server
33   private $dbName = '';        // logical database name on that server
34   private $dbUser = '';        // database authorized user
35   private $dbPass = '';        // user's password
36   private $dbCharset = 'utf8';// Database charset
37   private $dbNewLink = false; // Return a new linkID when connect is called again
38   private $dbClientFlags = 0; // MySQL Client falgs
39   private $linkId = 0;        // last result of mysqli_connect()
40   private $queryId = 0;        // last result of mysqli_query()
41   private $record    = array();    // last record fetched
42   private $autoCommit = 1;    // Autocommit Transactions
43   private $currentRow;        // current row number
44   private $errorNumber = 0;    // last error number
45   public $errorMessage = '';    // last error message
46   private $errorLocation = '';// last error location
47   public $show_error_messages = true; // false in server, true in interface
b5a2f8 48
f5b0ca 49   // constructor
5e5755 50   public function __construct($prefix = '') {
f5b0ca 51     global $conf;
5e5755 52     if($prefix != '') $prefix .= '_';
M 53     $this->dbHost = $conf[$prefix.'db_host'];
54     $this->dbName = $conf[$prefix.'db_database'];
55     $this->dbUser = $conf[$prefix.'db_user'];
56     $this->dbPass = $conf[$prefix.'db_password'];
57     $this->dbCharset = $conf[$prefix.'db_charset'];
58     $this->dbNewLink = $conf[$prefix.'db_new_link'];
59     $this->dbClientFlags = $conf[$prefix.'db_client_flags'];
60     parent::__construct($conf[$prefix.'db_host'], $conf[$prefix.'db_user'],$conf[$prefix.'db_password'],$conf[$prefix.'db_database']);
f5b0ca 61     if ($this->connect_error) {
N 62       $this->updateError('DB::__construct');
63       return false;
e6c1c4 64     }
f5b0ca 65     parent::query( 'SET NAMES '.$this->dbCharset); 
N 66     parent::query( "SET character_set_results = '".$this->dbCharset."', character_set_client = '".$this->dbCharset."', character_set_connection = '".$this->dbCharset."', character_set_database = '".$this->dbCharset."', character_set_server = '".$this->dbCharset."'");
67
68   }
69
70   public function __destruct() {
71     $this->close(); // helps avoid memory leaks, and persitent connections that don't go away.
72   }
73
74   // error handler
75   public function updateError($location) {
76     global $app;
77
78     if($this->connect_error) {
79       $this->errorNumber = $this->connect_errno;
80       $this->errorMessage = $this->connect_error;
81     } else {
82       $this->errorNumber = $this->errno;
83       $this->errorMessage = $this->error;
e6c1c4 84     }
f5b0ca 85
N 86     $this->errorLocation = $location;
87     if($this->errorNumber) {
88       $error_msg = $this->errorLocation .' '. $this->errorMessage;
89       // This right here will allow us to use the samefile for server & interface
90       if($this->show_error_messages) {
91     echo $error_msg;
92       } else if(method_exists($app, 'log')) {
93     $app->log($error_msg, LOGLEVEL_WARN);
94       }
e6c1c4 95     }
f5b0ca 96   }
N 97
98   public function query($queryString) {
99     $this->queryId = parent::query($queryString);
100     $this->updateError('DB::query('.$queryString.') -> mysqli_query');
a93288 101     if($this->errorNumber) debug_print_backtrace();
f5b0ca 102     if(!$this->queryId) {
N 103       return false;
e6c1c4 104     }
f5b0ca 105     $this->currentRow = 0;
N 106     return $this->queryId;
107   }
108
109   // returns all records in an array
110   public function queryAllRecords($queryString) {
111     if(!$this->query($queryString))
e6c1c4 112     {
f5b0ca 113       return false;
e6c1c4 114     }
f5b0ca 115     $ret = array();
N 116     while($line = $this->nextRecord())
e6c1c4 117     {
f5b0ca 118       $ret[] = $line;
e6c1c4 119     }
f5b0ca 120     return $ret;
N 121   }
122
123   // returns one record in an array
124   public function queryOneRecord($queryString) {
125     if(!$this->query($queryString) || $this->numRows() == 0)
126     {
127       return false;
128     }
129     return $this->nextRecord();
130   }
131
132   // returns the next record in an array
133   public function nextRecord() {
134     $this->record = $this->queryId->fetch_assoc();
135     $this->updateError('DB::nextRecord()-> mysql_fetch_array');
136     if(!$this->record || !is_array($this->record))
137     {
138       return false;
139     }
140     $this->currentRow++;
141     return $this->record;
142   }
143
144   // returns number of rows returned by the last select query
145   public function numRows() {
146     return $this->queryId->num_rows;
147   }
b0eb45 148   
T 149   public function affectedRows() {
150     return $this->queryId->affected_rows;
151   }
f5b0ca 152
N 153   // returns mySQL insert id
154   public function insertID() {
155     return $this->insert_id;
156   }
157
158
516e0e 159   //* Function to quote strings
f5b0ca 160   public function quote($formfield) {
N 161     return $this->escape_string($formfield);
162   }
163
516e0e 164   //* Function to unquotae strings
f5b0ca 165   public function unquote($formfield) {
N 166     return stripslashes($formfield);
167   }
168
169 public function toLower($record) {
170     if(is_array($record)) {
171       foreach($record as $key => $val) {
172     $key = strtolower($key);
173     $out[$key] = $val;
174       }
175     }
176     return $out;
177   }
178
179   public function diffrec($record_old, $record_new) {
180     $diffrec_full = array();
181     $diff_num = 0;
182
183     if(is_array($record_old) && count($record_old) > 0) {
184       foreach($record_old as $key => $val) {
185     // if(!isset($record_new[$key]) || $record_new[$key] != $val) {
186     if($record_new[$key] != $val) {
187       // Record has changed
188       $diffrec_full['old'][$key] = $val;
189       $diffrec_full['new'][$key] = $record_new[$key];
190       $diff_num++;
191     } else {
192       $diffrec_full['old'][$key] = $val;
193       $diffrec_full['new'][$key] = $val;
194     }
195       }
196       } elseif(is_array($record_new)) {
197     foreach($record_new as $key => $val) {
198       if(isset($record_new[$key]) && @$record_old[$key] != $val) {
199         // Record has changed
200         $diffrec_full['new'][$key] = $val;
201         $diffrec_full['old'][$key] = @$record_old[$key];
202         $diff_num++;
203       } else {
204         $diffrec_full['new'][$key] = $val;
205         $diffrec_full['old'][$key] = $val;
206       }
207     }
208       }
209
210       return array('diff_num' => $diff_num, 'diff_rec' => $diffrec_full);
211
212     }
213
214     //** Function to fill the datalog with a full differential record.
b0eb45 215     public function datalogSave($db_table, $action, $primary_field, $primary_id, $record_old, $record_new, $force_update = false) {
f5b0ca 216       global $app,$conf;
N 217
218       // Insert backticks only for incomplete table names.
219       if(stristr($db_table,'.')) {
220     $escape = '';
221       } else {
222     $escape = '`';
223       }
224
b0eb45 225         if($force_update == true) {
T 226             //* We force a update even if no record has changed
227             $diffrec_full = array('new' => $record_new,'old' => $record_old);
228             $diff_num = count($record_new);
229         } else {
230             //* get the difference record between old and new record
231             $tmp = $this->diffrec($record_old, $record_new);
232             $diffrec_full = $tmp['diff_rec'];
233             $diff_num = $tmp['diff_num'];
234             unset($tmp);
235         }
f5b0ca 236
N 237       // Insert the server_id, if the record has a server_id
238       $server_id = (isset($record_old['server_id']) && $record_old['server_id'] > 0)?$record_old['server_id']:0;
239       if(isset($record_new['server_id'])) $server_id = $record_new['server_id'];
240
241
242       if($diff_num > 0) {
243     //print_r($diff_num);
244     //print_r($diffrec_full);
245     $diffstr = $app->db->quote(serialize($diffrec_full));
246     $username = $app->db->quote($_SESSION['s']['user']['username']);
247     $dbidx = $primary_field.':'.$primary_id;
248
249     if($action == 'INSERT') $action = 'i';
250     if($action == 'UPDATE') $action = 'u';
251     if($action == 'DELETE') $action = 'd';
252     $sql = "INSERT INTO sys_datalog (dbtable,dbidx,server_id,action,tstamp,user,data) VALUES ('".$db_table."','$dbidx','$server_id','$action','".time()."','$username','$diffstr')";
253     $app->db->query($sql);
254       }
255
256       return true;
257     }
258
259     //** Inserts a record and saves the changes into the datalog
260     public function datalogInsert($tablename, $insert_data, $index_field) {
261       global $app;
ee260d 262       
T 263       if(is_array($insert_data)) {
264             $key_str = '';
265             $val_str = '';
266             foreach($insert_data as $key => $val) {
267                 $key_str .= "`".$key ."`,";
268                 $val_str .= "'".$this->quote($val)."',";
269             }
b0eb45 270             $key_str = substr($key_str,0,-1);
T 271             $val_str = substr($val_str,0,-1);
ee260d 272             $insert_data_str = '('.$key_str.') VALUES ('.$val_str.')';
T 273         } else {
274             $insert_data_str = $insert_data;
275         }
f5b0ca 276
N 277       $old_rec = array();
ee260d 278       $this->query("INSERT INTO $tablename $insert_data_str");
f5b0ca 279       $index_value = $this->insertID();
N 280       $new_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
281       $this->datalogSave($tablename, 'INSERT', $index_field, $index_value, $old_rec, $new_rec);
282
283       return $index_value;
284     }
285
286     //** Updates a record and saves the changes into the datalog
c0f39a 287     public function datalogUpdate($tablename, $update_data, $index_field, $index_value, $force_update = false) {
ee260d 288         global $app;
c0f39a 289       
b0eb45 290       $old_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
ee260d 291       
T 292       if(is_array($update_data)) {
293             $update_data_str = '';
294             foreach($update_data as $key => $val) {
295                 $update_data_str .= "`".$key ."` = '".$this->quote($val)."',";
296             }
b0eb45 297             $update_data_str = substr($update_data_str,0,-1);
ee260d 298         } else {
T 299             $update_data_str = $update_data;
300         }
301         
f5b0ca 302       $this->query("UPDATE $tablename SET $update_data WHERE $index_field = '$index_value'");
N 303       $new_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
b0eb45 304       $this->datalogSave($tablename, 'UPDATE', $index_field, $index_value, $old_rec, $new_rec, $force_update);
f5b0ca 305
N 306       return true;
307     }
308
309     //** Deletes a record and saves the changes into the datalog
310     public function datalogDelete($tablename, $index_field, $index_value) {
311       global $app;
312
313       $old_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
314       $this->query("DELETE FROM $tablename WHERE $index_field = '$index_value'");
315       $new_rec = array();
316       $this->datalogSave($tablename, 'DELETE', $index_field, $index_value, $old_rec, $new_rec);
317
318       return true;
319     }
320
321
55da90 322     public function freeResult($query) 
e6c1c4 323     {
f5b0ca 324       if(is_object($query) && (get_class($query) == "mysqli_result")) {
N 325     $query->free();
326     return true;
327       } else {
328     return false;
329       }
e6c1c4 330     }
12fcb2 331
f5b0ca 332     /* TODO: Does anything use this? */
N 333     public function delete() {
b5a2f8 334
f5b0ca 335     }
N 336
337     /* TODO: Does anything use this? */
338     public function Transaction($action) {
339       //action = begin, commit oder rollback
340
341     }
342
343     /*
344        $columns = array(action =>   add | alter | drop
345        name =>     Spaltenname
346        name_new => neuer Spaltenname, nur bei 'alter' belegt
347        type =>     42go-Meta-Type: int16, int32, int64, double, char, varchar, text, blob
348        typeValue => Wert z.B. bei Varchar
349        defaultValue =>  Default Wert
350        notNull =>   true | false
351        autoInc =>   true | false
352        option =>   unique | primary | index)
353
354
355      */
356
357     public function createTable($table_name,$columns) {
358       $index = '';
359       $sql = "CREATE TABLE $table_name (";
360       foreach($columns as $col){
361     $sql .= $col['name'].' '.$this->mapType($col['type'],$col['typeValue']).' ';
362
363     if($col['defaultValue'] != '') $sql .= "DEFAULT '".$col['defaultValue']."' ";
364     if($col['notNull'] == true) {
365       $sql .= 'NOT NULL ';
366     } else {
367       $sql .= 'NULL ';
368     }
369     if($col['autoInc'] == true) $sql .= 'auto_increment ';
370     $sql.= ',';
371     // key Definitionen
372     if($col['option'] == 'primary') $index .= 'PRIMARY KEY ('.$col['name'].'),';
373     if($col['option'] == 'index') $index .= 'INDEX ('.$col['name'].'),';
374     if($col['option'] == 'unique') $index .= 'UNIQUE ('.$col['name'].'),';
375       }
376       $sql .= $index;
377       $sql = substr($sql,0,-1);
378       $sql .= ')';
379       $this->query($sql);
380       return true;
381     }
382
383     /*
384        $columns = array(action =>   add | alter | drop
385        name =>     Spaltenname
386        name_new => neuer Spaltenname, nur bei 'alter' belegt
387        type =>     42go-Meta-Type: int16, int32, int64, double, char, varchar, text, blob
388        typeValue => Wert z.B. bei Varchar
389        defaultValue =>  Default Wert
390        notNull =>   true | false
391        autoInc =>   true | false
392        option =>   unique | primary | index)
393
394
395      */
396     public function alterTable($table_name,$columns) {
397       $index = '';
398       $sql = "ALTER TABLE $table_name ";
399       foreach($columns as $col){
400     if($col['action'] == 'add') {
401       $sql .= 'ADD '.$col['name'].' '.$this->mapType($col['type'],$col['typeValue']).' ';
402     } elseif ($col['action'] == 'alter') {
403       $sql .= 'CHANGE '.$col['name'].' '.$col['name_new'].' '.$this->mapType($col['type'],$col['typeValue']).' ';
404     } elseif ($col['action'] == 'drop') {
405       $sql .= 'DROP '.$col['name'].' ';
406     }
407     if($col['action'] != 'drop') {  
408       if($col['defaultValue'] != '') $sql .= "DEFAULT '".$col['defaultValue']."' ";
409       if($col['notNull'] == true) {
410         $sql .= 'NOT NULL ';
411       } else {
412         $sql .= 'NULL ';
413       }
414       if($col['autoInc'] == true) $sql .= 'auto_increment ';
415       $sql.= ',';
416       // Index definitions
417       if($col['option'] == 'primary') $index .= 'PRIMARY KEY ('.$col['name'].'),';
418       if($col['option'] == 'index') $index .= 'INDEX ('.$col['name'].'),';
419       if($col['option'] == 'unique') $index .= 'UNIQUE ('.$col['name'].'),';
420     }
421       }
422       $sql .= $index;
423       $sql = substr($sql,0,-1);
424
425       //die($sql);
426       $this->query($sql);
427       return true;
428     }
429
430     public function dropTable($table_name) {
431       $this->check($table_name);
432       $sql = "DROP TABLE '". $table_name."'";
433       return $this->query($sql);
434     }
435
436     // gibt Array mit Tabellennamen zur�ck
437     public function getTables($database_name = '') {
438
439       if($database_name == '') $database_name = $this->dbName;
440       $result = parent::query("SHOW TABLES FROM $database_name");
441       for ($i = 0; $i < $result->num_rows; $i++) {
442     $tb_names[$i] = (($result->data_seek( $i) && (($___mysqli_tmp = $result->fetch_row()) !== NULL)) ? array_shift($___mysqli_tmp) : false);
443       }
444       return $tb_names;       
445     }
446
447     // gibt Feldinformationen zur Tabelle zur�ck
448     /*
449        $columns = array(action =>   add | alter | drop
450        name =>     Spaltenname
451        name_new => neuer Spaltenname, nur bei 'alter' belegt
452        type =>     42go-Meta-Type: int16, int32, int64, double, char, varchar, text, blob
453        typeValue => Wert z.B. bei Varchar
454        defaultValue =>  Default Wert
455        notNull =>   true | false
456        autoInc =>   true | false
457        option =>   unique | primary | index)
458
459
460      */
461
462     function tableInfo($table_name) {
463
464       global $go_api,$go_info;
465       // Tabellenfelder einlesen
466
467       if($rows = $go_api->db->queryAllRecords('SHOW FIELDS FROM '.$table_name)){
468     foreach($rows as $row) {
469       $name = $row[0];
470       $default = $row[4];
471       $key = $row[3];
472       $extra = $row[5];
473       $isnull = $row[2];
474       $type = $row[1];
475
476
477       $column = array();
478
479       $column['name'] = $name;
480       //$column['type'] = $type;
481       $column['defaultValue'] = $default;
482       if(stristr($key,'PRI')) $column['option'] = 'primary';
483       if(stristr($isnull,'YES')) {
484         $column['notNull'] = false;
485       } else {
486         $column['notNull'] = true; 
487       }
488       if($extra == 'auto_increment') $column['autoInc'] = true;
489
490
491       // Type in Metatype umsetzen
492
493       if(stristr($type,'int(')) $metaType = 'int32';
494           if(stristr($type,'bigint')) $metaType = 'int64';
495           if(stristr($type,'char')) {
496           $metaType = 'char';
497           $tmp_typeValue = explode('(',$type);
498           $column['typeValue'] = substr($tmp_typeValue[1],0,-1);  
499           }
500           if(stristr($type,'varchar')) {
501           $metaType = 'varchar';
502           $tmp_typeValue = explode('(',$type);
503           $column['typeValue'] = substr($tmp_typeValue[1],0,-1);  
504           }
505           if(stristr($type,'text')) $metaType = 'text';
506           if(stristr($type,'double')) $metaType = 'double';
507           if(stristr($type,'blob')) $metaType = 'blob';
508
509
510           $column['type'] = $metaType;
511
512           $columns[] = $column;
513           }
514     return $columns;
515       } else {
516     return false;
517       }
518
519
520       //$this->createTable('tester',$columns);
521
522       /*
523      $result = mysql_list_fields($go_info["server"]["db_name"],$table_name);
524      $fields = mysql_num_fields ($result);
525      $i = 0;
526      $table = mysql_field_table ($result, $i);
527      while ($i < $fields) {
528      $name  = mysql_field_name  ($result, $i);
529      $type  = mysql_field_type  ($result, $i);
530      $len   = mysql_field_len   ($result, $i);
531      $flags = mysql_field_flags ($result, $i);
532      print_r($flags);
533
534      $columns = array(name => $name,
535      type =>     "",
536      defaultValue =>  "",
537      isnull =>   1,
538      option =>   "");
539      $returnvar[] = $columns;
540
541      $i++;
542      }
543        */
544
545
546
547     }
548
549     public function mapType($metaType,$typeValue) {
550       global $go_api;
551       $metaType = strtolower($metaType);
552       switch ($metaType) {
553     case 'int16':
554       return 'smallint';
555       break;
556     case 'int32':
557       return 'int';
558       break;
559     case 'int64':
560       return 'bigint';
561       break;
562     case 'double':
563       return 'double';
564       break;
565     case 'char':
566       return 'char';
567       break;
568     case 'varchar':
569       if($typeValue < 1) die('Database failure: Lenght required for these data types.');
570       return 'varchar('.$typeValue.')';
571           break;
572           case 'text':
573           return 'text';
574           break;
575           case 'blob':
576           return 'blob';
577           break;
578           }
579           }
580
581           }
582
819fd7 583           ?>