dolibarr  18.0.0
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 
28 require_once DOL_DOCUMENT_ROOT.'/core/db/DoliDB.class.php';
29 
33 class 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 }
DoliDBMysqli\connect
connect($host, $login, $passwd, $name, $port=0)
Connect to server.
Definition: mysqli.class.php:230
DoliDBMysqli\getDriverInfo
getDriverInfo()
Return version of database client driver.
Definition: mysqli.class.php:266
DoliDBMysqli\fetch_object
fetch_object($resultset)
Returns the current line (as an object) for the resultset cursor.
Definition: mysqli.class.php:364
DoliDBMysqli\convertSQLFromMysql
static convertSQLFromMysql($line, $type='ddl')
Convert a SQL request in Mysql syntax to native syntax.
Definition: mysqli.class.php:192
DoliDB\lasterror
lasterror()
Return last error label.
Definition: DoliDB.class.php:329
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
DoliDBMysqli\close
close()
Close database connexion.
Definition: mysqli.class.php:278
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:5107
DoliDBMysqli\num_rows
num_rows($resultset)
Return number of lines for result of a SELECT.
Definition: mysqli.class.php:422
DoliDBMysqli\decrypt
decrypt($value)
Decrypt sensitive data in database.
Definition: mysqli.class.php:611
DoliDBMysqli\fetch_array
fetch_array($resultset)
Return datas as an array.
Definition: mysqli.class.php:382
DoliDBMysqli\getDefaultCollationDatabase
getDefaultCollationDatabase()
Return collation used in current database.
Definition: mysqli.class.php:1119
DoliDBMysqli\getVersion
getVersion()
Return version of database server.
Definition: mysqli.class.php:256
rowid
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
Definition: email_expire_services_to_representatives.php:79
DoliDB\lastquery
lastquery()
Return last request executed with query()
Definition: DoliDB.class.php:274
DoliDBMysqli\__construct
__construct($type, $host, $user, $pass, $name='', $port=0)
Constructor.
Definition: mysqli.class.php:59
Exception
DoliDBMysqli\affected_rows
affected_rows($resultset)
Return the number of lines in the result of a request INSERT, DELETE or UPDATE.
Definition: mysqli.class.php:440
DoliDBMysqli\free
free($resultset=null)
Libere le dernier resultset utilise sur cette connexion.
Definition: mysqli.class.php:459
DoliDBMysqli\getPathOfRestore
getPathOfRestore()
Return full path of restore program.
Definition: mysqli.class.php:1178
DoliDBMysqli\getListOfCollation
getListOfCollation()
Return list of available collation that can be used for database.
Definition: mysqli.class.php:1137
DoliDBMysqli\$type
$type
Database type.
Definition: mysqli.class.php:38
DoliDBMysqli\getServerStatusValues
getServerStatusValues($filter='')
Return value of server status (current indicators on memory, cache...)
Definition: mysqli.class.php:1221
DoliDB\lasterrno
lasterrno()
Return last error code.
Definition: DoliDB.class.php:151
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1741
DoliDBMysqli\escape
escape($stringtoencode)
Escape a string to insert data.
Definition: mysqli.class.php:477
DoliDBMysqli
Class to manage Dolibarr database access for a MySQL database using the MySQLi extension.
Definition: mysqli.class.php:33
DoliDBMysqli\select_db
select_db($database)
Select a database.
Definition: mysqli.class.php:205
DoliDBMysqli\getListOfCharacterSet
getListOfCharacterSet()
Return list of available charset that can be used to store data in database.
Definition: mysqli.class.php:1094
DoliDBMysqli\getPathOfDump
getPathOfDump()
Return full path of dump program.
Definition: mysqli.class.php:1160
DoliDBMysqli\escapeforlike
escapeforlike($stringtoencode)
Escape a string to insert data into a like.
Definition: mysqli.class.php:488
$sql
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
DoliDBMysqli\query
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
Definition: mysqli.class.php:302
DoliDBMysqli\fetch_row
fetch_row($resultset)
Return datas as an array.
Definition: mysqli.class.php:399
DoliDB\lastqueryerror
lastqueryerror()
Return last query in error.
Definition: DoliDB.class.php:360
DoliDBMysqli\encrypt
encrypt($fieldorvalue, $withQuotes=1)
Encrypt sensitive data in database Warning: This function includes the escape and add the SQL simple ...
Definition: mysqli.class.php:582
DoliDBMysqli\LABEL
const LABEL
Database label.
Definition: mysqli.class.php:41
DoliDBMysqli\getServerParametersValues
getServerParametersValues($filter='')
Return value of server parameters.
Definition: mysqli.class.php:1197
DoliDBMysqli\VERSIONMIN
const VERSIONMIN
Version min database.
Definition: mysqli.class.php:43
DoliDBMysqli\error
error()
Return description of last error.
Definition: mysqli.class.php:550
DoliDBMysqli\hintindex
hintindex($nameofindex)
Return SQL string to force an index.
Definition: mysqli.class.php:179
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:156
DoliDBMysqli\last_insert_id
last_insert_id($tab, $fieldid='rowid')
Get last ID after an insert INSERT.
Definition: mysqli.class.php:568
type
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120
DoliDBMysqli\errno
errno()
Return generic error code of last operation.
Definition: mysqli.class.php:498