mysqli.class.php 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  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@capnetworks.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 <http://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * \file htdocs/core/db/mysqli.class.php
  24. * \brief Class file to manage Dolibarr database access for a MySQL database
  25. */
  26. require_once DOL_DOCUMENT_ROOT .'/core/db/DoliDB.class.php';
  27. /**
  28. * Class to manage Dolibarr database access for a MySQL database using the MySQLi extension
  29. */
  30. class DoliDBMysqli extends DoliDB
  31. {
  32. /** @var mysqli Database object */
  33. public $db;
  34. //! Database type
  35. public $type='mysqli';
  36. //! Database label
  37. const LABEL='MySQL or MariaDB';
  38. //! Version min database
  39. const VERSIONMIN='5.0.3';
  40. /** @var mysqli_result Resultset of last query */
  41. private $_results;
  42. /**
  43. * Constructor.
  44. * This create an opened connexion to a database server and eventually to a database
  45. *
  46. * @param string $type Type of database (mysql, pgsql...)
  47. * @param string $host Address of database server
  48. * @param string $user Nom de l'utilisateur autorise
  49. * @param string $pass Mot de passe
  50. * @param string $name Nom de la database
  51. * @param int $port Port of database server
  52. */
  53. function __construct($type, $host, $user, $pass, $name='', $port=0)
  54. {
  55. global $conf,$langs;
  56. // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
  57. if (! empty($conf->db->character_set)) $this->forcecharset=$conf->db->character_set;
  58. if (! empty($conf->db->dolibarr_main_db_collation)) $this->forcecollate=$conf->db->dolibarr_main_db_collation;
  59. $this->database_user=$user;
  60. $this->database_host=$host;
  61. $this->database_port=$port;
  62. $this->transaction_opened=0;
  63. //print "Name DB: $host,$user,$pass,$name<br>";
  64. if (! class_exists('mysqli'))
  65. {
  66. $this->connected = false;
  67. $this->ok = false;
  68. $this->error="Mysqli PHP functions for using Mysqli driver are not available in this version of PHP. Try to use another driver.";
  69. 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);
  70. }
  71. if (! $host)
  72. {
  73. $this->connected = false;
  74. $this->ok = false;
  75. $this->error=$langs->trans("ErrorWrongHostParameter");
  76. dol_syslog(get_class($this)."::DoliDBMysqli : Connect error, wrong host parameters",LOG_ERR);
  77. }
  78. // Try server connection
  79. // We do not try to connect to database, only to server. Connect to database is done later in constrcutor
  80. $this->db = $this->connect($host, $user, $pass, '', $port);
  81. if ($this->db->connect_errno) {
  82. $this->connected = false;
  83. $this->ok = false;
  84. $this->error = $this->db->connect_error;
  85. dol_syslog(get_class($this) . "::DoliDBMysqli Connect error: " . $this->error, LOG_ERR);
  86. } else {
  87. $this->connected = true;
  88. $this->ok = true;
  89. }
  90. // If server connection is ok, we try to connect to the database
  91. if ($this->connected && $name)
  92. {
  93. if ($this->select_db($name))
  94. {
  95. $this->database_selected = true;
  96. $this->database_name = $name;
  97. $this->ok = true;
  98. // If client connected with different charset than Dolibarr HTML output
  99. $clientmustbe='';
  100. if (preg_match('/UTF-8/i',$conf->file->character_set_client)) $clientmustbe='utf8';
  101. if (preg_match('/ISO-8859-1/i',$conf->file->character_set_client)) $clientmustbe='latin1';
  102. if ($this->db->character_set_name() != $clientmustbe) {
  103. $this->db->set_charset($clientmustbe);
  104. }
  105. }
  106. else
  107. {
  108. $this->database_selected = false;
  109. $this->database_name = '';
  110. $this->ok = false;
  111. $this->error=$this->error();
  112. dol_syslog(get_class($this)."::DoliDBMysqli : Select_db error ".$this->error,LOG_ERR);
  113. }
  114. }
  115. else
  116. {
  117. // Pas de selection de base demandee, ok ou ko
  118. $this->database_selected = false;
  119. if ($this->connected)
  120. {
  121. // If client connected with different charset than Dolibarr HTML output
  122. $clientmustbe='';
  123. if (preg_match('/UTF-8/i',$conf->file->character_set_client)) $clientmustbe='utf8';
  124. if (preg_match('/ISO-8859-1/i',$conf->file->character_set_client)) $clientmustbe='latin1';
  125. if ($this->db->character_set_name() != $clientmustbe) {
  126. $this->db->set_charset($clientmustbe);
  127. }
  128. }
  129. }
  130. }
  131. /**
  132. * Convert a SQL request in Mysql syntax to native syntax
  133. *
  134. * @param string $line SQL request line to convert
  135. * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
  136. * @return string SQL request line converted
  137. */
  138. static function convertSQLFromMysql($line,$type='ddl')
  139. {
  140. return $line;
  141. }
  142. /**
  143. * Select a database
  144. *
  145. * @param string $database Name of database
  146. * @return boolean true if OK, false if KO
  147. */
  148. function select_db($database)
  149. {
  150. dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
  151. return $this->db->select_db($database);
  152. }
  153. /**
  154. * Connect to server
  155. *
  156. * @param string $host database server host
  157. * @param string $login login
  158. * @param string $passwd password
  159. * @param string $name name of database (not used for mysql, used for pgsql)
  160. * @param integer $port Port of database server
  161. * @return mysqli Database access object
  162. * @see close
  163. */
  164. function connect($host, $login, $passwd, $name, $port = 0)
  165. {
  166. dol_syslog(get_class($this) . "::connect host=$host, port=$port, login=$login, passwd=--hidden--, name=$name", LOG_DEBUG);
  167. return new mysqli($host, $login, $passwd, $name, $port);
  168. }
  169. /**
  170. * Return version of database server
  171. *
  172. * @return string Version string
  173. */
  174. function getVersion()
  175. {
  176. return $this->db->server_info;
  177. }
  178. /**
  179. * Return version of database client driver
  180. *
  181. * @return string Version string
  182. */
  183. function getDriverInfo()
  184. {
  185. return $this->db->client_info;
  186. }
  187. /**
  188. * Close database connexion
  189. *
  190. * @return bool True if disconnect successfull, false otherwise
  191. * @see connect
  192. */
  193. function close()
  194. {
  195. if ($this->db)
  196. {
  197. if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR);
  198. $this->connected=false;
  199. return $this->db->close();
  200. }
  201. return false;
  202. }
  203. /**
  204. * Execute a SQL request and return the resultset
  205. *
  206. * @param string $query SQL query string
  207. * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
  208. * Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
  209. * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
  210. * @return bool|mysqli_result Resultset of answer
  211. */
  212. function query($query,$usesavepoint=0,$type='auto')
  213. {
  214. global $conf;
  215. $query = trim($query);
  216. if (! in_array($query,array('BEGIN','COMMIT','ROLLBACK'))) dol_syslog('sql='.$query, LOG_DEBUG);
  217. if (! $this->database_name)
  218. {
  219. // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
  220. $ret = $this->db->query($query);
  221. }
  222. else
  223. {
  224. $ret = $this->db->query($query);
  225. }
  226. if (! preg_match("/^COMMIT/i",$query) && ! preg_match("/^ROLLBACK/i",$query))
  227. {
  228. // Si requete utilisateur, on la sauvegarde ainsi que son resultset
  229. if (! $ret)
  230. {
  231. $this->lastqueryerror = $query;
  232. $this->lasterror = $this->error();
  233. $this->lasterrno = $this->errno();
  234. if ($conf->global->SYSLOG_LEVEL < LOG_DEBUG) dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
  235. dol_syslog(get_class($this)."::query SQL Error message: ".$this->lasterrno." ".$this->lasterror, LOG_ERR);
  236. }
  237. $this->lastquery=$query;
  238. $this->_results = $ret;
  239. }
  240. return $ret;
  241. }
  242. /**
  243. * Renvoie la ligne courante (comme un objet) pour le curseur resultset
  244. *
  245. * @param mysqli_result $resultset Curseur de la requete voulue
  246. * @return object|null Object result line or null if KO or end of cursor
  247. */
  248. function fetch_object($resultset)
  249. {
  250. // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
  251. if (! is_object($resultset)) { $resultset=$this->_results; }
  252. return $resultset->fetch_object();
  253. }
  254. /**
  255. * Return datas as an array
  256. *
  257. * @param mysqli_result $resultset Resultset of request
  258. * @return array|null Array or null if KO or end of cursor
  259. */
  260. function fetch_array($resultset)
  261. {
  262. // If resultset not provided, we take the last used by connexion
  263. if (! is_object($resultset)) { $resultset=$this->_results; }
  264. return $resultset->fetch_array();
  265. }
  266. /**
  267. * Return datas as an array
  268. *
  269. * @param mysqli_result $resultset Resultset of request
  270. * @return array|null|0 Array or null if KO or end of cursor or 0 if resultset is bool
  271. */
  272. function fetch_row($resultset)
  273. {
  274. // If resultset not provided, we take the last used by connexion
  275. if (! is_bool($resultset))
  276. {
  277. if (! is_object($resultset)) { $resultset=$this->_results; }
  278. return $resultset->fetch_row();
  279. }
  280. else
  281. {
  282. // si le curseur est un booleen on retourne la valeur 0
  283. return 0;
  284. }
  285. }
  286. /**
  287. * Return number of lines for result of a SELECT
  288. *
  289. * @param mysqli_result $resultset Resulset of requests
  290. * @return int Nb of lines
  291. * @see affected_rows
  292. */
  293. function num_rows($resultset)
  294. {
  295. // If resultset not provided, we take the last used by connexion
  296. if (! is_object($resultset)) { $resultset=$this->_results; }
  297. return $resultset->num_rows;
  298. }
  299. /**
  300. * Renvoie le nombre de lignes dans le resultat d'une requete INSERT, DELETE ou UPDATE
  301. *
  302. * @param mysqli_result $resultset Curseur de la requete voulue
  303. * @return int Nombre de lignes
  304. * @see num_rows
  305. */
  306. function affected_rows($resultset)
  307. {
  308. // If resultset not provided, we take the last used by connexion
  309. if (! is_object($resultset)) { $resultset=$this->_results; }
  310. // mysql necessite un link de base pour cette fonction contrairement
  311. // a pqsql qui prend un resultset
  312. return $this->db->affected_rows;
  313. }
  314. /**
  315. * Libere le dernier resultset utilise sur cette connexion
  316. *
  317. * @param mysqli_result $resultset Curseur de la requete voulue
  318. * @return void
  319. */
  320. function free($resultset=null)
  321. {
  322. // If resultset not provided, we take the last used by connexion
  323. if (! is_object($resultset)) { $resultset=$this->_results; }
  324. // Si resultset en est un, on libere la memoire
  325. if (is_object($resultset)) $resultset->free_result();
  326. }
  327. /**
  328. * Escape a string to insert data
  329. *
  330. * @param string $stringtoencode String to escape
  331. * @return string String escaped
  332. */
  333. function escape($stringtoencode)
  334. {
  335. return $this->db->real_escape_string($stringtoencode);
  336. }
  337. /**
  338. * Return generic error code of last operation.
  339. *
  340. * @return string Error code (Exemples: DB_ERROR_TABLE_ALREADY_EXISTS, DB_ERROR_RECORD_ALREADY_EXISTS...)
  341. */
  342. function errno()
  343. {
  344. if (! $this->connected) {
  345. // Si il y a eu echec de connexion, $this->db n'est pas valide.
  346. return 'DB_ERROR_FAILED_TO_CONNECT';
  347. } else {
  348. // Constants to convert a MySql error code to a generic Dolibarr error code
  349. $errorcode_map = array(
  350. 1004 => 'DB_ERROR_CANNOT_CREATE',
  351. 1005 => 'DB_ERROR_CANNOT_CREATE',
  352. 1006 => 'DB_ERROR_CANNOT_CREATE',
  353. 1007 => 'DB_ERROR_ALREADY_EXISTS',
  354. 1008 => 'DB_ERROR_CANNOT_DROP',
  355. 1022 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
  356. 1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
  357. 1044 => 'DB_ERROR_ACCESSDENIED',
  358. 1046 => 'DB_ERROR_NODBSELECTED',
  359. 1048 => 'DB_ERROR_CONSTRAINT',
  360. 1050 => 'DB_ERROR_TABLE_ALREADY_EXISTS',
  361. 1051 => 'DB_ERROR_NOSUCHTABLE',
  362. 1054 => 'DB_ERROR_NOSUCHFIELD',
  363. 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
  364. 1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
  365. 1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
  366. 1064 => 'DB_ERROR_SYNTAX',
  367. 1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
  368. 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
  369. 1091 => 'DB_ERROR_NOSUCHFIELD',
  370. 1100 => 'DB_ERROR_NOT_LOCKED',
  371. 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
  372. 1146 => 'DB_ERROR_NOSUCHTABLE',
  373. 1215 => 'DB_ERROR_CANNOT_ADD_FOREIGN_KEY_CONSTRAINT',
  374. 1216 => 'DB_ERROR_NO_PARENT',
  375. 1217 => 'DB_ERROR_CHILD_EXISTS',
  376. 1396 => 'DB_ERROR_USER_ALREADY_EXISTS', // When creating user already existing
  377. 1451 => 'DB_ERROR_CHILD_EXISTS'
  378. );
  379. if (isset($errorcode_map[$this->db->errno])) {
  380. return $errorcode_map[$this->db->errno];
  381. }
  382. $errno=$this->db->errno;
  383. return ($errno?'DB_ERROR_'.$errno:'0');
  384. }
  385. }
  386. /**
  387. * Return description of last error
  388. *
  389. * @return string Error text
  390. */
  391. function error()
  392. {
  393. if (! $this->connected) {
  394. // Si il y a eu echec de connexion, $this->db n'est pas valide pour mysqli_error.
  395. return 'Not connected. Check setup parameters in conf/conf.php file and your mysql client and server versions';
  396. }
  397. else {
  398. return $this->db->error;
  399. }
  400. }
  401. /**
  402. * Get last ID after an insert INSERT
  403. *
  404. * @param string $tab Table name concerned by insert. Ne sert pas sous MySql mais requis pour compatibilite avec Postgresql
  405. * @param string $fieldid Field name
  406. * @return int|string Id of row
  407. */
  408. function last_insert_id($tab,$fieldid='rowid')
  409. {
  410. return $this->db->insert_id;
  411. }
  412. /**
  413. * Encrypt sensitive data in database
  414. * Warning: This function includes the escape, so it must use direct value
  415. *
  416. * @param string $fieldorvalue Field name or value to encrypt
  417. * @param int $withQuotes Return string with quotes
  418. * @return string XXX(field) or XXX('value') or field or 'value'
  419. *
  420. */
  421. function encrypt($fieldorvalue, $withQuotes=0)
  422. {
  423. global $conf;
  424. // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
  425. $cryptType = (!empty($conf->db->dolibarr_main_db_encryption)?$conf->db->dolibarr_main_db_encryption:0);
  426. //Encryption key
  427. $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey)?$conf->db->dolibarr_main_db_cryptkey:'');
  428. $return = ($withQuotes?"'":"").$this->escape($fieldorvalue).($withQuotes?"'":"");
  429. if ($cryptType && !empty($cryptKey))
  430. {
  431. if ($cryptType == 2)
  432. {
  433. $return = 'AES_ENCRYPT('.$return.',\''.$cryptKey.'\')';
  434. }
  435. else if ($cryptType == 1)
  436. {
  437. $return = 'DES_ENCRYPT('.$return.',\''.$cryptKey.'\')';
  438. }
  439. }
  440. return $return;
  441. }
  442. /**
  443. * Decrypt sensitive data in database
  444. *
  445. * @param string $value Value to decrypt
  446. * @return string Decrypted value if used
  447. */
  448. function decrypt($value)
  449. {
  450. global $conf;
  451. // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
  452. $cryptType = (!empty($conf->db->dolibarr_main_db_encryption)?$conf->db->dolibarr_main_db_encryption:0);
  453. //Encryption key
  454. $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey)?$conf->db->dolibarr_main_db_cryptkey:'');
  455. $return = $value;
  456. if ($cryptType && !empty($cryptKey))
  457. {
  458. if ($cryptType == 2)
  459. {
  460. $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
  461. }
  462. else if ($cryptType == 1)
  463. {
  464. $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
  465. }
  466. }
  467. return $return;
  468. }
  469. /**
  470. * Return connexion ID
  471. *
  472. * @return string Id connexion
  473. */
  474. function DDLGetConnectId()
  475. {
  476. $resql=$this->query('SELECT CONNECTION_ID()');
  477. if ($resql)
  478. {
  479. $row=$this->fetch_row($resql);
  480. return $row[0];
  481. }
  482. else return '?';
  483. }
  484. /**
  485. * Create a new database
  486. * Do not use function xxx_create_db (xxx=mysql, ...) as they are deprecated
  487. * We force to create database with charset this->forcecharset and collate this->forcecollate
  488. *
  489. * @param string $database Database name to create
  490. * @param string $charset Charset used to store data
  491. * @param string $collation Charset used to sort data
  492. * @param string $owner Username of database owner
  493. * @return bool|mysqli_result resource defined if OK, null if KO
  494. */
  495. function DDLCreateDb($database,$charset='',$collation='',$owner='')
  496. {
  497. if (empty($charset)) $charset=$this->forcecharset;
  498. if (empty($collation)) $collation=$this->forcecollate;
  499. // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
  500. $sql = "CREATE DATABASE `".$this->escape($database)."`";
  501. $sql.= " DEFAULT CHARACTER SET `".$this->escape($charset)."` DEFAULT COLLATE `".$this->escape($collation)."`";
  502. dol_syslog($sql,LOG_DEBUG);
  503. $ret=$this->query($sql);
  504. if (! $ret)
  505. {
  506. // We try again for compatibility with Mysql < 4.1.1
  507. $sql = "CREATE DATABASE `".$this->escape($database)."`";
  508. dol_syslog($sql,LOG_DEBUG);
  509. $ret=$this->query($sql);
  510. }
  511. return $ret;
  512. }
  513. /**
  514. * List tables into a database
  515. *
  516. * @param string $database Name of database
  517. * @param string $table Nmae of table filter ('xxx%')
  518. * @return array List of tables in an array
  519. */
  520. function DDLListTables($database, $table='')
  521. {
  522. $listtables=array();
  523. $like = '';
  524. if ($table) $like = "LIKE '".$table."'";
  525. $sql="SHOW TABLES FROM ".$database." ".$like.";";
  526. //print $sql;
  527. $result = $this->query($sql);
  528. while($row = $this->fetch_row($result))
  529. {
  530. $listtables[] = $row[0];
  531. }
  532. return $listtables;
  533. }
  534. /**
  535. * List information of columns into a table.
  536. *
  537. * @param string $table Name of table
  538. * @return array Tableau des informations des champs de la table
  539. */
  540. function DDLInfoTable($table)
  541. {
  542. $infotables=array();
  543. $sql="SHOW FULL COLUMNS FROM ".$table.";";
  544. dol_syslog($sql,LOG_DEBUG);
  545. $result = $this->query($sql);
  546. while($row = $this->fetch_row($result))
  547. {
  548. $infotables[] = $row;
  549. }
  550. return $infotables;
  551. }
  552. /**
  553. * Create a table into database
  554. *
  555. * @param string $table Nom de la table
  556. * @param array $fields Tableau associatif [nom champ][tableau des descriptions]
  557. * @param string $primary_key Nom du champ qui sera la clef primaire
  558. * @param string $type Type de la table
  559. * @param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
  560. * @param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
  561. * @param array $keys Tableau des champs cles noms => valeur
  562. * @return int <0 if KO, >=0 if OK
  563. */
  564. function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys=null,$fulltext_keys=null,$keys=null)
  565. {
  566. // FIXME: $fulltext_keys parameter is unused
  567. // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
  568. // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
  569. $sql = "CREATE TABLE ".$table."(";
  570. $i=0;
  571. foreach($fields as $field_name => $field_desc)
  572. {
  573. $sqlfields[$i] = $field_name." ";
  574. $sqlfields[$i] .= $field_desc['type'];
  575. if( preg_match("/^[^\s]/i",$field_desc['value'])) {
  576. $sqlfields[$i] .= "(".$field_desc['value'].")";
  577. }
  578. if( preg_match("/^[^\s]/i",$field_desc['attribute'])) {
  579. $sqlfields[$i] .= " ".$field_desc['attribute'];
  580. }
  581. if( preg_match("/^[^\s]/i",$field_desc['default']))
  582. {
  583. if ((preg_match("/null/i",$field_desc['default'])) || (preg_match("/CURRENT_TIMESTAMP/i",$field_desc['default']))) {
  584. $sqlfields[$i] .= " default ".$field_desc['default'];
  585. }
  586. else {
  587. $sqlfields[$i] .= " default '".$field_desc['default']."'";
  588. }
  589. }
  590. if( preg_match("/^[^\s]/i",$field_desc['null'])) {
  591. $sqlfields[$i] .= " ".$field_desc['null'];
  592. }
  593. if( preg_match("/^[^\s]/i",$field_desc['extra'])) {
  594. $sqlfields[$i] .= " ".$field_desc['extra'];
  595. }
  596. $i++;
  597. }
  598. if($primary_key != "")
  599. $pk = "primary key(".$primary_key.")";
  600. if(is_array($unique_keys)) {
  601. $i = 0;
  602. foreach($unique_keys as $key => $value)
  603. {
  604. $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$value."')";
  605. $i++;
  606. }
  607. }
  608. if(is_array($keys))
  609. {
  610. $i = 0;
  611. foreach($keys as $key => $value)
  612. {
  613. $sqlk[$i] = "KEY ".$key." (".$value.")";
  614. $i++;
  615. }
  616. }
  617. $sql .= implode(',',$sqlfields);
  618. if($primary_key != "")
  619. $sql .= ",".$pk;
  620. if($unique_keys != "")
  621. $sql .= ",".implode(',',$sqluq);
  622. if(is_array($keys))
  623. $sql .= ",".implode(',',$sqlk);
  624. $sql .=") engine=".$type;
  625. dol_syslog($sql,LOG_DEBUG);
  626. if(! $this -> query($sql))
  627. return -1;
  628. else
  629. return 1;
  630. }
  631. /**
  632. * Return a pointer of line with description of a table or field
  633. *
  634. * @param string $table Name of table
  635. * @param string $field Optionnel : Name of field if we want description of field
  636. * @return bool|mysqli_result Resultset x (x->Field, x->Type, ...)
  637. */
  638. function DDLDescTable($table,$field="")
  639. {
  640. $sql="DESC ".$table." ".$field;
  641. dol_syslog(get_class($this)."::DDLDescTable ".$sql,LOG_DEBUG);
  642. $this->_results = $this->query($sql);
  643. return $this->_results;
  644. }
  645. /**
  646. * Create a new field into table
  647. *
  648. * @param string $table Name of table
  649. * @param string $field_name Name of field to add
  650. * @param string $field_desc Tableau associatif de description du champ a inserer[nom du parametre][valeur du parametre]
  651. * @param string $field_position Optionnel ex.: "after champtruc"
  652. * @return int <0 if KO, >0 if OK
  653. */
  654. function DDLAddField($table,$field_name,$field_desc,$field_position="")
  655. {
  656. // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
  657. // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
  658. $sql= "ALTER TABLE ".$table." ADD `".$field_name."` ";
  659. $sql.= $field_desc['type'];
  660. if(preg_match("/^[^\s]/i",$field_desc['value']))
  661. if (! in_array($field_desc['type'],array('date','datetime')))
  662. {
  663. $sql.= "(".$field_desc['value'].")";
  664. }
  665. if(preg_match("/^[^\s]/i",$field_desc['attribute']))
  666. $sql.= " ".$field_desc['attribute'];
  667. if(preg_match("/^[^\s]/i",$field_desc['null']))
  668. $sql.= " ".$field_desc['null'];
  669. if(preg_match("/^[^\s]/i",$field_desc['default']))
  670. {
  671. if(preg_match("/null/i",$field_desc['default']))
  672. $sql.= " default ".$field_desc['default'];
  673. else
  674. $sql.= " default '".$field_desc['default']."'";
  675. }
  676. if(preg_match("/^[^\s]/i",$field_desc['extra']))
  677. $sql.= " ".$field_desc['extra'];
  678. $sql.= " ".$field_position;
  679. dol_syslog(get_class($this)."::DDLAddField ".$sql,LOG_DEBUG);
  680. if($this->query($sql)) {
  681. return 1;
  682. }
  683. return -1;
  684. }
  685. /**
  686. * Update format of a field into a table
  687. *
  688. * @param string $table Name of table
  689. * @param string $field_name Name of field to modify
  690. * @param string $field_desc Array with description of field format
  691. * @return int <0 if KO, >0 if OK
  692. */
  693. function DDLUpdateField($table,$field_name,$field_desc)
  694. {
  695. $sql = "ALTER TABLE ".$table;
  696. $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
  697. if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
  698. $sql.="(".$field_desc['value'].")";
  699. }
  700. if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') $sql.=" NOT NULL";
  701. dol_syslog(get_class($this)."::DDLUpdateField ".$sql,LOG_DEBUG);
  702. if (! $this->query($sql))
  703. return -1;
  704. else
  705. return 1;
  706. }
  707. /**
  708. * Drop a field from table
  709. *
  710. * @param string $table Name of table
  711. * @param string $field_name Name of field to drop
  712. * @return int <0 if KO, >0 if OK
  713. */
  714. function DDLDropField($table,$field_name)
  715. {
  716. $sql= "ALTER TABLE ".$table." DROP COLUMN `".$field_name."`";
  717. dol_syslog(get_class($this)."::DDLDropField ".$sql,LOG_DEBUG);
  718. if ($this->query($sql)) {
  719. return 1;
  720. }
  721. $this->error=$this->lasterror();
  722. return -1;
  723. }
  724. /**
  725. * Create a user and privileges to connect to database (even if database does not exists yet)
  726. *
  727. * @param string $dolibarr_main_db_host Ip serveur
  728. * @param string $dolibarr_main_db_user Nom user a creer
  729. * @param string $dolibarr_main_db_pass Mot de passe user a creer
  730. * @param string $dolibarr_main_db_name Database name where user must be granted
  731. * @return int <0 if KO, >=0 if OK
  732. */
  733. function DDLCreateUser($dolibarr_main_db_host,$dolibarr_main_db_user,$dolibarr_main_db_pass,$dolibarr_main_db_name)
  734. {
  735. $sql = "CREATE USER '".$this->escape($dolibarr_main_db_user)."'";
  736. dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
  737. $resql=$this->query($sql);
  738. if (! $resql)
  739. {
  740. if ($this->lasterrno != 'DB_ERROR_USER_ALREADY_EXISTS')
  741. {
  742. return -1;
  743. }
  744. else
  745. {
  746. // If user already exists, we continue to set permissions
  747. dol_syslog(get_class($this)."::DDLCreateUser sql=".$sql, LOG_WARNING);
  748. }
  749. }
  750. $sql = "GRANT ALL PRIVILEGES ON ".$this->escape($dolibarr_main_db_name).".* TO '".$this->escape($dolibarr_main_db_user)."'@'".$this->escape($dolibarr_main_db_host)."' IDENTIFIED BY '".$this->escape($dolibarr_main_db_pass)."'";
  751. dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
  752. $resql=$this->query($sql);
  753. if (! $resql)
  754. {
  755. return -1;
  756. }
  757. $sql="FLUSH Privileges";
  758. dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
  759. $resql=$this->query($sql);
  760. if (! $resql)
  761. {
  762. return -1;
  763. }
  764. return 1;
  765. }
  766. /**
  767. * Return charset used to store data in database
  768. *
  769. * @return string Charset
  770. */
  771. function getDefaultCharacterSetDatabase()
  772. {
  773. $resql=$this->query('SHOW VARIABLES LIKE \'character_set_database\'');
  774. if (!$resql)
  775. {
  776. // version Mysql < 4.1.1
  777. return $this->forcecharset;
  778. }
  779. $liste=$this->fetch_array($resql);
  780. return $liste['Value'];
  781. }
  782. /**
  783. * Return list of available charset that can be used to store data in database
  784. *
  785. * @return array|null List of Charset
  786. */
  787. function getListOfCharacterSet()
  788. {
  789. $resql=$this->query('SHOW CHARSET');
  790. $liste = array();
  791. if ($resql)
  792. {
  793. $i = 0;
  794. while ($obj = $this->fetch_object($resql) )
  795. {
  796. $liste[$i]['charset'] = $obj->Charset;
  797. $liste[$i]['description'] = $obj->Description;
  798. $i++;
  799. }
  800. $this->free($resql);
  801. } else {
  802. // version Mysql < 4.1.1
  803. return null;
  804. }
  805. return $liste;
  806. }
  807. /**
  808. * Return collation used in database
  809. *
  810. * @return string Collation value
  811. */
  812. function getDefaultCollationDatabase()
  813. {
  814. $resql=$this->query('SHOW VARIABLES LIKE \'collation_database\'');
  815. if (!$resql)
  816. {
  817. // version Mysql < 4.1.1
  818. return $this->forcecollate;
  819. }
  820. $liste=$this->fetch_array($resql);
  821. return $liste['Value'];
  822. }
  823. /**
  824. * Return list of available collation that can be used for database
  825. *
  826. * @return array|null Liste of Collation
  827. */
  828. function getListOfCollation()
  829. {
  830. $resql=$this->query('SHOW COLLATION');
  831. $liste = array();
  832. if ($resql)
  833. {
  834. $i = 0;
  835. while ($obj = $this->fetch_object($resql) )
  836. {
  837. $liste[$i]['collation'] = $obj->Collation;
  838. $i++;
  839. }
  840. $this->free($resql);
  841. } else {
  842. // version Mysql < 4.1.1
  843. return null;
  844. }
  845. return $liste;
  846. }
  847. /**
  848. * Return full path of dump program
  849. *
  850. * @return string Full path of dump program
  851. */
  852. function getPathOfDump()
  853. {
  854. $fullpathofdump='/pathtomysqldump/mysqldump';
  855. $resql=$this->query('SHOW VARIABLES LIKE \'basedir\'');
  856. if ($resql)
  857. {
  858. $liste=$this->fetch_array($resql);
  859. $basedir=$liste['Value'];
  860. $fullpathofdump=$basedir.(preg_match('/\/$/',$basedir)?'':'/').'bin/mysqldump';
  861. }
  862. return $fullpathofdump;
  863. }
  864. /**
  865. * Return full path of restore program
  866. *
  867. * @return string Full path of restore program
  868. */
  869. function getPathOfRestore()
  870. {
  871. $fullpathofimport='/pathtomysql/mysql';
  872. $resql=$this->query('SHOW VARIABLES LIKE \'basedir\'');
  873. if ($resql)
  874. {
  875. $liste=$this->fetch_array($resql);
  876. $basedir=$liste['Value'];
  877. $fullpathofimport=$basedir.(preg_match('/\/$/',$basedir)?'':'/').'bin/mysql';
  878. }
  879. return $fullpathofimport;
  880. }
  881. /**
  882. * Return value of server parameters
  883. *
  884. * @param string $filter Filter list on a particular value
  885. * @return array Array of key-values (key=>value)
  886. */
  887. function getServerParametersValues($filter='')
  888. {
  889. $result=array();
  890. $sql='SHOW VARIABLES';
  891. if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
  892. $resql=$this->query($sql);
  893. if ($resql)
  894. {
  895. while($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
  896. }
  897. return $result;
  898. }
  899. /**
  900. * Return value of server status (current indicators on memory, cache...)
  901. *
  902. * @param string $filter Filter list on a particular value
  903. * @return array Array of key-values (key=>value)
  904. */
  905. function getServerStatusValues($filter='')
  906. {
  907. $result=array();
  908. $sql='SHOW STATUS';
  909. if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
  910. $resql=$this->query($sql);
  911. if ($resql)
  912. {
  913. while($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
  914. }
  915. return $result;
  916. }
  917. }