dolibarr 18.0.6
mysqli.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001 Fabien Seisen <seisen@linuxfr.org>
3 * Copyright (C) 2002-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
4 * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
6 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
7 * Copyright (C) 2015 Raphaƫl Doursenaud <rdoursenaud@gpcsolutions.fr>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
28require_once DOL_DOCUMENT_ROOT.'/core/db/DoliDB.class.php';
29
33class DoliDBMysqli extends DoliDB
34{
36 public $db;
38 public $type = 'mysqli';
39
41 const LABEL = 'MySQL or MariaDB';
43 const VERSIONMIN = '5.0.3';
44
46 private $_results;
47
59 public function __construct($type, $host, $user, $pass, $name = '', $port = 0)
60 {
61 global $conf, $langs;
62
63 // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
64 if (!empty($conf->db->character_set)) {
65 $this->forcecharset = $conf->db->character_set;
66 }
67 if (!empty($conf->db->dolibarr_main_db_collation)) {
68 $this->forcecollate = $conf->db->dolibarr_main_db_collation;
69 }
70
71 $this->database_user = $user;
72 $this->database_host = $host;
73 $this->database_port = $port;
74
75 $this->transaction_opened = 0;
76
77 //print "Name DB: $host,$user,$pass,$name<br>";
78
79 if (!class_exists('mysqli')) {
80 $this->connected = false;
81 $this->ok = false;
82 $this->error = "Mysqli PHP functions for using Mysqli driver are not available in this version of PHP. Try to use another driver.";
83 dol_syslog(get_class($this)."::DoliDBMysqli : Mysqli PHP functions for using Mysqli driver are not available in this version of PHP. Try to use another driver.", LOG_ERR);
84 }
85
86 if (!$host) {
87 $this->connected = false;
88 $this->ok = false;
89 $this->error = $langs->trans("ErrorWrongHostParameter");
90 dol_syslog(get_class($this)."::DoliDBMysqli : Connect error, wrong host parameters", LOG_ERR);
91 }
92
93 // Try server connection
94 // We do not try to connect to database, only to server. Connect to database is done later in constrcutor
95 $this->db = $this->connect($host, $user, $pass, '', $port);
96
97 if ($this->db && empty($this->db->connect_errno)) {
98 $this->connected = true;
99 $this->ok = true;
100 } else {
101 $this->connected = false;
102 $this->ok = false;
103 $this->error = empty($this->db) ? 'Failed to connect' : $this->db->connect_error;
104 dol_syslog(get_class($this)."::DoliDBMysqli Connect error: ".$this->error, LOG_ERR);
105 }
106
107 // If server connection is ok, we try to connect to the database
108 if ($this->connected && $name) {
109 if ($this->select_db($name)) {
110 $this->database_selected = true;
111 $this->database_name = $name;
112 $this->ok = true;
113
114 // If client is old latin, we force utf8
115 $clientmustbe = empty($conf->db->character_set) ? 'utf8' : $conf->db->character_set;
116 if (preg_match('/latin1/', $clientmustbe)) {
117 $clientmustbe = 'utf8';
118 }
119
120 if ($this->db->character_set_name() != $clientmustbe) {
121 $this->db->set_charset($clientmustbe); // This set charset, but with a bad collation
122
123 $collation = $conf->db->dolibarr_main_db_collation;
124 if (preg_match('/latin1/', $collation)) {
125 $collation = 'utf8_unicode_ci';
126 }
127
128 if (!preg_match('/general/', $collation)) {
129 $this->db->query("SET collation_connection = ".$collation);
130 }
131 }
132 } else {
133 $this->database_selected = false;
134 $this->database_name = '';
135 $this->ok = false;
136 $this->error = $this->error();
137 dol_syslog(get_class($this)."::DoliDBMysqli : Select_db error ".$this->error, LOG_ERR);
138 }
139 } else {
140 // Pas de selection de base demandee, ok ou ko
141 $this->database_selected = false;
142
143 if ($this->connected) {
144 // If client is old latin, we force utf8
145 $clientmustbe = empty($conf->db->character_set) ? 'utf8' : $conf->db->character_set;
146 if (preg_match('/latin1/', $clientmustbe)) {
147 $clientmustbe = 'utf8';
148 }
149 if (preg_match('/utf8mb4/', $clientmustbe)) {
150 $clientmustbe = 'utf8';
151 }
152
153 if ($this->db->character_set_name() != $clientmustbe) {
154 $this->db->set_charset($clientmustbe); // This set utf8_unicode_ci
155
156 $collation = $conf->db->dolibarr_main_db_collation;
157 if (preg_match('/latin1/', $collation)) {
158 $collation = 'utf8_unicode_ci';
159 }
160 if (preg_match('/utf8mb4/', $collation)) {
161 $collation = 'utf8_unicode_ci';
162 }
163
164 if (!preg_match('/general/', $collation)) {
165 $this->db->query("SET collation_connection = ".$collation);
166 }
167 }
168 }
169 }
170 }
171
172
179 public function hintindex($nameofindex)
180 {
181 return " FORCE INDEX(".preg_replace('/[^a-z0-9_]/', '', $nameofindex).")";
182 }
183
184
192 public static function convertSQLFromMysql($line, $type = 'ddl')
193 {
194 return $line;
195 }
196
197
198 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
205 public function select_db($database)
206 {
207 // phpcs:enable
208 dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
209 $result = false;
210 try {
211 $result = $this->db->select_db($database);
212 } catch (Exception $e) {
213 // Nothing done on error
214 }
215 return $result;
216 }
217
218
230 public function connect($host, $login, $passwd, $name, $port = 0)
231 {
232 dol_syslog(get_class($this)."::connect host=$host, port=$port, login=$login, passwd=--hidden--, name=$name", LOG_DEBUG);
233
234 //mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
235
236 // Can also be
237 // mysqli::init(); mysql::options(MYSQLI_INIT_COMMAND, 'SET AUTOCOMMIT = 0'); mysqli::options(MYSQLI_OPT_CONNECT_TIMEOUT, 5);
238 // return mysqli::real_connect($host, $user, $pass, $db, $port);
239 $tmp = false;
240 try {
241 if (!class_exists('mysqli')) {
242 dol_print_error('', 'Driver mysqli for PHP not available');
243 }
244 $tmp = new mysqli($host, $login, $passwd, $name, $port);
245 } catch (Exception $e) {
246 dol_syslog(get_class($this)."::connect failed", LOG_DEBUG);
247 }
248 return $tmp;
249 }
250
256 public function getVersion()
257 {
258 return $this->db->server_info;
259 }
260
266 public function getDriverInfo()
267 {
268 return $this->db->client_info;
269 }
270
271
278 public function close()
279 {
280 if ($this->db) {
281 if ($this->transaction_opened > 0) {
282 dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
283 }
284 $this->connected = false;
285 return $this->db->close();
286 }
287 return false;
288 }
289
290
291
302 public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
303 {
304 global $conf, $dolibarr_main_db_readonly;
305
306 $query = trim($query);
307
308 if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK'))) {
309 $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
310 dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
311 }
312 if (empty($query)) {
313 return false; // Return false = error if empty request
314 }
315
316 if (!empty($dolibarr_main_db_readonly)) {
317 if (preg_match('/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
318 $this->lasterror = 'Application in read-only mode';
319 $this->lasterrno = 'APPREADONLY';
320 $this->lastquery = $query;
321 return false;
322 }
323 }
324
325 try {
326 if (!$this->database_name) {
327 // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
328 $ret = $this->db->query($query, $result_mode);
329 } else {
330 $ret = $this->db->query($query, $result_mode);
331 }
332 } catch (Exception $e) {
333 dol_syslog(get_class($this)."::query Exception in query instead of returning an error: ".$e->getMessage(), LOG_ERR);
334 $ret = false;
335 }
336
337 if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {
338 // Si requete utilisateur, on la sauvegarde ainsi que son resultset
339 if (!$ret) {
340 $this->lastqueryerror = $query;
341 $this->lasterror = $this->error();
342 $this->lasterrno = $this->errno();
343
344 if (getDolGlobalInt('SYSLOG_LEVEL') < LOG_DEBUG) {
345 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
346 }
347 dol_syslog(get_class($this)."::query SQL Error message: ".$this->lasterrno." ".$this->lasterror, LOG_ERR);
348 //var_dump(debug_print_backtrace());
349 }
350 $this->lastquery = $query;
351 $this->_results = $ret;
352 }
353
354 return $ret;
355 }
356
357 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
364 public function fetch_object($resultset)
365 {
366 // phpcs:enable
367 // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
368 if (!is_object($resultset)) {
369 $resultset = $this->_results;
370 }
371 return $resultset->fetch_object();
372 }
373
374
375 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
382 public function fetch_array($resultset)
383 {
384 // phpcs:enable
385 // If resultset not provided, we take the last used by connexion
386 if (!is_object($resultset)) {
387 $resultset = $this->_results;
388 }
389 return $resultset->fetch_array();
390 }
391
392 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
399 public function fetch_row($resultset)
400 {
401 // phpcs:enable
402 // If resultset not provided, we take the last used by connexion
403 if (!is_bool($resultset)) {
404 if (!is_object($resultset)) {
405 $resultset = $this->_results;
406 }
407 return $resultset->fetch_row();
408 } else {
409 // si le curseur est un booleen on retourne la valeur 0
410 return 0;
411 }
412 }
413
414 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
422 public function num_rows($resultset)
423 {
424 // phpcs:enable
425 // If resultset not provided, we take the last used by connexion
426 if (!is_object($resultset)) {
427 $resultset = $this->_results;
428 }
429 return isset($resultset->num_rows) ? $resultset->num_rows : 0;
430 }
431
432 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
440 public function affected_rows($resultset)
441 {
442 // phpcs:enable
443 // If resultset not provided, we take the last used by connexion
444 if (!is_object($resultset)) {
445 $resultset = $this->_results;
446 }
447 // mysql necessite un link de base pour cette fonction contrairement
448 // a pqsql qui prend un resultset
449 return $this->db->affected_rows;
450 }
451
452
459 public function free($resultset = null)
460 {
461 // If resultset not provided, we take the last used by connexion
462 if (!is_object($resultset)) {
463 $resultset = $this->_results;
464 }
465 // Si resultset en est un, on libere la memoire
466 if (is_object($resultset)) {
467 $resultset->free_result();
468 }
469 }
470
477 public function escape($stringtoencode)
478 {
479 return $this->db->real_escape_string((string) $stringtoencode);
480 }
481
488 public function escapeforlike($stringtoencode)
489 {
490 return str_replace(array('\\', '_', '%'), array('\\\\', '\_', '\%'), (string) $stringtoencode);
491 }
492
498 public function errno()
499 {
500 if (!$this->connected) {
501 // Si il y a eu echec de connexion, $this->db n'est pas valide.
502 return 'DB_ERROR_FAILED_TO_CONNECT';
503 } else {
504 // Constants to convert a MySql error code to a generic Dolibarr error code
505 $errorcode_map = array(
506 1004 => 'DB_ERROR_CANNOT_CREATE',
507 1005 => 'DB_ERROR_CANNOT_CREATE',
508 1006 => 'DB_ERROR_CANNOT_CREATE',
509 1007 => 'DB_ERROR_ALREADY_EXISTS',
510 1008 => 'DB_ERROR_CANNOT_DROP',
511 1022 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
512 1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
513 1044 => 'DB_ERROR_ACCESSDENIED',
514 1046 => 'DB_ERROR_NODBSELECTED',
515 1048 => 'DB_ERROR_CONSTRAINT',
516 1050 => 'DB_ERROR_TABLE_ALREADY_EXISTS',
517 1051 => 'DB_ERROR_NOSUCHTABLE',
518 1054 => 'DB_ERROR_NOSUCHFIELD',
519 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
520 1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
521 1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
522 1064 => 'DB_ERROR_SYNTAX',
523 1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
524 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
525 1091 => 'DB_ERROR_NOSUCHFIELD',
526 1100 => 'DB_ERROR_NOT_LOCKED',
527 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
528 1146 => 'DB_ERROR_NOSUCHTABLE',
529 1215 => 'DB_ERROR_CANNOT_ADD_FOREIGN_KEY_CONSTRAINT',
530 1216 => 'DB_ERROR_NO_PARENT',
531 1217 => 'DB_ERROR_CHILD_EXISTS',
532 1396 => 'DB_ERROR_USER_ALREADY_EXISTS', // When creating a user that already existing
533 1451 => 'DB_ERROR_CHILD_EXISTS',
534 1826 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS'
535 );
536
537 if (isset($errorcode_map[$this->db->errno])) {
538 return $errorcode_map[$this->db->errno];
539 }
540 $errno = $this->db->errno;
541 return ($errno ? 'DB_ERROR_'.$errno : '0');
542 }
543 }
544
550 public function error()
551 {
552 if (!$this->connected) {
553 // Si il y a eu echec de connexion, $this->db n'est pas valide pour mysqli_error.
554 return 'Not connected. Check setup parameters in conf/conf.php file and your mysql client and server versions';
555 } else {
556 return $this->db->error;
557 }
558 }
559
560 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
568 public function last_insert_id($tab, $fieldid = 'rowid')
569 {
570 // phpcs:enable
571 return $this->db->insert_id;
572 }
573
582 public function encrypt($fieldorvalue, $withQuotes = 1)
583 {
584 global $conf;
585
586 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
587 $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
588
589 //Encryption key
590 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
591
592 $escapedstringwithquotes = ($withQuotes ? "'" : "").$this->escape($fieldorvalue).($withQuotes ? "'" : "");
593
594 if ($cryptType && !empty($cryptKey)) {
595 if ($cryptType == 2) {
596 $escapedstringwithquotes = "AES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
597 } elseif ($cryptType == 1) {
598 $escapedstringwithquotes = "DES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
599 }
600 }
601
602 return $escapedstringwithquotes;
603 }
604
611 public function decrypt($value)
612 {
613 global $conf;
614
615 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
616 $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
617
618 //Encryption key
619 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
620
621 $return = $value;
622
623 if ($cryptType && !empty($cryptKey)) {
624 if ($cryptType == 2) {
625 $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
626 } elseif ($cryptType == 1) {
627 $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
628 }
629 }
630
631 return $return;
632 }
633
634
635 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
641 public function DDLGetConnectId()
642 {
643 // phpcs:enable
644 $resql = $this->query('SELECT CONNECTION_ID()');
645 if ($resql) {
646 $row = $this->fetch_row($resql);
647 return $row[0];
648 } else {
649 return '?';
650 }
651 }
652
653 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
665 public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
666 {
667 // phpcs:enable
668 if (empty($charset)) {
669 $charset = $this->forcecharset;
670 }
671 if (empty($collation)) {
672 $collation = $this->forcecollate;
673 }
674
675 // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
676 $sql = "CREATE DATABASE `".$this->escape($database)."`";
677 $sql .= " DEFAULT CHARACTER SET `".$this->escape($charset)."` DEFAULT COLLATE `".$this->escape($collation)."`";
678
679 dol_syslog($sql, LOG_DEBUG);
680 $ret = $this->query($sql);
681 if (!$ret) {
682 // We try again for compatibility with Mysql < 4.1.1
683 $sql = "CREATE DATABASE `".$this->escape($database)."`";
684 dol_syslog($sql, LOG_DEBUG);
685 $ret = $this->query($sql);
686 }
687 return $ret;
688 }
689
690 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
698 public function DDLListTables($database, $table = '')
699 {
700 // phpcs:enable
701 $listtables = array();
702
703 $like = '';
704 if ($table) {
705 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
706
707 $like = "LIKE '".$this->escape($tmptable)."'";
708 }
709 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
710
711 $sql = "SHOW TABLES FROM `".$tmpdatabase."` ".$like.";";
712 //print $sql;
713 $result = $this->query($sql);
714 if ($result) {
715 while ($row = $this->fetch_row($result)) {
716 $listtables[] = $row[0];
717 }
718 }
719 return $listtables;
720 }
721
722 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
730 public function DDLListTablesFull($database, $table = '')
731 {
732 // phpcs:enable
733 $listtables = array();
734
735 $like = '';
736 if ($table) {
737 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
738
739 $like = "LIKE '".$this->escape($tmptable)."'";
740 }
741 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
742
743 $sql = "SHOW FULL TABLES FROM `".$tmpdatabase."` ".$like.";";
744
745 $result = $this->query($sql);
746 if ($result) {
747 while ($row = $this->fetch_row($result)) {
748 $listtables[] = $row;
749 }
750 }
751 return $listtables;
752 }
753
754 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
761 public function DDLInfoTable($table)
762 {
763 // phpcs:enable
764 $infotables = array();
765
766 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
767
768 $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
769
770 dol_syslog($sql, LOG_DEBUG);
771 $result = $this->query($sql);
772 if ($result) {
773 while ($row = $this->fetch_row($result)) {
774 $infotables[] = $row;
775 }
776 }
777 return $infotables;
778 }
779
780 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
793 public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
794 {
795 // phpcs:enable
796 // FIXME: $fulltext_keys parameter is unused
797
798 $pk = '';
799 $sqluq = $sqlk = array();
800
801 // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
802 // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
803 $sql = "CREATE TABLE ".$table."(";
804 $i = 0;
805 $sqlfields = array();
806 foreach ($fields as $field_name => $field_desc) {
807 $sqlfields[$i] = $field_name." ";
808 $sqlfields[$i] .= $field_desc['type'];
809 if (preg_match("/^[^\s]/i", $field_desc['value'])) {
810 $sqlfields[$i] .= "(".$field_desc['value'].")";
811 }
812 if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
813 $sqlfields[$i] .= " ".$field_desc['attribute'];
814 }
815 if (preg_match("/^[^\s]/i", $field_desc['default'])) {
816 if ((preg_match("/null/i", $field_desc['default'])) || (preg_match("/CURRENT_TIMESTAMP/i", $field_desc['default']))) {
817 $sqlfields[$i] .= " default ".$field_desc['default'];
818 } else {
819 $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
820 }
821 }
822 if (preg_match("/^[^\s]/i", $field_desc['null'])) {
823 $sqlfields[$i] .= " ".$field_desc['null'];
824 }
825 if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
826 $sqlfields[$i] .= " ".$field_desc['extra'];
827 }
828 $i++;
829 }
830 if ($primary_key != "") {
831 $pk = "primary key(".$primary_key.")";
832 }
833
834 if (is_array($unique_keys)) {
835 $i = 0;
836 foreach ($unique_keys as $key => $value) {
837 $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
838 $i++;
839 }
840 }
841 if (is_array($keys)) {
842 $i = 0;
843 foreach ($keys as $key => $value) {
844 $sqlk[$i] = "KEY ".$key." (".$value.")";
845 $i++;
846 }
847 }
848 $sql .= implode(',', $sqlfields);
849 if ($primary_key != "") {
850 $sql .= ",".$pk;
851 }
852 if ($unique_keys != "") {
853 $sql .= ",".implode(',', $sqluq);
854 }
855 if (is_array($keys)) {
856 $sql .= ",".implode(',', $sqlk);
857 }
858 $sql .= ") engine=".$type;
859
860 if (!$this->query($sql)) {
861 return -1;
862 } else {
863 return 1;
864 }
865 }
866
867 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
874 public function DDLDropTable($table)
875 {
876 // phpcs:enable
877 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
878
879 $sql = "DROP TABLE ".$tmptable;
880
881 if (!$this->query($sql)) {
882 return -1;
883 } else {
884 return 1;
885 }
886 }
887
888 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
896 public function DDLDescTable($table, $field = "")
897 {
898 // phpcs:enable
899 $sql = "DESC ".$table." ".$field;
900
901 dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
902 $this->_results = $this->query($sql);
903 return $this->_results;
904 }
905
906 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
916 public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
917 {
918 // phpcs:enable
919 // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
920 // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
921 $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
922 $sql .= $field_desc['type'];
923 if (preg_match("/^[^\s]/i", $field_desc['value'])) {
924 if (!in_array($field_desc['type'], array('date', 'datetime')) && $field_desc['value']) {
925 $sql .= "(".$field_desc['value'].")";
926 }
927 }
928 if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) {
929 $sql .= " ".$field_desc['attribute'];
930 }
931 if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
932 $sql .= " ".$field_desc['null'];
933 }
934 if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
935 if (preg_match("/null/i", $field_desc['default'])) {
936 $sql .= " default ".$field_desc['default'];
937 } else {
938 $sql .= " default '".$this->escape($field_desc['default'])."'";
939 }
940 }
941 if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
942 $sql .= " ".$field_desc['extra'];
943 }
944 $sql .= " ".$field_position;
945
946 dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
947 if ($this->query($sql)) {
948 return 1;
949 }
950 return -1;
951 }
952
953 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
962 public function DDLUpdateField($table, $field_name, $field_desc)
963 {
964 // phpcs:enable
965 $sql = "ALTER TABLE ".$table;
966 $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
967 if (in_array($field_desc['type'], array('double', 'tinyint', 'int', 'varchar')) && $field_desc['value']) {
968 $sql .= "(".$field_desc['value'].")";
969 }
970 if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') {
971 // We will try to change format of column to NOT NULL. To be sure the ALTER works, we try to update fields that are NULL
972 if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') {
973 $sqlbis = "UPDATE ".$table." SET ".$field_name." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$field_name." IS NULL";
974 $this->query($sqlbis);
975 } elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
976 $sqlbis = "UPDATE ".$table." SET ".$field_name." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$field_name." IS NULL";
977 $this->query($sqlbis);
978 }
979
980 $sql .= " NOT NULL";
981 }
982
983 if (isset($field_desc['default']) && $field_desc['default'] != '') {
984 if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
985 $sql .= " DEFAULT ".$this->escape($field_desc['default']);
986 } elseif ($field_desc['type'] != 'text') {
987 $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; // Default not supported on text fields
988 }
989 }
990
991 dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
992 if (!$this->query($sql)) {
993 return -1;
994 } else {
995 return 1;
996 }
997 }
998
999 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1007 public function DDLDropField($table, $field_name)
1008 {
1009 // phpcs:enable
1010 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1011
1012 $sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`";
1013 if ($this->query($sql)) {
1014 return 1;
1015 }
1016 $this->error = $this->lasterror();
1017 return -1;
1018 }
1019
1020
1021 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1031 public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1032 {
1033 // phpcs:enable
1034 $sql = "CREATE USER '".$this->escape($dolibarr_main_db_user)."' IDENTIFIED BY '".$this->escape($dolibarr_main_db_pass)."'";
1035 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1036 $resql = $this->query($sql);
1037 if (!$resql) {
1038 if ($this->lasterrno != 'DB_ERROR_USER_ALREADY_EXISTS') {
1039 return -1;
1040 } else {
1041 // If user already exists, we continue to set permissions
1042 dol_syslog(get_class($this)."::DDLCreateUser sql=".$sql, LOG_WARNING);
1043 }
1044 }
1045
1046 // Redo with localhost forced (sometimes user is created on %)
1047 $sql = "CREATE USER '".$this->escape($dolibarr_main_db_user)."'@'localhost' IDENTIFIED BY '".$this->escape($dolibarr_main_db_pass)."'";
1048 $resql = $this->query($sql);
1049
1050 $sql = "GRANT ALL PRIVILEGES ON ".$this->escape($dolibarr_main_db_name).".* TO '".$this->escape($dolibarr_main_db_user)."'@'".$this->escape($dolibarr_main_db_host)."'";
1051 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1052 $resql = $this->query($sql);
1053 if (!$resql) {
1054 $this->error = "Connected user not allowed to GRANT ALL PRIVILEGES ON ".$this->escape($dolibarr_main_db_name).".* TO '".$this->escape($dolibarr_main_db_user)."'@'".$this->escape($dolibarr_main_db_host)."'";
1055 return -1;
1056 }
1057
1058 $sql = "FLUSH Privileges";
1059
1060 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1061 $resql = $this->query($sql);
1062 if (!$resql) {
1063 return -1;
1064 }
1065
1066 return 1;
1067 }
1068
1076 public function getDefaultCharacterSetDatabase()
1077 {
1078 $resql = $this->query('SHOW VARIABLES LIKE \'character_set_database\'');
1079 if (!$resql) {
1080 // version Mysql < 4.1.1
1081 return $this->forcecharset;
1082 }
1083 $liste = $this->fetch_array($resql);
1084 $tmpval = $liste['Value'];
1085
1086 return $tmpval;
1087 }
1088
1094 public function getListOfCharacterSet()
1095 {
1096 $resql = $this->query('SHOW CHARSET');
1097 $liste = array();
1098 if ($resql) {
1099 $i = 0;
1100 while ($obj = $this->fetch_object($resql)) {
1101 $liste[$i]['charset'] = $obj->Charset;
1102 $liste[$i]['description'] = $obj->Description;
1103 $i++;
1104 }
1105 $this->free($resql);
1106 } else {
1107 // version Mysql < 4.1.1
1108 return null;
1109 }
1110 return $liste;
1111 }
1112
1120 {
1121 $resql = $this->query('SHOW VARIABLES LIKE \'collation_database\'');
1122 if (!$resql) {
1123 // version Mysql < 4.1.1
1124 return $this->forcecollate;
1125 }
1126 $liste = $this->fetch_array($resql);
1127 $tmpval = $liste['Value'];
1128
1129 return $tmpval;
1130 }
1131
1137 public function getListOfCollation()
1138 {
1139 $resql = $this->query('SHOW COLLATION');
1140 $liste = array();
1141 if ($resql) {
1142 $i = 0;
1143 while ($obj = $this->fetch_object($resql)) {
1144 $liste[$i]['collation'] = $obj->Collation;
1145 $i++;
1146 }
1147 $this->free($resql);
1148 } else {
1149 // version Mysql < 4.1.1
1150 return null;
1151 }
1152 return $liste;
1153 }
1154
1160 public function getPathOfDump()
1161 {
1162 $fullpathofdump = '/pathtomysqldump/mysqldump';
1163
1164 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1165 if ($resql) {
1166 $liste = $this->fetch_array($resql);
1167 $basedir = $liste['Value'];
1168 $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1169 }
1170 return $fullpathofdump;
1171 }
1172
1178 public function getPathOfRestore()
1179 {
1180 $fullpathofimport = '/pathtomysql/mysql';
1181
1182 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1183 if ($resql) {
1184 $liste = $this->fetch_array($resql);
1185 $basedir = $liste['Value'];
1186 $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1187 }
1188 return $fullpathofimport;
1189 }
1190
1197 public function getServerParametersValues($filter = '')
1198 {
1199 $result = array();
1200
1201 $sql = 'SHOW VARIABLES';
1202 if ($filter) {
1203 $sql .= " LIKE '".$this->escape($filter)."'";
1204 }
1205 $resql = $this->query($sql);
1206 if ($resql) {
1207 while ($obj = $this->fetch_object($resql)) {
1208 $result[$obj->Variable_name] = $obj->Value;
1209 }
1210 }
1211
1212 return $result;
1213 }
1214
1221 public function getServerStatusValues($filter = '')
1222 {
1223 $result = array();
1224
1225 $sql = 'SHOW STATUS';
1226 if ($filter) {
1227 $sql .= " LIKE '".$this->escape($filter)."'";
1228 }
1229 $resql = $this->query($sql);
1230 if ($resql) {
1231 while ($obj = $this->fetch_object($resql)) {
1232 $result[$obj->Variable_name] = $obj->Value;
1233 }
1234 }
1235
1236 return $result;
1237 }
1238}
Class to manage Dolibarr database access.
lastqueryerror()
Return last query in error.
lasterror()
Return last error label.
lasterrno()
Return last error code.
lastquery()
Return last request executed with query()
Class to manage Dolibarr database access for a MySQL database using the MySQLi extension.
fetch_array($resultset)
Return datas as an array.
__construct($type, $host, $user, $pass, $name='', $port=0)
Constructor.
free($resultset=null)
Libere le dernier resultset utilise sur cette connexion.
escapeforlike($stringtoencode)
Escape a string to insert data into a like.
getServerStatusValues($filter='')
Return value of server status (current indicators on memory, cache...)
num_rows($resultset)
Return number of lines for result of a SELECT.
getServerParametersValues($filter='')
Return value of server parameters.
const VERSIONMIN
Version min database.
$type
Database type.
error()
Return description of last error.
static convertSQLFromMysql($line, $type='ddl')
Convert a SQL request in Mysql syntax to native syntax.
escape($stringtoencode)
Escape a string to insert data.
getVersion()
Return version of database server.
fetch_object($resultset)
Returns the current line (as an object) for the resultset cursor.
encrypt($fieldorvalue, $withQuotes=1)
Encrypt sensitive data in database Warning: This function includes the escape and add the SQL simple ...
affected_rows($resultset)
Return the number of lines in the result of a request INSERT, DELETE or UPDATE.
getDefaultCollationDatabase()
Return collation used in current database.
select_db($database)
Select a database.
decrypt($value)
Decrypt sensitive data in database.
fetch_row($resultset)
Return datas as an array.
last_insert_id($tab, $fieldid='rowid')
Get last ID after an insert INSERT.
const LABEL
Database label.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
hintindex($nameofindex)
Return SQL string to force an index.
getPathOfRestore()
Return full path of restore program.
getPathOfDump()
Return full path of dump program.
connect($host, $login, $passwd, $name, $port=0)
Connect to server.
errno()
Return generic error code of last operation.
getListOfCollation()
Return list of available collation that can be used for database.
getDriverInfo()
Return version of database client driver.
getListOfCharacterSet()
Return list of available charset that can be used to store data in database.
close()
Close database connexion.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1632
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:120