ウノウラボ Unoh Labs: ウェブアプリ開発を助けるGETコマンドを使ってハックしてみよう!!
さてウェブアプリケーションの開発をしていると当然ですがブラウザーで画面の確認をしたりしますが,ブラウザーで確認をしているとキャッシュに悩んだり面倒くさいことが少なくありません.普通そういう時はtelnetなどで直接HTTPプロトコルでウェブサーバーと会話するわけですが面倒くさいですよね.
jokagiは何年か前に偶然見つけたGETというコマンド(HEADもよく使う)を使用していますので,このコマンドの紹介と超簡単なハックをひとつ紹介したいと思います.
GETコマンドはしらなんだー。
でも個人的にcurlを使うことが多いのでこの機会にまとめながらメモ
■インストール
FreeBSDなら
/usr/ports/ftp/curl
あたりから
■ヘルプ
$ curl --help
いっぱーい。
自分がよく使うものは
ここらへんにまとめ。
■普通にGET
$ curl '-#' 'http://www.yahoo.co.jp/' | head
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-jp">
<!--京-->
<title>Yahoo! JAPAN</title>
<meta name="description" content="日本最大級のポータルサイト。検索、オークション、ニュース、メール、コミュニティ、ショッピング、など80以上のサービスを展開。あなたの生活をより豊かにする「ライフ・エンジン」を目指していきます。">
<style type="text/css" media="all">
<!--
.spacer { line-height: 110%; }
.spacer1 {line-height: 115%; }
'-#' は変な進捗状況を表示したくないのでプログレスバーにしているだけ・・。
あれって消せないのかなぁ。
■APIをGETで叩く
$ curl '-#' 'http://api.photozou.jp/rest/photo_list_public?type=album&user_id=98953&album_id=224030' | head
<?xml version="1.0" encoding="UTF-8" ?>
<rsp stat="ok">
<info>
<photo>
<photo_id>2298762</photo_id>
<user_id>98953</user_id>
<album_id>224030</album_id>
<type>jpg</type>
<width>450</width>
<height>337</height>
######################################################################## 100.0%%
RESTなAPIならそのまま叩くだけ。
■レスポンスヘッダを見てみる
$ curl -I 'http://api.photozou.jp/rest/photo_list_public?type=album&user_id=98953&album_id=224030'
HTTP/1.1 200 OK
Date: Thu, 15 Feb 2007 16:20:59 GMT
Server: Apache
X-Powered-By: PHP/4.3.11
Content-Type: text/xml; charset=UTF-8
フォト蔵さんはPHP4なのだすなー。
■やり取りを詳しく!
$ curl '-#' -v 'http://api.photozou.jp/rest/photo_list_public?type=album&user_id=98953&album_id=224030' | head
* About to connect() to api.photozou.jp port 80 (#0)
* Trying 124.32.224.107... connected
* Connected to api.photozou.jp (124.32.224.107) port 80 (#0)
> GET /rest/photo_list_public?type=album&user_id=98953&album_id=224030 HTTP/1.1
> User-Agent: curl/7.16.0 (i386-portbld-freebsd6.0) libcurl/7.16.0 OpenSSL/0.9.7e zlib/1.2.2
> Host: api.photozou.jp
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 15 Feb 2007 16:56:09 GMT
< Server: Apache
< X-Powered-By: PHP/4.3.11
< Content-Type: text/xml; charset=UTF-8
< Transfer-Encoding: chunked
{ [data not shown]
<?xml version="1.0" encoding="UTF-8" ?>
<rsp stat="ok">
<info>
<photo>
<photo_id>2298762</photo_id>
<user_id>98953</user_id>
<album_id>224030</album_id>
<type>jpg</type>
<width>450</width>
<height>337</height>
######################################################################## 100.0%%
個人的にこれが激しく便利。
■APIをPOSTで叩いて怒られてみる
フォト蔵さんのphoto_list_public API はなにやらGETのみ対応らしいので
-d オプションを使って POST で叩いて怒られてみよう
$ curl '-#' 'http://api.photozou.jp/rest/photo_list_public' -d 'type=album&user_id=98953&album_id=224030' | head
<?xml version="1.0" encoding="UTF-8" ?>
<rsp stat="ok">
<info>
<photo>
<photo_id>2298762</photo_id>
<user_id>98953</user_id>
<album_id>224030</album_id>
<type>jpg</type>
<width>450</width>
<height>337</height>
あれ、、怒られるかと思ったけど大丈夫みたい。
■ほんとにPOSTか詳しく見てみる
$ curl '-#' -v 'http://api.photozou.jp/rest/photo_list_public' -d 'type=album&user_id=98953&album_id=224030' | head
* About to connect() to api.photozou.jp port 80 (#0)
* Trying 124.32.224.107... connected
* Connected to api.photozou.jp (124.32.224.107) port 80 (#0)
> POST /rest/photo_list_public HTTP/1.1
> User-Agent: curl/7.16.0 (i386-portbld-freebsd6.0) libcurl/7.16.0 OpenSSL/0.9.7e zlib/1.2.2
> Host: api.photozou.jp
> Accept: */*
> Content-Length: 40
> Content-Type: application/x-www-form-urlencoded
>
} [data not shown]
< HTTP/1.1 200 OK
< Date: Thu, 15 Feb 2007 17:01:23 GMT
< Server: Apache
< X-Powered-By: PHP/4.3.11
< Content-Type: text/xml; charset=UTF-8
< Transfer-Encoding: chunked
{ [data not shown]
<?xml version="1.0" encoding="UTF-8" ?>
<rsp stat="ok">
<info>
<photo>
<photo_id>2298762</photo_id>
<user_id>98953</user_id>
<album_id>224030</album_id>
<type>jpg</type>
<width>450</width>
<height>337</height>
うむ、やっぱりPOSTで叩いてるっぽい。
どっちも対応してるのかな。
Development Environment Conference
直訳すると開発環境会議
の申し込みになんとか間に合った。
今日の今日でオレンジニュース経由でこの情報を知り、(最近忙しくて見るの忘れるんだけど偶々朝チェックしててよかった)
仕事そっちのけで待った甲斐がありました。
12時ちょうどにリロードしてサクサクっと申し込んだらOKのメールが届いておりましたよ。
そしてその後リロードしたら
「定員に達したため、申し込みを終了しました。 」
になってました!
なんと開始3分くらいで定員の120名に達した模様です。
なにこのプレミアムチケット。
そして向こうで同じ会社の人見かけまくるんだろうなぁ。
それにしてもこれ金曜の18:30開場だから確実に早退しないといけないのがちょっと痛い。
フラグなのに文字列を使ってたり、
定数なのにdefine使わなかったり、
あとみんな===演算子とか使わないのはなんで?
==だとちょっと怖くない?
だって
var_dump('0' == 0);
var_dump('' == 0);
var_dump(null == 0);
var_dump(false == 0);
var_dump('aaa' == 0);
これ全部 true だよ!
なんかいやじゃない?
ってまぁなんでこんなことを愚痴ったのかと言いますと、
仕事で使ってる某ライブラリでちょっとハマったのです。
あるクラス、例えばTheClassがありまして、
そのクラスに何がしかの内部状態を返すgetStatus()メソッドがあるとします。
$cls = new TheClass();
$status = $cls->getStatus();
こんな感じで。
そんでこのgetStatus()メソッドが返す値はライブラリの中で定義されてます。
define('STATUS1', 0);
define('STATUS2', 1);
define('STATUS3', 2);
こんな感じね。
で、その使い方のサンプルコードにはこんな風にかいてあります。
$cls = new TheClass();
$status = $cls->getStatus();
if ( $status == STAT1 ) {
echo 'status1の時の処理';
}
うん、ここまでは問題ない。
そして自分は == よりも === の方が安全だなと思い、そのように書き換えました。
$cls = new TheClass();
$status = $cls->getStatus();
if ( $status === STAT1 ) {
echo 'status1の時の処理';
}
そしたらですね。これが条件に通らないんですよ。
さっきまでは通っていたのに。
と、既にお気づきの方もおられると思いますが、
サンプルコードのif文の中の定数が間違っていたのですよ。
×if ( $status == STAT1 ) {
○if ( $status == STATUS1 ) {
STAT1 なんて定数はライブラリ中でどこにも定義されてなくて本当は STATUS1 なわけです。
でもサンプルコードでは STAT1 になっている。
単純にサンプルコードを書くときに書き間違えたんでしょうね。
でですね、これがエラーになればすぐ気づくので問題ないんですが、
この間違いなサンプルコードでも通っちゃうんです。
ためしに
var_dump( 0 == STAT1 );
とかやってみましょう。
trueになるはずです。
定義されていない定数STAT1は文字列"STAT1"とみなされ、それをintで評価すると0になるので結果的にSTATUS1と同等になってしまうというわけです。
でもこれ定義されていない定数を使った時点でNoticeレベルのエラーがでるはずです。
そう、だから本来はこれで気づくはずなんですが、
なんというかこのライブラリでは自前のエラーハンドラーを使ってまして、
そいつがE_WARNINGとE_NOTICEを捕捉してないんですね。
だからいくらWariningやNoticeを出そうが一切エラーログに吐かれない。
あーだから何が言いたいかといいますと
===使おうよと。見た目がゴージャスだし。
忘れないように整理しておく。
間違っていたら誰か指摘してくれるとありがたいです。。
php4にはデストラクタは存在しない
しかし
register_shutdown_functionを使ってデストラクタ的なもの(以降なんちゃってデストラクタと呼ぶ)を定義することはできる。
一番簡単なのは
PEARクラスを継承すること。
そうすれば、_クラス名(アンダーバー+クラス名)のメソッドを定義することでそれが自動的になんちゃってデストラクタになる。
(ここらへんの実装はソースを見ると面白いかもしれない)
それくらいでわざわざPEAR継承したくないよ!とか
PEARを使わない方針の場合は自分でコンストラクタの中でregister_shutdown_functionを使ってやればよい。
↓こんな感じで。
hoge.class.php
fuga.class.php
どちらの場合(PEARも自前)もregister_shutdown_functionを使っているので、
このなんちゃってデストラクタが呼び出されるタイミングはあくまでスクリプト終了時。
こんな感じのソースで
実行すると・・・
スコープから抜けてオブジェクトが参照されなくなってもなんちゃってデストラクタが呼ばれてないことがわかる。
本来のデストラクタならインスタンスの開放時に呼ばれるべき。
これがなんちゃってデストラクタとか言われる所以。らしい。
結局のところ非持続的なresource型の開放(mysql_closeなど)が目的ならば
phpでは自動的に開放されるのでわざわざなんちゃってデストラクタを定義して開放する必要性はあまりない。
(phpが自動的にresourceを開放するのがスクリプト終了時、なんちゃってデストラクタが呼ばれるのもスクリプト終了時なので明示的に書く意味がない。)
よってなんちゃってデストラクタを作ること自体php4ではあまりないのかもしれない。
少なくとも先に述べたようにresource型を開放するだけのために作るのは意味がない。はず。
参考:
付録 L. リソース型の一覧
ほぼ自分用メモ。
http://phparch.com/zftut/
サンプルコードしか見てないからなんともいえないけど
パっと見は他のMVCフレームワークと大差ないような気がするけど特長はなんなんだろー。
あとテンプレートに書く出力用のechoの記述が冗長であまり好きじゃないかも。
escapeメソッドでなくてecho自体をラップしたほうが見た目はスッキリするよなぁ細かいけど。
その点やっぱりSmartyのほうがテンプレの見た目はすっきりするなーと改めて思った。
と本文を読まないで無責任に発言してみる。
結局phpのデファクトスタンダードなフレームワークは何になるんだろうなぁ。
なんでもいいから早くある程度枯れて欲しい。。
いっぱいになりつつある今日この頃。
ただの技術書マニアになりつつあります。
これはいかがなものか。。
勢いあまってAmazonで注文してしまった
Advanced Php Programmingが先日届きました。
・・・もちろんまったく読めません。
ただサンプルコードは読めるので、少しでもいいから参考にしたいところ・・。
エラーハンドリングの章はなんとか読みたいなぁ。
技術者は英語必須ですね。得られる情報量が全然違う。
さて、今日も今日とて本を買ってきました。
(毎月いくら使ってるんだろう・・・。)
といっても会社の人に頼まれて会社のお金で買ったので懐は痛くありません。
PHP5の
赤マンモス本と
青マンモス本です。
これのPHP4版は自腹で買って持ってるんだけど、ざーっと見た感じでは結構内容がかぶってるような・・。
とりあえず会社のなのでまーいいか。。
あともう1冊
JavaScriptを買いました。
こっちは自腹で・・・。
まだ少ししか読んでいませんが、これは良い買い物でした。
ちゃんとjavascriptを知りたい人にはおすすめですね。
こういう感じの本はPHPだと
これですかね。
ようするにこの2冊は技術者が読むべき本です。
phpとかjavascriptはなんというか簡単な言語という側面が強いので、初心者向けの本はたくさん出ています。
それはそれで良いのですが、本業の人はきちんと言語を理解しておかないと。
こういうなんとなく書けちゃう言語はなんとなく習得する期間は短いものの、それっぽくかけるようになるにはそれなりに時間がかかるものです。多分。
PHPなのにCっぽく書いてたりとかperlなのにperlっぽく書いてないとか、そんなことは日常茶飯事だとは思いますが、少なくともそれで出来ます!って威張れるのはちょっと違うかと。
やっぱりその言語特有の書き方とかどっちの書き方の方がパフォーマンスがいいとかスマートだとかが分かって初めてその言語が出来ると言えるのじゃないかと思います。
とか言って自分の身を引き締める。
たまにはプログラムのことを書いてみる。
phpでSmartyを使うほどでもないけどロジックによってはテンプレートの出し分けしたいなーっていう場合に自分はこんな関数を使ってます。
function display( $tpl, $tpl_vars = null ) {
if ( defined('DEFAULT_TEMPLATE_DIR') ) {
if ( substr(DEFAULT_TEMPLATE_DIR, -1) !== DIRECTORY_SEPARATOR ) {
$tpl = DEFAULT_TEMPLATE_DIR . DIRECTORY_SEPARATOR . $tpl;
} else {
$tpl = DEFAULT_TEMPLATE_DIR . $tpl;
}
}
if ( ! file_exists($tpl) ) {
trigger_error("'$tpl' is not found", E_USER_ERROR);
}
if ( $tpl_vars !== null ) {
extract($tpl_vars);
}
include($tpl);
exit;
}
呼び出し側はこんな感じ
if ( $isHoge ) {
display('hoge.tpl', array('msg' => 'hoge'));
} else {
display('fuga.tpl', array('msg' => 'fuga', 'msg2' => 'foobar'));
}
で、テンプレートはそれぞれこんな感じ。
hoge.tpl
<html>
<head>
<title>hoge.tpl</title>
</head>
<body>
<h1>Hello <?php echo $msg ?> world.</h1>
</body>
</html>
fuga.tpl
<html>
<head>
<title>fuga.tpl</title>
</head>
<body>
<h1>Hello <?php echo $msg ?> world.</h1>
<h2><?php echo $msg2 ?></h2>
</body>
</html>
パフォーマンス優先で機能はあんまりいらない、かつテンプレートの見た目が多少ごちゃついてもいい場合はこんなのでも良いのではと思います。
追記:
テンプレートにバインドする変数が無い時の対応がなかったので
display関数の第2引数のデフォルトを null にした。
それにともない null の時はextractしないように修正。
あとパフォーマンスとかいいつつちゃんとベンチとっていなかったので pear/Benchmark を使ってSmartyと比較してみた。
詳細は手元に無いので書けないんだけど、
上記の関数を使った場合を1とすると・・・
Smarty使用の1回目はキャッシュが生成されてないのでだいたい30倍くらいで、
2回目以降はキャッシュが聞いてるので3倍くらいだった。
適当にやっただけなのであくまで参考値だけどとりあえず遅くなくてよかった。
はい、行ってきましたPHPCon2005。
京急蒲田駅って何も無いのな!
コンビニすらないし。ちょっと歩けばあったけど。
んで、メモ書き(間違いは責任放棄)、かつ感想。
PHPセキュリティ関連
XSS
とか
SQLインジェクション
- まず、ユーザ入力チェック
- 次にSQL文字のエスケープ(addslashes, mysql_escape_stringなど)または、プリペアドステートメントを使う(php5のPDOとかPEAR::DBとか)
セッションハイジャック
- session_regenerate_id関数を使う
使う場所はsession_start()の後らへんで良いんじゃん?
コマンドインジェクション
暗号化
- 不可逆
- md5() ファイルハッシュなどに
- crypt() DES, unixパスワードの保持に
- 可逆
- mcrypt() 3DES, AES, RC4
- PEAR::BlowFish BlowFishアルゴリズムに対応
php.ini
- register_globals
- magic_quotes
- error_reporting, display_errors
- safe_mode
- expose_php
ここらへんをチェック
セキュリティ向上ツール
- Hardened_PHP
- ionCube PHP Encorder
フレームワークの話
Mojavi
良かったんですけど、早口で聞き取りづらかったのと、ソースの文字が小さくて見づらくて残念だった。
そしてmojaviだと海外製なのでICC(Input, Confirm, Complete)やろうとするとめんどくさいらしい。
確かにそうかも。
agaviとかいうのがあるらしい。
既にjpドメインも取ったらしい。
おもしろそう。
Ethna
プレゼンが良かった。分かりやすくて。
あと正直な言い回しが好感が持てる。
んでドキュメントが足りてないんでアレなんだけど、
- Ethna_AppObject ・・・ O/Rマッパー?
- Ethna_MailSender ・・・ メール送信
とかもあるらしい。
そして今後はRuby on Railsに負けずにとか言っていたので勝手に期待大。
maple
あ!聴いててメモるの忘れてた!
確かDIの説明とかしてた。
DIを標準で搭載してるのってmapleだけだっけか??
php5
いろいろ問題もあるけどphp5.1 になってそろそろ使ってもいいんじゃん?
みたいな結論?
Zendエンジン早くなったらしい。
個人的にはPDO使ってみたい。
あと配列の値を更新する時に、
foreach ( $arr as $key => &$value ) {
$value = "{$value}!!!!!";
}
みたいな書き方が出来るようになったらしい。
これは今までなんで出来ないんだろーと思っていたので嬉すい。