dolibarr  x.y.z
sqlite3.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-2009 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 DoliDBSqlite3 extends DoliDB
34 {
36  public $type = 'sqlite3';
38  const LABEL = 'Sqlite3';
40  const VERSIONMIN = '3.0.0';
41 
45  private $_results;
46 
47  const WEEK_MONDAY_FIRST = 1;
48  const WEEK_YEAR = 2;
49  const WEEK_FIRST_WEEKDAY = 4;
50 
51 
63  public function __construct($type, $host, $user, $pass, $name = '', $port = 0)
64  {
65  global $conf;
66 
67  // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
68  if (!empty($conf->db->character_set)) {
69  $this->forcecharset = $conf->db->character_set;
70  }
71  if (!empty($conf->db->dolibarr_main_db_collation)) {
72  $this->forcecollate = $conf->db->dolibarr_main_db_collation;
73  }
74 
75  $this->database_user = $user;
76  $this->database_host = $host;
77  $this->database_port = $port;
78 
79  $this->transaction_opened = 0;
80 
81  //print "Name DB: $host,$user,$pass,$name<br>";
82 
83  /*if (! function_exists("sqlite_query"))
84  {
85  $this->connected = false;
86  $this->ok = false;
87  $this->error="Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.";
88  dol_syslog(get_class($this)."::DoliDBSqlite3 : Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.",LOG_ERR);
89  return $this->ok;
90  }*/
91 
92  /*if (! $host)
93  {
94  $this->connected = false;
95  $this->ok = false;
96  $this->error=$langs->trans("ErrorWrongHostParameter");
97  dol_syslog(get_class($this)."::DoliDBSqlite3 : Erreur Connect, wrong host parameters",LOG_ERR);
98  return $this->ok;
99  }*/
100 
101  // Essai connexion serveur
102  // We do not try to connect to database, only to server. Connect to database is done later in constrcutor
103  $this->db = $this->connect($host, $user, $pass, $name, $port);
104 
105  if ($this->db) {
106  $this->connected = true;
107  $this->ok = true;
108  $this->database_selected = true;
109  $this->database_name = $name;
110 
111  $this->addCustomFunction('IF');
112  $this->addCustomFunction('MONTH');
113  $this->addCustomFunction('CURTIME');
114  $this->addCustomFunction('CURDATE');
115  $this->addCustomFunction('WEEK', 1);
116  $this->addCustomFunction('WEEK', 2);
117  $this->addCustomFunction('WEEKDAY');
118  $this->addCustomFunction('date_format');
119  //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
120  } else {
121  // host, login ou password incorrect
122  $this->connected = false;
123  $this->ok = false;
124  $this->database_selected = false;
125  $this->database_name = '';
126  //$this->error=sqlite_connect_error();
127  dol_syslog(get_class($this)."::DoliDBSqlite3 : Error Connect ".$this->error, LOG_ERR);
128  }
129 
130  return $this->ok;
131  }
132 
133 
141  public static function convertSQLFromMysql($line, $type = 'ddl')
142  {
143  // Removed empty line if this is a comment line for SVN tagging
144  if (preg_match('/^--\s\$Id/i', $line)) {
145  return '';
146  }
147  // Return line if this is a comment
148  if (preg_match('/^#/i', $line) || preg_match('/^$/i', $line) || preg_match('/^--/i', $line)) {
149  return $line;
150  }
151  if ($line != "") {
152  if ($type == 'auto') {
153  if (preg_match('/ALTER TABLE/i', $line)) {
154  $type = 'dml';
155  } elseif (preg_match('/CREATE TABLE/i', $line)) {
156  $type = 'dml';
157  } elseif (preg_match('/DROP TABLE/i', $line)) {
158  $type = 'dml';
159  }
160  }
161 
162  if ($type == 'dml') {
163  $line = preg_replace('/\s/', ' ', $line); // Replace tabulation with space
164 
165  // we are inside create table statement so lets process datatypes
166  if (preg_match('/(ISAM|innodb)/i', $line)) { // end of create table sequence
167  $line = preg_replace('/\‍)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb);/i', ');', $line);
168  $line = preg_replace('/\‍)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb);/i', ');', $line);
169  $line = preg_replace('/,$/', '', $line);
170  }
171 
172  // Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
173  if (preg_match('/[\s\t\‍(]*(\w*)[\s\t]+int.*auto_increment/i', $line, $reg)) {
174  $newline = preg_replace('/([\s\t\‍(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i', '\\1 \\2 integer PRIMARY KEY AUTOINCREMENT', $line);
175  //$line = "-- ".$line." replaced by --\n".$newline;
176  $line = $newline;
177  }
178 
179  // tinyint type conversion
180  $line = str_replace('tinyint', 'smallint', $line);
181 
182  // nuke unsigned
183  $line = preg_replace('/(int\w+|smallint)\s+unsigned/i', '\\1', $line);
184 
185  // blob -> text
186  $line = preg_replace('/\w*blob/i', 'text', $line);
187 
188  // tinytext/mediumtext -> text
189  $line = preg_replace('/tinytext/i', 'text', $line);
190  $line = preg_replace('/mediumtext/i', 'text', $line);
191 
192  // change not null datetime field to null valid ones
193  // (to support remapping of "zero time" to null
194  $line = preg_replace('/datetime not null/i', 'datetime', $line);
195  $line = preg_replace('/datetime/i', 'timestamp', $line);
196 
197  // double -> numeric
198  $line = preg_replace('/^double/i', 'numeric', $line);
199  $line = preg_replace('/(\s*)double/i', '\\1numeric', $line);
200  // float -> numeric
201  $line = preg_replace('/^float/i', 'numeric', $line);
202  $line = preg_replace('/(\s*)float/i', '\\1numeric', $line);
203 
204  // unique index(field1,field2)
205  if (preg_match('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', $line)) {
206  $line = preg_replace('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', 'UNIQUE\‍(\\1\‍)', $line);
207  }
208 
209  // We remove end of requests "AFTER fieldxxx"
210  $line = preg_replace('/AFTER [a-z0-9_]+/i', '', $line);
211 
212  // We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
213  $line = preg_replace('/ALTER TABLE [a-z0-9_]+ DROP INDEX/i', 'DROP INDEX', $line);
214 
215  // Translate order to rename fields
216  if (preg_match('/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i', $line, $reg)) {
217  $line = "-- ".$line." replaced by --\n";
218  $line .= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3];
219  }
220 
221  // Translate order to modify field format
222  if (preg_match('/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i', $line, $reg)) {
223  $line = "-- ".$line." replaced by --\n";
224  $newreg3 = $reg[3];
225  $newreg3 = preg_replace('/ DEFAULT NULL/i', '', $newreg3);
226  $newreg3 = preg_replace('/ NOT NULL/i', '', $newreg3);
227  $newreg3 = preg_replace('/ NULL/i', '', $newreg3);
228  $newreg3 = preg_replace('/ DEFAULT 0/i', '', $newreg3);
229  $newreg3 = preg_replace('/ DEFAULT \'[0-9a-zA-Z_@]*\'/i', '', $newreg3);
230  $line .= "ALTER TABLE ".$reg[1]." ALTER COLUMN ".$reg[2]." TYPE ".$newreg3;
231  // TODO Add alter to set default value or null/not null if there is this in $reg[3]
232  }
233 
234  // alter table add primary key (field1, field2 ...) -> We create a unique index instead as dynamic creation of primary key is not supported
235  // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity);
236  if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\‍((.*)$/i', $line, $reg)) {
237  $line = "-- ".$line." replaced by --\n";
238  $line .= "CREATE UNIQUE INDEX ".$reg[2]." ON ".$reg[1]."(".$reg[3];
239  }
240 
241  // Translate order to drop foreign keys
242  // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx;
243  if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i', $line, $reg)) {
244  $line = "-- ".$line." replaced by --\n";
245  $line .= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
246  }
247 
248  // alter table add [unique] [index] (field1, field2 ...)
249  // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
250  if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\‍(([\w,\s]+)\‍)/i', $line, $reg)) {
251  $fieldlist = $reg[4];
252  $idxname = $reg[3];
253  $tablename = $reg[1];
254  $line = "-- ".$line." replaced by --\n";
255  $line .= "CREATE ".(preg_match('/UNIQUE/', $reg[2]) ? 'UNIQUE ' : '')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")";
256  }
257  if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\‍(([\w,\s]+)\‍)\s*REFERENCES\s+(\w+)\s*\‍(([\w,\s]+)\‍)/i', $line, $reg)) {
258  // Pour l'instant les contraintes ne sont pas créées
259  dol_syslog(get_class().'::query line emptied');
260  $line = 'SELECT 0;';
261  }
262 
263  //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) {
264  //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line);
265  //}
266  }
267 
268  // Delete using criteria on other table must not declare twice the deleted table
269  // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
270  if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', $line, $reg)) {
271  if ($reg[1] == $reg[2]) { // If same table, we remove second one
272  $line = preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', 'DELETE FROM \\1 USING \\3', $line);
273  }
274  }
275 
276  // Remove () in the tables in FROM if one table
277  $line = preg_replace('/FROM\s*\‍((([a-z_]+)\s+as\s+([a-z_]+)\s*)\‍)/i', 'FROM \\1', $line);
278  //print $line."\n";
279 
280  // Remove () in the tables in FROM if two table
281  $line = preg_replace('/FROM\s*\‍(([a-z_]+\s+as\s+[a-z_]+)\s*,\s*([a-z_]+\s+as\s+[a-z_]+\s*)\‍)/i', 'FROM \\1, \\2', $line);
282  //print $line."\n";
283 
284  // Remove () in the tables in FROM if two table
285  $line = preg_replace('/FROM\s*\‍(([a-z_]+\s+as\s+[a-z_]+)\s*,\s*([a-z_]+\s+as\s+[a-z_]+\s*),\s*([a-z_]+\s+as\s+[a-z_]+\s*)\‍)/i', 'FROM \\1, \\2, \\3', $line);
286  //print $line."\n";
287 
288  //print "type=".$type." newline=".$line."<br>\n";
289  }
290 
291  return $line;
292  }
293 
294  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
301  public function select_db($database)
302  {
303  // phpcs:enable
304  dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
305  // sqlite_select_db() does not exist
306  //return sqlite_select_db($this->db,$database);
307  return true;
308  }
309 
310 
322  public function connect($host, $login, $passwd, $name, $port = 0)
323  {
324  global $main_data_dir;
325 
326  dol_syslog(get_class($this)."::connect name=".$name, LOG_DEBUG);
327 
328  $dir = $main_data_dir;
329  if (empty($dir)) {
330  $dir = DOL_DATA_ROOT;
331  }
332  // With sqlite, port must be in connect parameters
333  //if (! $newport) $newport=3306;
334  $database_name = $dir.'/database_'.$name.'.sdb';
335  try {
336  /*** connect to SQLite database ***/
337  //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb');
338  $this->db = new SQLite3($database_name);
339  //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
340  } catch (Exception $e) {
341  $this->error = self::LABEL.' '.$e->getMessage().' current dir='.$database_name;
342  return '';
343  }
344 
345  //print "Resultat fonction connect: ".$this->db;
346  return $this->db;
347  }
348 
349 
355  public function getVersion()
356  {
357  $tmp = $this->db->version();
358  return $tmp['versionString'];
359  }
360 
366  public function getDriverInfo()
367  {
368  return 'sqlite3 php driver';
369  }
370 
371 
378  public function close()
379  {
380  if ($this->db) {
381  if ($this->transaction_opened > 0) {
382  dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
383  }
384  $this->connected = false;
385  $this->db->close();
386  unset($this->db); // Clean this->db
387  return true;
388  }
389  return false;
390  }
391 
402  public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
403  {
404  global $conf, $dolibarr_main_db_readonly;
405 
406  $ret = null;
407 
408  $query = trim($query);
409 
410  $this->error = '';
411 
412  // Convert MySQL syntax to SQLite syntax
413  $reg = array();
414  if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\‍(([\w,\s]+)\‍)\s*REFERENCES\s+(\w+)\s*\‍(([\w,\s]+)\‍)/i', $query, $reg)) {
415  // Ajout d'une clef étrangère à la table
416  // procédure de remplacement de la table pour ajouter la contrainte
417  // Exemple : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)
418  // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid))
419  $foreignFields = $reg[5];
420  $foreignTable = $reg[4];
421  $localfields = $reg[3];
422  $constraintname = trim($reg[2]);
423  $tablename = trim($reg[1]);
424 
425  $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='".$this->escape($tablename)."'");
426 
427  // 1- Renommer la table avec un nom temporaire
428  $this->query("ALTER TABLE ".$tablename." RENAME TO tmp_".$tablename);
429 
430  // 2- Recréer la table avec la contrainte ajoutée
431 
432  // on bricole la requete pour ajouter la contrainte
433  $descTable = substr($descTable, 0, strlen($descTable) - 1);
434  $descTable .= ", CONSTRAINT ".$constraintname." FOREIGN KEY (".$localfields.") REFERENCES ".$foreignTable."(".$foreignFields.")";
435 
436  // fermeture de l'instruction
437  $descTable .= ')';
438 
439  // Création proprement dite de la table
440  $this->query($descTable);
441 
442  // 3- Transférer les données
443  $this->query("INSERT INTO ".$tablename." SELECT * FROM tmp_".$tablename);
444 
445  // 4- Supprimer la table temporaire
446  $this->query("DROP TABLE tmp_".$tablename);
447 
448  // dummy statement
449  $query = "SELECT 0";
450  } else {
451  $query = $this->convertSQLFromMysql($query, $type);
452  }
453  //print "After convertSQLFromMysql:\n".$query."<br>\n";
454 
455  if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK'))) {
456  $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
457  dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
458  }
459  if (empty($query)) {
460  return false; // Return false = error if empty request
461  }
462 
463  if (!empty($dolibarr_main_db_readonly)) {
464  if (preg_match('/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
465  $this->lasterror = 'Application in read-only mode';
466  $this->lasterrno = 'APPREADONLY';
467  $this->lastquery = $query;
468  return false;
469  }
470  }
471 
472  // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
473  try {
474  //$ret = $this->db->exec($query);
475  $ret = $this->db->query($query); // $ret is a Sqlite3Result
476  if ($ret) {
477  $ret->queryString = $query;
478  }
479  } catch (Exception $e) {
480  $this->error = $this->db->lastErrorMsg();
481  }
482 
483  if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {
484  // Si requete utilisateur, on la sauvegarde ainsi que son resultset
485  if (!is_object($ret) || $this->error) {
486  $this->lastqueryerror = $query;
487  $this->lasterror = $this->error();
488  $this->lasterrno = $this->errno();
489 
490  dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR);
491 
492  $errormsg = get_class($this)."::query SQL Error message: ".$this->lasterror;
493 
494  if (preg_match('/[0-9]/', $this->lasterrno)) {
495  $errormsg .= ' ('.$this->lasterrno.')';
496  }
497 
498  if ($conf->global->SYSLOG_LEVEL < LOG_DEBUG) {
499  dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
500  }
501  dol_syslog(get_class($this)."::query SQL Error message: ".$errormsg, LOG_ERR);
502  }
503  $this->lastquery = $query;
504  $this->_results = $ret;
505  }
506 
507  return $ret;
508  }
509 
510  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
517  public function fetch_object($resultset)
518  {
519  // phpcs:enable
520  // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
521  if (!is_object($resultset)) {
522  $resultset = $this->_results;
523  }
524  //return $resultset->fetch(PDO::FETCH_OBJ);
525  $ret = $resultset->fetchArray(SQLITE3_ASSOC);
526  if ($ret) {
527  return (object) $ret;
528  }
529  return false;
530  }
531 
532 
533  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
540  public function fetch_array($resultset)
541  {
542  // phpcs:enable
543  // If resultset not provided, we take the last used by connexion
544  if (!is_object($resultset)) {
545  $resultset = $this->_results;
546  }
547  //return $resultset->fetch(PDO::FETCH_ASSOC);
548  $ret = $resultset->fetchArray(SQLITE3_ASSOC);
549  return $ret;
550  }
551 
552  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
559  public function fetch_row($resultset)
560  {
561  // phpcs:enable
562  // If resultset not provided, we take the last used by connexion
563  if (!is_bool($resultset)) {
564  if (!is_object($resultset)) {
565  $resultset = $this->_results;
566  }
567  return $resultset->fetchArray(SQLITE3_NUM);
568  } else {
569  // si le curseur est un booleen on retourne la valeur 0
570  return false;
571  }
572  }
573 
574  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
582  public function num_rows($resultset)
583  {
584  // phpcs:enable
585  // FIXME: SQLite3Result does not have a queryString member
586 
587  // If resultset not provided, we take the last used by connexion
588  if (!is_object($resultset)) {
589  $resultset = $this->_results;
590  }
591  if (preg_match("/^SELECT/i", $resultset->queryString)) {
592  return $this->db->querySingle("SELECT count(*) FROM (".$resultset->queryString.") q");
593  }
594  return 0;
595  }
596 
597  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
605  public function affected_rows($resultset)
606  {
607  // phpcs:enable
608  // FIXME: SQLite3Result does not have a queryString member
609 
610  // If resultset not provided, we take the last used by connexion
611  if (!is_object($resultset)) {
612  $resultset = $this->_results;
613  }
614  if (preg_match("/^SELECT/i", $resultset->queryString)) {
615  return $this->num_rows($resultset);
616  }
617  // mysql necessite un link de base pour cette fonction contrairement
618  // a pqsql qui prend un resultset
619  return $this->db->changes();
620  }
621 
622 
629  public function free($resultset = null)
630  {
631  // If resultset not provided, we take the last used by connexion
632  if (!is_object($resultset)) {
633  $resultset = $this->_results;
634  }
635  // Si resultset en est un, on libere la memoire
636  if ($resultset && is_object($resultset)) {
637  $resultset->finalize();
638  }
639  }
640 
647  public function escape($stringtoencode)
648  {
649  return Sqlite3::escapeString($stringtoencode);
650  }
651 
658  public function escapeforlike($stringtoencode)
659  {
660  return str_replace(array('_', '\\', '%'), array('\_', '\\\\', '\%'), (string) $stringtoencode);
661  }
662 
668  public function errno()
669  {
670  if (!$this->connected) {
671  // Si il y a eu echec de connexion, $this->db n'est pas valide.
672  return 'DB_ERROR_FAILED_TO_CONNECT';
673  } else {
674  // Constants to convert error code to a generic Dolibarr error code
675  /*$errorcode_map = array(
676  1004 => 'DB_ERROR_CANNOT_CREATE',
677  1005 => 'DB_ERROR_CANNOT_CREATE',
678  1006 => 'DB_ERROR_CANNOT_CREATE',
679  1007 => 'DB_ERROR_ALREADY_EXISTS',
680  1008 => 'DB_ERROR_CANNOT_DROP',
681  1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
682  1044 => 'DB_ERROR_ACCESSDENIED',
683  1046 => 'DB_ERROR_NODBSELECTED',
684  1048 => 'DB_ERROR_CONSTRAINT',
685  'HY000' => 'DB_ERROR_TABLE_ALREADY_EXISTS',
686  1051 => 'DB_ERROR_NOSUCHTABLE',
687  1054 => 'DB_ERROR_NOSUCHFIELD',
688  1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
689  1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
690  1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
691  1064 => 'DB_ERROR_SYNTAX',
692  1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
693  1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
694  1091 => 'DB_ERROR_NOSUCHFIELD',
695  1100 => 'DB_ERROR_NOT_LOCKED',
696  1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
697  1146 => 'DB_ERROR_NOSUCHTABLE',
698  1216 => 'DB_ERROR_NO_PARENT',
699  1217 => 'DB_ERROR_CHILD_EXISTS',
700  1451 => 'DB_ERROR_CHILD_EXISTS'
701  );
702 
703  if (isset($errorcode_map[$this->db->errorCode()]))
704  {
705  return $errorcode_map[$this->db->errorCode()];
706  }*/
707  $errno = $this->db->lastErrorCode();
708  if ($errno == 'HY000' || $errno == 0) {
709  if (preg_match('/table.*already exists/i', $this->error)) {
710  return 'DB_ERROR_TABLE_ALREADY_EXISTS';
711  } elseif (preg_match('/index.*already exists/i', $this->error)) {
712  return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS';
713  } elseif (preg_match('/syntax error/i', $this->error)) {
714  return 'DB_ERROR_SYNTAX';
715  }
716  }
717  if ($errno == '23000') {
718  if (preg_match('/column.* not unique/i', $this->error)) {
719  return 'DB_ERROR_RECORD_ALREADY_EXISTS';
720  } elseif (preg_match('/PRIMARY KEY must be unique/i', $this->error)) {
721  return 'DB_ERROR_RECORD_ALREADY_EXISTS';
722  }
723  }
724  if ($errno > 1) {
725  // TODO Voir la liste des messages d'erreur
726  }
727 
728  return ($errno ? 'DB_ERROR_'.$errno : '0');
729  }
730  }
731 
737  public function error()
738  {
739  if (!$this->connected) {
740  // Si il y a eu echec de connexion, $this->db n'est pas valide pour sqlite_error.
741  return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version';
742  } else {
743  return $this->error;
744  }
745  }
746 
747  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
755  public function last_insert_id($tab, $fieldid = 'rowid')
756  {
757  // phpcs:enable
758  return $this->db->lastInsertRowId();
759  }
760 
769  public function encrypt($fieldorvalue, $withQuotes = 1)
770  {
771  global $conf;
772 
773  // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
774  $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
775 
776  //Encryption key
777  $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
778 
779  $escapedstringwithquotes = ($withQuotes ? "'" : "").$this->escape($fieldorvalue).($withQuotes ? "'" : "");
780 
781  if ($cryptType && !empty($cryptKey)) {
782  if ($cryptType == 2) {
783  $escapedstringwithquotes = "AES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
784  } elseif ($cryptType == 1) {
785  $escapedstringwithquotes = "DES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
786  }
787  }
788 
789  return $escapedstringwithquotes;
790  }
791 
798  public function decrypt($value)
799  {
800  global $conf;
801 
802  // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
803  $cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
804 
805  //Encryption key
806  $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
807 
808  $return = $value;
809 
810  if ($cryptType && !empty($cryptKey)) {
811  if ($cryptType == 2) {
812  $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
813  } elseif ($cryptType == 1) {
814  $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
815  }
816  }
817 
818  return $return;
819  }
820 
821 
822  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
828  public function DDLGetConnectId()
829  {
830  // phpcs:enable
831  return '?';
832  }
833 
834 
835  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
847  public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
848  {
849  // phpcs:enable
850  if (empty($charset)) {
851  $charset = $this->forcecharset;
852  }
853  if (empty($collation)) {
854  $collation = $this->forcecollate;
855  }
856 
857  // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
858  $sql = "CREATE DATABASE ".$this->escape($database);
859  $sql .= " DEFAULT CHARACTER SET ".$this->escape($charset)." DEFAULT COLLATE ".$this->escape($collation);
860 
861  dol_syslog($sql, LOG_DEBUG);
862  $ret = $this->query($sql);
863 
864  return $ret;
865  }
866 
867  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
875  public function DDLListTables($database, $table = '')
876  {
877  // phpcs:enable
878  $listtables = array();
879 
880  $like = '';
881  if ($table) {
882  $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
883 
884  $like = "LIKE '".$this->escape($tmptable)."'";
885  }
886  $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
887 
888  $sql = "SHOW TABLES FROM ".$tmpdatabase." ".$like.";";
889  //print $sql;
890  $result = $this->query($sql);
891  if ($result) {
892  while ($row = $this->fetch_row($result)) {
893  $listtables[] = $row[0];
894  }
895  }
896  return $listtables;
897  }
898 
899  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
907  public function DDLInfoTable($table)
908  {
909  // phpcs:enable
910  $infotables = array();
911 
912  $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
913 
914  $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
915 
916  dol_syslog($sql, LOG_DEBUG);
917  $result = $this->query($sql);
918  if ($result) {
919  while ($row = $this->fetch_row($result)) {
920  $infotables[] = $row;
921  }
922  }
923  return $infotables;
924  }
925 
926  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
939  public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
940  {
941  // phpcs:enable
942  // FIXME: $fulltext_keys parameter is unused
943 
944  // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
945  // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
946  $sql = "create table ".$table."(";
947  $i = 0;
948  foreach ($fields as $field_name => $field_desc) {
949  $sqlfields[$i] = $field_name." ";
950  $sqlfields[$i] .= $field_desc['type'];
951  if (preg_match("/^[^\s]/i", $field_desc['value'])) {
952  $sqlfields[$i] .= "(".$field_desc['value'].")";
953  } elseif (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
954  $sqlfields[$i] .= " ".$field_desc['attribute'];
955  } elseif (preg_match("/^[^\s]/i", $field_desc['default'])) {
956  if (preg_match("/null/i", $field_desc['default'])) {
957  $sqlfields[$i] .= " default ".$field_desc['default'];
958  } else {
959  $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
960  }
961  } elseif (preg_match("/^[^\s]/i", $field_desc['null'])) {
962  $sqlfields[$i] .= " ".$field_desc['null'];
963  } elseif (preg_match("/^[^\s]/i", $field_desc['extra'])) {
964  $sqlfields[$i] .= " ".$field_desc['extra'];
965  }
966  $i++;
967  }
968  if ($primary_key != "") {
969  $pk = "primary key(".$primary_key.")";
970  }
971 
972  if (is_array($unique_keys)) {
973  $i = 0;
974  foreach ($unique_keys as $key => $value) {
975  $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
976  $i++;
977  }
978  }
979  if (is_array($keys)) {
980  $i = 0;
981  foreach ($keys as $key => $value) {
982  $sqlk[$i] = "KEY ".$key." (".$value.")";
983  $i++;
984  }
985  }
986  $sql .= implode(',', $sqlfields);
987  if ($primary_key != "") {
988  $sql .= ",".$pk;
989  }
990  if (is_array($unique_keys)) {
991  $sql .= ",".implode(',', $sqluq);
992  }
993  if (is_array($keys)) {
994  $sql .= ",".implode(',', $sqlk);
995  }
996  $sql .= ") type=".$type;
997 
998  dol_syslog($sql, LOG_DEBUG);
999  if (!$this -> query($sql)) {
1000  return -1;
1001  }
1002  return 1;
1003  }
1004 
1005  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1012  public function DDLDropTable($table)
1013  {
1014  // phpcs:enable
1015  $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
1016 
1017  $sql = "DROP TABLE ".$tmptable;
1018 
1019  if (!$this->query($sql)) {
1020  return -1;
1021  } else {
1022  return 1;
1023  }
1024  }
1025 
1026  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1034  public function DDLDescTable($table, $field = "")
1035  {
1036  // phpcs:enable
1037  $sql = "DESC ".$table." ".$field;
1038 
1039  dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
1040  $this->_results = $this->query($sql);
1041  return $this->_results;
1042  }
1043 
1044  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1054  public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1055  {
1056  // phpcs:enable
1057  // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
1058  // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
1059  $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
1060  $sql .= $field_desc['type'];
1061  if (preg_match("/^[^\s]/i", $field_desc['value'])) {
1062  if (!in_array($field_desc['type'], array('date', 'datetime'))) {
1063  $sql .= "(".$field_desc['value'].")";
1064  }
1065  }
1066  if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1067  $sql .= " ".$field_desc['attribute'];
1068  }
1069  if (preg_match("/^[^\s]/i", $field_desc['null'])) {
1070  $sql .= " ".$field_desc['null'];
1071  }
1072  if (preg_match("/^[^\s]/i", $field_desc['default'])) {
1073  if (preg_match("/null/i", $field_desc['default'])) {
1074  $sql .= " default ".$field_desc['default'];
1075  } else {
1076  $sql .= " default '".$this->escape($field_desc['default'])."'";
1077  }
1078  }
1079  if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
1080  $sql .= " ".$field_desc['extra'];
1081  }
1082  $sql .= " ".$field_position;
1083 
1084  dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1085  if (!$this->query($sql)) {
1086  return -1;
1087  }
1088  return 1;
1089  }
1090 
1091  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1100  public function DDLUpdateField($table, $field_name, $field_desc)
1101  {
1102  // phpcs:enable
1103  $sql = "ALTER TABLE ".$table;
1104  $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
1105  if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
1106  $sql .= "(".$field_desc['value'].")";
1107  }
1108 
1109  dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1110  if (!$this->query($sql)) {
1111  return -1;
1112  }
1113  return 1;
1114  }
1115 
1116  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1124  public function DDLDropField($table, $field_name)
1125  {
1126  // phpcs:enable
1127  $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1128 
1129  $sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`";
1130  if (!$this->query($sql)) {
1131  $this->error = $this->lasterror();
1132  return -1;
1133  }
1134  return 1;
1135  }
1136 
1137 
1138  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1148  public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1149  {
1150  // phpcs:enable
1151  $sql = "INSERT INTO user ";
1152  $sql .= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1153  $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')";
1154  $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1155 
1156  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1157  $resql = $this->query($sql);
1158  if (!$resql) {
1159  return -1;
1160  }
1161 
1162  $sql = "INSERT INTO db ";
1163  $sql .= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1164  $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'";
1165  $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1166 
1167  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1168  $resql = $this->query($sql);
1169  if (!$resql) {
1170  return -1;
1171  }
1172 
1173  $sql = "FLUSH Privileges";
1174 
1175  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1176  $resql = $this->query($sql);
1177  if (!$resql) {
1178  return -1;
1179  }
1180  return 1;
1181  }
1182 
1188  public function getDefaultCharacterSetDatabase()
1189  {
1190  return 'UTF-8';
1191  }
1192 
1198  public function getListOfCharacterSet()
1199  {
1200  $liste = array();
1201  $i = 0;
1202  $liste[$i]['charset'] = 'UTF-8';
1203  $liste[$i]['description'] = 'UTF-8';
1204  return $liste;
1205  }
1206 
1212  public function getDefaultCollationDatabase()
1213  {
1214  return 'UTF-8';
1215  }
1216 
1222  public function getListOfCollation()
1223  {
1224  $liste = array();
1225  $i = 0;
1226  $liste[$i]['charset'] = 'UTF-8';
1227  $liste[$i]['description'] = 'UTF-8';
1228  return $liste;
1229  }
1230 
1236  public function getPathOfDump()
1237  {
1238  // FIXME: not for SQLite
1239  $fullpathofdump = '/pathtomysqldump/mysqldump';
1240 
1241  $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1242  if ($resql) {
1243  $liste = $this->fetch_array($resql);
1244  $basedir = $liste['Value'];
1245  $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1246  }
1247  return $fullpathofdump;
1248  }
1249 
1255  public function getPathOfRestore()
1256  {
1257  // FIXME: not for SQLite
1258  $fullpathofimport = '/pathtomysql/mysql';
1259 
1260  $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1261  if ($resql) {
1262  $liste = $this->fetch_array($resql);
1263  $basedir = $liste['Value'];
1264  $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1265  }
1266  return $fullpathofimport;
1267  }
1268 
1275  public function getServerParametersValues($filter = '')
1276  {
1277  $result = array();
1278  static $pragmas;
1279  if (!isset($pragmas)) {
1280  // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur
1281  // indépendante de la base de données.
1282  // cf. http://www.sqlite.org/pragma.html
1283  $pragmas = array(
1284  'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size',
1285  'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list',
1286  'compile_options', 'data_version', /*'database_list',*/
1287  'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count',
1288  'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check',
1289  'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode',
1290  'max_page_count', 'page_count', 'page_size', 'parser_trace',
1291  'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers',
1292  'reverse_unordered_selects', 'schema_version', 'user_version',
1293  'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit',
1294  'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads',
1295  'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace',
1296  'wal_autocheckpoint',
1297  );
1298  }
1299 
1300  // TODO prendre en compte le filtre
1301  foreach ($pragmas as $var) {
1302  $sql = "PRAGMA $var";
1303  $resql = $this->query($sql);
1304  if ($resql) {
1305  $obj = $this->fetch_row($resql);
1306  //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
1307  $result[$var] = $obj[0];
1308  } else {
1309  // TODO Récupérer le message
1310  $result[$var] = 'FAIL';
1311  }
1312  }
1313  return $result;
1314  }
1315 
1322  public function getServerStatusValues($filter = '')
1323  {
1324  $result = array();
1325  /*
1326  $sql='SHOW STATUS';
1327  if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
1328  $resql=$this->query($sql);
1329  if ($resql)
1330  {
1331  while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1332  }
1333  */
1334 
1335  return $result;
1336  }
1337 
1347  private function addCustomFunction($name, $arg_count = -1)
1348  {
1349  if ($this->db) {
1350  $newname = preg_replace('/_/', '', $name);
1351  $localname = __CLASS__.'::db'.$newname;
1352  $reflectClass = new ReflectionClass(__CLASS__);
1353  $reflectFunction = $reflectClass->getMethod('db'.$newname);
1354  if ($arg_count < 0) {
1355  $arg_count = $reflectFunction->getNumberOfParameters();
1356  }
1357  if (!$this->db->createFunction($name, $localname, $arg_count)) {
1358  $this->error = "unable to create custom function '$name'";
1359  }
1360  }
1361  }
1362 
1363  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1372  private static function calc_daynr($year, $month, $day)
1373  {
1374  // phpcs:enable
1375  $y = $year;
1376  if ($y == 0 && $month == 0) {
1377  return 0;
1378  }
1379  $num = (365 * $y + 31 * ($month - 1) + $day);
1380  if ($month <= 2) {
1381  $y--;
1382  } else {
1383  $num -= floor(($month * 4 + 23) / 10);
1384  }
1385  $temp = floor(($y / 100 + 1) * 3 / 4);
1386  return $num + floor($y / 4) - $temp;
1387  }
1388 
1389  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1397  private static function calc_weekday($daynr, $sunday_first_day_of_week)
1398  {
1399  // phpcs:enable
1400  $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
1401  return $ret;
1402  }
1403 
1404  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1411  private static function calc_days_in_year($year)
1412  {
1413  // phpcs:enable
1414  return (($year & 3) == 0 && ($year % 100 || ($year % 400 == 0 && $year)) ? 366 : 365);
1415  }
1416 
1417  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1428  private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year)
1429  {
1430  // phpcs:enable
1431  $daynr = self::calc_daynr($year, $month, $day);
1432  $first_daynr = self::calc_daynr($year, 1, 1);
1433  $monday_first = ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0;
1434  $week_year = ($week_behaviour & self::WEEK_YEAR) ? 1 : 0;
1435  $first_weekday = ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0;
1436 
1437  $weekday = self::calc_weekday($first_daynr, !$monday_first);
1438  $calc_year = $year;
1439 
1440  if ($month == 1 && $day <= 7 - $weekday) {
1441  if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) {
1442  return 0;
1443  }
1444  $week_year = 1;
1445  $calc_year--;
1446  $first_daynr -= ($days = self::calc_days_in_year($calc_year));
1447  $weekday = ($weekday + 53 * 7 - $days) % 7;
1448  }
1449 
1450  if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
1451  $days = $daynr - ($first_daynr + (7 - $weekday));
1452  } else {
1453  $days = $daynr - ($first_daynr - $weekday);
1454  }
1455 
1456  if ($week_year && $days >= 52 * 7) {
1457  $weekday = ($weekday + self::calc_days_in_year($calc_year)) % 7;
1458  if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) {
1459  $calc_year++;
1460  return 1;
1461  }
1462  }
1463  return floor($days / 7 + 1);
1464  }
1465 }
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 SQLite database.
fetch_object($resultset)
Returns the current line (as an object) for the resultset cursor.
escape($stringtoencode)
Escape a string to insert data.
fetch_array($resultset)
Return datas as an array.
error()
Renvoie le texte de l'erreur mysql de l'operation precedente.
fetch_row($resultset)
Return datas as an array.
getPathOfRestore()
Return full path of restore program.
errno()
Renvoie le code erreur generique de l'operation precedente.
const LABEL
Database label.
close()
Close database connexion.
static calc_days_in_year($year)
calc_days_in_year
static calc_daynr($year, $month, $day)
calc_daynr
escapeforlike($stringtoencode)
Escape a string to insert data into a like.
static calc_weekday($daynr, $sunday_first_day_of_week)
calc_weekday
encrypt($fieldorvalue, $withQuotes=1)
Encrypt sensitive data in database Warning: This function includes the escape and add the SQL simple ...
last_insert_id($tab, $fieldid='rowid')
Get last ID after an insert INSERT.
affected_rows($resultset)
Return number of lines for result of a SELECT.
decrypt($value)
Decrypt sensitive data in database.
static calc_week($year, $month, $day, $week_behaviour, &$calc_year)
calc_week
getDriverInfo()
Return version of database client driver.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
addCustomFunction($name, $arg_count=-1)
Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees.
select_db($database)
Select a database.
connect($host, $login, $passwd, $name, $port=0)
Connexion to server.
num_rows($resultset)
Return number of lines for result of a SELECT.
static convertSQLFromMysql($line, $type='ddl')
Convert a SQL request in Mysql syntax to native syntax.
getVersion()
Return version of database server.
getServerParametersValues($filter='')
Return value of server parameters.
free($resultset=null)
Free last resultset used.
__construct($type, $host, $user, $pass, $name='', $port=0)
Constructor.
const VERSIONMIN
Version min database.
getServerStatusValues($filter='')
Return value of server status.
$type
Database type.
if(isModEnabled('facture') &&!empty($user->rights->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') &&!empty($user->rights->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)) $resql
Social contributions to pay.
Definition: index.php:745
print *****$script_file(".$version.") pid cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
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:119
$conf db
API class for accounts.
Definition: inc.php:41