Skip to content
← Back to Snippets
Code

CSV Header Contract Validator

Validates a CSV header row against required and optional column contracts before importing file data.

Purpose

Validates a CSV header row against required and optional column contracts before importing file data.

Snippet details

ContextFileLevelAdvancedCopy-and-paste statusMarked safe after review.

Categories

  • Security

Code

<?php

/*
 * Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
 * Free for personal and internal use. Paid project use requires visible credit
 * to Jeffery L. Paris. Corporate use requires a paid license fee unless a
 * separate written license states otherwise.
 */

/**
 * CSV Header Contract Validator.
 *
 * Purpose:
 * Checks whether a CSV header row contains every required column, rejects
 * duplicate columns, and flags unexpected columns before import begins.
 *
 * @param array $header_row Header values read from the first CSV row.
 * @param array $required_columns Required column names.
 * @param array $optional_columns Optional approved column names.
 * @return array Header contract result with errors and a column position map.
 */
function ogSnippetCsvHeaderContractValidator(array $header_row, array $required_columns, array $optional_columns): array {
	$errors = array();
	$position_map = array();
	$seen_columns = array();
	$approved_columns = array();

	foreach ($required_columns as $column_name) {
		$clean_name = strtolower(trim((string) $column_name));

		if ($clean_name !== '') {
			$approved_columns[$clean_name] = true;
		}
	}

	foreach ($optional_columns as $column_name) {
		$clean_name = strtolower(trim((string) $column_name));

		if ($clean_name !== '') {
			$approved_columns[$clean_name] = true;
		}
	}

	foreach ($header_row as $position => $column_name) {
		$clean_name = strtolower(trim((string) $column_name));

		if ($clean_name === '') {
			$errors[] = 'Column '.($position + 1).' is blank.';
			continue;
		}

		if (isset($seen_columns[$clean_name]) === true) {
			$errors[] = 'Column "'.$clean_name.'" appears more than once.';
			continue;
		}

		$seen_columns[$clean_name] = true;
		$position_map[$clean_name] = (int) $position;

		if (isset($approved_columns[$clean_name]) === false) {
			$errors[] = 'Column "'.$clean_name.'" is not in the approved CSV contract.';
		}
	}

	foreach ($required_columns as $column_name) {
		$clean_name = strtolower(trim((string) $column_name));

		if ($clean_name !== '' && isset($seen_columns[$clean_name]) === false) {
			$errors[] = 'Required column "'.$clean_name.'" is missing.';
		}
	}

	return array(
		'valid' => count($errors) === 0,
		'errors' => $errors,
		'position_map' => $position_map
	);
}

$csv_header = array('ship_id', 'captain', 'registry', 'sector');
$required_columns = array('ship_id', 'captain', 'registry');
$optional_columns = array('sector', 'mission_status');
$contract = ogSnippetCsvHeaderContractValidator($csv_header, $required_columns, $optional_columns);

if ($contract['valid'] === true) {
	echo 'Starfleet CSV header contract approved.';
} else {
	echo 'Starfleet CSV header contract failed.';
}