[CodeIgniter2.x]Cacheクラスを継承するには(+2.0.2)


XSSフィルタ部分に脆弱性が見つかり、CodeIgniter 2.0.2がリリースされました。ただ、CSRF関連のバグが新たに発生しているようです。アップグレードについては十分注意してください。

2.0.1と2.0.2のdiffを見てみたところ、

  • Security.phpがcoreに移動
  • doctypes.php、smileys.php、foreign_chars.php、user_agents.php、mimes.php、routes.php、hooks.php、constants.phpが環境切り分けに対応
  • ENVIRONMENT定数の存在チェック追加
  • Cacheまわりのクラス名にCI_プレフィックスが付与

と言った感じでした。

Cacheまわりのクラス名にCI_プレフィックスが付与という事だったので、ついに継承を考慮されたのかと思い、前回、[CodeIgniter2.x]Cacheクラスを継承するにはで書いた、Cacheクラスの継承ですが、2.0.2を利用する場合、継承方法がどのように変わったのか試しています。

広告

前回のソースをベースに話をしていきたいと思います。

CI_プレフィックスの付与

まず、Cache.php、Cache/drivers/以下のクラスにCI_プレフィックスが追加されているのでMY_Cacheにも追加します。

application/libraries/Cache/MY_Cache.php

< ?php
- class MY_Cache extends Cache {
+ class MY_Cache extends CI_Cache {

application/libraries/MY_Cache/drivers/MY_Cache_memcached.php

< ?php
require_once BASEPATH.'libraries/Cache/drivers/Cache_memcached.php';
- class MY_Cache_memcached extends Cache_memcached {
+ class MY_Cache_memcached extends CI_Cache_memcached {

この状態で動かすと下記のようなエラーになります。また、その際のログです。

An Error Was Encountered
Unable to load the requested driver: MY_Cache_memcached
INFO  - 2011-04-08 10:47:41 --> load driver=application/libraries/my_cache/drivers/My_cache_memcached.php
INFO  - 2011-04-08 10:47:41 --> load driver=application/libraries/my_cache/drivers/my_cache_memcached.php
INFO  - 2011-04-08 10:47:41 --> load driver=/home/tatsuya/Dropbox/www/ci202_cache/system/libraries/my_cache/drivers/My_cache_memcached.php
INFO  - 2011-04-08 10:47:41 --> load driver=/home/tatsuya/Dropbox/www/ci202_cache/system/libraries/my_cache/drivers/my_cache_memcached.php
ERROR - 2011-04-08 10:47:41 --> Unable to load the requested driver: MY_Cache_memcached

以前と読み込み場所が変わっていますね。前回までの構造は、

./
|-- Cache
|   `-- MY_Cache.php
|-- MY_Cache
|   `-- drivers
|       |-- MY_Cache_apc.php
|       |-- MY_Cache_dummy.php
|       |-- MY_Cache_file.php
|       `-- MY_Cache_memcached.php
`-- index.html

となっていましたので、読み込み場所の指定方法が変わったようです。

Driver.phpのCI_対応

system/libraries/Driver.php

2.0.1の頃と比べると$lib_nameや$child_classがstrtolowerされているので、上記のように小文字のディレクトリを読み込み対象とするようになりました。

--- CodeIgniter_2.0.1/system/libraries/Driver.php       2011-03-16 02:54:00.000000000 +0800
+++ CodeIgniter_2.0.2/system/libraries/Driver.php       2011-04-07 12:20:00.000000000 +0800
@@ -44,7 +44,11 @@
                // The class will be prefixed with the parent lib
                $child_class = $this->lib_name.'_'.$child;
 
-               if (in_array(strtolower($child_class), array_map('strtolower', $this->valid_drivers)))
+               // Remove the CI_ prefix and lowercase
+               $lib_name = strtolower(preg_replace('/^CI_/', '', $this->lib_name));
+               $driver_name = strtolower(preg_replace('/^CI_/', '', $child_class));
+
+               if (in_array($driver_name, array_map('strtolower', $this->valid_drivers)))
                {
                        // check and see if the driver is in a separate file
                        if ( ! class_exists($child_class))
@@ -52,19 +56,15 @@
                                // check application path first
                                foreach (array(APPPATH, BASEPATH) as $path)
                                {
-                                       // and check for case sensitivity of both the parent and child libs
-                                       foreach (array(ucfirst($this->lib_name), strtolower($this->lib_name)) as $lib)
+                                       // loves me some nesting!
+                                       foreach (array(ucfirst($driver_name), $driver_name) as $class)
                                        {
-                                               // loves me some nesting!
-                                               foreach (array(ucfirst($child_class), strtolower($child_class)) as $class)
-                                               {
-                                                       $filepath = $path.'libraries/'.$this->lib_name.'/drivers/'.$child_class.EXT;
+                                               $filepath = $path.'libraries/'.$lib_name.'/drivers/'.$class.EXT;
 
-                                                       if (file_exists($filepath))
-                                                       {
-                                                               include_once $filepath;
-                                                               break;
-                                                       }
+                                               if (file_exists($filepath))
+                                               {
+                                                       include_once $filepath;
+                                                       break;
                                                }
                                        }
                                }

ディレクトリ、ファイル名を2.0.2に対応

今までの説明を踏まえて、下記のようなディレクトリに変更してみます。

./
|-- Cache
|   `-- MY_Cache.php
|-- my_cache
|   `-- drivers
|       |-- My_cache_apc.php
|       |-- My_cache_dummy.php
|       |-- My_cache_file.php
|       `-- My_cache_memcached.php
`-- index.html

これで、再度アクセスしてみると無事動くようになりました。

最後に

CI_プレフィックスが付与されていたので、継承を考慮されているのかと思ったのですが、残念ながらまだ中途半端な状態でした。まだまだ、この辺は変更されそうな感じがしますので、継承する場合は激しく自己責任でお願いします。

追記:2011.04.09 18:21
ellislab / CodeIgniter Reactor / issues / #193 – CI_Cache_file — Bitbucket
既に本家に登録されていて対応もされているようですが、上記のDriver.php内の$lib_name変数がstrtolowerされているので、小文字化されてしまっており、読み込み対象のディレクトリも2.0.1のucfirstではなくなっており、正常に読み込めないバグが今回新たに発生しています。対処法としては、下記のように$lib_nameにucfirst実行後の値を代入すれば大丈夫です。

$lib_name = ucfirst(strtolower(preg_replace('/^CI_/', '', $this->lib_name)));

関連記事