From 81de3b3d7b801314a16443f7683b5bd2bb34a028 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 17 Apr 2025 10:27:30 +0530 Subject: [PATCH 1/3] update: add stricter checks for column/attribute checks. --- src/Migration/Sources/CSV.php | 36 ++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/Migration/Sources/CSV.php b/src/Migration/Sources/CSV.php index fed64d74..76804f81 100644 --- a/src/Migration/Sources/CSV.php +++ b/src/Migration/Sources/CSV.php @@ -160,15 +160,21 @@ private function exportDocuments(int $batchSize): void } } - $this->withCSVStream(function ($stream) use ($attributeTypes, $manyToManyKeys, $collection, $batchSize) { + $this->withCSVStream(function ($stream) use ($attributes, $attributeTypes, $manyToManyKeys, $collection, $batchSize) { $headers = fgetcsv($stream); if (! is_array($headers) || count($headers) === 0) { return; } + $this->validateCSVHeaders($headers, $attributes); + $buffer = []; while (($row = fgetcsv($stream)) !== false) { + if (count($row) !== count($headers)) { + throw new \Exception('CSV row does not match the number of header columns.'); + } + $data = array_combine($headers, $row); if ($data === false) { continue; @@ -277,4 +283,32 @@ private function withCsvStream(callable $fn): void fclose($stream); } } + + /** + * @throws \Exception + */ + private function validateCSVHeaders(array $headers, array $expectedAttributes): void + { + // Ignore keys like $id, $permissions, etc. + $filteredHeaders = array_filter($headers, fn ($key) => ! str_starts_with($key, '$')); + + $extraAttributes = array_diff($filteredHeaders, $expectedAttributes); + $missingAttributes = array_diff($expectedAttributes, $filteredHeaders); + + if (! empty($missingAttributes) || ! empty($extraAttributes)) { + $messages = []; + + if (! empty($missingAttributes)) { + $label = count($missingAttributes) === 1 ? 'Missing attribute' : 'Missing attributes'; + $messages[] = "{$label}: '".implode("', '", $missingAttributes)."'"; + } + + if (! empty($extraAttributes)) { + $label = count($extraAttributes) === 1 ? 'Unexpected attribute' : 'Unexpected attributes'; + $messages[] = "{$label}: '".implode("', '", $extraAttributes)."'"; + } + + throw new \Exception('CSV header mismatch. '.implode(' | ', $messages)); + } + } } From 3c186a12d6a5d1085ff9943887d1abd5ac3128f6 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 17 Apr 2025 10:30:16 +0530 Subject: [PATCH 2/3] fix: passed invalid variable for checks. --- src/Migration/Sources/CSV.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migration/Sources/CSV.php b/src/Migration/Sources/CSV.php index 76804f81..e12f14ce 100644 --- a/src/Migration/Sources/CSV.php +++ b/src/Migration/Sources/CSV.php @@ -160,13 +160,13 @@ private function exportDocuments(int $batchSize): void } } - $this->withCSVStream(function ($stream) use ($attributes, $attributeTypes, $manyToManyKeys, $collection, $batchSize) { + $this->withCSVStream(function ($stream) use ($attributeTypes, $manyToManyKeys, $collection, $batchSize) { $headers = fgetcsv($stream); if (! is_array($headers) || count($headers) === 0) { return; } - $this->validateCSVHeaders($headers, $attributes); + $this->validateCSVHeaders($headers, $attributeTypes); $buffer = []; From 0bcb3f8b1020842d19ba7b030fa1c91bace49329 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 17 Apr 2025 10:35:09 +0530 Subject: [PATCH 3/3] fix: need to check the keys! --- src/Migration/Sources/CSV.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Migration/Sources/CSV.php b/src/Migration/Sources/CSV.php index e12f14ce..75c489da 100644 --- a/src/Migration/Sources/CSV.php +++ b/src/Migration/Sources/CSV.php @@ -287,8 +287,10 @@ private function withCsvStream(callable $fn): void /** * @throws \Exception */ - private function validateCSVHeaders(array $headers, array $expectedAttributes): void + private function validateCSVHeaders(array $headers, array $attributeTypes): void { + $expectedAttributes = array_keys($attributeTypes); + // Ignore keys like $id, $permissions, etc. $filteredHeaders = array_filter($headers, fn ($key) => ! str_starts_with($key, '$'));