Last updated: August 28, 2026.
CSV has no universal in-band encoding declaration. Spreadsheet software often guesses, so identify the exporting system’s encoding before converting.
Preserve the original
Detection functions provide hints rather than certainty because short byte sequences can be valid in several encodings. Keep the source and test records containing accents, quotes, and currency symbols.
Parse rows while converting
Use fgetcsv behavior through SplFileObject so quoted commas and embedded line breaks remain valid.
<?php
$input = new SplFileObject(__DIR__ . '/legacy.csv', 'rb');
$output = new SplFileObject(__DIR__ . '/utf8.csv', 'wb');
$input->setFlags(SplFileObject::READ_CSV);
foreach ($input as $row) {
if ($row === [null]) continue;
$row = array_map(
static fn ($v) => mb_convert_encoding((string) $v, 'UTF-8', 'Windows-1252'),
$row
);
$output->fputcsv($row);
}Encoding is not the delimiter
A semicolon-delimited file can still be UTF-8, and a comma-delimited file can still be Windows-1252. Confirm both settings. Validate row counts and the first header after conversion; a BOM can become part of that first field.
Reference: PHP fgetcsv reference.