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”という名前で、出力されるので開いてみると下記のようになりました。
文字化けせずに開けていることが確認できました。
試しにそのまま出力すると、文字化けするか確認してみます。
データを作る箇所を下記のようにしてみます。
foreach ($recordRow as $recordValue) {
$outputs .= $recordValue . ',';
}
これで出力すると、このように文字化けしてしまいます。
Excelで表示すると、数値の前頭0が見えない
Excelで表示する場合に気をつけることとして、カラムに数値のみが入っている場合は、数値として扱われるため先頭0が表示されないといった問題が起こります。
サンプルであったように、電話番号などを出力するときに問題になるかと思います。
サンプルにあるように出力する内容を全て、Excelの式を使って文字列にしてあげれば解決します。
(ただテキストエディタなどで開いた場合は全て「="hoge"」
のようになるので、見づらいですが…😅)
$recordValue = "=\"$recordValue\"";
こんな感じで式を使って、文字列として強制すると良いです。
終わりに
今回は「PHPで出力したCSVをExcelで開くと、文字化ける」といったことに対応してみました。
mb_convert_encoding
関数を使用することで、簡単に対応することができました。
そもそも、Excelで開くと文字化けますが、テキストエディタなどUTF-8
の文字コードに対応したソフトウェアで開くと見ることが可能です。
今回のようにExcelでなくても、ソフトウェアが「使いたい文字コード」に対応していない場合は文字化けが発生してしまいます。
文字化けが発生した場合は、ファイルを開いたソフトウェアの「デフォルト文字コードは?」や「ソフトウェアで文字コードは変更できるのか?」なども考えて、難しい場合は変換処理をしてあげると良いかと思います。
コメント