発展編01

外部検索エンジンを使う

外部検索エンジンを使用して検索する

この発展編01からファイル間の連携が入ってきますので、落ち着いて実行していきましょう。

ここではキーワードを外部の検索エンジンを利用して、検索するスクリプト例を見ていきましょう。二つにファイルを分けて記述していきます。search.phpは検索する検索エンジンと検索キーワードを決定します。rdir.phpはsearch.phpからの入力情報を受け取り、検索画面の検索結果画面にリダイレクトします。

search.php

    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>外部検索エンジンを活用</title>
    </head>
    <body>

        <h1>
            検索エンジンを選択する
        </h1>

        <form method="post" action="rdir.php">

            <p>検索キーワード:</p>
            <input type="text" name="key" width="50" />

            <p>使用する検索エンジン:</p>
            <select name="sea">
                <option value="google">
                    google
                </option>
                <option value="yahoo">
                    Yahoo!
                </option>
            </select>

            <input type="submit" value="検索" />

        </form>

    </body>
    </html>
    

「<form method="post" action="rdir.php">」によってsearch.phpの全体のアクションをrdir.phpに渡しています。「<input type="text" name="key" width="50" />」の「name="key"」で検索するキーワードをrdir.phpに渡しています。「<select name="sea">」では「name="sea"」により、どの検索エンジンでリダイレクトするかの決定を渡せるようにしています。

rdir.php

    <?php

        $strkey = urlencode($_POST[key]);

        switch($_POST['sea']) {

            case "google":
            $url = "http://www.google.co.jp/search?q=";
            break;

            case "yahoo":
            $url = "http://search.yahoo.co.jp/search?p=";
            break;

        }

        header("Location: ".$url.$strkey);

    ?>
    

「$strkey = urlencode($_POST[key]);」ではポスト送信された検索キーワードの文字列「key」を「urlencode」により、URLエンコードをしさらに変数「$strkey」に代入しています。「switch($_POST['sea']) 」により、どの検索エンジンでキーワードが検索されたかをswitch文で判定します。「header("Location: ".$url.$strkey);」では 「.」の文字列結合によって取得した検索エンジンのURL($URL)に検索したキーワード($strkey)を結合し検索結果のページにリダイレクトをしています。

実行結果

検索エンジンを選択する

googleを選択し、検索ボタンを押します。

googleを選択

ここでは検索結果の画面は省きますが、通常の検索エンジンで検索したと同じ、検索画面が表示されるはずです。

更新情報を知らせる

新着情報を告知する

ここでは、よくウェブサイトに見られる新着項目にnewという新着マークを表示させる方法を実践してみます。

new_info.php

    <html>
    <head>
    <title>新着情報の告知</title>
    </head>
    <body>
    <h1>
        新着情報の告知
    </h1>

    <ul>
    <?php

        clearstatcache();

        $objectdir = dir("./doc");

        while($strpath = $objectdir->read()) {

            if($strpath!= "." && $strpath!= "..") {

                $key = "rec".str_replace(".","_",$strpath);

                echo("<li><a href='cookie.php?doc=".$strpath."'>".$strpath."</a>");

                if((!isset($_COOKIE[$key]) || $COOKIE[$key] != filemtime("./doc/".$strpath))

                    &&filemtime("./doc/".$strpath)>=strtotime("-3 days")) {

                        echo (" <img src='new.gif' width='33' height='13' alt='new' />");

                    }

                echo ("</li>");

            }

        }

        $objectdir->close();

    ?>
    </ul>
    </body>
    </html>
    

更新日時などの情報を常に最新の状態にする必要がありますので、clearstatcache()関数でファイルステータスのキャッシュをクリアします。「$objectdir = dir("./doc");」はdir関数でファイルがあるディレクトリを表し、変数「$objectdir」に代入しています。「while($strpath = $objectdir->read())」はread()で$objectdirに入っているファイルを読み込み、それを変数「$strpath」に代入してwhile文で繰り返し処理をしています。

read()によって読み込まれるファイルには一階層上を示す「..」と現在階層「.」が含まれますので、今回実際にファイルではないので「if($strpath!= "." && $strpath!= "..")」により除外します。

「$key = "rec".str_replace(".","_",$strpath);」は「"rec".str_replace(".","_",$strpath);」によりクッキーのキーを「rec」を先頭につけ、ファイル名の「.」を「_」に置き換えます。理由としては、クッキーのキーは先頭に来る文字が「1234」などの文字である場合や「.」が含まれることは許されません。例として、「1234.php」というファイルのクッキーのキーは「rec1234_php」という具合になります。

「echo("<li><a href='cookie.php?doc=".$strpath."'>".$strpath."</a>");」は各ファイルにアクセスする際、cookie.phpの処理を通し、そこからリダイレクトさせています。cookie.phpはクッキーに更新したファイルの更新年月を記録するスクリプトを記述しています。

赤い下線を引いた部分のスクリプトでは、現在のクッキー、キー$keyが存在しない場合(isset関数で判定)もしくはクッキーに記録したファイルの最終更新日時と対応した実際に 更新したファイルの最終更新日時を比較し異なり、かつ最終の更新日時が3日以内(strtotime("-3 days")で判定)のものに対して、newの画像を表示させています。

「$objectdir->close();」はディレクトリに対して読み込みが終了した後、close()でオブジェクトを閉じています。

cookie.php

    <?php

        clearstatcache();

        $key = "rec".str_replace(".","_",$_GET['doc']);

        if(!isset($_COOKIE[$key]) || $_COOKIE[$key] != filemtime("./doc/".$_GET['doc'])) {

            setcookie($key,filemtime ("./doc/".$_GET['doc']),time()+60*60*24*90);
        }

        header("Location: "."./doc/".$_GET['doc']);

    ?>
    

「clearstatcache();」はファイルステータスのキャッシュをクリアします。

「$key = "rec".str_replace(".","_",$_GET['doc']);」はnew_info.phpと同様のロジックです。

赤い下線の部分のスクリプトは現在のクッキーにキー$keyがない、またはクッキーに記録されたファイルの最終更新日と対応する実際のファイルの現在の最終更新日とを比較し違っていた場合、新しくクッキーを生成し、または既存クッキーを上書きします。setcookie()関数で第一引数にファイル名、第二引数に最終更新日、第3引数にクッキーの有効期限を決定しています。

「header("Location: "."./doc/".$_GET['doc']);」はクッキーの保存処理を終了した後、対応したファイルにリダイレクトをします。

実行結果1

新着マークあり

上記の実行結果はnew_info.phpの「strtotime("-3 days"」とした結果です。更新または新たにファイルを作成したのが、3日以内ですので、new画像が表示されています。ファイルはdocディレクトリ内に保存しています。new画像はnew_info.php、cookie.phpと同階層に保存しています。

実行結果2

新着マークなし

上記の実行結果はnew_info.phpの「strtotime("now"」とした結果です。更新または新たにファイルを作成したのが現在時刻ですので、new画像が表示されていません。

アクセスログ

アクセスログを記録する

ここではファイルにログを記録するスクリプトを見ていきましょう。

log-generation.php

    <?php

        $delimits = date('Y:m:d:h:i:s')."\t";
        $delimits.= $_SERVER['SCRIPT_NAME']."\t";
        $delimits.= $_SERVER['HTTP_REFERER']."\t";
        $delimits.= $_SERVER['SCRIPT_ACCEPT_LANGUAGE']."\t";
        $delimits.= $_SERVER['HTTP_USER_AGENT'];

        $file = fopen("./logdata/".date("Ymd").".log","a");

        flock($file,LOCK_EX);
        fputs($file,$delimits."\n");
        flock($file,LOCK_UN);

        fclose($file);

    ?>
    

「$delimits = date('Y:m:d:h:i:s')."\t";」の「date('Y:m:d:h:i:s')」はアクセス年月日、「$delimits.= $_SERVER['SCRIPT_NAME']."\t";」の「$_SERVER['SCRIPT_NAME']」は呼び出されるスクリプト名(スクリプトまでのパス)、「$delimits.= $_SERVER['HTTP_REFERER']."\t";」の「$_SERVER['HTTP_REFERER']は「リンク元のURL」、「$delimits.= $_SERVER['SCRIPT_ACCEPT_LANGUAGE']."\t";」の「$_SERVER['SCRIPT_ACCEPT_LANGUAGE']」は「クライアントの言語」、「$delimits.= $_SERVER['HTTP_USER_AGENT'];」の「$_SERVER['HTTP_USER_AGENT'];」は「ブラウザの種類」を取得します。

「 $file = fopen("./logdata/".date("Ymd").".log","a");」の「fopen("./logdata/".date("Ymd").".log","a");」でlogdataフォルダに.logという拡張子で「"a"」により追記可能な状態にしています。

「flock($file,LOCK_EX);」は排他処理でファイルをロックしています。これは、ファイルが書き込まれている場合は複数のリクエストがあった場合のファイルの破損を防ぐために記述しています。「fputs($file,$delimits."\n");」では指定された文字列を書き込んでいます。「flock($file,LOCK_UN);」は書き込みの処理が終了した後、ファイルのロックを解除するために記述しています。「fclose($file);」は一連の書き込みの処理が終了した後に、ファイルを閉じています。

loging.php

    <?php require_once("log-generation.php"); ?>

    <html>
    <head>
    <title>アクセスログ</title>
    </head>
    <body>
    <h1>
        アクセスログ
    </h1>
    <p>アクセスログを記録しました。</p>
    </body>
    </html>
    

「<?php require_once("log-generation.php"); ?>」で「log-generation.php」を呼び出して、ログの記録を行っています。

実行結果

2008:02:21:04:58:14 /php-programing/2-03/log-generation.php Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)

実行結果からそれぞれ取得されていることがわかります。「2008:02:21:04:58:14」は「アクセス年月日」、「/php-programing/2-03/log-generation.php」は呼び出されるスクリプト名(スクリプトまでのパス)、「リンク元のURL」はリンクされる元のURLがこの場合存在していないので、取得はされません。「ja」は「クライアントの言語」、「Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)」は「ブラウザの種類」を表しています。

アクセスログを表示する

ここでは、ファイルに書き込んだログを表示するスクリプトを見ていきます。

display-log

    <?php

        if($_GET['dat'] == "") {

            $file = fopen("./logdata/".date("Ymd").".log","r");

            } else {

                $file = @fopen("./logdata/".$_GET['dat'].".log","r")

                or $file = fopen("./logdata/".date("Ymd").".log","r");

            }
    ?>

    <html>
    <head>
    <title>アクセスログ表示</title>
    </head>
    <body>
    <h1>
        アクセスログ表示
    </h1>
    <table border="1" cellspacing="0" cellpadding="0" style="width:500px;">
        <tr>
            <th>アクセス年月日</th>
            <th>URL</th>
            <th>リンク元URL</th>
            <th>言語</th>
            <th>使用ブラウザ</th>
        </tr>
        <?php while($arraydata = fgetcsv($file,300,"\t")) { ?>
        <tr>
            <?php foreach($arraydata as $data) { ?>
            <td><?php echo($data); ?></td>
            <?php }?>
        </tr>
        <?php } ?>
    </table>
    </body>
    </html>
    

赤い下線の部分のスクリプトでは、クエリ情報datが指定されていない場合は、今日のログファイルを表示し、指定がされている場合は指定されたログファイルを読み取り専用として開きます。

アクセスの表示はテーブルで内行います。「<?php while($arraydata = fgetcsv($file,300,"\t")) { ?>」はfgetcsv関数により、ファイルから次の1行を読み込み、指定したタブ文字("\t")により分割されています。「300」はその行内で含まれる最大の文字の長さを表しています。そして、最後の行に到達するまで、while文で、ファイル内の行を繰り返し処理しています。

「<?php foreach($arraydata as $data) { ?>」は配列$arraydataから順番に入っている要素を取得し、繰り返しの処理を行っています。取得された要素の値は「$data」に格納されます。ここでは$arraydataに入っている「2008:02:21:06:10:59」や、「/php-programing/2-03/log-generation.php」がテーブルのセルにそれぞれにわり割り当てられ、「<?php echo($data); ?>」で表示されています。

実行結果

アクセスログ表示

ファイルに書き込まれている情報が表示されていることがわかります。

バナー操作

バナーをランダムに表示させる

ここではバナーをランダム表示させるスクリプトを見ていきましょう。今回はファイルを3つに分けます。

  • random.phpはfollow.phpのスクリプトからバナーをランダムに表示出力をさせるスクリプト。
  • random.iniはバナーに関する幅、高さ、リンク先url、バナーが存在する場所、alt属性などの情報を記述したファイル。
  • follow.phpはrandom.iniに記述されている情報を受けて、表示するバナーを決めるスクリプト。

上記3つの構成になっています。

.iniという拡張子のファイルが出てきましたが、これはOSやアプリケーションソフトの設定を記録したファイルの拡張子に使用されます。ここではimageの設定ファイルとして作成し使用します。

random.php

    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <title>バナーをランダムに表示</title>
    </head>
    <body>
    <?php require_once("follow.php") ?>
    </body>
    </html>
    

「<?php require_once("follow.php") ?>」により、follow.phpをインクルードして、バナーを表示します。

random.ini

    [info]
    count=4
    width=221
    height=46

    [data]
    url1=http://px.xframework.net/
    image1=banner01.jpg
    alt1=セミナー情報
    weight1=50

    url2=http://px.xframework.net/
    image2=banner02.jpg
    alt2=セミナー情報-禁止
    weight2=20

    url3=http://px.xframework.net/
    image3=banner03.jpg
    alt3=開発事例
    weight3=15

    url4=http://px.xframework.net/
    image4=banner04.jpg
    alt4=開発事例-禁止
    weight4=15
    

見方としては[info]や[data]がセクション名、「count=4」では「count」が「キー名」、「4」が値という具合になります。

「[info]」以下には3つの設定項目が記述されています。「count=4」はバナーの数、「width=221」はバナーの幅、「height=46」はバナーの高さです。

[data]以下には4つの設定項目があります。「url」はバナーをクリックした飛び先のurl、「image」はバナーの画像が存在する場所のurl(ここではスクリプトと同じディレクトリ内にあるので、バナー名だけを入力しています。)、「alt」は代替テキスト、「weight」はバナーが表示される確率です。

follow.php

    <?php

        mt_srand((double)microtime()*100000);

        $random = mt_rand(1,100);

        $count = 0;

        $arrayini = parse_ini_file("random.ini",TRUE);

        for($i =1; $i<=$arrayini['info']['count']; $i++) {

            if($random > $count && $random <= $count+$arrayini['data']['weight'.$i]) {

                echo("<a href='".$arrayini['data']['url'.$i]."'>
                    <img border='0'
                        src='".$arrayini['data']['image'.$i]."'
                        width='".$arrayini['info']['width']."'
                        height='".$arrayini['info']['height']."'
                        alt='".$arrayini['data']['alt'.$i]."' />
                    </a>");
            }

            $count+=$arrayini['data']['weight'.$i];

        }
    ?>
    

「mt_srand((double)microtime()*100000);」ではまず、mt_srand関数で乱数生成器を初期化します。次にmicrotime関数により毎回、異なる値を生成しています。microtime関数は現在のUnixタイムスタンプをマイクロ秒まで返します。

「$random = mt_rand(1,100);」のmt_rand関数は改良型乱数値を生成します。ここでは第一引数に1、第二引数に100を入力することにより1~100までの乱数を生成しています。その生成した乱数を変数「$random」に代入しています。

「$count = 0;」は、random.iniに記述された表示確率の値を累積するための変数です。初期の値は0としています。

「$arrayini = parse_ini_file("random.ini",TRUE);」のparse_ini_file関数はiniファイルをロードし、連想配列としてその設定値を返します。ここでは、第一引数に読み込む設定ファイルを記述し、第二引数にはrandom.iniファイルにある「[info]」や「[data]」のセクションを認識するかどうかの判定を決定します。「TRUE」では$配列名($arrayini)セクション名と設定(キー名)が含まれた多次元の配列を取得することができます。「FALSE」では$arrayini[キー名]が取得されます。

「for($i =1; $i<=$arrayini['info']['count']; $i++) {」~「$count+=$arrayini['data']['weight'.$i]; }」ではバナーがある数(ここでは4つ)だけループ処理を繰り返しています。

「if($random > $count && $random <= $count+$arrayini['data']['weight'.$i]) {」から終了の「}」は「$random = mt_rand(1,100);」で生成された乱数 が「$count~$count+」の間にある場合に、該当するweightのバナーを出力する<img />タグを生成します。このとき<img />タグにある幅や高さなどの情報も付随してきます。

「$count+=$arrayini['data']['weight'.$i];」では変数$i番目に表示される確率を変数「$count+」に加算します。

実行結果

ランダムバナー03 ランダムバナー01 ランダムバナー04 ランダムバナー02

実行結果の画像だけではわかりづらいかもしれませんが、ブラウザの更新を実行する度に上記4つのいずれかのバナー画像がブラウザにランダムで表示されます。