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 }
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.
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 ...
convertSQLFromMysql($line, $type='ddl')
Convert a SQL request in Mysql syntax to native syntax.
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.
Class to make SSL connection.
__construct($host, $user, $pass, $name, $port=0, $socket="")
Constructor.
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