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 
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 }
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.
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
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
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.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120