diff --git a/src/CsvReader.php b/src/CsvReader.php index 795fef3..2dda6ee 100644 --- a/src/CsvReader.php +++ b/src/CsvReader.php @@ -103,7 +103,11 @@ public function fetchAllAssoc(array $keys = array()) $data = array(); + $rowCounter = 0; + while ($row = $this->getNextRow()) { + $rowCounter++; + if ($headerFlag) { $headerFlag = false; $keys = $this->negotiateEncoding($row); @@ -112,7 +116,10 @@ public function fetchAllAssoc(array $keys = array()) } if (count($row) !== $keysCount) { - throw new Exception('Malformed line in CSV input'); + throw new Exception(sprintf( + 'Malformed row (%s) in CSV input', + $rowCounter + )); } $data[] = array_combine($keys, $this->negotiateEncoding($row)); @@ -128,19 +135,17 @@ public function fetch() { $row = $this->getNextRow(); - if (false === $row) { - // EOF - return false; + if (is_array($row)) { + $row = $this->negotiateEncoding($row); } - $row = $this->negotiateEncoding($row); - return $row; } /** * @param array $keys * @return array|bool + * @throws Exception */ public function fetchAssoc(array $keys = array()) { @@ -165,6 +170,13 @@ public function fetchAssoc(array $keys = array()) $this->fetchRowLineCounter++; + if (count($row) !== count($this->fetchRowKeys)) { + throw new Exception(sprintf( + 'Malformed row (%s) in CSV input', + $this->fetchRowLineCounter + )); + } + return array_combine($this->fetchRowKeys, $this->negotiateEncoding($row)); } @@ -177,10 +189,6 @@ private function getNextRow() $tmp = fgetcsv($this->stream, 0, $this->delimiter, $this->enclosure, $this->escape); - if ($tmp !== false && !is_array($tmp)) { - throw new LogicException('Unexpected error in fgetcsv call'); - } - return $tmp; } diff --git a/tests/Kaloa/Tests/Filesystem/CsvReaderTest.php b/tests/Kaloa/Tests/Filesystem/CsvReaderTest.php index 8edef62..04a4b3d 100644 --- a/tests/Kaloa/Tests/Filesystem/CsvReaderTest.php +++ b/tests/Kaloa/Tests/Filesystem/CsvReaderTest.php @@ -73,7 +73,6 @@ public function testCanReadWithOnlyHeaders() $expected = array(); $this->assertSame($expected, $data); - } /** @@ -93,6 +92,23 @@ public function testCanReadWithoutHeaders() $this->assertSame($expected, $data); } + /** + * + */ + public function testCanReadWithCustomHeaders() + { + $stream = fopen(__DIR__ . '/csv-files/no-headers.csv', 'rb'); + $reader = new CsvReader($stream); + $data = $reader->fetchAllAssoc(array('Col a', 'Col b')); + fclose($stream); + + $expected = array(); + $expected[] = array('Col a' => 'value 1a', 'Col b' => 'value 1b'); + $expected[] = array('Col a' => 'value 2a', 'Col b' => 'value 2b'); + + $this->assertSame($expected, $data); + } + /** * */ @@ -199,18 +215,68 @@ public function testThrowsExceptionOnInvalidStream() new CsvReader('invalid'); } + /** + * + */ + public function testThrowsExceptionOnMalformedLine() + { + $csvData = <<<'CSV' +"Col a","Col b" +"value 1a" +"value 2a","value 2b" +CSV; + + $dataUri = $this->convertToDataUri($csvData); + + $stream = fopen($dataUri, 'rb'); + + $reader = new CsvReader($stream); + + $this->setExpectedException('Exception', 'Malformed row (2) in CSV input'); + + $reader->fetchAllAssoc(); + + fclose($stream); + } + + /** + * + */ + public function testThrowsExceptionOnMalformedLineInStreamingMode() + { + $csvData = <<<'CSV' +"Col a","Col b" +"value 1a" +"value 2a","value 2b" +CSV; + + $dataUri = $this->convertToDataUri($csvData); + + $stream = fopen($dataUri, 'rb'); + + $reader = new CsvReader($stream); + + $this->setExpectedException('Exception', 'Malformed row (2) in CSV input'); + + while ($row = $reader->fetchAssoc()) { + // nop + } + + fclose($stream); + } + /** * */ public function testCanConvertCharset() { $csvData = << 'Thomas Müller', 'team' => 'FC Bayern München', 'position' => 'Sturm'); + $expected = array('name' => 'Thomas Müller', 'team' => 'FC Bayern München', 'position' => 'Striker'); $this->assertSame($expected, $data[0]); - $expected = array('name' => 'Mario Gómez', 'team' => 'VfL Wolfsburg', 'position' => 'Sturm'); + $expected = array('name' => 'Mario Gómez', 'team' => 'VfL Wolfsburg', 'position' => 'Striker'); $this->assertSame($expected, $data[5]); } @@ -257,7 +323,7 @@ public function testFetchAllAfterEofReturnsEmptyArray() } /** - * @param $string + * @param string $string * @return string */ private function convertToDataUri($string)