The best solution I’ve found to this is to open the file, and re-write it with the new encoding before opening it for CSV reading;
function get_encoding($filename){ $encoding=''; $handle = fopen($filename, 'r'); $bom = fread($handle, 2); // fclose($handle); rewind($handle); if($bom === chr(0xff).chr(0xfe) || $bom === chr(0xfe).chr(0xff)){ // UTF16 Byte Order Mark present $encoding = 'UTF-16'; } else { $file_sample = fread($handle, 1000) + 'e'; //read first 1000 bytes // + e is a workaround for mb_string bug rewind($handle); $encoding = mb_detect_encoding($file_sample , 'UTF-8, UTF-7, ASCII, EUC-JP,SJIS, eucJP-win, SJIS-win, JIS, ISO-2022-JP'); } if ($encoding){ stream_filter_append($handle, 'convert.iconv.'.$encoding.'/UTF-8'); } return $encoding; } /** * Decode UTF-16 encoded strings. * * Can handle both BOM'ed data and un-BOM'ed data. * Assumes Big-Endian byte order if no BOM is available. * * @param string $str UTF-16 encoded data to decode. * @return string UTF-8 / ISO encoded data. * @access public * @version 0.1 / 2005-01-19 * @author Rasmus Andersson {@link http://rasmusandersson.se/} * @package Groupies */ function utf16_decode($str, &$be=null) { if (strlen($str) < 2) { return $str; } $c0 = ord($str{0}); $c1 = ord($str{1}); $start = 0; if ($c0 == 0xFE && $c1 == 0xFF) { $be = true; $start = 2; } else if ($c0 == 0xFF && $c1 == 0xFE) { $start = 2; $be = false; } if ($be === null) { $be = true; } $len = strlen($str); $newstr = ''; for ($i = $start; $i < $len; $i += 2) { if ($be) { $val = ord($str{$i}) << 4; $val += ord($str{$i+1}); } else { $val = ord($str{$i+1}) << 4; $val += ord($str{$i}); } $newstr .= ($val == 0x228) ? "\n" : chr($val); } return $newstr; } $newFilename = 'path/to/uploaded/file.scv'; $encoding = get_encoding($newFilename); /* This is the fix for UTF-16 files which come in from iPad */ if($encoding == 'UTF-16'){ $utf8Contents = utf16_decode(file_get_contents($newFilename)); $resource = fopen($newFilename, 'w'); /* Write the file over the uploaded one */ fwrite($resource, pack("CCC",0xef,0xbb,0xbf)); fwrite($resource, $utf8Contents); } if (($handle = fopen($newFilename, "r")) !== false) { while (($data = fgetcsv($handle)) !== false) { ... } }