今、案件でColdFusion9をやっています。ColdFusion自体を使うのは前々案件で経営層向けの指標一覧を作って以来だから、実に5年ぶりだったんですが、まぁ5年もやってなければすっかり忘れてる訳で…。
で、今回は当時もやらなかったCSV取込→DB登録という機能を実装する必要があったんですが、割と苦労したので備忘録的にポイントを残しておこうと思います。
<cfspreadsheet>は使えない
ColdFusion9から追加されている機能で<cfspreadsheet>というタグがあります。オンラインマニュアルを読むと一瞬これでExcelで扱えるファイルは全て読めるように錯覚するのですが、実際にはxlsやxlsxといったExcelフォーマットを読めるというもので、実はこのタグではCSVファイルは読めません*1!
CSVファイルを読み込むときには<cffile>を使用しましょう。
enctypeを指定し忘れない
<form>タグにenctype属性を指定し忘れると、クライアントから取り込んだファイルを「ファイル」として認識できなくなります。具体的に言うとファイル名の文字列のみ送ろうとするんですね。結果として<cffile>タグがファイルを認識できずにエラーを発生します。
必ず<form>もしくは<cfform>タグにはenctype="multipart/form-data"を指定するようにしましょう。
余談ですが、<input type="file">で取得したファイル名は、フルパスで取得することができません。試しに取得直後にJavaScriptで出力してみたんですが、以下のように表示されました。
「C:\fakepath\ファイル名」と表示される
Webのセキュリティ上の問題でわざと取得できないようになっているようです。最初オレは「CSVファイルが上手く取り込めないのはフルパスが取得できないせいだ」と勘違いしてフルパスをなんとか取得できないかと無駄に調べ回ってしまったのですが、フルパスは今回の機能実現にはまったく必要ありませんでした。ぎゃふん。
CSVtoArrayを活用
CSVデータをcffileタグで取り込むと普通のテキストファイルとして扱われるので、CSVの各カラムからデータを勝手に取りだしてくれる、ということはしてくれません。ここは自力で実装する必要があるんですが、今回は巷で専用のコードを公開してくれている方がいたのでそれを活用させて貰いました。以下、参考にさせて頂いたサイトです。
ソースコード
test.cfm
<html> <cfinclude template="../udf/CSVtoArray.cfm"> <CFIF isDefined("Form.csv_file")> <CFFILE action="read" file="#Form.csv_file#" variable="CsvData" charset="shift_jis"> <cfset CSVArray = CSVtoArray(CsvData)> <cfloop index="i" from="1" to="#ArrayLen(CSVArray)#"> <CFQUERY name="insert" dataSource="CFSample"> INSERT INTO mascot ( no, name, team ) VALUES ( '#CSVArray[i][1]#', '#CSVArray[i][2]#', '#CSVArray[i][3]#' ); </CFQUERY> </cfloop> <script type="text/javascript"> alert("データ追加成功!"); location.href="test.cfm"; </script> </CFIF> <head> <title>ColdFusion CSV読み込みサンプル</title> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> </head> <body width="100%" height="100%" valign="top"> <CFFORM name="csvread" action="test.cfm" method="post" enctype="multipart/form-data"> <table border="1"> <tr height="60"> <td align="left" valign="middle" nowrap>対象ファイル:<CFINPUT type="file" size="50" name="csv_file"></td> <td align="left" valign="middle" nowrap> <input type="button" value="テスト" name="テスト" onclick="javascript:alert(document.csvread.csv_file.value);"> <input type="submit" value="取込" name="getCSV"> </td> </tr> </table> </CFFORM> </body> <html>
mascot.csv
1,グランパス,名古屋グランパス 2,しかお,鹿島アントラーズ 3,GAMBA BOY,ガンバ大阪 4,ふろん太,川崎フロンターレ 5,ベガッ太,ベガルタ仙台 6,モンテス・ディーオ,モンテディオ山形 7,レディア,浦和レッズ 8,アルディ,大宮アルディージャ 9,東京ドロンパ,FC東京 10,マリノスケ,横浜Fマリノス 11,キングベル1世,湘南ベルマーレ 12,アルビくん,アルビレックス新潟 13,パル,清水エスパルス 14,ジュビロ,ジュビロ磐田 15,パーサくん,京都サンガFC 16,ロビー,セレッソ大阪 17,モーヴィ,ヴィッセル神戸 18,サンチェ,サンフレッチェ広島
↓
CSVファイル読み込むとMySQLにJリーグのマスコット名が取りこまれる、というシンプルなものです。良かったら参考にしてみて下さい。