]> git.mxchange.org Git - friendica.git/blob - include/dba.php
Restored privates variables
[friendica.git] / include / dba.php
1 <?php
2 require_once("dbm.php");
3 require_once('include/datetime.php');
4
5 /**
6  * @class MySQL database class
7  *
8  * For debugging, insert 'dbg(1);' anywhere in the program flow.
9  * dbg(0); will turn it off. Logging is performed at LOGGER_DATA level.
10  * When logging, all binary info is converted to text and html entities are escaped so that
11  * the debugging stream is safe to view within both terminals and web pages.
12  *
13  */
14
15 class dba {
16
17         private $debug = 0;
18         private $db;
19         private $result;
20         private $driver;
21         public  $connected = false;
22         public  $error = false;
23         private $_server_info = '';
24         private static $dbo;
25
26         function __construct($server, $user, $pass, $db, $install = false) {
27                 $a = get_app();
28
29                 $stamp1 = microtime(true);
30
31                 $server = trim($server);
32                 $user = trim($user);
33                 $pass = trim($pass);
34                 $db = trim($db);
35
36                 if (!(strlen($server) && strlen($user))) {
37                         $this->connected = false;
38                         $this->db = null;
39                         return;
40                 }
41
42                 if ($install) {
43                         if (strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1')) {
44                                 if (! dns_get_record($server, DNS_A + DNS_CNAME + DNS_PTR)) {
45                                         $this->error = sprintf(t('Cannot locate DNS info for database server \'%s\''), $server);
46                                         $this->connected = false;
47                                         $this->db = null;
48                                         return;
49                                 }
50                         }
51                 }
52
53                 if (class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) {
54                         $this->driver = 'pdo';
55                         $connect = "mysql:host=".$server.";dbname=".$db;
56                         if (isset($a->config["system"]["db_charset"])) {
57                                 $connect .= ";charset=".$a->config["system"]["db_charset"];
58                         }
59                         $this->db = @new PDO($connect, $user, $pass);
60                         if (!$this->db->errorCode()) {
61                                 $this->connected = true;
62                         }
63                 } elseif (class_exists('mysqli')) {
64                         $this->driver = 'mysqli';
65                         $this->db = @new mysqli($server,$user,$pass,$db);
66                         if (!mysqli_connect_errno()) {
67                                 $this->connected = true;
68
69                                 if (isset($a->config["system"]["db_charset"])) {
70                                         $this->db->set_charset($a->config["system"]["db_charset"]);
71                                 }
72                         }
73                 } elseif (function_exists('mysql_connect')) {
74                         $this->driver = 'mysql';
75                         $this->db = mysql_connect($server,$user,$pass);
76                         if ($this->db && mysql_select_db($db,$this->db)) {
77                                 $this->connected = true;
78
79                                 if (isset($a->config["system"]["db_charset"])) {
80                                         mysql_set_charset($a->config["system"]["db_charset"], $this->db);
81                                 }
82                         }
83                 } else {
84                         // No suitable SQL driver was found.
85                         if (!$install) {
86                                 system_unavailable();
87                         }
88                 }
89
90                 if (!$this->connected) {
91                         $this->db = null;
92                         if (!$install) {
93                                 system_unavailable();
94                         }
95                 }
96                 $a->save_timestamp($stamp1, "network");
97
98                 self::$dbo = $this;
99         }
100
101         /**
102          * @brief Returns the MySQL server version string
103          * 
104          * This function discriminate between the deprecated mysql API and the current
105          * object-oriented mysqli API. Example of returned string: 5.5.46-0+deb8u1
106          *
107          * @return string
108          */
109         public function server_info() {
110                 if ($this->_server_info == '') {
111                         switch ($this->driver) {
112                                 case 'pdo':
113                                         $this->_server_info = $this->db->getAttribute(PDO::ATTR_SERVER_VERSION);
114                                         break;
115                                 case 'mysqli':
116                                         $this->_server_info = $this->db->server_info;
117                                         break;
118                                 case 'mysql':
119                                         $this->_server_info = mysql_get_server_info($this->db);
120                                         break;
121                         }
122                 }
123                 return $this->_server_info;
124         }
125
126         /**
127          * @brief Returns the selected database name
128          *
129          * @return string
130          */
131         public function database_name() {
132                 $r = $this->q("SELECT DATABASE() AS `db`");
133
134                 return $r[0]['db'];
135         }
136
137         /**
138          * @brief Returns the number of rows
139          *
140          * @return integer
141          */
142         public function num_rows() {
143                 if (!$this->result) {
144                         return 0;
145                 }
146
147                 switch ($this->driver) {
148                         case 'pdo':
149                                 $rows = $this->result->rowCount();
150                                 break;
151                         case 'mysqli':
152                                 $rows = $this->result->num_rows;
153                                 break;
154                         case 'mysql':
155                                 $rows = mysql_num_rows($this->result);
156                                 break;
157                 }
158                 return $rows;
159         }
160
161         /**
162          * @brief Analyze a database query and log this if some conditions are met.
163          *
164          * @param string $query The database query that will be analyzed
165          */
166         public function log_index($query) {
167                 $a = get_app();
168
169                 if ($a->config["system"]["db_log_index"] == "") {
170                         return;
171                 }
172
173                 // Don't explain an explain statement
174                 if (strtolower(substr($query, 0, 7)) == "explain") {
175                         return;
176                 }
177
178                 // Only do the explain on "select", "update" and "delete"
179                 if (!in_array(strtolower(substr($query, 0, 6)), array("select", "update", "delete"))) {
180                         return;
181                 }
182
183                 $r = $this->q("EXPLAIN ".$query);
184                 if (!dbm::is_result($r)) {
185                         return;
186                 }
187
188                 $watchlist = explode(',', $a->config["system"]["db_log_index_watch"]);
189                 $blacklist = explode(',', $a->config["system"]["db_log_index_blacklist"]);
190
191                 foreach ($r AS $row) {
192                         if ((intval($a->config["system"]["db_loglimit_index"]) > 0)) {
193                                 $log = (in_array($row['key'], $watchlist) AND
194                                         ($row['rows'] >= intval($a->config["system"]["db_loglimit_index"])));
195                         } else {
196                                 $log = false;
197                         }
198
199                         if ((intval($a->config["system"]["db_loglimit_index_high"]) > 0) AND ($row['rows'] >= intval($a->config["system"]["db_loglimit_index_high"]))) {
200                                 $log = true;
201                         }
202
203                         if (in_array($row['key'], $blacklist) OR ($row['key'] == "")) {
204                                 $log = false;
205                         }
206
207                         if ($log) {
208                                 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
209                                 @file_put_contents($a->config["system"]["db_log_index"], datetime_convert()."\t".
210                                                 $row['key']."\t".$row['rows']."\t".$row['Extra']."\t".
211                                                 basename($backtrace[1]["file"])."\t".
212                                                 $backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t".
213                                                 substr($query, 0, 2000)."\n", FILE_APPEND);
214                         }
215                 }
216         }
217
218         public function q($sql, $onlyquery = false) {
219                 $a = get_app();
220
221                 if (!$this->db || !$this->connected) {
222                         return false;
223                 }
224
225                 $this->error = '';
226
227                 $connstr = ($this->connected() ? "Connected" : "Disonnected");
228
229                 $stamp1 = microtime(true);
230
231                 $orig_sql = $sql;
232
233                 if (x($a->config,'system') && x($a->config['system'], 'db_callstack')) {
234                         $sql = "/*".$a->callstack()." */ ".$sql;
235                 }
236
237                 $columns = 0;
238
239                 switch ($this->driver) {
240                         case 'pdo':
241                                 $result = @$this->db->query($sql);
242                                 // Is used to separate between queries that returning data - or not
243                                 if (!is_bool($result)) {
244                                         $columns = $result->columnCount();
245                                 }
246                                 break;
247                         case 'mysqli':
248                                 $result = @$this->db->query($sql);
249                                 break;
250                         case 'mysql':
251                                 $result = @mysql_query($sql,$this->db);
252                                 break;
253                 }
254                 $stamp2 = microtime(true);
255                 $duration = (float)($stamp2-$stamp1);
256
257                 $a->save_timestamp($stamp1, "database");
258
259                 if (strtolower(substr($orig_sql, 0, 6)) != "select") {
260                         $a->save_timestamp($stamp1, "database_write");
261                 }
262                 if (x($a->config,'system') && x($a->config['system'],'db_log')) {
263                         if (($duration > $a->config["system"]["db_loglimit"])) {
264                                 $duration = round($duration, 3);
265                                 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
266                                 @file_put_contents($a->config["system"]["db_log"], datetime_convert()."\t".$duration."\t".
267                                                 basename($backtrace[1]["file"])."\t".
268                                                 $backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t".
269                                                 substr($sql, 0, 2000)."\n", FILE_APPEND);
270                         }
271                 }
272
273                 switch ($this->driver) {
274                         case 'pdo':
275                                 $errorInfo = $this->db->errorInfo();
276                                 if ($errorInfo) {
277                                         $this->error = $errorInfo[2];
278                                         $this->errorno = $errorInfo[1];
279                                 }
280                                 break;
281                         case 'mysqli':
282                                 if ($this->db->errno) {
283                                         $this->error = $this->db->error;
284                                         $this->errorno = $this->db->errno;
285                                 }
286                                 break;
287                         case 'mysql':
288                                 if (mysql_errno($this->db)) {
289                                         $this->error = mysql_error($this->db);
290                                         $this->errorno = mysql_errno($this->db);
291                                 }
292                                 break;
293                 }
294                 if (strlen($this->error)) {
295                         logger('DB Error ('.$connstr.') '.$this->errorno.': '.$this->error);
296                 }
297
298                 if ($this->debug) {
299
300                         $mesg = '';
301
302                         if ($result === false) {
303                                 $mesg = 'false';
304                         } elseif ($result === true) {
305                                 $mesg = 'true';
306                         } else {
307                                 switch ($this->driver) {
308                                         case 'pdo':
309                                                 $mesg = $result->rowCount().' results'.EOL;
310                                                 break;
311                                         case 'mysqli':
312                                                 $mesg = $result->num_rows.' results'.EOL;
313                                                 break;
314                                         case 'mysql':
315                                                 $mesg = mysql_num_rows($result).' results'.EOL;
316                                                 break;
317                                 }
318                         }
319
320                         $str =  'SQL = ' . printable($sql) . EOL . 'SQL returned ' . $mesg
321                                 . (($this->error) ? ' error: ' . $this->error : '')
322                                 . EOL;
323
324                         logger('dba: ' . $str );
325                 }
326
327                 /**
328                  * If dbfail.out exists, we will write any failed calls directly to it,
329                  * regardless of any logging that may or may nor be in effect.
330                  * These usually indicate SQL syntax errors that need to be resolved.
331                  */
332
333                 if ($result === false) {
334                         logger('dba: ' . printable($sql) . ' returned false.' . "\n" . $this->error);
335                         if (file_exists('dbfail.out')) {
336                                 file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . ' returned false' . "\n" . $this->error . "\n", FILE_APPEND);
337                         }
338                 }
339
340                 if (is_bool($result)) {
341                         return $result;
342                 }
343                 if ($onlyquery) {
344                         $this->result = $result;
345                         return true;
346                 }
347
348                 $r = array();
349                 switch ($this->driver) {
350                         case 'pdo':
351                                 while ($x = $result->fetch(PDO::FETCH_ASSOC)) {
352                                         $r[] = $x;
353                                 }
354                                 $result->closeCursor();
355                                 break;
356                         case 'mysqli':
357                                 while ($x = $result->fetch_array(MYSQLI_ASSOC)) {
358                                         $r[] = $x;
359                                 }
360                                 $result->free_result();
361                                 break;
362                         case 'mysql':
363                                 while ($x = mysql_fetch_array($result, MYSQL_ASSOC)) {
364                                         $r[] = $x;
365                                 }
366                                 mysql_free_result($result);
367                                 break;
368                 }
369
370                 // PDO doesn't return "true" on successful operations - like mysqli does
371                 // Emulate this behaviour by checking if the query returned data and had columns
372                 // This should be reliable enough
373                 if (($this->driver == 'pdo') AND (count($r) == 0) AND ($columns == 0)) {
374                         return true;
375                 }
376
377                 //$a->save_timestamp($stamp1, "database");
378
379                 if ($this->debug) {
380                         logger('dba: ' . printable(print_r($r, true)));
381                 }
382                 return($r);
383         }
384
385         public function qfetch() {
386                 $x = false;
387
388                 if ($this->result) {
389                         switch ($this->driver) {
390                                 case 'pdo':
391                                         $x = $this->result->fetch(PDO::FETCH_ASSOC);
392                                         break;
393                                 case 'mysqli':
394                                         $x = $this->result->fetch_array(MYSQLI_ASSOC);
395                                         break;
396                                 case 'mysql':
397                                         $x = mysql_fetch_array($this->result, MYSQL_ASSOC);
398                                         break;
399                         }
400                 }
401                 return($x);
402         }
403
404         public function qclose() {
405                 if ($this->result) {
406                         switch ($this->driver) {
407                                 case 'pdo':
408                                         $this->result->closeCursor();
409                                         break;
410                                 case 'mysqli':
411                                         $this->result->free_result();
412                                         break;
413                                 case 'mysql':
414                                         mysql_free_result($this->result);
415                                         break;
416                         }
417                 }
418         }
419
420         public function dbg($dbg) {
421                 $this->debug = $dbg;
422         }
423
424         public function escape($str) {
425                 if ($this->db && $this->connected) {
426                         switch ($this->driver) {
427                                 case 'pdo':
428                                         return substr(@$this->db->quote($str, PDO::PARAM_STR), 1, -1);
429                                 case 'mysqli':
430                                         return @$this->db->real_escape_string($str);
431                                 case 'mysql':
432                                         return @mysql_real_escape_string($str,$this->db);
433                         }
434                 }
435         }
436
437         function connected() {
438                 switch ($this->driver) {
439                         case 'pdo':
440                                 // Not sure if this really is working like expected
441                                 $connected = ($this->db->getAttribute(PDO::ATTR_CONNECTION_STATUS) != "");
442                                 break;
443                         case 'mysqli':
444                                 $connected = $this->db->ping();
445                                 break;
446                         case 'mysql':
447                                 $connected = mysql_ping($this->db);
448                                 break;
449                 }
450                 return $connected;
451         }
452
453         function insert_id() {
454                 switch ($this->driver) {
455                         case 'pdo':
456                                 $id = $this->db->lastInsertId();
457                                 break;
458                         case 'mysqli':
459                                 $id = $this->db->insert_id;
460                                 break;
461                         case 'mysql':
462                                 $id = mysql_insert_id($this->db);
463                                 break;
464                 }
465                 return $id;
466         }
467
468         function __destruct() {
469                 if ($this->db) {
470                         switch ($this->driver) {
471                                 case 'pdo':
472                                         $this->db = null;
473                                         break;
474                                 case 'mysqli':
475                                         $this->db->close();
476                                         break;
477                                 case 'mysql':
478                                         mysql_close($this->db);
479                                         break;
480                         }
481                 }
482         }
483
484         /**
485          * @brief Replaces ANY_VALUE() function by MIN() function,
486          *  if the database server does not support ANY_VALUE().
487          *
488          * Considerations for Standard SQL, or MySQL with ONLY_FULL_GROUP_BY (default since 5.7.5).
489          * ANY_VALUE() is available from MySQL 5.7.5 https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html
490          * A standard fall-back is to use MIN().
491          *
492          * @param string $sql An SQL string without the values
493          * @return string The input SQL string modified if necessary.
494          */
495         public function any_value_fallback($sql) {
496                 $server_info = $this->server_info();
497                 if (version_compare($server_info, '5.7.5', '<') ||
498                         (stripos($server_info, 'MariaDB') !== false)) {
499                         $sql = str_ireplace('ANY_VALUE(', 'MIN(', $sql);
500                 }
501                 return $sql;
502         }
503
504         /**
505          * @brief Executes a prepared statement
506          *
507          * @param string $sql SQL statement
508          * @return object statement object
509          */
510         static public function p($sql) {
511                 $a = get_app();
512
513                 $stamp1 = microtime(true);
514
515                 $args = func_get_args();
516                 unset($args[0]);
517
518                 if (!self::$dbo OR !self::$dbo->connected) {
519                         return false;
520                 }
521
522                 $sql = self::$dbo->any_value_fallback($sql);
523
524                 $orig_sql = $sql;
525
526                 if (x($a->config,'system') && x($a->config['system'], 'db_callstack')) {
527                         $sql = "/*".$a->callstack()." */ ".$sql;
528                 }
529
530                 switch (self::$dbo->driver) {
531                         case 'pdo':
532                                 $stmt = self::$dbo->db->prepare($sql);
533
534                                 foreach ($args AS $param => $value) {
535                                         $stmt->bindParam($param, $args[$param]);
536                                 }
537
538                                 $success = $stmt->execute();
539
540                                 if ($success) {
541                                         $retval = $stmt;
542                                 } else {
543                                         $retval = false;
544                                 }
545
546                                 $errorInfo = self::$dbo->db->errorInfo();
547
548                                 if ($errorInfo) {
549                                         self::$dbo->error = $errorInfo[2];
550                                         self::$dbo->errorno = $errorInfo[1];
551                                 }
552
553                                 break;
554                         case 'mysqli':
555                                 $stmt = self::$dbo->db->stmt_init();
556
557                                 if (!$stmt->prepare($sql)) {
558                                         self::$dbo->error = self::$dbo->db->error;
559                                         self::$dbo->errorno = self::$dbo->db->errno;
560                                         $retval = false;
561                                         break;
562                                 }
563
564                                 $params = '';
565                                 $values = array();
566                                 foreach ($args AS $param => $value) {
567                                         if (is_int($args[$param])) {
568                                                 $params .= 'i';
569                                         } elseif (is_float($args[$param])) {
570                                                 $params .= 'd';
571                                         } elseif (is_string($args[$param])) {
572                                                 $params .= 's';
573                                         } else {
574                                                 $params .= 'b';
575                                         }
576                                         $values[] = &$args[$param];
577                                 }
578
579                                 array_unshift($values, $params);
580
581                                 call_user_func_array(array($stmt, 'bind_param'), $values);
582
583                                 if (!$stmt->execute()) {
584                                         self::$dbo->error = self::$dbo->db->error;
585                                         self::$dbo->errorno = self::$dbo->db->errno;
586                                         $retval = false;
587                                 } elseif (method_exists($stmt, 'get_result')) {
588                                         // Is mysqlnd installed?
589                                         $retval = $stmt->get_result();
590                                 } else {
591                                         $retval = $stmt;
592                                 }
593                                 break;
594                         case 'mysql':
595                                 // For the old "mysql" functions we cannot use prepared statements
596                                 foreach ($args AS $param => $value) {
597                                         if (is_int($args[$param]) OR is_float($args[$param])) {
598                                                 $replace = intval($args[$param]);
599                                         } else {
600                                                 $replace = "'".dbesc($args[$param])."'";
601                                         }
602
603                                         $pos = strpos($sql, '?');
604                                         if ($pos !== false) {
605                                                 $sql = substr_replace($sql, $replace, $pos, 1);
606                                         }
607                                 }
608
609                                 $retval = mysql_query($sql, self::$dbo->db);
610                                 if (mysql_errno(self::$dbo->db)) {
611                                         self::$dbo->error = mysql_error(self::$dbo->db);
612                                         self::$dbo->errorno = mysql_errno(self::$dbo->db);
613                                 }
614                                 break;
615                 }
616
617                 $stamp2 = microtime(true);
618                 $duration = (float)($stamp2 - $stamp1);
619
620                 $a->save_timestamp($stamp1, 'database');
621
622                 if (strtolower(substr($orig_sql, 0, 6)) != "select") {
623                         $a->save_timestamp($stamp1, "database_write");
624                 }
625
626                 return $retval;
627         }
628
629         /**
630          * @brief Executes a prepared statement
631          *
632          * @param string $sql SQL statement
633          * @return boolean Was the query successfull?
634          */
635         static public function e($sql) {
636                 $args = func_get_args();
637
638                 $stmt = self::p();
639                 self::close($stmt);
640         }
641
642         /**
643          * @brief Fetch a single row
644          *
645          * @param object $stmt statement object
646          * @return array current row
647          */
648         static public function fetch($stmt) {
649                 switch (self::$dbo->driver) {
650                         case 'pdo':
651                                 return $stmt->fetch(PDO::FETCH_ASSOC);
652                         case 'mysqli':
653                                 // When mysqlnd is installed, we can use a shortcut
654                                 if (method_exists($stmt, 'fetch_array')) {
655                                         return $stmt->fetch_array(MYSQLI_ASSOC);
656                                 }
657
658                                 // This code works, but is slow
659
660                                 // Bind the result to a result array
661                                 $cols = array();
662
663                                 $cols_num = array();
664                                 for ($x = 0; $x < $stmt->field_count; $x++) {
665                                         $cols[] = &$cols_num[$x];
666                                 }
667
668                                 call_user_func_array(array($stmt, 'bind_result'), $cols);
669
670                                 $success = $stmt->fetch();
671
672                                 if (!$success) {
673                                         return false;
674                                 }
675
676                                 // The slow part:
677                                 // We need to get the field names for the array keys
678                                 // It seems that there is no better way to do this.
679                                 $result = $stmt->result_metadata();
680
681                                 $columns = array();
682                                 foreach ($cols_num AS $col) {
683                                         $field = $result->fetch_field();
684                                         $columns[$field->name] = $col;
685                                 }
686                                 return $columns;
687                         case 'mysql':
688                                 return mysql_fetch_array(self::$dbo->result, MYSQL_ASSOC);
689                 }
690         }
691
692         /**
693          * @brief Closes the current statement
694          *
695          * @param object $stmt statement object
696          * @return boolean was the close successfull?
697          */
698         static public function close($stmt) {
699                 switch (self::$dbo->driver) {
700                         case 'pdo':
701                                 return $stmt->closeCursor();
702                         case 'mysqli':
703                                 return $stmt->close();
704                         case 'mysql':
705                                 return mysql_free_result($stmt);
706                 }
707         }
708 }
709
710 function printable($s) {
711         $s = preg_replace("~([\x01-\x08\x0E-\x0F\x10-\x1F\x7F-\xFF])~",".", $s);
712         $s = str_replace("\x00",'.',$s);
713         if (x($_SERVER,'SERVER_NAME')) {
714                 $s = escape_tags($s);
715         }
716         return $s;
717 }
718
719 // Procedural functions
720 function dbg($state) {
721         global $db;
722
723         if ($db) {
724                 $db->dbg($state);
725         }
726 }
727
728 function dbesc($str) {
729         global $db;
730
731         if ($db && $db->connected) {
732                 return($db->escape($str));
733         } else {
734                 return(str_replace("'","\\'",$str));
735         }
736 }
737
738 // Function: q($sql,$args);
739 // Description: execute SQL query with printf style args.
740 // Example: $r = q("SELECT * FROM `%s` WHERE `uid` = %d",
741 //                   'user', 1);
742 function q($sql) {
743         global $db;
744         $args = func_get_args();
745         unset($args[0]);
746
747         if ($db && $db->connected) {
748                 $sql = $db->any_value_fallback($sql);
749                 $stmt = @vsprintf($sql,$args); // Disabled warnings
750                 //logger("dba: q: $stmt", LOGGER_ALL);
751                 if ($stmt === false)
752                         logger('dba: vsprintf error: ' . print_r(debug_backtrace(),true), LOGGER_DEBUG);
753
754                 $db->log_index($stmt);
755
756                 return $db->q($stmt);
757         }
758
759         /**
760          *
761          * This will happen occasionally trying to store the
762          * session data after abnormal program termination
763          *
764          */
765         logger('dba: no database: ' . print_r($args,true));
766         return false;
767 }
768
769 /**
770  * @brief Performs a query with "dirty reads"
771  *
772  * By doing dirty reads (reading uncommitted data) no locks are performed
773  * This function can be used to fetch data that doesn't need to be reliable.
774  *
775  * @param $args Query parameters (1 to N parameters of different types)
776  * @return array Query array
777  */
778 function qu($sql) {
779         global $db;
780
781         $args = func_get_args();
782         unset($args[0]);
783
784         if ($db && $db->connected) {
785                 $sql = $db->any_value_fallback($sql);
786                 $stmt = @vsprintf($sql,$args); // Disabled warnings
787                 if ($stmt === false)
788                         logger('dba: vsprintf error: ' . print_r(debug_backtrace(),true), LOGGER_DEBUG);
789
790                 $db->log_index($stmt);
791
792                 $db->q("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
793                 $retval = $db->q($stmt);
794                 $db->q("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;");
795                 return $retval;
796         }
797
798         /**
799          *
800          * This will happen occasionally trying to store the
801          * session data after abnormal program termination
802          *
803          */
804         logger('dba: no database: ' . print_r($args,true));
805         return false;
806 }
807
808 /**
809  *
810  * Raw db query, no arguments
811  *
812  */
813 function dbq($sql) {
814         global $db;
815
816         if ($db && $db->connected) {
817                 $ret = $db->q($sql);
818         } else {
819                 $ret = false;
820         }
821         return $ret;
822 }
823
824 // Caller is responsible for ensuring that any integer arguments to
825 // dbesc_array are actually integers and not malformed strings containing
826 // SQL injection vectors. All integer array elements should be specifically
827 // cast to int to avoid trouble.
828 function dbesc_array_cb(&$item, $key) {
829         if (is_string($item))
830                 $item = dbesc($item);
831 }
832
833 function dbesc_array(&$arr) {
834         if (is_array($arr) && count($arr)) {
835                 array_walk($arr,'dbesc_array_cb');
836         }
837 }
838
839 function dba_timer() {
840         return microtime(true);
841 }