ギャラリーページ #2

前回の続きです。ギャラリーページ #1

今回はイラストアップロード部分をまとめていきます。

処理工程の一覧

  • イラストアップロード画面
  • 受け取る
  • ディレクトリ作成
  • 画像圧縮・jpg変換
  • データベース登録

イラストアップロード画面

 <div class="container mt-5">
        <h2>画像アップロード</h2>
        <form action= method="post" enctype="multipart/form-data">
            <div class="form-group">
                <label for="fileUpload">画像を選択(JPG, PNGのみ):</label>
                <input type="file" name="fileUpload" id="fileUpload" class="form-control-file" accept=".jpg, .jpeg, .png">
            </div>
            <button type="submit" class="btn btn-primary">アップロード</button>
        </form>

accept=”.jpg, .jpeg, .png” を使用してアップロード制限を設けています。

アップロード者は私だけになります。アクセスにIP制限を設置し、その他セキュリティ対策は考えていません。

 // $ipchkと一致すれば処理継続
$nowip = $_SERVER['REMOTE_ADDR'];
$ipchk= "111.111.111.11";
if( $nowip != $ipchk){
	// 許可されているIPアドレスではない場合の処理
	exit;
}else{
	// 許可されているIPアドレスであった場合の処理
}

アップロード後の処理

保存ディレクトリの確認

日付毎にディレクトリを分けています。

// 今日の日付を取得
$today = date('Ymd');

// 現在の年と月を取得
$currentYear = date('Y');  // 例: 2023
$currentMonth = date('m'); // 例: 11

// アップロードディレクトリのパスを設定
$uploadDir = "自分の環境にしてください"

// アップロードディレクトリが存在しない場合は作成
if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0777, true);
}

保存ファイル名の作成

連番のファイル名になるようにディレクトリをスキャンし、末尾に+1する。99まで対応可能。


// ディレクトリ内のファイルをスキャン
$files = scandir($uploadDir);
$nextNumber = 1;

// 拡張子取得
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));

foreach ($files as $existingFile) {
    // 拡張子に関わらず、基本的なファイル名パターンでマッチさせる
    if (preg_match("/mai_{$today}(\d{2})\./", $existingFile, $matches)) {
        $currentNumber = (int)$matches[1];
        if ($currentNumber >= $nextNumber) {
            $nextNumber = $currentNumber + 1;
        }
    }
}

// 新しいファイル名を生成(連番をフォーマットして追加)
$newFilename = sprintf("mai_%s%02d.%s", $today, $nextNumber, $extension);

画像圧縮・png変換処理

単純にアップロードするだけでは画像が大きく、ページ表示に時間がかかってしまいます。

jpgは解像度を下げる、png は解像度を下げた後に jpg に変換する関数を作成します。

変換処理にGDライブラリが必須になります。

function resizeImageWithAspectRatio($source, $destination, $newWidth, $imageType)
{
    // 元の画像のサイズを取得
    list($origWidth, $origHeight) = getimagesize($source);
    $origAspectRatio = $origWidth / $origHeight;

    // 新しい高さを元のアスペクト比に基づいて計算
    $newHeight = $newWidth / $origAspectRatio;

    // 画像の読み込み
    switch ($imageType) {
        case 'image/jpeg':
            $sourceImage = imagecreatefromjpeg($source);
            break;
        case 'image/png':
            $sourceImage = imagecreatefrompng($source);
            break;
        default:
            return false; // サポートされていない画像形式
    }

    // 新しい画像リソースの作成
    $newImage = imagecreatetruecolor($newWidth, $newHeight);

    // PNGの場合は透明性情報を保持
    if ($imageType == 'image/png') {
        imagealphablending($newImage, false);
        imagesavealpha($newImage, true);
    }

    // 画像のリサイズとコピー
    imagecopyresampled($newImage, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $origWidth, $origHeight);

    // 新しい画像を保存(PNGの場合はJPGとして保存)
    if ($imageType == 'image/jpeg') {
        imagejpeg($newImage, $destination);
    } else if ($imageType == 'image/png') {
        // PNG変換
        $jpgDestination = preg_replace('/\.png$/i', '.jpg', $destination);

        if (imagejpeg($newImage, $jpgDestination)) {
            // JPGへの変換に成功した場合、元のPNGファイルを削除
            if (file_exists($destination)) {
                unlink($destination);
            }
        } else {
            // JPGへの変換に失敗した場合のエラーハンドリング
            echo "JPGへの変換に失敗しました。";
            return false;
        }
    }


    // メモリの解放
    imagedestroy($sourceImage);
    imagedestroy($newImage);

    return true;
}

画像が縦長・横長を取得し解像度の基準を決めてから関数を実行する。

// 一時的な保存先のパス
$tempPath = ~~~~

// 画像の元のサイズを取得
list($origWidth, $origHeight) = getimagesize($file['tmp_name']);


// 画像が縦型か横型かに基づいて新しい幅を設定
if ($origWidth > $origHeight) {
    // 横型の場合
    $newWidth = 800;
} else {
    // 縦型の場合
    $newWidth = 400;
}

$imageType = $file['type'];


// 解像度、変換の関数実行
resizeImageWithAspectRatio($tempPath, $tempPath, $newWidth, $imageType);

データベースに登録

ディレクトリに保存したらデータベースにファイル名などを保存し、管理する。

ファイル名に日付を含めているのでDBはシンプルなもので構わない。

 // データベースにファイル情報を挿入
$sql = "INSERT INTO img_upload_data (filename, filesize, file_type ) VALUES (:filename, :filesize, :file_type )";
$stmt = $pdo2->prepare($sql);
$stmt->execute([
    'filename' => $newFilename,
    'filesize' => $fileSize,
    'file_type' => $fileType,
]);

まとめ

今回は、アップロード処理部分について重要な箇所をまとめました。

サイズが大きい画像をそのまま表示してしまうと、表示完了まで時間がかかり離脱に繫がります。

目安ですが1,210KBの png画像を 50KB まで圧縮できています。

ワードプレスの圧縮プラグインよりも圧縮できているのかなと思います。

解像度を800 もしくは 400 としていますが、スマートフォンユーザーがメインで500枚以上表示する場合は解像度を下げたいい方がかもしれません。

解像度を維持しながら100枚上表示する場合はキャッシュ表示が望ましいです。

次回は画像を表示するページをまとめていきます。