diff --git a/src/Csv.php b/src/Csv.php index fdb34ab..1143140 100644 --- a/src/Csv.php +++ b/src/Csv.php @@ -300,14 +300,15 @@ class Csv { * Class constructor * * @param string|null $input The CSV string or a direct filepath - * @param integer|null $offset Number of rows to ignore from the beginning - * of the data - * @param integer|null $limit Limits the number of returned rows to - * specified amount + * @param integer|null $offset Number of rows to ignore from the + * beginning of the data + * @param integer|null $limit Limits the number of returned rows + * to specified amount * @param string|null $conditions Basic SQL-like conditions for row * matching * @param null|true $keep_file_data Keep raw file data in memory after - * successful parsing (useful for debugging) + * successful parsing + * (useful for debugging) */ public function __construct($input = null, $offset = null, $limit = null, $conditions = null, $keep_file_data = null) { $this->init($offset, $limit, $conditions, $keep_file_data); @@ -318,14 +319,15 @@ class Csv { } /** - * @param integer|null $offset Number of rows to ignore from the beginning - * of the data - * @param integer|null $limit Limits the number of returned rows to - * specified amount + * @param integer|null $offset Number of rows to ignore from the + * beginning of the data + * @param integer|null $limit Limits the number of returned rows + * to specified amount * @param string|null $conditions Basic SQL-like conditions for row * matching * @param null|true $keep_file_data Keep raw file data in memory after - * successful parsing (useful for debugging) + * successful parsing + * (useful for debugging) */ public function init($offset = null, $limit = null, $conditions = null, $keep_file_data = null) { if (!is_null($offset)) { @@ -354,9 +356,12 @@ class Csv { * Parse a CSV file or string * * @param string|null $input The CSV string or a direct filepath - * @param integer $offset Number of rows to ignore from the beginning of the data - * @param integer $limit Limits the number of returned rows to specified amount - * @param string $conditions Basic SQL-like conditions for row matching + * @param integer $offset Number of rows to ignore from the + * beginning of the data + * @param integer $limit Limits the number of returned rows to + * specified amount + * @param string $conditions Basic SQL-like conditions for row + * matching * * @return bool True on success */ @@ -366,13 +371,11 @@ class Csv { } if (empty($input)) { - // todo: but why true? - return true; + return false; } $this->init($offset, $limit, $conditions); - if (strlen($input) <= PHP_MAXPATHLEN && is_readable($input)) { $this->file = $input; $this->data = $this->parse_file(); @@ -382,12 +385,7 @@ class Csv { $this->data = $this->parse_string(); } - if ($this->data === false) { - return false; - } - - return true; - + return $this->data !== false; } /** @@ -396,8 +394,10 @@ class Csv { * * @param string $file File location to save to * @param array $data 2D array of data - * @param bool $append Append current data to end of target CSV, if file exists - * @param array $fields Field names. Sets the header. If it is not set $this->titles would be used instead. + * @param bool $append Append current data to end of target CSV, if file + * exists + * @param array $fields Field names. Sets the header. If it is not set + * $this->titles would be used instead. * * @return bool */ @@ -419,7 +419,10 @@ class Csv { * @param string|null $filename If a filename is specified here or in the * object, headers and data will be output * directly to browser as a downloadable - * file. + * file. This file doesn't have to exist on + * the server; the parameter only affects + * how the download is called to the + * browser. * @param array[] $data 2D array with data * @param array $fields Field names * @param string|null $delimiter character used to separate data @@ -527,8 +530,8 @@ class Csv { } /** - * Get total number of data rows (exclusive heading line if present) in csv - * without parsing whole data. + * Get total number of data rows (exclusive heading line if present) in CSV + * without parsing the whole data string. * * @return bool|int */ @@ -541,9 +544,10 @@ class Csv { $this->_detect_and_remove_sep_row_from_data($data); - $pattern = sprintf('/(%1$s[^%1$s]*%1$s)/i', $this->enclosure); + $pattern = sprintf('/%1$s[^%1$s]*%1$s/i', $this->enclosure); preg_match_all($pattern, $data, $matches); + /** @var array[] $matches */ foreach ($matches[0] as $match) { if (empty($match) || (strpos($match, $this->enclosure) === false)) { continue; @@ -781,6 +785,9 @@ class Csv { public function unparse($data = array(), $fields = array(), $append = FileProcessingModeEnum::MODE_FILE_OVERWRITE, $is_php = false, $delimiter = null) { if (!is_array($data) || empty($data)) { $data = &$this->data; + } else { + /** @noinspection ReferenceMismatchInspection */ + $this->data = $data; } if (!is_array($fields) || empty($fields)) { @@ -795,6 +802,7 @@ class Csv { $entry = array(); // create heading + /** @noinspection ReferenceMismatchInspection */ $fieldOrder = $this->_validate_fields_for_unparse($fields); if (!$fieldOrder && !empty($data)) { $column_count = count($data[0]); @@ -813,7 +821,7 @@ class Csv { // create data foreach ($data as $key => $row) { - foreach (array_keys($fieldOrder) as $index){ + foreach (array_keys($fieldOrder) as $index) { $cell_value = $row[$index]; $entry[] = $this->_enclose_value($cell_value, $delimiter); } @@ -829,19 +837,20 @@ class Csv { return $string; } - private function _validate_fields_for_unparse($fields){ - // this is needed because sometime titles property is overwritten instead of using fields parameter! - $titlesOnParse = !empty($this->data) ? array_keys($this->data[0]) : array(); - if (empty($fields)){ + private function _validate_fields_for_unparse($fields) { + if (empty($fields)) { $fields = $this->titles; } - if (empty($fields)){ + if (empty($fields)) { return array(); } + // this is needed because sometime titles property is overwritten instead of using fields parameter! + $titlesOnParse = !empty($this->data) ? array_keys($this->data[0]) : array(); + // both are identical, also in ordering - if (array_values($fields) === array_values($titlesOnParse)){ + if (array_values($fields) === array_values($titlesOnParse)) { return array_combine($fields, $fields); } @@ -859,7 +868,10 @@ class Csv { // original titles are not given in fields. that is okay if count is okay. if (count($fields) != count($titlesOnParse)) { - throw new \UnexpectedValueException('The specified fields do not match any titles and do not match column count.'); + throw new \UnexpectedValueException( + "The specified fields do not match any titles and do not match column count.\n" . + "\$fields was " . print_r($fields, true) . + "\$titlesOnParse was " . print_r($titlesOnParse, true)); } return array_combine($titlesOnParse, $fields); @@ -1007,16 +1019,14 @@ class Csv { $op = $capture[2]; $value = $capture[3]; - if (preg_match('/^([\'\"]{1})(.*)([\'\"]{1})$/', $value, $capture)) { - if ($capture[1] == $capture[3]) { - $value = strtr($capture[2], array( - "\\n" => "\n", - "\\r" => "\r", - "\\t" => "\t", - )); + if (preg_match('/^([\'\"]{1})(.*)([\'\"]{1})$/', $value, $capture) && $capture[1] == $capture[3]) { + $value = strtr($capture[2], array( + "\\n" => "\n", + "\\r" => "\r", + "\\t" => "\t", + )); - $value = stripslashes($value); - } + $value = stripslashes($value); } if (array_key_exists($field, $row)) { diff --git a/tests/methods/DataRowCountTest.php b/tests/methods/DataRowCountTest.php index 693d736..a256fde 100644 --- a/tests/methods/DataRowCountTest.php +++ b/tests/methods/DataRowCountTest.php @@ -64,7 +64,6 @@ class DataRowCountTest extends TestCase { $this->assertEquals(3, $this->csv->getTotalDataRowCount()); } - public function testGetTotalRowCountSingleEnclosure() { $this->csv->heading = false; $this->csv->enclosure = "'"; @@ -73,4 +72,11 @@ class DataRowCountTest extends TestCase { $this->assertEquals(3, $this->csv->getTotalDataRowCount()); } + public function testGetTotalRowCountSingleRow() { + $this->csv->heading = false; + $this->csv->enclosure = "'"; + $sInput = "86545235689"; + $this->csv->load_data($sInput); + $this->assertEquals(1, $this->csv->getTotalDataRowCount()); + } } diff --git a/tests/methods/OutputTest.php b/tests/methods/OutputTest.php new file mode 100644 index 0000000..f323411 --- /dev/null +++ b/tests/methods/OutputTest.php @@ -0,0 +1,21 @@ + ['a', 'b', 'c'], 1 => ['d', 'e', 'f']]; + $fields = ['col1', 'col2', 'col3']; + $output = $csv->output('test.csv', $data, $fields, ','); + $expected = "col1,col2,col3\ra,b,c\rd,e,f\r"; + self::assertEquals($expected, $output); + } +}