Bug #74713 [Com]: CSV cell split after fputcsv() + fgetcsv() round trip.

From: Date: Mon, 12 Jun 2017 01:27:58 +0000
Subject: Bug #74713 [Com]: CSV cell split after fputcsv() + fgetcsv() round trip.
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-209488@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=74713&edit=1

 ID:                 74713
 Comment by:         danack@php.net
 Reported by:        andreas at dqxtech dot net
 Summary:            CSV cell split after fputcsv() + fgetcsv() round
                     trip.
 Status:             Open
 Type:               Bug
 Package:            Filesystem function related
 Operating System:   Linux / 3v4l
 PHP Version:        7.1.5
 Block user comment: N
 Private report:     N

 New Comment:

I looked at fixing the behaviour of the CSV functions before......basically, I'm not sure it is
fixable in a way that would be acceptable. Any fix around the behaviour you're seeing will
result in a BC break for some existing applications.

I'd recommend using a userland CSV parser instead.


Previous Comments:
------------------------------------------------------------------------
[2017-06-08 17:14:10] andreas at dqxtech dot net

Description:
------------
If one cell of the data sent to fputcsv() contains
"{$enclosure}{$escape_char}{$escape_char}{$enclosure}{$delimiter}", this cell will be
split after a round trip of fputcsv() + fgetcsv().

E.g. with specific choice of delimiter, enclosure and escape character:

Send ['"@@","B"'] to fputcsv() as a row of data.
fgetcsv() gives you back ['"@@', 'B"""'].
https://3v4l.org/3ZUO8

The reason is that fputcsv() writes
'"""@@",""B"""' to the file, instead of
'"""@@"",""B"""'.

In fact, writing the latter explicitly with fwrite() instead of fputcsv() fixes the problem:
https://3v4l.org/mjQRi


See https://stackoverflow.com/questions/44427926/data-gets-garbled-when-writing-to-csv-with-fputcsv-fgetcsv
Especially this answer, https://stackoverflow.com/a/44441433/246724



Test script:
---------------
$delimiter = ',';
$enclosure = '"';
$escape_char = "@";

$row_before =
["{$enclosure}{$escape_char}{$escape_char}{$enclosure}{$delimiter}{$enclosure}B{$enclosure}"];

print "\nBEFORE:\n";
var_export($row_before);
print "\n";

$fh = fopen($file = 'php://temp', 'rb+');


fputcsv($fh,$row_before,$delimiter,$enclosure, $escape_char);

# fwrite($fh, '"""@@"",""B"""');

rewind($fh);

$row_plain = fread($fh, 1000);

print "\nPLAIN:\n";
var_export($row_plain);
print "\n";

rewind($fh);

$row_after = fgetcsv($fh, 500,$delimiter,$enclosure, $escape_char);

print "\nAFTER:\n";
var_export($row_after);
print "\n\n";

fclose($fh);

Expected result:
----------------
BEFORE:
array (
  0 => '"@@","B"',
)

PLAIN:
'"""@@"",""B"""
'

AFTER:
array (
  0 => '"@@","B"',
)

Actual result:
--------------
BEFORE:
array (
  0 => '"@@","B"',
)

PLAIN:
'"""@@",""B"""
'

AFTER:
array (
  0 => '"@@',
  1 => 'B"""',
)


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=74713&edit=1


Thread (11 messages)

« previous php.bugs (#209488) next »