Bug #55763 [Com]: str_getcsv incorrectly handles line-breaks inside fields

From: 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

« previous php.bugs (#221353) next »