dolibarr  17.0.4
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 
659  public function escapeunderscore($stringtoencode)
660  {
661  return str_replace('_', '\_', (string) $stringtoencode);
662  }
663 
670  public function escapeforlike($stringtoencode)
671  {
672  return str_replace(array('\\', '_', '%'), array('\\\\', '\_', '\%'), (string) $stringtoencode);
673  }
674 
680  public function errno()
681  {
682  if (!$this->connected) {
683  // Si il y a eu echec de connexion, $this->db n'est pas valide.
684  return 'DB_ERROR_FAILED_TO_CONNECT';
685  } else {
686  // Constants to convert error code to a generic Dolibarr error code
687  /*$errorcode_map = array(
688  1004 => 'DB_ERROR_CANNOT_CREATE',
689  1005 => 'DB_ERROR_CANNOT_CREATE',
690  1006 => 'DB_ERROR_CANNOT_CREATE',
691  1007 => 'DB_ERROR_ALREADY_EXISTS',
692  1008 => 'DB_ERROR_CANNOT_DROP',
693  1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
694  1044 => 'DB_ERROR_ACCESSDENIED',
695  1046 => 'DB_ERROR_NODBSELECTED',
696  1048 => 'DB_ERROR_CONSTRAINT',
697  'HY000' => 'DB_ERROR_TABLE_ALREADY_EXISTS',
698  1051 => 'DB_ERROR_NOSUCHTABLE',
699  1054 => 'DB_ERROR_NOSUCHFIELD',
700  1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
701  1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
702  1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
703  1064 => 'DB_ERROR_SYNTAX',
704  1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
705  1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
706  1091 => 'DB_ERROR_NOSUCHFIELD',
707  1100 => 'DB_ERROR_NOT_LOCKED',
708  1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
709  1146 => 'DB_ERROR_NOSUCHTABLE',
710  1216 => 'DB_ERROR_NO_PARENT',
711  1217 => 'DB_ERROR_CHILD_EXISTS',
712  1451 => 'DB_ERROR_CHILD_EXISTS'
713  );
714 
715  if (isset($errorcode_map[$this->db->errorCode()]))
716  {
717  return $errorcode_map[$this->db->errorCode()];
718  }*/
719  $errno = $this->db->lastErrorCode();
720  if ($errno == 'HY000' || $errno == 0) {
721  if (preg_match('/table.*already exists/i', $this->error)) {
722  return 'DB_ERROR_TABLE_ALREADY_EXISTS';
723  } elseif (preg_match('/index.*already exists/i', $this->error)) {
724  return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS';
725  } elseif (preg_match('/syntax error/i', $this->error)) {
726  return 'DB_ERROR_SYNTAX';
727  }
728  }
729  if ($errno == '23000') {
730  if (preg_match('/column.* not unique/i', $this->error)) {
731  return 'DB_ERROR_RECORD_ALREADY_EXISTS';
732  } elseif (preg_match('/PRIMARY KEY must be unique/i', $this->error)) {
733  return 'DB_ERROR_RECORD_ALREADY_EXISTS';
734  }
735  }
736  if ($errno > 1) {
737  // TODO Voir la liste des messages d'erreur
738  }
739 
740  return ($errno ? 'DB_ERROR_'.$errno : '0');
741  }
742  }
743 
749  public function error()
750  {
751  if (!$this->connected) {
752  // Si il y a eu echec de connexion, $this->db n'est pas valide pour sqlite_error.
753  return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version';
754  } else {
755  return $this->error;
756  }
757  }
758 
759  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
767  public function last_insert_id($tab, $fieldid = 'rowid')
768  {
769  // phpcs:enable
770  return $this->db->lastInsertRowId();
771  }
772 
781  public function encrypt($fieldorvalue, $withQuotes = 1)
782  {
783  global $conf;
784 
785  // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
786  $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
787 
788  //Encryption key
789  $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
790 
791  $escapedstringwithquotes = ($withQuotes ? "'" : "").$this->escape($fieldorvalue).($withQuotes ? "'" : "");
792 
793  if ($cryptType && !empty($cryptKey)) {
794  if ($cryptType == 2) {
795  $escapedstringwithquotes = "AES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
796  } elseif ($cryptType == 1) {
797  $escapedstringwithquotes = "DES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
798  }
799  }
800 
801  return $escapedstringwithquotes;
802  }
803 
810  public function decrypt($value)
811  {
812  global $conf;
813 
814  // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
815  $cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
816 
817  //Encryption key
818  $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
819 
820  $return = $value;
821 
822  if ($cryptType && !empty($cryptKey)) {
823  if ($cryptType == 2) {
824  $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
825  } elseif ($cryptType == 1) {
826  $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
827  }
828  }
829 
830  return $return;
831  }
832 
833 
834  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
840  public function DDLGetConnectId()
841  {
842  // phpcs:enable
843  return '?';
844  }
845 
846 
847  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
859  public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
860  {
861  // phpcs:enable
862  if (empty($charset)) {
863  $charset = $this->forcecharset;
864  }
865  if (empty($collation)) {
866  $collation = $this->forcecollate;
867  }
868 
869  // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
870  $sql = "CREATE DATABASE ".$this->escape($database);
871  $sql .= " DEFAULT CHARACTER SET ".$this->escape($charset)." DEFAULT COLLATE ".$this->escape($collation);
872 
873  dol_syslog($sql, LOG_DEBUG);
874  $ret = $this->query($sql);
875 
876  return $ret;
877  }
878 
879  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
887  public function DDLListTables($database, $table = '')
888  {
889  // phpcs:enable
890  $listtables = array();
891 
892  $like = '';
893  if ($table) {
894  $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
895 
896  $like = "LIKE '".$this->escape($tmptable)."'";
897  }
898  $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
899 
900  $sql = "SHOW TABLES FROM ".$tmpdatabase." ".$like.";";
901  //print $sql;
902  $result = $this->query($sql);
903  if ($result) {
904  while ($row = $this->fetch_row($result)) {
905  $listtables[] = $row[0];
906  }
907  }
908  return $listtables;
909  }
910 
911  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
919  public function DDLInfoTable($table)
920  {
921  // phpcs:enable
922  $infotables = array();
923 
924  $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
925 
926  $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
927 
928  dol_syslog($sql, LOG_DEBUG);
929  $result = $this->query($sql);
930  if ($result) {
931  while ($row = $this->fetch_row($result)) {
932  $infotables[] = $row;
933  }
934  }
935  return $infotables;
936  }
937 
938  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
951  public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
952  {
953  // phpcs:enable
954  // FIXME: $fulltext_keys parameter is unused
955 
956  // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
957  // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
958  $sql = "create table ".$table."(";
959  $i = 0;
960  foreach ($fields as $field_name => $field_desc) {
961  $sqlfields[$i] = $field_name." ";
962  $sqlfields[$i] .= $field_desc['type'];
963  if (preg_match("/^[^\s]/i", $field_desc['value'])) {
964  $sqlfields[$i] .= "(".$field_desc['value'].")";
965  } elseif (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
966  $sqlfields[$i] .= " ".$field_desc['attribute'];
967  } elseif (preg_match("/^[^\s]/i", $field_desc['default'])) {
968  if (preg_match("/null/i", $field_desc['default'])) {
969  $sqlfields[$i] .= " default ".$field_desc['default'];
970  } else {
971  $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
972  }
973  } elseif (preg_match("/^[^\s]/i", $field_desc['null'])) {
974  $sqlfields[$i] .= " ".$field_desc['null'];
975  } elseif (preg_match("/^[^\s]/i", $field_desc['extra'])) {
976  $sqlfields[$i] .= " ".$field_desc['extra'];
977  }
978  $i++;
979  }
980  if ($primary_key != "") {
981  $pk = "primary key(".$primary_key.")";
982  }
983 
984  if (is_array($unique_keys)) {
985  $i = 0;
986  foreach ($unique_keys as $key => $value) {
987  $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
988  $i++;
989  }
990  }
991  if (is_array($keys)) {
992  $i = 0;
993  foreach ($keys as $key => $value) {
994  $sqlk[$i] = "KEY ".$key." (".$value.")";
995  $i++;
996  }
997  }
998  $sql .= implode(',', $sqlfields);
999  if ($primary_key != "") {
1000  $sql .= ",".$pk;
1001  }
1002  if (is_array($unique_keys)) {
1003  $sql .= ",".implode(',', $sqluq);
1004  }
1005  if (is_array($keys)) {
1006  $sql .= ",".implode(',', $sqlk);
1007  }
1008  $sql .= ") type=".$type;
1009 
1010  dol_syslog($sql, LOG_DEBUG);
1011  if (!$this -> query($sql)) {
1012  return -1;
1013  }
1014  return 1;
1015  }
1016 
1017  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1024  public function DDLDropTable($table)
1025  {
1026  // phpcs:enable
1027  $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
1028 
1029  $sql = "DROP TABLE ".$tmptable;
1030 
1031  if (!$this->query($sql)) {
1032  return -1;
1033  } else {
1034  return 1;
1035  }
1036  }
1037 
1038  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1046  public function DDLDescTable($table, $field = "")
1047  {
1048  // phpcs:enable
1049  $sql = "DESC ".$table." ".$field;
1050 
1051  dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
1052  $this->_results = $this->query($sql);
1053  return $this->_results;
1054  }
1055 
1056  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1066  public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1067  {
1068  // phpcs:enable
1069  // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
1070  // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
1071  $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
1072  $sql .= $field_desc['type'];
1073  if (preg_match("/^[^\s]/i", $field_desc['value'])) {
1074  if (!in_array($field_desc['type'], array('date', 'datetime'))) {
1075  $sql .= "(".$field_desc['value'].")";
1076  }
1077  }
1078  if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1079  $sql .= " ".$field_desc['attribute'];
1080  }
1081  if (preg_match("/^[^\s]/i", $field_desc['null'])) {
1082  $sql .= " ".$field_desc['null'];
1083  }
1084  if (preg_match("/^[^\s]/i", $field_desc['default'])) {
1085  if (preg_match("/null/i", $field_desc['default'])) {
1086  $sql .= " default ".$field_desc['default'];
1087  } else {
1088  $sql .= " default '".$this->escape($field_desc['default'])."'";
1089  }
1090  }
1091  if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
1092  $sql .= " ".$field_desc['extra'];
1093  }
1094  $sql .= " ".$field_position;
1095 
1096  dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1097  if (!$this->query($sql)) {
1098  return -1;
1099  }
1100  return 1;
1101  }
1102 
1103  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1112  public function DDLUpdateField($table, $field_name, $field_desc)
1113  {
1114  // phpcs:enable
1115  $sql = "ALTER TABLE ".$table;
1116  $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
1117  if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
1118  $sql .= "(".$field_desc['value'].")";
1119  }
1120 
1121  dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1122  if (!$this->query($sql)) {
1123  return -1;
1124  }
1125  return 1;
1126  }
1127 
1128  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1136  public function DDLDropField($table, $field_name)
1137  {
1138  // phpcs:enable
1139  $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1140 
1141  $sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`";
1142  if (!$this->query($sql)) {
1143  $this->error = $this->lasterror();
1144  return -1;
1145  }
1146  return 1;
1147  }
1148 
1149 
1150  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1160  public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1161  {
1162  // phpcs:enable
1163  $sql = "INSERT INTO user ";
1164  $sql .= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1165  $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')";
1166  $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1167 
1168  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1169  $resql = $this->query($sql);
1170  if (!$resql) {
1171  return -1;
1172  }
1173 
1174  $sql = "INSERT INTO db ";
1175  $sql .= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1176  $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'";
1177  $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1178 
1179  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1180  $resql = $this->query($sql);
1181  if (!$resql) {
1182  return -1;
1183  }
1184 
1185  $sql = "FLUSH Privileges";
1186 
1187  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1188  $resql = $this->query($sql);
1189  if (!$resql) {
1190  return -1;
1191  }
1192  return 1;
1193  }
1194 
1200  public function getDefaultCharacterSetDatabase()
1201  {
1202  return 'UTF-8';
1203  }
1204 
1210  public function getListOfCharacterSet()
1211  {
1212  $liste = array();
1213  $i = 0;
1214  $liste[$i]['charset'] = 'UTF-8';
1215  $liste[$i]['description'] = 'UTF-8';
1216  return $liste;
1217  }
1218 
1224  public function getDefaultCollationDatabase()
1225  {
1226  return 'UTF-8';
1227  }
1228 
1234  public function getListOfCollation()
1235  {
1236  $liste = array();
1237  $i = 0;
1238  $liste[$i]['charset'] = 'UTF-8';
1239  $liste[$i]['description'] = 'UTF-8';
1240  return $liste;
1241  }
1242 
1248  public function getPathOfDump()
1249  {
1250  // FIXME: not for SQLite
1251  $fullpathofdump = '/pathtomysqldump/mysqldump';
1252 
1253  $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1254  if ($resql) {
1255  $liste = $this->fetch_array($resql);
1256  $basedir = $liste['Value'];
1257  $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1258  }
1259  return $fullpathofdump;
1260  }
1261 
1267  public function getPathOfRestore()
1268  {
1269  // FIXME: not for SQLite
1270  $fullpathofimport = '/pathtomysql/mysql';
1271 
1272  $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1273  if ($resql) {
1274  $liste = $this->fetch_array($resql);
1275  $basedir = $liste['Value'];
1276  $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1277  }
1278  return $fullpathofimport;
1279  }
1280 
1287  public function getServerParametersValues($filter = '')
1288  {
1289  $result = array();
1290  static $pragmas;
1291  if (!isset($pragmas)) {
1292  // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur
1293  // indépendante de la base de données.
1294  // cf. http://www.sqlite.org/pragma.html
1295  $pragmas = array(
1296  'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size',
1297  'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list',
1298  'compile_options', 'data_version', /*'database_list',*/
1299  'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count',
1300  'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check',
1301  'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode',
1302  'max_page_count', 'page_count', 'page_size', 'parser_trace',
1303  'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers',
1304  'reverse_unordered_selects', 'schema_version', 'user_version',
1305  'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit',
1306  'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads',
1307  'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace',
1308  'wal_autocheckpoint',
1309  );
1310  }
1311 
1312  // TODO prendre en compte le filtre
1313  foreach ($pragmas as $var) {
1314  $sql = "PRAGMA $var";
1315  $resql = $this->query($sql);
1316  if ($resql) {
1317  $obj = $this->fetch_row($resql);
1318  //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
1319  $result[$var] = $obj[0];
1320  } else {
1321  // TODO Récupérer le message
1322  $result[$var] = 'FAIL';
1323  }
1324  }
1325  return $result;
1326  }
1327 
1334  public function getServerStatusValues($filter = '')
1335  {
1336  $result = array();
1337  /*
1338  $sql='SHOW STATUS';
1339  if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
1340  $resql=$this->query($sql);
1341  if ($resql)
1342  {
1343  while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1344  }
1345  */
1346 
1347  return $result;
1348  }
1349 
1359  private function addCustomFunction($name, $arg_count = -1)
1360  {
1361  if ($this->db) {
1362  $newname = preg_replace('/_/', '', $name);
1363  $localname = __CLASS__.'::db'.$newname;
1364  $reflectClass = new ReflectionClass(__CLASS__);
1365  $reflectFunction = $reflectClass->getMethod('db'.$newname);
1366  if ($arg_count < 0) {
1367  $arg_count = $reflectFunction->getNumberOfParameters();
1368  }
1369  if (!$this->db->createFunction($name, $localname, $arg_count)) {
1370  $this->error = "unable to create custom function '$name'";
1371  }
1372  }
1373  }
1374 
1375  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1384  private static function calc_daynr($year, $month, $day)
1385  {
1386  // phpcs:enable
1387  $y = $year;
1388  if ($y == 0 && $month == 0) {
1389  return 0;
1390  }
1391  $num = (365 * $y + 31 * ($month - 1) + $day);
1392  if ($month <= 2) {
1393  $y--;
1394  } else {
1395  $num -= floor(($month * 4 + 23) / 10);
1396  }
1397  $temp = floor(($y / 100 + 1) * 3 / 4);
1398  return $num + floor($y / 4) - $temp;
1399  }
1400 
1401  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1409  private static function calc_weekday($daynr, $sunday_first_day_of_week)
1410  {
1411  // phpcs:enable
1412  $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
1413  return $ret;
1414  }
1415 
1416  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1423  private static function calc_days_in_year($year)
1424  {
1425  // phpcs:enable
1426  return (($year & 3) == 0 && ($year % 100 || ($year % 400 == 0 && $year)) ? 366 : 365);
1427  }
1428 
1429  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1440  private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year)
1441  {
1442  // phpcs:enable
1443  $daynr = self::calc_daynr($year, $month, $day);
1444  $first_daynr = self::calc_daynr($year, 1, 1);
1445  $monday_first = ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0;
1446  $week_year = ($week_behaviour & self::WEEK_YEAR) ? 1 : 0;
1447  $first_weekday = ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0;
1448 
1449  $weekday = self::calc_weekday($first_daynr, !$monday_first);
1450  $calc_year = $year;
1451 
1452  if ($month == 1 && $day <= 7 - $weekday) {
1453  if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) {
1454  return 0;
1455  }
1456  $week_year = 1;
1457  $calc_year--;
1458  $first_daynr -= ($days = self::calc_days_in_year($calc_year));
1459  $weekday = ($weekday + 53 * 7 - $days) % 7;
1460  }
1461 
1462  if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
1463  $days = $daynr - ($first_daynr + (7 - $weekday));
1464  } else {
1465  $days = $daynr - ($first_daynr - $weekday);
1466  }
1467 
1468  if ($week_year && $days >= 52 * 7) {
1469  $weekday = ($weekday + self::calc_days_in_year($calc_year)) % 7;
1470  if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) {
1471  $calc_year++;
1472  return 1;
1473  }
1474  }
1475  return floor($days / 7 + 1);
1476  }
1477 }
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
escapeunderscore($stringtoencode)
Escape a string to insert data.
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