2007年8月アーカイブ
盛り上がってるところ*1に水を差すようですが、
気になって仕事が手につきません。
さっき前の席の人に「なんでニヤニヤ*2してるんですか?」って聞かれました。
そろそろお昼なのに、食事も喉を通らないかもしれないので、
書いてしまいます。
はてダで Javascript を実行するという件について。
先日、自分のはてなダイアリーにブログパーツを設置できるようになったので、事実上の JavaScript 解禁になりました。
ということで、JavaScript の eval を貼り付けるガジェットを Google Gadgets で作ってみました。
てっく煮ブログ - はてなダイアリーで JavaScript eval
やりたくなる気持ちはわかります。
僕も id:amachang さん(面識も本題に関係もないのに名前出してすいません)とかのスクリプトとか、その場で実行したいです。
でも、外部から来た変数に eval したらいかんと思うのですよ。
↓例えばこんなことできちゃう
いきなりこんな画面でボタン押す方がおかしいですが、
このガジェットを使用することで
「任意の人が自分の手を汚さずに(リンクを張るだけで)任意のコードを
実行させることができる」
んじゃないかと思います。
自動実行とかもやろうと思えばきっとできちゃうわけですからね。
代案があまり思いつかないですが、
- 任意の人が
- リンクを張るだけで
の部分を何とか出来そうな気がします。
トークンとセットじゃないと eval しないとか。
個人的には、外部から来た変数への eval は御法度だと思ってるんですが、
実際のところはどうなんでしょうね。
*1:はてブ http://b.hatena.ne.jp/entry/http%3A//d.hatena.ne.jp/nitoyon/20070820/javascript_eval_on_hatena_diary
*2:ニヤニヤしてたのは、やらしいことを考えていたからです
CakePHP をいきなり実践投入して2ヶ月程たった。
最近は Web アプリ作る時に当たり前のように Ajax 使うし、
それを当たり前のように要求される。
(要求されるのはほとんどがアニメーションとかの部分であって、特に ajax ではないけど。)
で、それを当たり前のようにこなすに当たり、CakePHP は便利なんだけど、
何が便利かっていうと、 決して php から Ajax コードを記述する、
Ajax helper があるからではない。
せっかくだから Ajax helper を何度か使おうとしたけど、
結局全く使わなかった。(使えなかった)
php から javascript を記述しようとすると、痒いところが多すぎる。
じゃあ CakePHP は何が便利かっていうと、
controller 内 の action で、
$this->layout = '';
こうするだけで、簡単に layout なしの HTML パーツを生成できるから便利。
それを javascritp で受け取って表示するコードなんて、すぐ書ける。
- HTML の生成は PHP が行う
- javascript はそれを受け取って表示する
- それ以外のアニメーションを含む HTML の加工は javascript が行う
それって当たり前のことなんだけど、改めてそう決めておけばメンテナンス性が落ちることもない。ハズ。
下手に Ajax helperを使ってしまうと、
どうしてもある部分では PHPで、ある部分は javascript に書かれてて、
しかもその境界があいまいになっちゃったりする。
関係ないけど javascript HTML テンプレートとか使い出したらいよいよ危ない。
html helper もいろいろあるけど、
html タグを書きたくない病の人向けすぎる。 form 関連だけで十分。
div タグとか img タグとか、そんなもん手で書けばよいと思う。
最近のデザイナーさんは smarty 混じりの html くらいなら普通に手を入れてくれるし。
僕のまわりのデザイナーさんが優秀なだけかもしれんけど。
それが smarty じゃなくて php コードだったらまた話は違ってくると思う。
確かめたわけじゃないけど。
なんでかっていうと、 「<?」これとか「?>」これとかが ぱっと見で html タグと区別しづらいから。
僕自身、PHP 混じり HTML 文見るとイラっとするし。
だから、PHP プログラマはできるだけ HTML 書きたくない病にかかったりするんだと思ってる。
※僕の cake は 1.2.0.5146
CakePHP で /app/tests/cases/ 以下に testCase を作成すると、
App Test Cases でテストの一覧を表示してくれる。
勝手に表示してくれるのはありがたいが、
でもどうせだったら全部まとめて実行したい。
勝手に表示してくれるくらいだから、
全部まとめて取得するメソッドあるんだろうと思ったら、やっぱりあった。
こんな group test を作ると、App Test Groups のところに表示されて、
testCase 全部まとめて実行してくれる。重いけど。
/app/tests/groups/app_all.group.php
class AppAllGroupTest extends GroupTest {
var $label = 'run all app test';function AppAllGroupTest() {
TestManager::addTestCasesFromDirectory($this, APP_TEST_CASES . DS );
}
}
前エントリで書いた、任意の url で任意の controller, action を実行する方法で、
例外が一つある。
url と controller, action のマッピングメモ
それは、既に存在するディレクトリ名を含むマッピングができないという点である。
例えば、既に /blog ディレクトリが存在する場合、
いくら routes.php にこう書いても、 /blog/ へのアクセスで
BlogController は実行されない。
Router::connect ('/blog/:action/*', array('controller'=>'Blog', 'action'=>'index'));
これは、ドキュメントルート直下の .htaccess で以下のように記述されているためである。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>
リクエストに該当するファイルやディレクトリが無い場合に限り、
index.php に Rewrite されるのだ。
/blog が既に存在する場合、 Rewrite はされない。
でもどうしてもどうしても /blog で BlogController を実行したい場合は、
/blog/index.php に、以下内容を記述すればよい。
<?php $_GET['url'] = '/blog/';// ドキュメントルート直下の index.php をインクルードする
require('/../index.php');
?>
因みにこのことは .htaccess の↓の行をコメントアウトしたら
実現しそうな気もするが、それは罠である。ムリ。
RewriteCond %{REQUEST_FILENAME} !-d
さらに言えば、静的 html も view ディレクトリ下に配置して、
Cakephp から(例えば pagesController)から呼び出すという方法もあるが、
全ファイルが php になってしまうので、時と場合を選ぶ。
Session を保持しつづけなければならないようなサイトでは、
その方法がよさそうだと思った。
※CakePHP1.2 の話です。
CakePHP で既存の controller, action を任意の url で実行するには
/app/config/routes.php にマッピングを記述すればよい。
例えば、マニュアルには /blog/history/05/june という url で
BlogController の history アクションに 05, june というパラメータを
渡す方法を書いてある。
次の例では、/blog のすべてのURLを、 BlogController に接続します。デフォルトのアクションは、 BlogController::index() になります。
例 4.3. Route の例
connect ('/blog/:action/*', array('controller'=>'Blog', 'action'=>'index'));
Routes の設定
でも実はこれ、特に設定しなくても普通に実行される。
何も設定しなくても、ディレクトリの第一階層は controller として扱われるし、
第二階層は action として扱われる。
そして、それ以下はパラメータになる。
マニュアルで言わんとしてるのは、これが任意の url で可能であるってことだ。
例えば、 /archive/05/june/ という url で上記と同じ action を実行するには、
以下のように記述するとよい。
Router::connect('/archive/*', array('controller' => 'blog', 'action' => 'history'));
また、 /blog ではなく、 /cms 以下全ての url を BlogController に接続するには、以下のようにする。
Router::connect('/cms/:action/*', array('controller' => 'blog', 'action' => 'index'));
ここまでがマニュアルに書いてあることだ。
試してみた限りでは、さらに /archives/something/category/ という url で、
BlogController の category アクションに、 "something" というパラメータを渡すことが可能だ。
こうする。
Router::connect('/archives/:pass/:action/*', array('controller' => 'blog'));
ただし、/archives/something/category/hoge/ としても、 hoge はパラメータとして渡されない。
ぽい。
メモ。