PHPで出力したCSVで文字化け発生(原因と直す方法)

PHP

PHPでCSVを出したときに、Excelで開いたら文字化けしてました。
なぜ文字化けが起こるのかと、「Excelで表示できるCSVファイル」を出力する方法などを書いています。

サンプルコードにはPHPのバージョン8を使って検証しています。
ExcelにはExcel for Macを使っています。

なぜ文字化けが起こるのか?

ExcelでCSVを開いた場合に、UTF-8に対応していないため文字化けが起こるようです。
CSVを読み込むと、Shift_JISで読み込んでしまって文字化けしてしまいます。

PHPで使用されている文字コードはデフォルトで、UTF-8になります。
php.iniのdefault_charset項目に書いています。
この項目の内容については、公式のこちらに詳細が書いてあります。

PHPではUTF-8で出力しているけど、ExcelではShift_JISで読み込もうとするので文字化けしてしまいます。
なので、PHPでShift_JISで出力してあげることにより、文字化けせずに開くようになります。

文字化けさせずに出力するサンプル

csv_output.phpという名前で下記のファイルを作成しました。

<?php
$records = [
    ['ID', '名前', '住所', '電話番号', '性別'],
    [1, '佐藤太郎', '福岡県福岡市', '08011112222', '男'],
    [2, '鈴木花子', '長崎県長崎市', '08011112223', '女'],
    [3, '山田太郎', '大分県大分市', '08011112224', '男'],
];

$outputs = '';
foreach ($records as $recordRow) {
    foreach ($recordRow as $recordValue) {
        $recordValue = mb_convert_encoding($recordValue, "SJIS", "UTF-8");
        $recordValue = "=\"$recordValue\"";
        $outputs .= $recordValue . ',';
    }
    $outputs = rtrim($outputs, ',') . "\n";
}

file_put_contents("output.csv", $outputs);

解説

$recordsにCSV出力したいデータ配列を固定で作成しました。
1行目がCSVヘッダーで、2行目からデータです。ユーザーのデータをCSV出力する感じで適当なデータを作りました。

$outputsに文字列を入れて行って、最後にfile_put_contentsで出力します。
今回はデータとして「,」を含んでいない前提で、値の後に「,」を入れて出力データを作成します。

2次元配列になっているので、foreachを2つ使っています。
$recordRowには1行分のデータが取り出されます。
$recordValueに1行に入っている、それぞれの値が入ってきます。

値を文字化けしないように変換している箇所が下記になります。

$recordValue = mb_convert_encoding($recordValue, "SJIS", "UTF-8");

mb_convert_encoding関数を使用して、”UTF-8″から”SJIS”になるように指定しています。これで文字化けなくなります。
下記の箇所は、後述していますが、先頭が0だった場合の対応です。

$recordValue = "=\"$recordValue\"";

行が終わったら、最後の「,」をrtrim関数で削除して、改行文字をくっつけています。

$outputs = rtrim($outputs, ',') . "\n";

最後にfile_put_contents関数を使用して、”output.csv”という名前で出力しています。

動作確認

PHPコマンドで今回作成したファイルを実行すると、同じディレクトリにcsvファイルを作成してくれます。

$ php csv_output.csv

“output.csv”という名前で、出力されるので開いてみると下記のようになりました。
PHPでCSVの文字化け回避テスト

文字化けせずに開けていることが確認できました。

試しにそのまま出力すると、文字化けするか確認してみます。
データを作る箇所を下記のようにしてみます。

foreach ($recordRow as $recordValue) {
    $outputs .= $recordValue . ',';
}

これで出力すると、このように文字化けしてしまいます。
PHPでCSVの文字化けする場合

Excelで表示すると、数値の前頭0が見えない

Excelで表示する場合に気をつけることとして、カラムに数値のみが入っている場合は、数値として扱われるため先頭0が表示されないといった問題が起こります。
サンプルであったように、電話番号などを出力するときに問題になるかと思います。

サンプルにあるように出力する内容を全て、Excelの式を使って文字列にしてあげれば解決します。
(ただテキストエディタなどで開いた場合は全て「="hoge"」のようになるので、見づらいですが…😅)

$recordValue = "=\"$recordValue\"";

こんな感じで式を使って、文字列として強制すると良いです。

終わりに

今回は「PHPで出力したCSVをExcelで開くと、文字化ける」といったことに対応してみました。
mb_convert_encoding関数を使用することで、簡単に対応することができました。

そもそも、Excelで開くと文字化けますが、テキストエディタなどUTF-8の文字コードに対応したソフトウェアで開くと見ることが可能です。
今回のようにExcelでなくても、ソフトウェアが「使いたい文字コード」に対応していない場合は文字化けが発生してしまいます。

文字化けが発生した場合は、ファイルを開いたソフトウェアの「デフォルト文字コードは?」や「ソフトウェアで文字コードは変更できるのか?」なども考えて、難しい場合は変換処理をしてあげると良いかと思います。

コメント

タイトルとURLをコピーしました