dolibarr  18.0.0
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 DDLListTablesFull($database, $table = '')
908  {
909  // phpcs:enable
910  $listtables = array();
911 
912  $like = '';
913  if ($table) {
914  $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
915 
916  $like = "LIKE '".$this->escape($tmptable)."'";
917  }
918  $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
919 
920  $sql = "SHOW FULL TABLES FROM ".$tmpdatabase." ".$like.";";
921  //print $sql;
922  $result = $this->query($sql);
923  if ($result) {
924  while ($row = $this->fetch_row($result)) {
925  $listtables[] = $row;
926  }
927  }
928  return $listtables;
929  }
930 
931  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
939  public function DDLInfoTable($table)
940  {
941  // phpcs:enable
942  $infotables = array();
943 
944  $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
945 
946  $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
947 
948  dol_syslog($sql, LOG_DEBUG);
949  $result = $this->query($sql);
950  if ($result) {
951  while ($row = $this->fetch_row($result)) {
952  $infotables[] = $row;
953  }
954  }
955  return $infotables;
956  }
957 
958  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
971  public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
972  {
973  // phpcs:enable
974  // FIXME: $fulltext_keys parameter is unused
975 
976  // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
977  // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
978  $sql = "create table ".$table."(";
979  $i = 0;
980  foreach ($fields as $field_name => $field_desc) {
981  $sqlfields[$i] = $field_name." ";
982  $sqlfields[$i] .= $field_desc['type'];
983  if (preg_match("/^[^\s]/i", $field_desc['value'])) {
984  $sqlfields[$i] .= "(".$field_desc['value'].")";
985  } elseif (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
986  $sqlfields[$i] .= " ".$field_desc['attribute'];
987  } elseif (preg_match("/^[^\s]/i", $field_desc['default'])) {
988  if (preg_match("/null/i", $field_desc['default'])) {
989  $sqlfields[$i] .= " default ".$field_desc['default'];
990  } else {
991  $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
992  }
993  } elseif (preg_match("/^[^\s]/i", $field_desc['null'])) {
994  $sqlfields[$i] .= " ".$field_desc['null'];
995  } elseif (preg_match("/^[^\s]/i", $field_desc['extra'])) {
996  $sqlfields[$i] .= " ".$field_desc['extra'];
997  }
998  $i++;
999  }
1000  if ($primary_key != "") {
1001  $pk = "primary key(".$primary_key.")";
1002  }
1003 
1004  if (is_array($unique_keys)) {
1005  $i = 0;
1006  foreach ($unique_keys as $key => $value) {
1007  $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
1008  $i++;
1009  }
1010  }
1011  if (is_array($keys)) {
1012  $i = 0;
1013  foreach ($keys as $key => $value) {
1014  $sqlk[$i] = "KEY ".$key." (".$value.")";
1015  $i++;
1016  }
1017  }
1018  $sql .= implode(',', $sqlfields);
1019  if ($primary_key != "") {
1020  $sql .= ",".$pk;
1021  }
1022  if (is_array($unique_keys)) {
1023  $sql .= ",".implode(',', $sqluq);
1024  }
1025  if (is_array($keys)) {
1026  $sql .= ",".implode(',', $sqlk);
1027  }
1028  $sql .= ") type=".$type;
1029 
1030  dol_syslog($sql, LOG_DEBUG);
1031  if (!$this -> query($sql)) {
1032  return -1;
1033  }
1034  return 1;
1035  }
1036 
1037  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1044  public function DDLDropTable($table)
1045  {
1046  // phpcs:enable
1047  $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
1048 
1049  $sql = "DROP TABLE ".$tmptable;
1050 
1051  if (!$this->query($sql)) {
1052  return -1;
1053  } else {
1054  return 1;
1055  }
1056  }
1057 
1058  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1066  public function DDLDescTable($table, $field = "")
1067  {
1068  // phpcs:enable
1069  $sql = "DESC ".$table." ".$field;
1070 
1071  dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
1072  $this->_results = $this->query($sql);
1073  return $this->_results;
1074  }
1075 
1076  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1086  public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1087  {
1088  // phpcs:enable
1089  // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
1090  // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
1091  $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
1092  $sql .= $field_desc['type'];
1093  if (preg_match("/^[^\s]/i", $field_desc['value'])) {
1094  if (!in_array($field_desc['type'], array('date', 'datetime'))) {
1095  $sql .= "(".$field_desc['value'].")";
1096  }
1097  }
1098  if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1099  $sql .= " ".$field_desc['attribute'];
1100  }
1101  if (preg_match("/^[^\s]/i", $field_desc['null'])) {
1102  $sql .= " ".$field_desc['null'];
1103  }
1104  if (preg_match("/^[^\s]/i", $field_desc['default'])) {
1105  if (preg_match("/null/i", $field_desc['default'])) {
1106  $sql .= " default ".$field_desc['default'];
1107  } else {
1108  $sql .= " default '".$this->escape($field_desc['default'])."'";
1109  }
1110  }
1111  if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
1112  $sql .= " ".$field_desc['extra'];
1113  }
1114  $sql .= " ".$field_position;
1115 
1116  dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1117  if (!$this->query($sql)) {
1118  return -1;
1119  }
1120  return 1;
1121  }
1122 
1123  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1132  public function DDLUpdateField($table, $field_name, $field_desc)
1133  {
1134  // phpcs:enable
1135  $sql = "ALTER TABLE ".$table;
1136  $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
1137  if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
1138  $sql .= "(".$field_desc['value'].")";
1139  }
1140 
1141  dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1142  if (!$this->query($sql)) {
1143  return -1;
1144  }
1145  return 1;
1146  }
1147 
1148  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1156  public function DDLDropField($table, $field_name)
1157  {
1158  // phpcs:enable
1159  $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1160 
1161  $sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`";
1162  if (!$this->query($sql)) {
1163  $this->error = $this->lasterror();
1164  return -1;
1165  }
1166  return 1;
1167  }
1168 
1169 
1170  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1180  public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1181  {
1182  // phpcs:enable
1183  $sql = "INSERT INTO user ";
1184  $sql .= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1185  $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')";
1186  $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1187 
1188  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1189  $resql = $this->query($sql);
1190  if (!$resql) {
1191  return -1;
1192  }
1193 
1194  $sql = "INSERT INTO db ";
1195  $sql .= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1196  $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'";
1197  $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1198 
1199  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1200  $resql = $this->query($sql);
1201  if (!$resql) {
1202  return -1;
1203  }
1204 
1205  $sql = "FLUSH Privileges";
1206 
1207  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1208  $resql = $this->query($sql);
1209  if (!$resql) {
1210  return -1;
1211  }
1212  return 1;
1213  }
1214 
1220  public function getDefaultCharacterSetDatabase()
1221  {
1222  return 'UTF-8';
1223  }
1224 
1230  public function getListOfCharacterSet()
1231  {
1232  $liste = array();
1233  $i = 0;
1234  $liste[$i]['charset'] = 'UTF-8';
1235  $liste[$i]['description'] = 'UTF-8';
1236  return $liste;
1237  }
1238 
1244  public function getDefaultCollationDatabase()
1245  {
1246  return 'UTF-8';
1247  }
1248 
1254  public function getListOfCollation()
1255  {
1256  $liste = array();
1257  $i = 0;
1258  $liste[$i]['charset'] = 'UTF-8';
1259  $liste[$i]['description'] = 'UTF-8';
1260  return $liste;
1261  }
1262 
1268  public function getPathOfDump()
1269  {
1270  // FIXME: not for SQLite
1271  $fullpathofdump = '/pathtomysqldump/mysqldump';
1272 
1273  $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1274  if ($resql) {
1275  $liste = $this->fetch_array($resql);
1276  $basedir = $liste['Value'];
1277  $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1278  }
1279  return $fullpathofdump;
1280  }
1281 
1287  public function getPathOfRestore()
1288  {
1289  // FIXME: not for SQLite
1290  $fullpathofimport = '/pathtomysql/mysql';
1291 
1292  $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1293  if ($resql) {
1294  $liste = $this->fetch_array($resql);
1295  $basedir = $liste['Value'];
1296  $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1297  }
1298  return $fullpathofimport;
1299  }
1300 
1307  public function getServerParametersValues($filter = '')
1308  {
1309  $result = array();
1310  static $pragmas;
1311  if (!isset($pragmas)) {
1312  // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur
1313  // indépendante de la base de données.
1314  // cf. http://www.sqlite.org/pragma.html
1315  $pragmas = array(
1316  'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size',
1317  'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list',
1318  'compile_options', 'data_version', /*'database_list',*/
1319  'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count',
1320  'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check',
1321  'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode',
1322  'max_page_count', 'page_count', 'page_size', 'parser_trace',
1323  'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers',
1324  'reverse_unordered_selects', 'schema_version', 'user_version',
1325  'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit',
1326  'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads',
1327  'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace',
1328  'wal_autocheckpoint',
1329  );
1330  }
1331 
1332  // TODO prendre en compte le filtre
1333  foreach ($pragmas as $var) {
1334  $sql = "PRAGMA $var";
1335  $resql = $this->query($sql);
1336  if ($resql) {
1337  $obj = $this->fetch_row($resql);
1338  //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
1339  $result[$var] = $obj[0];
1340  } else {
1341  // TODO Récupérer le message
1342  $result[$var] = 'FAIL';
1343  }
1344  }
1345  return $result;
1346  }
1347 
1354  public function getServerStatusValues($filter = '')
1355  {
1356  $result = array();
1357  /*
1358  $sql='SHOW STATUS';
1359  if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
1360  $resql=$this->query($sql);
1361  if ($resql)
1362  {
1363  while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1364  }
1365  */
1366 
1367  return $result;
1368  }
1369 
1379  private function addCustomFunction($name, $arg_count = -1)
1380  {
1381  if ($this->db) {
1382  $newname = preg_replace('/_/', '', $name);
1383  $localname = __CLASS__.'::db'.$newname;
1384  $reflectClass = new ReflectionClass(__CLASS__);
1385  $reflectFunction = $reflectClass->getMethod('db'.$newname);
1386  if ($arg_count < 0) {
1387  $arg_count = $reflectFunction->getNumberOfParameters();
1388  }
1389  if (!$this->db->createFunction($name, $localname, $arg_count)) {
1390  $this->error = "unable to create custom function '$name'";
1391  }
1392  }
1393  }
1394 
1395  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1404  private static function calc_daynr($year, $month, $day)
1405  {
1406  // phpcs:enable
1407  $y = $year;
1408  if ($y == 0 && $month == 0) {
1409  return 0;
1410  }
1411  $num = (365 * $y + 31 * ($month - 1) + $day);
1412  if ($month <= 2) {
1413  $y--;
1414  } else {
1415  $num -= floor(($month * 4 + 23) / 10);
1416  }
1417  $temp = floor(($y / 100 + 1) * 3 / 4);
1418  return $num + floor($y / 4) - $temp;
1419  }
1420 
1421  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1429  private static function calc_weekday($daynr, $sunday_first_day_of_week)
1430  {
1431  // phpcs:enable
1432  $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
1433  return $ret;
1434  }
1435 
1436  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1443  private static function calc_days_in_year($year)
1444  {
1445  // phpcs:enable
1446  return (($year & 3) == 0 && ($year % 100 || ($year % 400 == 0 && $year)) ? 366 : 365);
1447  }
1448 
1449  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1460  private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year)
1461  {
1462  // phpcs:enable
1463  $daynr = self::calc_daynr($year, $month, $day);
1464  $first_daynr = self::calc_daynr($year, 1, 1);
1465  $monday_first = ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0;
1466  $week_year = ($week_behaviour & self::WEEK_YEAR) ? 1 : 0;
1467  $first_weekday = ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0;
1468 
1469  $weekday = self::calc_weekday($first_daynr, !$monday_first);
1470  $calc_year = $year;
1471 
1472  if ($month == 1 && $day <= 7 - $weekday) {
1473  if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) {
1474  return 0;
1475  }
1476  $week_year = 1;
1477  $calc_year--;
1478  $first_daynr -= ($days = self::calc_days_in_year($calc_year));
1479  $weekday = ($weekday + 53 * 7 - $days) % 7;
1480  }
1481 
1482  if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
1483  $days = $daynr - ($first_daynr + (7 - $weekday));
1484  } else {
1485  $days = $daynr - ($first_daynr - $weekday);
1486  }
1487 
1488  if ($week_year && $days >= 52 * 7) {
1489  $weekday = ($weekday + self::calc_days_in_year($calc_year)) % 7;
1490  if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) {
1491  $calc_year++;
1492  return 1;
1493  }
1494  }
1495  return floor($days / 7 + 1);
1496  }
1497 }
DoliDBSqlite3\getDriverInfo
getDriverInfo()
Return version of database client driver.
Definition: sqlite3.class.php:366
DoliDBSqlite3\addCustomFunction
addCustomFunction($name, $arg_count=-1)
Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees.
Definition: sqlite3.class.php:1379
DoliDBSqlite3\last_insert_id
last_insert_id($tab, $fieldid='rowid')
Get last ID after an insert INSERT.
Definition: sqlite3.class.php:755
description
print *****$script_file(".$version.") pid cd cd cd description as description
Definition: email_expire_services_to_customers.php:83
DoliDBSqlite3\__construct
__construct($type, $host, $user, $pass, $name='', $port=0)
Constructor.
Definition: sqlite3.class.php:63
DoliDB\lasterror
lasterror()
Return last error label.
Definition: DoliDB.class.php:329
DoliDBSqlite3\error
error()
Renvoie le texte de l'erreur mysql de l'operation precedente.
Definition: sqlite3.class.php:737
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
DoliDBSqlite3\select_db
select_db($database)
Select a database.
Definition: sqlite3.class.php:301
DoliDBSqlite3\convertSQLFromMysql
static convertSQLFromMysql($line, $type='ddl')
Convert a SQL request in Mysql syntax to native syntax.
Definition: sqlite3.class.php:141
DoliDBSqlite3\$type
$type
Database type.
Definition: sqlite3.class.php:36
DoliDBSqlite3\escape
escape($stringtoencode)
Escape a string to insert data.
Definition: sqlite3.class.php:647
DoliDBSqlite3\calc_days_in_year
static calc_days_in_year($year)
calc_days_in_year
Definition: sqlite3.class.php:1443
DoliDBSqlite3\connect
connect($host, $login, $passwd, $name, $port=0)
Connexion to server.
Definition: sqlite3.class.php:322
DoliDBSqlite3\encrypt
encrypt($fieldorvalue, $withQuotes=1)
Encrypt sensitive data in database Warning: This function includes the escape and add the SQL simple ...
Definition: sqlite3.class.php:769
DoliDBSqlite3\getServerStatusValues
getServerStatusValues($filter='')
Return value of server status.
Definition: sqlite3.class.php:1354
DoliDBSqlite3\free
free($resultset=null)
Free last resultset used.
Definition: sqlite3.class.php:629
rowid
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
Definition: email_expire_services_to_representatives.php:79
DoliDB\lastquery
lastquery()
Return last request executed with query()
Definition: DoliDB.class.php:274
Exception
DoliDBSqlite3\close
close()
Close database connexion.
Definition: sqlite3.class.php:378
DoliDBSqlite3\calc_week
static calc_week($year, $month, $day, $week_behaviour, &$calc_year)
calc_week
Definition: sqlite3.class.php:1460
DoliDBSqlite3\VERSIONMIN
const VERSIONMIN
Version min database.
Definition: sqlite3.class.php:40
DoliDB\lasterrno
lasterrno()
Return last error code.
Definition: DoliDB.class.php:151
DoliDBSqlite3\fetch_row
fetch_row($resultset)
Return datas as an array.
Definition: sqlite3.class.php:559
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1741
DoliDBSqlite3\fetch_array
fetch_array($resultset)
Return datas as an array.
Definition: sqlite3.class.php:540
DoliDBSqlite3\affected_rows
affected_rows($resultset)
Return number of lines for result of a SELECT.
Definition: sqlite3.class.php:605
DoliDBSqlite3\getPathOfRestore
getPathOfRestore()
Return full path of restore program.
Definition: sqlite3.class.php:1287
DoliDBSqlite3\fetch_object
fetch_object($resultset)
Returns the current line (as an object) for the resultset cursor.
Definition: sqlite3.class.php:517
$sql
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
DoliDBSqlite3\num_rows
num_rows($resultset)
Return number of lines for result of a SELECT.
Definition: sqlite3.class.php:582
DoliDB\lastqueryerror
lastqueryerror()
Return last query in error.
Definition: DoliDB.class.php:360
DoliDBSqlite3\query
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
Definition: sqlite3.class.php:402
DoliDBSqlite3\calc_weekday
static calc_weekday($daynr, $sunday_first_day_of_week)
calc_weekday
Definition: sqlite3.class.php:1429
DoliDBSqlite3\escapeforlike
escapeforlike($stringtoencode)
Escape a string to insert data into a like.
Definition: sqlite3.class.php:658
DoliDBSqlite3\calc_daynr
static calc_daynr($year, $month, $day)
calc_daynr
Definition: sqlite3.class.php:1404
DoliDBSqlite3\getVersion
getVersion()
Return version of database server.
Definition: sqlite3.class.php:355
DoliDBSqlite3
Class to manage Dolibarr database access for a SQLite database.
Definition: sqlite3.class.php:33
type
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120
DoliDBSqlite3\getServerParametersValues
getServerParametersValues($filter='')
Return value of server parameters.
Definition: sqlite3.class.php:1307
DoliDBSqlite3\decrypt
decrypt($value)
Decrypt sensitive data in database.
Definition: sqlite3.class.php:798
DoliDBSqlite3\errno
errno()
Renvoie le code erreur generique de l'operation precedente.
Definition: sqlite3.class.php:668
DoliDBSqlite3\LABEL
const LABEL
Database label.
Definition: sqlite3.class.php:38