dolibarr  19.0.0-dev
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 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  $tmp = false;
237  try {
238  if (!class_exists('mysqli')) {
239  dol_print_error('', 'Driver mysqli for PHP not available');
240  }
241  if (strpos($host, 'ssl://') === 0) {
242  $tmp = new mysqliDoli($host, $login, $passwd, $name, $port);
243  } else {
244  $tmp = new mysqli($host, $login, $passwd, $name, $port);
245  }
246  } catch (Exception $e) {
247  dol_syslog(get_class($this)."::connect failed", LOG_DEBUG);
248  }
249  return $tmp;
250  }
251 
257  public function getVersion()
258  {
259  return $this->db->server_info;
260  }
261 
267  public function getDriverInfo()
268  {
269  return $this->db->client_info;
270  }
271 
272 
279  public function close()
280  {
281  if ($this->db) {
282  if ($this->transaction_opened > 0) {
283  dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
284  }
285  $this->connected = false;
286  return $this->db->close();
287  }
288  return false;
289  }
290 
291 
292 
303  public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
304  {
305  global $conf, $dolibarr_main_db_readonly;
306 
307  $query = trim($query);
308 
309  if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK'))) {
310  $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
311  dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
312  }
313  if (empty($query)) {
314  return false; // Return false = error if empty request
315  }
316 
317  if (!empty($dolibarr_main_db_readonly)) {
318  if (preg_match('/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
319  $this->lasterror = 'Application in read-only mode';
320  $this->lasterrno = 'APPREADONLY';
321  $this->lastquery = $query;
322  return false;
323  }
324  }
325 
326  try {
327  if (!$this->database_name) {
328  // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
329  $ret = $this->db->query($query, $result_mode);
330  } else {
331  $ret = $this->db->query($query, $result_mode);
332  }
333  } catch (Exception $e) {
334  dol_syslog(get_class($this)."::query Exception in query instead of returning an error: ".$e->getMessage(), LOG_ERR);
335  $ret = false;
336  }
337 
338  if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {
339  // Si requete utilisateur, on la sauvegarde ainsi que son resultset
340  if (!$ret) {
341  $this->lastqueryerror = $query;
342  $this->lasterror = $this->error();
343  $this->lasterrno = $this->errno();
344 
345  if (getDolGlobalInt('SYSLOG_LEVEL') < LOG_DEBUG) {
346  dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
347  }
348  dol_syslog(get_class($this)."::query SQL Error message: ".$this->lasterrno." ".$this->lasterror, LOG_ERR);
349  //var_dump(debug_print_backtrace());
350  }
351  $this->lastquery = $query;
352  $this->_results = $ret;
353  }
354 
355  return $ret;
356  }
357 
358  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
365  public function fetch_object($resultset)
366  {
367  // phpcs:enable
368  // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
369  if (!is_object($resultset)) {
370  $resultset = $this->_results;
371  }
372  return $resultset->fetch_object();
373  }
374 
375 
376  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
383  public function fetch_array($resultset)
384  {
385  // phpcs:enable
386  // If resultset not provided, we take the last used by connexion
387  if (!is_object($resultset)) {
388  $resultset = $this->_results;
389  }
390  return $resultset->fetch_array();
391  }
392 
393  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
400  public function fetch_row($resultset)
401  {
402  // phpcs:enable
403  // If resultset not provided, we take the last used by connexion
404  if (!is_bool($resultset)) {
405  if (!is_object($resultset)) {
406  $resultset = $this->_results;
407  }
408  return $resultset->fetch_row();
409  } else {
410  // si le curseur est un booleen on retourne la valeur 0
411  return 0;
412  }
413  }
414 
415  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
423  public function num_rows($resultset)
424  {
425  // phpcs:enable
426  // If resultset not provided, we take the last used by connexion
427  if (!is_object($resultset)) {
428  $resultset = $this->_results;
429  }
430  return isset($resultset->num_rows) ? $resultset->num_rows : 0;
431  }
432 
433  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
441  public function affected_rows($resultset)
442  {
443  // phpcs:enable
444  // If resultset not provided, we take the last used by connexion
445  if (!is_object($resultset)) {
446  $resultset = $this->_results;
447  }
448  // mysql necessite un link de base pour cette fonction contrairement
449  // a pqsql qui prend un resultset
450  return $this->db->affected_rows;
451  }
452 
453 
460  public function free($resultset = null)
461  {
462  // If resultset not provided, we take the last used by connexion
463  if (!is_object($resultset)) {
464  $resultset = $this->_results;
465  }
466  // Si resultset en est un, on libere la memoire
467  if (is_object($resultset)) {
468  $resultset->free_result();
469  }
470  }
471 
478  public function escape($stringtoencode)
479  {
480  return $this->db->real_escape_string((string) $stringtoencode);
481  }
482 
489  public function escapeforlike($stringtoencode)
490  {
491  return str_replace(array('\\', '_', '%'), array('\\\\', '\_', '\%'), (string) $stringtoencode);
492  }
493 
499  public function errno()
500  {
501  if (!$this->connected) {
502  // Si il y a eu echec de connexion, $this->db n'est pas valide.
503  return 'DB_ERROR_FAILED_TO_CONNECT';
504  } else {
505  // Constants to convert a MySql error code to a generic Dolibarr error code
506  $errorcode_map = array(
507  1004 => 'DB_ERROR_CANNOT_CREATE',
508  1005 => 'DB_ERROR_CANNOT_CREATE',
509  1006 => 'DB_ERROR_CANNOT_CREATE',
510  1007 => 'DB_ERROR_ALREADY_EXISTS',
511  1008 => 'DB_ERROR_CANNOT_DROP',
512  1022 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
513  1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
514  1044 => 'DB_ERROR_ACCESSDENIED',
515  1046 => 'DB_ERROR_NODBSELECTED',
516  1048 => 'DB_ERROR_CONSTRAINT',
517  1050 => 'DB_ERROR_TABLE_ALREADY_EXISTS',
518  1051 => 'DB_ERROR_NOSUCHTABLE',
519  1054 => 'DB_ERROR_NOSUCHFIELD',
520  1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
521  1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
522  1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
523  1064 => 'DB_ERROR_SYNTAX',
524  1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
525  1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
526  1091 => 'DB_ERROR_NOSUCHFIELD',
527  1100 => 'DB_ERROR_NOT_LOCKED',
528  1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
529  1146 => 'DB_ERROR_NOSUCHTABLE',
530  1215 => 'DB_ERROR_CANNOT_ADD_FOREIGN_KEY_CONSTRAINT',
531  1216 => 'DB_ERROR_NO_PARENT',
532  1217 => 'DB_ERROR_CHILD_EXISTS',
533  1396 => 'DB_ERROR_USER_ALREADY_EXISTS', // When creating a user that already existing
534  1451 => 'DB_ERROR_CHILD_EXISTS',
535  1826 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS'
536  );
537 
538  if (isset($errorcode_map[$this->db->errno])) {
539  return $errorcode_map[$this->db->errno];
540  }
541  $errno = $this->db->errno;
542  return ($errno ? 'DB_ERROR_'.$errno : '0');
543  }
544  }
545 
551  public function error()
552  {
553  if (!$this->connected) {
554  // Si il y a eu echec de connexion, $this->db n'est pas valide pour mysqli_error.
555  return 'Not connected. Check setup parameters in conf/conf.php file and your mysql client and server versions';
556  } else {
557  return $this->db->error;
558  }
559  }
560 
561  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
569  public function last_insert_id($tab, $fieldid = 'rowid')
570  {
571  // phpcs:enable
572  return $this->db->insert_id;
573  }
574 
583  public function encrypt($fieldorvalue, $withQuotes = 1)
584  {
585  global $conf;
586 
587  // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
588  $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
589 
590  //Encryption key
591  $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
592 
593  $escapedstringwithquotes = ($withQuotes ? "'" : "").$this->escape($fieldorvalue).($withQuotes ? "'" : "");
594 
595  if ($cryptType && !empty($cryptKey)) {
596  if ($cryptType == 2) {
597  $escapedstringwithquotes = "AES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
598  } elseif ($cryptType == 1) {
599  $escapedstringwithquotes = "DES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
600  }
601  }
602 
603  return $escapedstringwithquotes;
604  }
605 
612  public function decrypt($value)
613  {
614  global $conf;
615 
616  // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
617  $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
618 
619  //Encryption key
620  $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
621 
622  $return = $value;
623 
624  if ($cryptType && !empty($cryptKey)) {
625  if ($cryptType == 2) {
626  $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
627  } elseif ($cryptType == 1) {
628  $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
629  }
630  }
631 
632  return $return;
633  }
634 
635 
636  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
642  public function DDLGetConnectId()
643  {
644  // phpcs:enable
645  $resql = $this->query('SELECT CONNECTION_ID()');
646  if ($resql) {
647  $row = $this->fetch_row($resql);
648  return $row[0];
649  } else {
650  return '?';
651  }
652  }
653 
654  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
666  public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
667  {
668  // phpcs:enable
669  if (empty($charset)) {
670  $charset = $this->forcecharset;
671  }
672  if (empty($collation)) {
673  $collation = $this->forcecollate;
674  }
675 
676  // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
677  $sql = "CREATE DATABASE `".$this->escape($database)."`";
678  $sql .= " DEFAULT CHARACTER SET `".$this->escape($charset)."` DEFAULT COLLATE `".$this->escape($collation)."`";
679 
680  dol_syslog($sql, LOG_DEBUG);
681  $ret = $this->query($sql);
682  if (!$ret) {
683  // We try again for compatibility with Mysql < 4.1.1
684  $sql = "CREATE DATABASE `".$this->escape($database)."`";
685  dol_syslog($sql, LOG_DEBUG);
686  $ret = $this->query($sql);
687  }
688  return $ret;
689  }
690 
691  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
699  public function DDLListTables($database, $table = '')
700  {
701  // phpcs:enable
702  $listtables = array();
703 
704  $like = '';
705  if ($table) {
706  $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
707 
708  $like = "LIKE '".$this->escape($tmptable)."'";
709  }
710  $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
711 
712  $sql = "SHOW TABLES FROM `".$tmpdatabase."` ".$like.";";
713  //print $sql;
714  $result = $this->query($sql);
715  if ($result) {
716  while ($row = $this->fetch_row($result)) {
717  $listtables[] = $row[0];
718  }
719  }
720  return $listtables;
721  }
722 
723  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
731  public function DDLListTablesFull($database, $table = '')
732  {
733  // phpcs:enable
734  $listtables = array();
735 
736  $like = '';
737  if ($table) {
738  $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
739 
740  $like = "LIKE '".$this->escape($tmptable)."'";
741  }
742  $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
743 
744  $sql = "SHOW FULL TABLES FROM `".$tmpdatabase."` ".$like.";";
745 
746  $result = $this->query($sql);
747  if ($result) {
748  while ($row = $this->fetch_row($result)) {
749  $listtables[] = $row;
750  }
751  }
752  return $listtables;
753  }
754 
755  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
762  public function DDLInfoTable($table)
763  {
764  // phpcs:enable
765  $infotables = array();
766 
767  $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
768 
769  $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
770 
771  dol_syslog($sql, LOG_DEBUG);
772  $result = $this->query($sql);
773  if ($result) {
774  while ($row = $this->fetch_row($result)) {
775  $infotables[] = $row;
776  }
777  }
778  return $infotables;
779  }
780 
781  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
794  public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
795  {
796  // phpcs:enable
797  // FIXME: $fulltext_keys parameter is unused
798 
799  $pk = '';
800  $sqluq = $sqlk = array();
801 
802  // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
803  // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
804  $sql = "CREATE TABLE ".$table."(";
805  $i = 0;
806  $sqlfields = array();
807  foreach ($fields as $field_name => $field_desc) {
808  $sqlfields[$i] = $field_name." ";
809  $sqlfields[$i] .= $field_desc['type'];
810  if (preg_match("/^[^\s]/i", $field_desc['value'])) {
811  $sqlfields[$i] .= "(".$field_desc['value'].")";
812  }
813  if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
814  $sqlfields[$i] .= " ".$field_desc['attribute'];
815  }
816  if (preg_match("/^[^\s]/i", $field_desc['default'])) {
817  if ((preg_match("/null/i", $field_desc['default'])) || (preg_match("/CURRENT_TIMESTAMP/i", $field_desc['default']))) {
818  $sqlfields[$i] .= " default ".$field_desc['default'];
819  } else {
820  $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
821  }
822  }
823  if (preg_match("/^[^\s]/i", $field_desc['null'])) {
824  $sqlfields[$i] .= " ".$field_desc['null'];
825  }
826  if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
827  $sqlfields[$i] .= " ".$field_desc['extra'];
828  }
829  $i++;
830  }
831  if ($primary_key != "") {
832  $pk = "primary key(".$primary_key.")";
833  }
834 
835  if (is_array($unique_keys)) {
836  $i = 0;
837  foreach ($unique_keys as $key => $value) {
838  $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
839  $i++;
840  }
841  }
842  if (is_array($keys)) {
843  $i = 0;
844  foreach ($keys as $key => $value) {
845  $sqlk[$i] = "KEY ".$key." (".$value.")";
846  $i++;
847  }
848  }
849  $sql .= implode(',', $sqlfields);
850  if ($primary_key != "") {
851  $sql .= ",".$pk;
852  }
853  if ($unique_keys != "") {
854  $sql .= ",".implode(',', $sqluq);
855  }
856  if (is_array($keys)) {
857  $sql .= ",".implode(',', $sqlk);
858  }
859  $sql .= ") engine=".$type;
860 
861  if (!$this->query($sql)) {
862  return -1;
863  } else {
864  return 1;
865  }
866  }
867 
868  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
875  public function DDLDropTable($table)
876  {
877  // phpcs:enable
878  $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
879 
880  $sql = "DROP TABLE ".$tmptable;
881 
882  if (!$this->query($sql)) {
883  return -1;
884  } else {
885  return 1;
886  }
887  }
888 
889  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
897  public function DDLDescTable($table, $field = "")
898  {
899  // phpcs:enable
900  $sql = "DESC ".$table." ".$field;
901 
902  dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
903  $this->_results = $this->query($sql);
904  return $this->_results;
905  }
906 
907  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
917  public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
918  {
919  // phpcs:enable
920  // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
921  // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
922  $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
923  $sql .= $field_desc['type'];
924  if (preg_match("/^[^\s]/i", $field_desc['value'])) {
925  if (!in_array($field_desc['type'], array('date', 'datetime')) && $field_desc['value']) {
926  $sql .= "(".$field_desc['value'].")";
927  }
928  }
929  if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) {
930  $sql .= " ".$field_desc['attribute'];
931  }
932  if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
933  $sql .= " ".$field_desc['null'];
934  }
935  if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
936  if (preg_match("/null/i", $field_desc['default'])) {
937  $sql .= " default ".$field_desc['default'];
938  } else {
939  $sql .= " default '".$this->escape($field_desc['default'])."'";
940  }
941  }
942  if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
943  $sql .= " ".$field_desc['extra'];
944  }
945  $sql .= " ".$field_position;
946 
947  dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
948  if ($this->query($sql)) {
949  return 1;
950  }
951  return -1;
952  }
953 
954  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
963  public function DDLUpdateField($table, $field_name, $field_desc)
964  {
965  // phpcs:enable
966  $sql = "ALTER TABLE ".$table;
967  $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
968  if (in_array($field_desc['type'], array('double', 'tinyint', 'int', 'varchar')) && $field_desc['value']) {
969  $sql .= "(".$field_desc['value'].")";
970  }
971  if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') {
972  // 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
973  if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') {
974  $sqlbis = "UPDATE ".$table." SET ".$field_name." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$field_name." IS NULL";
975  $this->query($sqlbis);
976  } elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
977  $sqlbis = "UPDATE ".$table." SET ".$field_name." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$field_name." IS NULL";
978  $this->query($sqlbis);
979  }
980 
981  $sql .= " NOT NULL";
982  }
983 
984  if (isset($field_desc['default']) && $field_desc['default'] != '') {
985  if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
986  $sql .= " DEFAULT ".$this->escape($field_desc['default']);
987  } elseif ($field_desc['type'] != 'text') {
988  $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; // Default not supported on text fields
989  }
990  }
991 
992  dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
993  if (!$this->query($sql)) {
994  return -1;
995  } else {
996  return 1;
997  }
998  }
999 
1000  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1008  public function DDLDropField($table, $field_name)
1009  {
1010  // phpcs:enable
1011  $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1012 
1013  $sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`";
1014  if ($this->query($sql)) {
1015  return 1;
1016  }
1017  $this->error = $this->lasterror();
1018  return -1;
1019  }
1020 
1021 
1022  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1032  public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1033  {
1034  // phpcs:enable
1035  $sql = "CREATE USER '".$this->escape($dolibarr_main_db_user)."' IDENTIFIED BY '".$this->escape($dolibarr_main_db_pass)."'";
1036  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1037  $resql = $this->query($sql);
1038  if (!$resql) {
1039  if ($this->lasterrno != 'DB_ERROR_USER_ALREADY_EXISTS') {
1040  return -1;
1041  } else {
1042  // If user already exists, we continue to set permissions
1043  dol_syslog(get_class($this)."::DDLCreateUser sql=".$sql, LOG_WARNING);
1044  }
1045  }
1046 
1047  // Redo with localhost forced (sometimes user is created on %)
1048  $sql = "CREATE USER '".$this->escape($dolibarr_main_db_user)."'@'localhost' IDENTIFIED BY '".$this->escape($dolibarr_main_db_pass)."'";
1049  $resql = $this->query($sql);
1050 
1051  $sql = "GRANT ALL PRIVILEGES ON ".$this->escape($dolibarr_main_db_name).".* TO '".$this->escape($dolibarr_main_db_user)."'@'".$this->escape($dolibarr_main_db_host)."'";
1052  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1053  $resql = $this->query($sql);
1054  if (!$resql) {
1055  $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)."'";
1056  return -1;
1057  }
1058 
1059  $sql = "FLUSH Privileges";
1060 
1061  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1062  $resql = $this->query($sql);
1063  if (!$resql) {
1064  return -1;
1065  }
1066 
1067  return 1;
1068  }
1069 
1077  public function getDefaultCharacterSetDatabase()
1078  {
1079  $resql = $this->query('SHOW VARIABLES LIKE \'character_set_database\'');
1080  if (!$resql) {
1081  // version Mysql < 4.1.1
1082  return $this->forcecharset;
1083  }
1084  $liste = $this->fetch_array($resql);
1085  $tmpval = $liste['Value'];
1086 
1087  return $tmpval;
1088  }
1089 
1095  public function getListOfCharacterSet()
1096  {
1097  $resql = $this->query('SHOW CHARSET');
1098  $liste = array();
1099  if ($resql) {
1100  $i = 0;
1101  while ($obj = $this->fetch_object($resql)) {
1102  $liste[$i]['charset'] = $obj->Charset;
1103  $liste[$i]['description'] = $obj->Description;
1104  $i++;
1105  }
1106  $this->free($resql);
1107  } else {
1108  // version Mysql < 4.1.1
1109  return null;
1110  }
1111  return $liste;
1112  }
1113 
1121  {
1122  $resql = $this->query('SHOW VARIABLES LIKE \'collation_database\'');
1123  if (!$resql) {
1124  // version Mysql < 4.1.1
1125  return $this->forcecollate;
1126  }
1127  $liste = $this->fetch_array($resql);
1128  $tmpval = $liste['Value'];
1129 
1130  return $tmpval;
1131  }
1132 
1138  public function getListOfCollation()
1139  {
1140  $resql = $this->query('SHOW COLLATION');
1141  $liste = array();
1142  if ($resql) {
1143  $i = 0;
1144  while ($obj = $this->fetch_object($resql)) {
1145  $liste[$i]['collation'] = $obj->Collation;
1146  $i++;
1147  }
1148  $this->free($resql);
1149  } else {
1150  // version Mysql < 4.1.1
1151  return null;
1152  }
1153  return $liste;
1154  }
1155 
1161  public function getPathOfDump()
1162  {
1163  $fullpathofdump = '/pathtomysqldump/mysqldump';
1164 
1165  $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1166  if ($resql) {
1167  $liste = $this->fetch_array($resql);
1168  $basedir = $liste['Value'];
1169  $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1170  }
1171  return $fullpathofdump;
1172  }
1173 
1179  public function getPathOfRestore()
1180  {
1181  $fullpathofimport = '/pathtomysql/mysql';
1182 
1183  $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1184  if ($resql) {
1185  $liste = $this->fetch_array($resql);
1186  $basedir = $liste['Value'];
1187  $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1188  }
1189  return $fullpathofimport;
1190  }
1191 
1198  public function getServerParametersValues($filter = '')
1199  {
1200  $result = array();
1201 
1202  $sql = 'SHOW VARIABLES';
1203  if ($filter) {
1204  $sql .= " LIKE '".$this->escape($filter)."'";
1205  }
1206  $resql = $this->query($sql);
1207  if ($resql) {
1208  while ($obj = $this->fetch_object($resql)) {
1209  $result[$obj->Variable_name] = $obj->Value;
1210  }
1211  }
1212 
1213  return $result;
1214  }
1215 
1222  public function getServerStatusValues($filter = '')
1223  {
1224  $result = array();
1225 
1226  $sql = 'SHOW STATUS';
1227  if ($filter) {
1228  $sql .= " LIKE '".$this->escape($filter)."'";
1229  }
1230  $resql = $this->query($sql);
1231  if ($resql) {
1232  while ($obj = $this->fetch_object($resql)) {
1233  $result[$obj->Variable_name] = $obj->Value;
1234  }
1235  }
1236 
1237  return $result;
1238  }
1239 }
1240 
1244 class mysqliDoli extends mysqli
1245 {
1257  public function __construct($host, $user, $pass, $name, $port = 0, $socket = "")
1258  {
1259  $flags = 0;
1260  parent::init();
1261  if (strpos($host, 'ssl://') === 0) {
1262  $host = substr($host, 6);
1263  parent::options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, false);
1264  parent::ssl_set(null, null, "", null, null);
1265  $flags = MYSQLI_CLIENT_SSL;
1266  }
1267  parent::real_connect($host, $user, $pass, $name, $port, $socket, $flags);
1268  }
1269 }
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:267
DoliDBMysqli\fetch_object
fetch_object($resultset)
Returns the current line (as an object) for the resultset cursor.
Definition: mysqli.class.php:365
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:279
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:423
DoliDBMysqli\decrypt
decrypt($value)
Decrypt sensitive data in database.
Definition: mysqli.class.php:612
DoliDBMysqli\fetch_array
fetch_array($resultset)
Return datas as an array.
Definition: mysqli.class.php:383
DoliDBMysqli\getDefaultCollationDatabase
getDefaultCollationDatabase()
Return collation used in current database.
Definition: mysqli.class.php:1120
mysqliDoli\__construct
__construct($host, $user, $pass, $name, $port=0, $socket="")
Constructor.
Definition: mysqli.class.php:1257
DoliDBMysqli\getVersion
getVersion()
Return version of database server.
Definition: mysqli.class.php:257
mysqli
DoliDBMysqli\convertSQLFromMysql
convertSQLFromMysql($line, $type='ddl')
Convert a SQL request in Mysql syntax to native syntax.
Definition: mysqli.class.php:192
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:441
DoliDBMysqli\free
free($resultset=null)
Libere le dernier resultset utilise sur cette connexion.
Definition: mysqli.class.php:460
DoliDBMysqli\getPathOfRestore
getPathOfRestore()
Return full path of restore program.
Definition: mysqli.class.php:1179
DoliDBMysqli\getListOfCollation
getListOfCollation()
Return list of available collation that can be used for database.
Definition: mysqli.class.php:1138
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:1222
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:478
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:1095
DoliDBMysqli\getPathOfDump
getPathOfDump()
Return full path of dump program.
Definition: mysqli.class.php:1161
DoliDBMysqli\escapeforlike
escapeforlike($stringtoencode)
Escape a string to insert data into a like.
Definition: mysqli.class.php:489
$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:303
DoliDBMysqli\fetch_row
fetch_row($resultset)
Return datas as an array.
Definition: mysqli.class.php:400
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:583
DoliDBMysqli\LABEL
const LABEL
Database label.
Definition: mysqli.class.php:41
DoliDBMysqli\getServerParametersValues
getServerParametersValues($filter='')
Return value of server parameters.
Definition: mysqli.class.php:1198
DoliDBMysqli\VERSIONMIN
const VERSIONMIN
Version min database.
Definition: mysqli.class.php:43
DoliDBMysqli\error
error()
Return description of last error.
Definition: mysqli.class.php:551
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
mysqliDoli
Class to make SSL connection.
Definition: mysqli.class.php:1244
DoliDBMysqli\last_insert_id
last_insert_id($tab, $fieldid='rowid')
Get last ID after an insert INSERT.
Definition: mysqli.class.php:569
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:499