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

From: Date: Tue, 18 Jun 2019 06:40:31 +0000
Subject: Bug #55763 [Nab]: str_getcsv incorrectly handles line-breaks inside fields
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-221357@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 Updated by: cmb@php.net 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: Again, str_getcsv() is supposed to parse a *single* CSV record (aka. line), exactly like fgetcsv() does. How to split CSV contents into records is left to the programmer. <https://3v4l.org/D8Mqt> uses concrete knowledge of the input data to correctly do that. Previous Comments: ------------------------------------------------------------------------ [2019-06-17 23:56:11] php at myingling dot com This *IS* a bug. Here is an example of valid quotation marks and new lines which illustrates the real problem: https://3v4l.org/HAJh1 ------------------------------------------------------------------------ [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 ) ------------------------------------------------------------------------ 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 (#221357) next »