2013-01-18 2 views
4

한 달에 한 번 FTP로 CSV 파일을받는 웹 사이트가 있습니다. 수년 동안 그것은 ASCII 파일이었습니다. 이제 UTF-8을 한 달에 한 다음 UTF-16BE를 다음 달에 UTF-16LE를 그 다음 달에받습니다. 다음 달에 UTF-32를 얻을 수 있습니다. Fgets는 UTF 파일의 시작 부분에 바이트 순서 표시를 리턴합니다. 문자 인코딩을 자동으로 인식하도록 PHP를 얻으려면 어떻게해야합니까? 나는 mb_detect_encoding을 시도했고 파일 유형에 관계없이 ASCII를 리턴했다. BOM을 읽고 명시 적으로 문자 인코딩을 mb_convert_encoding에 넣도록 코드를 변경했습니다. 이것은 UTF-16LE 인 최신 파일까지 작동했습니다. 이 파일에서 첫 번째 행을 올바르게 읽고 모든 후속 행을 물음표 ("?")로 표시합니다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?fgets로 csv 파일을 읽는 PHP 문자 인코딩 지옥

$fhandle = fopen($file_in, "r"); 
if (fhandle === false) 
    { 
    echo "<p class=redbold>Error opening file $file_in.</p>"; 
    die(); 
    } 

$i = 0; 
while(($line = fgets($fhandle)) !== false) 
{ 
$i++; 

// Detect encoding on first line. Actual text always begins with string "Document" 
if ($i == 1) 
    { 
    $line_start = substr($line, 0, 4); 
    $line_start_hex = bin2hex($line_start); 
    $utf16_start = 'fffe4400'; 
    $utf8_start = 'efbbbf44'; 
    if (strcmp($line_start, 'Docu') == 0) 
     { $char_encoding = 'ASCII'; } 
    elseif (strcmp($line_start_hex, 'efbbbf44') == 0) 
     { 
     $char_encoding = 'UTF-8'; 
     $line = substr($line, 3); 
     } 
    elseif (strcmp($line_start_hex, 'fffe4400') == 0) 
     { 
     $char_encoding = 'UTF-16LE'; 
     $line = substr($line, 2); 
     } 
    elseif (strcmp($line_start_hex, 'feff4400') == 0) 
     { 
     $char_encoding = 'UTF-16BE'; 
     $line = substr($line, 2); 
     } 
    else 
     { 
     echo "<p class=redbold>Error, unknown character encoding. Line =<br>", $line_start_hex, '</p>'; 
     require('../footer.php'); 
     die(); 
     } 
    echo "<p>char_encoding = $char_encoding</p>"; 
    } 

// Convert UTF 
if ($char_encoding != 'ASCII') 
    { 
    $line = mb_convert_encoding($line, 'ASCII', $char_encoding); 
    } 

echo '<p>'; var_dump($line); echo '</p>'; 
} 

출력 :

char_encoding = UTF-16LE 

string(101) "DocumentNumber,RecordedTS,Title,PageCount,City,TransTaxAccountCode,TotalTransferTax,Description,Name 
" 

string(83) "???????????????????????????????????????????????????????????????????????????????????" 

string(88) "????????????????????????????????????????????????????????????????????????????????????????" 

string(84) "????????????????????????????????????????????????????????????????????????????????????" 

string(80) "????????????????????????????????????????????????????????????????????????????????" 

답변

1

나의 제안은 UTF-8 또는 ASCII (당신이 UTF-모든 것을 변환하려는 경우 게시 된 코드는 매우 확실하지 않은 모든 것을 변환하는 것 8 또는 ASCII)

$utf8Line = iconv(mb_detect_encoding($line), 'UTF-8', $line); 

또는 ...

$asciiLine = iconv(mb_detect_encoding($line), 'ASCII', $line); 

mb_detect_encoding 무거운 짐을 덜어 줄 수 있습니다.

+0

불행히도 mb_detect_encoding은 일부 UTF 파일에 대해 "ASCII"를 반환하는 것으로 보입니다. – George

+0

아저씨, 질문 중 그 부분을 놓쳤습니다. 드로잉 보드 –

+0

으로 돌아가지만 ascii는 유니 코드 (하위 255 자)의 하위 집합이므로 쉽게 변환해야합니다. 그냥 ASCII로 변환하고 멀티 바이트 문자열을 사용하지 마십시오. 오, 그리고 FTP 데이터를 제공하는 사람들에게 소리 지른다고 생각한 적이 있습니까? – Amelia

4

엄격한 매개 변수를 사용하여 탐지 할 수있는 가능한 인코딩과 순서를 명시 적으로 전달하십시오. 또한 파일이 UTF-16LE 인 경우 file_get_contents을 사용하십시오. fgets이 처리합니다.

<?php 
header("Content-Type: text/html; charset=utf-8"); 
$input = file_get_contents($file_in); 

$encoding = mb_detect_encoding($input, array(
    "UTF-8", 
    "UTF-32", 
    "UTF-32BE", 
    "UTF-32LE", 
    "UTF-16", 
    "UTF-16BE", 
    "UTF-16LE" 
), TRUE); 

if($encoding !== "UTF-8") { 
    $input = mb_convert_encoding($input, "UTF-8", $encoding); 
} 
echo "<p>$encoding</p>"; 

foreach(explode(PHP_EOL, $input) as $line) { 
    var_dump($line); 
} 

UTF-8 및 UTF-32가 더 제한적이고 UTF-16이 매우 허용되기 때문에 순서가 중요합니다. 거의 임의의 임의의 문자 짝수 바이트의 길이가 유효한 UTF-16입니다.

모든 정보를 유지하는 유일한 방법은 ASCII가 아닌 유니 코드 인코딩으로 변환하는 것입니다.