##はじめに
PHPで画像のアップロードから表示までの一連の処理を
備忘録としてこちらまとめさせていただきます。
##手順
①FORMから画像を選択してPOSTで送信
②送信した画像が存在するかチェック
③ファイル名をユニーク化
④画像ファイルかのチェック
⑤DBではなくサーバーのimageディレクトリに画像を保存
⑥DBにはファイル名保存
⑦DBのファイル名を元に画像表示
##ファイル構造
test
|-images(画像ファイル保存ディレクトリ)
|-image.php(画像表示ファイル)
|-upload.php(画像アップロード処理するファイル)
##画像アップロード処理するファイル(upload.php)
①FORMから画像を選択してPOSTで送信
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="file" name="image">
<button><input type="submit" name="upload" value="送信"></button>
</form>
②~⑥
<?php
$dsn = "mysql:host=localhost; dbname=xxx; charset=utf8";
$username = "xxx";
$password = "xxx";
try {
$dbh = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
echo $e->getMessage();
}
if (isset($_POST['upload'])) {
$temp_file = $_FILES['image']['tmp_name'];
$dir = './images/';
if (file_exists($temp_file)) {//②送信した画像が存在するかチェック
$image = uniqid(mt_rand(), false);//③ファイル名をユニーク化
switch (@exif_imagetype($temp_file)) {//④画像ファイルかのチェック
case IMAGETYPE_GIF:
$image .= '.gif';
break;
case IMAGETYPE_JPEG:
$image .= '.jpg';
break;
case IMAGETYPE_PNG:
$image .= '.png';
break;
default:
echo '拡張子を変更してください';
}
//⑤DBではなくサーバーのimageディレクトリに画像を保存
move_uploaded_file($temp_file, $dir . $image);
}
//⑥DBにはファイル名保存
$sql = "INSERT INTO images(name) VALUES (:image)";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':image', $image, PDO::PARAM_STR);
$stmt->execute();
}
?>
##セキュリティ
画像アップロード
ファイルアップロードを使った攻撃があり、悪意あるコードを注入した不正ファイルをアップロードし、そのファイルにアクセスすることで成立する。この攻撃は、XSSを使って第三者に接続させる方法や攻撃する側が自らサーバにコードを注入して実行させる方法がある。
脆弱性を防ぐために...
1.アップロードされたファイルを非公開ディレクトリに移す(悪意あるスクリプトを実行できなくする)
2.アップロードされたファイル名をrenameする(拡張子などを変えることによって悪意あるスクリプトを実行できなくする)
##画像表示ファイル(image.php)
⑦DBのファイル名を元に画像表示
<?php
$dsn = "mysql:host=localhost; dbname=xxx; charset=utf8";
$username = "xxx";
$password = "xxx";
$id = 1;
try {
$dbh = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
echo $e->getMessage();
}
//⑦DBのファイル名を元に画像表示
$sql = "SELECT * FROM images WHERE id = :id";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':id', $id);
$stmt->execute();
$image = $stmt->fetch();
?>
<h1>画像表示</h1>
<img src="images/<?php echo $image['name']; ?>" width="300" height="300">
##まとめ
画像アップロード自体は簡単にできます。ですが、脆弱性を意識しながらコードを書こうとすると様々な書き方があり、それを読み解くことでセキュリティに対しての理解を深めることができました。