PHPにおけるプログレスバーの実現2

再び、競馬の解析のPHP作成を再開しました。前はサイアーラインから色分けした血統表を作成、ってところまで作ったので、とりあえず保留。これからはオッズと着順の関係を条件ごとに検索できるシステムをちょくちょく作っていきたいと思っています。今はURL指定すれば自動で10000件くらいのレースのデータを取って来れるようにはなりました。次は取ってきたデータを解析するところを作っていきます。
話は変わってこのブログで一番アクセスが多いのがPHPのプログレスバー関連の話なので、gdgdだった前回の説明を補足、簡略化する意味で再び解説していきたいと思います。

プログレスバー?
競馬の解析をする際、情報はネットからスクレイピング(必要な部分だけ抽出してくること: はてなダイアリー)していますが、単純にウェブサイトを読み込む時間が必要なので、如何にブロードバンド時代と云えど100ページとか読み込むには相当な時間がかかります。しかもPHP側で特に何もしないと、果たして動いているのか動いていないのか分からないです(もしかしたらエラーが起きているかもしれない…)。そこでWindowsなどでファイルを移動するときに移動状況を表してくれる”アレ”がPHPでも使えたら便利じゃないか!まさにその”アレ”こそ、プログレスバーなのです。

タイムアウトするんだけど?
長い処理をするとタイムアウトしてしまうので、それを防がないとなりません。
set_time_limit(0);
こんな記述を冒頭に入れてあげましょう。


PHPの知識だけでできるの?
PHPの知識を持ってらっしゃる方は、大体HTMLの知識も持っていらっしゃると思います。プログレスバーは、PHP+JavaScriptで実現するのです。つまり、
    PHPでJavaScriptの関数を呼出 ⇒ JavaScriptでプログレスバーを動かす
といったことをやるわけです。それではPHPからどのようにして、JavaScriptを動かせば良いのでしょうか?

JavaScriptの準備
簡単のために、まずはテキストが表示される例を作成してみましょう。HTML側には以下のような記述をしてください。
<span id="msg"></span>
<script type="text/javascript">
function changeMsg(msg) {
    document.getElementById("msg").innerHTML = msg;
}
</script>
このchangeMsg()関数をPHPから呼び出し、<span>タグの中身を書き換えるわけです。

バッファについて
PHP側の記述を紹介する前に、「バッファ」について学んでおきましょう。バッファとはパソコンが処理をする際にそのデータを一時的に蓄えておくところのことです(パソコン用語 - バッファとは)。PHPで意識しなければならないバッファは2種類あります。1つ目はサーバー側のバッファで、PHPで処理しているデータを向こうが処理が完了するまでためている、なんてことがあったら処理が完了するまで途中経過のデータが見れないことになってしまいます。2つ目はブラウザ側のバッファです。読み込みが遅くて画面が真っ白だから、もうや~めた、と思って中止ボタンを押すと、途中まで表示された!なんて例を挙げてみると分かりやすいのではないでしょうか。これらを吐き出させるためにPHPで次の2行を記述しなければなりません。
ob_flush();
flush();
バッファをフラッシュ(水をどっと流す)してあげる記述です。

PHPからJavaScriptを呼び出す!
いよいよここまで来ましたね。さぁ、どうするんだ!といった感じですが、実は至って簡単なのです。
$com = "表示したい内容"
echo '<script type="text/javascript">changeMsg("' . $com . '")</script>';
Quick Lookup:
これだけです。ボブ風にいうと(ボブ知らなかったらすみませんww)、ほら、簡単でしょう?と言った感じですね。そして、お友達も書いてあげましょう、といった感じで、
sleep(1); // 重い処理する場所
$com = $i . "/" . $total; // $i: 処理中のデータ番号 $total: データ総数
echo '<script type="text/javascript">changeMsg("' . $com . '")</script>';
ob_flush();
flush();
こんな風にしちゃえばOKです。いかがでしょうか?思ったよりも簡単ですよね。具体例を挙げると、
$i=1;
foreach($url as $urls) {
    getDataFromURL($url);
    // ($urlのページからデータを取ってくる自分で定義した関数)
    $com = $i . "/" . count($datas);
    echo '<script type="text/javascript">changeMsg("' . $com . '")</script>';
    ob_flush();
    flush();
}

こんな感じです。

プログレスバーに応用したい場合は、JavaScript側で工夫さえすればPHPで何もする必要はありません。PHPにおけるプログレスバーの実現でプログレスバーを動かすサンプルを置いてあるのでぜひそちらも見てみてください。

ボールの放り投げ

ActionScript3.0始めました。今日はボールの放り投げについてのソースを書いてみました。ステージ内でボールをクリックするとドラッグ出来ます。そのまま放り投げたとき、ステージの端で跳ね返る運動を書いてみました。
サンプル:

// イベントリスナー
my_ball.addEventListener(MouseEvent.MOUSE_DOWN, switchOn);
stage.addEventListener(MouseEvent.MOUSE_UP, switchOff);
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveBox);
stage.addEventListener(Event.ENTER_FRAME, throwBox);

// パラメータ
var sw:Boolean = false;
var click_x:int = 0;
var click_y:int = 0;
var mouseX_bef:int;
var mouseY_bef:int;
var v_x:Number = 0;
var v_y:Number = 0;
var rub:Number = 1.01; // 摩擦
var ela:Number = 1.2; //弾性率
var limitX:int = stage.stageWidth - my_ball.width;
var limitY:int = stage.stageHeight - my_ball.height;

// マウスダウンするとスイッチON&ズレ分取得
function switchOn(event:MouseEvent):void {
    sw = true;
    click_x = event.stageX - my_ball.x;
    click_y = event.stageY - my_ball.y;
}

// マウスアップするとスイッチ
function switchOff(event:MouseEvent):void {
    sw = false;
}

// ボックスを移動する&速度指定
function moveBox(event:MouseEvent):void {
    if(sw) {
        my_ball.x = stage.mouseX - click_x;
        my_ball.y = stage.mouseY - click_y;
        v_x  = stage.mouseX - mouseX_bef;
        v_y = stage.mouseY - mouseY_bef;
        mouseX_bef = stage.mouseX;
        mouseY_bef = stage.mouseY;
    }
}

// ボールを投げる
function throwBox(event:Event):void {
    if(!sw) { // 捕まえられたら止まる
        // 画面外に行かないように
        if(my_ball.x < 0) my_ball.x = 0;
        if(my_ball.x > limitX) my_ball.x = limitX;
        if(my_ball.y < 0) my_ball.y = 0;
        if(my_ball.y > limitY) my_ball.y = limitY;
       
        // 端っこで跳ね返る
        if((my_ball.x + v_x) < 0 || (my_ball.x + v_x) > limitX) {
            v_x = -v_x/ela;
        }
        if((my_ball.y + v_y) < 0 || (my_ball.y + v_y) > limitY) {
            v_y = -v_y/ela;
        }
           
        // 摩擦
        v_x = v_x/rub;
        v_y = v_y/rub;
       
        // 移動
        my_ball.x += v_x
        my_ball.y += v_y;
       
        // 動き続けないように
        if(Math.abs(v_x) < 0.01) v_x = 0;
        if(Math.abs(v_y) < 0.01) v_y = 0;
    }
}


ちなみに、改良するとこんなんなります。

checkboxのリセット

PHPなどでチェックボックスを配列として受け取るときは、nameの後ろに[]を付ければOKです。しかし、JavaScriptを使ってそんなチェックボックスを全部リセットしたい!もしくは全部チェックしたい!って場面に出くわしたことはないでしょうか。nameが全部同じだからどうやって判別したらいいんだろう・・・?そんな時は、全部の要素を調べてしまうという方法があります。
<form action="./hoge.php" method="POST" name="hoge">
    <input type="checkbox" name="chk[]" value="1" />
    <input type="text" name="text1" value="凸" />
    <input type="checkbox" name="chk[]" value="2" />
    <input type="text" name="text2" value="凹" />
    <input type="checkbox" name="chk[]" value="3" />
</form>

-----------(preview)-----------
こんな風にタグが並んでいるときに、チェックボックスだけ選択してチェックをいれるためには、
document.[form名].elements.length
を使います。これはform内にある要素の数を数えてくれます。上の例でいえば5となります。では、早速すべてのチェックボックスをチェックするスクリプトを書いてみましょう。
<script type="text/javascript">
    function chkAllChkbox() {
        for(i=0;i<document.hoge.elements.length;i++) {
           if(document.hoge.elements[i].name == "chk[]") {
                document.hoge.elements[i].checked = true;
           }
        }
    }
</script>
<input type="button" onClick="chkAllChkbox()" value="check" />

-----------(preview)-----------
いかがでしょうか。なお、checkboxの数を
document.[form名].elements['checkboxの名前'].length
で調べることもできます。覚えておくと便利?これを使ってradioボタンみたいなことを実現してみましょう。checkboxに更にIDを加えます。上とは違ってgetElementByIdを使ってcheckedを調べています。

<script type="text/javascript">
    function unchkOthers(num) {
        for(i=1;i<=document.hoge2.elements['chk[]'].length;i++) {
            document.getElementById('chk' + i).checked = false;
        }
       document.getElementById('chk' + num).checked = true;
    }
</script>

<form action="./hoge.php" method="POST" name="hoge2">
    <input type="checkbox" name="chk[]" value="1" id="chk1" onClick="unchkOthers(1)" />
    <input type="checkbox" name="chk[]" value="2" id="chk2" onClick="unchkOthers(2)" />
    <input type="checkbox" name="chk[]" value="3" id="chk3" onClick="unchkOthers(3)" />
</form>

-----------(preview)-----------
getElementByIdとはその名の通りIDから要素を判別することができます。是非使ってみてくださいね。


Quick Lookup:

ドレミファソラシのMP3データ

FLASHでマウスオーバーするとポロロンってなるようにしたかったので、ドレミのWAVかMP3のデータを探したのですがなかなかなかったので作ってみました。手順は、
1、MuseでMIDIファイルを作成
2、Timidi95でWAVに変換
3、Lame Ivy Frontend EncoderでMP3に変換
といった面倒くさい手順を経て完成しました。ビットレートは48kでファイルサイズは1個当たり約6KB程度です。ちなみに著作権フリーなので適当に扱ってください。ダウンロードは下をクリックです。

drmfslc.zip