Skip to content
← Back to Functions
Code

Column Type Profiler

Samples rows and estimates likely data types for each column.

Function signature

ogProfileColumnTypes(rows, sample_size = 50)

Categories

  • File and Upload Safety

Parameters

rowsList of associative or numeric rows.sample_sizeMaximum rows to inspect.

Return value

Short public-safe status message.

  • rows_sampled
  • columns

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

/**
 * Profiles likely data types for each column in sampled row data.
 *
 * The result is advisory only. It returns confidence counts rather than forcing
 * a permanent schema decision.
 *
 * @param array $rows List of associative or numeric rows.
 * @param int $sample_size Maximum rows to inspect.
 * @return array Structured result with column profile counts and likely types.
 */
function ogProfileColumnTypes($rows, $sample_size = 50) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

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

	$sample_size = (int)$sample_size;
	if ($sample_size < 1) {
		$sample_size = 50;
	}

	$profiles = array();
	$row_count = 0;

	foreach ($rows as $row) {
		if ($row_count >= $sample_size) {
			break;
		}
		if (!is_array($row)) {
			continue;
		}
		$row_count++;

		foreach ($row as $column => $value) {
			$column = (string)$column;
			if (!array_key_exists($column, $profiles)) {
				$profiles[$column] = array(
					'blank' => 0,
					'integer' => 0,
					'decimal' => 0,
					'email' => 0,
					'date' => 0,
					'boolean' => 0,
					'text' => 0,
					'likely_type' => 'text'
				);
			}

			$value = trim((string)$value);
			if ($value === '') {
				$profiles[$column]['blank']++;
			} elseif (preg_match('/^-?[0-9]+$/', $value)) {
				$profiles[$column]['integer']++;
			} elseif (preg_match('/^-?[0-9]+\.[0-9]+$/', $value)) {
				$profiles[$column]['decimal']++;
			} elseif (filter_var($value, FILTER_VALIDATE_EMAIL) !== false) {
				$profiles[$column]['email']++;
			} elseif (strtotime($value) !== false && preg_match('/[0-9]{2,4}/', $value)) {
				$profiles[$column]['date']++;
			} elseif (preg_match('/^(yes|no|true|false|0|1)$/i', $value)) {
				$profiles[$column]['boolean']++;
			} else {
				$profiles[$column]['text']++;
			}
		}
	}

	foreach ($profiles as $column => $profile) {
		$best_type = 'text';
		$best_count = -1;
		foreach ($profile as $type => $count) {
			if ($type == 'likely_type') {
				continue;
			}
			if ($type != 'blank' && $count > $best_count) {
				$best_type = $type;
				$best_count = $count;
			}
		}
		$profiles[$column]['likely_type'] = $best_type;
	}

	$result['success'] = true;
	$result['message'] = 'Column types profiled.';
	$result['data'] = array(
		'rows_sampled' => $row_count,
		'columns' => $profiles
	);

	return $result;
}