diff --git a/ChangeLog b/ChangeLog index 60efdf1093b..6580a4e5dda 100644 --- a/ChangeLog +++ b/ChangeLog @@ -104,7 +104,7 @@ FIX: #yogosha21416 For users: ---------- -NEW: Compatibility with PHP 8.2 +NEW: Compatibility with PHP 8.2 (warning must be disabled) NEW: Module Workstation (used to enhance the module BOM and Manufacturing Order) is now stable NEW: Add a CLI tool to regenerate all documents NEW: Add a confirmation popup when deleting extrafields diff --git a/htdocs/core/db/mysqli.class.php b/htdocs/core/db/mysqli.class.php index be8ed977963..f1515eacabf 100644 --- a/htdocs/core/db/mysqli.class.php +++ b/htdocs/core/db/mysqli.class.php @@ -825,55 +825,66 @@ class DoliDBMysqli extends DoliDB public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null) { // phpcs:enable - // FIXME: $fulltext_keys parameter is unused + // @TODO: $fulltext_keys parameter is unused + + if (empty($type)) { + $type = 'InnoDB'; + } $pk = ''; $sqluq = $sqlk = array(); - // 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."("; + // Keys found into the array $fields: type,value,attribute,null,default,extra + // ex. : $fields['rowid'] = array( + // 'type'=>'int' or 'integer', + // 'value'=>'11', + // 'null'=>'not null', + // 'extra'=> 'auto_increment' + // ); + $sql = "CREATE TABLE ".$this->sanitize($table)."("; $i = 0; $sqlfields = array(); 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'].")"; + $sqlfields[$i] = $this->sanitize($field_name)." "; + $sqlfields[$i] .= $this->sanitize($field_desc['type']); + if (!is_null($field_desc['value']) && $field_desc['value'] !== '') { + $sqlfields[$i] .= "(".$this->sanitize($field_desc['value']).")"; } - if (preg_match("/^[^\s]/i", $field_desc['attribute'])) { - $sqlfields[$i] .= " ".$field_desc['attribute']; + if (!is_null($field_desc['attribute']) && $field_desc['attribute'] !== '') { + $sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute']); } - if (preg_match("/^[^\s]/i", $field_desc['default'])) { - if ((preg_match("/null/i", $field_desc['default'])) || (preg_match("/CURRENT_TIMESTAMP/i", $field_desc['default']))) { - $sqlfields[$i] .= " default ".$field_desc['default']; + if (!is_null($field_desc['default']) && $field_desc['default'] !== '') { + if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']); + } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') { + $sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']); } else { - $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'"; + $sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'"; } } - if (preg_match("/^[^\s]/i", $field_desc['null'])) { - $sqlfields[$i] .= " ".$field_desc['null']; + if (!is_null($field_desc['null']) && $field_desc['null'] !== '') { + $sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1); } - if (preg_match("/^[^\s]/i", $field_desc['extra'])) { - $sqlfields[$i] .= " ".$field_desc['extra']; + if (!is_null($field_desc['extra']) && $field_desc['extra'] !== '') { + $sqlfields[$i] .= " ".$this->sanitize($field_desc['extra'], 0, 0, 1); } $i++; } if ($primary_key != "") { - $pk = "primary key(".$primary_key.")"; + $pk = "PRIMARY KEY(".$this->sanitize($primary_key).")"; } if (is_array($unique_keys)) { $i = 0; foreach ($unique_keys as $key => $value) { - $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')"; + $sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')"; $i++; } } if (is_array($keys)) { $i = 0; foreach ($keys as $key => $value) { - $sqlk[$i] = "KEY ".$key." (".$value.")"; + $sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")"; $i++; } } @@ -887,7 +898,8 @@ class DoliDBMysqli extends DoliDB if (is_array($keys)) { $sql .= ",".implode(',', $sqlk); } - $sql .= ") engine=".$type; + $sql .= ")"; + $sql .= " engine=".$this->sanitize($type); if (!$this->query($sql)) { return -1; @@ -908,7 +920,7 @@ class DoliDBMysqli extends DoliDB // phpcs:enable $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table); - $sql = "DROP TABLE ".$tmptable; + $sql = "DROP TABLE ".$this->sanitize($tmptable); if (!$this->query($sql)) { return -1; @@ -928,7 +940,7 @@ class DoliDBMysqli extends DoliDB public function DDLDescTable($table, $field = "") { // phpcs:enable - $sql = "DESC ".$table." ".$field; + $sql = "DESC ".$this->sanitize($table)." ".$this->sanitize($field); dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG); $this->_results = $this->query($sql); @@ -950,30 +962,32 @@ class DoliDBMysqli extends DoliDB // phpcs:enable // 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')) && $field_desc['value']) { - $sql .= "(".$field_desc['value'].")"; + $sql = "ALTER TABLE ".$this->sanitize($table)." ADD ".$this->sanitize($field_name)." "; + $sql .= $this->sanitize($field_desc['type']); + if (isset($field_desc['value']) && preg_match("/^[^\s]/i", $field_desc['value'])) { + if (!in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'date', 'datetime')) && $field_desc['value']) { + $sql .= "(".$this->sanitize($field_desc['value']).")"; } } if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) { - $sql .= " ".$field_desc['attribute']; + $sql .= " ".$this->sanitize($field_desc['attribute']); } if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) { $sql .= " ".$field_desc['null']; } if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) { - if (preg_match("/null/i", $field_desc['default'])) { - $sql .= " default ".$field_desc['default']; + if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sql .= " DEFAULT ".((float) $field_desc['default']); + } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') { + $sql .= " DEFAULT ".$this->sanitize($field_desc['default']); } else { - $sql .= " default '".$this->escape($field_desc['default'])."'"; + $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; } } if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) { - $sql .= " ".$field_desc['extra']; + $sql .= " ".$this->escape($field_desc['extra'], 0, 0, 1); } - $sql .= " ".$field_position; + $sql .= " ".$this->escape($field_position, 0, 0, 1); dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG); if ($this->query($sql)) { @@ -994,18 +1008,18 @@ class DoliDBMysqli extends DoliDB public function DDLUpdateField($table, $field_name, $field_desc) { // phpcs:enable - $sql = "ALTER TABLE ".$table; - $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type']; + $sql = "ALTER TABLE ".$this->sanitize($table); + $sql .= " MODIFY COLUMN ".$this->sanitize($field_name)." ".$this->sanitize($field_desc['type']); if (in_array($field_desc['type'], array('double', 'tinyint', 'int', 'varchar')) && $field_desc['value']) { - $sql .= "(".$field_desc['value'].")"; + $sql .= "(".$this->sanitize($field_desc['value']).")"; } if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') { // We will try to change format of column to NOT NULL. To be sure the ALTER works, we try to update fields that are NULL if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') { - $sqlbis = "UPDATE ".$table." SET ".$field_name." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$field_name." IS NULL"; + $sqlbis = "UPDATE ".$this->sanitize($table)." SET ".$this->sanitize($field_name)." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$this->sanitize($field_name)." IS NULL"; $this->query($sqlbis); - } elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') { - $sqlbis = "UPDATE ".$table." SET ".$field_name." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$field_name." IS NULL"; + } elseif (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sqlbis = "UPDATE ".$this->sanitize($table)." SET ".$this->sanitize($field_name)." = ".((float) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$this->sanitize($field_name)." IS NULL"; $this->query($sqlbis); } @@ -1013,8 +1027,8 @@ class DoliDBMysqli extends DoliDB } if (isset($field_desc['default']) && $field_desc['default'] != '') { - if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') { - $sql .= " DEFAULT ".$this->escape($field_desc['default']); + if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sql .= " DEFAULT ".((float) $field_desc['default']); } elseif ($field_desc['type'] != 'text') { $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; // Default not supported on text fields } @@ -1041,7 +1055,7 @@ class DoliDBMysqli extends DoliDB // phpcs:enable $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name); - $sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`"; + $sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`"; if ($this->query($sql)) { return 1; } diff --git a/htdocs/core/db/pgsql.class.php b/htdocs/core/db/pgsql.class.php index 14ba90b5bd9..90d8b6bb4c1 100644 --- a/htdocs/core/db/pgsql.class.php +++ b/htdocs/core/db/pgsql.class.php @@ -1068,51 +1068,63 @@ class DoliDBPgsql extends DoliDB public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null) { // phpcs:enable - // FIXME: $fulltext_keys parameter is unused + // @TODO: $fulltext_keys parameter is unused $sqlfields = array(); $sqlk = array(); $sqluq = array(); - // 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."("; + // Keys found into the array $fields: type,value,attribute,null,default,extra + // ex. : $fields['rowid'] = array( + // 'type'=>'int' or 'integer', + // 'value'=>'11', + // 'null'=>'not null', + // 'extra'=> 'auto_increment' + // ); + $sql = "CREATE TABLE ".$this->sanitize($table)."("; $i = 0; + $sqlfields = array(); 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'].")"; - } elseif (preg_match("/^[^\s]/i", $field_desc['attribute'])) { - $sqlfields[$i] .= " ".$field_desc['attribute']; - } elseif (preg_match("/^[^\s]/i", $field_desc['default'])) { - if (preg_match("/null/i", $field_desc['default'])) { - $sqlfields[$i] .= " default ".$field_desc['default']; + $sqlfields[$i] = $this->sanitize($field_name)." "; + $sqlfields[$i] .= $this->sanitize($field_desc['type']); + if (!is_null($field_desc['value']) && $field_desc['value'] !== '') { + $sqlfields[$i] .= "(".$this->sanitize($field_desc['value']).")"; + } + if (!is_null($field_desc['attribute']) && $field_desc['attribute'] !== '') { + $sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute']); + } + if (!is_null($field_desc['default']) && $field_desc['default'] !== '') { + if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']); + } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') { + $sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']); } else { - $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'"; + $sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'"; } - } elseif (preg_match("/^[^\s]/i", $field_desc['null'])) { - $sqlfields[$i] .= " ".$field_desc['null']; - } elseif (preg_match("/^[^\s]/i", $field_desc['extra'])) { - $sqlfields[$i] .= " ".$field_desc['extra']; + } + if (!is_null($field_desc['null']) && $field_desc['null'] !== '') { + $sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1); + } + if (!is_null($field_desc['extra']) && $field_desc['extra'] !== '') { + $sqlfields[$i] .= " ".$this->sanitize($field_desc['extra']); } $i++; } if ($primary_key != "") { - $pk = "primary key(".$primary_key.")"; + $pk = "PRIMARY KEY(".$this->sanitize($primary_key).")"; } if (is_array($unique_keys)) { $i = 0; foreach ($unique_keys as $key => $value) { - $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')"; + $sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')"; $i++; } } if (is_array($keys)) { $i = 0; foreach ($keys as $key => $value) { - $sqlk[$i] = "KEY ".$key." (".$value.")"; + $sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")"; $i++; } } @@ -1120,15 +1132,15 @@ class DoliDBPgsql extends DoliDB if ($primary_key != "") { $sql .= ",".$pk; } - if (is_array($unique_keys)) { + if ($unique_keys != "") { $sql .= ",".implode(',', $sqluq); } if (is_array($keys)) { $sql .= ",".implode(',', $sqlk); } - $sql .= ") type=".$type; + $sql .= ")"; + //$sql .= " engine=".$this->sanitize($type); - dol_syslog($sql, LOG_DEBUG); if (!$this->query($sql)) { return -1; } else { @@ -1148,7 +1160,7 @@ class DoliDBPgsql extends DoliDB // phpcs:enable $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table); - $sql = "DROP TABLE ".$tmptable; + $sql = "DROP TABLE ".$this->sanitize($tmptable); if (!$this->query($sql)) { return -1; @@ -1157,31 +1169,6 @@ class DoliDBPgsql extends DoliDB } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Create a user to connect to database - * - * @param string $dolibarr_main_db_host Ip server - * @param string $dolibarr_main_db_user Name of user to create - * @param string $dolibarr_main_db_pass Password of user to create - * @param string $dolibarr_main_db_name Database name where user must be granted - * @return int Return integer <0 if KO, >=0 if OK - */ - public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name) - { - // phpcs:enable - // Note: using ' on user does not works with pgsql - $sql = "CREATE USER ".$this->escape($dolibarr_main_db_user)." with password '".$this->escape($dolibarr_main_db_pass)."'"; - - dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log - $resql = $this->query($sql); - if (!$resql) { - return -1; - } - - return 1; - } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Return a pointer of line with description of a table or field @@ -1219,30 +1206,32 @@ class DoliDBPgsql extends DoliDB // phpcs:enable // 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('smallint', 'int', 'date', 'datetime')) && $field_desc['value']) { - $sql .= "(".$field_desc['value'].")"; + $sql = "ALTER TABLE ".$this->sanitize($table)." ADD ".$this->sanitize($field_name)." "; + $sql .= $this->sanitize($field_desc['type']); + if (isset($field_desc['value']) && preg_match("/^[^\s]/i", $field_desc['value'])) { + if (!in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'date', 'datetime')) && $field_desc['value']) { + $sql .= "(".$this->sanitize($field_desc['value']).")"; } } - if (preg_match("/^[^\s]/i", $field_desc['attribute'])) { - $sql .= " ".$field_desc['attribute']; + if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) { + $sql .= " ".$this->sanitize($field_desc['attribute']); } - if (preg_match("/^[^\s]/i", $field_desc['null'])) { + if (isset($field_desc['null']) && 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']; + if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) { + if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sql .= " DEFAULT ".((float) $field_desc['default']); + } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') { + $sql .= " DEFAULT ".$this->sanitize($field_desc['default']); } else { - $sql .= " default '".$this->escape($field_desc['default'])."'"; + $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; } } - if (preg_match("/^[^\s]/i", $field_desc['extra'])) { - $sql .= " ".$field_desc['extra']; + if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) { + $sql .= " ".$this->escape($field_desc['extra'], 0, 0, 1); } - $sql .= " ".$field_position; + $sql .= " ".$this->escape($field_position, 0, 0, 1); dol_syslog($sql, LOG_DEBUG); if (!$this -> query($sql)) { @@ -1263,30 +1252,30 @@ class DoliDBPgsql extends DoliDB public function DDLUpdateField($table, $field_name, $field_desc) { // phpcs:enable - $sql = "ALTER TABLE ".$table; - $sql .= " ALTER COLUMN ".$this->escape($field_name)." TYPE ".$field_desc['type']; + $sql = "ALTER TABLE ".$this->sanitize($table); + $sql .= " ALTER COLUMN ".$this->sanitize($field_name)." TYPE ".$this->sanitize($field_desc['type']); if (preg_match("/^[^\s]/i", $field_desc['value'])) { if (!in_array($field_desc['type'], array('smallint', 'int', 'date', 'datetime')) && $field_desc['value']) { - $sql .= "(".$field_desc['value'].")"; + $sql .= "(".$this->sanitize($field_desc['value']).")"; } } if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') { // We will try to change format of column to NOT NULL. To be sure the ALTER works, we try to update fields that are NULL if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') { - $sqlbis = "UPDATE ".$table." SET ".$this->escape($field_name)." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$this->escape($field_name)." IS NULL"; + $sqlbis = "UPDATE ".$this->sanitize($table)." SET ".$this->escape($field_name)." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$this->escape($field_name)." IS NULL"; $this->query($sqlbis); - } elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') { - $sqlbis = "UPDATE ".$table." SET ".$this->escape($field_name)." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$this->escape($field_name)." IS NULL"; + } elseif (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sqlbis = "UPDATE ".$this->sanitize($table)." SET ".$this->escape($field_name)." = ".((float) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$this->escape($field_name)." IS NULL"; $this->query($sqlbis); } } if (isset($field_desc['default']) && $field_desc['default'] != '') { - if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') { - $sql .= " DEFAULT ".$this->escape($field_desc['default']); - } elseif ($field_desc['type'] != 'text') { - $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; // Default not supported on text fields + if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sql .= ", ALTER COLUMN ".$this->sanitize($field_name)." SET DEFAULT ".((float) $field_desc['default']); + } elseif ($field_desc['type'] != 'text') { // Default not supported on text fields ? + $sql .= ", ALTER COLUMN ".$this->sanitize($field_name)." SET DEFAULT '".$this->escape($field_desc['default'])."'"; } } @@ -1310,7 +1299,7 @@ class DoliDBPgsql extends DoliDB // phpcs:enable $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name); - $sql = "ALTER TABLE ".$table." DROP COLUMN ".$tmp_field_name; + $sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN ".$this->sanitize($tmp_field_name); if (!$this->query($sql)) { $this->error = $this->lasterror(); return -1; @@ -1318,6 +1307,31 @@ class DoliDBPgsql extends DoliDB return 1; } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Create a user to connect to database + * + * @param string $dolibarr_main_db_host Ip server + * @param string $dolibarr_main_db_user Name of user to create + * @param string $dolibarr_main_db_pass Password of user to create + * @param string $dolibarr_main_db_name Database name where user must be granted + * @return int Return integer <0 if KO, >=0 if OK + */ + public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name) + { + // phpcs:enable + // Note: using ' on user does not works with pgsql + $sql = "CREATE USER ".$this->sanitize($dolibarr_main_db_user)." with password '".$this->escape($dolibarr_main_db_pass)."'"; + + dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log + $resql = $this->query($sql); + if (!$resql) { + return -1; + } + + return 1; + } + /** * Return charset used to store data in database * diff --git a/htdocs/core/db/sqlite3.class.php b/htdocs/core/db/sqlite3.class.php index b53bdeb8adc..70ac8d69fed 100644 --- a/htdocs/core/db/sqlite3.class.php +++ b/htdocs/core/db/sqlite3.class.php @@ -970,51 +970,63 @@ class DoliDBSqlite3 extends DoliDB public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null) { // phpcs:enable - // FIXME: $fulltext_keys parameter is unused + // @TODO: $fulltext_keys parameter is unused $sqlfields = array(); $sqlk = array(); $sqluq = array(); - // 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."("; + // Keys found into the array $fields: type,value,attribute,null,default,extra + // ex. : $fields['rowid'] = array( + // 'type'=>'int' or 'integer', + // 'value'=>'11', + // 'null'=>'not null', + // 'extra'=> 'auto_increment' + // ); + $sql = "CREATE TABLE ".$this->sanitize($table)."("; $i = 0; + $sqlfields = array(); 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'].")"; - } elseif (preg_match("/^[^\s]/i", $field_desc['attribute'])) { - $sqlfields[$i] .= " ".$field_desc['attribute']; - } elseif (preg_match("/^[^\s]/i", $field_desc['default'])) { - if (preg_match("/null/i", $field_desc['default'])) { - $sqlfields[$i] .= " default ".$field_desc['default']; + $sqlfields[$i] = $this->sanitize($field_name)." "; + $sqlfields[$i] .= $this->sanitize($field_desc['type']); + if (!is_null($field_desc['value']) && $field_desc['value'] !== '') { + $sqlfields[$i] .= "(".$this->sanitize($field_desc['value']).")"; + } + if (!is_null($field_desc['attribute']) && $field_desc['attribute'] !== '') { + $sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute']); + } + if (!is_null($field_desc['default']) && $field_desc['default'] !== '') { + if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']); + } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') { + $sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']); } else { - $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'"; + $sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'"; } - } elseif (preg_match("/^[^\s]/i", $field_desc['null'])) { - $sqlfields[$i] .= " ".$field_desc['null']; - } elseif (preg_match("/^[^\s]/i", $field_desc['extra'])) { - $sqlfields[$i] .= " ".$field_desc['extra']; + } + if (!is_null($field_desc['null']) && $field_desc['null'] !== '') { + $sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1); + } + if (!is_null($field_desc['extra']) && $field_desc['extra'] !== '') { + $sqlfields[$i] .= " ".$this->sanitize($field_desc['extra']); } $i++; } if ($primary_key != "") { - $pk = "primary key(".$primary_key.")"; + $pk = "PRIMARY KEY(".$this->sanitize($primary_key).")"; } if (is_array($unique_keys)) { $i = 0; foreach ($unique_keys as $key => $value) { - $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')"; + $sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')"; $i++; } } if (is_array($keys)) { $i = 0; foreach ($keys as $key => $value) { - $sqlk[$i] = "KEY ".$key." (".$value.")"; + $sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")"; $i++; } } @@ -1022,19 +1034,20 @@ class DoliDBSqlite3 extends DoliDB if ($primary_key != "") { $sql .= ",".$pk; } - if (is_array($unique_keys)) { + if ($unique_keys != "") { $sql .= ",".implode(',', $sqluq); } if (is_array($keys)) { $sql .= ",".implode(',', $sqlk); } - $sql .= ") type=".$type; + $sql .= ")"; + //$sql .= " engine=".$this->sanitize($type); - dol_syslog($sql, LOG_DEBUG); - if (!$this -> query($sql)) { + if (!$this->query($sql)) { return -1; + } else { + return 1; } - return 1; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps @@ -1105,16 +1118,18 @@ class DoliDBSqlite3 extends DoliDB $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']; + if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) { + $sql .= " DEFAULT ".((float) $field_desc['default']); + } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') { + $sql .= " DEFAULT ".$this->sanitize($field_desc['default']); } else { - $sql .= " default '".$this->escape($field_desc['default'])."'"; + $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; } } - if (preg_match("/^[^\s]/i", $field_desc['extra'])) { - $sql .= " ".$field_desc['extra']; + if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) { + $sql .= " ".$this->escape($field_desc['extra'], 0, 0, 1); } - $sql .= " ".$field_position; + $sql .= " ".$this->escape($field_position, 0, 0, 1); dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG); if (!$this->query($sql)) { @@ -1135,10 +1150,10 @@ class DoliDBSqlite3 extends DoliDB public function DDLUpdateField($table, $field_name, $field_desc) { // phpcs:enable - $sql = "ALTER TABLE ".$table; - $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type']; + $sql = "ALTER TABLE ".$this->sanitize($table); + $sql .= " MODIFY COLUMN ".$this->sanitize(($field_name)." ".$this->sanitize($field_desc['type']); if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') { - $sql .= "(".$field_desc['value'].")"; + $sql .= "(".$this->sanitize($field_desc['value']).")"; } dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG); @@ -1161,7 +1176,7 @@ class DoliDBSqlite3 extends DoliDB // phpcs:enable $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name); - $sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`"; + $sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`"; if (!$this->query($sql)) { $this->error = $this->lasterror(); return -1; diff --git a/htdocs/core/lib/modulebuilder.lib.php b/htdocs/core/lib/modulebuilder.lib.php index 95e4711b396..1ae0d52d93a 100644 --- a/htdocs/core/lib/modulebuilder.lib.php +++ b/htdocs/core/lib/modulebuilder.lib.php @@ -1288,12 +1288,12 @@ function createNewDictionnary($modulename, $file, $namedic, $dictionnaires = nul } $columns = array( - 'rowid' => array('type' => 'integer(11)'), - 'code' => array('type' => 'varchar(255) NOT NULL'), - 'label' => array('type' => 'varchar(255) NOT NULL'), - 'position' => array('type' => 'integer(11) NULL'), - 'use_default' => array('type' => 'varchar(255) DEFAULT 1'), - 'active' => array('type' => 'integer') + 'rowid' => array('type' => 'integer', 'value' => 11, 'extra' => 'AUTO_INCREMENT PRIMARY KEY'), + 'code' => array('type' => 'varchar', 'value' => 255, 'null'=>'NOT NULL'), + 'label' => array('type' => 'varchar', 'value' => 255, 'null'=>'NOT NULL'), + 'position' => array('type' => 'integer', 'value' => 11, 'null'=>'NULL'), + 'use_default' => array('type' => 'varchar', 'value' => 11, 'default'=>'1'), + 'active' => array('type' => 'integer', 'value' => 3) ); @@ -1309,13 +1309,13 @@ function createNewDictionnary($modulename, $file, $namedic, $dictionnaires = nul } } // check if tablename exist in Database and create it if not - $query = "SHOW TABLES LIKE '" . MAIN_DB_PREFIX.strtolower($namedic) . "'"; + $query = "SHOW TABLES LIKE '" . $db->sanitize(MAIN_DB_PREFIX.strtolower($namedic)) . "'"; $checkTable = $db->query($query); if ($checkTable && $db->num_rows($checkTable) > 0) { setEventMessages($langs->trans("ErrorTableExist", $namedic), null, 'errors'); return; } else { - $_results = $db->DDLCreateTable(MAIN_DB_PREFIX.strtolower($namedic), $columns, $primaryKey, "InnoDB"); + $_results = $db->DDLCreateTable(MAIN_DB_PREFIX.strtolower($namedic), $columns, $primaryKey, ""); if ($_results < 0) { dol_print_error($db); $langs->load("errors"); diff --git a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php index 0ecefaed4ce..686475d1211 100644 --- a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php +++ b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php @@ -243,7 +243,7 @@ class doc_generic_invoice_odt extends ModelePDFFactures $object->fetch_thirdparty(); - $dir = $conf->facture->dir_output; + $dir = empty($conf->facture->multidir_output[$object->entity]) ? $conf->facture->dir_output : $conf->facture->multidir_output[$object->entity]; $objectref = dol_sanitizeFileName($object->ref); if (!preg_match('/specimen/i', $objectref)) { $dir .= "/".$objectref; diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php index feec219703d..ad4b0d1bdd8 100644 --- a/htdocs/public/payment/newpayment.php +++ b/htdocs/public/payment/newpayment.php @@ -2152,7 +2152,7 @@ if ($action != 'dopayment') { if (getDolGlobalString('PAYPAL_API_INTEGRAL_OR_PAYPALONLY') != 'integral') { print '
 
'; } - print ' '; + print ' '; if (getDolGlobalString('PAYPAL_API_INTEGRAL_OR_PAYPALONLY') == 'integral') { print '
'; print ''.$langs->trans("CreditOrDebitCard").' - '; diff --git a/test/phpunit/DoliDBTest.php b/test/phpunit/DoliDBTest.php index 7abc7557a91..adafc6a676c 100644 --- a/test/phpunit/DoliDBTest.php +++ b/test/phpunit/DoliDBTest.php @@ -48,6 +48,41 @@ $conf->global->MAIN_DISABLE_ALL_MAILS = 1; */ class DoliDBTest extends CommonClassTest { + /** + * testDDLUpdateField + * + * @return int + */ + public function testDDLCreateTable() + { + global $conf,$user,$langs,$db; + $conf = $this->savconf; + $user = $this->savuser; + $langs = $this->savlangs; + $db = $this->savdb; + + $namedic = MAIN_DB_PREFIX.'tmptesttabletoremove'; + + $res = $db->DDLDropTable($namedic); + + $columns = array( + 'rowid' => array('type' => 'integer', 'value' => 11, 'AUTO_INCREMENT PRIMARY KEY'), + 'code' => array('type' => 'varchar', 'value' => 255, 'null'=>'NOT NULL'), + 'label' => array('type' => 'varchar', 'value' => 255, 'null'=>'NOT NULL'), + 'position' => array('type' => 'integer', 'value' => 11, 'null'=>'NULL'), + 'use_default' => array('type' => 'varchar', 'value' => 11, 'default'=>'1'), + 'active' => array('type' => 'integer', 'value' => 3) + ); + $primaryKey = 'rowid'; + + print __METHOD__.' db->type = '.$db->type."\n"; + + $res = $db->DDLCreateTable($namedic, $columns, $primaryKey, ""); + + $this->assertEquals(1, $res); + print __METHOD__." result=".$res."\n"; + } + /** * testDDLUpdateField * @@ -81,9 +116,10 @@ class DoliDBTest extends CommonClassTest print __METHOD__." result=".$result."\n"; // TODO Use $savtype and $savnull instead of hard coded - $field_desc = array('type' => 'varchar', 'value' => '16', 'null' => 'NOT NULL'); + $field_desc = array('type'=>'varchar', 'value'=>'16', 'null'=>'NOT NULL', 'default'=>'aaaabbbbccccdddd'); $result = $db->DDLUpdateField($db->prefix().'c_paper_format', 'code', $field_desc); + $this->assertEquals(1, $result); print __METHOD__." result=".$result."\n";