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='';