Bug #55763 [Com]: str_getcsv incorrectly handles line-breaks inside fields
| From: | php at myingling dot com | Date: | Mon, 17 Jun 2019 23:56:11 +0000 |
| Subject: | Bug #55763 [Com]: str_getcsv incorrectly handles line-breaks inside fields | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-221353@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=55763&edit=1
ID: 55763
Comment by: php at myingling dot com
Reported by: talk at alexmingoia dot com
Summary: str_getcsv incorrectly handles line-breaks inside
fields
Status: Not a bug
Type: Bug
Package: Strings related
Operating System: OS X 10.6
PHP Version: 5.3.8
Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
This *IS* a bug. Here is an example of valid quotation marks and new lines which illustrates the
real problem:
https://3v4l.org/HAJh1
Previous Comments:
------------------------------------------------------------------------
[2015-05-18 14:42:22] cmb@php.net
str_getcsv() is designed to parse a single CSV record into fields (what works as expected, see
<http://3v4l.org/f1DXO>).
If \n as given as delimiter, it splits the string at the line endings, and also heeds the enclosing
parameter, but only if that characters encloses the complete field (in this case one or more lines).
This also works as expected, see <http://3v4l.org/UfsLi>.
------------------------------------------------------------------------
[2014-11-17 10:51:52] andrzejborkowski at gmail dot com
$csvTestStr = 'mg3150 manual,12,-61%,6,-54%,50%,8.0,1.0,
"canon powershot sx400 is 16mp, 30x zoom mini bridge camera w/ case & sd
card",12,?,6,?,50%,50,1.0,
canon printer mg6450,12,20%,6,,50%,-10,1.0,
canon pixma 3150 wireless setup,12,-48%,6,-33%,50%,10,1.0,
mg3150 manual,12,-61%,6,-54%,50%,8.0,1.0,
"canon powershot sx400 is 16mp, 30x zoom mini bridge camera w/ case & sd
card",12,?,6,?,50%,50,1.0,
canon printer mg6450,12,20%,6,,50%,-10,1.0,
canon pixma 3150 wireless setup,12,-48%,6,-33%,50%,10,1.0,';
//$fields = str_getcsv($row,"/n"); #fail
$rows =
preg_split('/[\r\n]{1,2}(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/',
$csvTestStr); #split rows properly
$this->assertTrue(count($rows) === 8);
foreach ($rows as $row) {
$fields = str_getcsv($row,',');
$this->assertTrue(count($fields) === 9);
if (count($fields) !== 9) {
debug($fields);
}
}
------------------------------------------------------------------------
[2013-08-22 03:09:00] alotacents at gmail dot com
to split the string in to record lines I used a regular expression that makes sure not to split
inside of double quotes instead of using the str_getcsv. Then I used the str_getcsv on the line.
example
$s2=<<<EOD
Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very
Large""","",5000.00
1996,Jeep,Grand Cherokee,"MUST SELL!
air, moon roof, loaded",4799.00
EOD;
lines =
preg_split('/[\r\n]{1,2}(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/',$s2);
it outputs
Array (
[0] => Year,Make,Model,Description,Price
[1] => 1997,Ford,E350,"ac, abs, moon",3000.00
[2] => 1999,Chevy,"Venture ""Extended
Edition""","",4900.00
[3] => 1999,Chevy,"Venture ""Extended Edition, Very
Large""","",5000.00
[4] => 1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00
)
to further convert
$data = array();
foreach($lines as $row) {
$data[] = str_getcsv($row);
}
print_r($data);
which will output
Array (
[0] => Array (
[0] => Year
[1] => Make
[2] => Model
[3] => Description
[4] => Price
)
[1] => Array (
[0] => 1997
[1] => Ford
[2] => E350
[3] => ac, abs, moon
[4] => 3000.00
)
[2] => Array (
[0] => 1999
[1] => Chevy
[2] => Venture "Extended Edition"
[3] =>
[4] => 4900.00
)
[3] => Array (
[0] => 1999
[1] => Chevy
[2] => Venture "Extended Edition, Very Large"
[3] =>
[4] => 5000.00
)
[4] => Array (
[0] => 1996
[1] => Jeep
[2] => Grand Cherokee
[3] => MUST SELL! air, moon roof, loaded
[4] => 4799.00
)
)
------------------------------------------------------------------------
[2012-04-27 03:11:17] darren at dcook dot org
The problem can also be shown with the example from the Wikipedia page
(http://en.wikipedia.org/wiki/Comma-separated_values):
$s2=<<<EOD
Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very
Large""","",5000.00
1996,Jeep,Grand Cherokee,"MUST SELL!
air, moon roof, loaded",4799.00
EOD;
$lines=str_getcsv($s2,"\n");
print_r($lines);
It outputs:
Array
(
[0] => Year,Make,Model,Description,Price
[1] => 1997,Ford,E350,"ac, abs, moon",3000.00
[2] => 1999,Chevy,"Venture ""Extended
Edition""","",4900.00
[3] => 1999,Chevy,"Venture ""Extended Edition, Very
Large""","",5000.00
[4] => 1996,Jeep,Grand Cherokee,"MUST SELL!
[5] => air, moon roof, loaded",4799.00
)
But it should output:
Array
(
[0] => Year,Make,Model,Description,Price
[1] => 1997,Ford,E350,"ac, abs, moon",3000.00
[2] => 1999,Chevy,"Venture ""Extended
Edition""","",4900.00
[3] => 1999,Chevy,"Venture ""Extended Edition, Very
Large""","",5000.00
[4] => 1996,Jeep,Grand Cherokee,"MUST SELL!
air, moon roof, loaded",4799.00
)
------------------------------------------------------------------------
[2011-09-22 16:45:02] talk at alexmingoia dot com
Sorry... expected output should be
array(4) {
[0]=>
string(15) "Name,Desc,Email"
[1]=>
string(4) "Alex"
[2]=>
string(18) "Is a PHP
developer
"
[3]=>
string(16) "alex@example.com"
}
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=55763
--
Edit this bug report at https://bugs.php.net/bug.php?id=55763&edit=1