【特別企画】 トラフィックエクスチェンジを作ってみよう! > 5、他のユーザーのページを表示できるようにしてみる

5、他のユーザーのページを表示できるようにしてみる

トラフィックエクスチェンジと言えばタイーマとフレーム。 そしてそのフレームの中に次々に表示される登録ユーザーのページの数々です。
回れカウンター! 増えろPV!
無人の室内で、就寝後の闇の中で、電気代と回線の負荷だけを上げ続けながらどこまでも!

動作テスト用にURLをいくつか登録しておく

前回まででユーザーのレコードファイルを生成して、そこにポイントを書き込んでいく準備まではできたのでした。 今回はサーフ時にそのレコードを読み込んで、各ユーザーのページを実際にフレーム内に表示していきましょう。

というわけで、事前に動作テスト用にユーザーレコードをいくつか登録しておくとよいです。 手作業でuserDataフォルダにファイルを作ってもよいのですが、ファイル名がMD5なので少々やりづらいかもしれません。 せっかくログインフォームまで作成済みなのですから、それを使って適当にURLをいくつか登録しておきましょう。 自分のサイトやブログをお持ちの方はその中のページを個別に登録するとよいでしょう。 ローカル環境で動作テストしているならば、ローカル環境に適当にページを作ればよいですね。 ただし、間違っても無関係の一般のサイトを登録してはいけません。DOSアタックだと思われちゃうかもしれないゾ!

フレームにユーザーのページを表示する

さて、やりたい処理は何かと言うと、
サーフページにアクセスしたときに、

・userDataフォルダの中からファイルを1つランダムに選び出して
・そこに登録されているURLをフレーム内に表示

です。

たとえばこんな感じになってるといいな〜、って感じですよね

surf.php のPHP部分
<?php
    // 外部のファイルを読み込む
    require_once ("functions.php");
    
    // ログインフォームからの入力を受け取る
    $url = $_POST['url'];
    
    // セッション開始
    session_start();
    
    // セッションにログイン情報(っていうかURLだけ)を保存
    $_SESSION['url'] = $url;
    
    // 登録されてないなら登録する
    RegisterIfNecessary ( $url );
    
    // 自分の情報を取得
    $info = ReadUserDataFile ( md5($url) );
    $myPoint = $info['point'];

    // サーフ対象ページ取得
    $pageToSurf = GetPageToSurf ( $url );
    
?>

前回までに作っておいたサーフ画面のPHP部分の末尾に GetPageToSurf を追加しています。 もちろんPHPにこんな都合のいい機能があるわけがないノダァふえ〜んごめんなさいですぅなので 例によって後で functions.php に処理の中身を作り込んでいこうかなということなのでありまして、 ここで先に夢だけ見ておいて後でカム・トゥルーさせようってことです。

夢を語りましょう。GetPageToSurf を実行すると内部でゴニョゴニョして、登録されているURLが1つ選び出されてくる、という仕掛けです。 パラメータに自分のURLを入れているのはどういう意味かというと、自分のページは表示しなくてもいいので ゴニョゴニョの際に除外してね、ってことです。 そうして選び出されたURLが $pageToSurf に入ってくる。 それをフレームに表示するのはHTMLの世界です。 どっちかというとJavaScriptかな? つまり専門用語で言うと「クライアント側」ってやつです。

surf.php の JavaScript部分
    <script>

        // 初期の秒数。
        var time = 10;
        
        // 最初に実行される処理
        function start() {
            
            // フレームにユーザーのページを表示
            var surfFrame = document.getElementById("surfFrame");
            surfFrame.src = "<?php echo $pageToSurf; ?>";
                    
            // 秒数を表示(関数化しました)
            updateTimer();

            // countDownという名前の関数を 1000ミリ秒後に実行
            setTimeout ( countDown, 1000 );
        }
        
        ~ 中略 ~
        
    </script>

JavaScriptで最初に実行される関数の中で表示処理を書いています。 フレームのIDを指定して、URLを代入です。

フレーム部分はこんな感じでしたね。

surf.php の フレーム部分
    <body onload="start();">

        <!-- タイマーが表示される側 -->
        <div id="surfNavi">
    
            MyURL : <?php print $url; ?> <br>
            ポイント : <?php echo $myPoint ?><br>
    
            あと<span id="timer"></span>秒
        </div>

        <!-- 宣伝先のページが表示される側 -->
        <iframe id="surfFrame"></iframe>

    </body>

今まではデフォルトで src="デフォルトページ" という属性を書いてたと思いますが、 サーフページを表示した瞬間に一瞬それが表示されてしまうのはカッコ悪いような気がしなくもないのでここではsrc属性は削除しました。

ん? っていうかわざわざJavaScriptでやらなくても、iframeタグの src属性の側に "<?php echo $pageToSurf; ?>" を書けばいいのかな?  そんな気もしてきました。お好みでどうぞ。

ではさきほど夢見た通りに functions.php の側に GetPageToSurf を書いていきましょう。

functions.php の中のどこかに追加
//=========================================================
// サーフ対象のページURLを取得
//=========================================================
function GetPageToSurf ( $selfUrl ) {
    
    $result = "";
    $userDataDir = "userdata";
    $selfUrlMd5 = md5($selfUrl);
    
    // userdataフォルダの中のファイルのリスト(=ユーザーレコードのリスト)を取得
    $files = array_diff ( scandir($userDataDir), array('.', '..', $selfUrlMd5));
    
    // レコード数を確認    
    $fileCount = count($files);
    
    // レコードが存在する場合
    if ( $fileCount > 0 ) {
        
        $randomKey = array_rand ( $files );
        
        $userFileName = $files[ $randomKey ];
        
        $info = ReadUserDataFile($userFileName);
        
        $result = GetValue ( $info, 'url');
    
    // レコードが存在しない場合
    } else {
        
        // デフォルトページでも表示することしましょうか。
        $result = "http://デフォルトページ"; // ファイルを適当に作ってURLを書いておいてください。

    }

    return $result;
}

冒頭3行は見たままとして、その次。

    // userdataフォルダの中のファイルのリスト(=ユーザーレコードのリスト)を取得    
    $files = array_diff ( scandir($userDataDir), array('.', '..', $selfUrlMd5));

scandir というのがPHPの便利機能で、指定したフォルダの中のファイル名のリストを取得できます。 素朴に書くなら $files = scandir($userDataDir); です。 が、こうすると余分なものまで取得されてしまうのです。 余分なものとは何かというと「.」と「..」です。

これは一体何なのか?

「.」というのは「このフォルダ」を表す特殊な文字列です。
「..」というのは「1つ上の階層」を表す特殊な文字列です。
余分なものと言ってはファイルシステムさんに失礼ですが、今回の用途には不要です。

それからもう1つ、自分のレコードも不要ですよね。 つまり scandir で取得できるリストの中から、その3つを差し引いたものが欲しい。 というわけで array_diff です。 これまたPHPの便利機能でありまして、リストを2つ指定して、差分のリストを取得することができます。まさに渡りに船。 指定する2つのリストとはすなわち以下の2つです。

・userdataに入っている全ファイル名のリスト : scandir($userDataDir)
・特殊文字と自分のレコードを合わせたリスト : array('.', '..', $selfUrlMd5)

この2つを array_diff に入れる。 つまり上のソースにあるように、

    $files = array_diff ( scandir($userDataDir), array('.', '..', $selfUrlMd5));

とすることで $files に目的のリストが入ってくるというわけです。やったぜ!

そういえば、ポイントが0になっているユーザー(URL)は表示しないようにしなくていいんでしょうか?  いいんです。なぜかと言うと、「このフォルダにレコードファイルが存在する=ポイントが残っている」だからです。 ここで「何ポイント残っているか?」を気にする必要はありません。 というか、そういうふうにします。次回以降ですがポイントを減らす処理のところで「ゼロになったらファイルごと削除」 という処理を入れます。

さて、その後はレコードの件数を確認しています。

    $fileCount = count($files);

そして if文で、レコードが存在する場合は本来の処理を、存在しない場合はデフォルトページを入れる、というふうにしています。 あれ? ちょっと気になったんですが、今更ながらif文ってわかります? PHP自体の説明をしているとキリがないのですが、要は「場合分け」です。 たとえて言うなら if (愛してる) { 旅立つ } else { やっぱり旅立つ } ということです。うむ。わかりやすい。問題ないですよね。

ではさて、その本来の処理で何をしているか?

    // レコードが存在する場合
    if ( $fileCount > 0 ) {
        
        $randomKey = array_rand ( $files );
        
        $userFileName = $files[ $randomKey ];
        
        $info = ReadUserDataFile($userFileName);
        
        $result = $info['url'];

array_randというのがまたまたPHPの便利機能で、リストを指定するとランダムに1つ選び出してくれます。 が、リストの中身を選んでくれるのではなく、リストの添字というか、つまり通し番号を選んでくれるという微妙に回りくどい便利機能なのでした。 というわけで、これで取得した値を使って、$files[ $randomKey ]; として中身を手に入れています。 「中身」とは何かと言うと、ユーザーレコードのファイル名でしたね。

ここまできたら後は楽勝です。 前回だったか前々回だったら忘れましたが、ユーザーの登録情報を取得する機能「ReadUserDataFile」を作ったではありませんか。 それを使って登録情報を取得し、URLを取り出すのです。

ではさて、これで夢が実現しているはず。
目を開けて確かめるぜ!

ログイン画面からサーフ画面へアクセスすると……

登録しておいたユーザーのページが表示されるぜ! イヤッホゥ!

タイマーのカウントゼロで次のページを表示

夢が実現したと思いきや、今のままだといちいちログインしなおさないと次のページが表示されません。 そのような手作業をユーザーに課すようではトラフィックエクスチェンジとは呼べぬ! 閲覧者不在で動いてこそトラフィックエクスチェンジ!

というわけでタイマーのカウントがゼロになったときの処理を追加していきましょう。

確か今はその部分は仮埋めとして、こうなってたんでしたっけ。

surf.php のJavaScriptの部分
    // サーフ完了の処理
    function surfCompleted() {

        /*
            次回のお楽しみ
            (あ、これは「複数行のコメント」です)
        */

        // 今日のところはタイマーの数字を元に戻して再びカウント続行することにします。
        time = 10;
        updateTimer();
        setTimeout(countDown, 1000);
    }

次回のお楽しみと言いつつ、結構引っ張ってしまいましたね。 ではこの関数の中身を実際の処理に変えていきましょう。

やることは何かと言えば、登録されているユーザーのページを再びランダムに選び出してフレームに表示、です。 なーんだ、それならもう処理を作ってあるからそれをコピペすればいいだけですよね?
こんな感じで↓

    // サーフ完了の処理
    function surfCompleted() {
        
        // サーフ対象ページ取得
        $pageToSurf = GetPageToSurf ( $url );
    }

が、そうは問屋が下ろさない。あ、字ぃ間違えた。卸さない。 なぜならここはJavaScriptの世界。PHPの処理を持ち込むことはできないのでした。

ここでちょっと「サーバー」「クライアント」という楽しいガイネンを意識してください。
PHPで書いた処理は「サーバー側」で実行されます。 つまり、ネットワークを通ってあなたのブラウザに届く前にサーバーの内部で実行されます。 一方、JavaScriptやHTMLは「クライアント側」です。 つまり、あなたのパソコン(ブラウザ)の側の世界です。 もちろんデータそのものは元はと言えばサーバー側にあるのですけど、 そこでは単にデータとして保存されているだけなのであって、実行されるというわけではないのです。 あなたのパソコンに送信されて、ブラウザに読み込まれた段階で初めてHTMLとして効力を発揮する。JavaScriptが実行される(あなたのパソコンで)。 「クライアント側」というのはそういう意味です。ちなみに今回は関係ありませんがスタイルシートもですね。

さて、登録ユーザーのレコード群はサーバー側に保存されています。 だから、「次のページ」を取得するには、もう一度サーバー側にアクセスする必要があるのでした。 ここには単にPHPとJavaScriptという言語の壁があるだけでなく、ネットワークの壁があるのでした。

ではさて、サーバーにアクセスするにはどうすればいいだろう?  方法はいろいろあります。 が、もっとも単純なのはブラウザのアドレス欄にURLを入力してしまうことです。 しかし、それではあんまりなので、JavaScript的にやりましょう。

    // サーフ完了の処理
    function surfCompleted() {
        
        location.href = "surfCompleted.php";
    }

location.href にファイル名というかURLを指定すると、ブラウザがそこにアクセスしてくれます。ぶっちゃけページを移動しちゃうわけですよ。わかりやすい!  というわけでサーバー側に surfCompleted.php というファイル(ページ)を追加しましょう。 そこにアクセスされてしまえばそこはもうサーバー側ですから、そこで好きなだけゴニョゴニョするのです。

surfCompleted.php
<?php

    // サーフページへ戻る(URLはあなたが作っているサーフページのものにしておいてね)
    header('Location: http://xxxxxxxxxxx/surf.php');

?>

あれ? ゴニョゴニョと言いつつこんだけですか?
何をしているかと言うと、サーフページを再表示しているだけです。 次のページを取得したりするんじゃなかったでしたっけ?  それはそうなんですけど、それはサーフページの冒頭のPHP処理の中に書いてあるんですから、サーフページへ戻れば望み通りですよね。 ん? でも、だったらこんなふうにファイルを追加しなくても、単に画面をリロードしたって同じだったんじゃないんですか?
確かにそうです。
が、サーフ完了時には他にもサーバー側でやりたいことがあるじゃないですか。 ほら、ポイントを追加するとか、相手のポイントを消費させるとか。 それを次回以降、ここに書いていこうってことなのサ。なーんだ、そうならそうと言いなさいよねっ。アハハ。ウフフ。

でも、このまま無造作にサーフ画面に戻るとマズイことが起きます。
ソースを見てみましょう。

surf.php のPHP部分
<?php
    // 外部のファイルを読み込む
    require_once ("functions.php");
    
    // ログインフォームからの入力を受け取る
    $url = $_POST['url'];
    
    // セッション開始
    session_start();
    
    // セッションにログイン情報(っていうかURLだけ)を保存
    $_SESSION['url'] = $url;
    
    ~ 以下略 ~
    

ログインフォームを経由せずにここへ来ると $url が取得できません。 つまり $_POST['url'] が存在しないということです。 存在しないものを取得しようとするとPHP的によろしくないことになります。 取得できないままの変数 $url を持ち回るのもよろしくありません。

よろしくないならどうするか?
処理を書き換えるのです。

surf.php のPHP部分
<?php
    // 外部のファイルを読み込む
    require_once ("functions.php");
    
    // ログインフォームからの入力を受け取る
    $url = GetValue ($_POST, "url");
    
    // セッション開始
    session_start();
    
    // この時点で $url が取得できていない = すでにログイン済みなんじゃない?    
    if ( empty($url) ) {
        
        // セッションからURLを取得
        $url = GetValue ($_SESSION, "url");
        
    // ログインフォームからのURLが入力されていた=ログインしたところってことですね?
    } else {
        
        // セッションにログイン情報(っていうかURLだけ)を保存
        $_SESSION['url'] = $url;
    }
    
    // (念のための確認)
    // それでもまだ URLが取得できていない=空欄でログインでもしたのかな?
    if ( empty($url) ) {
        
        // ログイン画面にでも戻っておく
        header('Location: http://xxxxxxxxxxx/login.html');
        exit(0);
    }    

    ~ 以下略 ~
    

まず冒頭の、

    // ログインフォームからの入力を受け取る
    $url = GetValue ($_POST, "url");

というのは何かというと、$_POST の中に "url" というキーで値が入っているかどうかを確認しつつ値を取得、 という至れり尽くせりな機能です。$_POSTに限らず、$_SESSIONにでも何にでも使えます。 へぇ〜PHPには便利な機能が……ってそんなもんないわ! 自分で作るんじゃ! ふえ〜んごめんなさいですぅ〜。

というわけで、functions.php にでも実装しておくこととします。

functions.php の中のどこかに
function GetValue ( $obj, $key ) {
    
    $value = "";
    
    if ( isset ( $obj[$key] ) ) {
        $value = $obj[$key];
    }
    
    return $value;
}

何をしているかと言うと、つまりその、 さきほど夢見た通りに至って尽くしているというわけです。
このぐらいPHPが標準で面倒見てくれるといいんですけどねぇ。 ひょっとして私が知らないだけで実はあったりして? ククク、赤面の予感がするぜ!  はい、もしあるならそっちを使うとよいですよ、っと。

さて、surf.phpの方に話を戻しましょう。
この GetValue で $_POST の 'url' の値を取得した結果、取得できなかった(=空文字)とき、 すでにログイン済みであると判断し、$_POST ではなく $_SESSION からログイン情報(というか URL)を取得しています。 $_POSTからURLを取得できたならログイン画面を経由してサーフ画面に来たのだと判断し、 今まで通りのログイン処理をしています。

細かいことを気にし出すと心が病んできますが、大体このぐらい細工をしておけばよいでしょう。

では試してみましょう。
ログイン画面からサーフ画面へ移動して……

タイマーが0になると……

次のページが表示された!
これぞオートサーフ! よーし、このまま放置して宇宙の果てまでお買い物にお出かけだ!

ところで、これが例えば「手動」だったとしたらどうすればいいでしょうか?
ここに「次へ」とかのボタンを追加して、ボタンが押されたかどうかを判定して……という処理を追加する必要があります。 あるいは表示されたサイト名を含む4択を表示するとかクイズを表示するとかの創意工夫をしようと思うとさらなる努力が必要です。 つまり作る立場ではオートが一番楽ちんってことです。「オートという便利な機能」なんかじゃないんだぜ? 手抜きなんだぜ?

今回のまとめ

今回変更を加えたのは surf.php と functions.php。そして surfCompleted.php を新たに追加したのでした。

surf.php
<?php
    // 外部のファイルを読み込む
    require_once ("functions.php");
    
    // ログインフォームからの入力を受け取る
    $url = GetValue ($_POST, "url");
    
    // セッション開始
    session_start();
    
    // この時点で $url が取得できていない = すでにログイン済みなんじゃない?    
    if ( empty($url) ) {
        
        // セッションからURLを取得
        $url = GetValue ($_SESSION, "url");
        
    // ログインフォームからのURLが入力されていた=ログインしたところってことですね?
    } else {
        
        // セッションにログイン情報(っていうかURLだけ)を保存
        $_SESSION['url'] = $url;
    }
    
    // (念のための確認)
    // それでもまだ URLが取得できていない=空欄でログインでもしたのかな?
    if ( empty($url) ) {
        
        // ログイン画面にでも戻っておく
        header('Location: http://xxxxxxxxxxx/login.html');
        exit(0);
    }    

    // 登録されてないなら登録する
    RegisterIfNecessary ( $url );
    
    // 自分の情報を取得
    $info = ReadUserDataFile ( md5($url) );
    $myPoint = $info['point'];

    // サーフ対象ページ取得
    $pageToSurf = GetPageToSurf ( $url );
    
?>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>トラフィックエクスチェンジだぜ!</title>

        <script>
            
            var time = 10;
            
            function start() {

                var surfFrame = document.getElementById("surfFrame");
                surfFrame.src = "<?php echo $pageToSurf; ?>";
                
                updateTimer();
                
                setTimeout(countDown, 1000);
            }
            
            function updateTimer() {
            
                var timer = document.getElementById("timer");
                timer.innerHTML = time;
            }

            function surfCompleted() {
                
                location.href = "surfCompleted.php";
            }
            
            function countDown() {
                
                time -= 1;
                
                if ( time <= 0) {
                
                    surfCompleted();

                } else {
                
                    setTimeout(countDown, 1000);
                }

                updateTimer();
                
            }
            
            
            
        </script>

        <style>
            html,body {
                margin:0;
                padding:0;
                height : 100%;
            }
            #surfNavi {
                width : 100%;
                height : 20%;
            }
            
            #surfFrame {
                width : 100%;
                height : 80%;
                border : 0px;
                position : absolute;
            }
        </style>
    </head>
    <body onload="start();">
        <div id="surfNavi">
            
            MyURL : <?php echo $url ?><br>
            ポイント : <?php echo $myPoint ?><br>
            
            あと<span id="timer"></span>秒
            
        </div>
        
        <iframe id="surfFrame"></iframe>
        
        
    </body>
</html>
surfCompleted.php
<?php

    // サーフページへ戻る
    header('Location: http://xxxxxxxxxxx/surf.php');
?>
functions.php
<?php

//=========================================================
// キーの存在を確認しつつオブジェクトから値を取得
//=========================================================
function GetValue ( $obj, $key ) {
    
    $value = "";
    
    if ( isset ( $obj[$key] ) ) {
        $value = $obj[$key];
    }
    
    return $value;
}


//=========================================================
// サーフ対象のページURLを取得
//=========================================================
function GetPageToSurf ( $selfUrl ) {
    
    $result = ""
    $userDataDir = "userdata";
    $selfUrlMd5 = md5($selfUrl);
    
    // userdataフォルダの中のファイルのリスト(=ユーザーレコードのリスト)を取得
    $files = array_diff ( scandir($userDataDir), array('.', '..', $selfUrlMd5));
    
    // レコード数を確認    
    $fileCount = count($files);
    
    // レコードが存在する場合
    if ( $fileCount > 0 ) {
        
        $randomKey = array_rand ( $files );
        
        $userFileName = $files[ $randomKey ];
        
        $info = ReadUserDataFile($userFileName);
        
        $result = GetValue ( $info, 'url');
    
    // レコードが存在しない場合
    } else {
        
        // デフォルトページでも表示することしましょうか。
        $result = "http://デフォルトページ"; // ファイルを適当に作ってURLを書いておいてください。

    }

    return $result;


//=========================================================
// ユーザーデータを取得
//=========================================================
function ReadUserDataFile ( $userFileName ) {
    
    $info = array();

    $point = 0;
    $url   = "";
    
    $userDataDir = "userdata/";

    // ファイルが存在する?
    if ( file_exists( $userDataDir . $userFileName  ) ) {
        
        $f = fopen ( $userDataDir . $userFileName, "r") or die("ファイルを開けませんでした...");
    
        $rowNumber = 0;

        while ( !feof($f) ) {

            $row = fgets ( $f );
        
            if ( $rowNumber > 0 ) {
            
                $row = trim($row);
            
                if ( is_numeric ( $row ) ) {
                    $point += $row;
                }
                
            } else {
            
                $url = trim($row);
            }
        
            ++$rowNumber;
        }
    
        fclose($f);
        
    // ファイルが存在しない
    } else {
        // 何もしない
    }
    
    // 結果を格納
    $info['url']   = $url;
    $info['point'] = $point;
    
    return $info;
}


//=========================================================
// 新規登録
//=========================================================
function RegisterIfNecessary ( $url ) {
    
    $urlMd5 = md5($url);
    $userDataDir = "userdata/";

    // ファイルが存在しないなら作る
    if ( !file_exists( $userDataDir . $urlMd5  ) ) {
        
        // ファイルを作る
        $f = fopen( $userDataDir . $urlMd5, "w");
        
        // パーミッションを適当に設定しておく
        chmod ( $userDataDir . $urlMd5 , 0666 );

        // URLを書き込む
        fwrite($f, $url . "\n");

        // 初期登録ポイントをつける場合
        fwrite($f, "10" . "\n");
        
        // 閉じる
        fclose($f);
    }
}

?>

次回予告

前回「ポイントを記録できるようにしてみる」と言いつつ、サーフしてもポイントが増えないままここまで来てしまいました。 しかしログインできて登録できてサーフまでできている。 こうなったら次こそいよいよポイントを動かすぜ!  と、言いたいところですが、とはもう言わせないぜ!

はい。というわけで次回はサーフしたときにポイントが増えるようにしていきます。 今回 surfCompleted.php というサーフ画面に戻るだけのファイルを作りましたよね。 その中にポイント追加の処理を書き加えていきますよ。お楽しみに!

サイトTOPへ戻る
目次へ戻る
前のページ
次のページ