【備忘録】PHPとAjax(jquery)で進捗状況(プログレスバー)を表示する

# 概要
* 社内ツールでビューからオブジェクトを呼び出してデータの挿入をするツールを作りました
* 処理に時間がかかるためプログレスバーを表示する方向にしました
* データを送るということが構造上？知識的に難しかったので一時ファイルに吐き出し、それをajaxで一定時間ごとに読み込むという形で実現できました

# 最終的にどうなったか
* テスト検証のgifで実際にデータを入れているシーンなので進捗の推移が遅いです。

![progress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146880/3694a83d-7d5d-3557-5f11-cd4ddcd69ed5.gif)

# 処理構成(簡潔に)
1. index.php(ビューとビューからの処理が書かれている)の内容が画面に表示されています
2. ユーザーは色々とチェックボックスやラジオボタンなどの条件を入れます
3. 確認ボタンを押すと2.で入力された条件を元にデータを抽出しします(抽出したのは画面に表示)
4. さらに登録ボタンを押すと、抽出された内容がDBにInsertされ処理が完了するというものです。

## データの挿入条件
* 約8万件の情報
* DBの負荷を考えて5000件単位でInsert
* 処理開始から終了まで約15分

## 挿入中の画面状態
* 左上のくるくるがずっと出ている感じ

## 挿入後の画面状態
* 挿入後は画面が切り替わり、例外等なければ完了メッセージが出る

## 環境
* PHP5.2.8
* RHEL4
、、、社内ツールということもありリプレースの予定もなく古いです。

# ajaxで値のやり取りではなくローカルファイルから随時読み込む形に
## 進捗状況はアップロードばかり?調べてもあまり出てこない
* 調べても出てくるのはファイルをローカルからサーバーにアップロードするときの進捗状況の表示ばかりでした
* 大体がビューと同じファイルに書かれた処理の値をjs側で取得している内容でした
* 別phpファイルにリクエストを投げて取得するのもありましたが今回はオブジェクトとして呼び出したファイルから3ファイル先のオブジェクトを呼び出しそこでInsertするようにしていたので実現したいことと違う処理に感じました

## 実装(実際よりも簡単にしたのを書きます)
### 進捗状況までの流れ
1.Insert開始
2.Insertはループになっておりそのなかで進捗状況を上書きで書き出すようにしました

```php:insert.php

foreach ($idData as $id) {
    // 進捗率を求める(小数点以下はfloor()で切り捨て)
    $percent = floor($insertedIdCnt / $allIdCnt * 100);

    // ファイルに書込み
    $fp = fopen('percentNow.log', 'w');
    fwrite($fp, $percent);
    fclose($fp);

    // 挿入処理

    // 1ループ10秒止めておく
    sleep(10);
}
```
* この段階で毎ループで進捗率($percent)が上書きされていきます


3. ビュー側で上で吐き出したファイルを読み込んでいきます(以下ではjsファイルとして書いてますが実際にはphpファイルです

```javascript:progress.js

var Progress = (function() {
    function Progress(p) {
        this.bar = document.querySelectorAll('#progressBar > .progressBarBody')[0];
        this.p = p;
        this.update();
    }
    Progress.prototype.update = function() {
        this.bar.style.width = this.p + '%';
    }
    Progress.prototype.countup = function(data) {
        if (this.p < 100) {
            this.p = Number(data);
        }
        this.update();
    }
    return Progress;
}());

// 進捗率と進捗バーを更新する部分です
var updateProgress = function(progress) {
    $.ajax('./hogehoge/percent.log', {
        dataType: 'text',
        success: function(data) {
            $('#progress').html('進捗状況: '+data+'%');
                progress.countup(data);
        }
    });
}
 
// 今回はsubmitが2つあるためclickとボタンのID(#register)で処理します
// 10秒ごとにInsert≒進捗率変更なので1秒ごとに取得すれば十分かなと思いそう設定しています
$('#register').on('click', function() {
    $('#progressArea').html('<div id="progressBar" class="progress"><div class="progressBarBody"></div></div>');
    var progress = new Progress(0);
    $('#progress').html('進捗状況: 0%');
    setInterval(function() {
        updateProgress(progress);
    }, 1000);
});
```

5. ビューに表示(これもほんとはphpファイル)

```html:view.html

<!-- 進捗状況表示 -->
<div id="progressVal">
    <span id="progress"></span>
</div>
<div id="progressArea">
</div>
```

6. 進捗バーのCSS(デザインに合わせて調整してください)

```css:style.css

.progress {
  width: 60%;
  height: 30px;
  background-color: #F5F5F5;
  border-radius: 4px;
  box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
}

.progressBarBody {
  transition: width 0.5s linear;
  height: 100%;
  background-color: #337AB7;
  border-radius: 4px;
}
```

# 参考
* プログレスバーはこちらを参考にさせていただきました  
https://kuroeveryday.blogspot.com/2016/03/progressbar.html