tbrehm
2012-04-12 fddedde16a26a98e783047ab86751990ba833c7a
commit | author | age
b5a2f8 1 <?php
T 2 /*
436ed8 3 Copyright (c) 2007, Till Brehm, projektfarm Gmbh
b5a2f8 4 All rights reserved.
T 5
6 Redistribution and use in source and binary forms, with or without modification,
7 are permitted provided that the following conditions are met:
8
9     * Redistributions of source code must retain the above copyright notice,
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.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
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 */
29
436ed8 30 class db {
00dfba 31     private $dbHost = '';           // hostname of the MySQL server
R 32     private $dbName = '';           // logical database name on that server
33     private $dbUser = '';           // database authorized user
34     private $dbPass = '';           // user's password
12fcb2 35     private $dbCharset = '';       // what charset comes and goes to mysql: utf8 / latin1
c84a6d 36     private $dbNewLink = false;    // Return a new linkID when connect is called again
T 37     private $dbClientFlags = 0;    // MySQL Client falgs
00dfba 38     private $linkId = 0;           // last result of mysql_connect()
R 39     private $queryId = 0;           // last result of mysql_query()
40     private $record    = array();       // last record fetched
12fcb2 41     private $autoCommit = 1;        // Autocommit Transactions
00dfba 42     private $currentRow;           // current row number
R 43     private $errorNumber = 0;       // last error number
44     public $errorMessage = '';       // last error message
45     private $errorLocation = '';   // last error location
010876 46     public $show_error_messages = false;
b5a2f8 47
e6c1c4 48     public function __construct()
P 49     {
50         global $conf;
51         $this->dbHost = $conf['db_host'];
52         $this->dbName = $conf['db_database'];
53         $this->dbUser = $conf['db_user'];
54         $this->dbPass = $conf['db_password'];
00dfba 55         $this->dbCharset = $conf['db_charset'];
c84a6d 56         $this->dbNewLink = $conf['db_new_link'];
T 57         $this->dbClientFlags = $conf['db_client_flags'];
e6c1c4 58         //$this->connect();
P 59     }
60
61     /**  Error handler */
62     public function updateError($location)
63     {
64         $this->errorNumber = mysql_errno();
65         $this->errorMessage = mysql_error();
66         $this->errorLocation = $location;
67         if($this->errorNumber && $this->show_error_messages){
68             echo('<br /><b>'.$this->errorLocation.'</b><br />'.$this->errorMessage);
69             flush();
b5a2f8 70         }
e6c1c4 71     }
b5a2f8 72
e6c1c4 73     public function connect()
12fcb2 74     {
e6c1c4 75         if($this->linkId == 0){
c84a6d 76             $this->linkId = mysql_connect($this->dbHost, $this->dbUser, $this->dbPass, $this->dbNewLink, $this->dbClientFlags);
e6c1c4 77             if(!$this->linkId){
P 78                 $this->updateError('DB::connect()<br />mysql_connect');
b5a2f8 79                 return false;
T 80             }
00dfba 81             $this->queryId = @mysql_query('SET NAMES '.$this->dbCharset, $this->linkId);
e65b04 82             $this->queryId = @mysql_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."'", $this->linkId);
b5a2f8 83         }
e6c1c4 84         return true;
P 85     }
b5a2f8 86
e6c1c4 87     public function query($queryString)
12fcb2 88     {
e6c1c4 89         if(!$this->connect()){
P 90             return false;
b5a2f8 91         }
e6c1c4 92         if(!mysql_select_db($this->dbName, $this->linkId)){
P 93             $this->updateError('DB::connect()<br />mysql_select_db');
94             return false;
95         }
96         $this->queryId = @mysql_query($queryString, $this->linkId);
97         $this->updateError('DB::query('.$queryString.')<br />mysql_query');
98         if(!$this->queryId){
99             return false;
100         }
101         $this->currentRow = 0;
102         return $this->queryId;
103     }
b5a2f8 104
e6c1c4 105     /** Returns all records as an array */
P 106     public function queryAllRecords($queryString)
12fcb2 107     {
e6c1c4 108         if(!$this->query($queryString)){
P 109             return false;
b5a2f8 110         }
e6c1c4 111         $ret = array();
P 112         while($line = $this->nextRecord()){
113             $ret[] = $line;
114         }
115         return $ret;
116     }
b5a2f8 117
e6c1c4 118     /** Returns one row as an array */
P 119     public function queryOneRecord($queryString)
12fcb2 120     {
e6c1c4 121         if(!$this->query($queryString) || $this->numRows() == 0){
P 122             return false;
b5a2f8 123         }
e6c1c4 124         return $this->nextRecord();
P 125     }
b5a2f8 126
e6c1c4 127     /** Returns the next record as an array */
P 128     public function nextRecord()
12fcb2 129     {
J 130     $this->record = mysql_fetch_assoc($this->queryId);
e6c1c4 131         $this->updateError('DB::nextRecord()<br />mysql_fetch_array');
P 132         if(!$this->record || !is_array($this->record)){
133             return false;
b5a2f8 134         }
e6c1c4 135         $this->currentRow++;
P 136         return $this->record;
137     }
138
139     /** Returns the number of rows returned by the last select query */
140     public function numRows()
141     {
142         return mysql_num_rows($this->queryId);
143     }
144
145     public function affectedRows()
146     {
147         return mysql_affected_rows($this->linkId);
148     }
b5a2f8 149         
e6c1c4 150     /** Returns the last mySQL insert_id() */
P 151     public function insertID()
12fcb2 152     {
e6c1c4 153         return mysql_insert_id($this->linkId);
P 154     }
b5a2f8 155         
e6c1c4 156     /** Checks a variable - Depreciated, use quote() */
P 157     public function check($formfield)
158     {
159         return $this->quote($formfield);
160     }
b5a2f8 161         
8500be 162     /** Escapes quotes in variable. mysql_real_escape_string() */
e6c1c4 163     public function quote($formfield)
8500be 164     {    
T 165         if(!$this->connect()){
166             $this->updateError('WARNING: mysql_connect: Used addslashes instead of mysql_real_escape_string');
167             return addslashes($formfield);
168         }
169         return mysql_real_escape_string($formfield, $this->linkId);
e6c1c4 170     }
b5a2f8 171         
e6c1c4 172     /** Unquotes a variable, strip_slashes() */
P 173     public function unquote($formfield)
174     {
175         return stripslashes($formfield);
176     }
b5a2f8 177         
e6c1c4 178     public function toLower($record)
P 179     {
180         if(is_array($record)){
181             foreach($record as $key => $val) {
182                 $key = strtolower($key);
183                 $out[$key] = $val;
b5a2f8 184             }
T 185         }
e6c1c4 186         return $out;
P 187     }
b5a2f8 188        
430a0f 189     // deprecated
T 190     /*
e6c1c4 191     public function insert($tablename, $form, $debug = 0)
P 192     {
193         if(is_array($form)){
194             foreach($form as $key => $value){
195                 $sql_key .= "$key, ";
196                 $sql_value .= "'".$this->check($value)."', ";
197             }
198             $sql_key = substr($sql_key,0,strlen($sql_key) - 2);
199             $sql_value = substr($sql_value,0,strlen($sql_value) - 2);
200             $sql = "INSERT INTO $tablename (".$sql_key.') VALUES ('.$sql_value.')';
201             //TODO: where has $debug come from !???
202             if($debug == 1){ echo "SQL-Statement: $sql<br><br>"; }
203             $this->query($sql);
204             if($debug == 1){ echo 'mySQL Error Message: '.$this->errorMessage; }
205         }
206     }
430a0f 207     
T 208     // Deprecated
e6c1c4 209     public function update($tablename, $form, $bedingung, $debug = 0)
P 210     {
211         if(is_array($form)){
212             foreach($form as $key => $value){
213                 $insql .= "$key = '".$this->check($value)."', ";
214             }
215             $insql = substr($insql, 0, strlen($insql) - 2);
216             $sql = "UPDATE $tablename SET " . $insql . " WHERE $bedingung";
217             if($debug == 1){ echo "SQL-Statement: $sql<br><br>"; }
218             $this->query($sql);
219             if($debug == 1){ echo 'mySQL Error Message: '.$this->errorMessage; }
220         }
221     }
430a0f 222     */
12fcb2 223
74829e 224     public function diffrec($record_old, $record_new) {
958705 225         $diffrec_full = array();
T 226         $diff_num = 0;
227
228         if(is_array($record_old) && count($record_old) > 0) {
229             foreach($record_old as $key => $val) {
74829e 230                 // if(!isset($record_new[$key]) || $record_new[$key] != $val) {
T 231                 if($record_new[$key] != $val) {
958705 232                     // Record has changed
T 233                     $diffrec_full['old'][$key] = $val;
234                     $diffrec_full['new'][$key] = $record_new[$key];
235                     $diff_num++;
236                 } else {
237                     $diffrec_full['old'][$key] = $val;
238                     $diffrec_full['new'][$key] = $val;
239                 }
240             }
241         } elseif(is_array($record_new)) {
242             foreach($record_new as $key => $val) {
8065e0 243                 if(isset($record_new[$key]) && @$record_old[$key] != $val) {
958705 244                     // Record has changed
T 245                     $diffrec_full['new'][$key] = $val;
8065e0 246                     $diffrec_full['old'][$key] = @$record_old[$key];
958705 247                     $diff_num++;
T 248                 } else {
249                     $diffrec_full['new'][$key] = $val;
250                     $diffrec_full['old'][$key] = $val;
251                 }
252             }
253         }
254         
74829e 255         return array('diff_num' => $diff_num, 'diff_rec' => $diffrec_full);
T 256         
257     }
258     
259     //** Function to fill the datalog with a full differential record.
260     public function datalogSave($db_table, $action, $primary_field, $primary_id, $record_old, $record_new) {
261         global $app,$conf;
262
263         // Insert backticks only for incomplete table names.
264         if(stristr($db_table,'.')) {
265             $escape = '';
266         } else {
267             $escape = '`';
268         }
269
270         $tmp = $this->diffrec($record_old, $record_new);
271         $diffrec_full = $tmp['diff_rec'];
272         $diff_num = $tmp['diff_num'];
273         unset($tmp);
274         
958705 275         // Insert the server_id, if the record has a server_id
12fcb2 276         $server_id = (isset($record_old['server_id']) && $record_old['server_id'] > 0)?$record_old['server_id']:0;
J 277         if(isset($record_new['server_id'])) $server_id = $record_new['server_id'];
430a0f 278         
958705 279
T 280         if($diff_num > 0) {
74829e 281             //print_r($diff_num);
T 282             //print_r($diffrec_full);
958705 283             $diffstr = $app->db->quote(serialize($diffrec_full));
12fcb2 284             $username = $app->db->quote($_SESSION['s']['user']['username']);
J 285             $dbidx = $primary_field.':'.$primary_id;
958705 286                         
T 287             if($action == 'INSERT') $action = 'i';
288             if($action == 'UPDATE') $action = 'u';
289             if($action == 'DELETE') $action = 'd';
290             $sql = "INSERT INTO sys_datalog (dbtable,dbidx,server_id,action,tstamp,user,data) VALUES ('".$db_table."','$dbidx','$server_id','$action','".time()."','$username','$diffstr')";
291             $app->db->query($sql);
292         }
293
294         return true;
295     }
296     
eea5cf 297     //** Inserts a record and saves the changes into the datalog
430a0f 298     public function datalogInsert($tablename, $insert_data, $index_field) {
T 299         global $app;
300         
301         $old_rec = array();
302         $this->query("INSERT INTO $tablename $insert_data");
303         $index_value = $this->insertID();
304         $new_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
305         $this->datalogSave($tablename, 'INSERT', $index_field, $index_value, $old_rec, $new_rec);
306         
13d323 307         return $index_value;
430a0f 308     }
T 309     
310     //** Updates a record and saves the changes into the datalog
fddedd 311     public function datalogUpdate($tablename, $update_data, $index_field, $index_value, $force_update = false) {
958705 312         global $app;
T 313         
fddedd 314         if($force_update == true) {
T 315             $old_rec = array();
316         } else {
317             $old_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
318         }
958705 319         $this->query("UPDATE $tablename SET $update_data WHERE $index_field = '$index_value'");
T 320         $new_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
321         $this->datalogSave($tablename, 'UPDATE', $index_field, $index_value, $old_rec, $new_rec);
322         
323         return true;
324     }
430a0f 325     
T 326     //** Deletes a record and saves the changes into the datalog
327     public function datalogDelete($tablename, $index_field, $index_value) {
328         global $app;
329         
330         $old_rec = $this->queryOneRecord("SELECT * FROM $tablename WHERE $index_field = '$index_value'");
331         $this->query("DELETE FROM $tablename WHERE $index_field = '$index_value'");
332         $new_rec = array();
333         $this->datalogSave($tablename, 'DELETE', $index_field, $index_value, $old_rec, $new_rec);
334         
335         return true;
336     }
12fcb2 337
J 338
b5a2f8 339        
e6c1c4 340     public function closeConn()
P 341     {
55da90 342         if($this->linkId)
B 343         {
344             mysql_close($this->linkId);
345             return true;
346         } else { return false; }
e6c1c4 347     }
12fcb2 348     
55da90 349     public function freeResult($query) 
e6c1c4 350     {
55da90 351         if(mysql_free_result($query))
B 352         {
353             return true;
354         } else {
355             return false;
356         }
e6c1c4 357     }
430a0f 358     
T 359     /*
e6c1c4 360     public function delete()
P 361     {
362     }
430a0f 363     */
T 364     
365     /*
e6c1c4 366     public function Transaction($action)
P 367     {
368         //action = begin, commit oder rollback
369     }
430a0f 370     */
e6c1c4 371     
P 372     /** Creates a database table with the following format for the $columns array   
373     * <code>
374     * $columns = array(action =>   add | alter | drop
375     *                  name =>     Spaltenname
376     *                  name_new => neuer Spaltenname, nur bei 'alter' belegt
377     *                  type =>     42go-Meta-Type: int16, int32, int64, double, char, varchar, text, blob
378     *                  typeValue => Wert z.B. bei Varchar
379     *                  defaultValue =>  Default Wert
380     *                  notNull =>   true | false
381     *                  autoInc =>   true | false
382     *                  option =>   unique | primary | index)
383     * </code>   
384     */
430a0f 385     
T 386     
e6c1c4 387     public function createTable($table_name, $columns)
P 388     {
389         $index = '';
390         $sql = "CREATE TABLE $table_name (";
391         foreach($columns as $col){
392             $sql .= $col['name'].' '.$this->mapType($col['type'], $col['typeValue']).' ';
393             //* Set default value
010876 394             if(isset($col['defaultValue']) && $col['defaultValue'] != '') {
e6c1c4 395                 if($col['defaultValue'] == 'NULL' or $col['defaultValue'] == 'NOT NULL') {
P 396                     $sql .= 'DEFAULT '.$col['defaultValue'].' ';
397                 } else {
398                     $sql .= "DEFAULT '".$col['defaultValue']."' ";
399                 }
400             } elseif($col['defaultValue'] != false) {
401                 $sql .= "DEFAULT '' ";
402             }
010876 403             if(isset($col['defaultValue']) && $col['defaultValue'] != 'NULL' && $col['defaultValue'] != 'NOT NULL') {
e6c1c4 404                 if($col['notNull'] == true) {
P 405                     $sql .= 'NOT NULL ';
406                 } else {
407                     $sql .= 'NULL ';
408                 }
409             }
010876 410             if(isset($col['autoInc']) && $col['autoInc'] == true){ $sql .= 'auto_increment '; }
e6c1c4 411             $sql.= ',';
P 412             //* Index Definitions
010876 413             if(isset($col['option']) && $col['option'] == 'primary'){ $index .= 'PRIMARY KEY ('.$col['name'].'),'; }
T 414             if(isset($col['option']) && $col['option'] == 'index'){   $index .= 'INDEX ('.$col['name'].'),'; }
415             if(isset($col['option']) && $col['option'] == 'unique'){  $index .= 'UNIQUE ('.$col['name'].'),'; }
12fcb2 416        }
b5a2f8 417        $sql .= $index;
T 418        $sql = substr($sql,0,-1);
12fcb2 419        $sql .= ')';
b5a2f8 420        $this->query($sql);
T 421        return true;
e6c1c4 422     }
b5a2f8 423        
e6c1c4 424     /** Changes a table definition. The format for the $columns array is 
P 425     * <code>
426     * $columns = array(action =>   add | alter | drop
427     *                  name =>     Spaltenname
428     *                 name_new => neuer Spaltenname, nur bei 'alter' belegt
429     *                 type =>     42go-Meta-Type: int16, int32, int64, double, char, varchar, text, blob
430     *                 typeValue => Wert z.B. bei Varchar
431     *                 defaultValue =>  Default Wert
432     *                 notNull =>   true | false
433     *                 autoInc =>   true | false
434     *                 option =>   unique | primary | index)
435     */
436     public function alterTable($table_name,$columns)
437     {
12fcb2 438        $index = '';
J 439        $sql = "ALTER TABLE $table_name ";
440        foreach($columns as $col){
e6c1c4 441             if($col['action'] == 'add'){
12fcb2 442                 $sql .= 'ADD '.$col['name'].' '.$this->mapType($col['type'],$col['typeValue']).' ';
e6c1c4 443             }elseif($col['action'] == 'alter') {
P 444                 $sql .= 'CHANGE '.$col['name'].' '.$col['name_new'].' '.$this->mapType($col['type'],$col['typeValue']).' ';
445             }elseif($col['action'] == 'drop') {
446                 $sql .= 'DROP '.$col['name'].' ';
b5a2f8 447             }
12fcb2 448             if($col['action'] != 'drop') {  
J 449             if($col['defaultValue'] != '') $sql .= "DEFAULT '".$col['defaultValue']."' ";
450             if($col['notNull'] == true) {
451                 $sql .= 'NOT NULL ';
b5a2f8 452             } else {
12fcb2 453                 $sql .= 'NULL ';
b5a2f8 454             }
12fcb2 455             if($col['autoInc'] == true) $sql .= 'auto_increment ';
J 456             $sql.= ',';
e6c1c4 457             //* Index definitions
P 458             if($col['option'] == 'primary') $index .= 'PRIMARY KEY ('.$col['name'].'),';
459             if($col['option'] == 'index') $index .= 'INDEX ('.$col['name'].'),';
460             if($col['option'] == 'unique') $index .= 'UNIQUE ('.$col['name'].'),';
b5a2f8 461             }
12fcb2 462        }
J 463        $sql .= $index;
464        $sql = substr($sql,0,-1);
465        //die($sql);
466        $this->query($sql);
467        return true;
e6c1c4 468     }
b5a2f8 469        
e6c1c4 470     public function dropTable($table_name) 
P 471     {
472         $this->check($table_name);
473         $sql = "DROP TABLE '". $table_name."'";
474         return $this->query($sql);
475     }
b5a2f8 476        
e6c1c4 477     /** Return an array of table names */
P 478     public function getTables($database_name = '')
479     {
480         if($database_name == ''){
481             $database_name = $this->dbName;
482         }
92bc67 483         $result = @mysql_list_tables($database_name);
e6c1c4 484         $tb_names = array();
92bc67 485         for ($i = 0; $i < @mysql_num_rows($result); $i++) {
T 486             $tb_names[$i] = @mysql_tablename($result, $i);
e6c1c4 487         }
P 488         return $tb_names;       
489     }
b5a2f8 490        
T 491        
e6c1c4 492     public function tableInfo($table_name) {
P 493         //* Tabellenfelder einlesen ?
fb3a98 494         if($rows = $this->queryAllRecords('SHOW FIELDS FROM '.$table_name)){
b5a2f8 495         foreach($rows as $row) {
07ba80 496             $name    = $row['Field'];
T 497             $default = $row['Default'];
498             $key     = $row['Key'];
499             $extra   = $row['Extra'];
500             $isnull  = $row['Null'];
501             $type    = $row['Type'];
b5a2f8 502         
e6c1c4 503             $column = array('name' => $name, 'defaultValue' => $default);
b5a2f8 504             //$column["type"] = $type;
e6c1c4 505             if(stristr($key, 'PRI')){ $column['option'] = 'primary'; }
P 506             $column['notNull'] = stristr($isnull,'YES') ? false : true;
507             if($extra == 'auto_increment'){ $column['autoInc'] = true; }         
b5a2f8 508             
e6c1c4 509             //* Get the Data and Metatype
P 510             if( stristr($type, 'int(') ){    $metaType = 'int32'; }
511             if( stristr($type, 'bigint') ){  $metaType = 'int64'; }
512             if( stristr($type, 'char') ) {
b5a2f8 513                 $metaType = 'char';
T 514                 $tmp_typeValue = explode('(',$type);
e6c1c4 515                 $column['typeValue'] = substr($tmp_typeValue[1], 0, -1);  
b5a2f8 516             }
e6c1c4 517             if( stristr($type, 'varchar') ){
b5a2f8 518                 $metaType = 'varchar';
T 519                 $tmp_typeValue = explode('(',$type);
e6c1c4 520                 $column['typeValue'] = substr($tmp_typeValue[1], 0, -1);  
b5a2f8 521             }
12fcb2 522             if(stristr($type,'text'))   $metaType = 'text';
J 523             if(stristr($type,'double')) $metaType = 'double';
524             if(stristr($type,'blob'))   $metaType = 'blob';
b5a2f8 525             
e6c1c4 526             $column['type'] = $metaType;
P 527             $columns[] = $column;
b5a2f8 528         }
T 529             return $columns;
530         } else {
531             return false;
532         }
e6c1c4 533     }
b5a2f8 534        
e6c1c4 535     public function mapType($metaType, $typeValue) {
P 536         //TODO: ? this is not required ?? global $go_api;
537         $metaType = strtolower($metaType);
538         switch ($metaType) {
539         case 'int16':
b5a2f8 540             return 'smallint';
e6c1c4 541         case 'int32':
b5a2f8 542             return 'int';
e6c1c4 543         case 'int64':
b5a2f8 544             return 'bigint';
e6c1c4 545         case 'double':
b5a2f8 546             return 'double';
e6c1c4 547         case 'char':
b5a2f8 548             return 'char';
e6c1c4 549         case 'varchar':
P 550             if($typeValue < 1) die('Datenbank Fehler: F�r diesen Datentyp ist eine L�ngenangabe notwendig.');
b5a2f8 551             return 'varchar('.$typeValue.')';
e6c1c4 552         case 'text':
b5a2f8 553             return 'text';
e6c1c4 554         case 'blob':
b5a2f8 555             return 'blob';
e6c1c4 556         }
P 557     }
12fcb2 558
e6c1c4 559 }
b5a2f8 560
12fcb2 561 ?>