Home > PHP > CakePHP

CakePHP Archive

CakePHP勉強会を開催します[告知]

この記事の所要時間: 035

ちょいフライング気味の告知です;-)

12/7に都内でCakePHPの勉強会を行います。

これまでPHP勉強会、カンファレンスなどでyandoさんによる発表が行われていたのですが、今回はCakePHPに特化したイベントになります。

発表者には、yandoさんはもちろんの事、青い人ことakiyanさんにもお願いしています。(私もできれば何かネタを持って行くつもりです。)発表のネタをもとにディスカッションなどできればと考えています。

申込については近日中に行う予定ですので、またお知らせいたします。しばしお待ちを。events.php.gr.jpにて申込を開始しました。

CakePHP 1.2でPostgreSQLを使うとエラーが出る

この記事の所要時間: 212

あ,そうだ。PostgreSQL だともうなんだか色々エラーが出てるので諦めちゃいました……。

1.2を試してみました – まゆの日記

同じエラーかどうか分かりませんが、同じような現象があったので。

CakePHP1.2.0.5875 pre-betaでPostgreSQLに接続しようとすると以下のようなエラーが出ました。

Warning (2): pg_query() [function.pg-query]: Query failed: ERROR:  syntax error at end of input at character 20 [CORE\cake\libs\model\datasources\dbo\dbo_postgres.php, line 123]

原因は[app/config/database.php]に追加された「schema」パラメータです。このパラメータを使うとPostgreSQLにてschemaを指定できるのですが、デフォルトの設定では空文字になっており、それをそのままDBへ発行するのでSQLエラーとなります。

解決策としてはschemaパラメータにschemaを指定します。テーブル生成時等にschemaを指定しなければデフォルトで「public」になります。個別にschemaを指定している場合はそれを設定します。

[app/config/database.php]

class DATABASE_CONFIG {
	var $default = array(
		'driver' => 'postgres',
		'persistent' => false,
		'host' => 'localhost',
		'port' => '',
		'login' => '1x1',
		'password' => 'pass',
		'database' => 'inquiry',
//		'schema' => '',
		'schema' => 'public',   <--- schema
		'prefix' => '',
		'encoding' => ''
	);
}

なおschemaパラメータを指定しない場合もpublicが使われます(厳密に言うとDboPostgresで定義されている値が使われます。)つまりschemaパラメータを削除してしまう手もありますが、内部動作は変わる可能性があるので、database.phpで明確に指定しておいた方が無難でしょう。

CakePHP1.2をベースにしたオープンソースシステム-NoseRub

この記事の所要時間: 132

CakePHP1.2はまだpre-betaの状態ですが、既にこれをベースとしたオープンソースシステムが公開されています。

それがNoseRubです。

NoseRubはざっと見た感じ「マイクロブログ」に分類されるシステムです。様々なRSSフィードをアグリゲートできるようでTwitterというよりJaikuに近い印象を受けました。NoseRubの内容については上記サイトにこのシステムを利用したサービスが公開されている(ここなど)のでそちらを参考にして下さい。

 

ここで大事なのはこのシステムがCakePHP1.2ベースで作られているという事です。

1.2に関してはpre-betaという事もあり、箇所箇所の情報は見られるのですが、これを実際のシステムに組み込むノウハウがまだ共有されていない状態にあります。その中において実際にサービスとして動作するシステムがオープンソースで公開されているのはとても有り難いことです。

実際にダウンロードして中身を見てみました。ソースはわりと丁寧に書かれていて読みやすいです。やはり根本のフレームワークは理解しているので処理を追いやすいですね。まだ導入部分しか読んでいませんが、細かな実装のヒントが見つかり、これはかなり参考になりそうです。

ちなみに最新版であるNoseRub0.5.1はCakePHP1.2.0.5875 pre-betaベースとなっていました。

これから1.2で実装したい方は是非一度ダウンロードして参考にしてみて下さい。

# ホント、オススメです!

 

ちなみにCakePHPを使ったシステムやサービスなどは以下のサイトに公開されています。

Cake Apps/Sites In The Wild – Cake PHP | Google グループ

CakePHP 公開する時はデバッグ情報を出さない

この記事の所要時間: 351

CakePHPで作ったシステムを公開する時は、フレームワークが出力するデバッグ情報に気をつけましょう。

1. SQLログ

DEBUG定数の値を2以上に設定すると実行されたSQL文がログとして画面に表示されます。通常本稼働する際はDEBUGを0にしてこの出力は抑制するのですが、たまに本稼働でもSQL文がログが出力されているサイトがあります。

ちなみにSQLログに含まれるキーワードをGoogleで検索すると出力したままのサイトが見つかったりします。

“queries took” “Took (ms)” – Google 検索

対策

[app/config/core.php]にあるDEBUGを0にしておきます。公開サイトでSQL文を確認したい場合はCakePHP SQLをログに記録する方法などを使ってログファイルに出力するのが良いでしょう。

[app/config/core.php]

//	define('DEBUG', 2);
	define('DEBUG', 0);

2. PageControllerへのルーティング

デフォルトのURLルーティングでは[/]と[/pages/*]なURLはPageControllerのdisplayアクションにルーティングされるようになっています。displayアクションでは[/pages/]以降で指定された値をビューテンプレートとして出力します。([/]は/pages/homeとして処理されます)

[/]なURLは大抵アクセスを想定しているのでルーティングを変更すると思うのですが、[/pages/*]なURLは変更を忘れがちです。そのままだと[/pages/home]なURLを指定すると、フレームワークに含まれるhome.thtmlが出力されてしまいます。

http://example.com/pages/home

対策

[app/config/routes.php]にあるPageControllerへのルーティングを削除します。

[app/config/routes.php]

// [/]のURLルーティングを変更
//	$Route->connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
	$Route->connect('/', array('controller' => 'top', 'action' => 'index'));
(snip)
// [/pages/*]のURLルーティングを変更
//	$Route->connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));

3. 存在しないコントローラ、アクション

これもDEBUG定数の値によって出力されます。DEBUGの値が1以上の場合、存在しないコントローラやアクションがURLで指定されるとエラーメッセージが表示されてしまいます。

例えばそこで[/a/a]のように存在しないであろうコントローラやアクションを指定すると「Missing Controller」や「Missing Method」が表示されます。

対策

1.と同様にDEBUGの値を0にします。

対策-さらに

フレームワークは[/foo(/bar)?]なURLであればコントローラとアクション(/barがなければ/indexが存在するとみなす)を探そうとします。ですのでリバースプロキシなどで外部からCakePHPシステムへアクセスされるURLを限定してしまうのもアリです。

こうしておけば予期せぬURLからのアクセスを防ぐことができるので、URLルーティングにおける想定外の動作を防ぐことができます。(この手法は結構好きなので良く使用します。;-))

便利機能には注意を

CakePHPに限らず各種フレームワークには開発に有用なデバッグ情報出力などの機能が用意されています。これらの情報は開発には役立ちますが、一般に公開すると攻撃者へヒントを与えることにもなりますし、何より見た目が宜しくありません。

特にURLルーティングに関しては今時のフレームワークでは実装されている機能だと思います。外部に公開するシステムでは、あらかじめ想定外のURLが指定された場合、どのような動作をするかを確認しておきましょう。

CakePHPガイドブック登場

この記事の所要時間: 032

先日ご案内したCakePHP本がいよいよ登場します。タイトルは「CakePHPガイドブック」です。

ベタな名前ですが、あえて奇をてらわず、定番となる本になって欲しい!という執筆陣の思いが詰まっています。またカバーもシンプルなデザインになっているのでオフィスに置いて頂いても違和感無いかと思います。

10月末頃には書店に並ぶそうです。見かけたら一度手に取って頂ければ嬉しいです。

# 私自身も初めての書籍なのでとても楽しみです。;-)

出版元のマイコミさんのサイト [MYCOM BOOKS – CakePHPガイドブック]

CakePHP解説本を書きました

この記事の所要時間: 046

先日のPHPカンファレンス2007で安藤さんが発表されたとおりCakePHPの解説本が出版されます。

この本の執筆にcakephp.jp管理人である堂園さん、そしてPHP勉強会やカンファレンスでお馴染みの安藤さん、と共に参加させて頂きました。

原稿はほぼ書き終えた状況で、現在は10月出版を目指して諸々の作業を行っています。

これまでもCakePHPを扱った書籍はあったのですが、単独での解説本としては(世界?)初となります。基本的な使い方から実践的な内容までカバーしているので、CakePHPユーザはもちろんの事、フレームワークは初めてという方にもおすすめの一冊となっています。

現段階ではamazon等で予約はできませんが、正式な発売日など決まりましたら、またお知らせ致します。

お楽しみに!

via: CakePHP のおいしい食べ方: 間もなくCake本登場!!

CakePHP データベースを使わないアプリケーション

この記事の所要時間: 220

CakePHPはデータベースを使用することが前提となっているので、フレームワークがデータベースへの接続を自動的に行います。ただマッシュアップ系のサービスなどデータベースを全く使用しない場合はこの機能を無効にしたくなります。

そこでCakePHPアプリケーション全体でデータベースを使わない方法です。

ちなみにこの方法では[app/config/database.php]を作成する必要もありません。

1. モデルを使わない

コントローラの$usesにnull or array()を設定することによりモデルを使用しないようにできます。データベースへの接続はモデルを介して行うのでモデルを使わなければ接続処理は行われません。(セッションやキャッシュをDBに保存する場合は別ですが)

<?php
class HogeController extends AppController {
  var $uses = null;
}
?>

ただこの方法だと当然ながらモデルは使用できませんし、各コントローラに$uses=nullを設定する必要があります。

2. AppModelに$useTableを設定する

モデルの$useTableにfalseを設定することにより、そのモデルではデータベースを使用しないようにできます。これを利用して基底クラスAppModelの$useTableにfalseを設定します。

[app/app_model.php]

<?php
class AppModel extends Model {
  var $useTable = false;
}
?>

この方法ならAppModelに設定するだけで、全てのモデルでデータベースを使用しなくなります。1.よりも手間がかからないのでオススメです。

フレームワークのビューテンプレートに注意

いずれの方法を取った場合でもデフォルトのルーティングのままで[http://example.com/]にアクセスするとデータベースに接続できないといったエラーメッセージが表示されます。

これは出力されるビューテンプレート[cake/libs/view/templates/pages/home.thtml]にてデータベース接続を行っているためです。このビューテンプレートはアプリケーション稼働時に出力することは通常無いので無視して構いません。

なおこのビューテンプレートへのルーティングをコメントアウトしてしまえば表示されなくなります。

[app/config/routes.php]

<?php
// コメントアウト
//	$Route->connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
?>

DATABASE_CONFIGを空にする方法はNG

“データベースをまったく使わない設定” フォーラム – CakePHP Users in JapanにDATABASE_CONFIGクラスを空にする方法が紹介されていますが、1.1.16.5421ではObject#cakeError()が呼ばれてしまうのでこの方法は使えません。ご注意を。

PHPベンチマーク CakePHPでモデルを使用しない

この記事の所要時間: 135

via: PHPベンチマーク: Zend Framework vs Symfony vs CakePHP vs CodeIgniter vs PHP on TRAX – 徒然なるままにBlog

エントリでPHPフレームワークのベンチが比較されており、とても興味深いものです。

ベンチ対象のソースが公開されているので、ざっと見てみると気になるところが一点ありました。

各フレームワークで行った処理はコントローラを呼び出しビューに遷移させて
“Hello World!”を表示させるだけのかなりシンプルな内容です。
DBへの接続やモデルの作成は行わず、自動レイアウト機能があるものはオフにするか全て削除しています。

PHPベンチマーク: Zend Framework vs Symfony vs CakePHP vs CodeIgniter vs PHP on TRAX – 徒然なるままにBlog

モデル作成を行わないはずなのにCakePHPだけモデルが生成されるようになっていました。

そこでモデル生成あり・なしでどの程度差が出るかを計ってみます。計測方法は[ab -c 100 -n 100]を10セットしてその平均を出しています。

モデル生成ありのソースは元エントリのまま。モデル生成なしは元エントリのhello_controller.phpを下のように変更しています。

<?php
class HelloNoModelController extends AppController{
  var $layout=null;
  var $autoLayout=false;
  var $uses = array(); // モデルを使用しない

  function hello()
  {
  }
}
?>

結果は以下のとおり。

モデル生成あり 5.145 Request/sec
モデル生成なし 6.381 Request/sec

実行環境が元エントリとは異なるので絶対的な数値にはあまり意味が無いですが、両者を比べるとモデル生成なしの方が20%ほど速いようです。

できれば元エントリの環境でモデル生成なし版によるベンチが見てみたいところです;-)。

CakePHP 1.1.15.5144以降はHtmlHelper#tagValueに注意

この記事の所要時間: 13

確認画面等で入力値を表示するのにHtmlHelper#tagValueを使っています。

これは内部でHTMLタグをエスケープしてくれるので重宝していたのですが、1.1.15.5144から、このメソッドにエスケープするか否かを表すフラグが追加されました。

[cake/libs/view/helpers/html.php]

<?php

   function tagValue($fieldName, $escape = false) {

?>

困った事にデフォルトではfalseになっているので、従来の[$html->tagValue(‘Foo/bar’);]のような使い方をしているとHTMLタグがそのまま出力されてしまいます。1.1.15.5144以降(昨日リリースされた1.1.16.5421も含む)でHTMLタグをエスケープするには以下のように第2引数にtrueを指定しなければなりません。

// tagValueでHTMLタグをエスケープ
<?php echo $html->tagValue('Foo/bar', true);
// もしくはh()で囲む
<?php echo h($html->tagValue('Foo/bar')) ?>;

1.1.14.4797以前から1.1.15.5144以降へバージョンアップする際はくれぐれもご用心を。

ちなみに1.2.0.5147ではtagValueがdeprecatedになっており、代わりにvalueメソッドを使うようになるようです。

CakePHP 比較演算子インジェクションに注意

この記事の所要時間: 239

@deprecated

この情報はCakePHP1.2betaまでのものです。1.2RC1についてはこの方法は有効ではありません。詳しくはCakePHP 1.2RC1からは比較演算子をキーに書くをどうぞ。

CakePHPのモデルで検索条件を指定する場合は比較演算子に注意が必要です。

検索条件では↓な感じで条件値の他にSQLの比較演算子を入れることができます。

<?php
class UserController extends AppController {
  funtion index($id) {
     $id = is_numeric($id) ? $id : 0;
     // $id より大きなidを持つレコードを取得
     $list = $this->findAll(array('id' => '> ' . $id)); 
     $this->set('list', $list);
  }
}
?>

これを見ただけで分かる人はピンと来ますね。そう外部から送られてきた値に比較演算子が含まれていてもそれがそのままSQL文として動作してしまうわけです。

これがマズそうな場面は色々あるでしょうけど、決定的なのがログイン画面です。例としてメールアドレスとパスワードで認証するアクションを見てみます。

<?php
    function login() {
      if (!empty($this->data['User'])) {
        $conds = array();
        $conds['email'] = $this->data['User']['email'];
        $conds['password'] = $this->data['User']['password'];
        $user = $this->User->find($conds);
        if (!empty($user)) {
          // ログイン成功
        }
      }
    }
?>

まあありがちな処理だと思いますが、このアクションに[email=!=hoge@example.com&password=!=a]をPOSTすると↓のようなSQL文が発行されてしまいます。(WHERE句以降)

WHERE "email" != 'hoge@example.com' AND "password" != 'a' LIMIT 1

これだとusers.emailにhoge@expample.com、users.passwordにaのどちらもが存在しなければログインする事が可能となります。つまりユーザ情報に登録されていなさそうな値を使えば誰でもログインが可能となります。

他にも登録されているメールアドレスを入力して、パスワードだけ[!=]を使うという手もあります。これならユーザのメールアドレスさえ分かればどのユーザとしてもログインできてしまいます。

この問題の対策は2つ+1つあります。

1. findBy/findAllByを使う

findBy/findAllByを使うとこの現象は発生しません。先程のloginアクションを書き換えてみます。

<?php
//        $user = $this->User->find($conds);
      $user = $this->User->findByEmailAndPassword($conds['email']
                                                          , $conds['password']);

これなら入力された比較演算子も文字列として処理されます。

WHERE "User"."email" = '!=hoge@example.com' AND "User"."password" = '!=a' LIMIT 1

2. 入力値の前に’= ‘を付ける

findやfindAllで条件を連想配列で渡したい場合は各値の前に’= ‘を付けます。実はfindBy/findAllByでは内部的にこの処理を行ってます。つまりそれを自分でやってしまうというわけです。

ここでのポイントは’=’の後ろにスペースを入れるという事です。これが無いと一部の演算子が有効となってしまいます。

<?php
        $conds = array();
        $conds&#91;'email'&#93; = '= ' . $this->data['User']['email'];
        $conds['password'] = '= ' . $this->data['User']['password'];
        $user = $this->User->find($conds);
?>

3. 入力値を厳密にチェックする

これももちろん大事です。検索に使用する値が数値のみや日付形式といった制限がある場合はそちらのチェックでこの問題を防ぐことができます。

ただ、実は比較演算子の他に[like/ilike/in/or/not/in/between/regexp/similar to]といったキーワードも同様の問題をはらんでいます。これらは文字列の中では通常の単語として出てくる可能性もある(「Like a child」とか)ので判別が難しいです。

ちなみにこの問題が発生するのは比較演算子・キーワードが文字列の先頭になっている場合のみです。それ以外の箇所にある場合は問題ありません。

find/findAllで検索条件に連想配列を使う場合は注意を

これは忘れるとインパクトがあるのでfind/findByfindBy/findAllByで検索する場合はくれぐれもご注意を。

@see: CakePHPの何か「CakePHPのModelを使う」

ホーム > PHP > CakePHP

検索
フィード
メタ情報

Return to page top