LoginSignup
14
7

More than 5 years have passed since last update.

PHP「fgetcsvはsetlocaleしないと日本語が読めない」は迷信なのか?

Last updated at Posted at 2019-01-15

PHPのfgetcsvはロケールに依存しており、ロケールの環境設定次第では読めないデータが存在するという情報がいくつか存在する。

fgetcsvのロケール問題に言及した記事

まずはどのような情報があるか見てみよう。

【php】fgetcsv()はロケールの設定に依存する at softelメモより:

「”名前”,”住所”,”岐阜”,”愛知”,”東京”」は読めるけど、「名前,住所,岐阜,愛知,東京」は読めない。

fgetcsv関数を文字化け対応 setlocaleの文字コード指定 - [PHP + PHP] ぺんたん infoより:

ID,名前,都道府県ID,電話番号or携帯番号

これをfgetcsv()関数で読み込むと

Array(
   [0] => ID,
   [1] => ,
   [2] => ID,
   [3] => or携帯番号,
)

となります。

PHP5 fgetcsv 日本語文字が消える場合 | Bamboo lath 日々の記録より:

今回問題となった元のデータはこれ

9033,裏面その他(モノクロ),"9033,9034,9035,9036,9037,9038,9039,9040",,サンプル画像は見本になります。<br />記載内容に合わせ、当方にてバランス良くレイアウトをさせていただきます。

今回問題となった箇所はここ

サンプル画像は見本になります。<br />記載内容に合わせ、当方にてバランス良くレイアウトをさせていただきます。

消えた状態

<br />記載内容に合わせ、当方にてバランス良くレイアウトをさせていただきます。

見つけられた範囲で読めないデータを提示している情報源は以上の3つだけだったが、データの提示なしにsetlocaleを使うことを推奨する記事はかなりの数があった。

本当にfgetcsvはsetlocaleしないとだめなのか?

手元のPHP環境(PHP 7.1)ではsetlocaleをしなくてもfgetcsvで問題なくデータが読み込めていたので、 fgetcsvはsetlocaleしないと読めないデータがあるというのは本当なのかという疑問が生まれた。

一応、macOS上のPHPだけでなく、Alpine Linux(localeがない)やUbuntu(localeがC)でも試したが再現しなかった。

また、SJISのCSVでも再現しなかった。

仮説: PHPのあるバージョンからロケール問題がなくなった

fgetcsvでロケールの調整が必要とする記事がPHP5時代のものが多かったので、もしかするとPHPのあるバージョンから上で取り上げたようなロケール問題が解消されているのではないかと考えた。

※ロケール問題が解消されたというのは、setlocaleをしなくてもデータが読み込めるということで、fgetcsvがロケール依存でなくなったという意味ではない。

検証

PHPバージョンでの差異を検証するために、次の検証コードを用意した。ロケールCでUTF-8のCSVデータを読み込むロジックになっている。

<?php

// テスト用CSVの用意
$filename = tempnam(sys_get_temp_dir(), 'CSV');
file_put_contents(
    $filename, 
    "名前,住所,岐阜,愛知,東京\n". // ロケールが正しくないと読めないとされる行
    'ID,名前,都道府県ID,電話番号or携帯番号'."\n". // ロケールが正しくないと読めないとされる行
    '9033,裏面その他(モノクロ),"9033,9034,9035,9036,9037,9038,9039,9040",,サンプル画像は見本になります。<br />記載内容に合わせ、当方にてバランス良くレイアウトをさせていただきます。'
);

// テスト
setlocale(LC_ALL, 'C'); // ロケールをCにする
$file = new SplFileObject($filename, 'r');
$file->setFlags(SplFileObject::READ_CSV);
var_dump(iterator_to_array($file, false));

検証範囲はPHP5.2.1から7.3.1とする。

検証結果

上記の検証コードを複数のPHPバージョンでコードを実行できる環境で実行してみたところ、次の結果が得られた。

  • PHP 5.3.7 - 5.6.38, 7.0.0 - 7.3.1: 再現せず
  • B: PHP 5.2.1 - 5.3.6: ロケール問題が再現した
PHP5.3.7~5.6.38,7.0.0~7.3.1の実行結果
array(3) {
  [0]=>
  array(5) {
    [0]=>
    string(6) "名前"
    [1]=>
    string(6) "住所"
    [2]=>
    string(6) "岐阜"
    [3]=>
    string(6) "愛知"
    [4]=>
    string(6) "東京"
  }
  [1]=>
  array(4) {
    [0]=>
    string(2) "ID"
    [1]=>
    string(6) "名前"
    [2]=>
    string(14) "都道府県ID"
    [3]=>
    string(26) "電話番号or携帯番号"
  }
  [2]=>
  array(5) {
    [0]=>
    string(4) "9033"
    [1]=>
    string(33) "裏面その他(モノクロ)"
    [2]=>
    string(39) "9033,9034,9035,9036,9037,9038,9039,9040"
    [3]=>
    string(0) ""
    [4]=>
    string(156) "サンプル画像は見本になります。<br />記載内容に合わせ、当方にてバランス良くレイアウトをさせていただきます。"
  }
}
PHP5.2.1~5.3.6の実行結果
array(3) {
  [0]=>
  array(5) {
    [0]=>
    string(0) ""
    [1]=>
    string(0) ""
    [2]=>
    string(0) ""
    [3]=>
    string(0) ""
    [4]=>
    string(0) ""
  }
  [1]=>
  array(4) {
    [0]=>
    string(2) "ID"
    [1]=>
    string(0) ""
    [2]=>
    string(2) "ID"
    [3]=>
    string(14) "or携帯番号"
  }
  [2]=>
  array(5) {
    [0]=>
    string(4) "9033"
    [1]=>
    string(0) ""
    [2]=>
    string(39) "9033,9034,9035,9036,9037,9038,9039,9040"
    [3]=>
    string(0) ""
    [4]=>
    string(111) "<br />記載内容に合わせ、当方にてバランス良くレイアウトをさせていただきます。"
  }
}

結論

fgetcsvはsetlocaleしないと読めないデータがあるというのは、PHP5.3.6以下のバージョンで、PHP7の環境が普通の今日現在ではsetlocaleしなくても問題はなさそう。

14
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
7