4

月に一度 FTP で CSV ファイルを受信する Web サイトがあります。何年もの間、それは ASCII ファイルでした。現在、UTF-8 を 1 か月受け取り、次に UTF-16BE を受け取り、その翌月に UTF-16LE を受け取っています。来月はUTF-32になるかも。Fgets は、UTF ファイルの先頭にあるバイト オーダー マークを返します。PHP に文字エンコーディングを自動的に認識させるにはどうすればよいですか? mb_detect_encoding を試したところ、ファイルの種類に関係なく ASCII が返されました。BOM を読み取るようにコードを変更し、明示的に文字エンコーディングを mb_convert_encoding に入れました。これは、UTF-16LE である最新のファイルまで機能しました。このファイルでは、最初の行が正しく読み取られ、後続の行はすべて疑問符 ("?") として表示されます。私は何を間違っていますか?

$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) "????????????????????????????????????????????????????????????????????????????????"
4

2 に答える 2

4

検出する順序と可能なエンコーディングを明示的に渡し、strict パラメータを使用します。またfile_get_contents、ファイルが UTF-16LE の場合はを使用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 ではなく Unicode エンコーディングに変換することです。

于 2013-01-19T10:09:23.907 に答える
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あなたはあなたのために重い持ち上げをするために活用することができます

于 2013-01-18T21:10:40.570 に答える