自分のための次世代CMS製作メモ

Jeans & Development 電子ブロック工房 三日坊主 フロントページ

coreを基底クラスに? [General]

2008年2月17日

coreクラスは、config.phpをインクルードしたときに一番初めに定義されるクラスだ。今、このcoreクラスをすべてのクラスの基底クラスにするかどうかで悩んでいる。

例えば、プラグインで文字出力を行う場合、現在の仕様では

core::p($text);
core:echohtml('<p>id: <%1%></p>',$id);

のように記述するが、coreクラスを基底クラスとしてプラグインクラスを作成すると、

$this->p($text);
$this->echohtml('<p>id: <%1%></p>',$id);

のように記述してもよいし、

self::p($text);

のように記述することもできる。PHP5ではメソッドのオーバーライドができないように設定できるから、プラグインでpメソッドやechohtmlメソッドを書き換えて変なことをするのも禁止できる。

pluginoptionクラス [General]

2008年2月9日

プラグインオプションの値は、plugionoptionクラスのオブジェクトに保持させることにした。

pluginクラス内にて、

$this->option=new pluginoption($this->id);

もしくは、

public function blogoption($bid){
    $obj=new pluginoption($this->id,'blog',$bid);
    return $obj;
}

のように使う。

プラグイン周りの仕様 [General]

2008年2月9日

現在のところ、コアではほとんどのコードでクラスのスタティックメソッドを利用するため、あまりオブジェクト指向とはいえないコードになっている。

一方で、プラグインの部分は、オブジェクト経由でアクセスする予定。理由は、次のとおり。

Nucleusと同じく、プラグインはすべてpluginクラスを継承したクラスとして記述することになる。プラグインのクラスをスタティックなメソッドの集合体として扱った場合、複数のプラグインのクラスが単一のpluginクラスを継承しているため、親クラスであるpluginクラスのそれぞれのメソッドで、各プラグインに固有の値(プラグインオプションなど)を処理できないのである。

一方で、Nucleusがやっているようにすべてオブジェクト経由で扱った場合、pluginクラスのメソッドでは$thisオブジェクトを経由することでこれを行うことができる(他方、コアの各クラスは、複数のインスタンスを持たせる必要が無いため、スタティックなメソッドやプロパティを扱うやり方で、今のところコードに混乱は無い)。

プラグインの仕様については、Nucleusのプラグインとほぼ同一のものを提供する予定である。が、もともとこのプロジェクトをはじめた動機のひとつとして、プラグインを書くときに楽をしたいというのもあるので、そうなるような仕様の変更を考えている。

現在のところ、どんなことで楽ができるかというと、

1)sql_table() 関数を使う必要が無い。
2)global $manager, $CONF, $DIR_LIBS; といった記述が不要。
3)echo htmlspecialchars($text,ENT_QUOTE,_CHARSET); の代わりに core::p($text); で良い。
4)3と同様だが、クエリーでaddslashes()やmysql_escape_string()なども使う必要が無い。

など。

セキュリティー対策、あれこれ [Security]

2008年2月3日

先の記事もそうであるが、セキュリティー対策のためのコードをいくつか追加したので、改めてメモ。

1)SQLインジェクション対策
 sql::query()メソッドで、簡易プリペアードステートメントを使う。MySQL5やPostgreSQLほど本格的なプリペアードステートメントではないが、この方法でほぼ100%、SQLインジェクションは防げる。SQLステートメントでフィールド部分を入力値にしたがって変更したい場合は、core::fill()メソッドを用いて正規表現でホワイトリスト形式で入力値をチェックしながら値を挿入する。

2)XSS対策
 core::echohtml()メソッドで、プリペアードステートメント様の機能が使える。正規表現で入力値をチェックすることも可能。

3)リモートスクリプトインクルード対策
 クラス名を適切に選んでおけば、PHPファイルのインクルードはコアが自動的に行ってくれる。include, require などのステートメントを使うことはほとんどないはず。

4)ディレクトリトラバーサル対策
 file_exists()の代わりに、core::checkFile()メソッドを使用する(下のコードを参照)。

5)ヌルバイト攻撃対策
 リクエストにヌルバイトがあると、コア呼び出し時に自動的に停止する(先の記事のコードを参照)。

リクエストに関する規約 [Regulations]

2008年2月3日

$_GET, $_POST, $_COOKIE 使用時の規約を定めることにした。こうすることで、少ないリソース量で有効なセキュリティ対策が行える。

1)キー名が『binary』で終わる場合以外は、ヌルバイトは使用禁止。
2)キー名が『id』で終わる場合は、数値のみを利用。
3)キー名が『path』で終わる場合、URLもしくはファイルなどのパスを指定できる。ただし、日本語使用不可。
4)キー名が『text』で終わる場合、ヌルバイト以外なら何でも使用可。
5)上のどれにも当てはまらない場合、英数字、ピリオド、ハイフン、アンダースコア、スラッシュおよび日本語のみが使用可能。
6)URIに『#』および2つ以上の『?』を含むものを禁止。

(080208 改定)
キー名が『binary』で終わる場合に、ヌルバイトを受け付けるようにした。また、6)の条件を追加した。

sqlite_popen(`:memory:`) [General]

2008年1月28日

『sqlite_popen(':memory:')』を使うと、メモリ上にテーブルを構築できるらしい。

<html><body><?php

$db=sqlite_popen(':memory:');
@sqlite_query($db,'CREATE TABLE test(id INTEGER NOT NULL PRIMARY KEY, test TEXT)');
for($i=0;$i<3;$i++) sqlite_query($db,"INSERT INTO test(test) VALUES('".md5(rand())."')");
echo count(sqlite_array_query($db,'SELECT * FROM test'));
//sqlite_close($db);

?></body></html>

ひょっとしたら、何かのキャッシュに使えるかも?忘れないように、ここにメモ。

ただし、レンタルサーバなどでのセキュリティー上の問題が発生する可能性あり。要チェック。

権限管理 [General]

2008年1月25日

スキン変数を実装していく段階で、ブログチームの管理部分に行き着いたのであるが、一からCMSを書くのであれば、さまざまな権限を別個に設定できるようにしたい。

今のところ、jeans_loginテーブルにstatusとフィールドを設けていて、ここで各メンバーのステータスを決定することにしている。どんなステータスがあるかは、

SELECT status FROM jeans_login GROUP BY status

で取得できるはず。現在のところは『admin』ステータスだけであるが、『blogadmin』『poweruser』など、さまざまなステータスをここに設定できる。いろいろ考えた結果、権限管理にはもう一つテーブルを作るだけでよさそう。

NucleusにあってJeansに無い機能 [General]

2008年1月24日

あるいは、動作が変更される機能。

適宜、更新。

あるアイテムと前後のものを同時に取得 その2 [General]

2008年1月19日

4つの方法を用い、スピードを比較した。ここで用いているデータは、およそ250個のアイテムがすでに挿入されている、Nucleus-SQLiteのnucleus_itemテーブルを用いた。

方法1:すべてのアイテムのid,title,timeを一旦メモリに取り込んでおいて、その後に処理。

方法2:方法1と同じだが、sqlite_array_query を使用。

方法3:先の記事で一番最後に述べた方法。

方法4:クエリーを3回実行。一回目であるアイテム、2回目で前を、3回目で後を取得。

結果(それぞれの方法にかかった秒数で表示)
Method1: 0.018667936325073
Method2: 0.015633106231689
Method3: 0.0060269832611084
Method4: 0.00052618980407715


結局は、もっとも単純だと思われる4の方法が一番早かった。SQLのクエリーを複雑に記述する『技』におぼれる弊害が現れているということか。

あるアイテムと前後のものを同時に取得 [General]

2008年1月16日

表題のためのクエリ:

SELECT  i.inumber as thisid, j.inumber as previd, k.inumber as nextid 
FROM nucleus_item as i,nucleus_item as j,nucleus_item as k 
WHERE i.inumber=10 AND j.itime<=i.itime AND i.itime<=k.itime 
AND NOT (i.inumber=j.inumber OR i.inumber=k.inumber) 
ORDER BY TIMEDIFF(j.itime,k.itime) DESC LIMIT 1
クエリー実行 0.0021 秒

ただし、最新の記事もしくは最古の記事でこれを行うと、失敗する。
<<前の記事   後の記事>>