今回はPHP7.4でCSVファイルのアップロードに関して実例をもとにご紹介します。
皆さん、CSVって知っていますか?
CSVとは「カンマで値を区切ったデータ(Comma Separated Values)」のことを指します。
このCSVは下記の点でとても使い勝手が良く、あらゆるところで汎用されています。
1. 様々なプログラムでサポートされている
2. データのインポート/エクスポートに便利
3. 単純であるため扱いやすい
4. サイズが小さく、メモリ消費量が少ない
皆さんがよく使用されているExcelやGoogleSpreadSheetにもインポートできるという素晴らしい汎用性を持っています。逆に、ExcelやGoogleSpreadSheetからエクスポートもできます。
汎用性の高いCSVをDBに入れるまでのロジックをご紹介させていただきます。
目次
1. PHPでCSVアップロード機能を実装する準備
1-1. ディレクトリ構成に従ってファイルやディレクトリを作成
作成するのはcsvディレクトリ、sample01.php、sample02.phpの3つです。
役割としては
csvディレクトリ
こちらではアップロードしたCSVファイルを保存するディレクトリです
sample01.php
こちらはCSVファイルをアップロードするフォームを表示させるファイルです。
sample02.php
こちらはアップロードしたCSVファイルをCSVディレクトリやDBに保存するファイルです。
// ディレクトリ構成
.
├── csv
│ └── ここにアップロードされたCSVファイルが保存される
│ └── sample.csv といった形で保存される
├── sample01.php
└── sample02.php
1-2. アップロードするCSVファイルの中身の確認
テーブル作成するために、カラム名や、カラムの条件を決めるためCSVの中身を確認しなければなりません。
というのも、CSVの列が何個あるのか?列の一番上には列の名前がついているのか確認します。
例えば、sample.csvのようなデータを持っていたとします。
この場合、DBに入れるためにテーブルを作成します。そのために何のカラムが必要なのかをCSVファイルの中身を確認します。
今回は「name,age,height,weight」の項目があり、DBにすべてのデータを挿入する際はこの4つ分のカラムが必要となります。
一番上の行の「name,age,height,weight」があるので、CSVをテーブルに入れる時にこちらの行が入らない実装を入れなければなりません。
// CSVの中身
name,age,height,weight <- 不要な行
石原,26,169,50
林,33,154,46
川島,24,167,54
山本,24,198,78
1-3. テーブルの作成
データをテーブルを作成しましょう。
テーブル名: membersで「id,name,age,height,weight」(注2)のカラムを持つテーブルを作成します。
idはCSVファイルには入っていませんが、PRIMARY KEYとしての役割を担っているカラムになります
(注2)
CREATE TABLE members (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT(11) NOT NULL,
height INT(11) NOT NULL,
weight INT(11) NOT NULL,
PRIMARY KEY (id)
)
上記のSQL文を実行すると、下記のようなmembersテーブルが作成されます。(phpMyAdminを使用)
2. 実装
2-1. CSVアップロードのフォームを作成する
まず、CSVアップロードのフォームをHTMLで作成しましょう。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>CSVアップロード</title>
</head>
<body>
<form method="POST" action="sample02.php" enctype="multipart/form-data">
<input type="file" name="csv_file"><br>
<button type="submit">アップロード</button>
</form>
</body>
</html>
enctype=”multipart/form-data”は、HTMLフォームでファイルをアップロードする際に使用される属性の一つで、フォームデータをエンコード(注1)する方法を指定します。
inputのtype=”file“を指定します。また、nameはなんでもいいのですが、わかりやすくcsv_fileとします。
上記のHTMLを記載すると下記の画像のようなフォームが作成されればOKです。
2-2. CSVアップロードのロジックを実装する
CSVアップロードのコードを実装しましょう。
全体の処理はこちです。
コメントアウトで何をしているか大体はわかると思います。
<?php
// sample01.php でアップロードされたCSVファイルは$_FILES['csv_file']取得できる
$fileName = $_FILES['csv_file']['name'];
$fileTmpName = $_FILES['csv_file']['tmp_name'];
// ファイルパス
$filePath = './csv/' . $fileName;
// CSVファイルをcsvディレクトリに保存する
move_uploaded_file($fileTmpName, $filePath);
// csvディレクトリに保存したCSVファイルを読み込み、配列に置き換る。
$data = array_map('str_getcsv', file($filePath));
// 今回はDB:testにテーブル:membersを作成しておく
try{
$db = new PDO('mysql:dbname=test;host=localhost;charset-utf8','root','root');
} catch(PDOException $e) {
echo '接続エラー:' . $e->getMessage();
exit;
}
// usersテーブルにデータを挿入する
foreach ($data as $key => $row) {
// 1行目はテーブルに入れたくないのでスキップする
if($key === 0) {
continue;
}
$name = $row[0];
$age = $row[1];
$height = $row[2];
$weight = $row[3];
$stmt = $db->prepare("INSERT INTO members (name, age, height, weight) VALUES (:name, :age, :height, :weight)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':age', $age);
$stmt->bindParam(':height', $height);
$stmt->bindParam(':weight', $weight);
$stmt->execute();
}
echo 'CSVアップロードが完了しました';
?>
CSVをアップロードし、データがテーブルに入ると「CSVアップロードが完了しました」と表示が出るようにしました。
下記のようにデータが入っていればOKです。
まとめ
CSVアップロードは汎用性が高いので、実際に実装することが多いと思います。
今回はCSVをアップロードして、テーブルに入れるという2点に絞ってお話さした。
しかし、実際はセッキュリティに関することやバリデーション関連のことを考慮せねばばりません。
今回はページが長くなり、内容が細かくなる関係からここら辺のコードを省きました。
どういったことを考慮せねばならないかという内容を簡単ではありますが、下記に記載させていただきました。
参考にしていただければ幸いです。
備考①〜セッキュリティ、バリデーションに関する考慮事項〜
セッキュリティに関する考慮事項
ファイルサイズ制限:
ファイルサイズが大きすぎるとサーバーがオーバーロードするので、その防止。
ファイル形式制限:
アップロードできるファイルの種類を制限することにより、悪意のあるファイルを防止する。
ファイルの内容チェック:
CSVファイルの内容を検証し、不正なデータが含まれていないことを確認する。悪意のあるスクリプトが含まれていないかどうかを確認する。
ファイルのアクセス制御:
アップロードされたCSVファイルにアクセスするための権限を制御する。
必要なユーザーのみがアクセスできるようにする。
バリデーションに関する考慮事項
フォーマットチェック:
CSVファイルの形式が正しいかどうかを確認する。列が正しい形式であるか、必要な列が含まれているかを確認する。
文字コードチェック:
CSVファイルの文字コードが正しいかどうかを確認する。異なる文字コードで保存されたCSVファイルをアップロードすると、文字化けなどの問題が発生する可能性がある。
データ型チェック:
CSVファイルの各列のデータ型が正しいかどうかを確認する。例えば、数値の列に文字列が含まれていた場合、処理が失敗する可能性がある。
備考②〜注釈〜
(注1)「エンコード(encode)」とは?
あるデータを別の形式に変換することを指します。一般的には、データを別の形式に変換して符号化(暗号化)することが多いです。
例えば、テキストを扱う場合には、ASCIIやUTF-8などのエンコーディング方式に従ってデータを符号化します。また、画像を扱う場合には、JPEGやPNGなどのフォーマットに従ってデータを符号化することを指します。
(注2)id
カラムはPRIMARY KEY制約
PRIMARY KEY制約とは、テーブル内のレコードに重複をさせないための制約です。PRIMARY KEY制約が設定された列(カラム)には、重複する値を許可しないため、同じ値が複数存在することはできません。