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

From: Date: Mon, 18 May 2015 14:42:23 +0000
Subject: Bug #55763 [Opn->Nab]: str_getcsv incorrectly handles line-breaks inside fields
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-192734@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: Open +Status: Not a bug Type: Bug Package: Strings related Operating System: OS X 10.6 PHP Version: 5.3.8 -Assigned To: +Assigned To: cmb Block user comment: N Private report: N New Comment: 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>. Previous Comments: ------------------------------------------------------------------------ [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" } ------------------------------------------------------------------------ [2011-09-22 16:41:15] talk at alexmingoia dot com Description: ------------ RFC4180 states that fields can contain line breaks as long as they are properly enclosed by double-quotes. str_getcsv treats line-breaks inside of enclosed fields as new records in the CSV. Setting 'auto_detect_line_ending' to TRUE or using "\r\n" instead of "\n" still produces incorrect results. Test script: --------------- $csv = file_get_contents('test.csv'); $csvArray = str_getcsv($csv, "\n"); var_dump($csvArray); Expected result: ---------------- 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" } Actual result: -------------- array(4) { [0]=> string(15) "Name,Desc,Email" [1]=> string(14) "Alex,"Is a PHP" [2]=> string(9) "developer" [3]=> string(17) ",alex@example.com" } ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=55763&edit=1

« previous php.bugs (#192734) next »