diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b2ed920c..d8bdc0259 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ * Fixed collections using `page@.self:` should allow modular pages if requested * Fixed an error when trying to delete a file from non-existing Flex Object * Fixed `FlexObject::exists()` failing sometimes just after the object has been saved + * Fixed CSV formatter not encoding strings with `"` and `,` properly # v1.6.11 ## 06/21/2019 diff --git a/system/src/Grav/Framework/File/Formatter/CsvFormatter.php b/system/src/Grav/Framework/File/Formatter/CsvFormatter.php index 2a700258c..22b798ccf 100644 --- a/system/src/Grav/Framework/File/Formatter/CsvFormatter.php +++ b/system/src/Grav/Framework/File/Formatter/CsvFormatter.php @@ -53,11 +53,11 @@ class CsvFormatter extends AbstractFormatter $header = array_keys(reset($data)); // Encode the field names - $string = implode($delimiter, $header). "\n"; + $string = $this->encodeLine($header, $delimiter); // Encode the data foreach ($data as $row) { - $string .= implode($delimiter, $row). "\n"; + $string .= $this->encodeLine($row, $delimiter); } return $string; @@ -87,4 +87,23 @@ class CsvFormatter extends AbstractFormatter return $list; } + + protected function encodeLine(array $line, $delimiter = null): string + { + foreach ($line as $key => &$value) { + $value = $this->escape((string)$value); + } + unset($value); + + return implode($delimiter, $line). "\n"; + } + + protected function escape(string $value) + { + if (preg_match('/[,"\r\n]/u', $value) !== false) { + $value = '"' . preg_replace('/"/', '""', $value) . '"'; + } + + return $value; + } }