解放区在住氷翠 緑の閃光
【解放区在住氷翠】webアプリケーション

【jquery】ファイルのアップロードとプログレスバー

2023-08-02

どうも、氷翠です。

さて、今回はHTML+CSS+javascript(jquery)を利用したプログレスバー(進捗状況)を表現する。実際に使う現場というところは、大きなサイズのファイルのアップロードするときというのがほとんどかと思われます。

もちろん、受け取り側はPHPで準備しています。

<?php
// 情報を受け取る
$fileInfo = $_FILES['file'];

// 保存先のパスの定義とファイル名を変更する
$path = __DIR__.'/data/';
// 拡張子を取り出したいのでピリオドで分割する
// 前の部分は使わないので、適当な変数名にしておく
list($p, $exp) = preg_split("/\./", $fileInfo['name']);
// サーバーに保存するファイル名は日付と時間で保管する
$fn = date("YmdHis").'.'.$exp;
$filePath = $path.$fn;

// 出力
// アップロードファイルを指定のパスに保存する
// 成功したら文字列で'true'を出力、失敗したら'false'を出力する
if(move_uploaded_file($fileInfo['tmp_name'], $filePath))
{
    echo 'true';
} // end if
else
{
    echo 'false';
} // end else

このファイルは基本的なものなので、これといって特記するところではないかも。

最終的に出力しているのは、「true」「false」という2種類の文字列を出力している。

では、次にアップロードするフォームです。

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>【jquery】ファイルのアップロードとプログレスバー</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
</head>
<body>
<main>
    <div class="inner">
        <p>ファイルのアップロード</p>
        <p><input type="file" name="file"></p>
        <p><button type="button" name="send">送信</button></p>
        <div id="prog"><span></span></div>
        <p>(<span id="pv">0%</span>)</p>
    </div>
</main>
</body>
</html>

HTMLです。とりあえず、jqueryを読み込ませる。
この中ではjavascriptとCSSを省いた状態にしてある。

単純なもの。

しかし、progressタグは使っていない。というのも、この時点ではsafariでは反応しなかったというのがある。それ以外のchrome、Edge、firefoxなどのブラウザは普通に動いてくれたのだが、safariだけは動いてくれなかったのだ。

次にCSS。

<style type="text/css">
    /* HTMLとbodyに対しての初期化 */
    html, body {
        width: 100%;
        height: 100%;
        padidng: 0;
        margin: 0;
    }
    /* mainタグに対しては画面全体の定義とする */
    main {
        width: 100%;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
    }
    .inner {
        border-radius: 5px;
        border: 1px solid #333;
        padding: 1em;
    }
    p {
        margin: 0 0 1em;
        text-align: center
    }
    p:last-child {
        margin: 0;
    }
    p > span {
        color: #00b200;
    }
    /* プログレスバーを作成する */
    #prog {
        width: 100%;
        height: 6px;
        border-radius: 3px;
        border: 1px solid #CCC;
        background-color: #EEE;
        margin: 0.5em 0;
        overflow: hidden;
    }
    /* プログレスバーの中身を定義 */
    #prog > span
    {
        content: '';
        display:block;
        border-radius: 2px;
        height: 4px;
        position: relative;
        top: 0px;
        left: 0px;
        background-color: #0A0;
        box-sizing: border-box;
    }
</style>

画面の中央に表示させるという感じ。あとはプログレスバーをそれなりに形を整える感じで。

あと、プログレスバーの中のspanタグがバーになっているのだが、これはspanタグが進捗状況を表現しているものになる。これに関してはいろいろな方法があるが、ここではspanタグを利用している。

そして、肝心のjavascriptです。

<script>
$(function() {
    // プログレスバーの初期化
    // 横幅を0%にすることで、何も表示されなくなる
    $('#prog > span').css('width', '0%');
    // 送信ボタンが押されたときの動作
    $('button').on(
        'click', 
        function() 
    {
        // FormDataにアップロードするファイル情報を入れておく
        var formData = new FormData();
        formData.append("file", $("[name=\"file\"]")[0].files[0]);
        // 一応、ここでもプログレスバーを初期化する
        // これで何度でも使うことができる
        $('#prog > span').css('width', '0%');
        // ajaxを利用してアップロードする
        $.ajax({
            url: './upload.php',
            type: 'POST',
            processData: false,
            contentType: false,
            async: true,
            data: formData,
            // データを送信する間の情報をここで受けとる
            xhr: function() {
                XHR = $.ajaxSettings.xhr();
                if (XHR.upload)
                {
                    XHR.upload.addEventListener('progress', function(e)
                    {
                        // eの中に情報が入っている
                        // 小数点2位までの%を計算する
                        var progVal = parseInt(e.loaded / e.total * 10000) / 100;
                        // プログレスバーの横幅を%で表示していく
                        $('#prog > span').css('width', progVal + '%');
                        // テキストでも表示する
                        $('#pv').text(progVal + '%');
                        if (progVal == 100)
                        {
                            // アップロードが完了したら、サーバー側で保存処理が始まる
                            $('#pv').text('保存中...');
                        } // end if
                    }, false);
                }
                return XHR;
            }
        })
        .statusCode({
            // ステータスコードによる処理
            404: function() {
                alert("404エラーにより処理を中断しました");
                return false;
            },
            500: function() {
                alert("500エラーにより処理を中断しました");
                return false;
            }
        })
        .done(function(data) {
            // サーバーの処理が完了したら
            // その結果を受け取る
            if (data == 'true')
            {
                alert('アップロードが完了しました。');
                // 最後のアラートを出したら、
                // プログレスバーと文字列の部分を初期化して終了となる
                $('#prog > span').css('width', '0%');
                $('#pv').text('0%');
            } // end if
            else
            {
                alert('アップロードが失敗しました。');
            } // end else
        });
    });
});
</script>

問題なのは、「xhr: function() {…}」という部分になる。

結構難しい感じになっているのだが、最善の策だろうかとw

いろんなサイトを見て勉強した結果、こんな感じになったわけです。

動画では20分超えの動画になってしまったけど、これをテンプレートにしてしまえば、それほど時間をかけずに処理することができるのではないでしょうか?

コメントを残す

メールアドレスが公開されることはありません。