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

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

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

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

PHP

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

Q&A

1回答

4132閲覧

php CSVファイルを読み込んでカンマ区切りで分解し配列に正しく入れたい。

Sai-fl

総合スコア0

CSV

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

PHP

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

0グッド

2クリップ

投稿2020/08/27 05:24

編集2020/08/27 23:43

前提・実現したいこと

手元の環境(Windows10のIIS,PHP7.4.1,CSVはUTF-8,改行コードはCRLF)
PHPでcsvファイル読み込んで出力をする画面を作っています。

発生している問題・エラーメッセージ

CSVファイルを読み込んでカンマ区切りで分解し配列にしているがうまく区切られない。

該当のソースコード

PHP

php

1<?php 2 3 $filePath = './data.csv'; 4 5 if(file_exists($filePath) == true){ 6 7 //書き込みの件数 8 $count = 0; 9 10 //CSVファイルを読み込んでカンマ区切りで分解し配列にする 11 $fp = fopen($filePath, 'rb'); 12 while($fields = fgetcsv($fp)){ 13 $count++; 14 print("フィールド0:{$fields[0]}"); 15 print('<br/>'); 16 print("フィールド1:{$fields[1]}"); 17 print('<br/>'); 18 print("フィールド2:{$fields[2]}"); 19 print('<br/>'); 20 print("フィールド3:{$fields[3]}"); 21 print('<br/>'); 22 } 23 24 //ファイルクローズ 25 fclose($fp); 26 } 27?> 28

試したこと

補足情報(FW/ツールのバージョンなど)

■data.csvの中身

"あああああ","ああさあ","入力して下さいあささ",2020/08/27 02:14:43

■画面に表示された内容

フィールド0:あああああ
フィールド1:ああさあ",入力して下さいあささ"
フィールド2:2020/08/27 02:14:43
フィールド3:

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

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

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

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

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

m.ts10806

2020/08/27 05:28

コードはマークダウンのcode機能を利用してご提示ください。
guest

回答1

0

回答

ソースの最初に

PHP

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

と追記するとも無く動作しました。

IIS+PHP固有の問題っぽいのでこれ以上深掘りしませんが、
Windows版 PHP7 の環境で CSV アップロードに失敗する #1780

が参考になりました。

個人的には、どうしてもIISを使わないといけない理由がない限りはApacheなりnginxなりで動かすか、仮想環境でLAMP環境を作る方がトラブルが少なくて幸せになれると思います。


(追記)手元の環境(CentOS7,PHP7.3.19,CSVはUTF-8,改行コードはLF)でテストをしてみたら、質問中のコードで特に問題無く動きました。

実行環境(OS、PHPバージョン)文字コード、改行コード等を提示されるとより適切な回答がつくかと思います。
(データを改行コードと文字コードが見えるエディタで作り直しても良いかもしれません)

実行結果

フィールド0:あああああ<br/>フィールド1:ああさあ<br/>フィールド2:入力して下さいあささ<br/>フィールド3:2020/08/27 02:14:43<br/>

以下、追記前の回答

関数の挙動が良くわからない場合は
PHPマニュアル fgetcsv
を参照して、オプションを色々試してみてください。

多分この辺

delimiter オプションの delimiter パラメータで、フィールドのデリミタ (1 文字のみ) を設定します。 enclosure オプションの enclosure パラメータで、フィールド囲いこみ文字 (1 文字のみ) を設定します。

未テストですが

PHP

1while($fields = fgetcsv($fp)){

PHP

1while($fields = fgetcsv($fp,0,',','"')){

で行けそうな気がします。
(追記)

  • 第二、第三、第四引数はそれぞれデフォルト値と同じものを明示的に指定しているだけです

投稿2020/08/27 06:17

編集2020/08/28 17:50
tanat

総合スコア18713

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

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

Sai-fl

2020/08/27 09:08

各種環境について情報が不足していました。 手元の環境(Windows10のIIS,PHP7.4.1,CSVはUTF-8,改行コードはCRLF) 先ほど教えてもらったオプションを利用しても結果変わらずでした。 while($fields = fgetcsv($fp,0,',','"')){
tanat

2020/08/27 09:14

CSVのデータが実は "あああああ",ああさあ","入力して下さいあささ",2020/08/27 02:14:43 という感じで二つ目のフィールドの先頭のダブルクォートが抜けてたりしませんかね? (挙動としてはそういう理由に見えます) 質問文にあるテキストをそのままコピーして、新たに作ったCSVで試してみるとどうなるでしょうか。
tanat

2020/08/27 09:15

環境については質問文に追記された方が他の回答者の目に留まりますので追記されることをお勧めします。(他の回答のコメントまで見る人はあんまりいないと思います)
Sai-fl

2020/08/27 23:53

質問文に追記しました、ありがとうございます。 CSVのデータには問題なくダブルコーテーションは入っていますね。 あまりこういう挙動は見たいことがないので原因がわからないでいます。
tanat

2020/08/28 00:54

謎な挙動ですね。 例えば以下のコードだと結果はどうなりますか? <?php $filePath = './data.csv'; if(file_exists($filePath) == true){ //書き込みの件数 $count = 0; file_put_contents($filePath,"あああああ","ああさあ","入力して下さいあささ",2020/08/27 02:14:43); //CSVファイルを読み込んでカンマ区切りで分解し配列にする $fp = fopen($filePath, 'rb'); while($fields = fgetcsv($fp)){ $count++; print("フィールド0:{$fields[0]}"); print('<br/>'); print("フィールド1:{$fields[1]}"); print('<br/>'); print("フィールド2:{$fields[2]}"); print('<br/>'); print("フィールド3:{$fields[3]}"); print('<br/>'); } //ファイルクローズ fclose($fp); }
Sai-fl

2020/08/28 02:42

サンプルありがとうございます。 以下の部分でParse error: Invalid numeric literal inが発生します。 file_put_contents($filePath,"あああああ","ああさあ","入力して下さいあささ",2020/08/27 02:14:43);
tanat

2020/08/28 02:55

ああ、すみません $csv = '"あああああ","ああさあ","入力して下さいあささ",2020/08/27 02:14:43)'; file_put_contents($filePath,$csv); としてください
Sai-fl

2020/08/28 03:46

あ、そうですよね、ちょっと試行錯誤試していました。 表示はやはり以下のようになりました。 フィールド0:あああああ フィールド1:ああさあ",入力して下さいあささ" フィールド2:2020/08/27 02:14:43) フィールド3:
tanat

2020/08/28 03:52

PHPから直接書き込んでもダメってことですね・・・ これはさっぱりわからないですね。。。 特に根拠は無いですが SqlFileObject::fgetcsv() https://www.php.net/manual/ja/splfileobject.fgetcsv.php を使うとうまくいったりするかもしれません。
Sai-fl

2020/08/28 05:19

ありがとうございます。 この関数?は今回の場合だと、どの内容を入れ替えれば実装ができますか?
tanat

2020/08/28 07:21 編集

while($fields = fgetcsv($fp)){ からの一連の流れをを https://www.php.net/manual/ja/splfileobject.fgetcsv.php の $file = new SplFileObject("data.csv"); while (!$file->eof()) { var_dump($file->fgetcsv()); } を参考にして置き換えてみてください。 多分こんな感じ(未テスト) $file = new SplFileObject($filePath); while (!$file->eof()) { $fields = $file->fgetcsv(); $count++; print("フィールド0:{$fields[0]}"); print('<br/>'); print("フィールド1:{$fields[1]}"); print('<br/>'); print("フィールド2:{$fields[2]}"); print('<br/>'); print("フィールド3:{$fields[3]}"); print('<br/>'); }
Sai-fl

2020/08/28 08:48

実装してみましたがやはり変化無しでした。 どうもうまくいかないですね、原因がよくわからないのが気持ち悪いですね。
m.ts10806

2020/08/28 09:33

IISじゃなかったらどうなりますか? XAMPPでも立ててやってみてください。
tanat

2020/08/28 10:05

そうですね。環境依存の可能性が高いですね。 あとは、 1. ファイルにBOMがついちゃって無いか確認する(ソース中でファイル作った場合でも駄目なので可能性としては低いと思います) 2. ひらがなを全て半角アルファベットに変更して試してみて切り分けをする くらいしか思いつきません。 sjisだといくらでも問題発生しそうなんですけどね。 https://www.softel.co.jp/blogs/tech/archives/2331
kyoya0819

2020/08/28 12:45 編集

再現しなかったもの Ubuntu PHP7.4.1 CRLF UTF-8(Apache) Windows10 PHP7.4.8 CRLF UTF-8(ビルトインサーバー) 再現したもの Windows10 PHP7.4.8 CRLF UTF-8(IIS)
tanat

2020/08/28 12:46

> kyoya0819さん 検証ありがとうございます! IIS+PHP固有の事象なんですかね。。。 私も試してみます
kyoya0819

2020/08/28 12:48

tanatさんの未検証のものも特に効果はありませんでした。。。 <?php $filePath = './data.csv'; if(file_exists($filePath) == true){ //書き込みの件数 $count = 0; $csv = '"あああああ","ああさあ","入力して下さいあささ",2020/08/27 02:14:43'; file_put_contents($filePath,$csv); //CSVファイルを読み込んでカンマ区切りで分解し配列にする $fp = fopen($filePath, 'rb'); while($fields = fgetcsv($fp,0,',','"')){ $count++; print("フィールド0:{$fields[0]}"); print('<br/>'); print("フィールド1:{$fields[1]}"); print('<br/>'); print("フィールド2:{$fields[2]}"); print('<br/>'); } //ファイルクローズ fclose($fp); } phpinfo();
kyoya0819

2020/08/28 12:50 編集

上書き文字列内のクオーテーションとダブルクオーテーションを逆にすると動作しました。
tanat

2020/08/28 12:52

ダブルクォートの解釈がおかしな感じですね IISでロケールとCSVの問題は色々見かけるので https://github.com/EC-CUBE/ec-cube/issues/1780 ロケールと文字コードを厳密に一致させても解決するかもですね
tanat

2020/08/28 17:51

手元のIIS環境だと setLocale(LC_ALL, 'English_United States.1252'); で解決しました。 試してみてください
退会済みユーザー

退会済みユーザー

2020/08/28 19:45

> tanat さん すげーw これ、再現したってことですか? 興味本位で恐縮ですが、差し支えなければ再現条件を教えてもらえますか?
tanat

2020/08/29 01:11

> te2jiさん win10pro64bit+IIS+PHP7.4.9(x86)で ini等はデフォルトで再現しました。 kyoya0819さんのコメント > 環境構築の参考元 > http://mztm.jp/2017/10/12/windows10iisphp/ の通りで再現出来ると思います。 どうやら、ダブルクォートの直前にマルチバイト文字があるとダブルクォートだと認識出来ないようです。
退会済みユーザー

退会済みユーザー

2020/08/29 01:16

ありがとうございます! > ダブルクォートの直前にマルチバイト文字があるとダブルクォートだと認識出来ないようです。 マジか。。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問