+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * \file htdocs/core/db/sqlite.class.php
+ * \brief Class file to manage Dolibarr database access for a Sqlite database
+ */
+
+require_once DOL_DOCUMENT_ROOT .'/core/db/DoliDB.class.php';
+
+/**
+ * Class to manage Dolibarr database access for a Sqlite database
+ */
+class DoliDBSqlite3 extends DoliDB
+{
+ //! Database type
+ public $type='sqlite3';
+ //! Database label
+ const LABEL='Sqlite3';
+ //! Version min database
+ const VERSIONMIN='3.0.0';
+ //! Resultset of last query
+ private $_results;
+
+ const WEEK_MONDAY_FIRST=1;
+ const WEEK_YEAR = 2;
+ const WEEK_FIRST_WEEKDAY=4;
+
+
+ /**
+ * Constructor.
+ * This create an opened connexion to a database server and eventually to a database
+ *
+ * @param string $type Type of database (mysql, pgsql...)
+ * @param string $host Address of database server
+ * @param string $user Nom de l'utilisateur autorise
+ * @param string $pass Mot de passe
+ * @param string $name Nom de la database
+ * @param int $port Port of database server
+ */
+ function __construct($type, $host, $user, $pass, $name='', $port=0)
+ {
+ global $conf,$langs;
+
+ // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
+ if (! empty($conf->db->character_set)) $this->forcecharset=$conf->db->character_set;
+ if (! empty($conf->db->dolibarr_main_db_collation)) $this->forcecollate=$conf->db->dolibarr_main_db_collation;
+
+ $this->database_user=$user;
+ $this->database_host=$host;
+ $this->database_port=$port;
+
+ $this->transaction_opened=0;
+
+ //print "Name DB: $host,$user,$pass,$name
";
+
+ /*if (! function_exists("sqlite_query"))
+ {
+ $this->connected = 0;
+ $this->ok = 0;
+ $this->error="Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.";
+ 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);
+ return $this->ok;
+ }*/
+
+ /*if (! $host)
+ {
+ $this->connected = 0;
+ $this->ok = 0;
+ $this->error=$langs->trans("ErrorWrongHostParameter");
+ dol_syslog(get_class($this)."::DoliDBSqlite3 : Erreur Connect, wrong host parameters",LOG_ERR);
+ return $this->ok;
+ }*/
+
+ // Essai connexion serveur
+ // We do not try to connect to database, only to server. Connect to database is done later in constrcutor
+ $this->db = $this->connect($host, $user, $pass, $name, $port);
+
+ if ($this->db)
+ {
+ $this->connected = 1;
+ $this->ok = 1;
+ $this->database_selected = 1;
+ $this->database_name = $name;
+
+ $this->addCustomFunction('IF');
+ $this->addCustomFunction('MONTH');
+ $this->addCustomFunction('CURTIME');
+ $this->addCustomFunction('CURDATE');
+ $this->addCustomFunction('WEEK', 1);
+ $this->addCustomFunction('WEEK', 2);
+ $this->addCustomFunction('WEEKDAY');
+ $this->addCustomFunction('date_format');
+ //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ }
+ else
+ {
+ // host, login ou password incorrect
+ $this->connected = 0;
+ $this->ok = 0;
+ $this->database_selected = 0;
+ $this->database_name = '';
+ //$this->error=sqlite_connect_error();
+ dol_syslog(get_class($this)."::DoliDBSqlite3 : Error Connect ".$this->error,LOG_ERR);
+ }
+
+ return $this->ok;
+ }
+
+
+ /**
+ * Convert a SQL request in Mysql syntax to native syntax
+ *
+ * @param string $line SQL request line to convert
+ * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
+ * @return string SQL request line converted
+ */
+ static function convertSQLFromMysql($line,$type='ddl')
+ {
+ // Removed empty line if this is a comment line for SVN tagging
+ if (preg_match('/^--\s\$Id/i',$line)) {
+ return '';
+ }
+ // Return line if this is a comment
+ if (preg_match('/^#/i',$line) || preg_match('/^$/i',$line) || preg_match('/^--/i',$line))
+ {
+ return $line;
+ }
+ if ($line != "")
+ {
+ if ($type == 'auto')
+ {
+ if (preg_match('/ALTER TABLE/i',$line)) $type='dml';
+ else if (preg_match('/CREATE TABLE/i',$line)) $type='dml';
+ else if (preg_match('/DROP TABLE/i',$line)) $type='dml';
+ }
+
+ if ($type == 'dml')
+ {
+ $line=preg_replace('/\s/',' ',$line); // Replace tabulation with space
+
+ // we are inside create table statement so lets process datatypes
+ if (preg_match('/(ISAM|innodb)/i',$line)) { // end of create table sequence
+ $line=preg_replace('/\)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb);/i',');',$line);
+ $line=preg_replace('/\)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb);/i',');',$line);
+ $line=preg_replace('/,$/','',$line);
+ }
+
+ // Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
+ if (preg_match('/[\s\t\(]*(\w*)[\s\t]+int.*auto_increment/i',$line,$reg)) {
+ $newline=preg_replace('/([\s\t\(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i','\\1 \\2 integer PRIMARY KEY AUTOINCREMENT',$line);
+ //$line = "-- ".$line." replaced by --\n".$newline;
+ $line=$newline;
+ }
+
+ // tinyint type conversion
+ $line=str_replace('tinyint','smallint',$line);
+
+ // nuke unsigned
+ $line=preg_replace('/(int\w+|smallint)\s+unsigned/i','\\1',$line);
+
+ // blob -> text
+ $line=preg_replace('/\w*blob/i','text',$line);
+
+ // tinytext/mediumtext -> text
+ $line=preg_replace('/tinytext/i','text',$line);
+ $line=preg_replace('/mediumtext/i','text',$line);
+
+ // change not null datetime field to null valid ones
+ // (to support remapping of "zero time" to null
+ $line=preg_replace('/datetime not null/i','datetime',$line);
+ $line=preg_replace('/datetime/i','timestamp',$line);
+
+ // double -> numeric
+ $line=preg_replace('/^double/i','numeric',$line);
+ $line=preg_replace('/(\s*)double/i','\\1numeric',$line);
+ // float -> numeric
+ $line=preg_replace('/^float/i','numeric',$line);
+ $line=preg_replace('/(\s*)float/i','\\1numeric',$line);
+
+ // unique index(field1,field2)
+ if (preg_match('/unique index\s*\((\w+\s*,\s*\w+)\)/i',$line))
+ {
+ $line=preg_replace('/unique index\s*\((\w+\s*,\s*\w+)\)/i','UNIQUE\(\\1\)',$line);
+ }
+
+ // We remove end of requests "AFTER fieldxxx"
+ $line=preg_replace('/AFTER [a-z0-9_]+/i','',$line);
+
+ // We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
+ $line=preg_replace('/ALTER TABLE [a-z0-9_]+ DROP INDEX/i','DROP INDEX',$line);
+
+ // Translate order to rename fields
+ if (preg_match('/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i',$line,$reg))
+ {
+ $line = "-- ".$line." replaced by --\n";
+ $line.= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3];
+ }
+
+ // Translate order to modify field format
+ if (preg_match('/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i',$line,$reg))
+ {
+ $line = "-- ".$line." replaced by --\n";
+ $newreg3=$reg[3];
+ $newreg3=preg_replace('/ DEFAULT NULL/i','',$newreg3);
+ $newreg3=preg_replace('/ NOT NULL/i','',$newreg3);
+ $newreg3=preg_replace('/ NULL/i','',$newreg3);
+ $newreg3=preg_replace('/ DEFAULT 0/i','',$newreg3);
+ $newreg3=preg_replace('/ DEFAULT \'[0-9a-zA-Z_@]*\'/i','',$newreg3);
+ $line.= "ALTER TABLE ".$reg[1]." ALTER COLUMN ".$reg[2]." TYPE ".$newreg3;
+ // TODO Add alter to set default value or null/not null if there is this in $reg[3]
+ }
+
+ // alter table add primary key (field1, field2 ...) -> We create a unique index instead as dynamic creation of primary key is not supported
+ // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity);
+ if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\((.*)$/i',$line,$reg))
+ {
+ $line = "-- ".$line." replaced by --\n";
+ $line.= "CREATE UNIQUE INDEX ".$reg[2]." ON ".$reg[1]."(".$reg[3];
+ }
+
+ // Translate order to drop foreign keys
+ // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx;
+ if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i',$line,$reg))
+ {
+ $line = "-- ".$line." replaced by --\n";
+ $line.= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
+ }
+
+ // alter table add [unique] [index] (field1, field2 ...)
+ // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
+ if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\(([\w,\s]+)\)/i',$line,$reg))
+ {
+ $fieldlist=$reg[4];
+ $idxname=$reg[3];
+ $tablename=$reg[1];
+ $line = "-- ".$line." replaced by --\n";
+ $line.= "CREATE ".(preg_match('/UNIQUE/',$reg[2])?'UNIQUE ':'')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")";
+ }
+ 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)) {
+ // Pour l'instant les contraintes ne sont pas créées
+ dol_syslog(get_class().'::query line emptied');
+ $line = 'SELECT 0;';
+
+ }
+
+ //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) {
+ //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line);
+ //}
+ }
+
+ // Delete using criteria on other table must not declare twice the deleted table
+ // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
+ if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i',$line,$reg))
+ {
+ if ($reg[1] == $reg[2]) // If same table, we remove second one
+ {
+ $line=preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i','DELETE FROM \\1 USING \\3', $line);
+ }
+ }
+
+ // Remove () in the tables in FROM if one table
+ $line=preg_replace('/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i','FROM \\1',$line);
+ //print $line."\n";
+
+ // Remove () in the tables in FROM if two table
+ $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);
+ //print $line."\n";
+
+ // Remove () in the tables in FROM if two table
+ $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);
+ //print $line."\n";
+
+ //print "type=".$type." newline=".$line."
\n";
+ }
+
+ return $line;
+ }
+
+ /**
+ * Select a database
+ *
+ * @param string $database Name of database
+ * @return boolean true if OK, false if KO
+ */
+ function select_db($database)
+ {
+ dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
+ return sqlite_select_db($this->db,$database);
+ }
+
+
+ /**
+ * Connexion to server
+ *
+ * @param string $host database server host
+ * @param string $login login
+ * @param string $passwd password
+ * @param string $name name of database (not used for mysql, used for pgsql)
+ * @param string $port Port of database server
+ * @return resource Database access handler
+ * @see close
+ */
+ function connect($host, $login, $passwd, $name, $port=0)
+ {
+ global $conf,$main_data_dir;
+
+ dol_syslog(get_class($this)."::connect name=".$name,LOG_DEBUG);
+
+ $dir=$main_data_dir;
+ if (empty($dir)) $dir=DOL_DATA_ROOT;
+ // With sqlite, port must be in connect parameters
+ //if (! $newport) $newport=3306;
+ $database_name = $dir.'/database_'.$name.'.sdb';
+ try {
+ /*** connect to SQLite database ***/
+ //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb');
+ $this->db = new SQLite3($database_name);
+ //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ }
+ catch(Exception $e)
+ {
+ $this->error= self::LABEL.' '.$e->getMessage().' current dir='.$database_name;
+ return '';
+ }
+
+ //print "Resultat fonction connect: ".$this->db;
+ return $this->db;
+ }
+
+
+ /**
+ * Return version of database server
+ *
+ * @return string Version string
+ */
+ function getVersion()
+ {
+ return $this->db->version()['versionString'];
+ }
+
+ /**
+ * Return version of database client driver
+ *
+ * @return string Version string
+ */
+ function getDriverInfo()
+ {
+ // FIXME: Dummy method
+ // TODO: Implement
+
+ return '';
+ }
+
+
+ /**
+ * Close database connexion
+ *
+ * @return boolean True if disconnect successfull, false otherwise
+ * @see connect
+ */
+ function close()
+ {
+ if ($this->db)
+ {
+ if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR);
+ $this->connected=0;
+ $this->db->close();
+ $this->db=null; // Clean this->db
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Execute a SQL request and return the resultset
+ *
+ * @param string $query SQL query string
+ * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
+ * Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
+ * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
+ * @return resource Resultset of answer
+ */
+ function query($query,$usesavepoint=0,$type='auto')
+ {
+ $errmsg='';
+
+ $ret='';
+ $query = trim($query);
+ $this->error = 0;
+
+ // Convert MySQL syntax to SQLite syntax
+ 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)) {
+ // Ajout d'une clef étrangère à la table
+ // procédure de remplacement de la table pour ajouter la contrainte
+ // Exemple : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)
+ // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid))
+ $foreignFields = $reg[5];
+ $foreignTable = $reg[4];
+ $localfields = $reg[3];
+ $constraintname=trim($reg[2]);
+ $tablename=trim($reg[1]);
+
+ $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='" . $tablename . "'");
+
+ // 1- Renommer la table avec un nom temporaire
+ $this->query('ALTER TABLE ' . $tablename . ' RENAME TO tmp_' . $tablename);
+
+ // 2- Recréer la table avec la contrainte ajoutée
+
+ // on bricole la requete pour ajouter la contrainte
+ $descTable = substr($descTable, 0, strlen($descTable) - 1);
+ $descTable .= ", CONSTRAINT " . $constraintname . " FOREIGN KEY (" . $localfields . ") REFERENCES " .$foreignTable . "(" . $foreignFields . ")";
+
+ // fermeture de l'instruction
+ $descTable .= ')';
+
+ // Création proprement dite de la table
+ $this->query($descTable);
+
+ // 3- Transférer les données
+ $this->query('INSERT INTO ' . $tablename . ' SELECT * FROM tmp_' . $tablename);
+
+ // 4- Supprimer la table temporaire
+ $this->query('DROP TABLE tmp_' . $tablename);
+
+ // dummy statement
+ $query="SELECT 0";
+
+ } else {
+ $query=$this->convertSQLFromMysql($query,$type);
+ }
+ //print "After convertSQLFromMysql:\n".$query."
\n";
+
+ dol_syslog('sql='.$query, LOG_DEBUG);
+
+ // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
+ try {
+ //$ret = $this->db->exec($query);
+ $ret = $this->db->query($query); // $ret is a Sqlite3Result
+ if ($ret) {
+ $ret->queryString = $query;
+ }
+ }
+ catch(Exception $e)
+ {
+ $this->error=$this->db->lastErrorMsg();
+ }
+
+ if (! preg_match("/^COMMIT/i",$query) && ! preg_match("/^ROLLBACK/i",$query))
+ {
+ // Si requete utilisateur, on la sauvegarde ainsi que son resultset
+ if (! is_object($ret) || $this->error)
+ {
+ $this->lastqueryerror = $query;
+ $this->lasterror = $this->error();
+ $this->lasterrno = $this->errno();
+
+ dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR);
+
+ $errormsg = get_class($this)."::query SQL Error message: ".$this->lasterror;
+
+ if (preg_match('/[0-9]/',$this->lasterrno)) {
+ $errormsg .= ' ('.$this->lasterrno.')';
+ }
+
+ dol_syslog($errormsg, LOG_ERR);
+ }
+ $this->lastquery=$query;
+ $this->_results = $ret;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renvoie la ligne courante (comme un objet) pour le curseur resultset
+ *
+ * @param Resultset $resultset Curseur de la requete voulue
+ * @return Object Object result line or false if KO or end of cursor
+ */
+ function fetch_object($resultset)
+ {
+ // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
+ if (! is_object($resultset)) { $resultset=$this->_results; }
+ //return $resultset->fetch(PDO::FETCH_OBJ);
+ $ret = $resultset->fetchArray(SQLITE3_ASSOC);
+ if ($ret) {
+ return (object)$ret;
+ }
+ }
+
+
+ /**
+ * Return datas as an array
+ *
+ * @param Resultset $resultset Resultset of request
+ * @return array Array
+ */
+ function fetch_array($resultset)
+ {
+ // If resultset not provided, we take the last used by connexion
+ if (! is_object($resultset)) { $resultset=$this->_results; }
+ //return $resultset->fetch(PDO::FETCH_ASSOC);
+ $ret = $resultset->fetchArray(SQLITE3_ASSOC);
+ if ($ret) {
+ return (array)$ret;
+ }
+ }
+
+ /**
+ * Return datas as an array
+ *
+ * @param Resultset $resultset Resultset of request
+ * @return array Array
+ */
+ function fetch_row($resultset)
+ {
+ // If resultset not provided, we take the last used by connexion
+ if (! is_bool($resultset))
+ {
+ if (! is_object($resultset)) { $resultset=$this->_results; }
+ return $resultset->fetchArray(SQLITE3_NUM);
+ }
+ else
+ {
+ // si le curseur est un booleen on retourne la valeur 0
+ return 0;
+ }
+ }
+
+ /**
+ * Return number of lines for result of a SELECT
+ *
+ * @param Resultset $resultset Resulset of requests
+ * @return int Nb of lines
+ * @see affected_rows
+ */
+ function num_rows($resultset)
+ {
+ // If resultset not provided, we take the last used by connexion
+ if (! is_object($resultset)) { $resultset=$this->_results; }
+ if (preg_match("/^SELECT/i", $resultset->queryString)) {
+ return $this->db->querySingle("SELECT count(*) FROM (" . $resultset->queryString . ") q");
+ }
+ return 0;
+ }
+
+ /**
+ * Return number of lines for result of a SELECT
+ *
+ * @param Resultset $resultset Resulset of requests
+ * @return int Nb of lines
+ * @see affected_rows
+ */
+ function affected_rows($resultset)
+ {
+ // If resultset not provided, we take the last used by connexion
+ if (! is_object($resultset)) { $resultset=$this->_results; }
+ if (preg_match("/^SELECT/i", $resultset->queryString)) {
+ return $this->num_rows($resultset);
+ }
+ // mysql necessite un link de base pour cette fonction contrairement
+ // a pqsql qui prend un resultset
+ return $this->db->changes();
+ }
+
+
+ /**
+ * Free last resultset used.
+ *
+ * @param resultset $resultset Curseur de la requete voulue
+ * @return void
+ */
+ function free($resultset=0)
+ {
+ // If resultset not provided, we take the last used by connexion
+ if (! is_object($resultset)) { $resultset=$this->_results; }
+ // Si resultset en est un, on libere la memoire
+ if ($resultset && is_object($resultset)) $resultset->finalize();
+ }
+
+ /**
+ * Escape a string to insert data
+ *
+ * @param string $stringtoencode String to escape
+ * @return string String escaped
+ */
+ function escape($stringtoencode)
+ {
+ return Sqlite3::escapeString($stringtoencode);
+ }
+
+ /**
+ * Renvoie le code erreur generique de l'operation precedente.
+ *
+ * @return string Error code (Exemples: DB_ERROR_TABLE_ALREADY_EXISTS, DB_ERROR_RECORD_ALREADY_EXISTS...)
+ */
+ function errno()
+ {
+ if (! $this->connected) {
+ // Si il y a eu echec de connexion, $this->db n'est pas valide.
+ return 'DB_ERROR_FAILED_TO_CONNECT';
+ }
+ else {
+ // Constants to convert error code to a generic Dolibarr error code
+ /*$errorcode_map = array(
+ 1004 => 'DB_ERROR_CANNOT_CREATE',
+ 1005 => 'DB_ERROR_CANNOT_CREATE',
+ 1006 => 'DB_ERROR_CANNOT_CREATE',
+ 1007 => 'DB_ERROR_ALREADY_EXISTS',
+ 1008 => 'DB_ERROR_CANNOT_DROP',
+ 1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
+ 1044 => 'DB_ERROR_ACCESSDENIED',
+ 1046 => 'DB_ERROR_NODBSELECTED',
+ 1048 => 'DB_ERROR_CONSTRAINT',
+ 'HY000' => 'DB_ERROR_TABLE_ALREADY_EXISTS',
+ 1051 => 'DB_ERROR_NOSUCHTABLE',
+ 1054 => 'DB_ERROR_NOSUCHFIELD',
+ 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
+ 1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
+ 1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
+ 1064 => 'DB_ERROR_SYNTAX',
+ 1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
+ 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
+ 1091 => 'DB_ERROR_NOSUCHFIELD',
+ 1100 => 'DB_ERROR_NOT_LOCKED',
+ 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
+ 1146 => 'DB_ERROR_NOSUCHTABLE',
+ 1216 => 'DB_ERROR_NO_PARENT',
+ 1217 => 'DB_ERROR_CHILD_EXISTS',
+ 1451 => 'DB_ERROR_CHILD_EXISTS'
+ );
+
+ if (isset($errorcode_map[$this->db->errorCode()]))
+ {
+ return $errorcode_map[$this->db->errorCode()];
+ }*/
+ $errno=$this->db->lastErrorCode();
+ if ($errno=='HY000' || $errno == 0)
+ {
+ if (preg_match('/table.*already exists/i',$this->error)) return 'DB_ERROR_TABLE_ALREADY_EXISTS';
+ elseif (preg_match('/index.*already exists/i',$this->error)) return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS';
+ elseif (preg_match('/syntax error/i',$this->error)) return 'DB_ERROR_SYNTAX';
+ }
+ if ($errno=='23000')
+ {
+ if (preg_match('/column.* not unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS';
+ elseif (preg_match('/PRIMARY KEY must be unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS';
+ }
+ if ($errno > 1) {
+ // TODO Voir la liste des messages d'erreur
+ }
+
+ return ($errno?'DB_ERROR_'.$errno:'0');
+ }
+ }
+
+ /**
+ * Renvoie le texte de l'erreur mysql de l'operation precedente.
+ *
+ * @return string Error text
+ */
+ function error()
+ {
+ if (! $this->connected) {
+ // Si il y a eu echec de connexion, $this->db n'est pas valide pour sqlite_error.
+ return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version';
+ }
+ else {
+ return $this->error;
+ }
+ }
+
+ /**
+ * Get last ID after an insert INSERT
+ *
+ * @param string $tab Table name concerned by insert. Ne sert pas sous MySql mais requis pour compatibilite avec Postgresql
+ * @param string $fieldid Field name
+ * @return int Id of row
+ */
+ function last_insert_id($tab,$fieldid='rowid')
+ {
+ return $this->db->lastInsertRowId();
+ }
+
+ /**
+ * Encrypt sensitive data in database
+ * Warning: This function includes the escape, so it must use direct value
+ *
+ * @param string $fieldorvalue Field name or value to encrypt
+ * @param int $withQuotes Return string with quotes
+ * @return return XXX(field) or XXX('value') or field or 'value'
+ */
+ function encrypt($fieldorvalue, $withQuotes=0)
+ {
+ global $conf;
+
+ // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
+ $cryptType = ($conf->db->dolibarr_main_db_encryption?$conf->db->dolibarr_main_db_encryption:0);
+
+ //Encryption key
+ $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey)?$conf->db->dolibarr_main_db_cryptkey:'');
+
+ $return = ($withQuotes?"'":"").$this->escape($fieldorvalue).($withQuotes?"'":"");
+
+ if ($cryptType && !empty($cryptKey))
+ {
+ if ($cryptType == 2)
+ {
+ $return = 'AES_ENCRYPT('.$return.',\''.$cryptKey.'\')';
+ }
+ else if ($cryptType == 1)
+ {
+ $return = 'DES_ENCRYPT('.$return.',\''.$cryptKey.'\')';
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * Decrypt sensitive data in database
+ *
+ * @param string $value Value to decrypt
+ * @return string Decrypted value if used
+ */
+ function decrypt($value)
+ {
+ global $conf;
+
+ // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
+ $cryptType = ($conf->db->dolibarr_main_db_encryption?$conf->db->dolibarr_main_db_encryption:0);
+
+ //Encryption key
+ $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey)?$conf->db->dolibarr_main_db_cryptkey:'');
+
+ $return = $value;
+
+ if ($cryptType && !empty($cryptKey))
+ {
+ if ($cryptType == 2)
+ {
+ $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
+ }
+ else if ($cryptType == 1)
+ {
+ $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
+ }
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Return connexion ID
+ *
+ * @return string Id connexion
+ */
+ function DDLGetConnectId()
+ {
+ return '?';
+ }
+
+
+ /**
+ * Create a new database
+ * Do not use function xxx_create_db (xxx=mysql, ...) as they are deprecated
+ * We force to create database with charset this->forcecharset and collate this->forcecollate
+ *
+ * @param string $database Database name to create
+ * @param string $charset Charset used to store data
+ * @param string $collation Charset used to sort data
+ * @param string $owner Username of database owner
+ * @return resource resource defined if OK, null if KO
+ */
+ function DDLCreateDb($database,$charset='',$collation='',$owner='')
+ {
+ if (empty($charset)) $charset=$this->forcecharset;
+ if (empty($collation)) $collation=$this->forcecollate;
+
+ // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
+ $sql = 'CREATE DATABASE '.$database;
+ $sql.= ' DEFAULT CHARACTER SET '.$charset.' DEFAULT COLLATE '.$collation;
+
+ dol_syslog($sql,LOG_DEBUG);
+ $ret=$this->query($sql);
+ if (! $ret)
+ {
+ // We try again for compatibility with Mysql < 4.1.1
+ $sql = 'CREATE DATABASE '.$database;
+ $ret=$this->query($sql);
+ dol_syslog($sql,LOG_DEBUG);
+ }
+ return $ret;
+ }
+
+ /**
+ * List tables into a database
+ *
+ * @param string $database Name of database
+ * @param string $table Name of table filter ('xxx%')
+ * @return array List of tables in an array
+ */
+ function DDLListTables($database, $table='')
+ {
+ $listtables=array();
+
+ $like = '';
+ if ($table) $like = "LIKE '".$table."'";
+ $sql="SHOW TABLES FROM ".$database." ".$like.";";
+ //print $sql;
+ $result = $this->query($sql);
+ while($row = $this->fetch_row($result))
+ {
+ $listtables[] = $row[0];
+ }
+ return $listtables;
+ }
+
+ /**
+ * List information of columns into a table.
+ *
+ * @param string $table Name of table
+ * @return array Tableau des informations des champs de la table
+ * TODO modify for sqlite
+ */
+ function DDLInfoTable($table)
+ {
+ $infotables=array();
+
+ $sql="SHOW FULL COLUMNS FROM ".$table.";";
+
+ dol_syslog($sql,LOG_DEBUG);
+ $result = $this->query($sql);
+ while($row = $this->fetch_row($result))
+ {
+ $infotables[] = $row;
+ }
+ return $infotables;
+ }
+
+ /**
+ * Create a table into database
+ *
+ * @param string $table Nom de la table
+ * @param array $fields Tableau associatif [nom champ][tableau des descriptions]
+ * @param string $primary_key Nom du champ qui sera la clef primaire
+ * @param string $type Type de la table
+ * @param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
+ * @param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
+ * @param string $keys Tableau des champs cles noms => valeur
+ * @return int <0 if KO, >=0 if OK
+ */
+ function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys="",$fulltext_keys="",$keys="")
+ {
+ // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
+ // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
+ $sql = "create table ".$table."(";
+ $i=0;
+ foreach($fields as $field_name => $field_desc)
+ {
+ $sqlfields[$i] = $field_name." ";
+ $sqlfields[$i] .= $field_desc['type'];
+ if( preg_match("/^[^\s]/i",$field_desc['value']))
+ $sqlfields[$i] .= "(".$field_desc['value'].")";
+ else if( preg_match("/^[^\s]/i",$field_desc['attribute']))
+ $sqlfields[$i] .= " ".$field_desc['attribute'];
+ else if( preg_match("/^[^\s]/i",$field_desc['default']))
+ {
+ if(preg_match("/null/i",$field_desc['default']))
+ $sqlfields[$i] .= " default ".$field_desc['default'];
+ else
+ $sqlfields[$i] .= " default '".$field_desc['default']."'";
+ }
+ else if( preg_match("/^[^\s]/i",$field_desc['null']))
+ $sqlfields[$i] .= " ".$field_desc['null'];
+
+ else if( preg_match("/^[^\s]/i",$field_desc['extra']))
+ $sqlfields[$i] .= " ".$field_desc['extra'];
+ $i++;
+ }
+ if($primary_key != "")
+ $pk = "primary key(".$primary_key.")";
+
+ if($unique_keys != "")
+ {
+ $i = 0;
+ foreach($unique_keys as $key => $value)
+ {
+ $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$value."')";
+ $i++;
+ }
+ }
+ if($keys != "")
+ {
+ $i = 0;
+ foreach($keys as $key => $value)
+ {
+ $sqlk[$i] = "KEY ".$key." (".$value.")";
+ $i++;
+ }
+ }
+ $sql .= implode(',',$sqlfields);
+ if($primary_key != "")
+ $sql .= ",".$pk;
+ if($unique_keys != "")
+ $sql .= ",".implode(',',$sqluq);
+ if($keys != "")
+ $sql .= ",".implode(',',$sqlk);
+ $sql .=") type=".$type;
+
+ dol_syslog($sql,LOG_DEBUG);
+ if(! $this -> query($sql))
+ return -1;
+ else
+ return 1;
+ }
+
+ /**
+ * Return a pointer of line with description of a table or field
+ *
+ * @param string $table Name of table
+ * @param string $field Optionnel : Name of field if we want description of field
+ * @return resource Resource
+ */
+ function DDLDescTable($table,$field="")
+ {
+ $sql="DESC ".$table." ".$field;
+
+ dol_syslog(get_class($this)."::DDLDescTable ".$sql,LOG_DEBUG);
+ $this->_results = $this->query($sql);
+ return $this->_results;
+ }
+
+ /**
+ * Create a new field into table
+ *
+ * @param string $table Name of table
+ * @param string $field_name Name of field to add
+ * @param string $field_desc Tableau associatif de description du champ a inserer[nom du parametre][valeur du parametre]
+ * @param string $field_position Optionnel ex.: "after champtruc"
+ * @return int <0 if KO, >0 if OK
+ */
+ function DDLAddField($table,$field_name,$field_desc,$field_position="")
+ {
+ // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
+ // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
+ $sql= "ALTER TABLE ".$table." ADD ".$field_name." ";
+ $sql.= $field_desc['type'];
+ if(preg_match("/^[^\s]/i",$field_desc['value']))
+ if (! in_array($field_desc['type'],array('date','datetime')))
+ {
+ $sql.= "(".$field_desc['value'].")";
+ }
+ if(preg_match("/^[^\s]/i",$field_desc['attribute']))
+ $sql.= " ".$field_desc['attribute'];
+ if(preg_match("/^[^\s]/i",$field_desc['null']))
+ $sql.= " ".$field_desc['null'];
+ if(preg_match("/^[^\s]/i",$field_desc['default']))
+ {
+ if(preg_match("/null/i",$field_desc['default']))
+ $sql.= " default ".$field_desc['default'];
+ else
+ $sql.= " default '".$field_desc['default']."'";
+ }
+ if(preg_match("/^[^\s]/i",$field_desc['extra']))
+ $sql.= " ".$field_desc['extra'];
+ $sql.= " ".$field_position;
+
+ dol_syslog(get_class($this)."::DDLAddField ".$sql,LOG_DEBUG);
+ if(! $this->query($sql))
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ /**
+ * Update format of a field into a table
+ *
+ * @param string $table Name of table
+ * @param string $field_name Name of field to modify
+ * @param string $field_desc Array with description of field format
+ * @return int <0 if KO, >0 if OK
+ */
+ function DDLUpdateField($table,$field_name,$field_desc)
+ {
+ $sql = "ALTER TABLE ".$table;
+ $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
+ if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
+ $sql.="(".$field_desc['value'].")";
+ }
+
+ dol_syslog(get_class($this)."::DDLUpdateField ".$sql,LOG_DEBUG);
+ if (! $this->query($sql))
+ return -1;
+ else
+ return 1;
+ }
+
+ /**
+ * Drop a field from table
+ *
+ * @param string $table Name of table
+ * @param string $field_name Name of field to drop
+ * @return int <0 if KO, >0 if OK
+ */
+ function DDLDropField($table,$field_name)
+ {
+ $sql= "ALTER TABLE ".$table." DROP COLUMN `".$field_name."`";
+ dol_syslog(get_class($this)."::DDLDropField ".$sql,LOG_DEBUG);
+ if (! $this->query($sql))
+ {
+ $this->error=$this->lasterror();
+ return -1;
+ }
+ else return 1;
+ }
+
+
+ /**
+ * Create a user and privileges to connect to database (even if database does not exists yet)
+ *
+ * @param string $dolibarr_main_db_host Ip serveur
+ * @param string $dolibarr_main_db_user Nom user a creer
+ * @param string $dolibarr_main_db_pass Mot de passe user a creer
+ * @param string $dolibarr_main_db_name Database name where user must be granted
+ * @return int <0 if KO, >=0 if OK
+ */
+ function DDLCreateUser($dolibarr_main_db_host,$dolibarr_main_db_user,$dolibarr_main_db_pass,$dolibarr_main_db_name)
+ {
+ $sql = "INSERT INTO user ";
+ $sql.= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
+ $sql.= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')";
+ $sql.= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
+
+ dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
+ $resql=$this->query($sql);
+ if (! $resql)
+ {
+ return -1;
+ }
+
+ $sql = "INSERT INTO db ";
+ $sql.= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
+ $sql.= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'";
+ $sql.= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
+
+ dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
+ $resql=$this->query($sql);
+ if (! $resql)
+ {
+ return -1;
+ }
+
+ $sql="FLUSH Privileges";
+
+ dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
+ $resql=$this->query($sql);
+ if (! $resql)
+ {
+ return -1;
+ }
+
+ return 1;
+ }
+
+ /**
+ * Return charset used to store data in database
+ *
+ * @return string Charset
+ */
+ function getDefaultCharacterSetDatabase()
+ {
+ return 'UTF-8';
+ }
+
+ /**
+ * Return list of available charset that can be used to store data in database
+ *
+ * @return array List of Charset
+ */
+ function getListOfCharacterSet()
+ {
+ $liste = array();
+ $i=0;
+ $liste[$i]['charset'] = 'UTF-8';
+ $liste[$i]['description'] = 'UTF-8';
+ return $liste;
+ }
+
+ /**
+ * Return collation used in database
+ *
+ * @return string Collation value
+ */
+ function getDefaultCollationDatabase()
+ {
+ return 'UTF-8';
+ }
+
+ /**
+ * Return list of available collation that can be used for database
+ *
+ * @return array List of Collation
+ */
+ function getListOfCollation()
+ {
+ $liste = array();
+ $i=0;
+ $liste[$i]['charset'] = 'UTF-8';
+ $liste[$i]['description'] = 'UTF-8';
+ return $liste;
+ }
+
+ /**
+ * Return full path of dump program
+ *
+ * @return string Full path of dump program
+ */
+ function getPathOfDump()
+ {
+ $fullpathofdump='/pathtomysqldump/mysqldump';
+
+ $resql=$this->query('SHOW VARIABLES LIKE \'basedir\'');
+ if ($resql)
+ {
+ $liste=$this->fetch_array($resql);
+ $basedir=$liste['Value'];
+ $fullpathofdump=$basedir.(preg_match('/\/$/',$basedir)?'':'/').'bin/mysqldump';
+ }
+ return $fullpathofdump;
+ }
+
+ /**
+ * Return full path of restore program
+ *
+ * @return string Full path of restore program
+ */
+ function getPathOfRestore()
+ {
+ $fullpathofimport='/pathtomysql/mysql';
+
+ $resql=$this->query('SHOW VARIABLES LIKE \'basedir\'');
+ if ($resql)
+ {
+ $liste=$this->fetch_array($resql);
+ $basedir=$liste['Value'];
+ $fullpathofimport=$basedir.(preg_match('/\/$/',$basedir)?'':'/').'bin/mysql';
+ }
+ return $fullpathofimport;
+ }
+
+ /**
+ * Return value of server parameters
+ *
+ * @param string $filter Filter list on a particular value
+ * @return array Array of key-values (key=>value)
+ */
+ function getServerParametersValues($filter='')
+ {
+ $result=array();
+ static $pragmas;
+ if (! isset($pragmas)) {
+ // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur
+ // indépendante de la base de données.
+ // cf. http://www.sqlite.org/pragma.html
+ $pragmas = array(
+ 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size',
+ 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list',
+ 'compile_options', 'data_version', /*'database_list',*/
+ 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count',
+ 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check',
+ 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode',
+ 'max_page_count', 'page_count', 'page_size', 'parser_trace',
+ 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers',
+ 'reverse_unordered_selects', 'schema_version', 'user_version',
+ 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit',
+ 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads',
+ 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace',
+ 'wal_autocheckpoint',
+ );
+ }
+
+ // TODO prendre en compte le filtre
+ foreach($pragmas as $var) {
+ $sql = "PRAGMA $var";
+ $resql=$this->query($sql);
+ if ($resql)
+ {
+ $obj = $this->fetch_row($resql);
+ //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
+ $result[$var] = $obj[0];
+ }
+ else {
+ // TODO Récupérer le message
+ $result[$var] = 'FAIL';
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Return value of server status
+ *
+ * @param string $filter Filter list on a particular value
+ * @return array Array of key-values (key=>value)
+ */
+ function getServerStatusValues($filter='')
+ {
+ $result=array();
+ /*
+ $sql='SHOW STATUS';
+ if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
+ $resql=$this->query($sql);
+ if ($resql)
+ {
+ while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
+ }
+ */
+
+ return $result;
+ }
+
+ /**
+ * Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees.
+ * Note: le nom de la fonction personnalisee est prefixee par 'db_'. La fonction doit être
+ * statique et publique. Le nombre de parametres est determine automatiquement.
+ * @param string $name Le nom de la fonction a definir dans Sqlite
+ */
+ private function addCustomFunction($name, $arg_count = -1) {
+ if ($this->db) {
+ $localname = __CLASS__ . '::' . 'db_' . $name;
+ $reflectClass = new ReflectionClass(__CLASS__);
+ $reflectFunction = $reflectClass->getMethod('db_' . $name);
+ if ($arg_count < 0) {
+ $arg_count = $reflectFunction->getNumberOfParameters();
+ }
+ if (!$this->db->createFunction($name, $localname , $arg_count)) {
+ $this->error = "unable to create custom function '$name'";
+ }
+ }
+ }
+
+ /**
+ * Cette fonction est l'equivalent de la fonction MONTH de MySql.
+ * @param string $date
+ * @return integer
+ */
+ public static function db_MONTH($date) {
+ return date('n', strtotime($date));
+ }
+
+ /**
+ * calcule du numéro de semaine
+ *
+ * @param string date
+ * @param int mode
+ */
+ public static function db_WEEK($date, $mode = 0) {
+ $arr = date_parse($date);
+ $calc_year = 0;
+ return self::calc_week($arr['year'], $arr['month'], $arr['day'], self::week_mode($mode), $calc_year);
+ }
+
+ public static function db_CURDATE() {
+ return date('Y-m-d');
+ }
+
+ public static function db_CURTIME() {
+ return date('H:i:s');
+ }
+
+ public static function db_WEEKDAY($date) {
+ $arr = date_parse($date);
+ return self::calc_weekday(self::calc_daynr($arr['year'], $arr['month'], $arr['day']), 0);
+
+ }
+
+ /**
+ * Cette fonction est l'equivelent de la fonction date_format de MySQL.
+ * @staticvar string $mysql_replacement Les symboles formatage a remplacer
+ * @param string $date la date dans un format ISO
+ * @param string $format la chaine de formatage
+ * @return string La date formatee.
+ */
+ public static function db_date_format($date, $format) {
+ static $mysql_replacement;
+ if (! isset($mysql_replacement)) {
+ $mysql_replacement = array(
+ '%' => '%',
+ 'a' => 'D',
+ 'b' => 'M',
+ 'c' => 'n',
+ 'D' => 'jS',
+ 'd' => 'd',
+ 'e' => 'j',
+ 'f' => 'u',
+ 'H' => 'H',
+ 'h' => 'h',
+ 'I' => 'h',
+ 'i' => 'i',
+ 'k' => 'H',
+ 'l' => 'g',
+ 'M' => 'F',
+ 'm' => 'm',
+ 'p' => 'A',
+ 'r' => 'h:i:s A',
+ 'S' => 's',
+ 's' => 's',
+ 'T' => 'H:i:s',
+ 'W' => 'l',
+ 'w' => 'w',
+ 'Y' => 'Y',
+ 'y' => 'y',
+ );
+ }
+
+ $fmt = '';
+ $lg = strlen($format);
+ $state = 0;
+ $timestamp = strtotime($date);
+ $yday = date('z', $timestamp);
+ $month = (integer)date("n", $timestamp);
+ $year = (integer)date("Y", $timestamp);
+ $day = (integer)date("d", $timestamp);
+ for($idx = 0; $idx < $lg; ++$idx) {
+ $char = $format[$idx];
+ if ($state == 0) {
+ if ($char == '%') {
+ $state = 1;
+ } else {
+ $fmt .= $char;
+ }
+ }
+ elseif ($state == 1) {
+ if (array_key_exists($char, $mysql_replacement)) {
+ $fmt .= $mysql_replacement[$char];
+ } else {
+ $calc_year = 0;
+ switch ($char) {
+ case 'j': // day of the year 001
+ $char = sprintf("%03d", $yday+1);
+ break;
+ case 'U': // mode 0: semaine 0 = premiere semaine complète qui commence un dimanche
+ $char = sprintf("%02d", self::calc_week($year, $month, $day, 4, $calc_year));
+ break;
+ case 'u': // mode 1: semaine 0 = première semaine de 4 jours. Début le dimanche
+ $char = sprintf("%02d", self::calc_week($year, $month, $day, 1, $calc_year));
+ break;
+ case 'V': // mode 2: semaine 1 = premiere semaine complète qui commence un dimanche
+ $char = sprintf("%02d", self::calc_week($year, $month, $day, 6, $calc_year));
+ break;
+ case 'v': // mode 3: semaine 1 = premiere semaine de 4 jours. Début le lundi
+ $char = sprintf("%02d", self::calc_week($year, $month, $day, 3, $calc_year));
+ break;
+ case 'X':
+ self::calc_week($year, $month, $day, 6, $calc_year);
+ $char = sprintf("%04d", $calc_year);
+ break;
+ case 'x':
+ self::calc_week($year, $month, $day, 3, $calc_year);
+ $char = sprintf("%04d", $calc_year);
+ break;
+ }
+ $fmt .= $char;
+ }
+ $state = 0;
+ }
+ }
+ return date($fmt, strtotime($date));
+ }
+
+ /**
+ * Equivalent de la fonction MySQL IF
+ * @param boolean $test Le resultat du test
+ * @param mixed $true_part Partie a retourner si vrai
+ * @param mixed $false_part Partie a retourner si faux
+ * @return mixed Partie selectionnee en fonction du test
+ */
+ public static function db_IF($test, $true_part, $false_part) {
+ return ( $test ) ? $true_part : $false_part;
+ }
+
+ // Adapté de mytime.c des sources de mariadb
+ // fonction calc_daynr
+ private static function calc_daynr($year, $month, $day) {
+ $y = $year;
+ if ($y == 0 && $month == 0) return 0;
+ $num = (365* $y + 31 * ($month - 1) + $day);
+ if ($month <= 2) {
+ $y--; }
+ else {
+ $num -= floor(($month * 4 + 23) / 10);
+ }
+ $temp = floor(($y / 100 + 1) * 3 / 4);
+ return $num + floor($y / 4) - $temp;
+ }
+
+ private static function calc_weekday($daynr, $sunday_first_day_of_week) {
+ $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
+ return $ret;
+ }
+
+ private static function calc_days_in_year($year)
+ {
+ return (($year & 3) == 0 && ($year%100 || ($year%400 == 0 && $year)) ? 366 : 365);
+ }
+
+ private static function week_mode($mode) {
+ $week_format= ($mode & 7);
+ if (!($week_format & self::WEEK_MONDAY_FIRST)) {
+ $week_format^= self::WEEK_FIRST_WEEKDAY;
+ }
+ return $week_format;
+ }
+
+
+ private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year) {
+ $daynr=self::calc_daynr($year,$month,$day);
+ $first_daynr=self::calc_daynr($year,1,1);
+ $monday_first= ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0;
+ $week_year= ($week_behaviour & self::WEEK_YEAR) ? 1 : 0;
+ $first_weekday= ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0;
+
+ $weekday=self::calc_weekday($first_daynr, !$monday_first);
+ $calc_year=$year;
+
+ if ($month == 1 && $day <= 7-$weekday)
+ {
+ if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)))
+ return 0;
+ $week_year= 1;
+ $calc_year--;
+ $first_daynr-= ($days=self::calc_days_in_year($calc_year));
+ $weekday= ($weekday + 53*7- $days) % 7;
+ }
+
+ if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
+ $days= $daynr - ($first_daynr+ (7-$weekday));
+ }
+ else {
+ $days= $daynr - ($first_daynr - $weekday);
+ }
+
+ if ($week_year && $days >= 52*7)
+ {
+ $weekday= ($weekday + self::calc_days_in_year($calc_year)) % 7;
+ if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0))
+ {
+ $calc_year++;
+ return 1;
+ }
+ }
+ return floor($days/7+1);
+ }
+
+}
+
diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php
index 17b8b8e8def..017d1eb8662 100644
--- a/htdocs/core/modules/DolibarrModules.class.php
+++ b/htdocs/core/modules/DolibarrModules.class.php
@@ -39,166 +39,166 @@ abstract class DolibarrModules
*/
public $db;
- /**
- * @var string Relative path to module style sheet
- * @deprecated
- */
- public $style_sheet = '';
+ /**
+ * @var string Relative path to module style sheet
+ * @deprecated
+ */
+ public $style_sheet = '';
- /**
- * @var array Paths to create when module is activated
- */
- public $dirs = array();
+ /**
+ * @var array Paths to create when module is activated
+ */
+ public $dirs = array();
- /**
- * @var array Module boxes
- */
- public $boxes = array();
+ /**
+ * @var array Module boxes
+ */
+ public $boxes = array();
- /**
- * @var array Module constants
- */
- public $const = array();
+ /**
+ * @var array Module constants
+ */
+ public $const = array();
- /**
- * @var array Module access rights
- */
- public $rights;
+ /**
+ * @var array Module access rights
+ */
+ public $rights;
- /**
- * @var string Module access rights family
- */
- public $rights_class;
+ /**
+ * @var string Module access rights family
+ */
+ public $rights_class;
- /**
- * @var array Module menu entries
- */
- public $menu = array();
+ /**
+ * @var array Module menu entries
+ */
+ public $menu = array();
- /**
- * @var array Module parts
- * array(
- * // Set this to 1 if module has its own trigger directory (/mymodule/core/triggers)
- * 'triggers' => 0,
- * // Set this to 1 if module has its own login method directory (/mymodule/core/login)
+ /**
+ * @var array Module parts
+ * array(
+ * // Set this to 1 if module has its own trigger directory (/mymodule/core/triggers)
+ * 'triggers' => 0,
+ * // Set this to 1 if module has its own login method directory (/mymodule/core/login)
* 'login' => 0,
- * // Set this to 1 if module has its own substitution function file (/mymodule/core/substitutions)
+ * // Set this to 1 if module has its own substitution function file (/mymodule/core/substitutions)
* 'substitutions' => 0,
- * // Set this to 1 if module has its own menus handler directory (/mymodule/core/menus)
+ * // Set this to 1 if module has its own menus handler directory (/mymodule/core/menus)
* 'menus' => 0,
- * // Set this to 1 if module has its own theme directory (/mymodule/theme)
+ * // Set this to 1 if module has its own theme directory (/mymodule/theme)
* 'theme' => 0,
- * // Set this to 1 if module overwrite template dir (/mymodule/core/tpl)
- * 'tpl' => 0,
- * // Set this to 1 if module has its own barcode directory (/mymodule/core/modules/barcode)
+ * // Set this to 1 if module overwrite template dir (/mymodule/core/tpl)
+ * 'tpl' => 0,
+ * // Set this to 1 if module has its own barcode directory (/mymodule/core/modules/barcode)
* 'barcode' => 0,
- * // Set this to 1 if module has its own models directory (/mymodule/core/modules/xxx)
+ * // Set this to 1 if module has its own models directory (/mymodule/core/modules/xxx)
* 'models' => 0,
- * // Set this to relative path of css file if module has its own css file
+ * // Set this to relative path of css file if module has its own css file
* 'css' => '/mymodule/css/mymodule.css.php',
- * // Set this to relative path of js file if module must load a js on all pages
+ * // Set this to relative path of js file if module must load a js on all pages
* 'js' => '/mymodule/js/mymodule.js',
- * // Set here all hooks context managed by module
+ * // Set here all hooks context managed by module
* 'hooks' => array('hookcontext1','hookcontext2'),
- * // Set here all workflow context managed by module
+ * // Set here all workflow context managed by module
* 'workflow' => array(
- * 'WORKFLOW_MODULE1_YOURACTIONTYPE_MODULE2' = >array(
- * 'enabled' => '! empty($conf->module1->enabled) && ! empty($conf->module2->enabled)',
- * 'picto'=>'yourpicto@mymodule'
- * )
- * )
- * )
- */
- public $module_parts = array();
+ * 'WORKFLOW_MODULE1_YOURACTIONTYPE_MODULE2' = >array(
+ * 'enabled' => '! empty($conf->module1->enabled) && ! empty($conf->module2->enabled)',
+ * 'picto'=>'yourpicto@mymodule'
+ * )
+ * )
+ * )
+ */
+ public $module_parts = array();
- /**
- * @var string Module documents ?
- * @deprecated Seems unused anywhere
- */
- public $docs;
+ /**
+ * @var string Module documents ?
+ * @deprecated Seems unused anywhere
+ */
+ public $docs;
- /**
- * @var string ?
- * @deprecated Seems unused anywhere
- */
- public $dbversion = "-";
+ /**
+ * @var string ?
+ * @deprecated Seems unused anywhere
+ */
+ public $dbversion = "-";
- /**
- * @var string Error message
- */
- public $error;
+ /**
+ * @var string Error message
+ */
+ public $error;
- /**
- * @var int Module unique ID
- */
- public $numero;
+ /**
+ * @var int Module unique ID
+ */
+ public $numero;
- /**
- * @var string Module name
- */
- public $name;
+ /**
+ * @var string Module name
+ */
+ public $name;
- /**
- * @var string Module version
- */
- public $version;
+ /**
+ * @var string Module version
+ */
+ public $version;
- /**
- * @var string Module description
- */
- public $description;
+ /**
+ * @var string Module description
+ */
+ public $description;
- /**
- * @var string[] Module language files
- */
- public $langfiles;
+ /**
+ * @var string[] Module language files
+ */
+ public $langfiles;
- /**
- * @var string Module export code
- */
- public $export_code;
+ /**
+ * @var string Module export code
+ */
+ public $export_code;
- /**
- * @var string Module export label
- */
- public $export_label;
+ /**
+ * @var string Module export label
+ */
+ public $export_label;
- /**
- * @var string Module import code
- */
- public $import_code;
+ /**
+ * @var string Module import code
+ */
+ public $import_code;
- /**
- * @var string Module import label
- */
- public $import_label;
+ /**
+ * @var string Module import label
+ */
+ public $import_label;
- /**
- * @var string Module constant name
- */
- public $const_name;
+ /**
+ * @var string Module constant name
+ */
+ public $const_name;
- /**
- * @var bool Module can't be disabled
- */
- public $always_enabled;
+ /**
+ * @var bool Module can't be disabled
+ */
+ public $always_enabled;
- /**
- * @var bool Module is enabled globally (Multicompany support)
- */
- public $core_enabled;
+ /**
+ * @var bool Module is enabled globally (Multicompany support)
+ */
+ public $core_enabled;
- /**
- * Enables a module.
- * Inserts all informations into database
- *
+ /**
+ * Enables a module.
+ * Inserts all informations into database
+ *
* @param array $array_sql SQL requests to be executed when enabling module
- * @param string $options String with options when disabling module:
- * 'noboxes' = Do not insert boxes
- * 'newboxdefonly' = For boxes, insert def of boxes only and not boxes activation
- *
- * @return int 1 if OK, 0 if KO
- */
+ * @param string $options String with options when disabling module:
+ * 'noboxes' = Do not insert boxes
+ * 'newboxdefonly' = For boxes, insert def of boxes only and not boxes activation
+ *
+ * @return int 1 if OK, 0 if KO
+ */
function _init($array_sql, $options='')
{
global $conf;
@@ -232,12 +232,12 @@ abstract class DolibarrModules
// Execute addons requests
$num=count($array_sql);
- for ($i = 0; $i < $num; $i++)
+ for ($i = 0; $i < $num; $i++)
{
if (! $err)
{
$val=$array_sql[$i];
- $sql=$val;
+ $sql=$val;
$ignoreerror=0;
if (is_array($val))
{
@@ -367,12 +367,12 @@ abstract class DolibarrModules
// If module name translation using it's unique id does not exists, we take use its name to find translation
if (is_array($this->langfiles))
{
- foreach($this->langfiles as $val)
- {
- if ($val) $langs->load($val);
- }
+ foreach($this->langfiles as $val)
+ {
+ if ($val) $langs->load($val);
+ }
}
- return $langs->trans($this->name);
+ return $langs->trans($this->name);
}
}
@@ -389,20 +389,20 @@ abstract class DolibarrModules
if ($langs->trans("Module".$this->numero."Desc") != ("Module".$this->numero."Desc"))
{
- // If module description translation exists
+ // If module description translation exists
return $langs->trans("Module".$this->numero."Desc");
}
else
- {
+ {
// If module description translation using it's unique id does not exists, we take use its name to find translation
if (is_array($this->langfiles))
{
- foreach($this->langfiles as $val)
- {
- if ($val) $langs->load($val);
- }
+ foreach($this->langfiles as $val)
+ {
+ if ($val) $langs->load($val);
+ }
}
- return $langs->trans($this->description);
+ return $langs->trans($this->description);
}
}
@@ -429,7 +429,7 @@ abstract class DolibarrModules
else $ret=$langs->trans("VersionUnknown");
if (preg_match('/_deprecated/',$this->version)) $ret.=' ('.$langs->trans("Deprecated").')';
- return $ret;
+ return $ret;
}
@@ -582,9 +582,9 @@ abstract class DolibarrModules
global $conf;
$error=0;
- $dirfound=0;
+ $dirfound=0;
- if (empty($reldir)) return 1;
+ if (empty($reldir)) return 1;
include_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
@@ -599,10 +599,10 @@ abstract class DolibarrModules
$handle=@opendir($dir); // Dir may not exists
if (is_resource($handle))
{
- $dirfound++;
+ $dirfound++;
- // Run llx_mytable.sql files
- while (($file = readdir($handle))!==false)
+ // Run llx_mytable.sql files
+ while (($file = readdir($handle))!==false)
{
if (preg_match('/\.sql$/i',$file) && ! preg_match('/\.key\.sql$/i',$file) && substr($file,0,4) == 'llx_' && substr($file,0,4) != 'data')
{
@@ -613,8 +613,8 @@ abstract class DolibarrModules
rewinddir($handle);
- // Run llx_mytable.key.sql files (Must be done after llx_mytable.sql)
- while (($file = readdir($handle))!==false)
+ // Run llx_mytable.key.sql files (Must be done after llx_mytable.sql)
+ while (($file = readdir($handle))!==false)
{
if (preg_match('/\.key\.sql$/i',$file) && substr($file,0,4) == 'llx_' && substr($file,0,4) != 'data')
{
@@ -626,7 +626,7 @@ abstract class DolibarrModules
rewinddir($handle);
// Run data_xxx.sql files (Must be done after llx_mytable.key.sql)
- while (($file = readdir($handle))!==false)
+ while (($file = readdir($handle))!==false)
{
if (preg_match('/\.sql$/i',$file) && ! preg_match('/\.key\.sql$/i',$file) && substr($file,0,4) == 'data')
{
@@ -638,7 +638,7 @@ abstract class DolibarrModules
rewinddir($handle);
// Run update_xxx.sql files
- while (($file = readdir($handle))!==false)
+ while (($file = readdir($handle))!==false)
{
if (preg_match('/\.sql$/i',$file) && ! preg_match('/\.key\.sql$/i',$file) && substr($file,0,6) == 'update')
{
@@ -671,9 +671,9 @@ abstract class DolibarrModules
*/
function insert_boxes($option='')
{
- require_once DOL_DOCUMENT_ROOT . '/core/class/infobox.class.php';
+ require_once DOL_DOCUMENT_ROOT . '/core/class/infobox.class.php';
- global $conf;
+ global $conf;
$err=0;
@@ -681,8 +681,8 @@ abstract class DolibarrModules
{
$pos_name = InfoBox::getListOfPagesForBoxes();
- foreach ($this->boxes as $key => $value)
- {
+ foreach ($this->boxes as $key => $value)
+ {
$file = isset($this->boxes[$key]['file'])?$this->boxes[$key]['file']:'';
$note = isset($this->boxes[$key]['note'])?$this->boxes[$key]['note']:'';
$enabledbydefaulton = isset($this->boxes[$key]['enabledbydefaulton'])?$this->boxes[$key]['enabledbydefaulton']:'Home';
@@ -724,15 +724,15 @@ abstract class DolibarrModules
foreach ($pos_name as $key2 => $val2)
{
- //print 'key2='.$key2.'-val2='.$val2."
\n";
+ //print 'key2='.$key2.'-val2='.$val2."
\n";
if ($enabledbydefaulton && $val2 != $enabledbydefaulton) continue; // Not enabled by default onto this page.
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."boxes (box_id,position,box_order,fk_user,entity)";
- $sql.= " VALUES (".$lastid.", ".$key2.", '0', 0, ".$conf->entity.")";
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."boxes (box_id,position,box_order,fk_user,entity)";
+ $sql.= " VALUES (".$lastid.", ".$key2.", '0', 0, ".$conf->entity.")";
- dol_syslog(get_class($this)."::insert_boxes onto page ".$key2."=".$val2."", LOG_DEBUG);
- $resql=$this->db->query($sql);
- if (! $resql) $err++;
+ dol_syslog(get_class($this)."::insert_boxes onto page ".$key2."=".$val2."", LOG_DEBUG);
+ $resql=$this->db->query($sql);
+ if (! $resql) $err++;
}
}
@@ -741,7 +741,7 @@ abstract class DolibarrModules
$this->db->commit();
}
else
- {
+ {
$this->error=$this->db->lasterror();
$this->db->rollback();
}
@@ -781,11 +781,22 @@ abstract class DolibarrModules
if (empty($file)) $file = isset($this->boxes[$key][1])?$this->boxes[$key][1]:''; // For backward compatibility
- $sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes";
- $sql.= " USING ".MAIN_DB_PREFIX."boxes, ".MAIN_DB_PREFIX."boxes_def";
- $sql.= " WHERE ".MAIN_DB_PREFIX."boxes.box_id = ".MAIN_DB_PREFIX."boxes_def.rowid";
- $sql.= " AND ".MAIN_DB_PREFIX."boxes_def.file = '".$this->db->escape($file)."'";
- $sql.= " AND ".MAIN_DB_PREFIX."boxes.entity = ".$conf->entity;
+ if ($this->db->type == 'sqlite3') {
+ // sqlite doesn't support "USING" syntax.
+ // TODO: remove this dependency.
+ $sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes ";
+ $sql .= "WHERE ".MAIN_DB_PREFIX."boxes.box_id IN (";
+ $sql .= "SELECT ".MAIN_DB_PREFIX."boxes_def.rowid ";
+ $sql .= "FROM ".MAIN_DB_PREFIX."boxes_def ";
+ $sql .= "WHERE ".MAIN_DB_PREFIX."boxes_def.file = '".$this->db->escape($file)."') ";
+ $sql .= "AND ".MAIN_DB_PREFIX."boxes.entity = ".$conf->entity;
+ } else {
+ $sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes";
+ $sql.= " USING ".MAIN_DB_PREFIX."boxes, ".MAIN_DB_PREFIX."boxes_def";
+ $sql.= " WHERE ".MAIN_DB_PREFIX."boxes.box_id = ".MAIN_DB_PREFIX."boxes_def.rowid";
+ $sql.= " AND ".MAIN_DB_PREFIX."boxes_def.file = '".$this->db->escape($file)."'";
+ $sql.= " AND ".MAIN_DB_PREFIX."boxes.entity = ".$conf->entity;
+ }
dol_syslog(get_class($this)."::delete_boxes", LOG_DEBUG);
$resql=$this->db->query($sql);
@@ -1012,7 +1023,7 @@ abstract class DolibarrModules
if ($resql)
{
$obj=$this->db->fetch_object($resql);
- if (! empty($obj->value) && ! empty($this->rights))
+ if ($obj !== null && ! empty($obj->value) && ! empty($this->rights))
{
// Si module actif
foreach ($this->rights as $key => $value)
@@ -1027,54 +1038,54 @@ abstract class DolibarrModules
if (empty($r_type)) $r_type='w';
- // Search if perm already present
- $sql = "SELECT count(*) as nb FROM ".MAIN_DB_PREFIX."rights_def";
- $sql.= " WHERE id = ".$r_id." AND entity = ".$entity;
- $resqlselect=$this->db->query($sql);
+ // Search if perm already present
+ $sql = "SELECT count(*) as nb FROM ".MAIN_DB_PREFIX."rights_def";
+ $sql.= " WHERE id = ".$r_id." AND entity = ".$entity;
+ $resqlselect=$this->db->query($sql);
- $obj = $this->db->fetch_object($resqlselect);
+ $obj = $this->db->fetch_object($resqlselect);
if ($obj->nb == 0)
{
- if (dol_strlen($r_perms) )
- {
- if (dol_strlen($r_subperms) )
- {
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def";
- $sql.= " (id, entity, libelle, module, type, bydefault, perms, subperms)";
- $sql.= " VALUES ";
- $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."','".$r_subperms."')";
- }
- else
- {
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def";
- $sql.= " (id, entity, libelle, module, type, bydefault, perms)";
- $sql.= " VALUES ";
- $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."')";
- }
- }
- else
- {
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def ";
- $sql .= " (id, entity, libelle, module, type, bydefault)";
- $sql .= " VALUES ";
- $sql .= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.")";
- }
+ if (dol_strlen($r_perms) )
+ {
+ if (dol_strlen($r_subperms) )
+ {
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def";
+ $sql.= " (id, entity, libelle, module, type, bydefault, perms, subperms)";
+ $sql.= " VALUES ";
+ $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."','".$r_subperms."')";
+ }
+ else
+ {
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def";
+ $sql.= " (id, entity, libelle, module, type, bydefault, perms)";
+ $sql.= " VALUES ";
+ $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."')";
+ }
+ }
+ else
+ {
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def ";
+ $sql .= " (id, entity, libelle, module, type, bydefault)";
+ $sql .= " VALUES ";
+ $sql .= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.")";
+ }
- $resqlinsert=$this->db->query($sql,1);
+ $resqlinsert=$this->db->query($sql,1);
- if (! $resqlinsert)
- {
- if ($this->db->errno() != "DB_ERROR_RECORD_ALREADY_EXISTS")
- {
- $this->error=$this->db->lasterror();
- $err++;
- break;
- }
- else dol_syslog(get_class($this)."::insert_permissions record already exists", LOG_INFO);
+ if (! $resqlinsert)
+ {
+ if ($this->db->errno() != "DB_ERROR_RECORD_ALREADY_EXISTS")
+ {
+ $this->error=$this->db->lasterror();
+ $err++;
+ break;
+ }
+ else dol_syslog(get_class($this)."::insert_permissions record already exists", LOG_INFO);
- }
+ }
- $this->db->free($resqlinsert);
+ $this->db->free($resqlinsert);
}
$this->db->free($resqlselect);
@@ -1082,9 +1093,9 @@ abstract class DolibarrModules
// If we want to init permissions on admin users
if ($reinitadminperms)
{
- if (! class_exists('User')) {
- require DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
- }
+ if (! class_exists('User')) {
+ require DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
+ }
$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."user WHERE admin = 1";
dol_syslog(get_class($this)."::insert_permissions Search all admin users", LOG_DEBUG);
$resqlseladmin=$this->db->query($sql,1);
@@ -1099,7 +1110,7 @@ abstract class DolibarrModules
$tmpuser=new User($this->db);
$tmpuser->fetch($obj2->rowid);
if (!empty($tmpuser->id)) {
- $tmpuser->addrights($r_id);
+ $tmpuser->addrights($r_id);
}
$i++;
}
@@ -1158,7 +1169,7 @@ abstract class DolibarrModules
*/
function insert_menus()
{
- global $user;
+ global $user;
require_once DOL_DOCUMENT_ROOT . '/core/class/menubase.class.php';
@@ -1415,68 +1426,68 @@ abstract class DolibarrModules
*/
function insert_module_parts()
{
- global $conf;
+ global $conf;
- $error=0;
- $entity=$conf->entity;
+ $error=0;
+ $entity=$conf->entity;
- if (is_array($this->module_parts) && ! empty($this->module_parts))
- {
- foreach($this->module_parts as $key => $value)
- {
+ if (is_array($this->module_parts) && ! empty($this->module_parts))
+ {
+ foreach($this->module_parts as $key => $value)
+ {
if (is_array($value) && count($value) == 0) continue; // Discard empty arrays
- $newvalue = $value;
+ $newvalue = $value;
- // Serialize array parameters
- if (is_array($value))
- {
- // Can defined other parameters
- if (is_array($value['data']) && ! empty($value['data']))
- {
- $newvalue = json_encode($value['data']);
- if (isset($value['entity'])) $entity = $value['entity'];
- }
- else
- {
- $newvalue = json_encode($value);
- }
- }
+ // Serialize array parameters
+ if (is_array($value))
+ {
+ // Can defined other parameters
+ if (is_array($value['data']) && ! empty($value['data']))
+ {
+ $newvalue = json_encode($value['data']);
+ if (isset($value['entity'])) $entity = $value['entity'];
+ }
+ else
+ {
+ $newvalue = json_encode($value);
+ }
+ }
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."const (";
- $sql.= "name";
- $sql.= ", type";
- $sql.= ", value";
- $sql.= ", note";
- $sql.= ", visible";
- $sql.= ", entity";
- $sql.= ")";
- $sql.= " VALUES (";
- $sql.= $this->db->encrypt($this->const_name."_".strtoupper($key), 1);
- $sql.= ", 'chaine'";
- $sql.= ", ".$this->db->encrypt($newvalue, 1);
- $sql.= ", null";
- $sql.= ", '0'";
- $sql.= ", ".$entity;
- $sql.= ")";
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."const (";
+ $sql.= "name";
+ $sql.= ", type";
+ $sql.= ", value";
+ $sql.= ", note";
+ $sql.= ", visible";
+ $sql.= ", entity";
+ $sql.= ")";
+ $sql.= " VALUES (";
+ $sql.= $this->db->encrypt($this->const_name."_".strtoupper($key), 1);
+ $sql.= ", 'chaine'";
+ $sql.= ", ".$this->db->encrypt($newvalue, 1);
+ $sql.= ", null";
+ $sql.= ", '0'";
+ $sql.= ", ".$entity;
+ $sql.= ")";
- dol_syslog(get_class($this)."::insert_const_".$key."", LOG_DEBUG);
- $resql=$this->db->query($sql,1);
- if (! $resql)
- {
- if ($this->db->lasterrno() != 'DB_ERROR_RECORD_ALREADY_EXISTS')
- {
- $error++;
- $this->error=$this->db->lasterror();
- }
- else
- {
- dol_syslog(get_class($this)."::insert_const_".$key." Record already exists.", LOG_WARNING);
- }
- }
- }
- }
- return $error;
+ dol_syslog(get_class($this)."::insert_const_".$key."", LOG_DEBUG);
+ $resql=$this->db->query($sql,1);
+ if (! $resql)
+ {
+ if ($this->db->lasterrno() != 'DB_ERROR_RECORD_ALREADY_EXISTS')
+ {
+ $error++;
+ $this->error=$this->db->lasterror();
+ }
+ else
+ {
+ dol_syslog(get_class($this)."::insert_const_".$key." Record already exists.", LOG_WARNING);
+ }
+ }
+ }
+ }
+ return $error;
}
/**
@@ -1486,31 +1497,31 @@ abstract class DolibarrModules
*/
function delete_module_parts()
{
- global $conf;
+ global $conf;
- $err=0;
- $entity=$conf->entity;
+ $err=0;
+ $entity=$conf->entity;
- if (is_array($this->module_parts) && ! empty($this->module_parts))
- {
- foreach($this->module_parts as $key => $value)
- {
- // If entity is defined
- if (is_array($value) && isset($value['entity'])) $entity = $value['entity'];
+ if (is_array($this->module_parts) && ! empty($this->module_parts))
+ {
+ foreach($this->module_parts as $key => $value)
+ {
+ // If entity is defined
+ if (is_array($value) && isset($value['entity'])) $entity = $value['entity'];
- $sql = "DELETE FROM ".MAIN_DB_PREFIX."const";
- $sql.= " WHERE ".$this->db->decrypt('name')." LIKE '".$this->const_name."_".strtoupper($key)."'";
- $sql.= " AND entity = ".$entity;
+ $sql = "DELETE FROM ".MAIN_DB_PREFIX."const";
+ $sql.= " WHERE ".$this->db->decrypt('name')." LIKE '".$this->const_name."_".strtoupper($key)."'";
+ $sql.= " AND entity = ".$entity;
- dol_syslog(get_class($this)."::delete_const_".$key."", LOG_DEBUG);
- if (! $this->db->query($sql))
- {
- $this->error=$this->db->lasterror();
- $err++;
- }
- }
- }
- return $err;
+ dol_syslog(get_class($this)."::delete_const_".$key."", LOG_DEBUG);
+ if (! $this->db->query($sql))
+ {
+ $this->error=$this->db->lasterror();
+ $err++;
+ }
+ }
+ }
+ return $err;
}
}
diff --git a/htdocs/install/etape1.php b/htdocs/install/etape1.php
index 4f31a728a1d..f7b81e1da66 100644
--- a/htdocs/install/etape1.php
+++ b/htdocs/install/etape1.php
@@ -86,12 +86,15 @@ if (! is_writable($conffile))
// Check parameters
+$is_sqlite = false;
if (empty($db_type))
{
print ''.$langs->trans("ErrorFieldRequired",$langs->transnoentities("DatabaseType")).'
';
$error++;
+} else {
+ $is_sqlite = ($db_type === 'sqlite' || $db_type === 'sqlite3' );
}
-if (empty($db_host))
+if (empty($db_host) && ! $is_sqlite)
{
print ''.$langs->trans("ErrorFieldRequired",$langs->transnoentities("Server")).'
';
$error++;
@@ -101,7 +104,7 @@ if (empty($db_name))
print ''.$langs->trans("ErrorFieldRequired",$langs->transnoentities("DatabaseName")).'
';
$error++;
}
-if (empty($db_user))
+if (empty($db_user) && ! $is_sqlite)
{
print ''.$langs->trans("ErrorFieldRequired",$langs->transnoentities("Login")).'
';
$error++;
diff --git a/htdocs/install/etape2.php b/htdocs/install/etape2.php
index 1f6c5244d84..612c3c64148 100644
--- a/htdocs/install/etape2.php
+++ b/htdocs/install/etape2.php
@@ -51,6 +51,8 @@ if ($dolibarr_main_db_type == "mysql") $choix=1;
if ($dolibarr_main_db_type == "mysqli") $choix=1;
if ($dolibarr_main_db_type == "pgsql") $choix=2;
if ($dolibarr_main_db_type == "mssql") $choix=3;
+if ($dolibarr_main_db_type == "sqlite3") $choix=4;
+
//if (empty($choix)) dol_print_error('','Database type '.$dolibarr_main_db_type.' not supported into etape2.php page');
// Now we load forced value from install.forced.php file.
@@ -411,6 +413,7 @@ if ($action == "set")
if ($choix==1) $dir = "mysql/functions/";
elseif ($choix==2) $dir = "pgsql/functions/";
elseif ($choix==3) $dir = "mssql/functions/";
+ elseif ($choix==4) { $dir = "sqlite3/functions/"; }
// Creation donnees
$file = "functions.sql";
diff --git a/htdocs/install/fileconf.php b/htdocs/install/fileconf.php
index 2c6a5730100..ec3e208374b 100644
--- a/htdocs/install/fileconf.php
+++ b/htdocs/install/fileconf.php
@@ -320,7 +320,7 @@ if (! empty($force_install_message))
if ($type=='mysqli') { $testfunction='mysqli_connect'; $testclass=''; }
if ($type=='pgsql') { $testfunction='pg_connect'; $testclass=''; }
if ($type=='mssql') { $testfunction='mssql_connect'; $testclass=''; }
- if ($type=='sqlite') { $testfunction=''; $testclass='PDO'; }
+ if ($type=='sqlite3') { $testfunction=''; $testclass='SQLite3'; }
$option.='';
@@ -479,7 +480,7 @@ if (! empty($force_install_message))
jQuery(document).ready(function() {
jQuery("#db_type").change(function() {
- if (jQuery("#db_type").val()=='sqlite') { jQuery(".hidesqlite").hide(); }
+ if (jQuery("#db_type").val()=='sqlite' || jQuery("#db_type").val()=='sqlite3') { jQuery(".hidesqlite").hide(); }
else { jQuery(".hidesqlite").show(); }
});
diff --git a/htdocs/install/sqlite3/functions/functions.sql b/htdocs/install/sqlite3/functions/functions.sql
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/htdocs/install/sqlite3/index.html b/htdocs/install/sqlite3/index.html
new file mode 100644
index 00000000000..e69de29bb2d