アナログCPU:5108843109

ゲームと音楽とプログラミング(酒と女とロックンロールのノリで)

('ω') < イザユケエンジニャー

アップロードされた画像をDBに保存する

作る機会があったのでメモ。
フォームのタイプとか、DBではなくファイルとして保存するとか、そういうアレンジは適当に。

手順

ざっくり分けると以下のような感じ。

  • 画像のアップロードフォームを作る
  • アップロードされた画像を加工する(リサイズなど)
  • 加工した画像をbase64化する
  • base64化したデータをDBに保存する

画像のアップロードフォームを作る

とはいえフォームの話は以前にも書いているのでそちらへのリンクを張っておきます。

ごく簡単なフォームならこちら。
CSVの話してますが画像でも同じ)
ローカルのCSVファイルをアップロードして処理 - アナログCPU:5108843109

ドラッグ&ドロップにしたい場合はこちら。
ドラッグ&ドロップでファイルをアップロードする(最低限版) - アナログCPU:5108843109

…とだけ書いておくのも何なので、
今回は画像特化ということでトリミング機能も付けてみたコードを貼っておきます。

cropperというjQueryプラグインがあるので、それを利用しています。
fengyuanchen.github.io


このプラグインは、トリミングした画像をpostするのではなく、
「画像」と「トリミングしたい範囲の情報」をpostするためのものです。
実際にはトリミング前の画像がpostされることに注意してください。

プラグインの読み込み:CSS

<link href="/js/lib/cropper.css" rel="stylesheet">

プラグインの読み込み:JS(もちろんjqueryの読み込みより後で)

<script src="/js/lib/cropper.js"></script>

フォーム

<form method="POST" enctype="multipart/form-data" action="【※アップロード後の処理用URL】">
  <input type="file" id="input-user_image" name="image">
  <img id="select-image" style="max-width:100%; max-height: 50vh;">
  <input type="hidden" id="upload-image-x" name="image_x" value="0">
  <input type="hidden" id="upload-image-y" name="image_y" value="0">
  <input type="hidden" id="upload-image-w" name="image_w" value="0">
  <input type="hidden" id="upload-image-h" name="image_h" value="0">
  <input type="submit" value="更新する">
</form>

設置したフォーム用のJS

$(function(){
    var options = {
        aspectRatio: 1 / 1,
        viewMode: 1,
        crop: function(e) {
            cropData = $('#select-image').cropper("getData");
            $("#upload-image-x").val(Math.floor(cropData.x));
            $("#upload-image-y").val(Math.floor(cropData.y));
            $("#upload-image-w").val(Math.floor(cropData.width));
            $("#upload-image-h").val(Math.floor(cropData.height));
        },
        zoomable: true,
        minCropBoxWidth: 100,
        minCropBoxHeight: 100
    }
    $('#select-image').cropper(options);
    $("#input-user_image").change(function(){
        $('#select-image').cropper('replace', URL.createObjectURL(this.files[0]));
    });
});

cropperについて書きはじめるとたぶん長くなるので
その他詳しくはマニュアルを読むなりいじって確かめてみるなりしてください。
これでアップロード用フォーム完成です。

参考
Jquery-画像を切り抜くことができるライブラリ「Cropper」 | 社員ブログ | リグレックス株式会社 | REGREX Co.,Ltd.

アップロードされた画像を加工する

アップロードされたファイルの一時保存先は以下で取得できます。

$_FILES['image']['tmp_name']

また、今回はフォームから以下が送られてきています。

$_POST['image_x'] // トリミング範囲の左上のX座標
$_POST['image_y'] // トリミング範囲の左上のY座標
$_POST['image_w'] // トリミング範囲の横幅
$_POST['image_h'] // トリミング範囲の縦幅

これらを使用し、必要な加工を行います。
今回は、「画像を指定通りにトリミングし、一辺を200pxにする」という加工を行っています。
トリミングは正方形になるようにしてimage_hは使わず、
image_wが200pxより大きい場合も小さい場合も200pxに縮小or拡大しています。

<?

$tmp_file_name = $_FILES['image']['tmp_name'];
$x             = $_POST['image_x'];
$y             = $_POST['image_y'];
$size          = $_POST['image_w'];

// ファイルタイプを判定し、それに対応した読み込みを行う
$base_img = null;
if (exif_imagetype($tmp_file_name) == IMAGETYPE_PNG)
{
    $base_img = imagecreatefrompng($tmp_file_name);  // PNG
}
elseif (exif_imagetype($tmp_file_name) == IMAGETYPE_JPEG)
{
    $base_img = imagecreatefromjpeg($tmp_file_name); // JPEG
}
elseif (exif_imagetype($tmp_file_name) == IMAGETYPE_GIF)
{
    $base_img = imagecreatefromgif($tmp_file_name);  // GIF
}

// 読み込んだ画像を加工・保存
if ($base_img !== null)
{
    // 新しい画像を作成し、縮小・トリミングした画像を貼り付ける
    $new_img = imagecreatetruecolor(200, 200);
    imagecopyresampled($new_img, $base_img, 0, 0, $x, $y, 200, 200, $size, $size);

    // 一時的な保存先パスを作る(あとで削除する)
    $tmp_path = "【※ファイル名に乱数を含めて衝突しないようにすると良い】";

    // 生成した画像をpng化して保存する
    imagepng($new_img, $tmp_path);

    // 保存した画像をbase64化する
    $img_base64 = base64_encode(file_get_contents($tmp_path));

    // 画像を削除する
    unlink($tmp_path);
}

参考
PHP: exif_imagetype - Manual
PHP: imagecreatefromjpeg - Manual
PHP: imagecreatetruecolor - Manual
PHP: imagecopyresampled - Manual
PHP: imagepng - Manual
PHP: base64_encode - Manual

image系関数が意外と豊富でびっくりした。

加工した画像を保存する

あとはデータベースに保存するだけ。
単純に、TEXT型などのカラムにINSERTやUPDATEします。

ただ、カラムのサイズ上限が小さいと保存しきれない場合があるので、写真など色数の多い画像を使って動作確認した方が良いです。
だめそうならもっと圧縮するようにするとか、カラムをLONGTEXT型にするとかで対応。

UPDATEの例

UPDATE `user`
SET    `icon_image` = '【※base64化したデータ】'
WHERE  `id` = 1

おまけ:base64データの表示方法

以下のような書き方で表示できます。

<img src="data:image/png;base64,【※base64データ】" >