Skip to content
← Back to Functions
Code

CSV Row Mapper

Maps CSV rows to internal field names using validated headers and defaults.

Function signature

ogMapCsvRowToFields(header_map, row_values, field_map, defaults = array())

Categories

  • Security

Parameters

header_mapCSV header name to zero-based column index map.row_valuesRaw row values from the CSV parser.field_mapInternal field name to CSV header name map.defaultsOptional default values by internal field name.

Return value

Short public-safe status message.

  • row
  • missing_fields
  • warnings

Compatibility

Existing function name and call order preserved; metadata signature corrected to source.

Minimum PHP version: 7.4

Security notes

Validate request method, identity, permissions, and caller-owned allowlists before use; keep secrets and internal paths out of public output.

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.
 */

/**
 * Maps one CSV row into internal field names using a validated header map.
 *
 * This helper does not guess column meaning. The caller provides the field map
 * so imports stay explicit and auditable.
 *
 * @param array $header_map CSV header name to zero-based column index map.
 * @param array $row_values Raw row values from the CSV parser.
 * @param array $field_map Internal field name to CSV header name map.
 * @param array $defaults Optional default values by internal field name.
 * @return array Structured mapping result with mapped values, warnings, and missing fields.
 */
function ogMapCsvRowToFields($header_map, $row_values, $field_map, $defaults = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	if (!is_array($header_map)) {
		$result['message'] = 'Header map must be an array.';
		return $result;
	}

	if (!is_array($row_values)) {
		$result['message'] = 'Row values must be an array.';
		return $result;
	}

	if (!is_array($field_map)) {
		$result['message'] = 'Field map must be an array.';
		return $result;
	}

	if (!is_array($defaults)) {
		$defaults = array();
	}

	$normalized_headers = array();
	foreach ($header_map as $header_name => $column_index) {
		$header_name = preg_replace('/^\xEF\xBB\xBF/', '', (string)$header_name);
		$header_key = strtolower(trim($header_name));
		if (!empty($header_key)) {
			$normalized_headers[$header_key] = (int)$column_index;
		}
	}

	$mapped = array();
	$missing = array();
	$warnings = array();

	foreach ($field_map as $internal_field => $csv_header) {
		$internal_field = trim((string)$internal_field);
		$csv_header_key = strtolower(trim((string)$csv_header));

		if (empty($internal_field)) {
			$warnings[] = 'Blank internal field name skipped.';
			continue;
		}

		if (!array_key_exists($csv_header_key, $normalized_headers)) {
			if (array_key_exists($internal_field, $defaults)) {
				$mapped[$internal_field] = $defaults[$internal_field];
			} else {
				$mapped[$internal_field] = '';
				$missing[] = $internal_field;
			}
			continue;
		}

		$column_index = $normalized_headers[$csv_header_key];
		if (array_key_exists($column_index, $row_values)) {
			if (is_scalar($row_values[$column_index])) {
				$mapped[$internal_field] = trim((string)$row_values[$column_index]);
			} else {
				$mapped[$internal_field] = $row_values[$column_index];
			}
		} else {
			if (array_key_exists($internal_field, $defaults)) {
				$mapped[$internal_field] = $defaults[$internal_field];
			} else {
				$mapped[$internal_field] = '';
				$missing[] = $internal_field;
			}
		}
	}

	$result['success'] = true;
	$result['message'] = 'CSV row mapped.';
	$result['data'] = array(
		'row' => $mapped,
		'missing_fields' => $missing,
		'warnings' => $warnings
	);

	return $result;
}