パタヘネ本を読む (コンピュータの構成と設計)

プログラムを作るだけではなく、CPUレベルでの動作原理を知りたくなり参考書を探してました。
ネットで調べてみた感じでは、パタヘネ本というのが入門向けに良いらしいです。

というわけで、これからパタヘネ本を読み進めていく事にします。
ただ読んでるだけだと、途中で挫けそうなので、本blog上で学んだ事をアウトプットしていく事にします。


目的

    プログラムのソフトウェアだけではなく、下のレイヤの知識を深める。
 
    最近のコンパイラでは意識する必要はなくなりつつあるけど,ハードから見た
    効率よいプログラム作りを意識できるようにする。
 
    純粋に知的好奇心の満足として。





ルール

    忙しくても、毎日10ページ以上読み進める。
    図書館で借りた本なので、上巻を2週間以内で読みきる。
    (別に買っても良いんですが、何時でも借りれるモノを買うのも場所がもったいないので...)
 
    学んだ事をblogにメモとして残す。
        自分用のメモ+他に同じ本を読む人のためのヒント(?)として
 
    分からなかった事、本に載ってない事で、自分で調べた事も一緒にメモする。
 
    練習問題は解くけど、回答はblog上に書かない
        後学者の人が見たときに、ネタばれ防止として。





学んだ事を生かして…

    PC上でCPUエミュレータを作れるようになる。
    PICとかだと簡単そうなイメージ(なんとなく)が有るので、一旦ここをターゲットにする。
    PICが、かなり難しそうならCASLエミュレーターでも可
    (実用にしたいわけではないので)
 
    本当はnesのエミュレータとか作れると面白そうだけど、
    サウンド・グラフィック周りなど気に掛ける事が多そうなので将来のお楽しみに取っておく。




目次

第1章 コンピュータの抽象化とテクノロジ
1.1 はじめに
1.2 プログラムの裏側
1.3 コンピュータの内部
1.4 性能
1.5 電力の壁
1.6 方向転換:単体プロセッサからマルチプロセッサへ
1.7 実例:AMD Opteron X4の製造技術とベンチマーク・テスト
1.8 誤信と落とし穴
1.9 おわりに
1.10 歴史展望と参考文献(◎CDコンテンツ)
1.11 演習問題
 
第2章 命令:コンピュータの言葉
2.1 はじめに
2.2 コンピュータ・ハードウエアの演算
2.3 コンピュータ・ハードウエアのオペランド
2.4 符号付き数と符号なし数
2.5 コンピュータ内での命令の表現
2.6 論理演算
2.7 条件判定用の命令
2.8 コンピュータ・ハードウエア内での手続きのサポート
2.9 人との情報交換
2.10 32ビットの即値およびアドレスに対するMIPSのアドレシング方式
2.11 並列処理と命令:同期
2.12 プログラムの翻訳と起動
2.13 Cプログラムの包括的な例題解説
2.14 配列とポインタの対比
2.15 高度な話題:CのコンパイルおよびインタープリタによるJavaの実行(◎CDコンテンツ)
2.16 実例:ARMの命令
2.17 実例:x86の命令
2.18 誤信と落とし穴
2.19 おわりに
2.20 歴史展望と参考文献(◎CDコンテンツ)
2.21 演習問題
 
第3章 コンピュータにおける算術演算
3.1 はじめに
3.2 加算と減算
3.3 乗算
3.4 除算
3.5 浮動小数点演算
3.6 並列処理とコンピュータの算術演算:結合則
3.7 実例:x86における浮動小数点演算
3.8 誤信と落とし穴
3.9 おわりに
3.10 歴史展望と参考文献(◎CDコンテンツ)
3.11 演習問題
 
第4章 プロセッサ
4.1 はじめに
4.2 論理設計とクロック方式
4.3 データパスの構築
4.4 単純な実現方式
4.5 パイプライン処理の概要
4.6 データパスのパイプライン化と制御
4.7 データ・ハザード:フォワーディングとストール
4.8 制御ハザード
4.9 例外
4.10 並列処理と高度な命令レベル並列性
4.11 実例:AMD Opteron X4 (Barcelona)のパイプライン
4.12 高度な話題:パイプラインの記述およびモデリング用のハードウエア設計言語を使用したディジタル設計の概要とパイプライン処理の追加図解(◎CDコンテンツ)
4.13 誤信と落とし穴
4.14 おわりに
4.15 歴史展望と参考文献(◎CDコンテンツ)
4.16 演習問題


下のほうにある”タグ: パタヘネ”をクリックすると、読書メモ一覧が表示されます。 ↓


4822284786
コンピュータの構成と設計 第4版(上) ハードウエアとソフトウエアのインタフェース (Computer Organization and Design: The Hardware/Software Interface, Fourth Edition)

.htaccessでRewriteRule使用時,アドレスバーのURL表示を変更させない

RewriteRuleの定義を.htaccessに行った際、設定によって、ブラウザのURL欄が書き換わったり、換わらなかったりしたので、その辺の仕様を改めて調べた結果のメモです。


URL書き換えの基本


.htaccessでRewriteRuleを使用すると、指定されたURLを書き換える事が出来る。


例えば、下記のルールは、任意のURL指定に対しても、Yahooのホームページが表示されるようになる。
この書き換えルールは、.htaccessが存在するディレクトリ以下のURLに対して適用される。

RewriteRule ^.*$ http://www.yahoo.co.jp/


この際のアドレスバー表示は、http://www.yahoo.co.jp/になる。



これが以下のルールの場合、アドレスバーの表示は変更されない

RewriteRule ^.*$ lib/contoller.php


結果として、ブラウザ側からするとURLのリライトが行われた事を検出できない。
これをforward(もしくはinternal redirect)と呼ぶ。



しかし、Rewrite後のURLをドメイン名付きで定義した場合は、redirect(もしくはexternal redirect)となる。

RewriteRule ^.*$ http://my.domain.com/lib/contoller.php


アドレスバー表示も、書き換え後のURLになる。
このときクライアント側のブラウザはリダイレクトが行われた事を検出できる。

実際には一旦Status=302:Foundでレスポンスが返され、Locationヘッダにhttp://my.domain.com/lib/contoller.phpが指定される(firebugで確認)。その後ブラウザは、302レスポンスコード受信時の仕様に従い、改めてhttp://my.domain.com/lib/contoller.phpへリクエストを投げる事になる。

この振る舞いは、たとえRewriteRuleに記載されているmy.domain.comが、最初のリクエストがあったサーバと同じであっても行われる(apacheからすると、my.domain.comが自分である事を確認できないため??)。




また、URLにドメインを明記しなくても、external redirectを明示する事は可能になっている。
下記の例のように、変更後URLの後ろにR=301と表記する事で、明示的に301リダイレクトを行わせる事が出来る。もちろんR=302とすれば、ステータスコード=302のときの振る舞いになるし、R=404でNotFoundにさせることも可能。

RewriteRule ^.*$ http://my.domain.com/lib/contoller.php [R=301]






その他のオプション

RewriteRule書き換え後のURLが、再度ルールにマッチするとき、無限ループに陥ってしまう。
これを防ぐにはルールの末尾に[L]オプションを定義する。


4873113814
Apacheクックブック 第2版 ―Webサーバ管理者のためのレシピ集


4774150363
サーバ構築の実際がわかる Apache[実践]運用/管理 (Software Design plus)

[PHP]twitter APIを使用して、検索した結果を出力する

twitterに書き込まれたツイートを、PHPで検索して出力させるプログラムです。

    $keyword = urlencode( 'キーワード' );
 
    //--------------------------------
    // twitter APIを使用して検索を行う
    //--------------------------------
    $result = file_get_contents( 'http://search.twitter.com/search.atom?q='. $keyword );
    $xml = new SimpleXMLElement( $result );
 
    if ( $xml != NULL && $xml->entry != NULL ) {
        $str = "";
 
        //----------------------------------
        // 全検索結果を処理するまで繰り返し
        //----------------------------------
        foreach($xml -> entry as $item) {
 
            //----------------------------------
            // 印字データを取得
            //----------------------------------
            $published = $item->published;
            $title     = $item->title;
            $userUrl   = $item->author->uri;
            $userName  = $item->author->name;
 
            //----------------------------------
            // 取得データをhtmlに変換
            //----------------------------------
            $str .= $title . '<br />';
            $str .= '<span style="color:#ccc;font-size:8pt"> by <a href="' . $userUrl . '">' . $userName . '</a> ';
            $str .= '<br />at ' . $published . '</span>';
            $str .= '<hr />';
        }
    }   
 
    //----------------------------------
    // 取得結果を表示する
    //----------------------------------
    echo $str;



http://search.twitter.com/search.atomのURLより検索を行います。

検索結果は、atom形式のxmlで返されるので、SimpleXMLを使用してデータの取得をを行い、htmlに変換して上で出力を行っています。

[PHP]年月日の文字が入った日付文字列を,YYYYMMDDに変換する(2012年1月31日 -> 20120131)

PHPで、例えば「2012年1月31日」といった、書式編集されている日付文字列を、
「20120131」のようなYYYYMMDD形式に変換します。。

function normalizeDate( $inStr ) {
    // 年月日の各パーツを分割する
    preg_match( "/([0-9]*)年([0-9]*)月([0-9]*)日/", $inStr, $data );
    if ( Count( $data ) != 4 ) {
        return $inStr;
    }
 
    // 先頭0埋めでYYYYMMDD形式の日付文字列に変換する
    $outStr = sprintf( "%04.4d%02.2d%02.2d", $data[1], $data[2], $data[3] );
 
    return $outStr;
}



preg_matchでは、正規表現を使用して、入力された文字列を年・月・日の各パーツに分離します。
その後c言語でも良く使われるsprintf()で再組み立てします。
入力文字の月日が1桁だった場合も0埋めする為に、”%02.2d”の形式で書式指定を行っています。

xpathで複数のclassが指定されたタグを取得する

xmlのデータから特定のタグ(ノード)を取得するにはxpathを指定すると便利です。
例えば、以下のxpath式では、xml内にあるliタグを検索する事が出来ます。

//li



さらに、xpath式では特定の属性値を持つデータのみを絞り込む事も可能です。
例えば以下のようなxhtmlがあった場合に…

<ul>
    <li class="row-data"> ... </li>
    <li class="row-data"> ... </li>
    <li class="row-data"> ... </li>
    <li class="row-data"> ... </li>
    <li class="row-data"> ... </li>
</ul>
<ul>
    <li class="menu-data"> ... </li>
    <li class="menu-data"> ... </li>
    <li class="menu-data"> ... </li>
</ul>



classがrow-dataであるliタグのみを抽出したい場合は、以下のxpath式を使用します。

//li[@class="feedbackRow"]




xhtmlでは、タグに対してclassを複数指定することが出来るのですが、以下のようなデータから検索を行いたい場合どのようにすればよいでしょうか?

<ul>
    <li class="row-data row-even"> ... </li>
    <li class="row-data row-odd" > ... </li>
    <li class="row-data row-even"> ... </li>
    <li class="row-data row-odd" > ... </li>
    <li class="row-data row-even"> ... </li>
</ul>





案1:2回のクエリに分ける


簡単な方法として思いつくのは、以下のようにxpath式を2つ用意し、プログラム側でマージするという方法があります。

//li[@class="feedbackRow row-even"]
//li[@class="feedbackRow row-odd"]



ただ、classに”row-even row-data”と指定された場合は、対応できません。
この方法は簡単ですが、classが複数指定可能で、種類数が多い状況では現実的では有りません。


案2:contains関数を使用する


xpathでは、”=”を使用した比較式のほかにも、関数を使用することが可能です。
今回は、classに”row-data”という文字を含むタグのみを取得したいので、下記のxpath式で期待したタグを抽出する事ができます。

//li[contains(@class,'feedbackRow')]



xpath関数には、contains以外にも多数用意されており、文字列処理系では他に、concat, normalize-space, string, string-length, substring-after, substring-before, translate等が有ります。
XSLT XPath実践マスター



4798113727
標準講座 XQuery (Programmer’s SELECTION)

WordPressにzenbackを導入する時にすべき2つの事

blogで自分が書いた記事に関連するページを自動でお勧めしてくれるzenbackですが、時々変なページを推薦してくる事があります。例えば、本サイトのblogタイトルはnanoblogなのですが、記事のない用に関係なくカワダから販売しているnanoblockの関連ページにリンクされる事が、結構ありました。

WordPressを使ってblogを運営している際に、zenbackを導入したい場合は、下記の2点をしておくと関連記事の表示が期待したように動作してくれます。


html内のどこが本文/タイトルなのかをマークする

zenbackのクローラーに対して、html内のどこに記事本体があるかを教えてあげます。

1.本文部分(the_title)を<!– zenback_body_begin –>と<!– zenback_body_end –>で囲みます

<!-- zenback_title_begin -->
<?php the_title(); ?>
<!-- zenback_title_end -->




記事タイトル部分(the_content)を<!– zenback_title_begin –>と<!– zenback_title_end –>で囲みます。ここでいうタイトルは、blogタイトルではなく、記事のタイトルです。

<!-- zenback_body_begin -->
<?php the_content(...); ?>
<!-- zenback_body_end -->




記事公開日時を含んだコメントタグ<!– zenback_date YYYY-MM-DD –>を入れます。場所はどこでも良いので、タイトルの下にでも入れておきます。

<!-- zenback_date <?php echo get_post_time('Y-m-d') ?> -->






プレビュー時、トップページをの表示時はzenbackを表示させない


プレビュー時もウィジットを表示させると、zenbackからの本文解析アクセスが来て邪魔くさいので非表示にします。また、トップページなど個別記事以外では、zenbackは正しく動作しないので個別記事のときのみウィジットを表示させるようにします。

<php if ( !is_preview() && ( is_single() || is_page() ) ) { ?>
zenbackのスクリプト
<?php endif ?>




これによって、関連記事や関連リンクの一覧に精度の高い情報が表示されるようになります。


B00436G1M8
nanoblock スペースセンター

B004OC44GQ
nanoblock 姫路城 NBH-018

[Research Artisan]ドメイン別のアクセス数ページのレイアウトを調整

ReserchHelper::timePageTag()と、reserch.cssに手を入れて以下の変更をおこないました。

    行の高さを調整
    ドメイン名設定のリンクを同じ行に
    ドメイン名設定の文字を薄くする


高さ25px,marginが5pxだったのをそれぞれ20px, 2pxに変更です。

変更後のデザインはこんな感じ。
行が細くなり、多数のデータを一度に表示出来る様になりました。





cssを変更した事に夜うれしい副作用として、他の明細系もすっきりしました。


変更前はこんな感じだったのでかなり便利です。



4905042097
「週4時間」だけ働く。

[Research Artisan]アクセスログをRSS配信するプラグイン

フリーのPHP製アクセスログ解析ソフトとして有名なReserch Artisan Liteですが、取得したアクセスログをRSSのフィードで配信するプログラムを作成したので公開します。

ダウンロード

以下のファイルをダウンロードしてください。
Download: rss.zip


インストール手順

以下の手順でインストールを行います。
コピーする対象のファイルは1つだけです。

1.上記ファイルをダウンロードします。
 
2.public_htmlに置いた ra/analyze/index.phpと同じフォルダに、rss.phpをコピーします。
  (フォルダ名を変更している場合は、各自読み替えてください。)
 
3.htt://xxx/ra/analyze/rss.phpにアクセスし、rssが出力される事を確認します。





出力例

配信されたrssをfirefoxで見た際のスクリーンショットです。
以下のように、ユニークユーザ・アクセス数に加えて、AdSenseクリック数やリンクのクリック数も表示されます。



出力内容の変更

出力フォーマットを変えたい場合はgetRssText()を改造してください。
また、出力するデータ自体を追加したい場合は、getAccessLog()を変更します。getAccessLog()ではReserch Artisan Liteが標準で提供しているLogクラスを使用してデータを取得しています。


ソースについて…

Reserch Artisanのアーキテクチャからすると、本拡張はviewを作ってcontrollerに手を入れて…という変更が正しい流れです。ですが、今回は変更に伴う作業を最小化したかったので、あえてrss.phpのファイル内に全てのロジックを詰め込んでいます。(本体がバージョンアップしたときの作業を減らしたかったので…)

ですので、Reserch Artisanに対して何か他の機能を追加しようと検討している方は、本ソースは参考にしない方が良いです(せめて、application/contollerのソースがアクションごとに別ファイルに分かれていれば、アーキテクチャに則った形で拡張しても良かったのですが…)。

使用時の注意点

データはrss配信なので、当然ながら認証処理が有りません。
外部から情報を見られたくない場合は、出力結果を暗号化しリーダー側で復号するとか工夫してください。
main()関数の$rssTextを変更すればOKです。

暗号化が面倒なら、出力時に生の値をn倍する等も有りかも…

ライセンス

Reserch Artisan Liteと同じでGPLです。

[PHP] DateTimeオブジェクトとRFC822形式文字列を相互変換

PHPで用意されているDateTimeオブジェクトと,RFC822規格で定められた文字列を相互に変換する処理です。RFC822形式の日付書式は、rss2.0のpubDateタグなどで使用されています。


サンプル

// DateTime -> RFC822
$sysdate = new DateTime();
echo $sysdate->format( DateTime::RFC822 );
 
 
// RFC822文字列 -> DateTime
$dateStr_rfc822 = "Wed, 30 May 2012 15:59:36 +0900";
$datetime = date('Y-m-d H:i:s', strtotime($dateStr_rfc822 ));



RFC822文字列からの出コードは、strtotime()に渡してあげれば適当にパースしてくれます。


ちなみにRFC822規格上では、以下の仕様になっています。

曜日と秒は省略しても良いです。
 
時分秒が1桁の場合は、先頭0埋めします。
 
RFC822的には年の部分は2桁でも4桁でも良いのですが、
本フォーマットを採用しているRSS2.0の仕様では"4桁にすべき"等、別途縛りがある場合も存在します。

[PHP]php5.3でDateTimeクラスに追加されたメソッドと同等の事を5.2で行う

PHP5.2に対して、PHP5.3ではDateTimeクラスに対してメソッドが追加されているため、5.3向けに書かれたコードを5.2の環境で動作させようとすると問題が発生する事があります。
このような場合の対処法を幾つか確認したのでメモしておきます。

    //-------------------------------
    // 現在の時刻を取得
    //-------------------------------
    $sysdate = new DateTime();
 
 
    //-------------------------------
    // 現在時刻を文字列で取得
    //-------------------------------
    echo $sysdate->format("Y/m/d H:i:s");   
 
 
    //-------------------------------
    // unixtimeを取得
    //-------------------------------
    echo $sysdate->getTimestamp();
 
//  echo $sysdate->format("U");         // 5.2まではこちら
 
 
    //-------------------------------
    // 翌日を取得(P1D = plus 1 day)
    //-------------------------------
    $tommorow = $sysdate->add( "P1D" ); 
 
//  $tommorow = clone $sysdate;         // 5.2まではこちら(2行)
//  $tommorow->modify('+1 day');
 
 
 
    //------------------------------------------
    // 2つのDateTimeオブジェクトの差分を求める
    //------------------------------------------
    $interval = $sysdate->diff($tommorow);   // 5.2までの対応は後述
    echo $interval->format( "%R%a日差です" );
 
 
    //------------------------------------------
    // 年・月・日をばらばらで取得(これは問題なし)
    //------------------------------------------
    $year  = $sysdate->format("Y"); 
    $month = $sysdate->format("m"); 
    $day   = $sysdate->format("d"); 
    echo $year;
    echo $month;
    echo $day;






diff()メソッドを5.2で使用したい場合は、該当のメソッドが用意されていないだけでなく、diff()の戻り値であるDateIntervalクラス自体がないのでちょっと面倒です。

これに関しては、http://www.php.net/manual/en/datetime.diff.php#97810にてDennis Cが代替関数を提案しているので、こちらを参考にすると便利です。

function date_diff($date1, $date2) {
    $current = $date1;
    $datetime2 = date_create($date2);
    $count = 0;
    while(date_create($current) < $datetime2){
        $current = gmdate("Y-m-d", strtotime("+1 day", strtotime($current)));
        $count++;
    }
    return $count;
}
 
echo (date_diff('2010-3-9', '2011-4-10')." days <br \>");

[Research Artisan]のソースコード解析メモ2

ResearchArtisanLiteの解析メモその2
その1はこちら:Research Artisan Liteのソースコード解析メモ

エントリポイントであるindex.phpから、データの取得周りまでの処理の流れを調べたときのメモです。
プログラムのソースを改変する人向けなので、1ユーザとして使用する際には全く必要ない情報です。




ヘルパーのロードは,RaView->showView()内からコールされる_loadHelper()で行われる.
このメソッドへ到達するための流れは以下の通り。

index.php
    Ra->execute()
        Ra->_showView()
            RaView->showView()  
                RaView->_loadHelper()
                    RaView->_checkHelper()
                        $helperFile = RA_CORE_DIR. RA_HELPER_DIR. ucfirst($controller). 'Helper.php';
                        require $helperFile;
 
                    return new $helperName($request, $session, $message, $result, $controller, $action);



Helperクラスをnewするには、コンストラクタで以下のパラメータが必要

public function __construct(
                            RaRequest $request,
                            RaSession $session, 
                            RaMessage $message,
                            RaResult $result=null
                            $controller,
                            $action );



コンストラクタ引数は、ResearchHelperクラスを見るとresultについては省略可能となっている

class ResearchHelper extends BaseHelper {
      public function __construct(RaRequest $request, RaSession $session, RaMessage $message, RaResult $result=null, $controller, $action) {
        parent::__construct($request, $session, $message, $result, $controller, $action);
      }




コンストラクタ引数はそれぞれ、下記のメソッドで初期化されている。

Ra->__construct()
    $_request    = new RaRequest();
    $_session    = new RaSession();
    $_message    = new RaMessage();
    $_controller = $this->_request->get('controller');
    $_action     = $this->_request->get('action');
 
Ra->execute()
    $result = new RaResult();





ページ(view)に表示するデータは、ResearchHelper->uniqueCount()等で取得しているが、これはコンストラクタで渡されたresultの情報を返しているだけ

public function uniqueCount() {
    print $this->getFormatNumber($this->result->get('uniqueCount'));
}



resultへの値をセットは、ReserchController->_doResearch()で行われている。
具体的にはfindSummary()メソッドの戻り値。

_doResearch() {
    $log = new Log();
    ...
    $results = $log->findSummary($findOptions, $method, $yyyyMmOptions, $compareValue);
    ...
 
    $result = $this->result;
    foreach($results as $k => $v) {
      $result->set($k, $v);
    }
    ...
}




Log->findSummary()では、findQuery()でDBからの結果セットを取得している。

$rs = $this->findQuery($options);
while ($row = $this->fetchRow($rs)) {
  $this->clearData();
  $data = $this->getData();
 
  foreach($data as $column => $value) {
    if (isset($row[$column])) $this->setValue($column, $row[$column]);
  }
 
  $this->setValue('yyyy', $term['yyyy']);
  $this->setValue('mm', $term['mm']);
  $function = '_'. $method;
  if (method_exists($this, $function)) {
    $this->$function();
  }
}




fetchRow()は継承元のRaModel.phpで定義され、MySQLのAPIをコールしている。
スコープがprotectedなので、継承先クラスしか本メソッドはコールできない。

protected final function fetchRow($rs) {
    return mysql_fetch_array($rs, MYSQL_ASSOC);
}



findQuery()も、RaModelで定義されている。

protected final function findQuery($options=null) {
    $query = 'SELECT *';
    $query .= ' FROM ' . $this->_escapeName($this->_table);
    $query .= $this->_makeOption($options);
    return $this->query($query);
}




findQueryへ渡す引数と、戻ってくるSQLの例は以下のような感じになっている

引数($options)
    array(2) {
      ["condition"]=>
      array(3) {
        [0]=>
        string(19) "dd >= ? AND dd <= ?"
        [1]=>
        string(2) "25"
        [2]=>
        string(2) "25"
      }
      ["order"]=>
      string(30) "dd ASC, hh ASC, mi ASC, ss ASC"
    }
 
戻り値
    "SELECT * FROM `ra_log_201205` WHERE dd >= '25' AND dd <= '25' ORDER BY dd ASC, hh ASC, mi ASC, ss ASC"




また、findQueryの呼び出し元だったfindSummaryの引数例は、以下の通り

options
    array(2) {
      ["condition"]=>
      array(1) {
        [0]=>
        string(0) ""
      }
      ["order"]=>
      string(30) "dd ASC, hh ASC, mi ASC, ss ASC"
    }
 
method
    string(4) "time"
 
yyyyMmOptions
    array(6) {
      ["yyyyFrom"]=>
      string(4) "2012"
      ["mmFrom"]=>
      string(2) "05"
      ["ddFrom"]=>
      string(2) "25"
      ["yyyyTo"]=>
      string(4) "2012"
      ["mmTo"]=>
      string(2) "05"
      ["ddTo"]=>
      string(2) "25"
    }
 
compareValue
    NULL




Logクラスの継承関係は以下の通り

class Log extends RaModel {
    public function __construct($noCreate=false, $yyyymm=null) {
        ...
    }
    ...
}
 
abstract class RaModel {
    protected final function findQuery($options=null) {
        ...
    }
 
    ...
}





調査結果より,通常の流れ以外でDBからデータ取得したい時は…
何らかの処理で、特別にアクセスログのデータが欲しい場合は、自前でLogクラスをnewしてデータを取得する。既存の処理を流用する時は、findSummaryメソッドの第二引数で、欲しいデータが表示されている画面を指定すると楽チン。その際,検索条件として、findOptionsを渡さなければならないが、何を渡すかはfindSummary()の内部でデバッグログを落とすように変更し、結果から逆算した方が手っ取り早い。


上記方針に従って試した結果。
例えば以下のコードで、特定の日に対するアクセス数が取得可能となる。

    $request    = new RaRequest();
    $session    = new RaSession();
    $message    = new RaMessage();
    $controller = "";
    $action     = "";
    $result     = new RaResult();
 
 
 
    $findOptions = array();
    $findOptions["condition"] = array();
    $findOptions["condition"][] = "";
    $findOptions["condition"][] = "dd ASC, hh ASC, mi ASC, ss ASC";
 
    $yyyyMmOptions = array();
    $yyyyMmOptions["yyyyFrom"] = "2012";
    $yyyyMmOptions["mmFrom"]   = "05";
    $yyyyMmOptions["ddFrom"]   = "27";
    $yyyyMmOptions["yyyyTo"]   = "2012";
    $yyyyMmOptions["mmTo"]     = "05";
    $yyyyMmOptions["ddTo"]     = "27";
 
    $compareValue = NULL;
 
    $log = new Log(true);
    $log->setKeys();
    $results = $log->findSummary($findOptions, "time", $yyyyMmOptions, $compareValue);
    echo( "UU=" . $results["uniqueCount"] . "\n" );
    echo( "PV=" . $results["totalCount" ] . "\n" );

Yahooメールのインタレストマッチ広告を停止する

Yahooメールの広告表示ルールが変更に

Yahoo! Japanは2012年8月1日以降、Yahooメールの使用時に広告表示の方法が変更されます。
変更の内容は、Yahooメールのページに表示されていた広告の種類が、今まではユーザの属性に関係なく表示されていたのですが、変更後はユーザにの嗜好に応じたインタレストマッチ広告が表示されるようになります。

そして、ユーザの趣味や嗜好をYahoo側が判定するために、Yahooにメール本文がチェックされます。

その対象は、メールのタイトルだけではなく、本文も含まれます。



広告の表示場所ですが、現在では、以下のようにメール本文の横やフォルダ一覧の上などにあります。


メールをチェックされるというと、プライバシーの侵害が気になるところですが、Yahoo Japanによると内容は機械的に解析され、解析の結果からは個人情報やメールの内容が流出する事は無いとのことです。


インタレストマッチって何?

このインタレストマッチというのは何かというと、興味関心連動型広告とも呼ばれており、ユーザがネットを使用している際に閲覧したページの内容、過去の閲覧履歴や検索キーワードを元に、何に興味を持っているかを推測し、広告の内容をそのユーザの趣味・嗜好に応じたものにするモノです。

今回の改変において、Yahooでは以下のような例をあげています。

例えば、お客様が国内旅行に関する内容が含まれるメールを閲覧されている場合、
国内旅行に関する広告が表示される可能性が高くなります。




インタレストマッチを止めて欲しい!

Yahooによると、メールの解析は機械的に行われるので、プライバシーの侵害について心配は無いとのことですが、人によってはそれでも気になる事もあるかと思います。
そのような場合は、以下の手順でインタレストマッチの機能をOFFにすることが出来ます。


下記のURLより、設定変更ページに移動します。
http://info.mail.yahoo.co.jp/im_optout/

広告表示についてのページが表示されます。

ページの一番下までスクロールさせると、現在の設定内容が表示されます。
今までに設定を行った事がない場合は、”本文解析が有効”に設定されているはずなので、無効にするボタンをクリックします。

クリックすると、”無効に設定されています”に表示が変わります。

これで、インタレストマッチ停止の作業は完了です。

これだけは知っておきたい個人情報保護



2012/5/29追記:
今回の変更についてYahooのカスタマサービスへ質問を送ってみたところ、
回答を頂きましたので掲載させて頂きます。

Q:インタレストマッチ広告が配信されるのはメール画面のみか?


A:
解析を利用したインタレストマッチ広告が表示されるのは、
Yahoo!メールで受信したメール本文画面です。
 
ほかのYahoo! JAPANサービス内に反映されることはございませんので
どうぞご安心ください。


============================================================

Q:今回の変更に伴う、プライバシー情報の管理は?


A:
インタレストマッチ広告の解析は機械的に行われるため、解析結果から
特定の個人や本文内容を識別できない仕組みになっております。
 
また、Yahoo! JAPANではプライバシー保護に最大限の注意を払っており
ご登録いただいた各種情報は、ソフトウエア的にも物理的にも機密性の高い
システム構築により厳重な管理を行っております。
 
お客様の登録情報を外部へ公開することや、販売および譲渡することも
行っておりませんので、どうぞご安心ください。
 
弊社での情報保護方針につきましては、以下のプライバシーポリシーに
明記いたしておりますので、あわせてご参照くださいますと幸いです。
 
◇プライバシーポリシー
http://docs.yahoo.co.jp/docs/info/terms/chapter1.html#cf2nd




2012/6/1追記:
Yahooカスタマサービスより、メールにて上記回答の訂正を受け取りました。
訂正内容は、こちらのエントリを参照してください。

WordPressでAdSenseの広告を表示させる時にすべき事

WordPressを使用してblogを運営している際、AdSense利用時には下記の事をしておくと良いです。

それは何かというと、個別ページの記事内容を表示させる関数である、the_content()の前後を、google_ad_section_start,endコメントで括る作業です。

<!-- google_ad_section_start -->
    <?php the_content() ); ?>
<!-- google_ad_section_end -->



このコメントタグによって、google側にhtml内で本文記事がどこにあるかを伝えてあげる事が出来ます。記事がある場所を伝える事によって、AdSenseの広告として何を表示させるかの決定に影響を与える事ができます。


上記のコメントタグ無しでも、もちろん広告は表示されますが、固定で表示されるヘッダやフッタ、コメントの記述内容も含めて、配信される広告の内容が決定されるため、広告のクリック率が下がる傾向があります。

場合によっては、タイトルを表示するthe_title()も含めて括ってあげると、さらに良いです。


google_ad_section_start,endの仕様については、下記が参考になります。
セクション ターゲットの概要とその設定方法

増補改訂版 グーグル・アドセンスの歩き方
4478041555

目次
 
01 Google AdSenseを始める前に
02 アカウントを作ろう
03 ページにAdSense広告を貼ろう
04 広告の効果を測定しよう
05 プログラムポリシーを理解しよう
06 収益を受け取ろう
07 モバイルでもAdSenseに挑戦しよう
08 DFPスタンダードを活用しよう
09 最適化で収益を向上させよう
10 Google AdSense導入事例
11 AdSense Q&A

[Research Artisan Lite]時間別の明細データを見やすく整形しなおす

時間別の明細データが見づらいので、レイアウトを改善します。
この画面、インストール直後は以下のような表示がされます。



多数の情報が表示されおり便利なのですが、一明細あたりの表示エリア(高さ)が大きく、多量のデータを見る時はスクロールが必要になります。そこで今回は、表示する内容はそのままにした上で、改行位置やフォントサイズを見直し、コンパクトに情報を閲覧できるようにします。
変更のベースにするソースはver1.17です。


ちなみに、時間別の明細データ画面は、ログイン後に出てくるページにある、グラフの時刻をクリックすると表示できます。




変更内容:
今回変更を行う対象は以下の2ファイルです。
ra_core\application\views\research\time_detail.html
ra_core\application\helpers\resultTimeDetailTag.php


time_detail.html

一覧表のヘッダを、以下のように変更します。

 <thead>
 <tr>
  <th class="thdetailleft" rowspan="4">アクセス時間</th>
  <th class="thdetailright">ID&nbsp;/&nbsp;訪問者名</th>
 </tr>
 <tr>
  <th class="thdetailright">IPアドレス / リモートホスト / ドメイン/ドメイン名 (都道府県)</th>
 </tr>
 <tr>
  <th class="thdetailright"><span class="property">画面解像度</span><span class="property">画面色数</span><span class="property">Javascript/Cookie</span><br />USER_AGENT</th>
 </tr>
 <tr>
  <th class="thdetailright">リンク元ページ &rarr; 閲覧ページ</th>
 </tr>
 </thead>
 <tbody>
 <?php $helper->resultTimeDetailTag(); ?>
 </tbody>






resultTimeDetailTag.php


一覧表の明細部を出力する関数、resultTimeDetailTag()のforeach内にある$html書き出し処理を変更します。Research Artisanでは、明細データの出力は、phpの関数内でタグ組み立てを行っています。

処理が長いので、一見すると複雑そうに見えますが、タグ組みを変更しただけです。

  public function resultTimeDetailTag() {
    <中略>
    foreach ($summaryData as $key => $value) {
        <さらに中略>
 
        $html .= '<tr>';
        $html .= '<td rowspan="4" class="tddetailleft'. $this->getEvenClass($i). '">'. $newTag. $accessTime. '</td>';
        $html .= '<td class="tddetailright'. $this->getEvenClass($i). '">';
        $html .= '<span class="favi"><img src="./images/'. $dispOsImg. '" alt="'. $dispOs. '" title="'. $dispOs. '" /></span>';
        $html .= '<span class="favi"><img src="./images/'. $dispBrowImg. '" alt="'. $dispBrow. '" title="'. $dispBrow. '" /></span>';
        $html .= '<a href="'. $this->getIndexUrl('research', 'uid_detail', '&amp;select='. $this->urlEncode($value['uid'])). '" title="'. $value['uid']. '">'. $this->getAlias($value['uid']). '</a>';
        $html .= '<span class="alias"><a href="'. $this->getIndexUrl('admin', 'aliasedit', '&amp;select='. $this->urlEncode($value['uid'])). '">訪問者名設定</a></span>';
        $html .= '</td>';
        $html .= '</tr>';
        $html .= '<tr>';
 
        $html .= '<td class="tddetailright'. $this->getEvenClass($i). '" style="font-size:80%;">';
        $html .= '<a href="'. $this->getIndexUrl('research', 'ip_user', '&amp;select='. $this->urlEncode($value['remote_addr'])). '" title="'. $value['remote_addr']. '">'. $value['remote_addr']. '</a> ';
        $html .= ' / <a href="'. $this->getIndexUrl('research', 'remotehost_user', '&amp;select='. $this->urlEncode($value['remote_host'])). '" title="'. $value['remote_host']. '">'. $value['remote_host']. '</a>';
        $html .= ' / <a href="'. $this->getIndexUrl('research', 'domain_user', '&amp;select='. $this->urlEncode($value['domain'])). '" title="'. $value['domain']. '">'. $this->getDomain($value['domain']). '</a>';
        $html .= ' (';
        if (!is_null($dispPrefImg)) $html .= '<span class="favi" ><img src="./images/'. $dispPrefImg. '" alt="'. $value['pref']. '" title="'. $value['pref']. '" /></span>';
        $html .= '<a href="'. $this->getIndexUrl('research', 'pref_user', '&amp;select='. $this->urlEncode($value['pref'])). '" title="'. $value['pref']. '">'. $value['pref']. '</a>)';
        $html .=  $this->getDomainEdit($value['domain']);
 
        $html .= '</td>';
        $html .= '</tr>';
        $html .= '<tr>';
        $html .= '<td class="tddetailright'. $this->getEvenClass($i). '" style="font-size:70%;color:#999;">';
        $html .= '<span class="property"><a href="'. $this->getIndexUrl('research', 'screenwh_user', '&amp;select='. $this->urlEncode($value['screenwh'])). '" title="'. $value['screenwh']. '">'. $value['screenwh']. '</a></span>';
        $html .= '<span class="property"><a href="'. $this->getIndexUrl('research', 'screencol_user', '&amp;select='. $this->urlEncode($value['screencol'])). '" title="'. $value['screencol']. '">'. $value['screencol']. '</a></span>';
        $html .= '<span class="property"><a href="'. $this->getIndexUrl('research', 'jsck_user', '&amp;select='. $this->urlEncode($value['jsck'])). '" title="'. $value['jsck']. '">'. $value['jsck']. '</a></span>';
        $html .= '<br />';
        $html .=  '<span>' . $this->escapeHtml($value['http_user_agent']) . '</span>';
 
        $html .= '</td>';
        $html .= '</tr>';
        $html .= '<tr>';
        $html .= '<td class="tddetailright'. $this->getEvenClass($i). '" style="font-size:90%;"><div class="detail">'. $dispReferer. '</div><div class="detail">'. $arrowTag. '<span class="requesturi">'. $dispRequest. '</span></div></td>';
        $html .= '</tr>';
 
        ...




上記変更を行うと、以下のように明細行の高さが半分以下になりました。
今まで1明細を表示させるエリア内に、2明細分の情報を詰め込みました。
変更前:


変更後:


今回の改造は実質的にタグの修正だけなので、phpが良く分からなくてもhtmlさえ知っていれば、好みのレイアウトに変更する事が出来ます。

[Research Artisan]ページヘッダの画像を小さくする

Reserch Artisan Liteで、常に表示されているページヘッダ画像を縮小表示させます。
不要な情報を減らすことで、見たい情報をスクロールせずに閲覧できるようにします。

変更内容:

main.css

場所:ra\analyze\stylesheets\

#bannerの表示エリア調整と、その中にあるimgタグのサイズ指定を行います。

#banner { 
/* mod: 2012/05 トップバナー表示エリアを小さくする
   height: 80px;    
   width: 500px;
   margin: 0 0 15px 0;
*/
  margin 0px;
  font-size: 120%;
  font-weight: bold;
  padding: 0;
  display: inline;
  float: left;
  clear: right;
}
/* add: 2012/05 バナー画像を小さくする */
#banner img {
	width:150px;
}




ヘッダ画像が小さくなり、より下のほうまで情報が表示されるようになりました。

変更前:


変更後:


画像サイズを変更させるのではなく画像自体を削除・変更したい場合は、以下のファイルを修正することで自由自在に変更できます。

ra_core\application\views\layout\main.html

[Research Artisan]ログイン画面でパスワード入力欄にフォーカスセットさせる

ログイン画面を表示させたとき、初期状態でパスワード入力欄にフォーカスがセットされていないので、フォーカスセットさせる為の改造です。
細かい事ですが、ちょっとした事の積み重ねで使い勝手が変わってきます。
ベースとなるソースは、ver1.17です。


変更内容

login.html

場所: ra_core\application\views\login

ファイルの最後に、以下のスクリプトを追加します。

<script>
window.onload = function() {
    //パスワード入力欄にフォーカスセット
    var edtPass = document.getElementById( "pswd" );
    edtPass.focus();
};
</script>



デフォルトでフォーカスがセットされるようになりました。

[Research Artisan]ログイン後の画面に、AdSenseクリック数・リンククリック数を表示させる


Reserch Artisan Liteでは、ログインを行った直後に、当日の時間別アクセス数が表示されます。
今回の改造は、このページにAdSenseのクリック総数と、リンクのクリック総数を表示させます。


上記の情報を表示させるためには、Reserch Artisan Liteのソースを変更する必要があります。
今回は、ver1.17のソースを元に手を入れています。


変更対象となるファイルは、以下の3ファイルです。

ReserchController.php

場所: ra_core\application\controllers

time()メソッドで表示対象のログデータのSQL組み立て処理を、以下のように書き換えます。

  public function time() {
    $conditions = $this->_initConditions();
    if (!is_null($this->session->get('selectPage'))) {
      $conditions[0] .= ' AND url = ?';
      array_push($conditions, $this->session->get('selectPage'));
    }
    $order = 'dd ASC, hh ASC, mi ASC, ss ASC';
    $findOptions = array('condition' => $conditions, 'order' => $order);
    return $this->_doResearch($findOptions, $this->request->get('select'));
 
    // Mod:2012/05: ログデータ取得処理を変更
/*
    $conditions = $this->_initConditions(Config::NORMAL_ACCESS);
    if (!is_null($this->session->get('selectPage'))) {
      $conditions[0] .= ' AND url = ?';
      array_push($conditions, $this->session->get('selectPage'));
    }
    $order = 'dd ASC, hh ASC, mi ASC, ss ASC';
    $findOptions = array('condition' => $conditions, 'order' => $order);
    return $this->_doResearch($findOptions);
*/
  }





Log.php

場所: ra_core\application\models

time()メソッドで、クリック数の情報を集計させます。

  private function _time() {
    $this->_extractTimeData($this->getValue('uid') . $this->getValue('yyyy') . $this->getValue('mm') . $this->getValue('dd'), $this->getValue('hh'));
 
    // Add:2012/05: 追加の明細情報を集計する
    $this->_extractDetailCount();
  }





time.html

場所: ra_core\application\views\research


ヘッダ部に、取得したデータの表示エリアを追加します。

<table class="header_value">
<tr>
  <td class="label">ユニークアクセス総数</td>
  <td class="label">:</td>
  <td class="value"><span class="header_value"><?php $helper->uniqueCount();?></span></td>
</tr>
<tr>
  <td class="label">アクセス総数</td>
  <td class="label">:</td>
  <td class="value"><span class="header_value"><?php $helper->totalCount();?></span></td>
</tr>
 
<!-- Add:2012/05: クリック数の表示エリアを追加 -->
<tr>
  <td class="label">AdSenseクリック 総数</td>
  <td class="label">:</td>
  <td class="value"><span class="header_value"><?php $helper->clickAdsenseCount();?> (<a href="https://www.google.com/adsense/" target="_blank">ログイン</a>)</span></td>
</tr>
<tr>
  <td class="label">リンククリック 総数</td>
  <td class="label">:</td>
  <td class="value"><span class="header_value"><?php $helper->clickLinkCount();?></span></td>
</tr>
 
</table>




変更を行った後ログインすると、以下のように表示欄が追加されます。
ログインのリンクをクリックすると、AdSenseの管理ページが別タブで表示されます。

[PHP]メソッドの呼び出し元関数名を取得する

debug_backtrace()関数を使用することで、スタックトレースの情報から取得可能です。

function showCallerFunc() {
    $dbg = debug_backtrace();
    echo( $dbg[1]['function'] );
}



メソッド内で、呼び元が誰かを知る必要は通常ありませんが、デバッグやログ出力目的には便利です。

また、debug_backtrace()メソッドでは、function以外に以下の情報も取得できます。

function    string  
    関数名。
 
line    integer     
    行番号。
 
file    string  
    ファイル名。
 
class   string  
    クラス名。
 
object  object  
    オブジェクト。
 
type    string  
    コール方式。
    メソッド呼び出しの場合は "->"、 静的なメソッド呼び出しの場合は "::" が返されます。 
    関数呼び出しの場合は何も返されません。
 
args    array   
    関数の内部の場合、関数の引数のリストとなります。 
    インクルードされたファイル内では、 読み込まれたファイルの名前となります。


Reserch Artisan Liteの明細画面で、1ページあたりの表示件数を変更する


PHP製アクセス解析のオープンソースソフトウェアとして、有名なモノにReserch Artisan Liteがあります。フリーで使用可能でありながら、非常に高機能な事で有名なソフトです。

概ね満足しているのですが、デフォルトだとログの出力結果が若干見づらい部分が幾つかあるので、見やすくする為の修正方法を幾つか行ってみます。



まずは、検索結果の明細ページに表示される1ページあたりの件数を変更します。
デフォルトでは、以下のように30件づつ表示されます。


アクセス数が少ない場合はこれでも良いのですが、多くなってくるとページ遷移が面倒になってくるので、表示件数を増やします。


この件数はシステム設定画面から変更が可能です。

まずは、ログインを行い、左のメニューから”アクセス解析設定”を選択します。
アクセス解析設定は、背景がグレーになっているボタンの一番上にあります。



明細表示件数の設定欄があるので、この値を変更します。
今回は最大値である100件に変更してみました。



変更後、明細ページを確認すると確かに100件づつの表示に変わりました。




もし、100件以上にしたい場合は、SettingConfig.phpに選択肢の一覧があるので、ここを修正すればOKです。
ファイルがある場所は、ra_core\application\config です。

ファイル内に、以下のような記述があるので…

  public static $dispViews = array(
                    '10' => '10件',
                    '20' => '20件',
                    '30' => '30件',
                    '40' => '40件',
                    '50' => '50件',
                    '60' => '60件',
                    '70' => '70件',
                    '80' => '80件',
                    '90' => '90件',
                    '100' => '100件'
  );



もし、500件/ページの選択肢を追加したい場合は、以下のように書き換えます。

  public static $dispViews = array(
                    '10' => '10件',
                    '20' => '20件',
                    '30' => '30件',
                    '40' => '40件',
                    '50' => '50件',
                    '60' => '60件',
                    '70' => '70件',
                    '80' => '80件',
                    '90' => '90件',
                    '100' => '100件',
                    '500' => '500件'             // ← この行を追加
  );




ファイル更新後に設定画面を開くと、確かに選択肢が追加されました。

Research Artisan Liteのソースコード解析メモ

データ集計周りのロジックを調査したときのメモ。
ソースを調査した目的は、Research Artisan Liteでログイン直後に表示される時間別画面に、各種サマリー値(adsenseクリック数など)を出したかったから。


確認できた事


ログの集計は、RaModel.phpのfindQuery()で実施される。

ログの種類は各種ある(アクセスログ、クリックログ、adsenseログetc.)、これらはlogテーブルのlogtype列で種別分けされている

logtypeの種類はConfig.phpで定義されている。

  const NORMAL_ACCESS = '0';
  const CLICK_LINK = '1';
  const CLICK_BTN = '2';
  const CLICK_ADSENSE = 'g';



アクセスログの各種確認画面で、データの取得を行うSQLは、ResearchController.phpで決定されている。
(画面に応じて、本クラスのデータ取得メソッドがコールされる)


どの画面が,どのデータ取得メソッドをコールするかは、MenuConfig.phpに定義されている。

  public static $convertActions = array(
                    'time_detail' => 'time',
                    'uid_detail' => 'uid',
                    'ip_user' => 'ip',
                    'remotehost_user' => 'remotehost',
                    'domain_user' => 'domain',
                    'jpdomain_user' => 'jpdomain',
                    'country_user' => 'country',
                    'pref_user' => 'pref',
                    'rank_user' => 'rank',
                    'key_user' => 'key',
                    'engine_key' => 'engine',
                    'engine_user' => 'engine',
                    'host_user' => 'host',
                    'crawler_user' => 'crawler',
                    'referer_user' => 'referer',
                    'rate_user' => 'rate',
                    'clickrank_user' => 'clickrank',
                    'btnrank_user' => 'btnrank',
                    'pagein_user' => 'pagein',
                    'pageout_user' => 'pageout',
                    'brow_ver' => 'brow',
                    'brow_user' => 'brow',
                    'os_user' => 'os',
                    'screenwh_user' => 'screenwh',
                    'screencol_user' => 'screencol',
                    'jsck_user' => 'jsck',
                    'adsenserank_user' => 'adsenserank',
                    'adsensepagerank_user' => 'adsensepagerank',
                    'adsenseip_user' => 'adsenseip',
                    'aliasedit' => 'aliaslist',
                    'domainedit' => 'domainlist',
                    'douninstall' => 'uninstall',
                    'deletelog_confirm' => 'deletelog'
  );



view側では、例えばユニークユーザは$helper->uniqueCount()で取得可能だが、”ユニークユーザ”が何であるかは、ResearchController.phpで決められる。なので、時間別アクセス数のページで、Adsenseクリック数のユニークユーザーを表示させるには工夫が必要。(前述のメソッドをコールすると、当然ながら時間別アクセス数のUUが表示されるので)


アクセスログ表示画面に対する$helper->uniqueCount()の実態は、ReserchHelper.phpで定義されている。

  public function uniqueCount() {
    print $this->getFormatNumber($this->result->get('uniqueCount'));
  }




ReserchHelper.phpを見ると、clickAdsenseCount()メソッドとか有るので、これをコールすれだけかと思いきや、残念ながら常に0が返ってくるだけ。


なぜかというと、Log.phpで、logtypeがCLICK_ADSENSEのときしか値を取ってないから。
これがCLICK_ADSENSEになるのは、アドセンスログのログ画面を表示させるときだけだから、今回やりたい事にとっては、役に立たない。

  private function _extractDetailCount() {
    switch($this->getValue('logtype')) {
    case Config::NORMAL_ACCESS:
      ++$this->_totalCount;
      break;
    case Config::CLICK_LINK:
      ++$this->_clickLinkCount;
      break;
    case Config::CLICK_BTN:
      ++$this->_clickBtnCount;
      break;
    case Config::CLICK_ADSENSE:
      ++$this->_clickAdsenseCount;
      break;
    }




結局のところ、特定のcontrollerから複数のhelperをコールしたいのだけど、MenuConfigでcontroller:helperが1:1に紐付けられているので、対応が難しい…という感じっぽい
どうしたものか…