前回の続きで、PHPを使ってメールでアップロードしたCSVファイルでデータベースを更新する処理を作ってみます
行う内容としては
1,CSVファイルの解析
2,対象となるデータベース、テーブルの特定
3,データベースの更新(追加)
4,結果のレポート
となります
まず、CSVファイルの解析は
ファイルを開いて、データーの取得です
ファイルの大きさにもよるのですが
PHPには、CSVを読み込む関数があるので、それを使ってみる
また、1行目がフィールド名になっている事が多いので、
1行目は特別とします
データは、以下のような形式になります
1 2 3 |
"日付","摘要","入金金額","出金金額","残高","メモ" "20240831","Visaデビット利用 ダイソー/NFC 承認番号:450835 TID:584244293990318","","1100","97402","" "20240830","振込 ストライプジヤパン(カ","19170","","106302","" |
ファイルを扱う場合、文字コードも意識しないと行けないのですが
文字化けに注意しながら進めてみる
ファイル名を
inp_file.csv
とすると
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php // CSVファイルを読み込みモードで開く $fp = fopen("inp_data.csv", "r"); // ファイルを1行ずつ取得する while (($line = fgetcsv($fp)) !== FALSE) { //dump($line); //print("1"); //print_r($line); //print("2"); //print_r(mb_convert_encoding($line,"sjis","utf-8")); //print("3"); //print_r(mb_convert_encoding($line,"utf-8","sjis")); //print("4"); //print_r(mb_convert_encoding($line,"sjis","auto")); //print("5"); //print_r(mb_convert_encoding($line,"utf-8","auto")); これで、上手く行った //print("6"); for ($c = 0; $c < count($line); $c++) { $str = mb_convert_encoding($line[$c] ,"utf-8","auto"); // Call to undefined function mb_convert_encoding() // sudo apt-get install php-mbstring ダメ // sudo apt-get install php7.4-mbstring 上手く行った // Ubuntu 24.04にて print($str); } } fclose($fp); // 参考 https://qiita.com/web-serve/items/164329e512f6ff7e9bdc ?> |
まずは、データベースを固定して
追加の文章を作ってみよう
insertとupdateがあるが全てinsertとしよう
ただし、以前にアップロードしたデータについては
除外することにする
1行目のヘッダーとカラムの対応表が必要になる
INSERT INTO テーブル名 (列名1, 列名2,…) VALUES (値1, 値2,…);
となるので、列名と値の対応が必要になる
列名を、ヘッダーに合わせて、順番を変更するか
あるいは、確定して、行く方法もあるが、順番は確定として
進めることにする
次に、重複を避ける方法として、レコードを特定するユニークなコードがあればいいが、必ずしもあるとは、限らないため
データの一致にて行うことにする
つまり、フィールドが全て、同じ場合は、見送りとし
カラムがわずかでも変わっていた場合には、新規に追加するものとする
INSERT INTO テーブル名 (列名1, 列名2,…) VALUES
まで、固定で、
(値1, 値2,…);
を、入力したデータにて変更するよになる
SQL文を、文字列で作成する方法もあるが、エラーチェックは、インジェクション処理などの処理を含まれた、処理を行う
データベース名
openbook
テーブル名
tp_gmo_corp
“日付”,”摘要”,”入金金額”,”出金金額”,”残高”,”メモ”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
CREATE TABLE `tp_gmo_corp` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `tp_datetime` VARCHAR(2000) NOT NULL COLLATE 'utf8mb4_general_ci', `tp_month` VARCHAR(100) NOT NULL DEFAULT '2024' COLLATE 'utf8mb4_general_ci', `tp_summary` VARCHAR(2000) NOT NULL COLLATE 'utf8mb4_general_ci', `tp_deposit` INT(11) NOT NULL DEFAULT '0', `tp_investment` INT(11) NOT NULL DEFAULT '0', `tp_balance` INT(11) NOT NULL DEFAULT '0', `tp_type` INT(11) NOT NULL DEFAULT '0', `tp_memo` VARCHAR(200) NOT NULL COLLATE 'utf8mb4_general_ci', `pub_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) USING BTREE ) COLLATE='utf8mb4_general_ci' ENGINE=InnoDB ; |
データベースへの書き込み(insert)はで行う
文字化けしたので
mb_convert_encoding($line,”utf-8″,”auto”)
を、追加した所、エラーとなった
sudo apt-get install php-mbstring
で、行ったが、やはりダメ
sudo apt install php7.4-mbstring
で、上手く行った
次は
could not find driver
のエラーになった
sudo apt-get install php7-mysql
では、読み込めなかったので
sudo apt-get install php7.4-mysql
で、解消した
これで、CSVに従って書き込んでいたら
数値カラムのInsertでエラーになった
$culum=””;
で、数値のカラムに入れるとエラーになる
””のときは、0に書き換える必要があるとると
カラムの属性情報も管理しないといけない
手抜きは、できないようである
まずは、ハードコーディングで、サンプルを書き込む所まで
行ってみる
ファイルを開けて、追加してみる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?php try { $pdo = new PDO('mysql:dbname=openbook;host=xxx.xxx.xxx.xxx;charset=utf8mb4', 'acountname', 'password', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]); } catch (PDOException $e) { exit($e->getMessage()); } // ヘッダー // "日付","摘要","入金金額","出金金額","残高","メモ" // 実データ // "20240831","Visaデビット利用 ダイソー/NFC 承認番号:450835 TID:584244293990318","","1100","97402","" // 1行動作検証 $tp_datetime="20240831"; $tp_summary="Visaデビット利用 ダイソー/NFC 承認番号:450835 TID:584244293990318__"; //$tp_deposit=""; 数値のカラムだとエラーになる $tp_deposit="0"; $tp_investment="1100"; $tp_balance="97402"; $tp_memo=""; $sql = 'insert into tp_gmo_corp (tp_datetime,tp_summary,tp_deposit,tp_investment,tp_balance,tp_memo) values (?,?,?,?,?,?)'; $stmt = $pdo->prepare($sql); $flag = $stmt->execute(array($tp_datetime,$tp_summary,$tp_deposit,$tp_investment,$tp_balance,$tp_memo)); // could not find driver // sudo apt-get install php7-mysql こちらはだめ // sudo apt-get install php7.4-mysql こちらで、できた print($flag); |
2つの処理を合体してみよう
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<?php try { $pdo = new PDO('mysql:dbname=openbook;host=xxx.xxx.xxx.xxx;charset=utf8mb4', 'acountname', 'password', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]); } catch (PDOException $e) { exit($e->getMessage()); } // CSVファイルを読み込みモードで開く $fp = fopen("inp_data.csv", "r"); // ファイルを1行ずつ取得する $fl=0; while (($line = fgetcsv($fp)) !== FALSE) { for ($c = 0; $c < count($line); $c++) { $str = mb_convert_encoding($line[$c] ,"utf-8","auto"); print($str); } if($fl != 0){// ヘッダーは除外 $tp_datetime="20240831"; $tp_datetime=$line[0]; $tp_summary="Visaデビット利用 ダイソー/NFC 承認番号:450835 TID:584244293990318__"; $tp_summary=mb_convert_encoding($line[1] ,"utf-8","auto"); $tp_deposit="0"; $tp_deposit=$line[2]; if($line[2] == ''){ $tp_deposit="0"; } $tp_investment="1100"; $tp_investment=$line[3]; if($line[3] == ''){ $tp_investment="0"; } // intのカラムは全て行わないと行けない $tp_balance="97402"; $tp_balance=$line[4]; $tp_memo=""; $tp_memo=$line[5]; $sql = 'insert into tp_gmo_corp (tp_datetime,tp_summary,tp_deposit,tp_investment,tp_balance,tp_memo) values (?,?,?,?,?,?)'; $stmt = $pdo->prepare($sql); $flag = $stmt->execute(array($tp_datetime,$tp_summary,$tp_deposit,$tp_investment,$tp_balance,$tp_memo)); print($flag); } $fl=1; } fclose($fp); ?> |
これで、複数行の挿入ができた
次に、重複チェックを行う
既に登録済の行は登録しないようにする
行を特定する、カラムがないので、全てのカラムの一致で、除外するようにしてみる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
<?php try { $pdo = new PDO('mysql:dbname=openbook;host=xxx.xxx.xxx.xxx;charset=utf8mb4', 'acountname', 'password', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]); } catch (PDOException $e) { exit($e->getMessage()); } // CSVファイルを読み込みモードで開く $fp = fopen("inp_data.csv", "r"); // ファイルを1行ずつ取得する $fl=0; while (($line = fgetcsv($fp)) !== FALSE) { for ($c = 0; $c < count($line); $c++) { $str = mb_convert_encoding($line[$c] ,"utf-8","auto"); print($c); print("="); print($str); } if($fl != 0){// ヘッダーは除外 $tp_datetime="20240831"; $tp_datetime=$line[0]; $tp_summary="Visaデビット利用 ダイソー/NFC 承認番号:450835 TID:584244293990318__"; $tp_summary=mb_convert_encoding($line[1] ,"utf-8","auto"); $tp_deposit="0"; $tp_deposit=$line[2]; if($line[2] == ''){ $tp_deposit="0"; } $tp_investment="1100"; $tp_investment=$line[3]; if($line[3] == ''){ $tp_investment="0"; } $tp_balance="97402"; $tp_balance=$line[4]; $tp_memo=""; $tp_memo=$line[5]; // ここから、登録済か調べてみる $sql="select count(*) from tp_gmo_corp where "; $sql=$sql."tp_datetime= :tp_datetime "; $sql=$sql."and tp_summary= :tp_summary "; $sql=$sql."and tp_deposit= :tp_deposit "; $sql=$sql."and tp_investment= :tp_investment "; $sql=$sql."and tp_balance= :tp_balance "; $sql=$sql."and tp_memo= :tp_memo "; // print($sql); $stmt = $pdo->prepare($sql); $stmt->bindValue(':tp_datetime', $tp_datetime , PDO::PARAM_STR); $stmt->bindValue(':tp_summary', $tp_summary , PDO::PARAM_STR); $stmt->bindValue(':tp_deposit', $tp_deposit , PDO::PARAM_INT); $stmt->bindValue(':tp_investment', $tp_investment , PDO::PARAM_INT); $stmt->bindValue(':tp_balance', $tp_balance , PDO::PARAM_INT); $stmt->bindValue(':tp_memo', $tp_memo , PDO::PARAM_STR); $stmt->execute(); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); // 参考 http://hono-wp.seesaa.net/article/411183815.html // https://qiita.com/wakahara3/items/d7a3674eecd3b021a21e print_r($result); print($result[0]["count(*)"]); if($result[0]["count(*)"]==0){ //未登録なので、登録 print("Write"); $sql = 'insert into tp_gmo_corp (tp_datetime,tp_summary,tp_deposit,tp_investment,tp_balance,tp_memo) values (?,?,?,?,?,?)'; $stmt = $pdo->prepare($sql); $flag = $stmt->execute(array($tp_datetime,$tp_summary,$tp_deposit,$tp_investment,$tp_balance,$tp_memo)); print($flag); } if($result[0]["count(*)"]=!0){ // 登録済なので、見送り print("Send"); } } $fl=1; } fclose($fp); ?> |
一応できたが、データ依存性が大きいので、これをいかに、汎用化するか
まずは、ヘッダーにより、フィールドの定義を行う
これをもとに、前回のプログラムを書き換えてみます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
<?php $keyname="tp_gmo_corp"; //GOM法人口座 $keyname="tp_gmo_priv"; //GMO個人口座 $keyname="tp_stripe"; //Stripe $keyname="tp_paypal"; //Pyapal $keyname="tp_gmo_priv"; // 今回 // 縦型がいいか、横型がいいか 横型のORマッパー形式 $tabledic=array(); $tabledic["tp_gmo_corp"]["tabelename"]="tp_gmo_corp"; $tabledic["tp_gmo_corp"]["culumzok"]=array(1,1,0,0,0,1); $tabledic["tp_gmo_corp"]["culumselect"]=array(1,1,1,1,1,1); $tabledic["tp_gmo_corp"]["culumcheck"]=array(1,1,1,1,1,1); $tabledic["tp_gmo_corp"]["culumname"]=array("tp_datetime","tp_summary","tp_deposit","tp_investment","tp_balance","tp_memo"); $tabledic["tp_gmo_corp"]["filename"]="gmo_corp.csv"; $tabledic["tp_gmo_priv"]["tabelename"]="tp_gmo_priv"; $tabledic["tp_gmo_priv"]["culumzok"]=array(1,1,0,0,0,1); $tabledic["tp_gmo_priv"]["culumselect"]=array(1,1,1,1,1,1); $tabledic["tp_gmo_priv"]["culumcheck"]=array(1,1,1,1,1,1); $tabledic["tp_gmo_priv"]["culumname"]=array("tp_datetime","tp_summary","tp_deposit","tp_investment","tp_balance","tp_memo"); $tabledic["tp_gmo_priv"]["filename"]="gmo_priv.csv"; $tabledic["tp_stripe"]["tabelename"]="tp_stripe"; $tabledic["tp_stripe"]["culumzok"]=array(1,1,0,0,0,1); $tabledic["tp_stripe"]["culumselect"]=array(1,1,1,1,1,1); $tabledic["tp_stripe"]["culumcheck"]=array(1,1,1,1,1,1); $tabledic["tp_stripe"]["culumname"]=array("tp_datetime","tp_summary","tp_deposit","tp_investment","tp_balance","tp_memo"); $tabledic["tp_stripe"]["filename"]="stripe.csv"; $tabledic["tp_paypal"]["tabelename"]="tp_paypal"; $tabledic["tp_paypal"]["culumzok"]=array(1,1,0,0,0,1); $tabledic["tp_paypal"]["culumselect"]=array(1,1,1,1,1,1); $tabledic["tp_paypal"]["culumcheck"]=array(1,1,1,1,1,1); $tabledic["tp_paypal"]["culumname"]=array("tp_datetime","tp_summary","tp_deposit","tp_investment","tp_balance","tp_memo"); $tabledic["tp_paypal"]["filename"]="paypal.csv"; $tabelename=$tabledic[$keyname]["tabelename"]; $culumzok=$tabledic[$keyname]["culumzok"]; $culumselect=$tabledic[$keyname]["culumselect"]; $culumcheck=$tabledic[$keyname]["culumcheck"]; $culumname=$tabledic[$keyname]["culumname"]; $filename=$tabledic[$keyname]["filename"]; print_r($tabelename); print("----\n"); print_r($culumzok); print("----\n"); print_r($culumselect); print("----\n"); print_r($culumcheck); print("----\n"); print_r($culumname); print("----\n"); print_r($filename); print("----\n"); //exit("ok"); // 2回目はandがつこので、 最初だけの処理で行う // foreach php 最初だけ // 参考 https://qiita.com/_hiro_dev/items/fc48722eb518c6382895 $sql_select="select count(*) from ".$tabelename." where "; foreach ($culumname as $index => $culum) { if(!($index === array_key_first($culumname))){ // 1回目以降 $sql_select=$sql_select."and "; } $sql_select=$sql_select.$culum."= :".$culum." "; } print($sql_select); //$Sql = "insert into ".$tabelename."tp_gmo_corp (tp_datetime,tp_summary,tp_deposit,tp_investment,tp_balance,tp_memo) values (?,?,?,?,?,?)"; $sql_insert="insert into ".$tabelename."("; $sql_insert2=""; foreach ($culumname as $index => $culum) { if(!($index === array_key_first($culumname))){ // 1回目以降 $sql_insert=$sql_insert.", "; $sql_insert2=$sql_insert2.","; } $sql_insert=$sql_insert.$culum; $sql_insert2=$sql_insert2."?"; } $sql_insert=$sql_insert.") values (".$sql_insert2.")"; print($sql_select); print("\n"); print($sql_insert); //exit("ok"); try { $pdo = new PDO('mysql:dbname=openbook;host=xxx.xxx.xxx.xxx;charset=utf8mb4', 'acountname', 'password', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]); } catch (PDOException $e) { exit($e->getMessage()); } // CSVファイルを読み込みモードで開く $file_name="inp_data.csv"; //$file_name="inp_data_.csv"; $file_name=$filename; $fp = fopen($file_name, "r"); // ファイルを1行ずつ取得する $fl=0; while (($line = fgetcsv($fp)) !== FALSE) { for ($c = 0; $c < count($line); $c++) { $str = mb_convert_encoding($line[$c] ,"utf-8","sjis"); print("---------\n"); print($str); print("---------\n"); if($c==2){ print($c); print("="); print($str); print(":"); } } if($fl != 0){// ヘッダーは除外 $stmt = $pdo->prepare($sql_select); foreach ($culumname as $index => $culum) { if ($culumzok[$index]==1){ $stmt->bindValue(':'.$culum, mb_convert_encoding($line[$index],"utf-8","sjis") , PDO::PARAM_STR); }else{ if($line[$index]==''){ $stmt->bindValue(':'.$culum, "0" , PDO::PARAM_INT); }else{ $stmt->bindValue(':'.$culum, $line[$index] , PDO::PARAM_INT); } } } $stmt->execute(); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); // 参考 http://hono-wp.seesaa.net/article/411183815.html // https://qiita.com/wakahara3/items/d7a3674eecd3b021a21e print_r($result); print($result[0]["count(*)"]); if($result[0]["count(*)"]==0){ print("Write"); $stmt = $pdo->prepare($sql_insert); $mapdata=array(); foreach ($culumname as $index => $culum) { // $setdata=$line[$index]; if ($culumzok[$index]==1) { // 文字列 $setdata=mb_convert_encoding($line[$index],"utf-8","sjis") ; }else{ //数値 if ($line[$index]==""){ $setdata="0";}else{ $setdata=$line[$index]; }} array_push($mapdata,$setdata); } print_r($mapdata); $flag = $stmt->execute($mapdata); print($flag); } if($result[0]["count(*)"]=!0){ print("Send"); } } $fl=1; } fclose($fp); ?> |
重複検索のカラムの範囲と、挿入するカラムの範囲の処理はこれから
Stripのときには、不要なカラムが多いのと、ユニークカラムがあるので、この時に活用していく予定です
データディクショナリーは、Jsonに落として、外部にする事もできそうです
既存のデータを調べて、重複部分から、テーブルを特定する方法もあるが
当面は、この方法で
また、データディクションリーから、新規テーブルも作れるが
はじめの1回なので、後でいいかな