From d0f5fb9863fb9c1d667ec08d613cb3222575a974 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Thu, 3 Jul 2025 14:58:01 +0200 Subject: [PATCH] fix(export): escape CSV export for spreadsheet applications While in theory CSV is just plain data most users do not care and open it anyways in applications like Excel or LibreOffice. This can cause unwanted behavior if the cell value is evaluated like a formula. So for this we manually escape suche values. Signed-off-by: Ferdinand Thiessen --- lib/Service/SubmissionService.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/Service/SubmissionService.php b/lib/Service/SubmissionService.php index 546bbed36..316c0d0f4 100644 --- a/lib/Service/SubmissionService.php +++ b/lib/Service/SubmissionService.php @@ -312,9 +312,12 @@ private function exportData(array $header, array $data, string $fileFormat, ?Fil ->setWrapText(true); } else { // Explicitly set the type of the value to string for values that start with '=' to prevent it being interpreted as formulas - if (is_string($value) && str_starts_with($value, '=')) { + if (is_string($value)) { $activeWorksheet->getCell([$column, $row]) - ->setValueExplicit($value); + ->setValueExplicit($fileFormat === 'csv' + ? $this->escapeCSV($value) + : $value, + ); } else { $activeWorksheet->setCellValue([$column, $row], $value); } @@ -332,6 +335,19 @@ private function exportData(array $header, array $data, string $fileFormat, ?Fil return file_get_contents($exportedFile); } + /** + * Escape a value for writing it to a CSV file. + * This is needed to ensure the CSV, when loaded into an spreadsheet application, does not execute potential formulas. + */ + private function escapeCSV(string $value): string { + $BAD_CHARACTERS = ['=', '+', '-', '@', "\t", "\r"]; + if (strlen($value) > 0 && in_array(mb_str_split($value)[0], $BAD_CHARACTERS)) { + // Escape the value by adding a leading single quote + return "'$value"; + } + return $value; + } + /** * Validate all answers against the questions * @param array $questions Array of the questions of the form