STRICTモードなMySQLにCodeIgniterセッションをDB保存する際に注意すること

とある案件でちょっとハマったので覚書程度に書いておきます。

そもそもの発端

ご存知の通りCodeIgniterのセッションはちょっと特殊で、その性質上、私はDBに保存することがほとんどです。
で、いつも通りにやっててもDBに保存されないので「なんで!?」とアレコレやった結果です。
結論から言いますと、解決策はいたってシンプルです。

STRICTモードでの動作?

$db['default']['db_debug'] = FALSEにしてたせいで解決に時間がかかってしまいました・・・デバッグ大事。

STRICTモードとは、

MySQL::MySQL 5.1 リファレンスマニュアル::4.2.6 SQL モード

にあるように、厳格なモードで動作させるみたいです。このMySQLがこのモードで動作している場合CodeIgniterのSessionクラスがエラーになります。
エラーはこんな感じです。

メッセージからするに、user_dataカラムに初期値が設定されてないのが原因のようでした。
user_dataカラムは通常TEXTタイプにすると思うので、DEFAULT値を設定するのはダメですね。

コード修正とか

新規セッションデータを作成する際に問題があるようなので、CI_Session::sess_create()メソッドにデフォルト値を追記します。


function sess_create()
{
$sessid = '';
while (strlen($sessid) < 32)
{
$sessid .= mt_rand(0, mt_getrandmax());
}

// To make the session ID even more secure we'll combine it with the user's IP
$sessid .= $this->CI->input->ip_address();

$this->userdata = array(
'session_id' => md5(uniqid($sessid, TRUE)),
'ip_address' => $this->CI->input->ip_address(),
'user_agent' => substr($this->CI->input->user_agent(), 0, 50),
'last_activity'=> $this->now
);

// デフォルト値を設定
$this->userdata['user_data'] = '';

// Save the data to the DB if needed
if ($this->sess_use_database === TRUE)
{
$this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
}

// Write the cookie
$this->_set_cookie();
}


赤字の部分のように、user_dataカラムに空文字列をセットして動作させたところ、上手くセッションが開始されました!
新規セッションデータのINSERTなので、空文字列でいいと思います。

まとめ

クエリを発行してモードチェックと処理分岐まで書いてたのですが、「そこまでせんでも…」と思い直ってやめました。
そもそもMySQLの動作モードまでアプリケーションで吸収することじゃないよね、と思ったりしたので。

1行追記するだけなので、コアライブラリにそのまま書いちゃっていいかもしれませんが、そもそもSTRICTモードで動いている
MySQLが稀かもなので、困った時に追記すればいいですかね。

ちなみに、CodeIgniter2.0系でもこの処理は変わらずでした。

以上、私的な覚書でした。

HTML5 classList APIの速さを調べてみた

HTML5 classList APIっていうのがあるそうです。知りませんでした。
ちょっと覗いていたらこれは便利そうだ、ということで組み込んでみようか、という前に簡単にテストしてみました。
Native APIだから速いよね〜という期待を込めて。

そもそもの発端

Twitterでちょっと見かけたので。

テストしてみる

HTML5で追加されるclassList APIについてのメモ :: 5509

によると、現状では、

とかで使えるらしいです。add()とかtoggle()とか色々できるらしいのですが、ClassList#containsについて今回はちょっと調べてみました。
比較対象として、jQuery1.5.1とゴニョゴニョと判定する方式を使ってみます。以下がテストコードです。



<!doctype html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ClassList#contains</title>
<script type="text/javascript" src="../jquery.js"></script>

<script type="text/javascript">
onload = function() {
var result = document.getElementById('result'),
res = [];

res[res.length] = classListByJQuery('hogehoge');
res[res.length] = classListByNativeAPI('hogehoge');
res[res.length] = classListOrig('hogehoge');

result.innerHTML = res.join('<br />');
}

function classListByJQuery(c) {
var d = $(document.body),
i = 0,
start = new Date().getTime(),
r;

for (; i < 10000; ++i) {
if (!d.hasClass(c)) {
throw Error('class error');
}
}
r = new Date().getTime() - start;

return 'jquery::hasClass -> ' + r;
}

function classListByNativeAPI(c) {
var d = document.body,
i = 0,
start = new Date().getTime(),
r;

for (; i < 10000; ++i) {
if (!d.classList.contains(c)) {
throw Error('class error');
}
}
r = new Date().getTime() - start;

return 'Native classList API -> ' + r;
}

function classListOrig(c) {
var d = document.body,
i = 0,
start = new Date().getTime(),
r;

for (; i < 10000; ++i) {
if ((' ' + d.className + ' ').indexOf(' ' + c + ' ') === -1) {
throw Error('class error');
}
}
r = new Date().getTime() - start;

return 'Orig checker -> ' + r;
}

</script>
</head>
<body class="hogehoge hugahuga">
<div id="result"></div>
</body>
</html>

ちょっと長いですね。「classListByJQuery」がjQuery、「classListByNativeAPI」がclassList API、「classListOrig」がゴニョゴニョやるもので、
それぞれを10000回実行してみました。結果は以下のとおり。

Firefox:


jquery::hasClass -> 32
Native classList API -> 36
Orig checker -> 8

Chrome:


jquery::hasClass -> 10
Native classList API -> 3
Orig checker -> 3

やっぱりChromeは速いですねー。でもFirefoxではあんまり変わらないどころかやや遅めでした。
自分で判定する処理は文字列比較なので平均的な速度ですね。私は大体これで判定してます。

感想

Firefoxはこれから速くなればいいと思います。条件によっては使えるかもしれないですね。

CodeIgniter1.7.3でもセグメントアプローチ+$_GETを使いたい

CodeIgniter(以下CI)1系では、セグメントアプローチでのルーティングの際には、問答無用で$_GETが破棄されます。「まぁそういう仕様なんだね」ということでスルーしていたのですが、使えたらいいよねという感じで拡張してみました。

ある仕様とコンフリクトする可能性がある、というご指摘を受けて追記しました。↓にて追記してます

さらに追記:$_SERVER['QUERY_STRING']まで削除するのはやりすぎだと気づきました。

そもそもの発端

CI2.0 Reactorでは、$config['arrow_get_query']の設定により、$_GETが使えるようになっているそうです。なので、まだ現役な1.x系でも使えたらいいのに・・・と思ったので試しにやってみました。検索クエリの取り回しに使えるかもしれませんね。使用しているのはCI1.7.3です。

どこで破棄されるの?

Inputクラスが初期化された際に破棄されます。_sanitize_globals()メソッド内で「$_GET = array();」とありますね。Oh。
ただし、$config['enable_query_strings'] = TRUE;として、クエリベースアプローチの場合は破棄されません。

処理の順番的に

CIの初期化プロセスはシンプルなので、処理の順番が関わってきます。system/codeigniter/CodeIgniter.phpを見ると分かりますが、

  1. Configクラス
  2. URIクラス
  3. Routerクラス
  4. Outputクラス
  5. Inputクラス

の順にロードされていきます。なので、Inputクラスが初期化される前にゴニョゴニョしておく必要があるのですが、少し困った問題があります。


URIクラスでURI文字列を正規化する際に、$config['uri_protocol'] = 'AUTO'だと、
クエリストリングがあるとそれをURI情報に追加してしまう

ということになっているようです。試しにデフォルトのままクエリ文字列をつけてアクセスすると404に…。じゃあ設定を変えればいいじゃん、となるわけですが、こういう制限をかけるのはちょっと面白く無いので、$config['uri_protocol'] = 'AUTO'でも動作するようにしてみます。というわけで、拡張するのはURIクラスです。

一時的に退避→ルーティング後に復帰というやや強引な手法


URI正規化とルーティングの時点では$_GETは無かったことにして、ルーティング終了後にリカバリさせればいいかな

ということで、URIクラスのコンストラクタで退避させます:


class MY_URI extends CI_URI
{
var $_get_stack;

// override constructor.
function MY_URI()
{
parent::CI_URI();

// hack: We can use $_GET query at segment approche
if (count($_GET) > 0
&& config_item('uri_protocol') === 'AUTO'
&& config_item('enable_query_strings') === FALSE)
{
$this->_get_stack = $_GET;
$_SERVER['QUERY_STRING'] = '';
$_GET = array();
}
}

// recovery $_GET.
function __recovery_get_query()
{
$IPT = load_class('Input');
$_GET = $IPT->_clean_input_data($this->_get_stack);
}
.
.
.

$config['uri_protocol'] = 'AUTO'の場合、URIの正規化に使われるのは$_GETと$_SERVER['QUERY_STRING']の値のようなので(URI::_fetch_uri_string()参照)、
コンストラクタの時点で条件判定し、_get_stackに退避して、一時的に各パラメータはなかったことにします。
こうすることで、Routerクラスのルーティング時には$_SERVER['PATH_INFO']の値を使って、純粋にセグメントを元にコントローラが呼ばれます。


2011/03/04追記:
_fetch_uri_string()での正規化の順番を見たところ、


1. $_GET
2. $_SERVER['PATH_INFO']
3. $_SERVER['QUERY_STRING']


の順番でしたので、上記方法の場合、PATH_INFOの時点で正規化が完了する(はず)です。なので、3は特に考えなくても良い、さらに$config['index_page'] = 'index.php?';のような場合でも3でルーティングできるのではないか、と考えました。

あとは戻すだけ

ルーティングが完了後、_get_stackから戻すだけなのですが、その処理を実行するポイントが見つかりませんでした><
なので、私は(seezooでは)pre_controllerのフックでコントローラの実行が始まる直前にリカバリしました。
Controllerクラスのコンストラクタでやってもいいかな、と思います。Inputクラスを再度ロードして、_clean_input_data()メソッドに退避した$_GETのデータを通しておきます。

コントローラで使えるよ

これで、コントローラ内とかで、


$hoge = $this->input->get('hogehoge');

とやれば、セグメントアプローチでも$_GETパラメータが使えるようになりました。
それぞれのパラメータのセキュリティチェックは忘れずに。

感想とか

  • 本来ならInputクラスを拡張してやることなのかもしれない

今回は既にURIクラスを拡張したものを使っていたので、 そのまま拡張を続けた感じです。

  • スーパーグローバル変数に値を入れたりできるのはやっぱりどうかと思ったり。

「そういうものだよ」と納得せざるを得ないです。


他に問題とかあれば教えてください。

追記

@kenji_sさんよりご指摘をいただきましたー。

PATH_INFOが設定されていないサーバの場合のトラブルシューティングの方法

トラブルシューティング:CodeIgniter ユーザガイド 日本語版

と仕様がコンフリクトする可能性があります。$config['index_page'] = 'index.php?'とクエリ文字列で渡した場合、最初に$_GETを消してしまうとルーティング出来なくなっちゃいますね。

PATH_INFOが設定されているサーバでのみ有効、つまり、上記トラブルシューティングを発動しなくても動作できるサーバーで、ということに訂正させていただきます。

『Webサイト制作者のためのJavaScript入門講座』という本を書きました

Webサイト制作者のための JavaScript入門講座

Webサイト制作者のための JavaScript入門講座

岩田 享さん、安藤健一さんと共著で書籍を執筆させていただきました。

2011年1月7日発売、すでに書店に並んでいると思います。

どんな本?

これからJavaScriptを始めてみようかなという方に向けた入門書になれば、という感じです。
今のWebサイト製作において、JavaScriptはその地位を確立し、ほとんどのWebサイトに当たり前のように使われているな〜、と富みに感じます。

比較的簡単な部類に入るプログラミング言語だと言われていますが、それでもプログラム。HTMLやCSSとは少し毛色が違います。

幸い、今のネット上には便利なライブラリやコードが沢山溢れているので、それを利用する方も多いですし、そのままサイトに導入すればOKなケースがほとんどです。でも、そのライブラリやコードが「どんな理屈で動いているの?」と気になったことはないでしょうか?
本書では、コードの意味とその動作について事細かに解説できるように心がけました。

また、私自身HTML+CSSからこの世界に入ったものですから、プログラミングがある程度できるようになるまで苦労したのを覚えています。
特にif文とかって、意外と覚えにくいものです><

そうして僅かながらも積み上げてきたものを、今回の執筆でアウトプットしたつもりです。

とにかく、例を挙げてみた

ネタバレするといけないので伏せますが、構文とかは逐一身近な例を挙げて、なるべくイメージしやすいように、
また易しくなるように考えながら書きました。上手く伝われば幸いです。

目次

  • 第2章 開発環境の用意
    • 2.1 本書で必要な開発環境
    • 2.2 Firefoxをインストールしよう
    • 2.3 Adobe Dreamweaver CS5の環境設定をしよう
    • 2.4 サンプルプログラムをダウンロードしよう
  • 第4章 ページの背景色を変えてみよう
    • 4.1 サンプルプログラムを見てみよう
    • 4.2 HTMLの要素を操作してみよう
    • 4.3 変数を使ってみよう
    • 4.4 背景色をセットしよう
    • 4.5 関数について詳しく知っておこう
  • 第5章 時間によってページの背景画像を変えてみよう
    • 5.1 サンプルプログラムを見てみよう
    • 5.2 現在の時間を取得してみよう
    • 5.3 時間を判定しよう
    • 5.4 背景画像を切り替えよう
    • 5.5 背景画像を配列で管理しよう
  • 第6章 動きのあるテーブルを作ろう
    • 6.1 サンプルプログラムを見てみよう
    • 6.2 DOMを使ってターゲットとなる要素を取得しよう
    • 6.3 ループ文を使ってみよう
    • 6.4 マウスイベントで要素の背景色を変更しよう
    • 6.5 クリックされた行の中身を取得してみよう
    • 7.1 サンプルプログラムを見てみよう
    • 7.2 初期設定をしよう
    • 7.3 チェックボックスにイベントを設定しよう
    • 7.4 ボタンをアクティブにしよう
    • 7.5 確認メッセージを表示してみよう
    • 7.6 送信ボタン以外を押してフォームを送信してみよう
  • 第8章 タブで切り替えるメニューを作ろう
    • 8.1 サンプルプログラムを見てみよう
    • 8.2 タブとコンテンツの関連を考えよう
    • 8.3 要素の表示/非表示を切り替えよう
    • 8.4 クリックでタブとコンテンツを切り替えよう
    • 8.5 文字列の操作を詳しく知ろう
  • 第9章 外部からデータを取得してみよう
    • 9.1 サンプルプログラムを見てみよう
    • 9.2「Ajax」と呼ばれる技術
    • 9.3 ライブラリーを使おう
    • 9.4 Ajax通信でデータを取得しよう
    • 9.5 サーバーと連携して動的に生成された情報を読み出そう
    • 9.6 Google Maps APIを使って地図を表示しよう
  • 第10章 ライブラリーをもっと使ってみよう
    • 10.1 jQueryについて知ろう
    • 10.2 サンプルプログラムを見てみよう
    • 10.3 jQueryでページのロードを待とう
    • 10.4 CSSセレクタで要素を取得しよう
    • 10.5 jQueryのメソッドを使ってみよう
    • 10.6 jQuery UIを使ってみよう
  • 付録


本当に基本的な所だけに要点を絞って、少しずつ積み上げていく内容になっています。
なので、いきなり10章から読んでも多分あんまりわかりません><
また、ある程度JavaScriptをご存知の方だと得られるものはあまりないかもしれません。

まとめ

このような機会を与えて下さった技術評論社様に深くお礼を申し上げます。ありがとうございます。

また、後半体調を崩してしまって、共著のお二方に多大なるご迷惑をかけてしまったにも関わらず、
「頑張りましょう!」と言ってくださった安藤さん、岩田さんには足を向けて寝られません。
また、下で紹介している「PHP本」の著者の皆様、執筆中に色々と迷惑をかけてしまった社内の皆様等々、
たくさんの方に支えられて出来上がった書籍です。もう足を向ける方角がありません。


そんな見えないドラマが含まれた本書、手にとって頂けたなら嬉しいです。

PHP本もあります

同じく、安藤さんも執筆に参加されている「Webサイト製作者のためのPHP入門講座」も発売されてます。
表紙も色違いです。

Webサイト制作者のための PHP入門講座

Webサイト制作者のための PHP入門講座

こちらも合わせて手にとって頂ければ。


最後に

「オブジェクト」は「ロッカー」です。これ流行んないかなぁ・・・

CodeIgniter側でさくらインターネットのmod_rewriteの動きを自動で吸収する

さくらインターネットmod_rewriteが上手くいかないのは結構よくある話で、私も悩んだクチです。
自動とはいかないまでも、半自動でいいからアプリケーション側で吸収できたら幸せになれそうです。

そもそもの発端

「index.php/topとかついてるのはカッコ悪い。だからmod_rewriteで消すのだよ」

ということで設置するんですが、Seezooの短縮URL設定が上手くいかないんです。

ちなみに、解決策はすでに@kiyotchiさんがブログに書かれています。素晴らしい!


>> さくらインターネット(スタンダード)にSeezooCMSを入れる。


この通りに書いてももちろんOKですが、自身の勉強のためにもう一度、始めから。
ほとんど上記ブログからの情報です。この場を借りてお礼を。いつも助かってます。

本来ならばこういったことはサーバ設定時にやることかもしれませんが、
OSSという性質で見た場合、どんなサーバーでも動いたほうがいいよね、
アプリケーションで吸収しないといけないところもやっぱあるよね、
という非常に個人的な思いからです。

どうすればうまく設定できるのか?

ポイントは、

  • .htaccessの設定をちゃんとする。
  • PHPCGIモードで動いているかを判定する。
  • CodeIgniterのルーティングをPATH_INFOに基づいて行うようにする。

この3点です。.htaccessは、

引用:
RewriteEngine On
RewriteBase /
RewriteCond $1 !^(index\.php|sitemap.xml|sitemap_ssl.xml|css|js|captcha|uploads|templates|blocks|phpMyAdmin|.+\.gif$|.+\.jpg$|.+\.png$|.+\.js$|.+\.css$|.+\.json$|.+\.ico$|.+\.swf$|.+\.flv$)
RewriteRule ^(.*)$ index.php?__REQ__=$1 [L]


として、RewriteBaseは設定したほうがいいそうです。ふむふむ。
さすがに.htaccessをCIから変更するのは横着すぎるので、これは手動でサーバによって振り分けたほうがよさそうです。
これでリクエストパスが__REQ__というGETパラメータで渡されますね。

で、問題はPHP動作モードの判定と、ルーティングをPATH_INFOから行うことですが、

引用:
次に、/index.phpの冒頭に、次のPHPスクリプトを埋めます。
 

if( isset( $_GET['__REQ__'] ) ){
$_SERVER['PATH_INFO'] = $_GET['__REQ__'];
}

とすればOKみたいです。もちろんこれでOKですが、CIのバージョンアップに追従するため、index.phpは変更しない方法で実装してみたいと思います。
ポイントは、


CodeIgniterのルーティングが始まる前に、$config['uri_protocol']の値が変更されていれば良い

ということで、実際にRouter.phpをフックしてもいいのですが、CIの起動プロセスでは、先にURIクラスがロードされるので、こっちで正規化しておいた方が
確実だと思います。というわけで、URIクラスを拡張して、MY_URI.phpを作成します。以下が拡張したコードです。

system/application/MY_URI.php


class MY_URI extends CI_URI
{
var $_is_cgi = FALSE;

// コンストラクタでフックする
function SZ_URI()
{
parent::CI_URI();

// PHPの動作モードチェック
if ( strpos(PHP_SAPI, 'cgi') !== FALSE )
{
$this->_is_cgi = TRUE;

if (isset($_GET['__REQ__']))
{
// __REQ__というパラメータがあれば、PATH_INFOに格納する
$_SERVER['PATH_INFO'] = $_GET['__REQ__'];
// configの設定値変更
$this->config->set_item('uri_protocol', 'PATH_INFO');
}
}
}

// PHPCGIモードで動いているかを返すメンバ関数も追加
function is_cgi_mode()
{
return $this->_is_cgi;
}
}


Router.phpの内部ではURIクラスのプロパティを元にルーティングするので、コンストラクタの時点でパラメータをセットしておきます。
これでCIのコアクラスに影響を与えずに半自動でルーティングを成功させるようにしました。簡単ですね〜。

is_cgi_mode()メソッドは、アプリ中でCGIで動いているかを取得するのに追加しただけです。

この設定で実際にさくらのスタンダードで動かしたところ、見事index.phpが消えました!
@kiyotchiさん、ありがとうございます!

感想とか


最初は、gethostbyaddr($_SERVER['SERVER_ADDR'])でサーバー名を取得して、sakura.ne.jpを検索する、という
ものすごいハードコーディングをしてました。お恥ずかしい限りです。

PHP_SAPIっていう定義済み変数の存在を知るまでTwitterで小一時間ほど協議してました><全く知りませんでした・・・。
他にも、


ini_get('cgi.force_redirect')

の結果で判定するのも良さそうです。私は定数+strposの方が速かったので、そっちを使いました。
でも.htaceessはやっぱり各自で設定しないといけないので、半自動、という。


こんなちょっとした問題なのに、色々ご意見や手法を教えてくださった@kiyotchiさんを始め、
@bossatamaさん、@riatwさん、ありがとうございます!

2011/01/18追記

id:Kenji_sさんからコメント・トラバを頂きました。さくらインターネットmod_rewrite設定をそのままモジュールで使うのが楽ですね。また、CGIモードかどうかを判定するのはURIクラスではなくConfigクラスの方が適切だと私も思いました。ありがとうございます〜。

※SeezooもConfigクラスを拡張するように変更します^^;

CSSを即時にリロードするブックマークレット

Seezooと関係しないネタですが、ちょっと書いてみます。


CSSを書いているときに、


スタイル修正→リロード→スタイル確認→修正...

という感じに、毎回リロードするのが私はとても面倒臭いです。
特に重いページの場合はロードに時間がかかりますよね。
そこで、CSSファイルだけをリロードするブックマークレットを作りました。

自分が使って便利なものはきっと誰かにとっても便利なものだ

結構重宝しているので、きっと誰かも使ったら便利だと思ってもらえるかなぁ・・・
というわけで、以下がブックマークレットです。


javascript:(function(){var%20l=document.getElementsByTagName('link'),hr;for(var%20i=0;i


上記のコードをコピーして、新しいブックマークを作成、貼り付ければOKです。

後は、任意のページでブックマークレットを実行すれば、CSSがリロードされます。
開発時には、CSSファイルを編集、保存後に実行すれば反映されます。

注意というか仕様

linkタグで外部参照しているCSSファイルだけが対象です。styleタグやインラインスタイルは再読み込みしません。

よろしければ

お使いくださいー。

CodeIgniter1.7.3に合わせてSeezooもFIXしました

連日の記事となりますが、ご報告まで。

今日の朝来たら、CodeIgniter1.7.3がリリースされてました。
早速DL、Change Log — CodeIgniter 3.1.10 documentationを見てみると、

Version 1.7.3 is a security maintenance release, including a previously patched file Upload class, and a new security fix to prevent possible directory traversal in certain circumstances. There are no other significant changes.


ということらしいです。どうやらRouterのセキュリティFIXがあったようですね。
$config['enable_query_strings']がTRUEの時のディレクトリトラバーサル問題の解決らしいです。

というわけで、早速Diffをとって中身を見ると、



310c310< $this->class = str_replace(array('/', '.'), '', $class);

    • -

> $this->class = $class;
369c369< $this->directory = str_replace(array('/', '.'), '', $dir).'/';

    • -

> $this->directory = $dir.'/';


ふむふむ、Router::set_class()とRouter::set_directory()のコードが変わってるみたいですね。
これくらいならパパッと修正して〜…と思ってよく考えたらマズイことに気が付きました。

これだとディレクトリにパス(/)が含められない

早速Seezooに導入してみると、予想通り、3階層まで掘るルーティングができなくなってしまってます;;
Seezooはディレクトリを掘り進めて、その都度のディレクトリパスを「/」でつないでるので、2回目にset_directory()が
呼ばれると、それまであった「/」がstr_replace()によって消されてしまう、という状態でした。

解決策の模索

あ〜でもないこ〜でもないとうんうんうなりながら昼食していたら閃きました。


つまるところ、Directory Traversalの危険性のある文字を削除してる訳だよね


つまり、「/」と「.」が含まれるのがマズイ。でも階層を掘るなら「/」は付けないといけない。
ということなら、


格納する時点では付けず、最後にまとめてつければいいよね?


というわけで、ルーティング中はディレクトリデータ階層をstr_replace()した上で配列に格納、
最後にfetch_directroy()を呼び出す時にimplode()というやや強引な方法で解決しました。
具体的には、SZ_Router::fetch_directroy()をOverRideして処理変更。

コード

以下のように変更しました。

system/application/libraries/SZ_Router.php


var $directory = array() // override
var $directory_reg = array() // 拡張ルーティング用パス

.
.
.
// override CI_Router::set_directory
function set_directroy($dir)
{
// パスが含まれた最後のディレクトリ名を取得
$exp = explode('/', $dir);
$dir = str_replace(array('/', '.'), '', end($exp));

$this->directory[] = $dir;
}

.
.
.
// override CI_Router::fetch_directory
function fetch_directory()
{
$prefix = '';
if ($this->is_packaged_directory === TRUE) // 拡張ルーティング用
{
$prefix = '../../../' . SZ_EXT_DIR . 'controllers/';
}
return (count($this->directory) === 0)
? $prefix
: $prefix . (implode('/', $this->directory) . '/');
}

これで3階層+拡張パッケージからのルーティングを確認しました。
やや強引な方法だけど、Directory Traversalは怖いですからね><

感想

ルーティング部分の変更って意外とキツイ。
Seezooではquery_stringは使わないので影響はないだろうけど、コアのメソッドが変わってるのには影響を受けてしまいます。
でも拡張してOverrideで解決できるのもCodeIgniterの素晴らしいところですね。

1.7.3パッケージ導入後のSeezooは次のバージョンからです。
もし現行のSeezooをCI1.7.3にする場合は、上記のような修正をお願いします。



でもこれってコアでは「コントローラは2階層まで!」って事実上決められてしまったような気がします…