Codeworks Notes

 2023-05-26

PHP
PHP応用
バックエンド

アップロード画像を確認画面で保存させない

ファイルをアップロードして確認画面で表示させるとき、アップロード画像をこのタイミングで PUT しちゃうと「戻る」ボタンを押されたときにサーバーのゴミとして画像が残ったままになる。

「戻る」ボタンを設置しないのは UI として問題なので戻ってもファイルが残らないのが一番です。

そんなとき、ファイルをサーバーに PUT せんでもセッションに一時的に置いて完了時に PUT するというやり方があるので、それをざっくりまとめます。

まずアップロードフォーム

最低限の入れ物を作ります。アレンジは好きにしてください。

<form method="post" action="img_confirm.php" enctype="multipart/form-data">
	<label for="ul_image">アップロードする画像</label>
	<input type="file" id="ul_image" name="image" accept="image/*">
	<input type="submit" value="送信">
</form>

受け側の処理

送信データの受け側ではアップロードファイルを取得してセッションに保存する仕組みを書きます。

<?php
// アップロードファイルを取得
$img = $_FILES['reqimg']['tmp_name'];
// 画像データをセッションに保存する
session_start();
$_SESSION['image']['data'] = file_get_contents($img);
$_SESSION['image']['type'] = exif_imagetype($img);
?>

<p>この画像で登録します</p>
<img src="image.php">

<form method="post" action="img_upload_done.php">
<input type="button" onclick="history.back()" value="戻る">
<input type="submit" value="確定">

<img> タグのソースに指定されている image.php でセッションから画像を取得します。

session_start();
switch ($_SESSION['image']['type']) {
	case IMAGETYPE_JPEG:
	header('content-type: image/jpeg');
	break;
	case IMAGETYPE_PNG:
	header('content-type: image/png');
	break;
	case IMAGETYPE_GIF:
	header('content-type: image/gif');
	break;
	}
echo $_SESSION['image']['data'];

一時データのファイル保存処理

確定ボタンを押した後の処理も書いていきましょう。

<?php
$img_name = "なんかファイル名";
file_put_contents('./uploads/'.$img_name,$_SESSION['image']);
unset($_SESSION['image']);
?>

<p>登録完了しました</p>

画像部分はこんな流れで一時的にセッションに置いて、本当に欲しいときにサーバ保存できます。
保存した後セッションの中の画像を unset しておくと行儀がいいです。

ファイルチェック処理を加える場合

適切なファイルがアップロードされないとエラーになって困るというときはファイルチェックをするとより安全な仕組みになります。

正しくアップロードされてるのかチェックしたい

アップロードが正しくできているかのチェックが欲しければ、is_uploaded_file() 関数を使います。

<?php
//アップロード判定
if (is_uploaded_file($_FILES['reqimg']['tmp_name'])) {
	// 正しくアップされていればファイルを取得
	$img = $_FILES['reqimg']['tmp_name'];
} else {
	// アップされてなければ明示的にnullにする
	$img = null;
}

if ( !empty($img) ) {
	// 画像がアップされていたら画像データをセッションに保存する
	session_start();
	$_SESSION['image']['data'] = file_get_contents($img);
	$_SESSION['image']['type'] = exif_imagetype($img);
}
?>

<p>この画像で登録します</p>
<img src="image.php">

<form method="post" action="img_upload_done.php">
<input type="button" onclick="history.back()" value="戻る">
<input type="submit" value="確定">

欲しいファイル形式で送信されているかチェックしたい

JPG、PNG、GIF形式だけ受け付けたい!拡張子だけ書き換えた変なファイルはダメ!という場合もあることでしょう。
そんなときは exif_imagetype() 関数で画像形式を調べて処理を分岐させます。

<?php
// アップロードファイルを取得
$img = $_FILES['reqimg']['tmp_name'];

// 画像形式の判別
$imgtype = exif_imagetype($img);	// 画像タイプを取得
// JPG、PNG、GIF形式かどうか調べる
switch($imgtype) {
	case IMAGETYPE_JPEG: $imgcheck = true; break;
	case IMAGETYPE_PNG: $imgcheck = true; break;
	case IMAGETYPE_GIF: $imgcheck = true; break;
	default: $imgcheck = false;
}

// JPG、PNG、GIF形式だったら画像データをセッションに保存する
if ($imgcheck) {
	$_SESSION['image']['data'] = file_get_contents($img);
	$_SESSION['image']['type'] = exif_imagetype($img);
}
?>

<p>この画像で登録します</p>
<img src="image.php">

<form method="post" action="img_upload_done.php">
<input type="button" onclick="history.back()" value="戻る">
<input type="submit" value="確定">

所感

他人に何かアップロードさせる仕組みを作ろうとすると、どうしても「必要のないものまでサーバに残したくない」という事を考えちゃうんですね。

人間なんで中途半端に戻ったり途中で閉じたり、停電で中断させられたり、何があるかわからないのでサーバにファイルを残すのは最後で、それまでは抱えたままにする、というのがスマートでいいんじゃないかな。