diff --git a/htdocs/core/modules/export/export_csviso.modules.php b/htdocs/core/modules/export/export_csviso.modules.php
new file mode 100644
index 0000000000000..29a9e24e76acf
--- /dev/null
+++ b/htdocs/core/modules/export/export_csviso.modules.php
@@ -0,0 +1,101 @@
+
+ *
+ * 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/modules/export/export_csv.modules.php
+ * \ingroup export
+ * \brief File of class to build exports with CSV format
+ */
+
+require_once DOL_DOCUMENT_ROOT.'/core/modules/export/exports_csv.modules.php';
+
+// avoid timeout for big export
+set_time_limit(0);
+
+/**
+ * Class to build export files with format CSV iso
+ */
+class ExportCsvIso extends ExportCsv
+{
+
+ /**
+ * Constructor
+ *
+ * @param DoliDB $db Database handler
+ */
+ public function __construct($db)
+ {
+ global $conf, $langs;
+ $this->db = $db;
+
+ $this->separator = ',';
+ if (!empty($conf->global->EXPORT_CSV_SEPARATOR_TO_USE)) {
+ $this->separator = $conf->global->EXPORT_CSV_SEPARATOR_TO_USE;
+ }
+
+ $conf->global->EXPORT_CSV_FORCE_CHARSET = 'ISO-8859-1';
+
+ $this->escape = '"';
+ $this->enclosure = '"';
+ $this->id = 'csviso'; // Same value then xxx in file name export_xxx.modules.php
+ $this->label = 'CSV ISO-8859-1'; // Label of driver
+ $this->desc = $langs->trans("CSVFormatDesc", $this->separator, $this->enclosure, $this->escape);
+ $this->extension = 'csv'; // Extension for generated file by this driver
+ $this->picto = 'mime/other'; // Picto
+ $this->version = '1.32'; // Driver version
+
+ // If driver use an external library, put its name here
+ $this->label_lib = 'Dolibarr';
+ $this->version_lib = DOL_VERSION;
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Output title line into file
+ *
+ * @param array $array_export_fields_label Array with list of label of fields
+ * @param array $array_selected_sorted Array with list of field to export
+ * @param Translate $outputlangs Object lang to translate values
+ * @param array $array_types Array with types of fields
+ * @return int <0 if KO, >0 if OK
+ */
+ public function write_title($array_export_fields_label, $array_selected_sorted, $outputlangs, $array_types)
+ {
+ global $conf;
+ $conf->global->EXPORT_CSV_FORCE_CHARSET = 'ISO-8859-1';
+
+ parent::write_title($array_export_fields_label, $array_selected_sorted, $outputlangs, $array_types);
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Output record line into file
+ *
+ * @param array $array_selected_sorted Array with list of field to export
+ * @param resource $objp A record from a fetch with all fields from select
+ * @param Translate $outputlangs Object lang to translate values
+ * @param array $array_types Array with types of fields
+ * @return int <0 if KO, >0 if OK
+ */
+ public function write_record($array_selected_sorted, $objp, $outputlangs, $array_types)
+ {
+ global $conf;
+ $conf->global->EXPORT_CSV_FORCE_CHARSET = 'ISO-8859-1';
+
+ parent::write_record($array_selected_sorted, $objp, $outputlangs, $array_types);
+ }
+}
diff --git a/htdocs/core/modules/export/export_csvutf8.modules.php b/htdocs/core/modules/export/export_csvutf8.modules.php
new file mode 100644
index 0000000000000..f517dd00839dc
--- /dev/null
+++ b/htdocs/core/modules/export/export_csvutf8.modules.php
@@ -0,0 +1,99 @@
+
+ *
+ * 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/modules/export/export_csv.modules.php
+ * \ingroup export
+ * \brief File of class to build exports with CSV format
+ */
+
+require_once DOL_DOCUMENT_ROOT.'/core/modules/export/exports_csv.modules.php';
+
+// avoid timeout for big export
+set_time_limit(0);
+
+/**
+ * Class to build export files with format CSV utf-8
+ */
+class ExportCsvUtf8 extends ExportCsv
+{
+
+ /**
+ * Constructor
+ *
+ * @param DoliDB $db Database handler
+ */
+ public function __construct($db)
+ {
+ global $conf, $langs;
+ $this->db = $db;
+
+ $this->separator = ',';
+ if (!empty($conf->global->EXPORT_CSV_SEPARATOR_TO_USE)) {
+ $this->separator = $conf->global->EXPORT_CSV_SEPARATOR_TO_USE;
+ }
+
+ $this->escape = '"';
+ $this->enclosure = '"';
+ $this->id = 'csvutf8'; // Same value then xxx in file name export_xxx.modules.php
+ $this->label = 'CSV UTF-8'; // Label of driver
+ $this->desc = $langs->trans("CSVFormatDesc", $this->separator, $this->enclosure, $this->escape);
+ $this->extension = 'csv'; // Extension for generated file by this driver
+ $this->picto = 'mime/other'; // Picto
+ $this->version = '1.32'; // Driver version
+
+ // If driver use an external library, put its name here
+ $this->label_lib = 'Dolibarr';
+ $this->version_lib = DOL_VERSION;
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Output title line into file
+ *
+ * @param array $array_export_fields_label Array with list of label of fields
+ * @param array $array_selected_sorted Array with list of field to export
+ * @param Translate $outputlangs Object lang to translate values
+ * @param array $array_types Array with types of fields
+ * @return int <0 if KO, >0 if OK
+ */
+ public function write_title($array_export_fields_label, $array_selected_sorted, $outputlangs, $array_types)
+ {
+ global $conf;
+ $conf->global->EXPORT_CSV_FORCE_CHARSET = 'UTF-8';
+
+ parent::write_title($array_export_fields_label, $array_selected_sorted, $outputlangs, $array_types);
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Output record line into file
+ *
+ * @param array $array_selected_sorted Array with list of field to export
+ * @param resource $objp A record from a fetch with all fields from select
+ * @param Translate $outputlangs Object lang to translate values
+ * @param array $array_types Array with types of fields
+ * @return int <0 if KO, >0 if OK
+ */
+ public function write_record($array_selected_sorted, $objp, $outputlangs, $array_types)
+ {
+ global $conf;
+
+ $conf->global->EXPORT_CSV_FORCE_CHARSET = 'UTF-8';
+ parent::write_record($array_selected_sorted, $objp, $outputlangs, $array_types);
+ }
+}
diff --git a/htdocs/core/modules/export/export_csv.modules.php b/htdocs/core/modules/export/exports_csv.modules.php
similarity index 87%
rename from htdocs/core/modules/export/export_csv.modules.php
rename to htdocs/core/modules/export/exports_csv.modules.php
index 26f20378b23ec..442c7cb628f25 100644
--- a/htdocs/core/modules/export/export_csv.modules.php
+++ b/htdocs/core/modules/export/exports_csv.modules.php
@@ -57,36 +57,6 @@ class ExportCsv extends ModeleExports
public $handle; // Handle fichier
-
- /**
- * Constructor
- *
- * @param DoliDB $db Database handler
- */
- public function __construct($db)
- {
- global $conf, $langs;
- $this->db = $db;
-
- $this->separator = ',';
- if (!empty($conf->global->EXPORT_CSV_SEPARATOR_TO_USE)) {
- $this->separator = $conf->global->EXPORT_CSV_SEPARATOR_TO_USE;
- }
- $this->escape = '"';
- $this->enclosure = '"';
-
- $this->id = 'csv'; // Same value then xxx in file name export_xxx.modules.php
- $this->label = 'CSV'; // Label of driver
- $this->desc = $langs->trans("CSVFormatDesc", $this->separator, $this->enclosure, $this->escape);
- $this->extension = 'csv'; // Extension for generated file by this driver
- $this->picto = 'mime/other'; // Picto
- $this->version = '1.32'; // Driver version
-
- // If driver use an external library, put its name here
- $this->label_lib = 'Dolibarr';
- $this->version_lib = DOL_VERSION;
- }
-
/**
* getDriverId
*
@@ -215,11 +185,8 @@ public function write_title($array_export_fields_label, $array_selected_sorted,
// phpcs:enable
global $conf;
- if (!empty($conf->global->EXPORT_CSV_FORCE_CHARSET)) {
- $outputlangs->charset_output = $conf->global->EXPORT_CSV_FORCE_CHARSET;
- } else {
- $outputlangs->charset_output = 'ISO-8859-1';
- }
+ $outputlangs->charset_output = $conf->global->EXPORT_CSV_FORCE_CHARSET;
+
$selectlabel = array();
foreach ($array_selected_sorted as $code => $value) {
@@ -256,11 +223,7 @@ public function write_record($array_selected_sorted, $objp, $outputlangs, $array
// phpcs:enable
global $conf;
- if (!empty($conf->global->EXPORT_CSV_FORCE_CHARSET)) {
- $outputlangs->charset_output = $conf->global->EXPORT_CSV_FORCE_CHARSET;
- } else {
- $outputlangs->charset_output = 'ISO-8859-1';
- }
+ $outputlangs->charset_output = $conf->global->EXPORT_CSV_FORCE_CHARSET;
$this->col = 0;
diff --git a/test/phpunit/ExportTest.php b/test/phpunit/ExportTest.php
index cf2f0520908c7..0a0a1c867ba4c 100644
--- a/test/phpunit/ExportTest.php
+++ b/test/phpunit/ExportTest.php
@@ -149,6 +149,94 @@ protected function tearDown(): void
print __METHOD__."\n";
}
+ /**
+ * Other tests
+ *
+ * @return void
+ */
+ public function testExportCsvUtf()
+ {
+ global $conf,$user,$langs,$db;
+
+ $model='csvutf8';
+
+ $conf->global->EXPORT_CSV_SEPARATOR_TO_USE = ',';
+ print 'EXPORT_CSV_SEPARATOR_TO_USE = '.$conf->global->EXPORT_CSV_SEPARATOR_TO_USE;
+
+ // Creation of class to export using model ExportXXX
+ $dir = DOL_DOCUMENT_ROOT . "/core/modules/export/";
+ $file = "export_".$model.".modules.php";
+ $classname = "Export".$model;
+ require_once $dir.$file;
+ $objmodel = new $classname($db);
+
+ // First test without option USE_STRICT_CSV_RULES
+ unset($conf->global->USE_STRICT_CSV_RULES);
+
+ $valtotest='A simple string';
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, 'A simple string');
+
+ $valtotest='A string with , and ; inside';
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, '"A string with , and ; inside"', 'Error in csvClean for '.$file);
+
+ $valtotest='A string with " inside';
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, '"A string with "" inside"');
+
+ $valtotest='A string with " inside and '."\r\n".' carriage returns';
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, '"A string with "" inside and \n carriage returns"');
+
+ $valtotest='A string with html
content inside
'."\n";
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, '"A string with html
content inside"');
+
+ // Same tests with strict mode
+ $conf->global->USE_STRICT_CSV_RULES = 1;
+
+ $valtotest='A simple string';
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, 'A simple string');
+
+ $valtotest='A string with , and ; inside';
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, '"A string with , and ; inside"');
+
+ $valtotest='A string with " inside';
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, '"A string with "" inside"');
+
+ $valtotest='A string with " inside and '."\r\n".' carriage returns';
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, "\"A string with \"\" inside and \r\n carriage returns\"");
+
+ $valtotest='A string with html
content inside
'."\n";
+ print __METHOD__." valtotest=".$valtotest."\n";
+ $result = $objmodel->csvClean($valtotest, $langs->charset_output);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals($result, '"A string with html
content inside"');
+ }
+
/**
* Other tests
@@ -159,7 +247,7 @@ public function testExportOther()
{
global $conf,$user,$langs,$db;
- $model='csv';
+ $model='csviso';
$conf->global->EXPORT_CSV_SEPARATOR_TO_USE = ',';
print 'EXPORT_CSV_SEPARATOR_TO_USE = '.$conf->global->EXPORT_CSV_SEPARATOR_TO_USE;
@@ -263,7 +351,15 @@ public function testExportPersonalizedExport()
dol_mkdir($conf->export->dir_temp);
- $model='csv';
+ $model='csviso';
+
+ // Build export file
+ print "Process build_file for model = ".$model."\n";
+ $result=$objexport->build_file($user, $model, $datatoexport, $array_selected, array(), $sql);
+ $expectedresult = 1;
+ $this->assertEquals($expectedresult, $result, 'Error in CSV export');
+
+ $model='csvutf8';
// Build export file
print "Process build_file for model = ".$model."\n";
@@ -353,7 +449,7 @@ public function testExportModulesDatasets()
{
global $conf,$user,$langs,$db;
- $model='csv';
+ $model='csviso';
$filterdatatoexport='';
//$filterdatatoexport='';