Skip to content

Commit a64faeb

Browse files
Merge #19955 Quoting is only needed when separators appear in text
Quoting is only needed when separators appear in text
2 parents 233dc54 + d40c190 commit a64faeb

3 files changed

Lines changed: 50 additions & 47 deletions

File tree

src/Plugins/Export/ExportCsv.php

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
use function __;
2323
use function implode;
2424
use function is_string;
25-
use function mb_strtolower;
25+
use function str_contains;
2626
use function str_replace;
27+
use function strtolower;
2728

2829
/**
2930
* Handles the export for the CSV format
@@ -112,7 +113,7 @@ protected function setProperties(): ExportPluginProperties
112113
public function exportHeader(): bool
113114
{
114115
// Here we just prepare some values for export
115-
if ($this->terminated === '' || mb_strtolower($this->terminated) === 'auto') {
116+
if ($this->terminated === '' || strtolower($this->terminated) === 'auto') {
116117
$this->terminated = "\n";
117118
} else {
118119
$this->terminated = str_replace(
@@ -193,7 +194,13 @@ public function exportData(
193194
foreach ($result->getFieldNames() as $colAs) {
194195
$colAs = $this->getColumnAlias($aliases, $db, $table, $colAs);
195196

196-
if ($this->enclosed === '') {
197+
if (
198+
$this->enclosed === ''
199+
|| (! str_contains($colAs, $this->separator)
200+
&& ! str_contains($colAs, $this->enclosed)
201+
&& ! str_contains($colAs, $this->terminated)
202+
)
203+
) {
197204
$insertFields[] = $colAs;
198205
} else {
199206
$insertFields[] = $this->enclosed
@@ -224,7 +231,13 @@ public function exportData(
224231
);
225232
}
226233

227-
if ($this->enclosed === '') {
234+
if (
235+
$this->enclosed === ''
236+
|| (! str_contains($field, $this->separator)
237+
&& ! str_contains($field, $this->enclosed)
238+
&& ! str_contains($field, $this->terminated)
239+
)
240+
) {
228241
$insertValues[] = $field;
229242
} elseif ($this->escaped !== $this->enclosed) {
230243
// also double the escape string if found in the data
@@ -284,27 +297,27 @@ public function setExportOptions(ServerRequest $request, array $exportConfig): v
284297
);
285298
$this->terminated = $this->setStringValue(
286299
$request->getParsedBodyParam('csv_terminated'),
287-
$exportConfig['csv_terminated'] ?? null,
300+
$exportConfig['csv_terminated'] ?? $this->terminated,
288301
);
289302
$this->separator = $this->setStringValue(
290303
$request->getParsedBodyParam('csv_separator'),
291-
$exportConfig['csv_separator'] ?? null,
304+
$exportConfig['csv_separator'] ?? $this->separator,
292305
);
293306
$this->columns = (bool) ($request->getParsedBodyParam('csv_columns')
294307
?? $exportConfig['csv_columns'] ?? false);
295308
$this->enclosed = $this->setStringValue(
296309
$request->getParsedBodyParam('csv_enclosed'),
297-
$exportConfig['csv_enclosed'] ?? null,
310+
$exportConfig['csv_enclosed'] ?? $this->enclosed,
298311
);
299312
$this->escaped = $this->setStringValue(
300313
$request->getParsedBodyParam('csv_escaped'),
301-
$exportConfig['csv_escaped'] ?? null,
314+
$exportConfig['csv_escaped'] ?? $this->escaped,
302315
);
303316
$this->removeCrLf = (bool) ($request->getParsedBodyParam('csv_removeCRLF')
304317
?? $exportConfig['csv_removeCRLF'] ?? false);
305318
$this->null = $this->setStringValue(
306319
$request->getParsedBodyParam('csv_null'),
307-
$exportConfig['csv_null'] ?? null,
320+
$exportConfig['csv_null'] ?? $this->null,
308321
);
309322
}
310323

tests/unit/Plugins/Export/ExportCsvTest.php

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -281,17 +281,19 @@ public function testExportData(): void
281281
->withParsedBody(['csv_terminated' => ';', 'csv_columns' => 'On']);
282282

283283
$this->object->setExportOptions($request, []);
284+
$this->object->exportHeader();
284285

285286
ob_start();
286287
self::assertTrue($this->object->exportData(
287288
'test_db',
288289
'test_table',
289-
'SELECT * FROM `test_db`.`test_table`;',
290+
'SELECT * FROM `test_db`.`test_table_csv_export`;',
290291
));
291292
$result = ob_get_clean();
292293

293294
self::assertSame(
294-
'idnamedatetimefield;1abcd2011-01-20 02:00:02;2foo2010-01-20 02:00:02;3Abcd2012-01-20 02:00:02;',
295+
'id,name,datetimefield;1,"ab""cd",2011-01-20 02:00:02;2,"foo;",2010-01-20 02:00:02;3,'
296+
. "\n" . 'Abcd,2012-01-20 02:00:02;',
295297
$result,
296298
);
297299

@@ -300,63 +302,42 @@ public function testExportData(): void
300302
->withParsedBody(['csv_enclosed' => '"', 'csv_terminated' => ';', 'csv_columns' => 'On']);
301303

302304
$this->object->setExportOptions($request, []);
305+
$this->object->exportHeader();
303306

304307
ob_start();
305308
self::assertTrue($this->object->exportData(
306309
'test_db',
307-
'test_table',
308-
'SELECT * FROM `test_db`.`test_table`;',
310+
'test_table_csv_export',
311+
'SELECT * FROM `test_db`.`test_table_csv_export`;',
309312
));
310313
$result = ob_get_clean();
311314

312315
self::assertSame(
313-
'"id""name""datetimefield";"1""abcd""2011-01-20 02:00:02";'
314-
. '"2""foo""2010-01-20 02:00:02";"3""Abcd""2012-01-20 02:00:02";',
316+
'id,name,datetimefield;1,"ab""cd",2011-01-20 02:00:02;2,"foo;",2010-01-20 02:00:02;3,'
317+
. "\n" . 'Abcd,2012-01-20 02:00:02;',
315318
$result,
316319
);
317320

318321
// case 4
319-
ob_start();
320-
self::assertTrue($this->object->exportData(
321-
'test_db',
322-
'test_table',
323-
'SELECT * FROM `test_db`.`test_table`;',
324-
));
325-
$result = ob_get_clean();
326-
327-
self::assertSame(
328-
'"id""name""datetimefield";"1""abcd""2011-01-20 02:00:02";'
329-
. '"2""foo""2010-01-20 02:00:02";"3""Abcd""2012-01-20 02:00:02";',
330-
$result,
331-
);
332-
333-
// case 5
334-
ob_start();
335-
self::assertTrue($this->object->exportData(
336-
'test_db',
337-
'test_table',
338-
'SELECT * FROM `test_db`.`test_table`;',
339-
));
340-
$result = ob_get_clean();
322+
$request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/')
323+
->withParsedBody(['csv_enclosed' => '|', 'csv_terminated' => "\n", 'csv_escaped' => '\\', 'csv_columns' => 'On']);
341324

342-
self::assertSame(
343-
'"id""name""datetimefield";"1""abcd""2011-01-20 02:00:02";'
344-
. '"2""foo""2010-01-20 02:00:02";"3""Abcd""2012-01-20 02:00:02";',
345-
$result,
346-
);
325+
$this->object->setExportOptions($request, []);
326+
$this->object->exportHeader();
347327

348-
// case 6
349328
ob_start();
350329
self::assertTrue($this->object->exportData(
351330
'test_db',
352-
'test_table',
353-
'SELECT * FROM `test_db`.`test_table`;',
331+
'test_table_csv_export',
332+
'SELECT * FROM `test_db`.`test_table_csv_export`;',
354333
));
355334
$result = ob_get_clean();
356335

357336
self::assertSame(
358-
'"id""name""datetimefield";"1""abcd""2011-01-20 02:00:02";'
359-
. '"2""foo""2010-01-20 02:00:02";"3""Abcd""2012-01-20 02:00:02";',
337+
'id,name,datetimefield' . "\n"
338+
. '1,ab"cd,2011-01-20 02:00:02' . "\n"
339+
. '2,foo;,2010-01-20 02:00:02' . "\n"
340+
. '3,|' . "\n" . 'Abcd|,2012-01-20 02:00:02' . "\n",
360341
$result,
361342
);
362343
}

tests/unit/Stubs/DbiDummy.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,6 +1739,15 @@ private function init(): void
17391739
['3', 'Abcd', '2012-01-20 02:00:02'],
17401740
],
17411741
],
1742+
[
1743+
'query' => 'SELECT * FROM `test_db`.`test_table_csv_export`;',
1744+
'columns' => ['id', 'name', 'datetimefield'],
1745+
'result' => [
1746+
['1', 'ab"cd', '2011-01-20 02:00:02'],
1747+
['2', 'foo;', '2010-01-20 02:00:02'],
1748+
['3', "\nAbcd", '2012-01-20 02:00:02'],
1749+
],
1750+
],
17421751
[
17431752
'query' => 'SELECT * FROM `test_db`.`test_table_complex`;',
17441753
'columns' => ['f1', 'f2', 'f3', 'f4'],

0 commit comments

Comments
 (0)