Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
"docs": "https://portphp.readthedocs.io"
},
"require": {
"php": "^8.2",
"portphp/portphp": "^2.0"
"portphp/portphp": "dev-master"
},
"autoload": {
"psr-4": {
Expand Down
122 changes: 112 additions & 10 deletions src/CsvReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ class CsvReader implements CountableReader, \SeekableIterator
*/
protected $duplicateHeadersFlag;


protected $padValue = null;

protected $truncateHeader = false;

protected $removeEmptyField = false;

/**
* @param \SplFileObject $file
* @param string $delimiter
Expand All @@ -81,6 +88,8 @@ class CsvReader implements CountableReader, \SeekableIterator
*/
public function __construct(\SplFileObject $file, $delimiter = ',', $enclosure = '"', $escape = '\\')
{
// ini_set('auto_detect_line_endings', true);

$this->file = $file;
$this->file->setFlags(
\SplFileObject::READ_CSV |
Expand All @@ -99,6 +108,8 @@ public function __construct(\SplFileObject $file, $delimiter = ',', $enclosure =
* Return the current row as an array
*
* If a header row has been set, an associative array will be returned
*
* @return array
*/
public function current(): ?array
{
Expand All @@ -114,10 +125,15 @@ public function current(): ?array
while ($this->valid()) {
$line = $this->file->current();

$columnHeaders = $this->columnHeaders;

// In non-strict mode pad/slice the line to match the column headers
if (!$this->isStrict()) {
if ($this->headersCount > count($line)) {
$line = array_pad($line, $this->headersCount, null); // Line too short
if($this->truncateHeader){
$columnHeaders = array_slice($columnHeaders, 0, count($line));
}
else $line = array_pad($line, $this->headersCount, $this->getPadValue()); // Line too short
} else {
$line = array_slice($line, 0, $this->headersCount); // Line too long
}
Expand All @@ -129,8 +145,12 @@ public function current(): ?array
}

// Count the number of elements in both: they must be equal.
if (count($this->columnHeaders) === count($line)) {
return array_combine(array_keys($this->columnHeaders), $line);
if (count($columnHeaders) === count($line)) {
$finalLine = array_combine(array_keys($columnHeaders), $line);
if($this->isRemoveEmptyField()){
return array_filter($finalLine, function($value) { return $value !== ''; });
}
else return $finalLine;
}

// They are not equal, so log the row as error and skip it.
Expand Down Expand Up @@ -160,6 +180,7 @@ public function getColumnHeaders()
*/
public function setColumnHeaders(array $columnHeaders)
{
$columnHeaders = array_map('trim', $columnHeaders);
$this->columnHeaders = array_count_values($columnHeaders);
$this->headersCount = count($columnHeaders);
}
Expand Down Expand Up @@ -203,6 +224,9 @@ public function rewind(): void
}
}

/**
* {@inheritdoc}
*/
public function count(): int
{
if (null === $this->count) {
Expand All @@ -216,21 +240,33 @@ public function count(): int
return $this->count;
}

/**
* {@inheritdoc}
*/
public function next(): void
{
$this->file->next();
}

/**
* {@inheritdoc}
*/
public function valid(): bool
{
return $this->file->valid();
}

/**
* {@inheritdoc}
*/
public function key(): int
{
return $this->file->key();
}

/**
* {@inheritdoc}
*/
public function seek($pointer): void
{
$this->file->seek($pointer);
Expand Down Expand Up @@ -309,13 +345,15 @@ protected function readHeaderRow($rowNumber)
$this->file->seek($rowNumber);
$headers = $this->file->current();

/** BOM file encoding issue */
$headers[0] = $this->prepareJSON($headers[0]);
// Test for duplicate column headers
$diff = array_diff_assoc($headers, array_unique($headers));
if (count($diff) > 0) {
switch ($this->duplicateHeadersFlag) {
case self::DUPLICATE_HEADERS_INCREMENT:
$headers = $this->incrementHeaders($headers);
// Fall through
// Fall through
case self::DUPLICATE_HEADERS_MERGE:
break;
default:
Expand All @@ -342,15 +380,17 @@ protected function readHeaderRow($rowNumber)
*/
protected function incrementHeaders(array $headers)
{
$counts = [];
$incrementedHeaders = [];
foreach (array_count_values($headers) as $header => $count) {
if ($count > 1) {

foreach ($headers as $header) {

if (!isset($counts[$header])) {
$counts[$header] = 0;
$incrementedHeaders[] = $header;
for ($i = 1; $i < $count; $i++) {
$incrementedHeaders[] = $header . $i;
}
} else {
$incrementedHeaders[] = $header;
$counts[$header]++;
$incrementedHeaders[] = $header . $counts[$header];
}
}

Expand Down Expand Up @@ -388,4 +428,66 @@ protected function mergeDuplicates(array $line)

return $values;
}

/**
* @return null
*/
public function getPadValue()
{
return $this->padValue;
}

/**
* @param null $padValue
*/
public function setPadValue($padValue)
{
$this->padValue = $padValue;
}

/**
* @return bool
*/
public function isTruncateHeader(): bool
{
return $this->truncateHeader;
}

/**
* @param bool $truncateHeader
*/
public function setTruncateHeader(bool $truncateHeader)
{
$this->truncateHeader = $truncateHeader;
}

/**
* @return bool
*/
public function isRemoveEmptyField(): bool
{
return $this->removeEmptyField;
}

/**
* @param bool $removeEmptyField
*/
public function setRemoveEmptyField(bool $removeEmptyField)
{
$this->removeEmptyField = $removeEmptyField;
}

function prepareJSON($input) {
//This will convert ASCII/ISO-8859-1 to UTF-8.
//Be careful with the third parameter (encoding detect list), because
//if set wrong, some input encodings will get garbled (including UTF-8!)
$imput = mb_convert_encoding($input, 'UTF-8', 'ASCII,UTF-8,ISO-8859-1');
//Remove UTF-8 BOM if present, json_decode() does not like it.
if(substr($input, 0, 3) == pack("CCC", 0xEF, 0xBB, 0xBF)) $input = substr($input, 3);
return $input;
}




}
2 changes: 1 addition & 1 deletion src/CsvWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public function prepare(): void
/**
* {@inheritdoc}
*/
public function writeItem(array $item): void
public function writeItem(mixed $item)
{
if ($this->prependHeaderRow && 1 == $this->row++) {
$headers = array_keys($item);
Expand Down