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

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

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

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

PHP

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

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

4回答

2738閲覧

PHP&JavascriptでCSVファイルをImportする時にデータが切れてしまいます。

lovelydai

総合スコア38

CSV

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

PHP

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

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

0クリップ

投稿2018/01/31 07:34

編集2018/02/01 03:16

こんにちは、cakephp3基盤で時間割作成システムを作っています。

時間割作成に必要なデータをCSVファイルに入力&出力する機能を作りました。
例えば、科目情報をシステムに入力し、CSVファイルに出力すると以下のようにCSVファイルが生成されます。

"1","2017","7","父母","3","3","7","6","","true","",""
"2","2017","7","研究","4","4","8","7","","true","",""
"3","2017","7","会議","4","4","8","8","","true","",""
"4","2017","7","共・中1組1","1","1","1","1","","true","",""
"5","2017","7","必・中1組1","1","1","1","2","","true","",""

"100","2017","7","必・高3組3","1","1","1","2","","true","",""

このCSVファイルを入力するとシステムにImportされて情報がDBに入ります。
機能は意図通りに動いています。

問題は、このCSVファイルが長くなると(約50行以上)、途中でデータが切れてしまい中途半端な値が入ります。
例えば、上のデータだと、53行目までのデータはImportされますが、その後のデータはPHP側のエラーメッセージを吐き出しで無視されます。エラーメッセージは以下のようです。

2018-01-31 14:40:46 Notice (8): Undefined offset: 4 in [D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\src\Controller\ParticipantController.php, line 475] Request URL: /participant/import Referer URL: http://localhost:8765/participant/import
2018-01-31 14:40:46 Notice (8): Undefined offset: 5 in [D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\src\Controller\ParticipantController.php, line 475] Request URL: /participant/import Referer URL: http://localhost:8765/participant/import  … (以下省略)

chromeのデバッグツールでみたら、ファイルからデータは全て取れてます。たぶん、問題はそれをajaxのpostで送信する時に、サイズの制限又はメモリー容量の問題か、ファイルの途中までしか飲みとれず、DBにInsertする時に配列に値がないという感じで上のメッセージが出されて動かないです。もちろん、50行未満のファイルをImportすると問題なく上手く動きます。
例えば、こんな感じですね。

"53","2017","7","共・高2組2","1","1","1","1","","true","",""
"54","2017","7","必・高, null, null, null, null, null, null, null, null
(元のデータは、"54","2017","7","必・高2組3, ","1","1","1","1","","true","","" です。)

何が問題でしょうか?もしくは解決策はありませんか?
Javascriptのソースコードを添付しますのでもしわかる方教えてください。

Javascript

1var urlPath = window.location.pathname; 2 3var csvContents = {}; 4 5$('#file').change(function(e) 6{ 7e.preventDefault(); 8 9// ファイル名をテキストボックスに表示するためのコード 10$('#csvname').val($(this).val().replace("C:\fakepath\", "")); 11 12// CSVファイルを読み込んで連想配列を作る処理(FileAPI使用可能ブラウザーチェック) 13if(window.File && window.FileReader && window.FileList && window.Blob) 14{ 15 // ファイル情報を取得 16 var fileData = e.target.files[0]; 17 18 //console.log(fileData); // 取得した内容の確認用、問題なくとれてます。 19 20 // CSVファイル以外は処理を止める 21 if(fileData.name.match('.csv$')) 22 { 23 // FileReaderオブジェクトを使ってファイル読み込み 24 var reader = new FileReader(); 25 // ファイル読み込みに成功したときの処理 26 reader.onload = function() 27 { 28 'use strict'; 29 csvContents = CSV.parse(reader.result); 30 // console.log(csvContents); 31 32 } 33 // ファイル読み込みを実行 34 reader.readAsText(fileData); 35 } 36 else 37 { 38 alert('CSVファイルを選択してください。'); 39 $('#csvname').val(''); 40 return; 41 } 42} 43else 44{ 45 file.style.display = 'none'; 46 alert('File APIに対応したブラウザでご確認ください。'); 47 return; 48} 49}); 50 51 52$(function() 53{ 54 // Submit button 55 $('#import').on('submit', function(e){ 56 57 e.preventDefault(); 58 if( $('#csvname').val()=='') 59 { 60 alert('CSVファイルを選択してください。'); 61 $('#csvname').val(''); 62 return; 63 } 64 65 if(!confirm('CSVファイルからマスタ情報の入力を行います。本当によろしいですか?')) 66 { 67 alert('CSVファイル入力をキャンセルしました。'); 68 $('#csvname').val(''); 69 return false; 70 } 71 else 72 { 73 $.ajax({ 74 url:urlPath, 75 type:'POST', 76 cache: false, 77 dataType: 'JSON', 78 data:{'csvContents':csvContents} 79 }) 80 .done(function(data,status){ 81 $('#loader-bg').delay(900).fadeOut(800); 82 $('#loader').delay(600).fadeOut(300); 83 }) 84 .always(function(jqXHR,testStatus){ 85 $('#csvname').val(''); 86 var h = $(window).height(); 87 $('#loader-bg ,#loader').height(h).css('display','block'); 88 location.reload(); 89 }) 90 .fail(function(data,status){ 91 $('#loader-bg').delay(900).fadeOut(800); 92 $('#loader').delay(600).fadeOut(300); 93 }); 94 } 95 96 }); 97});
  • サーバサイドのソースコードも省略して添付します。長いので簡単に説明すると、CSVファイル読んでDBに同じ値があれば更新、なければ採番テーブルからIDXをとってきて新規登録です。また、付加的な情報があるのでサブテーブルにも値を入れるために既存のデータを削除して再登録という感じです。(ですので、かなりDB作業が多いです。)

PHP

1public function import() 2{ 3  if($this->request->is('ajax')) 4  { 5   // Data set 6  $csv_subject_idx = $csvContent[0]; 7  $csv_subject_year = $csvContent[1]; 8   // 省略、作成日や作成者等色んな値を設定します。 9 10    if($customer_idx == $csv_customer_idx && $year == $csv_subject_year) 11 { 12 $subject = $this->Subject->find()->where(['customer_idx' => $csv_customer_idx]) 13 ->andWhere(['subject_idx' => $csv_subject_idx]) 14 15 ->select(['subject_idx', 16 'year', 17 'customer_idx', 18 'subject_name', 19 'subject_short', 20 ]) 21 ->epilog('FOR UPDATE') 22 ->toArray(); 23 if(empty($subject)) 24 { 25 // Insert 26 $master_type = 'SJ'; 27 //採番テーブルのデータを持ってきて入れる 28 29 $query = $this->Masters->find()->where(['customer_idx' => $customer_idx, 'master_type' => $master_type]) 30 ->andWhere(['deleter IS NULL','deleted IS NULL']) 31 ->epilog('FOR UPDATE'); 32 $master = $query->first(); 33 34 if(!empty($master)) 35 { 36 // Master_indexテーブルにデータを追加し、Current_idxを1増加させる。 37 $current_idx = $master->current_idx + 1; 38 $query = $this->Masters->query(); 39 $query->update() 40 ->set(['current_idx' => $current_idx, 41 'modifier' => $modifier, 42 'modified' => $now]) 43 ->where(['customer_idx' => $customer_idx, 'master_type' => $master_type]) 44 ->execute(); 45 } 46 47 //データセット 48 $subject_data = [ 49 'subject_idx' => $current_idx, 50 'year' => $csv_subject_year, 51 'customer_idx' => $customer_idx, 52 'subject_name' => $csv_subject_name, 53 'subject_short' => $csv_subject_short, 54 55 ]; 56 57 $query = $this->Subject->query(); 58 $query->insert([ 59 'subject_idx', 60 'year', 61 'customer_idx', 62 'subject_name', 63 'subject_short', 64 65 ]); 66 $query->values($subject_data); 67 $query->execute(); 68 69 $count_insert = $count_insert + 1; 70 71 // subject_participant Table Delete with subject_idx // Table subject_participant Insert 72 // Table subject_equipment Insert 73 74 else 75 { 76 // Table subject Update 77 // subject_participant Table Delete with subject_idx 78 79 // subject_participant Table Insert 80 81 82 } 83 } 84 unset($participants); 85 } 86 87 // subject_equipment Table Delete with subject_idx 88 89 90 // subject_equipment Table Insert 91 92 } 93 } 94 unset($equipments); 95 } 96 } 97 // 他のソースは省略 98 } 99     } 100}

*追加(2018年2月1日)
PHP.iniの設定でメモリーを128MBー>512MBに、POSTデータのサイズを40MBー>100MBに変更してみましたが結果は同じでした。

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

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

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

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

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

x_x

2018/01/31 08:18

PHP側のコードは提示できないでしょうか?
defghi1977

2018/02/01 03:45

CSVファイルそのものに問題はありませんか?54行目に不正なデータ(null文字等)が入っているとか. また別のCSVファイルでも必ず54行目でエラーが発生するなど.
lovelydai

2018/02/01 05:25

PHPコード追加しました。
lovelydai

2018/02/01 05:27

CSVファイルには問題ありません。例えば400行のデータを50行づつで8つのCSVファイルに分けてImportすると上手くできます。
defghi1977

2018/02/01 09:34

問題を切り分けるために, PHP側で(元のコードをエスケープするなどして)CSVデータ全体を単一の変数に格納し, どこまで(何バイトまで)取得できているのかについて確認して下さい. 全データ取れている→PHPスクリプト側の問題, 途中で切れている→サーバー設定等の問題
lovelydai

2018/02/02 04:12

ありがとうございました。やってみたら値1000個くらいで切れるということがわかりました。
guest

回答4

0

ベストアンサー

使用しているライブラリの開示

問題の再現性の為に、使用しているライブラリのリンク先を開示した方が良いと思います。

過去ログや CSV.parse の名前より、拙作の csv.js (ver.1.0.3)を利用しているものと推察します。

再現性

"53","2017","7","共・高2組2","1","1","1","1","","true","",""
"54","2017","7","必・高, null, null, null, null, null, null, null, null
(元のデータは、"54","2017","7","必・高2組3, ","1","1","1","1","","true","","" です。)

私の環境(csv.js ver.1.0.3 + Google Chrome)では、現象を再現できませんでした。

JavaScript

1console.log(JSON.stringify(CSV.parse('"53","2017","7","共・高2組2","1","1","1","1","","true","",""\r\n"54","2017","7","必・高2組3, ","1","1","1","1","","true","",""'))); // [["53","2017","7","共・高2組2","1","1","1","1","","true","",""],["54","2017","7","必・高2組3, ","1","1","1","1","","true","",""]]

現象を再現可能な最小限のコードをください。
コードを全て書く必要はありません。
問題がCSVのparse処理にあるのなら、そこだけにフォーカスしたコードで良いという事です。

post_max_size (php.ini)

Re: lovelydai さん

投稿2018/02/01 05:04

編集2018/02/01 06:10
think49

総合スコア18156

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

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

lovelydai

2018/02/01 05:35

回答ありがとうございました。ライブラリは拙作の csv.jsで間違いないです。 コードが長いので張り付けるのはできませんでした。ただし、csvのPARSE問題でもないと思っています。400行のデータを50行づつ分けて登録すると上手く動きますのでcsvファイルの問題やCSVパースは大丈夫です。csvファイルから読み取ったデータをサーバサイドに投げるときに、そのデータのサイズか量がでかすぎて途中で切れてしまうのが原因ではないかと予想していますが。
think49

2018/02/01 06:11

軽く検索してみましたが、post_max_size が怪しい気がします。 親記事に追記しました。
think49

2018/02/01 06:16

post_max_size はサーバ側でJSONを正しく受け取れていない前提の原因候補です。 サーバで受け取ったパラメータを echo する等して、「正しく受け取れたか」を確認してみて下さい。 「どの手順まで期待通りに動作しているか」を確認する事が重要だと私は思います。
dit.

2018/02/01 06:36

部外者ですし質問、回答と直接関係のないことで恐縮ですが、拙作とは自分の作品をへりくだっていう言葉です。 think49さんが「つまらないものですが」と言って渡したお土産を、「えぇ、つまらないですね」と受け取っているように聞こえてしまいます。
think49

2018/02/01 06:44

To: lovelydai さん > PHP.iniの設定でメモリーを128MBー>512MBに、POSTデータのサイズを40MBー>100MBに変更してみましたが結果は同じでした。 2018/02/01 15:16のコメントで書いたことの繰り返しになりますが…。 対策を実施して「動作した/動作しない」の切り分けでなく、コードレベルで切り分けしないと原因を追究できないと思いますよ。 ■切り分け事例 - JavaScriptファイルにおいて、全てのコードは期待通りに動作している - PHPファイルにおいて10行目までは期待通りに動作しているが、11行目のコードが期待通りの動作ではない。具体的には関数fooの返り値が~になるはずが、~になってしまう。 To: dit. さん フォローありがとうございます。 返信の中の「拙作」は気になりましたが、本題ではないので受け流していました。 ただ、人に依っては気分を害する事に繋がるので気を付けた方がいいことは確かですね。
dit.

2018/02/01 07:03

think49さん せっかく受け流していたものを掘り返してしまってすみません。 知らないことは恥ではないと思いますが、知らないまま正しい使い方だと思ってしまうことが怖かったのでおせっかいながらコメントしました。ご理解ありがとうございます。
think49

2018/02/01 08:11

To: dit. さん > 知らないまま正しい使い方だと思ってしまうことが怖かったので 仰る通りだと思います。 私は複数の内容をコメントする事で伝わり方がぶれる事(2つ回答して1つだけ返信を貰う)を恐れて、その指摘を見逃しましたが、伝え方次第だと思います。 世の中にはいろんな考えの方がいらっしゃいますので、私が考える事は数ある中の一つに過ぎないと考えています。 私は「自分の考えが絶対的に正しい」と確信する事の危険性を認識していますし、指摘を頂く事で得る気付きや心遣いも大切なものです。 どちらかといえば、私に遠慮して指摘しない選択を選ぶ方が悲しいので、今回で懲りずに積極的に指摘頂けると私は嬉しいです。
lovelydai

2018/02/02 04:21

皆さんありがとうございました。原因は分かりましたが対策はこれからです。 CSVパースは、仕様書にある条件が色々ありまして、それを満たせるものが自分では書けなかったし、探って試した結果が一番良かったというか、仕様書にフィットしたからです。このバグにもつながるですが、このパーサーはパースした結果値が配列になり、それをPOSTで送ると値の制限が1000個までになるということでこんなバグになりました。色々教えてくださいましてありがとうございました。
guest

0

解決ではありませんが、使用していたcsv パーサーが配列値をリターンし、それをPOSTで送る時に、
php.iniのMax_input_varsという設定値にかかってしまったのが原因というのが分かりました。
その設定が1000になってましたので、カラム数個*53行で1007個が超えてしまい、そこで切れると。
一般のテキストだと大丈夫ですが、配列やオブジェクトに送るとVars数の制限がかかるらしいです。

対策としては、Max_input_vars値を増やすか、入力データを減らす又は分けるか、もしくはJavaScript 側からは JSON.stringify などで文字列化してPOSTし、PHP側では json_decode で配列化などするなどがよさそうです。設定変更はサービス提供上できないということなので文字化して送る方法を試してみたいと思います。(仕様書の条件を満たせるかは心配ですが。)

回答頂いた皆さんに感謝です。ありがとうございました。

参考リンク
http://www.webmagazine.kakisiti.co.jp/?p=743

投稿2018/02/02 04:28

lovelydai

総合スコア38

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

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

0

(元のデータは、"54","2017","7","必・高2組3, ","1","1","1","1","","true","","" です。)

"必・高2組3**, **"
この中にカンマが含まれていることが原因で、うまくCSVを解析できていないのではないでしょうか。

カラム内にカンマが含まれても問題無いPHPでの解析処理が必要な気がします。
よかったら、PHP内でのCSV解析処理をいただけませんか?

投稿2018/02/01 04:17

shu_otsuka

総合スコア59

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

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

lovelydai

2018/02/01 05:29

ありがとうございます。しかし、カンマは問題ありませんでした。私のコピペミスです。
guest

0

ファイルを読んでcsvContentsという名前でpostで送るんですよね?
これで送れませんか?

javascript

1$(function() { 2 $('input[type=submit][value=go]').on('click',function(e){ 3 e.preventDefault(); 4 with($(this).closest('form').find('[type=file]').eq(0)){ 5 var fname=prop('name'); 6 var file=prop('files')[0]; 7 } 8 var fr = new FileReader(); 9 fr.onload = function(e) { 10 var fd = new FormData(); 11 fd.append('csvContents',e.target.result); 12 $.ajax({ 13 url:"send.php", 14 type:"post", 15 data:fd, 16 cache:false, 17 processData: false, 18 contentType: false, 19 }).done(function(data){ 20 console.log(data); 21 }).fail(function(xhr,err){ 22 console.log(err); 23 }); 24 }; 25 fr.readAsText(file); 26 }); 27});

HTML

1<form> 2<input type="file" name="hoge"> 3<input type="submit" value="go"> 4</form> 5

投稿2018/01/31 08:29

yambejp

総合スコア114572

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

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

lovelydai

2018/02/01 03:17

回答ありがとうございました。うまく動きませんでした。TT
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問