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

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

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

ASCIIは、米国規格協会(ANSI)が制定したコンピューターの情報交換のための文字コードの一つ。アルファベットや数字などを1文字当たり7ビットで表します。英数字を表示する文字コードの中で最も高い互換性を持ち、多くの通信機器に利用されています。

FTP

FTP(File Transfer Protocol)は、ネットワークでのファイル転送を行うための通信プロトコルの1つである。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Q&A

3回答

2762閲覧

Laravel : FTP接続で取得したCSVデータの列数が合わない

Hir19

総合スコア12

ASCII

ASCIIは、米国規格協会(ANSI)が制定したコンピューターの情報交換のための文字コードの一つ。アルファベットや数字などを1文字当たり7ビットで表します。英数字を表示する文字コードの中で最も高い互換性を持ち、多くの通信機器に利用されています。

FTP

FTP(File Transfer Protocol)は、ネットワークでのファイル転送を行うための通信プロトコルの1つである。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

0グッド

0クリップ

投稿2020/02/21 06:45

編集2020/02/21 08:03

前提・実現したいこと

読み込んだCSVデータの列数を正確なものを取得したい。
(この問題に対しての対処方法を知りたい)

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

全部で739フィールドあるはずなのに、
ものによって1~2フィールド欠けてしまう。

ズレているCSVのデータが以下のようになっていました。

文字コードカンマ区切りデータ
sjis"27229022000","中野","","32-5","",
UTF-8"27229022000","����","","�R�Q��T","",

ずれが発生している該当箇所のレコードの中身

php

1 16 => "27229022000" 2 17 => "中野",",32-5"" 3 18 => ""

処理の順序

1.FTP通信にてcsvファイルをstorage/app 下に保存
2.保存したcsvを読み込む

試したこと

1.処理を切り分けた結果
FTPで取得したCSVの列数はあっているのを確認できたので、
CSVの読み込み部分に問題があることになります。

2.setlocale(LC_ALL, "ja_JP.utf8")から
setlocale(LC_ALL, "Japanese_Japan.932")に変更したが意味なかった;

3.以下のようにコードを変更したがこれも意味がなかった

php

1 public function import() 2 { 3 \Log::channel('batch')->info("START IMPORT" . "\n"); 4 5 setlocale(LC_ALL, "ja_JP.utf8"); 6 $csv_path = 'app/csvs/'. $this->now .'.csv'; 7 8 9 $data = file_get_contents(storage_path($csv_path)); 10 $data = mb_convert_encoding($data, 'UTF-8', 'utf8,SJIS-win'); 11 $temp = tmpfile(); //テンポラリファイルの作成 12 $meta = stream_get_meta_data($temp); //メタデータの取得 13 fwrite($temp, $data); //ファイル書き込み 14 rewind($temp); //ファイルポインタの位置を戻す 15 16 $file = new SplFileObject($meta['uri'], 'rb'); 17 $file->setFlags( 18 \SplFileObject::READ_CSV | 19 \SplFileObject::READ_AHEAD | 20 \SplFileObject::SKIP_EMPTY | 21 \SplFileObject::DROP_NEW_LINE 22 );

CSV読み込みのソースコード

php

1 public function setFile() #FTP先から文字コードsjisのファイルを取得 2 { 3 \Log::channel('batch')->info("START SET CSV" . "\n"); 4 5 Storage::disk('dm_csv')->writeStream( 6 $this->now . '.csv', 7 Storage::disk('ftp')->readStream('data.csv') 8 ); 9 10 \Log::channel('batch')->info("END SET CSV" . "\n"); 11 12 return $this; 13 } 14 15 public function import() 16 { 17 \Log::channel('batch')->info("START IMPORT" . "\n"); 18 19 setlocale(LC_ALL, "ja_JP.utf8"); 20 21 $csv_path = 'app/csvs/'. $this->now .'.csv'; 22 $file = new SplFileObject(storage_path($csv_path), 'rb'); 23 $file->setFlags( 24   \SplFileObject::READ_CSV | 25 \SplFileObject::READ_AHEAD | 26 \SplFileObject::SKIP_EMPTY | 27 \SplFileObject::DROP_NEW_LINE 28 ); 29 30 foreach($file as $val){ 31 var_dump(count($val)); #ここでのカウント数(フィールド)が合わない 32 } 33 34 }

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

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

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

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

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

yukky1201

2020/02/21 07:20

FTPで取得したCSVの列数が既に不足しているのか。 CSVを読み込んで列数をカウントしてら不足してしまうか。 はご自身で切り分けられると思います。 切り分け後にどちらで困っているのかを質問してはどうですか。
Hir19

2020/02/21 07:29

切り分けた結果, FTPで取得したCSVの列数はあっているので、 CSVの読み込み部分に問題があることになります アドバイスありがとうございます。
t_obara

2020/02/21 07:39

あと一歩なので、実際に表示し、目視でカウントしてみてはいかがですか?ご自身の想定とプログラムの動きで差異がある点を見いだせれば良いかと。 その上でも、どのように対処すべきかわからないのであれば、その旨を質問されてはいかがでしょうか。
Hir19

2020/02/21 08:04

様々なことを試しましたが全くうまくいきません... 質問+試したことの変更をしました
guest

回答3

0

これ本当は問題になっているのは"中野"ではないということはないですか? 症状は典型的な
sjisのダメ文字によって「"」がエスケープされて閉じない問題に見えるのですが。
(ダメ文字についての解説はたとえばShift_JISのダメ文字がわかりやすいです)

例えば「飯能」の「能」はSJISの2バイト目が「\」であるダメ文字の一つなのですが、

hoge.csv(文字コードはSJISにします):

csv

1"27229022000","中野","","32−5","", 2"27229022000","飯能","","32−5","",

hoge.php:

php

1<?php 2 3$path = "hoge.csv"; 4$file = new SplFileObject($path, 'rb'); 5$file->setFlags( 6 \SplFileObject::READ_CSV | 7 \SplFileObject::READ_AHEAD | 8 \SplFileObject::SKIP_EMPTY | 9 \SplFileObject::DROP_NEW_LINE 10); 11 12foreach($file as $val){ 13 var_dump(count($val)); #ここでのカウント数(フィールド)が合わない 14 var_dump($val); 15}

と用意して以下のように実行すると「飯能」の方だけおかしくなって、おかしくなり方がまさしくこのパターンです。

console

1% php hoge.php | nkf -w 2/Users/matsui/hoge.php:13: 3int(6) 4/Users/matsui/hoge.php:14: 5array(6) { 6 [0] => 7 string(11) "27229022000" 8 [1] => 9 string(4) "中野" 10 [2] => 11 string(0) "" 12 [3] => 13 string(8) "32−5" 14 [4] => 15 string(0) "" 16 [5] => 17 string(0) "" 18} 19/Users/matsui/hoge.php:13: 20int(4) 21/Users/matsui/hoge.php:14: 22array(4) { 23 [0] => 24 string(11) "27229022000" 25 [1] => 26 string(17) "飯能",",32−5"" 27 [2] => 28 string(0) "" 29 [3] => 30 string(0) "" 31}

これの対策はいくつか考えられて

  • 読み込むファイルをあらかじめこの問題が起きないutf8に変換しておく
  • ファイルはそのままcsvでなく行として読み込んで、行の文字列をutf8にコード変換してからstr_getcsvでパースする
  • あらかじめロケールをsjisにしておく。たとえばsetlocale(LC_ALL, 'ja_JP.sjis');

試したこと2がうまくいかなかった理由

上記対策の3つめに対応しますので考え方としては合っていますが、この場合は
"Japanese_Japan.932"というロケール指定が無効だったからではないかと思います。setlocaleの返り値を確認してください。falseだったら失敗しています。(何が有効かはシステムによりますが手元の環境(MacのCatalina)ではfalseでした)

試したこと3がうまくいかなかった理由

上記対策の1つめに対応しますのでこれもうまくいってよさそうですが、mb_convert_encoding$from_encodingパラメタが'utf8,SJIS-win'と余計なutf8が指定されているので、変換元ファイルの文字コード判定に失敗しているかもしれません。ちゃんと返還されたか確認してみてください。

投稿2020/02/22 01:57

crhg

総合スコア1175

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

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

0

SplFileObjectじゃなくて
fopenfegetcsv使ったり
explodeで分割して・・・みたいな感じで若干古風に実装してみると改善するかも?
(デバッグもしやすくなるし)

3.以下のようにコードを変更したがこれも意味がなかった

この方法で多分行けるんですがこれはfegetcsvで処理するようのコードです。
後半がSplFileObjectのままなので意味がないです

投稿2020/02/21 09:40

編集2020/02/22 04:04
mikkame

総合スコア5036

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

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

0

念のための確認なのですが列数の確認とは下記の認識ですが
Column1|Column2|Column3|・・・|Column738|Column739

そうではなくて下記ということでしたら(こっちは行数ですね)
Row1
Row2



Row738
Row739

PHPのバージョンによって挙動がバラバラな件が気になりました。

投稿2020/02/21 08:07

yukky1201

総合スコア2751

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問