fix: harden postcodes:import against duplicate headers and test collisions

This commit is contained in:
Ovidiu U
2026-04-22 12:33:10 +01:00
parent 4a60298606
commit 9ad62538b9
2 changed files with 21 additions and 7 deletions

View File

@@ -6,7 +6,6 @@ use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use RuntimeException;
#[Signature('postcodes:import {--file= : Path to ONSPD CSV file}')]
#[Description('Import UK postcodes (ONSPD) into the local postcodes and outcodes tables')]
@@ -27,7 +26,9 @@ final class ImportPostcodes extends Command
$handle = fopen($file, 'r');
if ($handle === false) {
throw new RuntimeException("Unable to open {$file}");
$this->error("Unable to open {$file}.");
return self::FAILURE;
}
$header = fgetcsv($handle);
@@ -39,6 +40,17 @@ final class ImportPostcodes extends Command
return self::FAILURE;
}
$headerCounts = array_count_values(array_map('strtolower', $header));
foreach (['pcd', 'lat', 'long'] as $required) {
if (($headerCounts[$required] ?? 0) > 1) {
$this->error("Column '{$required}' appears more than once — refusing to import.");
fclose($handle);
return self::FAILURE;
}
}
$columns = array_change_key_case(array_flip($header), CASE_LOWER);
foreach (['pcd', 'lat', 'long'] as $required) {

View File

@@ -5,6 +5,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
if (! function_exists('writeOnspdFixture')) {
function writeOnspdFixture(string $contents): string
{
$path = tempnam(sys_get_temp_dir(), 'onspd_').'.csv';
@@ -12,6 +13,7 @@ function writeOnspdFixture(string $contents): string
return $path;
}
}
it('imports active postcodes from an ONSPD CSV', function (): void {
$csv = <<<'CSV'