Michel Käser
2015-05-16 82e9b9e7c7ecf1664a7b0d4e57a5c4893739559d
commit | author | age
87a4a6 1 <?php
T 2 /*
f5b0ca 3    Copyright (c) 2005, Till Brehm, projektfarm Gmbh
N 4    All rights reserved.
87a4a6 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:
87a4a6 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.
87a4a6 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  */
87a4a6 29
f5b0ca 30 class db extends mysqli
N 31 {
cd8bb8 32     /**#@+
MC 33      * @access private
34      */
35     private $_iQueryId;
36     private $_iConnId;
37
38     private $dbHost = '';  // hostname of the MySQL server
82e9b9 39     private $dbPort = '';  // port of the MySQL server
b1a6a5 40     private $dbName = '';  // logical database name on that server
MC 41     private $dbUser = '';  // database authorized user
42     private $dbPass = '';  // user's password
43     private $dbCharset = 'utf8';// Database charset
44     private $dbNewLink = false; // Return a new linkID when connect is called again
45     private $dbClientFlags = 0; // MySQL Client falgs
cd8bb8 46     /**#@-*/
MC 47
48     public $show_error_messages = false; // false in server, true in interface
49
50
51     /* old things - unused now ////
b1a6a5 52     private $linkId = 0;  // last result of mysqli_connect()
MC 53     private $queryId = 0;  // last result of mysqli_query()
54     private $record = array(); // last record fetched
55     private $autoCommit = 1;    // Autocommit Transactions
56     private $currentRow;  // current row number
57     public $errorNumber = 0; // last error number
58     public $errorMessage = ''; // last error message
59     private $errorLocation = '';// last error location
60     private $isConnected = false; // needed to know if we have a valid mysqli object from the constructor
cd8bb8 61     ////
MC 62     */
87a4a6 63
b1a6a5 64     // constructor
82e9b9 65     public function __construct($host = NULL , $user = NULL, $pass = NULL, $database = NULL, $port = NULL) {
b1a6a5 66         global $app, $conf;
1d8f7f 67
b1a6a5 68         $this->dbHost = $host ? $host  : $conf['db_host'];
82e9b9 69         $this->dbPort = $port ? $port : $conf['db_port'];
b1a6a5 70         $this->dbName = $database ? $database : $conf['db_database'];
MC 71         $this->dbUser = $user ? $user : $conf['db_user'];
72         $this->dbPass = $pass ? $pass : $conf['db_password'];
73         $this->dbCharset = $conf['db_charset'];
74         $this->dbNewLink = $conf['db_new_link'];
75         $this->dbClientFlags = $conf['db_client_flags'];
1d8f7f 76
82e9b9 77         $this->_iConnId = mysqli_connect($this->dbHost, $this->dbUser, $this->dbPass, (int)$this->dbPort);
b1a6a5 78         $try = 0;
cd8bb8 79         while((!is_object($this->_iConnId) || mysqli_connect_error()) && $try < 5) {
MC 80             if($try > 0) sleep(1);
f5b0ca 81
b1a6a5 82             $try++;
82e9b9 83             $this->_iConnId = mysqli_connect($this->dbHost, $this->dbUser, $this->dbPass, (int)$this->dbPort);
b1a6a5 84         }
f5b0ca 85
cd8bb8 86         if(!is_object($this->_iConnId) || mysqli_connect_error()) {
MC 87             $this->_iConnId = null;
88             $this->_sqlerror('Zugriff auf Datenbankserver fehlgeschlagen! / Database server not accessible!');
89             return false;
90         }
ccfc84 91         if(!((bool)mysqli_query( $this->_iConnId, 'USE `' . $this->dbName . '`'))) {
cd8bb8 92             $this->close();
MC 93             $this->_sqlerror('Datenbank nicht gefunden / Database not found');
94             return false;
95         }
f5b0ca 96
cd8bb8 97         $this->_setCharset();
b1a6a5 98     }
MC 99
100     public function __destruct() {
cd8bb8 101         if($this->_iConnId) mysqli_close($this->_iConnId);
MC 102     }
103
104     public function close() {
105         if($this->_iConnId) mysqli_close($this->_iConnId);
106         $this->_iConnId = null;
b1a6a5 107     }
MC 108
109     /* This allows our private variables to be "read" out side of the class */
110     public function __get($var) {
111         return isset($this->$var) ? $this->$var : NULL;
112     }
113
cd8bb8 114     public function _build_query_string($sQuery = '') {
MC 115         $iArgs = func_num_args();
116         if($iArgs > 1) {
117             $aArgs = func_get_args();
b1a6a5 118
cd8bb8 119             if($iArgs == 3 && $aArgs[1] === true && is_array($aArgs[2])) {
MC 120                 $aArgs = $aArgs[2];
121                 $iArgs = count($aArgs);
122             } else {
123                 array_shift($aArgs); // delete the query string that is the first arg!
124             }
f5b0ca 125
cd8bb8 126             $iPos = 0;
MC 127             $iPos2 = 0;
128             foreach($aArgs as $sKey => $sValue) {
129                 $iPos2 = strpos($sQuery, '??', $iPos2);
130                 $iPos = strpos($sQuery, '?', $iPos);
131
132                 if($iPos === false && $iPos2 === false) break;
133
134                 if($iPos2 !== false && ($iPos === false || $iPos2 <= $iPos)) {
135                     $sTxt = $this->escape($sValue);
136
d7fe4d 137                     if(strpos($sTxt, '.') !== false) {
MC 138                         $sTxt = preg_replace('/^(.+)\.(.+)$/', '`$1`.`$2`', $sTxt);
139                         $sTxt = str_replace('.`*`', '.*', $sTxt);
140                     } else $sTxt = '`' . $sTxt . '`';
cd8bb8 141
MC 142                     $sQuery = substr_replace($sQuery, $sTxt, $iPos2, 2);
143                     $iPos2 += strlen($sTxt);
144                     $iPos = $iPos2;
b1a6a5 145                 } else {
cd8bb8 146                     if(is_int($sValue) || is_float($sValue)) {
MC 147                         $sTxt = $sValue;
3a11d2 148                     } elseif(is_null($sValue) || (is_string($sValue) && (strcmp($sValue, '#NULL#') == 0))) {
cd8bb8 149                         $sTxt = 'NULL';
MC 150                     } elseif(is_array($sValue)) {
3a11d2 151                         if(isset($sValue['SQL'])) {
MC 152                             $sTxt = $sValue['SQL'];
153                         } else {
154                             $sTxt = '';
155                             foreach($sValue as $sVal) $sTxt .= ',\'' . $this->escape($sVal) . '\'';
156                             $sTxt = '(' . substr($sTxt, 1) . ')';
157                             if($sTxt == '()') $sTxt = '(0)';
158                         }
cd8bb8 159                     } else {
MC 160                         $sTxt = '\'' . $this->escape($sValue) . '\'';
161                     }
162
163                     $sQuery = substr_replace($sQuery, $sTxt, $iPos, 1);
164                     $iPos += strlen($sTxt);
165                     $iPos2 = $iPos;
166                 }
b1a6a5 167             }
MC 168         }
cd8bb8 169
MC 170         return $sQuery;
f5b0ca 171     }
b1a6a5 172
cd8bb8 173     /**#@-*/
MC 174
175
176     /**#@+
177      * @access private
178      */
179     private function _setCharset() {
180         mysqli_query($this->_iConnId, 'SET NAMES '.$this->dbCharset);
181         mysqli_query($this->_iConnId, "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."'");
f5b0ca 182     }
N 183
cd8bb8 184     private function _query($sQuery = '') {
MC 185         global $app;
186
a4a4ea 187         //if($this->isConnected == false) return false;
cd8bb8 188         if ($sQuery == '') {
MC 189             $this->_sqlerror('Keine Anfrage angegeben / No query given');
190             return false;
191         }
192
b1a6a5 193         $try = 0;
MC 194         do {
195             $try++;
cd8bb8 196             $ok = mysqli_ping($this->_iConnId);
b1a6a5 197             if(!$ok) {
82e9b9 198                 if(!mysqli_connect($this->dbHost, $this->dbUser, $this->dbPass, $this->dbName, (int)$this->dbPort)) {
132081 199                     if($this->errorNumber == '111') {
MC 200                         // server is not available
201                         if($try > 9) {
202                             if(isset($app) && isset($app->forceErrorExit)) {
203                                 $app->forceErrorExit('Database connection failure!');
204                             }
205                             // if we reach this, the app object is missing or has no exit method, so we continue as normal
206                         }
207                         sleep(30); // additional seconds, please!
208                     }
209
b1a6a5 210                     if($try > 9) {
cd8bb8 211                         $this->_sqlerror('DB::query -> reconnect');
b1a6a5 212                         return false;
MC 213                     } else {
214                         sleep(($try > 7 ? 5 : 1));
215                     }
216                 } else {
cd8bb8 217                     $this->_setCharset();
b1a6a5 218                     $ok = true;
MC 219                 }
220             }
221         } while($ok == false);
cd8bb8 222
MC 223         $aArgs = func_get_args();
224         $sQuery = call_user_func_array(array(&$this, '_build_query_string'), $aArgs);
225
226         $this->_iQueryId = mysqli_query($this->_iConnId, $sQuery);
227         if (!$this->_iQueryId) {
228             $this->_sqlerror('Falsche Anfrage / Wrong Query', false, 'SQL-Query = ' . $sQuery);
b1a6a5 229             return false;
MC 230         }
cd8bb8 231
MC 232         return is_bool($this->_iQueryId) ? $this->_iQueryId : new db_result($this->_iQueryId, $this->_iConnId);
b1a6a5 233     }
f5b0ca 234
cd8bb8 235     /**#@-*/
MC 236
237
238
239
240
241     /**
242      * Executes a query
243      *
244      * Executes a given query string, has a variable amount of parameters:
245      * - 1 parameter
246      *   executes the given query
247      * - 2 parameters
248      *   executes the given query, replaces the first ? in the query with the second parameter
249      * - 3 parameters
250      *   if the 2nd parameter is a boolean true, the 3rd parameter has to be an array containing all the replacements for every occuring ? in the query, otherwise the second parameter replaces the first ?, the third parameter replaces the second ? in the query
251      * - 4 or more parameters
252      *   all ? in the query are replaced from left to right by the parameters 2 to x
253      *
254      * @access public
255      * @param string  $sQuery query string
256      * @param mixed   ... one or more parameters
257      * @return db_result the result object of the query
258      */
259
260
261     public function query($sQuery = '') {
262         $aArgs = func_get_args();
263         return call_user_func_array(array(&$this, '_query'), $aArgs);
b1a6a5 264     }
43b345 265
cd8bb8 266     /**
MC 267      * Execute a query and get first result array
268      *
269      * Executes a query and returns the first result row as an array
270      * This is like calling $result = $db->query(),  $result->get(), $result->free()
271      * Use of this function @see query
272      *
273      * @access public
274      * @param string  $sQuery query to execute
275      * @param ...     further params (see query())
276      * @return array result row or NULL if none found
277      */
278     public function queryOneRecord($sQuery = '') {
279         if(!preg_match('/limit \d+\s*,\s*\d+$/i', $sQuery)) $sQuery .= ' LIMIT 0,1';
280
281         $aArgs = func_get_args();
282         $oResult = call_user_func_array(array(&$this, 'query'), $aArgs);
283         if(!$oResult) return null;
284
285         $aReturn = $oResult->get();
286         $oResult->free();
287
288         return $aReturn;
b1a6a5 289     }
21c641 290
cd8bb8 291     public function queryOne($sQuery = '') {
7ae5b0 292         return call_user_func_array(array(&$this, 'queryOneRecord'), func_get_args());
b1a6a5 293     }
f5b0ca 294
cd8bb8 295     public function query_one($sQuery = '') {
7ae5b0 296         return call_user_func_array(array(&$this, 'queryOneRecord'), func_get_args());
cd8bb8 297     }
MC 298
299     /**
300      * Execute a query and return all rows
301      *
302      * Executes a query and returns all result rows in an array
303      * <strong>Use this with extreme care!!!</strong> Uses lots of memory on big result sets.
304      *
305      * @access public
306      * @param string  $sQuery query to execute
307      * @param ...     further params (see query())
308      * @return array all the rows in the result set
309      */
310     public function queryAllRecords($sQuery = '') {
311         $aArgs = func_get_args();
312         $oResult = call_user_func_array(array(&$this, 'query'), $aArgs);
313         if(!$oResult) return array();
314
315         $aResults = array();
316         while($aRow = $oResult->get()) {
317             $aResults[] = $aRow;
318         }
319         $oResult->free();
320
321         return $aResults;
322     }
323
324     public function queryAll($sQuery = '') {
7ae5b0 325         return call_user_func_array(array(&$this, 'queryAllRecords'), func_get_args());
cd8bb8 326     }
MC 327
328     public function query_all($sQuery = '') {
7ae5b0 329         return call_user_func_array(array(&$this, 'queryAllRecords'), func_get_args());
cd8bb8 330     }
MC 331
332     /**
333      * Execute a query and return all rows as simple array
334      *
335      * Executes a query and returns all result rows in an array with elements
336      * <strong>Only first column is returned</strong> Uses lots of memory on big result sets.
337      *
338      * @access public
339      * @param string  $sQuery query to execute
340      * @param ...     further params (see query())
341      * @return array all the rows in the result set
342      */
343     public function queryAllArray($sQuery = '') {
344         $aArgs = func_get_args();
345         $oResult = call_user_func_array(array(&$this, 'query'), $aArgs);
346         if(!$oResult) return array();
347
348         $aResults = array();
349         while($aRow = $oResult->get()) {
350             $aResults[] = reset($aRow);
351         }
352         $oResult->free();
353
354         return $aResults;
355     }
356
357     public function query_all_array($sQuery = '') {
7ae5b0 358         return call_user_func_array(array(&$this, 'queryAllArray'), func_get_args());
cd8bb8 359     }
MC 360
361
362
363     /**
364      * Get id of last inserted row
365      *
366      * Gives you the id of the last inserted row in a table with an auto-increment primary key
367      *
368      * @access public
369      * @return int id of last inserted row or 0 if none
370      */
371     public function insert_id() {
372         $iRes = mysqli_query($this->_iConnId, 'SELECT LAST_INSERT_ID() as `newid`');
373         if(!is_object($iRes)) return false;
374
375         $aReturn = mysqli_fetch_assoc($iRes);
376         mysqli_free_result($iRes);
377
378         return $aReturn['newid'];
379     }
380
381
382
383     /**
384      * get affected row count
385      *
386      * Gets the amount of rows affected by the previous query
387      *
388      * @access public
389      * @return int affected rows
390      */
391     public function affected() {
392         if(!is_object($this->_iConnId)) return 0;
393         $iRows = mysqli_affected_rows($this->_iConnId);
394         if(!$iRows) $iRows = 0;
395         return $iRows;
396     }
397
398
399
400     /**
385f54 401      * check if a utf8 string is valid
MC 402      *
403      * @access public
404      * @param string  $string the string to check
405      * @return bool true if it is valid utf8, false otherwise
406      */
407     private function check_utf8($str) {
408         $len = strlen($str);
409         for($i = 0; $i < $len; $i++){
410             $c = ord($str[$i]);
411             if ($c > 128) {
412                 if (($c > 247)) return false;
413                 elseif ($c > 239) $bytes = 4;
414                 elseif ($c > 223) $bytes = 3;
415                 elseif ($c > 191) $bytes = 2;
416                 else return false;
417                 if (($i + $bytes) > $len) return false;
418                 while ($bytes > 1) {
419                     $i++;
420                     $b = ord($str[$i]);
421                     if ($b < 128 || $b > 191) return false;
422                     $bytes--;
423                 }
424             }
425         }
426         return true;
427     } // end of check_utf8
428
429     /**
cd8bb8 430      * Escape a string for usage in a query
MC 431      *
432      * @access public
433      * @param string  $sString query string to escape
434      * @return string escaped string
435      */
436     public function escape($sString) {
437         global $app;
438         if(!is_string($sString) && !is_numeric($sString)) {
439             $app->log('NON-String given in escape function! (' . gettype($sString) . ')', LOGLEVEL_INFO);
563649 440             //$sAddMsg = getDebugBacktrace();
cd8bb8 441             $app->log($sAddMsg, LOGLEVEL_DEBUG);
MC 442             $sString = '';
443         }
444
385f54 445         $cur_encoding = mb_detect_encoding($sString);
cd8bb8 446         if($cur_encoding != "UTF-8") {
MC 447             if($cur_encoding != 'ASCII') {
385f54 448                 $app->log('String ' . substr($sString, 0, 25) . '... is ' . $cur_encoding . '.', LOGLEVEL_INFO);
cd8bb8 449                 if($cur_encoding) $sString = mb_convert_encoding($sString, 'UTF-8', $cur_encoding);
MC 450                 else $sString = mb_convert_encoding($sString, 'UTF-8');
451             }
385f54 452         } elseif(!$this->check_utf8($sString)) {
cd8bb8 453             $sString = utf8_encode($sString);
385f54 454         }
cd8bb8 455
MC 456         if($this->_iConnId) return mysqli_real_escape_string($this->_iConnId, $sString);
457         else return addslashes($sString);
458     }
459
460     /**
461      *
462      *
463      * @access private
464      */
465     private function _sqlerror($sErrormsg = 'Unbekannter Fehler', $sAddMsg = '') {
466         global $app, $conf;
467
468         $mysql_error = (is_object($this->_iConnId) ? mysqli_error($this->_iConnId) : mysqli_connect_error());
469         $mysql_errno = (is_object($this->_iConnId) ? mysqli_errno($this->_iConnId) : mysqli_connect_errno());
470
563649 471         //$sAddMsg .= getDebugBacktrace();
cd8bb8 472
MC 473         if($this->show_error_messages && $conf['demo_mode'] === false) {
474             echo $sErrormsg . $sAddMsg;
475         } else if(is_object($app) && method_exists($app, 'log')) {
a1918e 476                 $app->log($sErrormsg . $sAddMsg . ' -> ' . $mysql_errno . ' (' . $mysql_error . ')', LOGLEVEL_WARN);
cd8bb8 477             }
b1a6a5 478     }
MC 479
480     public function affectedRows() {
cd8bb8 481         return $this->affected();
b1a6a5 482     }
MC 483
484     // returns mySQL insert id
485     public function insertID() {
cd8bb8 486         return $this->insert_id();
b1a6a5 487     }
MC 488
489
cd8bb8 490     //* Function to quote strings
b1a6a5 491     public function quote($formfield) {
cd8bb8 492         return $this->escape($formfield);
b1a6a5 493     }
MC 494
cd8bb8 495     //* Function to unquotae strings
b1a6a5 496     public function unquote($formfield) {
MC 497         return stripslashes($formfield);
498     }
499
500     public function toLower($record) {
501         if(is_array($record)) {
502             foreach($record as $key => $val) {
503                 $key = strtolower($key);
504                 $out[$key] = $val;
505             }
506         }
507         return $out;
508     }
509
510     public function diffrec($record_old, $record_new) {
511         $diffrec_full = array();
512         $diff_num = 0;
513
514         if(is_array($record_old) && count($record_old) > 0) {
515             foreach($record_old as $key => $val) {
516                 // if(!isset($record_new[$key]) || $record_new[$key] != $val) {
517                 if(@$record_new[$key] != $val) {
518                     // Record has changed
519                     $diffrec_full['old'][$key] = $val;
520                     $diffrec_full['new'][$key] = @$record_new[$key];
521                     $diff_num++;
522                 } else {
523                     $diffrec_full['old'][$key] = $val;
524                     $diffrec_full['new'][$key] = $val;
525                 }
526             }
527         } elseif(is_array($record_new)) {
528             foreach($record_new as $key => $val) {
529                 if(isset($record_new[$key]) && @$record_old[$key] != $val) {
530                     // Record has changed
531                     $diffrec_full['new'][$key] = $val;
532                     $diffrec_full['old'][$key] = @$record_old[$key];
533                     $diff_num++;
534                 } else {
535                     $diffrec_full['new'][$key] = $val;
536                     $diffrec_full['old'][$key] = $val;
537                 }
538             }
539         }
540
541         return array('diff_num' => $diff_num, 'diff_rec' => $diffrec_full);
542
543     }
544
545     /**
546      * Function to get the database-size
547      * @param string $database_name
548      * @return int - database-size in bytes
549      */
550
551
552     public function getDatabaseSize($database_name) {
553         global $app;
554         include 'lib/mysql_clientdb.conf';
555         /* Connect to the database */
556         $link = mysql_connect($clientdb_host, $clientdb_user, $clientdb_password);
557         if (!$link) {
558             $app->log('Unable to connect to the database'.mysql_error($link), LOGLEVEL_DEBUG);
559             return;
560         }
561         /* Get database-size from information_schema */
562         $result=mysql_query("SELECT SUM(data_length+index_length) FROM information_schema.TABLES WHERE table_schema='".mysql_real_escape_string($database_name)."';", $link);
563         $this->close;
564         if (!$result) {
565             $app->log('Unable to get the database-size'.mysql_error($link), LOGLEVEL_DEBUG);
566             return;
567         }
568         $database_size = mysql_fetch_row($result);
569         return $database_size[0];
570     }
571
572     //** Function to fill the datalog with a full differential record.
573     public function datalogSave($db_table, $action, $primary_field, $primary_id, $record_old, $record_new, $force_update = false) {
574         global $app, $conf;
575
576         // Insert backticks only for incomplete table names.
577         if(stristr($db_table, '.')) {
578             $escape = '';
579         } else {
580             $escape = '`';
581         }
f5b0ca 582
43b345 583         if($force_update == true) {
T 584             //* We force a update even if no record has changed
b1a6a5 585             $diffrec_full = array('new' => $record_new, 'old' => $record_old);
43b345 586             $diff_num = count($record_new);
T 587         } else {
588             //* get the difference record between old and new record
589             $tmp = $this->diffrec($record_old, $record_new);
590             $diffrec_full = $tmp['diff_rec'];
591             $diff_num = $tmp['diff_num'];
592             unset($tmp);
593         }
f5b0ca 594
b1a6a5 595         // Insert the server_id, if the record has a server_id
MC 596         $server_id = (isset($record_old['server_id']) && $record_old['server_id'] > 0)?$record_old['server_id']:0;
597         if(isset($record_new['server_id'])) $server_id = $record_new['server_id'];
f5b0ca 598
N 599
b1a6a5 600         if($diff_num > 0) {
cd8bb8 601             $diffstr = serialize($diffrec_full);
b1a6a5 602             if(isset($_SESSION)) {
cd8bb8 603                 $username = $_SESSION['s']['user']['username'];
b1a6a5 604             } else {
MC 605                 $username = 'admin';
606             }
607             $dbidx = $primary_field.':'.$primary_id;
608
609             if($action == 'INSERT') $action = 'i';
610             if($action == 'UPDATE') $action = 'u';
611             if($action == 'DELETE') $action = 'd';
cd8bb8 612             $sql = "INSERT INTO sys_datalog (dbtable,dbidx,server_id,action,tstamp,user,data) VALUES (?, ?, ?, ?, ?, ?, ?)";
MC 613             $app->db->query($sql, $db_table, $dbidx, $server_id, $action, time(), $username, $diffstr);
346f60 614         }
f5b0ca 615
b1a6a5 616         return true;
346f60 617     }
f5b0ca 618
b1a6a5 619     //** Inserts a record and saves the changes into the datalog
MC 620     public function datalogInsert($tablename, $insert_data, $index_field) {
621         global $app;
f5b0ca 622
b1a6a5 623         if(is_array($insert_data)) {
43b345 624             $key_str = '';
T 625             $val_str = '';
2af58c 626             $params = array($tablename);
MC 627             $v_params = array();
43b345 628             foreach($insert_data as $key => $val) {
a6e3ae 629                 $key_str .= '??,';
2af58c 630                 $params[] = $key;
MC 631                 
632                 $val_str .= '?,';
633                 $v_params[] = $val;
43b345 634             }
b1a6a5 635             $key_str = substr($key_str, 0, -1);
MC 636             $val_str = substr($val_str, 0, -1);
43b345 637             $insert_data_str = '('.$key_str.') VALUES ('.$val_str.')';
2af58c 638             $this->query("INSERT INTO ?? $insert_data_str", true, $params + $v_params);
43b345 639         } else {
2af58c 640             /* TODO: deprecate this method! */
43b345 641             $insert_data_str = $insert_data;
2af58c 642             $this->query("INSERT INTO ?? $insert_data_str", $tablename);
3a11d2 643             $app->log("deprecated use of passing values to datalogInsert() - table " . $tablename, 1);
43b345 644         }
2af58c 645         
b1a6a5 646         $old_rec = array();
MC 647         $index_value = $this->insertID();
cd8bb8 648         $new_rec = $this->queryOneRecord("SELECT * FROM ?? WHERE ? = ?", $tablename, $index_field, $index_value);
b1a6a5 649         $this->datalogSave($tablename, 'INSERT', $index_field, $index_value, $old_rec, $new_rec);
f5b0ca 650
b1a6a5 651         return $index_value;
MC 652     }
f5b0ca 653
b1a6a5 654     //** Updates a record and saves the changes into the datalog
MC 655     public function datalogUpdate($tablename, $update_data, $index_field, $index_value, $force_update = false) {
43b345 656         global $app;
b1a6a5 657
cd8bb8 658         $old_rec = $this->queryOneRecord("SELECT * FROM ?? WHERE ?? = ?", $tablename, $index_field, $index_value);
b1a6a5 659
MC 660         if(is_array($update_data)) {
2af58c 661             $params = array($tablename);
43b345 662             $update_data_str = '';
T 663             foreach($update_data as $key => $val) {
2af58c 664                 $update_data_str .= '?? = ?,';
MC 665                 $params[] = $key;
666                 $params[] = $val;
43b345 667             }
2af58c 668             $params[] = $index_field;
MC 669             $params[] = $index_value;
b1a6a5 670             $update_data_str = substr($update_data_str, 0, -1);
2af58c 671             $this->query("UPDATE ?? SET $update_data_str WHERE ?? = ?", true, $params);
43b345 672         } else {
2af58c 673             /* TODO: deprecate this method! */
43b345 674             $update_data_str = $update_data;
2af58c 675             $this->query("UPDATE ?? SET $update_data_str WHERE ?? = ?", $tablename, $index_field, $index_value);
3a11d2 676             $app->log("deprecated use of passing values to datalogUpdate() - table " . $tablename, 1);
43b345 677         }
f5b0ca 678
cd8bb8 679         $new_rec = $this->queryOneRecord("SELECT * FROM ?? WHERE ?? = ?", $tablename, $index_field, $index_value);
b1a6a5 680         $this->datalogSave($tablename, 'UPDATE', $index_field, $index_value, $old_rec, $new_rec, $force_update);
f5b0ca 681
b1a6a5 682         return true;
MC 683     }
f5b0ca 684
7b47c0 685     //** Deletes a record and saves the changes into the datalog
b1a6a5 686     public function datalogDelete($tablename, $index_field, $index_value) {
MC 687         global $app;
7b47c0 688
cd8bb8 689         $old_rec = $this->queryOneRecord("SELECT * FROM ?? WHERE ?? = ?", $tablename, $index_field, $index_value);
MC 690         $this->query("DELETE FROM ?? WHERE ?? = ?", $tablename, $index_field, $index_value);
b1a6a5 691         $new_rec = array();
MC 692         $this->datalogSave($tablename, 'DELETE', $index_field, $index_value, $old_rec, $new_rec);
693
694         return true;
695     }
696
697     //** Deletes a record and saves the changes into the datalog
698     public function datalogError($errormsg) {
699         global $app;
700
2af58c 701         if(isset($app->modules->current_datalog_id) && $app->modules->current_datalog_id > 0) $this->query("UPDATE sys_datalog set error = ? WHERE datalog_id = ?", $errormsg, $app->modules->current_datalog_id);
b1a6a5 702
MC 703         return true;
704     }
f5b0ca 705
N 706
b1a6a5 707     public function freeResult($query)
MC 708     {
709         if(is_object($query) && (get_class($query) == "mysqli_result")) {
710             $query->free();
711             return true;
712         } else {
713             return false;
714         }
715     }
f5b0ca 716
b1a6a5 717     /*
f5b0ca 718        $columns = array(action =>   add | alter | drop
N 719        name =>     Spaltenname
720        name_new => neuer Spaltenname, nur bei 'alter' belegt
721        type =>     42go-Meta-Type: int16, int32, int64, double, char, varchar, text, blob
722        typeValue => Wert z.B. bei Varchar
723        defaultValue =>  Default Wert
724        notNull =>   true | false
725        autoInc =>   true | false
726        option =>   unique | primary | index)
727
728
729      */
730
b1a6a5 731     public function createTable($table_name, $columns) {
MC 732         $index = '';
cd8bb8 733         $sql = "CREATE TABLE ?? (";
b1a6a5 734         foreach($columns as $col){
MC 735             $sql .= $col['name'].' '.$this->mapType($col['type'], $col['typeValue']).' ';
f5b0ca 736
b1a6a5 737             if($col['defaultValue'] != '') $sql .= "DEFAULT '".$col['defaultValue']."' ";
MC 738             if($col['notNull'] == true) {
739                 $sql .= 'NOT NULL ';
740             } else {
741                 $sql .= 'NULL ';
742             }
743             if($col['autoInc'] == true) $sql .= 'auto_increment ';
744             $sql.= ',';
745             // key Definitionen
746             if($col['option'] == 'primary') $index .= 'PRIMARY KEY ('.$col['name'].'),';
747             if($col['option'] == 'index') $index .= 'INDEX ('.$col['name'].'),';
748             if($col['option'] == 'unique') $index .= 'UNIQUE ('.$col['name'].'),';
749         }
750         $sql .= $index;
751         $sql = substr($sql, 0, -1);
752         $sql .= ')';
cd8bb8 753         /* TODO: secure parameters */
MC 754         $this->query($sql, $table_name);
b1a6a5 755         return true;
f5b0ca 756     }
N 757
b1a6a5 758     /*
f5b0ca 759        $columns = array(action =>   add | alter | drop
N 760        name =>     Spaltenname
761        name_new => neuer Spaltenname, nur bei 'alter' belegt
762        type =>     42go-Meta-Type: int16, int32, int64, double, char, varchar, text, blob
763        typeValue => Wert z.B. bei Varchar
764        defaultValue =>  Default Wert
765        notNull =>   true | false
766        autoInc =>   true | false
767        option =>   unique | primary | index)
768
769
770      */
b1a6a5 771     public function alterTable($table_name, $columns) {
MC 772         $index = '';
cd8bb8 773         $sql = "ALTER TABLE ?? ";
b1a6a5 774         foreach($columns as $col){
MC 775             if($col['action'] == 'add') {
776                 $sql .= 'ADD '.$col['name'].' '.$this->mapType($col['type'], $col['typeValue']).' ';
777             } elseif ($col['action'] == 'alter') {
778                 $sql .= 'CHANGE '.$col['name'].' '.$col['name_new'].' '.$this->mapType($col['type'], $col['typeValue']).' ';
779             } elseif ($col['action'] == 'drop') {
780                 $sql .= 'DROP '.$col['name'].' ';
781             }
782             if($col['action'] != 'drop') {
783                 if($col['defaultValue'] != '') $sql .= "DEFAULT '".$col['defaultValue']."' ";
784                 if($col['notNull'] == true) {
785                     $sql .= 'NOT NULL ';
786                 } else {
787                     $sql .= 'NULL ';
788                 }
789                 if($col['autoInc'] == true) $sql .= 'auto_increment ';
790                 $sql.= ',';
791                 // Index definitions
792                 if($col['option'] == 'primary') $index .= 'PRIMARY KEY ('.$col['name'].'),';
793                 if($col['option'] == 'index') $index .= 'INDEX ('.$col['name'].'),';
794                 if($col['option'] == 'unique') $index .= 'UNIQUE ('.$col['name'].'),';
795             }
796         }
797         $sql .= $index;
798         $sql = substr($sql, 0, -1);
cd8bb8 799         /* TODO: secure parameters */
b1a6a5 800         //die($sql);
cd8bb8 801         $this->query($sql, $table_name);
b1a6a5 802         return true;
f5b0ca 803     }
b1a6a5 804
MC 805     public function dropTable($table_name) {
806         $this->check($table_name);
cd8bb8 807         $sql = "DROP TABLE ??";
MC 808         return $this->query($sql, $table_name);
f5b0ca 809     }
N 810
b1a6a5 811     // gibt Array mit Tabellennamen zur�ck
MC 812     public function getTables($database_name = '') {
cd8bb8 813         if(!is_object($this->_iConnId)) return false;
b1a6a5 814         if($database_name == '') $database_name = $this->dbName;
cd8bb8 815         $tb_names = $this->queryAllArray("SHOW TABLES FROM ??", $database_name);
b1a6a5 816         return $tb_names;
MC 817     }
f5b0ca 818
b1a6a5 819     // gibt Feldinformationen zur Tabelle zur�ck
MC 820     /*
f5b0ca 821        $columns = array(action =>   add | alter | drop
N 822        name =>     Spaltenname
823        name_new => neuer Spaltenname, nur bei 'alter' belegt
824        type =>     42go-Meta-Type: int16, int32, int64, double, char, varchar, text, blob
825        typeValue => Wert z.B. bei Varchar
826        defaultValue =>  Default Wert
827        notNull =>   true | false
828        autoInc =>   true | false
829        option =>   unique | primary | index)
830
831
832      */
833
b1a6a5 834     function tableInfo($table_name) {
f5b0ca 835
b1a6a5 836         global $go_api, $go_info;
MC 837         // Tabellenfelder einlesen
f5b0ca 838
cd8bb8 839         if($rows = $go_api->db->queryAllRecords('SHOW FIELDS FROM ??', $table_name)){
b1a6a5 840             foreach($rows as $row) {
cd8bb8 841                 $name = $row['Field'];
MC 842                 $default = $row['Default'];
843                 $key = $row['Key'];
844                 $extra = $row['Extra'];
845                 $isnull = $row['Null'];
846                 $type = $row['Type'];
f5b0ca 847
N 848
b1a6a5 849                 $column = array();
f5b0ca 850
b1a6a5 851                 $column['name'] = $name;
MC 852                 //$column['type'] = $type;
853                 $column['defaultValue'] = $default;
854                 if(stristr($key, 'PRI')) $column['option'] = 'primary';
855                 if(stristr($isnull, 'YES')) {
856                     $column['notNull'] = false;
857                 } else {
858                     $column['notNull'] = true;
859                 }
860                 if($extra == 'auto_increment') $column['autoInc'] = true;
f5b0ca 861
N 862
b1a6a5 863                 // Type in Metatype umsetzen
f5b0ca 864
b1a6a5 865                 if(stristr($type, 'int(')) $metaType = 'int32';
MC 866                 if(stristr($type, 'bigint')) $metaType = 'int64';
867                 if(stristr($type, 'char')) {
868                     $metaType = 'char';
869                     $tmp_typeValue = explode('(', $type);
870                     $column['typeValue'] = substr($tmp_typeValue[1], 0, -1);
871                 }
872                 if(stristr($type, 'varchar')) {
873                     $metaType = 'varchar';
874                     $tmp_typeValue = explode('(', $type);
875                     $column['typeValue'] = substr($tmp_typeValue[1], 0, -1);
876                 }
877                 if(stristr($type, 'text')) $metaType = 'text';
878                 if(stristr($type, 'double')) $metaType = 'double';
879                 if(stristr($type, 'blob')) $metaType = 'blob';
f5b0ca 880
N 881
b1a6a5 882                 $column['type'] = $metaType;
f5b0ca 883
b1a6a5 884                 $columns[] = $column;
MC 885             }
886             return $columns;
887         } else {
888             return false;
889         }
f5b0ca 890
N 891
b1a6a5 892         //$this->createTable('tester',$columns);
f5b0ca 893
b1a6a5 894         /*
f5b0ca 895      $result = mysql_list_fields($go_info["server"]["db_name"],$table_name);
N 896      $fields = mysql_num_fields ($result);
897      $i = 0;
898      $table = mysql_field_table ($result, $i);
899      while ($i < $fields) {
900      $name  = mysql_field_name  ($result, $i);
901      $type  = mysql_field_type  ($result, $i);
902      $len   = mysql_field_len   ($result, $i);
903      $flags = mysql_field_flags ($result, $i);
904      print_r($flags);
905
906      $columns = array(name => $name,
907      type =>     "",
908      defaultValue =>  "",
909      isnull =>   1,
910      option =>   "");
911      $returnvar[] = $columns;
912
913      $i++;
914      }
915        */
916
917
918
b1a6a5 919     }
f5b0ca 920
b1a6a5 921     public function mapType($metaType, $typeValue) {
MC 922         global $go_api;
923         $metaType = strtolower($metaType);
924         switch ($metaType) {
925         case 'int16':
926             return 'smallint';
927             break;
928         case 'int32':
929             return 'int';
930             break;
931         case 'int64':
932             return 'bigint';
933             break;
934         case 'double':
935             return 'double';
936             break;
937         case 'char':
938             return 'char';
939             break;
940         case 'varchar':
941             if($typeValue < 1) die('Database failure: Lenght required for these data types.');
942             return 'varchar('.$typeValue.')';
943             break;
944         case 'text':
945             return 'text';
946             break;
947         case 'blob':
948             return 'blob';
949             break;
950         }
951     }
f5b0ca 952
b1a6a5 953 }
f5b0ca 954
cd8bb8 955 /**
MC 956  * database query result class
957  *
958  * @package pxFramework
959  *
960  */
961 class db_result {
962
963     /**
964      *
965      *
966      * @access private
967      */
968     private $_iResId = null;
969     private $_iConnection = null;
970
971
972
973     /**
974      *
975      *
976      * @access private
977      */
978     public function db_result($iResId, $iConnection) {
979         $this->_iResId = $iResId;
980         $this->_iConnection = $iConnection;
981     }
982
983
984
985     /**
986      * get count of result rows
987      *
988      * Returns the amount of rows in the result set
989      *
990      * @access public
991      * @return int amount of rows
992      */
993     public function rows() {
994         if(!is_object($this->_iResId)) return 0;
995         $iRows = mysqli_num_rows($this->_iResId);
996         if(!$iRows) $iRows = 0;
997         return $iRows;
998     }
999
1000
1001
1002     /**
1003      * Get number of affected rows
1004      *
1005      * Returns the amount of rows affected by the previous query
1006      *
1007      * @access public
1008      * @return int amount of affected rows
1009      */
1010     public function affected() {
1011         if(!is_object($this->_iConnection)) return 0;
1012         $iRows = mysqli_affected_rows($this->_iConnection);
1013         if(!$iRows) $iRows = 0;
1014         return $iRows;
1015     }
1016
1017
1018
1019     /**
1020      * Frees the result set
1021      *
1022      * @access public
1023      */
1024     public function free() {
1025         if(!is_object($this->_iResId)) return;
1026
1027         mysqli_free_result($this->_iResId);
1028         return;
1029     }
1030
1031
1032
1033     /**
1034      * Get a result row (associative)
1035      *
1036      * Returns the next row in the result set. To be used in a while loop like while($currow = $result->get()) { do something ... }
1037      *
1038      * @access public
1039      * @return array result row
1040      */
1041     public function get() {
1042         $aItem = null;
1043
1044         if(is_object($this->_iResId)) {
1045             $aItem = mysqli_fetch_assoc($this->_iResId);
1046             if(!$aItem) $aItem = null;
1047         }
1048         return $aItem;
1049     }
1050
1051
1052
1053     /**
1054      * Get a result row (array with numeric index)
1055      *
1056      * @access public
1057      * @return array result row
1058      */
1059     public function getAsRow() {
1060         $aItem = null;
1061
1062         if(is_object($this->_iResId)) {
1063             $aItem = mysqli_fetch_row($this->_iResId);
1064             if(!$aItem) $aItem = null;
1065         }
1066         return $aItem;
1067     }
1068
1069 }
1070
1071 /**
1072  * database query result class
1073  *
1074  * emulates a db result set out of an array so you can use array results and db results the same way
1075  *
1076  * @package pxFramework
1077  * @see db_result
1078  *
1079  *
1080  */
1081 class fakedb_result {
1082
1083     /**
1084      *
1085      *
1086      * @access private
1087      */
1088     private $aResultData = array();
1089
1090     /**
1091      *
1092      *
1093      * @access private
1094      */
1095     private $aLimitedData = array();
1096
1097
1098
1099     /**
1100      *
1101      *
1102      * @access private
1103      */
1104     public function fakedb_result($aData) {
1105         $this->aResultData = $aData;
1106         $this->aLimitedData = $aData;
1107         reset($this->aLimitedData);
1108     }
1109
1110
1111
1112     /**
1113      * get count of result rows
1114      *
1115      * Returns the amount of rows in the result set
1116      *
1117      * @access public
1118      * @return int amount of rows
1119      */
1120     // Gibt die Anzahl Zeilen zurück
1121     public function rows() {
1122         return count($this->aLimitedData);
1123     }
1124
1125
1126
1127     /**
1128      * Frees the result set
1129      *
1130      * @access public
1131      */
1132     // Gibt ein Ergebnisset frei
1133     public function free() {
1134         $this->aResultData = array();
1135         $this->aLimitedData = array();
1136         return;
1137     }
1138
1139
1140
1141     /**
1142      * Get a result row (associative)
1143      *
1144      * Returns the next row in the result set. To be used in a while loop like while($currow = $result->get()) { do something ... }
1145      *
1146      * @access public
1147      * @return array result row
1148      */
1149     // Gibt eine Ergebniszeile zurück
1150     public function get() {
1151         $aItem = null;
1152
1153         if(!is_array($this->aLimitedData)) return $aItem;
1154
1155         if(list($vKey, $aItem) = each($this->aLimitedData)) {
1156             if(!$aItem) $aItem = null;
1157         }
1158         return $aItem;
1159     }
1160
1161
1162
1163     /**
1164      * Get a result row (array with numeric index)
1165      *
1166      * @access public
1167      * @return array result row
1168      */
1169     public function getAsRow() {
1170         return $this->get();
1171     }
1172
1173
1174
1175     /**
1176      * Limit the result (like a LIMIT x,y in a SQL query)
1177      *
1178      * @access public
1179      * @param int     $iStart offset to start read
1180      * @param int     iLength amount of datasets to read
1181      */
1182     public function limit_result($iStart, $iLength) {
1183         $this->aLimitedData = array_slice($this->aResultData, $iStart, $iLength, true);
1184     }
1185
1186 }
1187
1188
b1a6a5 1189 ?>