dolibarr  19.0.0-dev
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 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 }
Class to manage Dolibarr database access.
lastqueryerror()
Return last query in error.
lasterror()
Return last error label.
lasterrno()
Return last error code.
lastquery()
Return last request executed with query()
Class to manage Dolibarr database access for a SQLite database.
fetch_object($resultset)
Returns the current line (as an object) for the resultset cursor.
escape($stringtoencode)
Escape a string to insert data.
fetch_array($resultset)
Return datas as an array.
error()
Renvoie le texte de l'erreur mysql de l'operation precedente.
fetch_row($resultset)
Return datas as an array.
getPathOfRestore()
Return full path of restore program.
errno()
Renvoie le code erreur generique de l'operation precedente.
const LABEL
Database label.
close()
Close database connexion.
static calc_days_in_year($year)
calc_days_in_year
static calc_daynr($year, $month, $day)
calc_daynr
escapeforlike($stringtoencode)
Escape a string to insert data into a like.
static calc_weekday($daynr, $sunday_first_day_of_week)
calc_weekday
encrypt($fieldorvalue, $withQuotes=1)
Encrypt sensitive data in database Warning: This function includes the escape and add the SQL simple ...
last_insert_id($tab, $fieldid='rowid')
Get last ID after an insert INSERT.
affected_rows($resultset)
Return number of lines for result of a SELECT.
decrypt($value)
Decrypt sensitive data in database.
static calc_week($year, $month, $day, $week_behaviour, &$calc_year)
calc_week
getDriverInfo()
Return version of database client driver.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
addCustomFunction($name, $arg_count=-1)
Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees.
select_db($database)
Select a database.
connect($host, $login, $passwd, $name, $port=0)
Connexion to server.
num_rows($resultset)
Return number of lines for result of a SELECT.
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') && $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
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:120