dolibarr 19.0.4
mysqli.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001 Fabien Seisen <seisen@linuxfr.org>
3 * Copyright (C) 2002-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
4 * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
6 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
7 * Copyright (C) 2015 Raphaƫl Doursenaud <rdoursenaud@gpcsolutions.fr>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
28require_once DOL_DOCUMENT_ROOT.'/core/db/DoliDB.class.php';
29
33class DoliDBMysqli extends DoliDB
34{
36 public $db;
38 public $type = 'mysqli';
39
41 const LABEL = 'MySQL or MariaDB';
43 const VERSIONMIN = '5.0.3';
44
46 private $_results;
47
59 public function __construct($type, $host, $user, $pass, $name = '', $port = 0)
60 {
61 global $conf, $langs;
62
63 // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
64 if (!empty($conf->db->character_set)) {
65 $this->forcecharset = $conf->db->character_set;
66 }
67 if (!empty($conf->db->dolibarr_main_db_collation)) {
68 $this->forcecollate = $conf->db->dolibarr_main_db_collation;
69 }
70
71 $this->database_user = $user;
72 $this->database_host = $host;
73 $this->database_port = $port;
74
75 $this->transaction_opened = 0;
76
77 //print "Name DB: $host,$user,$pass,$name<br>";
78
79 if (!class_exists('mysqli')) {
80 $this->connected = false;
81 $this->ok = false;
82 $this->error = "Mysqli PHP functions for using Mysqli driver are not available in this version of PHP. Try to use another driver.";
83 dol_syslog(get_class($this)."::DoliDBMysqli : Mysqli PHP functions for using Mysqli driver are not available in this version of PHP. Try to use another driver.", LOG_ERR);
84 }
85
86 if (!$host) {
87 $this->connected = false;
88 $this->ok = false;
89 $this->error = $langs->trans("ErrorWrongHostParameter");
90 dol_syslog(get_class($this)."::DoliDBMysqli : Connect error, wrong host parameters", LOG_ERR);
91 }
92
93 // Try server connection
94 // We do not try to connect to database, only to server. Connect to database is done later in constrcutor
95 $this->db = $this->connect($host, $user, $pass, '', $port);
96
97 if ($this->db && empty($this->db->connect_errno)) {
98 $this->connected = true;
99 $this->ok = true;
100 } else {
101 $this->connected = false;
102 $this->ok = false;
103 $this->error = empty($this->db) ? 'Failed to connect' : $this->db->connect_error;
104 dol_syslog(get_class($this)."::DoliDBMysqli Connect error: ".$this->error, LOG_ERR);
105 }
106
107 // If server connection is ok, we try to connect to the database
108 if ($this->connected && $name) {
109 if ($this->select_db($name)) {
110 $this->database_selected = true;
111 $this->database_name = $name;
112 $this->ok = true;
113
114 // If client is old latin, we force utf8
115 $clientmustbe = empty($conf->db->character_set) ? 'utf8' : $conf->db->character_set;
116 if (preg_match('/latin1/', $clientmustbe)) {
117 $clientmustbe = 'utf8';
118 }
119
120 $disableforcecharset = 0; // Set to 1 to test without charset forcing
121 if (empty($disableforcecharset) && $this->db->character_set_name() != $clientmustbe) {
122 try {
123 //print "You should set the \$dolibarr_main_db_character_set and \$dolibarr_main_db_collation for the PHP to the one of the database ".$this->db->character_set_name();
124 dol_syslog(get_class($this)."::DoliDBMysqli You should set the \$dolibarr_main_db_character_set and \$dolibarr_main_db_collation for the PHP to the one of the database ".$this->db->character_set_name(), LOG_WARNING);
125 $this->db->set_charset($clientmustbe); // This set charset, but with a bad collation
126 } catch (Exception $e) {
127 print 'Failed to force character set to '.$clientmustbe." according to setup to match the one of the server database.<br>\n";
128 print $e->getMessage();
129 print "<br>\n";
130 if ($clientmustbe != 'utf8') {
131 print 'Edit conf/conf.php file to set a charset "utf8" instead of "'.$clientmustbe.'".'."\n";
132 }
133 exit;
134 }
135
136 $collation = (empty($conf) ? 'utf8_unicode_ci' : $conf->db->dolibarr_main_db_collation);
137 if (preg_match('/latin1/', $collation)) {
138 $collation = 'utf8_unicode_ci';
139 }
140
141 if (!preg_match('/general/', $collation)) {
142 $this->db->query("SET collation_connection = ".$collation);
143 }
144 }
145 } else {
146 $this->database_selected = false;
147 $this->database_name = '';
148 $this->ok = false;
149 $this->error = $this->error();
150 dol_syslog(get_class($this)."::DoliDBMysqli : Select_db error ".$this->error, LOG_ERR);
151 }
152 } else {
153 // No selection of database done. We may only be connected or not (ok or ko) to the server.
154 $this->database_selected = false;
155
156 if ($this->connected) {
157 // If client is old latin, we force utf8
158 $clientmustbe = empty($conf->db->character_set) ? 'utf8' : $conf->db->character_set;
159 if (preg_match('/latin1/', $clientmustbe)) {
160 $clientmustbe = 'utf8';
161 }
162 if (preg_match('/utf8mb4/', $clientmustbe)) {
163 $clientmustbe = 'utf8';
164 }
165
166 if ($this->db->character_set_name() != $clientmustbe) {
167 $this->db->set_charset($clientmustbe); // This set utf8_unicode_ci
168
169 $collation = $conf->db->dolibarr_main_db_collation;
170 if (preg_match('/latin1/', $collation)) {
171 $collation = 'utf8_unicode_ci';
172 }
173 if (preg_match('/utf8mb4/', $collation)) {
174 $collation = 'utf8_unicode_ci';
175 }
176
177 if (!preg_match('/general/', $collation)) {
178 $this->db->query("SET collation_connection = ".$collation);
179 }
180 }
181 }
182 }
183 }
184
185
192 public function hintindex($nameofindex)
193 {
194 return " FORCE INDEX(".preg_replace('/[^a-z0-9_]/', '', $nameofindex).")";
195 }
196
197
205 public function convertSQLFromMysql($line, $type = 'ddl')
206 {
207 return $line;
208 }
209
210
211 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
218 public function select_db($database)
219 {
220 // phpcs:enable
221 dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
222 $result = false;
223 try {
224 $result = $this->db->select_db($database);
225 } catch (Exception $e) {
226 // Nothing done on error
227 }
228 return $result;
229 }
230
231
243 public function connect($host, $login, $passwd, $name, $port = 0)
244 {
245 dol_syslog(get_class($this)."::connect host=$host, port=$port, login=$login, passwd=--hidden--, name=$name", LOG_DEBUG);
246
247 //mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
248
249 $tmp = false;
250 try {
251 if (!class_exists('mysqli')) {
252 dol_print_error('', 'Driver mysqli for PHP not available');
253 }
254 if (strpos($host, 'ssl://') === 0) {
255 $tmp = new mysqliDoli($host, $login, $passwd, $name, $port);
256 } else {
257 $tmp = new mysqli($host, $login, $passwd, $name, $port);
258 }
259 } catch (Exception $e) {
260 dol_syslog(get_class($this)."::connect failed", LOG_DEBUG);
261 }
262 return $tmp;
263 }
264
270 public function getVersion()
271 {
272 return $this->db->server_info;
273 }
274
280 public function getDriverInfo()
281 {
282 return $this->db->client_info;
283 }
284
285
292 public function close()
293 {
294 if ($this->db) {
295 if ($this->transaction_opened > 0) {
296 dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
297 }
298 $this->connected = false;
299 return $this->db->close();
300 }
301 return false;
302 }
303
304
305
316 public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
317 {
318 global $conf, $dolibarr_main_db_readonly;
319
320 $query = trim($query);
321
322 if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK'))) {
323 $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
324 dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
325 }
326 if (empty($query)) {
327 return false; // Return false = error if empty request
328 }
329
330 if (!empty($dolibarr_main_db_readonly)) {
331 if (preg_match('/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
332 $this->lasterror = 'Application in read-only mode';
333 $this->lasterrno = 'APPREADONLY';
334 $this->lastquery = $query;
335 return false;
336 }
337 }
338
339 try {
340 if (!$this->database_name) {
341 // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
342 $ret = $this->db->query($query, $result_mode);
343 } else {
344 $ret = $this->db->query($query, $result_mode);
345 }
346 } catch (Exception $e) {
347 dol_syslog(get_class($this)."::query Exception in query instead of returning an error: ".$e->getMessage(), LOG_ERR);
348 $ret = false;
349 }
350
351 if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {
352 // Si requete utilisateur, on la sauvegarde ainsi que son resultset
353 if (!$ret) {
354 $this->lastqueryerror = $query;
355 $this->lasterror = $this->error();
356 $this->lasterrno = $this->errno();
357
358 if (getDolGlobalInt('SYSLOG_LEVEL') < LOG_DEBUG) {
359 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
360 }
361 dol_syslog(get_class($this)."::query SQL Error message: ".$this->lasterrno." ".$this->lasterror, LOG_ERR);
362 //var_dump(debug_print_backtrace());
363 }
364 $this->lastquery = $query;
365 $this->_results = $ret;
366 }
367
368 return $ret;
369 }
370
371 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
378 public function fetch_object($resultset)
379 {
380 // phpcs:enable
381 // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
382 if (!is_object($resultset)) {
383 $resultset = $this->_results;
384 }
385 return $resultset->fetch_object();
386 }
387
388
389 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
396 public function fetch_array($resultset)
397 {
398 // phpcs:enable
399 // If resultset not provided, we take the last used by connexion
400 if (!is_object($resultset)) {
401 $resultset = $this->_results;
402 }
403 return $resultset->fetch_array();
404 }
405
406 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
413 public function fetch_row($resultset)
414 {
415 // phpcs:enable
416 // If resultset not provided, we take the last used by connexion
417 if (!is_bool($resultset)) {
418 if (!is_object($resultset)) {
419 $resultset = $this->_results;
420 }
421 return $resultset->fetch_row();
422 } else {
423 // si le curseur est un booleen on retourne la valeur 0
424 return 0;
425 }
426 }
427
428 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
436 public function num_rows($resultset)
437 {
438 // phpcs:enable
439 // If resultset not provided, we take the last used by connexion
440 if (!is_object($resultset)) {
441 $resultset = $this->_results;
442 }
443 return isset($resultset->num_rows) ? $resultset->num_rows : 0;
444 }
445
446 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
454 public function affected_rows($resultset)
455 {
456 // phpcs:enable
457 // If resultset not provided, we take the last used by connexion
458 if (!is_object($resultset)) {
459 $resultset = $this->_results;
460 }
461 // mysql necessite un link de base pour cette fonction contrairement
462 // a pqsql qui prend un resultset
463 return $this->db->affected_rows;
464 }
465
466
473 public function free($resultset = null)
474 {
475 // If resultset not provided, we take the last used by connexion
476 if (!is_object($resultset)) {
477 $resultset = $this->_results;
478 }
479 // Si resultset en est un, on libere la memoire
480 if (is_object($resultset)) {
481 $resultset->free_result();
482 }
483 }
484
491 public function escape($stringtoencode)
492 {
493 return $this->db->real_escape_string((string) $stringtoencode);
494 }
495
502 public function escapeforlike($stringtoencode)
503 {
504 return str_replace(array('\\', '_', '%'), array('\\\\', '\_', '\%'), (string) $stringtoencode);
505 }
506
512 public function errno()
513 {
514 if (!$this->connected) {
515 // Si il y a eu echec de connexion, $this->db n'est pas valide.
516 return 'DB_ERROR_FAILED_TO_CONNECT';
517 } else {
518 // Constants to convert a MySql error code to a generic Dolibarr error code
519 $errorcode_map = array(
520 1004 => 'DB_ERROR_CANNOT_CREATE',
521 1005 => 'DB_ERROR_CANNOT_CREATE',
522 1006 => 'DB_ERROR_CANNOT_CREATE',
523 1007 => 'DB_ERROR_ALREADY_EXISTS',
524 1008 => 'DB_ERROR_CANNOT_DROP',
525 1022 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
526 1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
527 1044 => 'DB_ERROR_ACCESSDENIED',
528 1046 => 'DB_ERROR_NODBSELECTED',
529 1048 => 'DB_ERROR_CONSTRAINT',
530 1050 => 'DB_ERROR_TABLE_ALREADY_EXISTS',
531 1051 => 'DB_ERROR_NOSUCHTABLE',
532 1054 => 'DB_ERROR_NOSUCHFIELD',
533 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
534 1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
535 1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
536 1064 => 'DB_ERROR_SYNTAX',
537 1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
538 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
539 1091 => 'DB_ERROR_NOSUCHFIELD',
540 1100 => 'DB_ERROR_NOT_LOCKED',
541 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
542 1146 => 'DB_ERROR_NOSUCHTABLE',
543 1215 => 'DB_ERROR_CANNOT_ADD_FOREIGN_KEY_CONSTRAINT',
544 1216 => 'DB_ERROR_NO_PARENT',
545 1217 => 'DB_ERROR_CHILD_EXISTS',
546 1396 => 'DB_ERROR_USER_ALREADY_EXISTS', // When creating a user that already existing
547 1451 => 'DB_ERROR_CHILD_EXISTS',
548 1826 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS'
549 );
550
551 if (isset($errorcode_map[$this->db->errno])) {
552 return $errorcode_map[$this->db->errno];
553 }
554 $errno = $this->db->errno;
555 return ($errno ? 'DB_ERROR_'.$errno : '0');
556 }
557 }
558
564 public function error()
565 {
566 if (!$this->connected) {
567 // Si il y a eu echec de connexion, $this->db n'est pas valide pour mysqli_error.
568 return 'Not connected. Check setup parameters in conf/conf.php file and your mysql client and server versions';
569 } else {
570 return $this->db->error;
571 }
572 }
573
574 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
582 public function last_insert_id($tab, $fieldid = 'rowid')
583 {
584 // phpcs:enable
585 return $this->db->insert_id;
586 }
587
596 public function encrypt($fieldorvalue, $withQuotes = 1)
597 {
598 global $conf;
599
600 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
601 $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
602
603 //Encryption key
604 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
605
606 $escapedstringwithquotes = ($withQuotes ? "'" : "").$this->escape($fieldorvalue).($withQuotes ? "'" : "");
607
608 if ($cryptType && !empty($cryptKey)) {
609 if ($cryptType == 2) {
610 $escapedstringwithquotes = "AES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
611 } elseif ($cryptType == 1) {
612 $escapedstringwithquotes = "DES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
613 }
614 }
615
616 return $escapedstringwithquotes;
617 }
618
625 public function decrypt($value)
626 {
627 global $conf;
628
629 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
630 $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
631
632 //Encryption key
633 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
634
635 $return = $value;
636
637 if ($cryptType && !empty($cryptKey)) {
638 if ($cryptType == 2) {
639 $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
640 } elseif ($cryptType == 1) {
641 $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
642 }
643 }
644
645 return $return;
646 }
647
648
649 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
655 public function DDLGetConnectId()
656 {
657 // phpcs:enable
658 $resql = $this->query('SELECT CONNECTION_ID()');
659 if ($resql) {
660 $row = $this->fetch_row($resql);
661 return $row[0];
662 } else {
663 return '?';
664 }
665 }
666
667 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
679 public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
680 {
681 // phpcs:enable
682 if (empty($charset)) {
683 $charset = $this->forcecharset;
684 }
685 if (empty($collation)) {
686 $collation = $this->forcecollate;
687 }
688
689 // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
690 $sql = "CREATE DATABASE `".$this->escape($database)."`";
691 $sql .= " DEFAULT CHARACTER SET `".$this->escape($charset)."` DEFAULT COLLATE `".$this->escape($collation)."`";
692
693 dol_syslog($sql, LOG_DEBUG);
694 $ret = $this->query($sql);
695 if (!$ret) {
696 // We try again for compatibility with Mysql < 4.1.1
697 $sql = "CREATE DATABASE `".$this->escape($database)."`";
698 dol_syslog($sql, LOG_DEBUG);
699 $ret = $this->query($sql);
700 }
701 return $ret;
702 }
703
704 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
712 public function DDLListTables($database, $table = '')
713 {
714 // phpcs:enable
715 $listtables = array();
716
717 $like = '';
718 if ($table) {
719 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
720
721 $like = "LIKE '".$this->escape($tmptable)."'";
722 }
723 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
724
725 $sql = "SHOW TABLES FROM `".$tmpdatabase."` ".$like.";";
726 //print $sql;
727 $result = $this->query($sql);
728 if ($result) {
729 while ($row = $this->fetch_row($result)) {
730 $listtables[] = $row[0];
731 }
732 }
733 return $listtables;
734 }
735
736 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
744 public function DDLListTablesFull($database, $table = '')
745 {
746 // phpcs:enable
747 $listtables = array();
748
749 $like = '';
750 if ($table) {
751 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
752
753 $like = "LIKE '".$this->escape($tmptable)."'";
754 }
755 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
756
757 $sql = "SHOW FULL TABLES FROM `".$tmpdatabase."` ".$like.";";
758
759 $result = $this->query($sql);
760 if ($result) {
761 while ($row = $this->fetch_row($result)) {
762 $listtables[] = $row;
763 }
764 }
765 return $listtables;
766 }
767
768 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
775 public function DDLInfoTable($table)
776 {
777 // phpcs:enable
778 $infotables = array();
779
780 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
781
782 $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
783
784 dol_syslog($sql, LOG_DEBUG);
785 $result = $this->query($sql);
786 if ($result) {
787 while ($row = $this->fetch_row($result)) {
788 $infotables[] = $row;
789 }
790 }
791 return $infotables;
792 }
793
794 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
807 public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
808 {
809 // phpcs:enable
810 // FIXME: $fulltext_keys parameter is unused
811
812 $pk = '';
813 $sqluq = $sqlk = array();
814
815 // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
816 // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
817 $sql = "CREATE TABLE ".$table."(";
818 $i = 0;
819 $sqlfields = array();
820 foreach ($fields as $field_name => $field_desc) {
821 $sqlfields[$i] = $field_name." ";
822 $sqlfields[$i] .= $field_desc['type'];
823 if (preg_match("/^[^\s]/i", $field_desc['value'])) {
824 $sqlfields[$i] .= "(".$field_desc['value'].")";
825 }
826 if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
827 $sqlfields[$i] .= " ".$field_desc['attribute'];
828 }
829 if (preg_match("/^[^\s]/i", $field_desc['default'])) {
830 if ((preg_match("/null/i", $field_desc['default'])) || (preg_match("/CURRENT_TIMESTAMP/i", $field_desc['default']))) {
831 $sqlfields[$i] .= " default ".$field_desc['default'];
832 } else {
833 $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
834 }
835 }
836 if (preg_match("/^[^\s]/i", $field_desc['null'])) {
837 $sqlfields[$i] .= " ".$field_desc['null'];
838 }
839 if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
840 $sqlfields[$i] .= " ".$field_desc['extra'];
841 }
842 $i++;
843 }
844 if ($primary_key != "") {
845 $pk = "primary key(".$primary_key.")";
846 }
847
848 if (is_array($unique_keys)) {
849 $i = 0;
850 foreach ($unique_keys as $key => $value) {
851 $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
852 $i++;
853 }
854 }
855 if (is_array($keys)) {
856 $i = 0;
857 foreach ($keys as $key => $value) {
858 $sqlk[$i] = "KEY ".$key." (".$value.")";
859 $i++;
860 }
861 }
862 $sql .= implode(',', $sqlfields);
863 if ($primary_key != "") {
864 $sql .= ",".$pk;
865 }
866 if ($unique_keys != "") {
867 $sql .= ",".implode(',', $sqluq);
868 }
869 if (is_array($keys)) {
870 $sql .= ",".implode(',', $sqlk);
871 }
872 $sql .= ") engine=".$type;
873
874 if (!$this->query($sql)) {
875 return -1;
876 } else {
877 return 1;
878 }
879 }
880
881 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
888 public function DDLDropTable($table)
889 {
890 // phpcs:enable
891 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
892
893 $sql = "DROP TABLE ".$tmptable;
894
895 if (!$this->query($sql)) {
896 return -1;
897 } else {
898 return 1;
899 }
900 }
901
902 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
910 public function DDLDescTable($table, $field = "")
911 {
912 // phpcs:enable
913 $sql = "DESC ".$table." ".$field;
914
915 dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
916 $this->_results = $this->query($sql);
917 return $this->_results;
918 }
919
920 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
930 public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
931 {
932 // phpcs:enable
933 // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
934 // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
935 $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
936 $sql .= $field_desc['type'];
937 if (preg_match("/^[^\s]/i", $field_desc['value'])) {
938 if (!in_array($field_desc['type'], array('date', 'datetime')) && $field_desc['value']) {
939 $sql .= "(".$field_desc['value'].")";
940 }
941 }
942 if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) {
943 $sql .= " ".$field_desc['attribute'];
944 }
945 if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
946 $sql .= " ".$field_desc['null'];
947 }
948 if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
949 if (preg_match("/null/i", $field_desc['default'])) {
950 $sql .= " default ".$field_desc['default'];
951 } else {
952 $sql .= " default '".$this->escape($field_desc['default'])."'";
953 }
954 }
955 if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
956 $sql .= " ".$field_desc['extra'];
957 }
958 $sql .= " ".$field_position;
959
960 dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
961 if ($this->query($sql)) {
962 return 1;
963 }
964 return -1;
965 }
966
967 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
976 public function DDLUpdateField($table, $field_name, $field_desc)
977 {
978 // phpcs:enable
979 $sql = "ALTER TABLE ".$table;
980 $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
981 if (in_array($field_desc['type'], array('double', 'tinyint', 'int', 'varchar')) && $field_desc['value']) {
982 $sql .= "(".$field_desc['value'].")";
983 }
984 if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') {
985 // 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
986 if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') {
987 $sqlbis = "UPDATE ".$table." SET ".$field_name." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$field_name." IS NULL";
988 $this->query($sqlbis);
989 } elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
990 $sqlbis = "UPDATE ".$table." SET ".$field_name." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$field_name." IS NULL";
991 $this->query($sqlbis);
992 }
993
994 $sql .= " NOT NULL";
995 }
996
997 if (isset($field_desc['default']) && $field_desc['default'] != '') {
998 if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
999 $sql .= " DEFAULT ".$this->escape($field_desc['default']);
1000 } elseif ($field_desc['type'] != 'text') {
1001 $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; // Default not supported on text fields
1002 }
1003 }
1004
1005 dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1006 if (!$this->query($sql)) {
1007 return -1;
1008 } else {
1009 return 1;
1010 }
1011 }
1012
1013 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1021 public function DDLDropField($table, $field_name)
1022 {
1023 // phpcs:enable
1024 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1025
1026 $sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`";
1027 if ($this->query($sql)) {
1028 return 1;
1029 }
1030 $this->error = $this->lasterror();
1031 return -1;
1032 }
1033
1034
1035 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1045 public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1046 {
1047 // phpcs:enable
1048 $sql = "CREATE USER '".$this->escape($dolibarr_main_db_user)."' IDENTIFIED BY '".$this->escape($dolibarr_main_db_pass)."'";
1049 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1050 $resql = $this->query($sql);
1051 if (!$resql) {
1052 if ($this->lasterrno != 'DB_ERROR_USER_ALREADY_EXISTS') {
1053 return -1;
1054 } else {
1055 // If user already exists, we continue to set permissions
1056 dol_syslog(get_class($this)."::DDLCreateUser sql=".$sql, LOG_WARNING);
1057 }
1058 }
1059
1060 // Redo with localhost forced (sometimes user is created on %)
1061 $sql = "CREATE USER '".$this->escape($dolibarr_main_db_user)."'@'localhost' IDENTIFIED BY '".$this->escape($dolibarr_main_db_pass)."'";
1062 $resql = $this->query($sql);
1063
1064 $sql = "GRANT ALL PRIVILEGES ON ".$this->escape($dolibarr_main_db_name).".* TO '".$this->escape($dolibarr_main_db_user)."'@'".$this->escape($dolibarr_main_db_host)."'";
1065 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1066 $resql = $this->query($sql);
1067 if (!$resql) {
1068 $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)."'";
1069 return -1;
1070 }
1071
1072 $sql = "FLUSH Privileges";
1073
1074 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1075 $resql = $this->query($sql);
1076 if (!$resql) {
1077 return -1;
1078 }
1079
1080 return 1;
1081 }
1082
1090 public function getDefaultCharacterSetDatabase()
1091 {
1092 $resql = $this->query("SHOW VARIABLES LIKE 'character_set_database'");
1093 if (!$resql) {
1094 // version Mysql < 4.1.1
1095 return $this->forcecharset;
1096 }
1097 $liste = $this->fetch_array($resql);
1098 $tmpval = $liste['Value'];
1099
1100 return $tmpval;
1101 }
1102
1108 public function getListOfCharacterSet()
1109 {
1110 $resql = $this->query('SHOW CHARSET');
1111 $liste = array();
1112 if ($resql) {
1113 $i = 0;
1114 while ($obj = $this->fetch_object($resql)) {
1115 $liste[$i]['charset'] = $obj->Charset;
1116 $liste[$i]['description'] = $obj->Description;
1117 $i++;
1118 }
1119 $this->free($resql);
1120 } else {
1121 // version Mysql < 4.1.1
1122 return null;
1123 }
1124 return $liste;
1125 }
1126
1133 public function getDefaultCollationDatabase()
1134 {
1135 $resql = $this->query("SHOW VARIABLES LIKE 'collation_database'");
1136 if (!$resql) {
1137 // version Mysql < 4.1.1
1138 return $this->forcecollate;
1139 }
1140 $liste = $this->fetch_array($resql);
1141 $tmpval = $liste['Value'];
1142
1143 return $tmpval;
1144 }
1145
1151 public function getListOfCollation()
1152 {
1153 $resql = $this->query('SHOW COLLATION');
1154 $liste = array();
1155 if ($resql) {
1156 $i = 0;
1157 while ($obj = $this->fetch_object($resql)) {
1158 $liste[$i]['collation'] = $obj->Collation;
1159 $i++;
1160 }
1161 $this->free($resql);
1162 } else {
1163 // version Mysql < 4.1.1
1164 return null;
1165 }
1166 return $liste;
1167 }
1168
1174 public function getPathOfDump()
1175 {
1176 $fullpathofdump = '/pathtomysqldump/mysqldump';
1177
1178 $resql = $this->query("SHOW VARIABLES LIKE 'basedir'");
1179 if ($resql) {
1180 $liste = $this->fetch_array($resql);
1181 $basedir = $liste['Value'];
1182 $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1183 }
1184 return $fullpathofdump;
1185 }
1186
1192 public function getPathOfRestore()
1193 {
1194 $fullpathofimport = '/pathtomysql/mysql';
1195
1196 $resql = $this->query("SHOW VARIABLES LIKE 'basedir'");
1197 if ($resql) {
1198 $liste = $this->fetch_array($resql);
1199 $basedir = $liste['Value'];
1200 $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1201 }
1202 return $fullpathofimport;
1203 }
1204
1211 public function getServerParametersValues($filter = '')
1212 {
1213 $result = array();
1214
1215 $sql = 'SHOW VARIABLES';
1216 if ($filter) {
1217 $sql .= " LIKE '".$this->escape($filter)."'";
1218 }
1219 $resql = $this->query($sql);
1220 if ($resql) {
1221 while ($obj = $this->fetch_object($resql)) {
1222 $result[$obj->Variable_name] = $obj->Value;
1223 }
1224 }
1225
1226 return $result;
1227 }
1228
1235 public function getServerStatusValues($filter = '')
1236 {
1237 $result = array();
1238
1239 $sql = 'SHOW STATUS';
1240 if ($filter) {
1241 $sql .= " LIKE '".$this->escape($filter)."'";
1242 }
1243 $resql = $this->query($sql);
1244 if ($resql) {
1245 while ($obj = $this->fetch_object($resql)) {
1246 $result[$obj->Variable_name] = $obj->Value;
1247 }
1248 }
1249
1250 return $result;
1251 }
1252}
1253
1257class mysqliDoli extends mysqli
1258{
1270 public function __construct($host, $user, $pass, $name, $port = 0, $socket = "")
1271 {
1272 $flags = 0;
1273 parent::init();
1274 if (strpos($host, 'ssl://') === 0) {
1275 $host = substr($host, 6);
1276 parent::options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, false);
1277 parent::ssl_set(null, null, "", null, null);
1278 $flags = MYSQLI_CLIENT_SSL;
1279 }
1280 parent::real_connect($host, $user, $pass, $name, $port, $socket, $flags);
1281 }
1282}
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.
num_rows($resultset)
Return number of lines for result of a SELECT.
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.
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.
connect($host, $login, $passwd, $name, $port=0)
Connect to server.
errno()
Return generic error code of last operation.
getDriverInfo()
Return version of database client driver.
close()
Close database connexion.
Class to make SSL connection.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
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 a Dolibarr global constant int value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1926
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:121