AJAXとPHPで実現するファイルアップロード進捗の表示方法

PHPとAJAXを使用したファイルアップロードは、ユーザーにとって利便性が高く、特に進捗状況がリアルタイムで表示されることで、操作の透明性が増します。通常、ファイルのアップロードはサーバーサイドで行われますが、進捗の可視化にはAJAXやJavaScriptが重要な役割を果たします。本記事では、AJAXとPHPの連携を通じて、ユーザーがアップロード中のファイルの進捗状況をリアルタイムで確認できる仕組みについて、具体的な手順と実装例を交えて詳しく解説します。この方法をマスターすることで、ユーザー体験を向上させる効果的なアップロードシステムを構築できるようになります。

目次

PHPとAJAXでのファイルアップロードの概要


ファイルアップロードをPHPとAJAXで実現する際には、サーバーとクライアントの連携が重要です。PHPはサーバーサイドでファイルの受け取りや保存を担当し、AJAXはクライアントサイドで非同期通信を行い、進捗状況をリアルタイムで表示します。AJAXを使用することで、ページを再読み込みすることなく、ファイルがアップロードされる進行状況をユーザーに提示できます。

PHPの役割


PHPは、受信したファイルを適切にサーバーへ保存し、エラー処理やファイルサイズ制限といった制御を行います。また、進捗状況を送信する役割も担い、AJAXからのリクエストに応じてアップロードの進行度を報告します。

AJAXの役割


AJAXは、JavaScriptを用いて非同期でサーバーと通信し、アップロードの進捗を受け取ります。これにより、ユーザーはアップロードの状況をリアルタイムで把握でき、待ち時間を視覚的に理解することが可能です。

必要な準備と環境設定


ファイルアップロードの進捗表示を実装するためには、まずPHP環境の設定と必要な準備が必要です。特に、ファイルアップロードに関する設定を適切に行うことで、予期せぬエラーを回避し、スムーズな実装が可能となります。

PHP設定の確認


PHP.iniの設定で、ファイルアップロードに関連するパラメータを確認し、必要に応じて調整します。以下の設定を確認してください。

  • file_uploads:ファイルアップロードを許可する設定です。Onに設定する必要があります。
  • upload_max_filesize:アップロードできるファイルの最大サイズを指定します。適切なサイズに設定しましょう。
  • post_max_size:POSTリクエストで送信できるデータの最大サイズを指定します。upload_max_filesizeよりも大きく設定することが推奨されます。

サーバー環境の確認


ファイルアップロード機能は、一部のサーバーで制限されることがあります。特に、セキュリティ上の理由から制限されているホスティング環境もあるため、実行環境がファイルアップロードに対応しているかを確認しましょう。

必要なJavaScriptライブラリの準備


進捗バーの表示にはJavaScriptの活用が重要です。jQueryなどのライブラリを使うと、AJAXの実装がよりシンプルで簡潔になります。必要に応じてCDN経由でjQueryを読み込み、進捗表示に備えましょう。

HTML構成とUIデザイン


ファイルアップロードの進捗状況を視覚的に表示するためには、ユーザーインターフェース(UI)を工夫することが重要です。HTMLフォームにプログレスバーやステータスメッセージを組み込むことで、ユーザーにとって直感的で使いやすいデザインを実現します。

ファイルアップロードフォームの基本構成


ファイルアップロードのフォームには、以下のような要素が含まれます。

  • ファイル選択ボタン:ユーザーがアップロードするファイルを選択するための入力フィールド。
  • アップロードボタン:選択したファイルをサーバーに送信するボタン。
  • プログレスバー:アップロードの進行状況を視覚的に示すバー。
  • ステータスメッセージ:アップロードの完了やエラーの発生を知らせるメッセージ。

以下は、基本的なHTML構成の例です。

<div class="upload-container">
    <form id="uploadForm" enctype="multipart/form-data">
        <input type="file" id="fileInput" name="file" required>
        <button type="button" onclick="uploadFile()">アップロード</button>
    </form>
    <div class="progress-bar" id="progressBar">
        <div class="progress-bar-fill" id="progressFill"></div>
    </div>
    <p id="statusMessage"></p>
</div>

CSSでのプログレスバーのデザイン


プログレスバーのデザインは、CSSで指定します。進捗状況を示すフィル要素をバー内で伸縮させることで、リアルタイムの進捗表示が可能です。

.upload-container {
    width: 300px;
    margin: auto;
}

.progress-bar {
    width: 100%;
    height: 20px;
    background-color: #e0e0e0;
    border-radius: 5px;
    margin-top: 10px;
    overflow: hidden;
}

.progress-bar-fill {
    height: 100%;
    width: 0;
    background-color: #4caf50;
    transition: width 0.4s ease;
}

UIデザインのポイント

  • プログレスバーの色やスタイルは、ユーザーに分かりやすいように工夫しましょう。
  • ステータスメッセージを動的に表示することで、アップロードの成功や失敗を明確に伝えられます。

PHPでのファイルアップロード処理の実装


サーバーサイドでは、PHPを使ってアップロードされたファイルを受け取り、指定のディレクトリに保存する処理を行います。ここでは、アップロードファイルの処理手順を具体的なコードで説明します。

ファイルアップロードの基本処理


PHPでファイルをアップロードするには、$_FILESグローバル変数を使って、クライアントから送信されたファイルを処理します。以下のコードでは、ファイルが正常にアップロードされたかどうかを確認し、問題がなければ指定のディレクトリに保存します。

<?php
// ファイルアップロード処理
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // アップロードしたファイルの情報を取得
    $file = $_FILES['file'];

    // エラーチェック
    if ($file['error'] === UPLOAD_ERR_OK) {
        // 保存するディレクトリのパス(相対パスまたは絶対パスで指定)
        $uploadDir = 'uploads/';
        // ファイルのパスを作成
        $filePath = $uploadDir . basename($file['name']);

        // ファイルの移動
        if (move_uploaded_file($file['tmp_name'], $filePath)) {
            echo json_encode(['status' => 'success', 'message' => 'ファイルのアップロードに成功しました!']);
        } else {
            echo json_encode(['status' => 'error', 'message' => 'ファイルの移動に失敗しました。']);
        }
    } else {
        echo json_encode(['status' => 'error', 'message' => 'ファイルのアップロードに失敗しました。']);
    }
}
?>

コードの解説

  1. ファイルの取得$_FILES['file']でクライアントから送られたファイルを取得します。
  2. エラーチェック:ファイルのアップロードにエラーがないか確認します。エラーコードがUPLOAD_ERR_OKである場合、正常にアップロードされています。
  3. 保存ディレクトリの指定$uploadDirに、アップロードファイルを保存するディレクトリのパスを指定します。このディレクトリには書き込み権限が必要です。
  4. ファイルの移動move_uploaded_file関数を使用して、一時保存されたファイルを指定ディレクトリに移動します。
  5. レスポンスの返却:JSON形式でアップロードの成功またはエラーメッセージを返します。これにより、AJAX側でレスポンスを簡単に処理できます。

ディレクトリの書き込み権限


アップロードディレクトリ(ここではuploadsフォルダ)には書き込み権限が必要です。必要に応じて、以下のコマンドでディレクトリの権限を設定します。

chmod 755 uploads/

セキュリティ上の注意点

  • アップロードされたファイル名にbasename関数を使用することで、ディレクトリトラバーサル攻撃を防止します。
  • 必要に応じて、アップロードできるファイルの拡張子やサイズに制限を設けると安全です。

AJAXで進捗状況を取得する方法


AJAXを使用することで、ユーザーがアップロードの進捗状況をリアルタイムで確認できるインターフェースを作成できます。JavaScriptのXMLHttpRequestオブジェクトを用いると、非同期通信を行いながらファイルのアップロード進行度を取得することが可能です。

AJAXリクエストの設定と進捗イベントの監視


AJAXリクエストの設定には、XMLHttpRequestオブジェクトを使用します。また、uploadイベントリスナーを使用することで、アップロードの進捗を監視し、リアルタイムでユーザーに表示できます。以下は、ファイルの進捗状況を取得するためのJavaScriptコードです。

function uploadFile() {
    // フォームデータの作成
    const fileInput = document.getElementById('fileInput');
    const formData = new FormData();
    formData.append('file', fileInput.files[0]);

    // XMLHttpRequestの設定
    const xhr = new XMLHttpRequest();
    xhr.open('POST', 'upload.php', true);

    // アップロード進捗状況の監視
    xhr.upload.addEventListener('progress', (event) => {
        if (event.lengthComputable) {
            // 進捗の割合を計算
            const percentComplete = (event.loaded / event.total) * 100;
            document.getElementById('progressFill').style.width = percentComplete + '%';
            document.getElementById('statusMessage').textContent = `アップロード中: ${Math.floor(percentComplete)}%`;
        }
    });

    // アップロード完了時の処理
    xhr.onload = () => {
        if (xhr.status === 200) {
            const response = JSON.parse(xhr.responseText);
            if (response.status === 'success') {
                document.getElementById('statusMessage').textContent = 'アップロードが完了しました!';
            } else {
                document.getElementById('statusMessage').textContent = 'アップロードに失敗しました。';
            }
        } else {
            document.getElementById('statusMessage').textContent = 'サーバーエラーが発生しました。';
        }
    };

    // リクエスト送信
    xhr.send(formData);
}

コードの解説

  1. フォームデータの準備FormDataオブジェクトを使い、アップロードするファイルを含むデータを作成します。
  2. リクエストの設定xhr.openでPOSTリクエストをupload.phpに送信するように設定します。
  3. 進捗イベントの監視xhr.upload.addEventListener('progress', callback)を使って進捗状況を監視し、event.loadedevent.totalから進捗率を計算して、プログレスバーの幅とステータスメッセージを更新します。
  4. 完了時の処理:アップロードが完了したら、レスポンス内容を確認し、アップロード成功・失敗のメッセージを表示します。
  5. リクエスト送信xhr.send(formData)で、サーバーにデータを送信します。

UIに進捗表示を反映するポイント

  • 進捗率に応じて、プログレスバーの幅をリアルタイムで更新することで、ユーザーがアップロードの進行を視覚的に把握できるようにします。
  • statusMessageを使用して、ユーザーにアップロードの状態やエラーメッセージを適切に伝えます。

このAJAX設定により、ユーザーはファイルアップロードの進捗をリアルタイムで確認でき、待機時間の不安が軽減されます。

JavaScriptでのプログレスバーの実装


ファイルアップロードの進捗を視覚的に表示するために、JavaScriptでプログレスバーを実装します。このプログレスバーは、AJAXリクエストから取得した進捗状況に応じてリアルタイムで幅が変化し、ユーザーが現在の進行度を一目で確認できるようにします。

プログレスバーの基本実装


プログレスバーは、widthスタイルの変更によって進捗度を視覚化します。前のセクションで作成したprogressFill要素の幅を、アップロード進捗に合わせて動的に変更することで実現できます。以下は、プログレスバーを更新するJavaScriptコードです。

function updateProgressBar(percentComplete) {
    // プログレスバーの幅を進捗に合わせて変更
    const progressBarFill = document.getElementById('progressFill');
    progressBarFill.style.width = percentComplete + '%';

    // ステータスメッセージの更新
    const statusMessage = document.getElementById('statusMessage');
    statusMessage.textContent = `アップロード中: ${Math.floor(percentComplete)}%`;
}

この関数は、進捗度の値(percentComplete)を引数として受け取り、progressFillの幅とstatusMessageのテキストを更新します。

AJAXの進捗イベントとの連携


前述のuploadFile関数内で、AJAXのprogressイベントが発火するたびに、updateProgressBarを呼び出すことでプログレスバーをリアルタイムで更新できます。

xhr.upload.addEventListener('progress', (event) => {
    if (event.lengthComputable) {
        const percentComplete = (event.loaded / event.total) * 100;
        updateProgressBar(percentComplete);
    }
});

プログレスバーのスタイル調整


プログレスバーをより見やすくするために、スタイルを調整しましょう。以下のCSSコードは、プログレスバーの色や幅を設定し、進行がスムーズに見えるようにしています。

.progress-bar {
    width: 100%;
    height: 20px;
    background-color: #e0e0e0;
    border-radius: 5px;
    margin-top: 10px;
    overflow: hidden;
    position: relative;
}

.progress-bar-fill {
    height: 100%;
    width: 0;
    background-color: #4caf50;
    transition: width 0.4s ease;
}
  • background-color:バーの背景色を設定します。
  • transition:幅の変更が滑らかになるように遷移を設定します。
  • overflow: hidden:進捗バーの範囲外にはみ出さないようにします。

アップロード完了時の処理


アップロードが完了すると、プログレスバーが100%に到達するため、進捗表示やメッセージを更新します。xhr.onloadイベント内でアップロードが完了したことを確認し、次のようにメッセージを表示します。

xhr.onload = () => {
    if (xhr.status === 200) {
        const response = JSON.parse(xhr.responseText);
        if (response.status === 'success') {
            updateProgressBar(100);
            document.getElementById('statusMessage').textContent = 'アップロードが完了しました!';
        } else {
            document.getElementById('statusMessage').textContent = 'アップロードに失敗しました。';
        }
    }
};

視覚的な効果とユーザーエクスペリエンスの向上


プログレスバーの視覚的な効果により、ユーザーはファイルがどの程度アップロードされたかを一目で確認できます。これにより、アップロード中の待機時間がわかりやすくなり、ユーザー体験が向上します。

エラーハンドリングとリトライ処理


ファイルアップロード中にエラーが発生することは避けられません。ユーザーエクスペリエンスを向上させるためには、エラーハンドリングとリトライ機能を実装することが重要です。ここでは、アップロード失敗時のエラーメッセージの表示とリトライ処理の方法を解説します。

エラーハンドリングの基本


エラーハンドリングでは、以下のようなケースに対する対処を考えます。

  • ネットワークエラー:ネットワーク接続の問題でアップロードが中断するケース。
  • ファイルサイズの制限:サーバー側の設定により、許可されているサイズを超えるファイルのアップロードが拒否されるケース。
  • サーバーエラー:サーバーが正常に動作していない場合や、ファイルの保存に失敗した場合。

以下は、エラーハンドリングを行うためのJavaScriptコードです。

xhr.onerror = () => {
    document.getElementById('statusMessage').textContent = 'ネットワークエラーが発生しました。再試行してください。';
    showRetryButton(); // リトライボタンを表示
};

xhr.onload = () => {
    if (xhr.status === 200) {
        const response = JSON.parse(xhr.responseText);
        if (response.status === 'success') {
            document.getElementById('statusMessage').textContent = 'アップロードが完了しました!';
            updateProgressBar(100);
        } else {
            document.getElementById('statusMessage').textContent = response.message || 'アップロードに失敗しました。';
            showRetryButton();
        }
    } else {
        document.getElementById('statusMessage').textContent = 'サーバーエラーが発生しました。';
        showRetryButton();
    }
};

リトライ処理の実装


エラー発生時には、ユーザーに再試行のオプションを提供することで利便性を向上できます。showRetryButton関数を用いてリトライボタンを表示し、クリック時にuploadFile関数を再度呼び出すことでリトライを実装します。

function showRetryButton() {
    const retryButton = document.createElement('button');
    retryButton.textContent = '再試行';
    retryButton.onclick = uploadFile;
    const statusContainer = document.getElementById('statusMessage');
    statusContainer.appendChild(retryButton);
}

リトライボタンは、エラーメッセージの下に表示され、ユーザーがクリックすると再度uploadFileが実行されます。これにより、ネットワークの一時的な不具合やその他のエラーが発生した場合でも、ユーザーが簡単に再試行できるようになります。

リトライ回数の制限


リトライを繰り返しすぎると、サーバーに過度の負荷がかかる可能性があるため、リトライ回数に制限を設けることも推奨されます。リトライ回数を変数で管理し、特定回数を超えたらリトライボタンを無効化するなどの対策が考えられます。

let retryCount = 0;
const maxRetries = 3;

function uploadFile() {
    if (retryCount >= maxRetries) {
        document.getElementById('statusMessage').textContent = 'リトライ回数の上限に達しました。';
        return;
    }
    retryCount++;
    // アップロード処理の実行
    // ...
}

ユーザーへのフィードバック

  • エラーメッセージ:具体的なエラーメッセージを表示し、問題を明確にします。
  • リトライオプション:再試行できるボタンを用意し、エラー発生時のユーザーのストレスを軽減します。

これらのエラーハンドリングとリトライ処理の実装により、ネットワークやサーバーの問題が発生した際もユーザーに柔軟な対応が可能となり、より信頼性の高いアップロードシステムを構築できます。

セキュリティ対策とファイルサイズ制限の実装


ファイルアップロード機能を実装する際には、セキュリティリスクを考慮し、適切な対策を講じることが重要です。また、サーバー負荷を軽減するために、ファイルサイズの制限を実装することも推奨されます。ここでは、PHPとJavaScriptを使ったセキュリティ対策とファイルサイズ制限の方法について解説します。

セキュリティ対策


ファイルアップロードに関する主なセキュリティリスクとして、悪意のあるファイルのアップロードやディレクトリトラバーサル攻撃が挙げられます。以下に推奨される対策を示します。

  1. ファイルタイプの制限
    アップロードできるファイルの種類を限定し、不正なファイルのアップロードを防ぎます。PHPのmime_content_type関数を用いて、ファイルのMIMEタイプを確認しましょう。
   $allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
   $fileType = mime_content_type($file['tmp_name']);

   if (!in_array($fileType, $allowedTypes)) {
       echo json_encode(['status' => 'error', 'message' => '許可されていないファイル形式です。']);
       exit;
   }
  1. ファイル名のサニタイズ
    アップロードされるファイル名に特殊文字やパスが含まれている場合、これを除去することでディレクトリトラバーサル攻撃を防ぎます。PHPのbasename関数を使い、安全なファイル名に変換します。
   $fileName = basename($file['name']);
  1. アップロードディレクトリの適切な設定
    アップロードされたファイルは、Webから直接アクセスできないディレクトリに保存することが望ましいです。また、アップロードディレクトリには書き込み権限を設定し、不要な権限を付与しないように注意します。
  2. ファイル拡張子の確認
    ファイルの拡張子だけでなく、MIMEタイプと内容を確認することで、さらにセキュリティを強化できます。PHPで画像やPDFファイルの内容をチェックするための追加のライブラリも利用可能です。

ファイルサイズ制限の実装


ファイルサイズを制限することで、サーバー負荷やストレージ消費を抑えられます。PHPとJavaScriptの両方でサイズ制限を設けると、アップロード前にサイズの不適合をユーザーに通知できるため、効率的です。

  1. PHPでのサイズ制限
    PHPの設定ファイル(php.ini)でアップロード可能なファイルサイズを指定します。
   upload_max_filesize = 5M
   post_max_size = 6M

また、サーバーサイドでサイズを確認し、制限を超えている場合にエラーを返すことも可能です。

   if ($file['size'] > 5 * 1024 * 1024) { // 5MB制限
       echo json_encode(['status' => 'error', 'message' => 'ファイルサイズが大きすぎます。']);
       exit;
   }
  1. JavaScriptでのサイズチェック
    ファイル選択時にJavaScriptでサイズをチェックし、事前に制限を超えていないか確認します。これにより、サーバーへの不要なリクエストを減らせます。
   function checkFileSize(file) {
       const maxSize = 5 * 1024 * 1024; // 5MB
       if (file.size > maxSize) {
           document.getElementById('statusMessage').textContent = 'ファイルサイズが大きすぎます。';
           return false;
       }
       return true;
   }

   document.getElementById('fileInput').addEventListener('change', (event) => {
       const file = event.target.files[0];
       if (!checkFileSize(file)) {
           event.target.value = ''; // サイズが大きい場合は入力をクリア
       }
   });

ユーザーへの通知

  • ファイル形式やサイズに関するエラーメッセージは、statusMessage要素でリアルタイムに表示し、ユーザーが条件に合わないファイルをアップロードしようとした際に、事前に問題を通知します。
  • これにより、不要なアップロードを回避し、ユーザーエクスペリエンスを向上させるとともに、サーバーリソースの効率的な活用が可能となります。

これらのセキュリティ対策とファイルサイズ制限を実装することで、安全で効率的なファイルアップロードシステムを構築でき、サーバーやユーザー双方にメリットが生まれます。

実装コードの解説と動作確認


これまで解説してきた要素を組み合わせ、PHPとAJAXを使ってファイルアップロードと進捗状況の表示を実現するコードをまとめます。このセクションでは、コードの詳細な解説と動作確認のポイントを示します。

HTMLとJavaScriptコードの統合


まず、ファイルアップロードフォーム、プログレスバー、ステータスメッセージの要素をHTMLで準備します。JavaScriptを用いてAJAXリクエストを送信し、アップロードの進行状況を監視します。

<div class="upload-container">
    <form id="uploadForm" enctype="multipart/form-data">
        <input type="file" id="fileInput" name="file" required>
        <button type="button" onclick="uploadFile()">アップロード</button>
    </form>
    <div class="progress-bar" id="progressBar">
        <div class="progress-bar-fill" id="progressFill"></div>
    </div>
    <p id="statusMessage"></p>
</div>

以下は、JavaScriptのAJAXリクエストとプログレスバーの更新機能を統合したコードです。

function uploadFile() {
    const fileInput = document.getElementById('fileInput');
    const file = fileInput.files[0];

    // サイズチェック
    if (!checkFileSize(file)) return;

    const formData = new FormData();
    formData.append('file', file);

    const xhr = new XMLHttpRequest();
    xhr.open('POST', 'upload.php', true);

    // 進捗状況を取得し、プログレスバーを更新
    xhr.upload.addEventListener('progress', (event) => {
        if (event.lengthComputable) {
            const percentComplete = (event.loaded / event.total) * 100;
            document.getElementById('progressFill').style.width = percentComplete + '%';
            document.getElementById('statusMessage').textContent = `アップロード中: ${Math.floor(percentComplete)}%`;
        }
    });

    // 成功・失敗時の処理
    xhr.onload = () => {
        const response = JSON.parse(xhr.responseText);
        if (xhr.status === 200 && response.status === 'success') {
            document.getElementById('statusMessage').textContent = 'アップロードが完了しました!';
            document.getElementById('progressFill').style.width = '100%';
        } else {
            document.getElementById('statusMessage').textContent = response.message || 'アップロードに失敗しました。';
            showRetryButton();
        }
    };

    // エラーハンドリング
    xhr.onerror = () => {
        document.getElementById('statusMessage').textContent = 'ネットワークエラーが発生しました。再試行してください。';
        showRetryButton();
    };

    xhr.send(formData);
}

PHPファイルアップロード処理のコード


upload.phpのコードでは、ファイルサイズやタイプのチェックを行い、安全にファイルを保存します。次のコードでは、エラーメッセージをJSON形式で返してAJAXに対応しています。

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $file = $_FILES['file'];
    $allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
    $uploadDir = 'uploads/';
    $maxFileSize = 5 * 1024 * 1024;

    // ファイルサイズチェック
    if ($file['size'] > $maxFileSize) {
        echo json_encode(['status' => 'error', 'message' => 'ファイルサイズが大きすぎます。']);
        exit;
    }

    // ファイルタイプチェック
    $fileType = mime_content_type($file['tmp_name']);
    if (!in_array($fileType, $allowedTypes)) {
        echo json_encode(['status' => 'error', 'message' => '許可されていないファイル形式です。']);
        exit;
    }

    // ファイルの保存処理
    $fileName = basename($file['name']);
    $filePath = $uploadDir . $fileName;
    if (move_uploaded_file($file['tmp_name'], $filePath)) {
        echo json_encode(['status' => 'success', 'message' => 'ファイルのアップロードに成功しました!']);
    } else {
        echo json_encode(['status' => 'error', 'message' => 'ファイルの保存に失敗しました。']);
    }
}
?>

動作確認のポイント

  1. 進捗表示:小さいサイズのファイルで進捗が見えにくい場合、大きめのファイルを使って確認します。
  2. エラーハンドリング:無効なファイルタイプやサイズの大きいファイルをアップロードし、エラーメッセージが適切に表示されることを確認します。
  3. リトライ機能:エラー発生時にリトライボタンが表示され、再試行できるかをテストします。

動作確認の結果に基づく改善提案

  • ファイル名の変更:アップロードファイル名が重複しないように、ユニークな名前で保存する機能を追加するのも良いでしょう。
  • 進捗のアニメーション:視覚的な魅力を高めるため、プログレスバーのアニメーション効果を改善することも検討できます。

以上のコードと動作確認により、ファイルアップロードの進捗表示が正しく動作し、ユーザーにとって直感的で利便性の高いアップロード機能が実現できます。

応用:複数ファイルの同時アップロードの実装


複数のファイルを同時にアップロードする機能を追加すると、ユーザーにとってさらに便利なアップロード機能が実現できます。AJAXとPHPを用いて、複数ファイルの進捗状況を個別に表示する方法を解説します。

HTMLフォームの更新


複数のファイルを選択できるように、input要素にmultiple属性を追加します。また、複数のファイルごとにプログレスバーを表示できるように設計します。

<div class="upload-container">
    <form id="uploadForm" enctype="multipart/form-data">
        <input type="file" id="fileInput" name="files[]" multiple required>
        <button type="button" onclick="uploadFiles()">アップロード</button>
    </form>
    <div id="progressContainer"></div>
    <p id="statusMessage"></p>
</div>

JavaScriptでの複数ファイルアップロード処理


JavaScript側でファイルリストを取得し、ファイルごとにAJAXリクエストを送信します。各ファイルの進捗状況を監視し、個別のプログレスバーで表示します。

function uploadFiles() {
    const fileInput = document.getElementById('fileInput');
    const files = fileInput.files;
    const progressContainer = document.getElementById('progressContainer');
    progressContainer.innerHTML = ''; // プログレスバーを初期化

    for (let i = 0; i < files.length; i++) {
        const file = files[i];
        const progressBar = createProgressBar(file.name);
        progressContainer.appendChild(progressBar.container);

        uploadSingleFile(file, progressBar);
    }
}

// プログレスバーを生成する関数
function createProgressBar(fileName) {
    const container = document.createElement('div');
    container.className = 'file-progress';

    const label = document.createElement('p');
    label.textContent = fileName;

    const progress = document.createElement('div');
    progress.className = 'progress-bar';

    const progressFill = document.createElement('div');
    progressFill.className = 'progress-bar-fill';

    progress.appendChild(progressFill);
    container.appendChild(label);
    container.appendChild(progress);

    return { container, progressFill };
}

// 単一ファイルのアップロードと進捗表示
function uploadSingleFile(file, progressBar) {
    const formData = new FormData();
    formData.append('file', file);

    const xhr = new XMLHttpRequest();
    xhr.open('POST', 'upload.php', true);

    xhr.upload.addEventListener('progress', (event) => {
        if (event.lengthComputable) {
            const percentComplete = (event.loaded / event.total) * 100;
            progressBar.progressFill.style.width = percentComplete + '%';
        }
    });

    xhr.onload = () => {
        if (xhr.status === 200) {
            const response = JSON.parse(xhr.responseText);
            if (response.status === 'success') {
                progressBar.progressFill.style.width = '100%';
                progressBar.progressFill.style.backgroundColor = '#4caf50';
            } else {
                progressBar.progressFill.style.backgroundColor = 'red';
            }
        } else {
            progressBar.progressFill.style.backgroundColor = 'red';
        }
    };

    xhr.send(formData);
}

PHPでの複数ファイル処理


upload.phpでは、複数ファイルのアップロードに対応するため、$_FILES['files']配列をループして各ファイルを処理します。

<?php
$allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
$uploadDir = 'uploads/';
$maxFileSize = 5 * 1024 * 1024;
$results = [];

foreach ($_FILES['files']['tmp_name'] as $key => $tmpName) {
    $file = [
        'name' => $_FILES['files']['name'][$key],
        'type' => mime_content_type($tmpName),
        'size' => $_FILES['files']['size'][$key],
        'tmp_name' => $tmpName,
        'error' => $_FILES['files']['error'][$key],
    ];

    if ($file['size'] > $maxFileSize || !in_array($file['type'], $allowedTypes)) {
        $results[] = ['status' => 'error', 'message' => $file['name'] . 'はアップロードできません。'];
        continue;
    }

    $fileName = basename($file['name']);
    $filePath = $uploadDir . $fileName;

    if (move_uploaded_file($file['tmp_name'], $filePath)) {
        $results[] = ['status' => 'success', 'message' => $fileName . 'のアップロードに成功しました。'];
    } else {
        $results[] = ['status' => 'error', 'message' => $fileName . 'のアップロードに失敗しました。'];
    }
}

echo json_encode($results);
?>

動作確認のポイント

  1. 個別のプログレス表示:各ファイルの進捗状況が個別に表示され、進行中のファイルのみプログレスバーが更新されているかを確認します。
  2. エラーハンドリング:対応外のファイルタイプやサイズ超過ファイルをアップロードし、エラー表示が各ファイルごとに適切に行われているか確認します。
  3. 同時アップロード:複数ファイルを選択し、すべてのアップロードが正常に完了することを確認します。

このように複数ファイルの同時アップロードを実装することで、ユーザーにとって便利で柔軟なアップロード機能を提供できるようになります。

まとめ


本記事では、PHPとAJAXを使用してファイルアップロードの進捗状況をリアルタイムで表示する方法について解説しました。基本のファイルアップロードから、進捗表示のためのプログレスバー、セキュリティ対策、エラーハンドリング、複数ファイルの同時アップロードまで、ユーザー体験を向上させるための実装方法を網羅しています。これらを活用することで、安全かつ効率的なアップロード機能を備えたWebアプリケーションを構築できるようになります。

コメント

コメントする

目次