質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

XAMPP

XAMPP(ザンプ)は、ウェブアプリケーションの実行に必要なフリーソフトウェアをパッケージングしたApacheディストリビューションです。 XAMPPひとつインストールするだけで、Apache、MySQL、PHP、Perlなどのソフトウェアと、 phpMyAdminなどの管理ツール、SQLiteなどのソフトウェアやライブラリモジュールなどを利用することが可能です。

Q&A

解決済

3回答

1501閲覧

PHPを用いてCSVの値を正しく取得したい

mocchiri

総合スコア47

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

XAMPP

XAMPP(ザンプ)は、ウェブアプリケーションの実行に必要なフリーソフトウェアをパッケージングしたApacheディストリビューションです。 XAMPPひとつインストールするだけで、Apache、MySQL、PHP、Perlなどのソフトウェアと、 phpMyAdminなどの管理ツール、SQLiteなどのソフトウェアやライブラリモジュールなどを利用することが可能です。

0グッド

2クリップ

投稿2020/09/06 13:39

編集2020/09/07 00:19

前提・実現したいこと

PHPのfgetcsv関数を使って、CSVの値を正しく取得したいです。
(取得した値は項目ごとにデータベースに登録しますが、今回の質問ではデータベース登録部分は割愛します。)

下記URLを参考にしており、CSVの中身は至ってシンプルです。
簡単に変換できる!PHPでCSVファイルを読み込む方法

名前年齢血液型
太郎21O
ジョン23A
ニキータ32AB
次郎22B

【test.csv】上記のような表でカンマ形式にしたものが保存されています。(文字コードはUTF-8)

CSV

1名前,年齢,血液型 2太郎,21,O 3ジョン,23,A 4ニキータ,32,AB 5次郎,22,B

値を表示するための実際のソースコード

PHP

1// ここにCSV名を入力する (文字コードはUTF-8) 2$csvfilename = "test.csv"; 3 4// 読み込み用にcsvを開く 5$f = fopen($csvfilename, "r"); 6 7while($line = fgetcsv($f)){ 8// 1行ずつCSV項目を表示させる 9 echo "<pre>"; 10 print_r( $line ); 11 echo "</pre>"; 12}

発生している問題

ソースコードもCSVも何も変更していないにも関わらず、プログラム処理するたびに表示結果が変わることがあります。
(結果1および結果2になります。)
どんなときに結果1が出て、どんなときに結果2が出るのか再現性が取れず困っています。

【結果1】正しく値が取得できており、各行3列ずつ表示されている
表示結果1

【結果2】正しく値が取得できておらず、"太郎,21"のように値のなかにカンマが入ってしまっています。結果的に列数が異なる扱いとなります。
表示結果2

補足情報(動作環境)

PHP Version 7.4.9
XAMPP v3.2.4 (Windows)

備考

  • MACの開発環境で試すと、結果2は表示されず、常に結果1となります。(Windowsのみの事象でしょうか)
  • 外部サイトを見ると、fputcsv関数にはバグがあるというような記載もあり、今回のトラブルにあてはまるのかもしれません。

それでは、何卒よろしくお願いします。
先輩エンジニアの皆さまから解決の糸口を拝借できれば幸いです。

追記

検証してみると、全角文字のマルチバイトに起因しているかもしれないと考えています。
(例えそうだとした場合、なぜWindowsのみで起こるのかについては解決しませんが。)
全てのカンマで結果2のようなことが起こるのではなく、いつも特定の文字に繋がるカンマのみにこの事象が発生します。

例) 次郎、太郎のような"郎"。ひらがなの"し"。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

原因が非常に気になるところですけど、暫定対処方法を提示しますw

【test.csv】上記のような表でカンマ形式にしたものが保存されています。(文字コードはUTF-8)

とあるので、fgetcsv() を使用せず、ごく単純に explode() で分割してやればよいです。

投稿2020/09/06 22:59

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tanat

2020/09/06 23:13

データにカンマが含まれない事が保証されているのであれば有りですよね。
mocchiri

2020/09/06 23:57

回答およびコメントありがとうございます。 いまのところ、本番時に運用したいCSVデータのなかにはカンマは含まれていませんので、うまく動作するかもしれません。
guest

0

ベストアンサー

fgetcsvで正しく日本語CSVを扱う場合、ロカールの変更などが必要となります。
その辺りの手間を全て吸収したライブラリがありますので、よろしければご利用ください。
https://github.com/fw3/streams#%E7%84%A1%E9%9B%A3%E3%81%AAcsv%E5%85%A5%E5%87%BA%E5%8A%9B

投稿2020/09/07 08:34

wakabadou

総合スコア31

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mocchiri

2020/09/07 08:39

ライブラリのご提供ありがとうございます。 やはりfgetcsvと日本語(マルチバイト)との相性問題でしょうかね。一度ライブラリを参考にして組み込んでみたいと思います。
wakabadou

2020/09/07 08:46

相性というか、明示的に設定していない場合、適切な設定ではない事が多いため、期待通りに動かないといった形です。 適切に動かないパターンは分かりやすいものだけでこれくらいあります。 https://qiita.com/wakabadou/items/84b48ca12f25fb2fb69c なお、前述のライブラリを参考に一から作る場合「みんなのPHP 現場で役立つ最新ノウハウ!」内、第7章の3「ストリームフィルタを用いた透過的なCSV入出力」に初学者向けの記事を書いておりますので、ぜひご参考になさってください。 4ページなのでサクッと読めると思います。
mocchiri

2020/09/07 12:59

諸々、ご案内ありがとうございます。適切に動かないパターン、これだけあるんですね^^; ひとまずこれらを読んだのち、プログラムを組み替えてみます。
退会済みユーザー

退会済みユーザー

2020/09/08 03:45

こちらの回答のライブラリ使用で直ったってことでしょうか? 原因に興味があるので、差し支えなければ教えてください。
mocchiri

2020/09/08 05:03

こちらのライブラリを使用して治りました。今のところは、質問に記載した結果2の現象は発生しなくなりました。ライブラリ内の全ては確認ができておらず、具体的にどこが原因であったのかについては不明なままです。 localeの設定かもしれませんし、それ以外かもしれません。 ひとまず、本当に不具合が再発しないかという点については不安を拭いきれませんが、このライブラリにて当初の要件を満たすことができたためベストアンサーとしております。
退会済みユーザー

退会済みユーザー

2020/09/08 06:02

大変興味深いコメント、ありがとうございました!
mocchiri

2020/09/08 23:20

一度、質問当時の初期状態にソースを戻し、いただいたダンプを表示すると"C"が出ております。 結果1が表示されており、結果2が出てこなくなりました。 再現性がないので、表示結果が気まぐれに変わります。今は何度試しても結果1が出ております。 引き続きlocale絡みに原因を仮定して調べてみようと思います。回答ありがとうございます。
wakabadou

2020/09/09 02:40

ご確認ありがとうございます。 Cであれば、結果1に固定されるはずですね。 となると結果2になる場合だけロカールが変わっているか、またはバージョン固有の不具合かといったところですか・・・ 上記ライブラリがやたら複雑になっている理由の一つでもあるのですが、PHPでは1リクエスト中に変更したロカールは同一リクエスト内に置いて全体に影響を与えます。 当該の行より前で経路によってロカールが変更されていた場合には、見かけ上ランダムに振舞うことはあるかもしれませんね。
mocchiri

2020/09/09 11:56

ご助言ありがとうございます。 結果2が出ることがあれば、そのときにダンプが何を表示しているのかまたお知らせします。 バージョン固有の不具合かどうかについては、他のWindowsでも試すことができるので検証してみます。引き続き進展があれば、このスレッドでお伝えします。
wakabadou

2020/09/09 15:41

あ、バージョンはPHP側です。 Windows版はPHPのバージョンによって適切に処理できるロカールが変わるという地獄のような仕様があるので・・・ ただ、OS側も併せて確認できるとよりよいですね。
mocchiri

2020/09/09 23:00

>Windows版はPHPのバージョンによって適切に処理できるロカールが変わるという地獄のような仕様があるので・・・ えっ!? それは仕様というより、バグ・・・(笑) こちらも伝え漏れてました。他のWindowsと言っても、それぞれでXamppのバージョンが異なるものをインストールしており、PHPのバージョンも異なります。 ちなみに通常のWindows と Windows Serverの2台ですのでOS検証も併せてできると思います。
guest

0

Windows+IIS+PHPでの同じような事象に近い事象かもしれません(こちらでは再現度100%だったので違うかもしれませんが)

ソースの頭に

PHP

1setLocale(LC_ALL, 'English_United States.1252');

を付けて試してみると治るかもしれません。

投稿2020/09/06 15:45

tanat

総合スコア18727

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mocchiri

2020/09/06 23:51

回答ありがとうございます。一度いただいた内容を使用してみて試してみます。 今回はApacheなので、いただいたIISとの固有の問題とは外れるかもしれません。
tanat

2020/09/07 00:03

> 今回はApacheなので、いただいたIISとの固有の問題とは外れるかもしれません。 そうなんですよね。 毎回再現するわけではないというのはかなり謎な事象なので、うまくいけばラッキーくらいで。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問