dolibarr 20.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 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
29require_once DOL_DOCUMENT_ROOT.'/core/db/DoliDB.class.php';
30
34class DoliDBSqlite3 extends DoliDB
35{
37 public $type = 'sqlite3';
39 const LABEL = 'Sqlite3';
41 const VERSIONMIN = '3.0.0';
42
46 private $_results;
47
51 private $queryString;
52
53 const WEEK_MONDAY_FIRST = 1;
54 const WEEK_YEAR = 2;
55 const WEEK_FIRST_WEEKDAY = 4;
56
57
69 public function __construct($type, $host, $user, $pass, $name = '', $port = 0)
70 {
71 global $conf;
72
73 // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
74 if (!empty($conf->db->character_set)) {
75 $this->forcecharset = $conf->db->character_set;
76 }
77 if (!empty($conf->db->dolibarr_main_db_collation)) {
78 $this->forcecollate = $conf->db->dolibarr_main_db_collation;
79 }
80
81 $this->database_user = $user;
82 $this->database_host = $host;
83 $this->database_port = $port;
84
85 $this->transaction_opened = 0;
86
87 //print "Name DB: $host,$user,$pass,$name<br>";
88
89 /*if (! function_exists("sqlite_query"))
90 {
91 $this->connected = false;
92 $this->ok = false;
93 $this->error="Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.";
94 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);
95 return;
96 }*/
97
98 /*if (! $host)
99 {
100 $this->connected = false;
101 $this->ok = false;
102 $this->error=$langs->trans("ErrorWrongHostParameter");
103 dol_syslog(get_class($this)."::DoliDBSqlite3 : Erreur Connect, wrong host parameters",LOG_ERR);
104 return;
105 }*/
106
107 // Essai connection serveur
108 // We do not try to connect to database, only to server. Connect to database is done later in constructor
109 $this->db = $this->connect($host, $user, $pass, $name, $port);
110
111 if ($this->db) {
112 $this->connected = true;
113 $this->ok = true;
114 $this->database_selected = true;
115 $this->database_name = $name;
116
117 $this->addCustomFunction('IF');
118 $this->addCustomFunction('MONTH');
119 $this->addCustomFunction('CURTIME');
120 $this->addCustomFunction('CURDATE');
121 $this->addCustomFunction('WEEK', 1);
122 $this->addCustomFunction('WEEK', 2);
123 $this->addCustomFunction('WEEKDAY');
124 $this->addCustomFunction('date_format');
125 //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
126 } else {
127 // host, login ou password incorrect
128 $this->connected = false;
129 $this->ok = false;
130 $this->database_selected = false;
131 $this->database_name = '';
132 //$this->error=sqlite_connect_error();
133 dol_syslog(get_class($this)."::DoliDBSqlite3 : Error Connect ".$this->error, LOG_ERR);
134 }
135 }
136
137
145 public function convertSQLFromMysql($line, $type = 'ddl')
146 {
147 // Removed empty line if this is a comment line for SVN tagging
148 if (preg_match('/^--\s\$Id/i', $line)) {
149 return '';
150 }
151 // Return line if this is a comment
152 if (preg_match('/^#/i', $line) || preg_match('/^$/i', $line) || preg_match('/^--/i', $line)) {
153 return $line;
154 }
155 if ($line != "") {
156 if ($type == 'auto') {
157 if (preg_match('/ALTER TABLE/i', $line)) {
158 $type = 'dml';
159 } elseif (preg_match('/CREATE TABLE/i', $line)) {
160 $type = 'dml';
161 } elseif (preg_match('/DROP TABLE/i', $line)) {
162 $type = 'dml';
163 }
164 }
165
166 if ($type == 'dml') {
167 $line = preg_replace('/\s/', ' ', $line); // Replace tabulation with space
168
169 // we are inside create table statement so lets process datatypes
170 if (preg_match('/(ISAM|innodb)/i', $line)) { // end of create table sequence
171 $line = preg_replace('/\‍)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb);/i', ');', $line);
172 $line = preg_replace('/\‍)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb);/i', ');', $line);
173 $line = preg_replace('/,$/', '', $line);
174 }
175
176 // Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
177 if (preg_match('/[\s\t\‍(]*(\w*)[\s\t]+int.*auto_increment/i', $line, $reg)) {
178 $newline = preg_replace('/([\s\t\‍(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i', '\\1 \\2 integer PRIMARY KEY AUTOINCREMENT', $line);
179 //$line = "-- ".$line." replaced by --\n".$newline;
180 $line = $newline;
181 }
182
183 // tinyint type conversion
184 $line = str_replace('tinyint', 'smallint', $line);
185
186 // nuke unsigned
187 $line = preg_replace('/(int\w+|smallint)\s+unsigned/i', '\\1', $line);
188
189 // blob -> text
190 $line = preg_replace('/\w*blob/i', 'text', $line);
191
192 // tinytext/mediumtext -> text
193 $line = preg_replace('/tinytext/i', 'text', $line);
194 $line = preg_replace('/mediumtext/i', 'text', $line);
195
196 // change not null datetime field to null valid ones
197 // (to support remapping of "zero time" to null
198 $line = preg_replace('/datetime not null/i', 'datetime', $line);
199 $line = preg_replace('/datetime/i', 'timestamp', $line);
200
201 // double -> numeric
202 $line = preg_replace('/^double/i', 'numeric', $line);
203 $line = preg_replace('/(\s*)double/i', '\\1numeric', $line);
204 // float -> numeric
205 $line = preg_replace('/^float/i', 'numeric', $line);
206 $line = preg_replace('/(\s*)float/i', '\\1numeric', $line);
207
208 // unique index(field1,field2)
209 if (preg_match('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', $line)) {
210 $line = preg_replace('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', 'UNIQUE\‍(\\1\‍)', $line);
211 }
212
213 // We remove end of requests "AFTER fieldxxx"
214 $line = preg_replace('/AFTER [a-z0-9_]+/i', '', $line);
215
216 // We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
217 $line = preg_replace('/ALTER TABLE [a-z0-9_]+ DROP INDEX/i', 'DROP INDEX', $line);
218
219 // Translate order to rename fields
220 if (preg_match('/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i', $line, $reg)) {
221 $line = "-- ".$line." replaced by --\n";
222 $line .= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3];
223 }
224
225 // Translate order to modify field format
226 if (preg_match('/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i', $line, $reg)) {
227 $line = "-- ".$line." replaced by --\n";
228 $newreg3 = $reg[3];
229 $newreg3 = preg_replace('/ DEFAULT NULL/i', '', $newreg3);
230 $newreg3 = preg_replace('/ NOT NULL/i', '', $newreg3);
231 $newreg3 = preg_replace('/ NULL/i', '', $newreg3);
232 $newreg3 = preg_replace('/ DEFAULT 0/i', '', $newreg3);
233 $newreg3 = preg_replace('/ DEFAULT \'[0-9a-zA-Z_@]*\'/i', '', $newreg3);
234 $line .= "ALTER TABLE ".$reg[1]." ALTER COLUMN ".$reg[2]." TYPE ".$newreg3;
235 // TODO Add alter to set default value or null/not null if there is this in $reg[3]
236 }
237
238 // alter table add primary key (field1, field2 ...) -> We create a unique index instead as dynamic creation of primary key is not supported
239 // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity);
240 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\‍((.*)$/i', $line, $reg)) {
241 $line = "-- ".$line." replaced by --\n";
242 $line .= "CREATE UNIQUE INDEX ".$reg[2]." ON ".$reg[1]."(".$reg[3];
243 }
244
245 // Translate order to drop foreign keys
246 // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx;
247 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i', $line, $reg)) {
248 $line = "-- ".$line." replaced by --\n";
249 $line .= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
250 }
251
252 // alter table add [unique] [index] (field1, field2 ...)
253 // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
254 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\‍(([\w,\s]+)\‍)/i', $line, $reg)) {
255 $fieldlist = $reg[4];
256 $idxname = $reg[3];
257 $tablename = $reg[1];
258 $line = "-- ".$line." replaced by --\n";
259 $line .= "CREATE ".(preg_match('/UNIQUE/', $reg[2]) ? 'UNIQUE ' : '')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")";
260 }
261 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)) {
262 // Pour l'instant les contraintes ne sont pas créées
263 dol_syslog(get_class().'::query line emptied');
264 $line = 'SELECT 0;';
265 }
266
267 //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) {
268 //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line);
269 //}
270 }
271
272 // Delete using criteria on other table must not declare twice the deleted table
273 // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
274 if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', $line, $reg)) {
275 if ($reg[1] == $reg[2]) { // If same table, we remove second one
276 $line = preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', 'DELETE FROM \\1 USING \\3', $line);
277 }
278 }
279
280 // Remove () in the tables in FROM if one table
281 $line = preg_replace('/FROM\s*\‍((([a-z_]+)\s+as\s+([a-z_]+)\s*)\‍)/i', 'FROM \\1', $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*)\‍)/i', 'FROM \\1, \\2', $line);
286 //print $line."\n";
287
288 // Remove () in the tables in FROM if two table
289 $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);
290 //print $line."\n";
291
292 //print "type=".$type." newline=".$line."<br>\n";
293 }
294
295 return $line;
296 }
297
298 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
305 public function select_db($database)
306 {
307 // phpcs:enable
308 dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
309 // sqlite_select_db() does not exist
310 //return sqlite_select_db($this->db,$database);
311 return true;
312 }
313
314
326 public function connect($host, $login, $passwd, $name, $port = 0)
327 {
328 global $main_data_dir;
329
330 dol_syslog(get_class($this)."::connect name=".$name, LOG_DEBUG);
331
332 $dir = $main_data_dir;
333 if (empty($dir)) {
334 $dir = DOL_DATA_ROOT;
335 }
336 // With sqlite, port must be in connect parameters
337 //if (! $newport) $newport=3306;
338 $database_name = $dir.'/database_'.$name.'.sdb';
339 try {
340 /*** connect to SQLite database ***/
341 //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb');
342 $this->db = new SQLite3($database_name);
343 //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
344 } catch (Exception $e) {
345 $this->error = self::LABEL.' '.$e->getMessage().' current dir='.$database_name;
346 return false;
347 }
348
349 //print "Resultat fonction connect: ".$this->db;
350 return $this->db;
351 }
352
353
359 public function getVersion()
360 {
361 $tmp = $this->db->version();
362 return $tmp['versionString'];
363 }
364
370 public function getDriverInfo()
371 {
372 return 'sqlite3 php driver';
373 }
374
375
382 public function close()
383 {
384 if ($this->db) {
385 if ($this->transaction_opened > 0) {
386 dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
387 }
388 $this->connected = false;
389 $this->db->close();
390 unset($this->db); // Clean this->db
391 return true;
392 }
393 return false;
394 }
395
406 public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
407 {
408 global $conf, $dolibarr_main_db_readonly;
409
410 $ret = false;
411
412 $query = trim($query);
413
414 $this->error = '';
415
416 // Convert MySQL syntax to SQLite syntax
417 $reg = array();
418 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)) {
419 // Ajout d'une clef étrangère à la table
420 // procédure de replacement de la table pour ajouter la contrainte
421 // Example : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)
422 // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid))
423 $foreignFields = $reg[5];
424 $foreignTable = $reg[4];
425 $localfields = $reg[3];
426 $constraintname = trim($reg[2]);
427 $tablename = trim($reg[1]);
428
429 $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='".$this->escape($tablename)."'");
430
431 // 1- Renommer la table avec un nom temporaire
432 $this->query("ALTER TABLE ".$tablename." RENAME TO tmp_".$tablename);
433
434 // 2- Recréer la table avec la contrainte ajoutée
435
436 // on bricole la requete pour ajouter la contrainte
437 $descTable = substr($descTable, 0, strlen($descTable) - 1);
438 $descTable .= ", CONSTRAINT ".$constraintname." FOREIGN KEY (".$localfields.") REFERENCES ".$foreignTable."(".$foreignFields.")";
439
440 // fermeture de l'instruction
441 $descTable .= ')';
442
443 // Création proprement dite de la table
444 $this->query($descTable);
445
446 // 3- Transférer les données
447 $this->query("INSERT INTO ".$tablename." SELECT * FROM tmp_".$tablename);
448
449 // 4- Supprimer la table temporaire
450 $this->query("DROP TABLE tmp_".$tablename);
451
452 // dummy statement
453 $query = "SELECT 0";
454 } else {
455 $query = $this->convertSQLFromMysql($query, $type);
456 }
457 //print "After convertSQLFromMysql:\n".$query."<br>\n";
458
459 if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK'))) {
460 $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
461 dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
462 }
463 if (empty($query)) {
464 return false; // Return false = error if empty request
465 }
466
467 if (!empty($dolibarr_main_db_readonly)) {
468 if (preg_match('/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
469 $this->lasterror = 'Application in read-only mode';
470 $this->lasterrno = 'APPREADONLY';
471 $this->lastquery = $query;
472 return false;
473 }
474 }
475
476 // Ordre SQL ne necessitant pas de connection a une base (example: CREATE DATABASE)
477 try {
478 //$ret = $this->db->exec($query);
479 $ret = $this->db->query($query); // $ret is a Sqlite3Result
480 if ($ret) {
481 $this->queryString = $query;
482 }
483 } catch (Exception $e) {
484 $this->error = $this->db->lastErrorMsg();
485 }
486
487 if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {
488 // Si requete utilisateur, on la sauvegarde ainsi que son resultset
489 if (!is_object($ret) || $this->error) {
490 $this->lastqueryerror = $query;
491 $this->lasterror = $this->error();
492 $this->lasterrno = $this->errno();
493
494 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR);
495
496 $errormsg = get_class($this)."::query SQL Error message: ".$this->lasterror;
497
498 if (preg_match('/[0-9]/', $this->lasterrno)) {
499 $errormsg .= ' ('.$this->lasterrno.')';
500 }
501
502 if ($conf->global->SYSLOG_LEVEL < LOG_DEBUG) {
503 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
504 }
505 dol_syslog(get_class($this)."::query SQL Error message: ".$errormsg, LOG_ERR);
506 }
507 $this->lastquery = $query;
508 $this->_results = $ret;
509 }
510
511 return $ret;
512 }
513
514 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
521 public function fetch_object($resultset)
522 {
523 // phpcs:enable
524 // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connection
525 if (!is_object($resultset)) {
526 $resultset = $this->_results;
527 }
528 //return $resultset->fetch(PDO::FETCH_OBJ);
529 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
530 if ($ret) {
531 return (object) $ret;
532 }
533 return false;
534 }
535
536
537 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
544 public function fetch_array($resultset)
545 {
546 // phpcs:enable
547 // If resultset not provided, we take the last used by connection
548 if (!is_object($resultset)) {
549 $resultset = $this->_results;
550 }
551 //return $resultset->fetch(PDO::FETCH_ASSOC);
552 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
553 return $ret;
554 }
555
556 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
563 public function fetch_row($resultset)
564 {
565 // phpcs:enable
566 // If resultset not provided, we take the last used by connection
567 if (!is_bool($resultset)) {
568 if (!is_object($resultset)) {
569 $resultset = $this->_results;
570 }
571 return $resultset->fetchArray(SQLITE3_NUM);
572 } else {
573 // si le curseur est un boolean on retourne la valeur 0
574 return false;
575 }
576 }
577
578 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
586 public function num_rows($resultset)
587 {
588 // phpcs:enable
589
590 // If resultset not provided, we take the last used by connection
591 if (!is_object($resultset)) {
592 $resultset = $this->_results;
593 }
594 if (preg_match("/^SELECT/i", $resultset->queryString)) {
595 return $this->db->querySingle("SELECT count(*) FROM (".$resultset->queryString.") q");
596 }
597 return 0;
598 }
599
600 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
608 public function affected_rows($resultset)
609 {
610 // phpcs:enable
611
612 // If resultset not provided, we take the last used by connection
613 if (!is_object($resultset)) {
614 $resultset = $this->_results;
615 }
616 if (preg_match("/^SELECT/i", $this->queryString)) {
617 return $this->num_rows($resultset);
618 }
619 // mysql necessite un link de base pour cette fonction contrairement
620 // a pqsql qui prend un resultset
621 return $this->db->changes();
622 }
623
624
631 public function free($resultset = null)
632 {
633 // If resultset not provided, we take the last used by connection
634 if (!is_object($resultset)) {
635 $resultset = $this->_results;
636 }
637 // Si resultset en est un, on libere la memoire
638 if ($resultset && is_object($resultset)) {
639 $resultset->finalize();
640 }
641 }
642
649 public function escape($stringtoencode)
650 {
651 return Sqlite3::escapeString($stringtoencode);
652 }
653
660 public function escapeforlike($stringtoencode)
661 {
662 return str_replace(array('\\', '_', '%'), array('\\\\', '\_', '\%'), (string) $stringtoencode);
663 }
664
670 public function errno()
671 {
672 if (!$this->connected) {
673 // Si il y a eu echec de connection, $this->db n'est pas valide.
674 return 'DB_ERROR_FAILED_TO_CONNECT';
675 } else {
676 // Constants to convert error code to a generic Dolibarr error code
677 /*$errorcode_map = array(
678 1004 => 'DB_ERROR_CANNOT_CREATE',
679 1005 => 'DB_ERROR_CANNOT_CREATE',
680 1006 => 'DB_ERROR_CANNOT_CREATE',
681 1007 => 'DB_ERROR_ALREADY_EXISTS',
682 1008 => 'DB_ERROR_CANNOT_DROP',
683 1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
684 1044 => 'DB_ERROR_ACCESSDENIED',
685 1046 => 'DB_ERROR_NODBSELECTED',
686 1048 => 'DB_ERROR_CONSTRAINT',
687 'HY000' => 'DB_ERROR_TABLE_ALREADY_EXISTS',
688 1051 => 'DB_ERROR_NOSUCHTABLE',
689 1054 => 'DB_ERROR_NOSUCHFIELD',
690 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
691 1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
692 1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
693 1064 => 'DB_ERROR_SYNTAX',
694 1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
695 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
696 1091 => 'DB_ERROR_NOSUCHFIELD',
697 1100 => 'DB_ERROR_NOT_LOCKED',
698 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
699 1146 => 'DB_ERROR_NOSUCHTABLE',
700 1216 => 'DB_ERROR_NO_PARENT',
701 1217 => 'DB_ERROR_CHILD_EXISTS',
702 1451 => 'DB_ERROR_CHILD_EXISTS'
703 );
704
705 if (isset($errorcode_map[$this->db->errorCode()]))
706 {
707 return $errorcode_map[$this->db->errorCode()];
708 }*/
709 $errno = $this->db->lastErrorCode();
710 if ($errno == 'HY000' || $errno == 0) {
711 if (preg_match('/table.*already exists/i', $this->error)) {
712 return 'DB_ERROR_TABLE_ALREADY_EXISTS';
713 } elseif (preg_match('/index.*already exists/i', $this->error)) {
714 return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS';
715 } elseif (preg_match('/syntax error/i', $this->error)) {
716 return 'DB_ERROR_SYNTAX';
717 }
718 }
719 if ($errno == '23000') {
720 if (preg_match('/column.* not unique/i', $this->error)) {
721 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
722 } elseif (preg_match('/PRIMARY KEY must be unique/i', $this->error)) {
723 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
724 }
725 }
726 if ($errno > 1) {
727 // TODO Voir la liste des messages d'erreur
728 }
729
730 return ($errno ? 'DB_ERROR_'.$errno : '0');
731 }
732 }
733
739 public function error()
740 {
741 if (!$this->connected) {
742 // Si il y a eu echec de connection, $this->db n'est pas valide pour sqlite_error.
743 return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version';
744 } else {
745 return $this->error;
746 }
747 }
748
749 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
757 public function last_insert_id($tab, $fieldid = 'rowid')
758 {
759 // phpcs:enable
760 return $this->db->lastInsertRowId();
761 }
762
771 public function encrypt($fieldorvalue, $withQuotes = 1)
772 {
773 global $conf;
774
775 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
776 $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
777
778 //Encryption key
779 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
780
781 $escapedstringwithquotes = ($withQuotes ? "'" : "").$this->escape($fieldorvalue).($withQuotes ? "'" : "");
782
783 if ($cryptType && !empty($cryptKey)) {
784 if ($cryptType == 2) {
785 $escapedstringwithquotes = "AES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
786 } elseif ($cryptType == 1) {
787 $escapedstringwithquotes = "DES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
788 }
789 }
790
791 return $escapedstringwithquotes;
792 }
793
800 public function decrypt($value)
801 {
802 global $conf;
803
804 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
805 $cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
806
807 //Encryption key
808 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
809
810 $return = $value;
811
812 if ($cryptType && !empty($cryptKey)) {
813 if ($cryptType == 2) {
814 $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
815 } elseif ($cryptType == 1) {
816 $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
817 }
818 }
819
820 return $return;
821 }
822
823
824 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
830 public function DDLGetConnectId()
831 {
832 // phpcs:enable
833 return '?';
834 }
835
836
837 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
849 public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
850 {
851 // phpcs:enable
852 if (empty($charset)) {
853 $charset = $this->forcecharset;
854 }
855 if (empty($collation)) {
856 $collation = $this->forcecollate;
857 }
858
859 // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
860 $sql = "CREATE DATABASE ".$this->escape($database);
861 $sql .= " DEFAULT CHARACTER SET ".$this->escape($charset)." DEFAULT COLLATE ".$this->escape($collation);
862
863 dol_syslog($sql, LOG_DEBUG);
864 $ret = $this->query($sql);
865
866 return $ret;
867 }
868
869 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
877 public function DDLListTables($database, $table = '')
878 {
879 // phpcs:enable
880 $listtables = array();
881
882 $like = '';
883 if ($table) {
884 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
885
886 $like = "LIKE '".$this->escape($tmptable)."'";
887 }
888 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
889
890 $sql = "SHOW TABLES FROM ".$tmpdatabase." ".$like.";";
891 //print $sql;
892 $result = $this->query($sql);
893 if ($result) {
894 while ($row = $this->fetch_row($result)) {
895 $listtables[] = $row[0];
896 }
897 }
898 return $listtables;
899 }
900
901 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
909 public function DDLListTablesFull($database, $table = '')
910 {
911 // phpcs:enable
912 $listtables = array();
913
914 $like = '';
915 if ($table) {
916 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
917
918 $like = "LIKE '".$this->escape($tmptable)."'";
919 }
920 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
921
922 $sql = "SHOW FULL TABLES FROM ".$tmpdatabase." ".$like.";";
923 //print $sql;
924 $result = $this->query($sql);
925 if ($result) {
926 while ($row = $this->fetch_row($result)) {
927 $listtables[] = $row;
928 }
929 }
930 return $listtables;
931 }
932
933 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
941 public function DDLInfoTable($table)
942 {
943 // phpcs:enable
944 $infotables = array();
945
946 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
947
948 $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
949
950 dol_syslog($sql, LOG_DEBUG);
951 $result = $this->query($sql);
952 if ($result) {
953 while ($row = $this->fetch_row($result)) {
954 $infotables[] = $row;
955 }
956 }
957 return $infotables;
958 }
959
960 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
973 public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
974 {
975 // phpcs:enable
976 // @TODO: $fulltext_keys parameter is unused
977
978 $sqlk = array();
979 $sqluq = array();
980
981 // Keys found into the array $fields: type,value,attribute,null,default,extra
982 // ex. : $fields['rowid'] = array(
983 // 'type'=>'int' or 'integer',
984 // 'value'=>'11',
985 // 'null'=>'not null',
986 // 'extra'=> 'auto_increment'
987 // );
988 $sql = "CREATE TABLE ".$this->sanitize($table)."(";
989 $i = 0;
990 $sqlfields = array();
991 foreach ($fields as $field_name => $field_desc) {
992 $sqlfields[$i] = $this->sanitize($field_name)." ";
993 $sqlfields[$i] .= $this->sanitize($field_desc['type']);
994 if (!is_null($field_desc['value']) && $field_desc['value'] !== '') {
995 $sqlfields[$i] .= "(".$this->sanitize($field_desc['value']).")";
996 }
997 if (!is_null($field_desc['attribute']) && $field_desc['attribute'] !== '') {
998 $sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute']);
999 }
1000 if (!is_null($field_desc['default']) && $field_desc['default'] !== '') {
1001 if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
1002 $sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']);
1003 } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
1004 $sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']);
1005 } else {
1006 $sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1007 }
1008 }
1009 if (!is_null($field_desc['null']) && $field_desc['null'] !== '') {
1010 $sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1011 }
1012 if (!is_null($field_desc['extra']) && $field_desc['extra'] !== '') {
1013 $sqlfields[$i] .= " ".$this->sanitize($field_desc['extra'], 0, 0, 1);
1014 }
1015 $i++;
1016 }
1017 if ($primary_key != "") {
1018 $pk = "PRIMARY KEY(".$this->sanitize($primary_key).")";
1019 }
1020
1021 if (is_array($unique_keys)) {
1022 $i = 0;
1023 foreach ($unique_keys as $key => $value) {
1024 $sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')";
1025 $i++;
1026 }
1027 }
1028 if (is_array($keys)) {
1029 $i = 0;
1030 foreach ($keys as $key => $value) {
1031 $sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")";
1032 $i++;
1033 }
1034 }
1035 $sql .= implode(',', $sqlfields);
1036 if ($primary_key != "") {
1037 $sql .= ",".$pk;
1038 }
1039 if ($unique_keys != "") {
1040 $sql .= ",".implode(',', $sqluq);
1041 }
1042 if (is_array($keys)) {
1043 $sql .= ",".implode(',', $sqlk);
1044 }
1045 $sql .= ")";
1046 //$sql .= " engine=".$this->sanitize($type);
1047
1048 if (!$this->query($sql)) {
1049 return -1;
1050 } else {
1051 return 1;
1052 }
1053 }
1054
1055 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1062 public function DDLDropTable($table)
1063 {
1064 // phpcs:enable
1065 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
1066
1067 $sql = "DROP TABLE ".$tmptable;
1068
1069 if (!$this->query($sql)) {
1070 return -1;
1071 } else {
1072 return 1;
1073 }
1074 }
1075
1076 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1084 public function DDLDescTable($table, $field = "")
1085 {
1086 // phpcs:enable
1087 $sql = "DESC ".$table." ".$field;
1088
1089 dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
1090 $this->_results = $this->query($sql);
1091 return $this->_results;
1092 }
1093
1094 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1104 public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1105 {
1106 // phpcs:enable
1107 // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
1108 // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
1109 $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
1110 $sql .= $field_desc['type'];
1111 if (isset($field_desc['value']) && preg_match("/^[^\s]/i", $field_desc['value'])) {
1112 if (!in_array($field_desc['type'], array('date', 'datetime'))) {
1113 $sql .= "(".$field_desc['value'].")";
1114 }
1115 }
1116 if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1117 $sql .= " ".$this->sanitize($field_desc['attribute']);
1118 }
1119 if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
1120 $sql .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1121 }
1122 if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
1123 if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
1124 $sql .= " DEFAULT ".((float) $field_desc['default']);
1125 } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
1126 $sql .= " DEFAULT ".$this->sanitize($field_desc['default']);
1127 } else {
1128 $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1129 }
1130 }
1131 if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
1132 $sql .= " ".$this->sanitize($field_desc['extra'], 0, 0, 1);
1133 }
1134 $sql .= " ".$this->sanitize($field_position, 0, 0, 1);
1135
1136 dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1137 if (!$this->query($sql)) {
1138 return -1;
1139 }
1140 return 1;
1141 }
1142
1143 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1152 public function DDLUpdateField($table, $field_name, $field_desc)
1153 {
1154 // phpcs:enable
1155 $sql = "ALTER TABLE ".$this->sanitize($table);
1156 $sql .= " MODIFY COLUMN ".$this->sanitize($field_name)." ".$this->sanitize($field_desc['type']);
1157 if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
1158 $sql .= "(".$this->sanitize($field_desc['value']).")";
1159 }
1160
1161 dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1162 if (!$this->query($sql)) {
1163 return -1;
1164 }
1165 return 1;
1166 }
1167
1168 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1176 public function DDLDropField($table, $field_name)
1177 {
1178 // phpcs:enable
1179 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1180
1181 $sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`";
1182 if (!$this->query($sql)) {
1183 $this->error = $this->lasterror();
1184 return -1;
1185 }
1186 return 1;
1187 }
1188
1189
1190 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1200 public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1201 {
1202 // phpcs:enable
1203 $sql = "INSERT INTO user ";
1204 $sql .= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1205 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')";
1206 $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1207
1208 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1209 $resql = $this->query($sql);
1210 if (!$resql) {
1211 return -1;
1212 }
1213
1214 $sql = "INSERT INTO db ";
1215 $sql .= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1216 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'";
1217 $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1218
1219 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1220 $resql = $this->query($sql);
1221 if (!$resql) {
1222 return -1;
1223 }
1224
1225 $sql = "FLUSH Privileges";
1226
1227 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1228 $resql = $this->query($sql);
1229 if (!$resql) {
1230 return -1;
1231 }
1232 return 1;
1233 }
1234
1240 public function getDefaultCharacterSetDatabase()
1241 {
1242 return 'UTF-8';
1243 }
1244
1250 public function getListOfCharacterSet()
1251 {
1252 $liste = array();
1253 $i = 0;
1254 $liste[$i]['charset'] = 'UTF-8';
1255 $liste[$i]['description'] = 'UTF-8';
1256 return $liste;
1257 }
1258
1264 public function getDefaultCollationDatabase()
1265 {
1266 return 'UTF-8';
1267 }
1268
1274 public function getListOfCollation()
1275 {
1276 $liste = array();
1277 $i = 0;
1278 $liste[$i]['charset'] = 'UTF-8';
1279 $liste[$i]['description'] = 'UTF-8';
1280 return $liste;
1281 }
1282
1288 public function getPathOfDump()
1289 {
1290 // FIXME: not for SQLite
1291 $fullpathofdump = '/pathtomysqldump/mysqldump';
1292
1293 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1294 if ($resql) {
1295 $liste = $this->fetch_array($resql);
1296 $basedir = $liste['Value'];
1297 $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1298 }
1299 return $fullpathofdump;
1300 }
1301
1307 public function getPathOfRestore()
1308 {
1309 // FIXME: not for SQLite
1310 $fullpathofimport = '/pathtomysql/mysql';
1311
1312 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1313 if ($resql) {
1314 $liste = $this->fetch_array($resql);
1315 $basedir = $liste['Value'];
1316 $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1317 }
1318 return $fullpathofimport;
1319 }
1320
1327 public function getServerParametersValues($filter = '')
1328 {
1329 $result = array();
1330 static $pragmas;
1331 if (!isset($pragmas)) {
1332 // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur
1333 // indépendante de la base de données.
1334 // cf. http://www.sqlite.org/pragma.html
1335 $pragmas = array(
1336 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size',
1337 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list',
1338 'compile_options', 'data_version', /*'database_list',*/
1339 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count',
1340 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check',
1341 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode',
1342 'max_page_count', 'page_count', 'page_size', 'parser_trace',
1343 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers',
1344 'reverse_unordered_selects', 'schema_version', 'user_version',
1345 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit',
1346 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads',
1347 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace',
1348 'wal_autocheckpoint',
1349 );
1350 }
1351
1352 // TODO prendre en compte le filtre
1353 foreach ($pragmas as $var) {
1354 $sql = "PRAGMA $var";
1355 $resql = $this->query($sql);
1356 if ($resql) {
1357 $obj = $this->fetch_row($resql);
1358 //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
1359 $result[$var] = $obj[0];
1360 } else {
1361 // TODO Récupérer le message
1362 $result[$var] = 'FAIL';
1363 }
1364 }
1365 return $result;
1366 }
1367
1374 public function getServerStatusValues($filter = '')
1375 {
1376 $result = array();
1377 /*
1378 $sql='SHOW STATUS';
1379 if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
1380 $resql=$this->query($sql);
1381 if ($resql)
1382 {
1383 while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1384 }
1385 */
1386
1387 return $result;
1388 }
1389
1401 private function addCustomFunction($name, $arg_count = -1)
1402 {
1403 if ($this->db) {
1404 $newname = preg_replace('/_/', '', $name);
1405 $localname = __CLASS__.'::db'.$newname;
1406 $reflectClass = new ReflectionClass(__CLASS__);
1407 $reflectFunction = $reflectClass->getMethod('db'.$newname);
1408 if ($arg_count < 0) {
1409 $arg_count = $reflectFunction->getNumberOfParameters();
1410 }
1411 if (!$this->db->createFunction($name, $localname, $arg_count)) {
1412 $this->error = "unable to create custom function '$name'";
1413 }
1414 }
1415 }
1416
1417 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1426 private static function calc_daynr($year, $month, $day)
1427 {
1428 // phpcs:enable
1429 $y = $year;
1430 if ($y == 0 && $month == 0) {
1431 return 0;
1432 }
1433 $num = (365 * $y + 31 * ($month - 1) + $day);
1434 if ($month <= 2) {
1435 $y--;
1436 } else {
1437 $num -= floor(($month * 4 + 23) / 10);
1438 }
1439 $temp = floor(($y / 100 + 1) * 3 / 4);
1440 return (int) ($num + floor($y / 4) - $temp);
1441 }
1442
1443 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1451 private static function calc_weekday($daynr, $sunday_first_day_of_week)
1452 {
1453 // phpcs:enable
1454 $ret = (int) floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
1455 return $ret;
1456 }
1457
1458 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1465 private static function calc_days_in_year($year)
1466 {
1467 // phpcs:enable
1468 return (($year & 3) == 0 && ($year % 100 || ($year % 400 == 0 && $year)) ? 366 : 365);
1469 }
1470
1471 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1482 private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year)
1483 {
1484 // phpcs:enable
1485 $daynr = self::calc_daynr($year, $month, $day);
1486 $first_daynr = self::calc_daynr($year, 1, 1);
1487 $monday_first = ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0;
1488 $week_year = ($week_behaviour & self::WEEK_YEAR) ? 1 : 0;
1489 $first_weekday = ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0;
1490
1491 $weekday = self::calc_weekday($first_daynr, !$monday_first);
1492 $calc_year = $year;
1493
1494 if ($month == 1 && $day <= 7 - $weekday) {
1495 if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) {
1496 return 0;
1497 }
1498 $week_year = 1;
1499 $calc_year--;
1500 $first_daynr -= ($days = self::calc_days_in_year($calc_year));
1501 $weekday = ($weekday + 53 * 7 - $days) % 7;
1502 }
1503
1504 if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
1505 $days = $daynr - ($first_daynr + (7 - $weekday));
1506 } else {
1507 $days = $daynr - ($first_daynr - $weekday);
1508 }
1509
1510 if ($week_year && $days >= 52 * 7) {
1511 $weekday = ($weekday + self::calc_days_in_year($calc_year)) % 7;
1512 if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) {
1513 $calc_year++;
1514 return 1;
1515 }
1516 }
1517 return (int) floor($days / 7 + 1);
1518 }
1519}
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.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
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 connection.
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.
addCustomFunction($name, $arg_count=-1)
Add a custom function in the database engine (STORED PROCEDURE) Notes:
select_db($database)
Select a database.
connect($host, $login, $passwd, $name, $port=0)
Connection 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.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
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:139
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall TAKEPOS_SHOW_SUBPRICE right right right takeposterminal SELECT e rowid
Definition invoice.php:1991