今回は画像を「フォルダに保存して表示」、「そのまま表示」、「DBに保存して表示」
の3パターンをまとめました。
画像をフォルダに保存して表示
formからファイルupして保存する
<form method="POST" action="upimg.php" enctype="multipart/form-data">
<input type="file" name="upimg" accept="image/*">
<input type="submit">
</form>
$img_name = $_FILES['upimg']['name'];
//画像を保存
move_uploaded_file($_FILES['upimg']['tmp_name'], './upload/' . $img_name);
echo '<img src="img.php?img_name=' . $img_name . '">';
外部サイトから取得して保存する
$url = "https://www.google.co.jp/images/srpr/logo11w.png";
$img = file_get_contents($url);
$imginfo = pathinfo($url);
$img_name = $imginfo['basename'];
//画像を保存
file_put_contents('./upload/' . $img_name, $img);
echo '<img src="img.php?img_name=' . $img_name . '" />';
保存した画像を表示
$img_name = $_GET['img_name'];
$img_dir = './upload/' . $img_name;
$imginfo = getimagesize($img_dir);
header('Content-Type: ' . $imginfo['mime']);
readfile($img_dir);
今回はformでupされたファイル名をそのまま画像名として保存していますが、
脆弱性の危険性があるので名前を変える必要があります。
ポイントは「img.php」にファイル名を渡してreadfile関数を使い、ディレクトリ内の画像を表示しています。
ちなみにpathinfoで取得した「extension」は画像名から取得した拡張子なのでmimeTypeとしては信用できないです。
画像をそのまま表示
formからファイルupしてそのまま表示
$fp = fopen($_FILES['upimg']['tmp_name'], "rb");
$img = fread($fp, filesize($_FILES['upimg']['tmp_name']));
fclose($fp);
$enc_img = base64_encode($img);
$imginfo = getimagesize('data:application/octet-stream;base64,' . $enc_img);
echo '<img src="data:' . $imginfo['mime'] . ';base64,'.$enc_img.'">';
外部サイトから取得してそのまま表示
$url = "https://www.google.co.jp/images/srpr/logo11w.png";
$img = file_get_contents($url);
$enc_img = base64_encode($img);
$imginfo = getimagesize('data:application/octet-stream;base64,' . $enc_img);
echo '<img src="data:' . $imginfo['mime'] . ';base64,'.$enc_img.'">';
ディレクトリ内に保存することもなくそのままの表示するので比較的安全。
DBに保存して表示
DBの中身はシンプルにIDとBLOBを保存するカラムだけです。
CREATE TABLE IF NOT EXISTS PICTURE (
PICID INT PRIMARY KEY,
PIC MEDIUMBLOB DEFAULT NULL
);
formからファイルupしてDBに保存
$pic_id = 1;
$fp = fopen($_FILES['upimg']['tmp_name'], "rb");
$img = fread($fp, filesize($_FILES['upimg']['tmp_name']));
fclose($fp);
$sql = <<<SQL
REPLACE INTO PICTURE
(PICID, PIC) VALUES (:pic_id, :PIC);
SQL;
$stmt = $DB->prepare($sql);
$stmt->bindValue(':pic_id' ,$pic_id);
$stmt->bindValue(':PIC' ,$img);
$stmt->execute();
$stmt = null;
echo '<img src="img.php?pic_id=' . $pic_id . '">';
外部サイトから取得してDBに保存
$pic_id = 2;
$url = "https://www.google.co.jp/images/srpr/logo11w.png";
$img = file_get_contents($url);
$sql = <<<SQL
REPLACE INTO PICTURE
(PICID, PIC) VALUES (:pic_id, :PIC);
SQL;
$stmt = $DB->prepare($sql);
$stmt->bindValue(':pic_id' ,$pic_id);
$stmt->bindValue(':PIC' ,$img);
$stmt->execute();
$stmt = null;
echo '<img src="img.php?pic_id=' . $pic_id . '">';
DBに保存した画像を表示
$pic_id = $_GET['pic_id'];
//画像取得
$sql = <<<SQL
SELECT PIC FROM PICTURE WHERE PICID = :pic_id
SQL;
$stmt = $DB->prepare($sql);
$stmt->bindValue(':pic_id' ,$pic_id);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$DB_PIC = $row['PIC'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_buffer($finfo, $DB_PIC);
finfo_close($finfo);
header('Content-Type: ' . $mimeType);
echo $DB_PIC;
一度IDを決めてDBに保存。「img.php」に先ほど保存した画像のIDを渡して表示させます。
DBにBLOBのデータを保存する際に「ON DUPLICATE KEY UPDATE」を使って
上書き保存させようとしたのですが、出来なかったので
「REPLACE INTO」を使って差し替えています。
DBに保存してある画像をまとめて表示
$sql = <<<SQL
SELECT PIC FROM PICTURE
SQL;
$stmt = $DB->prepare($sql);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC) ){
$DB_PIC_ARRAY[] = $row['PIC'];
}
$stmt = null;
foreach($DB_PIC_ARRAY as $pic){
$enc_img = base64_encode($pic);
$imginfo = getimagesize('data:application/octet-stream;base64,' . $enc_img);
echo '<img src="data:' . $imginfo['mime'] . ';base64,' . $enc_img . '" />';
}
まとめ
画像を扱う場合は脆弱性の危険性「../ をファイル名に含めて攻撃 (ディレクトリトラバーサル)」といったものがあるので注意が必要です。
基本的には画像をディレクトリ内に保存するのはやめた方が良いです。(別サーバーに保存するなどの対策)
参考リンク
PHPでファイルのMIMEタイプ取得に何を使う?explode? pathinfo? finfo_file?
【PHP】画像ファイルの種類(拡張子やMIMEタイプ)を取得する方法 – ysklog