Only variables should be assigned by reference エラー

Ethnaのログで一杯出てた。
一杯出てたんだけど、まいっかと思って放置してた。
けど、たまにログを見ると、こやつがむやみにログを汚しているので、本腰入れて直した。

ログを出しているところは、
Ethna_Plugin_Validator_Customの45行目。
$ret =& $this->af->$method($name);
ずっとEthna本体が悪いのかなーと思ってんたんだけど、カスタムなので自分の作った関数がいかんのじゃないかと思ったらビンゴ。
情けない・・・。

参考にしたサイトがこちら。
はっぴぃ・りなっくす - Notice [PHP]: Only variables should be assigned by reference - Tools > PHP - SmartSection

参照って分かっているようなわかっていないような。
けど、この説明は判りやすい気がした。
参照とは、値そのものではなく、値の格納されているメモリ位置の情報です。

ポインタとかってCOBOLの奴と一緒の概念かな。
Cとかと一緒らしいけど、まったくわかんないし。
COBOLも忘れてまったけど・・・ひたすら数えていた気がする。

この警告PHP4.4.xから出るんだな。
なるほど、無頓着なはずだ。

Ethnaでビット演算子って始めて知った

結構アクセスが増えてくると、セッションが上手く繋がらないことが多くなってくる。
で、Ethnaの場合だと、Ethna_Sessionクラスの_validateRemoteAddr関数が弾いているっぽい。

コメント欄で
セッションに保存されたIPアドレスとアクセス元のIPアドレスが同一ネットワーク範囲かどうかを判別する(16bit mask)
って書いてあったんだけど、よう分からんかった。

■16bitマスクについて
多分
xxx.xxx.yyy.yyy
で、xの部分(16bit分)が変わったらいかんよって事だ。
逆にyの部分(16bit分)が変わっても、同一ネットワーク範囲とするってことだ。

まあ、会社とかになると24bitのサブネットマスクとか当たり前になるので、これってセキュリティ上厳しいのか厳しくないのかようわからんけど、まあ、何でも自由ってのよりは全然良いわな。
それは間違いない。

で、意味は分かったんだけど(多分)、今度はソースが解読できない。

function _validateRemoteAddr($src_ip, $dst_ip)
{
    $src = ip2long($src_ip);
    $dst = ip2long($dst_ip);

    if (($src & 0xffff0000) == ($dst & 0xffff0000)) {
        return true;
    } else {
        $this->logger->log(LOG_NOTICE, "session IP validation failed [%s] - [%s]",
                           $src_ip, $dst_ip);
        return false;
    }
}

ip2long()とif文中にある"&"演算子。
ip2long関数は、まあすぐ調べることが出来たんだけど、"&"演算子がなかなか出てこなかった。

で、見つけた。
【 ほでなすPHP 】 PHPの基本 -> 演算子

結局「ビット演算子」ってものらしい。
ビットっていうぐらいだから、2進数でごにょごにょやるらしい。

0xffff0000の見た方がわからなかったんだけど、多分最初の0xってのは、正負の記号と見た!
んで、後ろのffff0000が32bitを表しているはず!

で、ffff0000を2進数で直すと
1111 1111 1111 1111 0000 0000 0000 0000
となる。

IPアドレスは8bit×4で32bitだから、上のにあわせると
11111111.11111111.00000000.00000000
↓
255.255.0.0
って感じになる。

んーこれって数学?

つまりのところ、このif分は、fの部分の16bit分がマスク扱いで、そこが一緒かどうかみてるってことね。
それが一緒なら、同一ネットワークですよと。

んーこうやってマスクのチェックをしていたんだなと納得。
凄いなあ、藤本さんは!
年下とは思えない・・・(涙)

さすがPHPのコミッターだなーって思ったけど、学校行って勉強した人とかにとっては普通かな?
独学の僕には新鮮だったわ。

つか、こんなの無理だわー。

Ethna 2.3.5 リリース!

もうEthnaって開発終わってんじゃないの?とIRCで嘆いたら、わーっとみんなからコメントがあって、なんだ表には出てきてないけど結構皆まだ触っているんだと思ったのが、確か去年の年末だったかなあ。

久しぶりにIRC覗いたら、Ethna 2.3.5リリースの瞬間に立ち会えた。
グダグダしていたけど、ちょっと熱があって素敵だったな。
みんな自分の仕事あるのに、睡眠時間削って平気で貢献しているのを見て、本当に凄いなと思った。

僕も、公式ドキュメントが間違っているとかちょろっと指摘したら、直ぐ対応してくれた。
素敵。

Ethnaのコミュニティはこういうアットホームなのが良いな。
今回はメンテナンスリリースってことで、大きな機能の追加とかは無いけど、次のリリース時にはなんとUTF-8対応とか書いてあったのでびっくりした。
でら熱い。

っつうことで、メインで頑張ったmumumuさんお疲れ様でした!

EthnaのCSRF対策

EthnaはCSRF対策機能まで実装してある。
すんばらしい。
クロスサイトリクエストフォージェリの対策コードについて

で、本来の使い方と違うかもしれないけど、CSRF対策限らず、「ある時点からセッションの内容が変更された」時のチェックとかにも何気に使えるので、これを応用して拡張した時のメモ。


■テンプレートにIDを埋め込む時、GETで渡したい場合
これ公式サイトにはPOST時のことしか載っていなかったけど、getの時のも用意されてそうだなーとソースを見たら載ってた。

{csrfid type="get"}で
ethna_csrf=xxxxxxxxxxxxx~
ってコードが生成されるんで、こんな感じに書くとOK

a href="http://hogehoge.com/index.php&{csrfid type="get"}"


■Sessionが匿名の奴(anonymous)の時も使いたい
Ethna_Plugin_Csrf_Sessionでは、anonymousだと弾かれてまう。
ので以下のように独自のプラグインを作成

class Hoge_Plugin_Csrf_Session extends Ethna_Plugin_Csrf
{
    /** @var    object  Ethna_Session    セッションオブジェクト */
    var $session;

    /** @var    bool    anonymous        セッションのanonymous */
    var $anonymous;

    /**
     *  Hoge_Plugin_Csrfのコンストラクタ
     *
     *  @access public
     *  @param  object  Ethna_Controller    &$controller    コントローラオブジェクト
     */
    function Hoge_Plugin_Csrf_Session(&$controller)
    {
        parent::Ethna_Plugin_Csrf($controller);

        // オブジェクトの設定
        $this->session   =& $this->controller->getSession();
+       $this->anonymous =  $this->session->isAnonymous();
    }

    /**
     *  トークンをViewとローカルファイルにセットする
     *
     *  @access public
     *  @return boolean  成功か失敗か
     */
    function set()
    {
-       if (! $this->session->isStart() {
-           $this->session->start();
-       }
+       if (! $this->session->isStart($this->anonymous)) {
+           $this->session->start(0, $anonymous);
+       }

        $token = $this->session->get($this->token_name);
        if ($token !== null) {
            return true;
        }

        $key = $this->_generateKey();
        $this->session->set($this->token_name, $key);

        return true;
    }

    /**
     *  トークンIDを取得する
     *
     *  @access public
     *  @return string トークンIDを返す。
     */
    function get()
-       if (! $this->session->isStart() {
-           $this->session->start();
-       }
+       if (! $this->session->isStart($this->anonymous)) {
+           $this->session->start(0, $anonymous);
+       }

        return $this->session->get($this->token_name);
    }

    /**
     *  トークンIDを削除する
     *
     *  @access public
     */
    function remove()
    {
-       if (! $this->session->isStart() {
-           $this->session->start();
-       }
+       if (! $this->session->isStart($this->anonymous)) {
+           $this->session->start(0, $anonymous);
+       }

        $this->session->remove($this->token_name);
    }

}

あと、リセットしたい場合(今までのを破棄&再発行)もあったので、関数追加した。
    /**
     *  トークンをViewとローカルファイルにリセットする
     *
     *  @access public
     */
    function reset()
    {
        $this->remove();
        $this->set();
    }

これだけじゃ折角追加した関数が使われないので、Hoge_Util.phpも独自に作成。
こっちは継承させて、以下の関数を追加。
デバッグ用にgetCsrfID()って関数も作ってみた。

    /**
     *  CSRFをリセットする
     *
     *  @access public
     *  @return bool    true:成功
     */
    function resetCsrfID()
    {
        $c =& Ethna_Controller::getInstance();
        $name = $c->config->get('csrf');
        
        if (is_null($name)) {
            $name = 'Session';
        }
        
        $plugin =& $c->getPlugin('Csrf', $name);
        $csrf =& $plugin->getPlugin('Csrf', $name);
        return $csrf->reset();
    }

    /**
     *  CsrfIDを取得する
     *
     *  @access public
     *  @return bool    true:成功
     */
    function getCsrfID()
    {
        $c =& Ethna_Controller::getInstance();
        $name = $c->config->get('csrf');
        
        if (is_null($name)) {
            $name = 'Session';
        }
        
        $plugin =& $c->getPlugin('Csrf', $name);
        $csrf =& $plugin->getPlugin('Csrf', $name);
        return $csrf->get();
    }
}

これで
Hoge_Util::getCsrfID();
とかすれば使えるように。
もう、どんどん拡張してるなー。
でもでら便利。

Ethnaのログの設定方法について

Ethnaでのログの設定方法なんだけど、公式サイトの本番環境の設定のサンプルが間違っている気がする。

方針はこれ。
とにかく画面にはなにも表示しない。回避可能だが意図した動作になっていないなどのLOG_WARNINGレベルはファイルに出力。データベースに接続できないなどの緊急時に発生するLOG_ERRレベルのログはメールでアラート用メーリングリストに送信する。

んで、実際の設定がこれ。
'debug' => false,
...
'log' => array(
// この3行があったら出力しちゃうと思うので削除
-   'echo' => array(
-       'level'         => 'notice',
-   ),
    'file' => array(
// 方針に従うとwarningな気がするんだけど・・・。
-       'level'         => 'debug',
+       'level'         => 'warning',
    ),
    'alertmail' => array(
        'level'         => 'err',
        'mailaddress'   => 'alert@ml.example.jp',
    ),
),
'log_option'        => 'pid,function,pos',
'log_filter_do'     => '',
'log_filter_ignore' => 'Undefined index.*%%.*tpl',

違うのかなー。
なんか自信ないからwiki触れないけど・・・。

でも、サンプルのまんまやると、noticeレベルでもechoされちゃうから絶対おかしいと思うんだけどな。

※IRCで聞いてみたら、やっぱ間違っていたみたい。いちいさんが直してくれました。

アーカイブ

2012

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
  • 11
  • 12

2011

2010

2009

2008

2007

コンタクト

longkey1[at]gmail[dot]com