こんにちは、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に変更してみましたが結果は同じでした。
回答4件
あなたの回答
tips
プレビュー