デコンパイラ JD-Eclipse を入れてみた

デコンパイラといえば jad と、 Eclipse 組み込み版の Jadclipse が主流でした。
しかし最近は Jadclipse がメンテナンスされていなかったり、そもそもjad が公式配布停止していたりで残念なことに事実上完全に開発停止になってしまったようです。
 
そこで代わりを探していたところ、JD-Eclipse というものを見つけました。
 
Eclipse 3.5 (galileo)ですんなりダウンロード完了。
Java 5 の逆コンパイルにも対応していて、Jad よりも高機能なようです。
 
Eclipse アップデートサイトからの更新はこちら。

http://java.decompiler.free.fr/jd-eclipse/update

 
日本語での使い方説明記事はこちら。
究極の問題解析ツール、逆コンパイラJD-Eclipseとは(@IT)
 
参考:
– JD-Eclipse Java Decompiler
– 究極の問題解析ツール、逆コンパイラJD-Eclipseとは(@IT)

PHPのCache_Lite で lifeTime を場所によって変える時の注意点

PEAR の CacheLite を、短期キャッシュと長期キャッシュに分けて運用する場合、普通に automaticCleaningFactor を使っていると、思った通りに動作しなくなります。
 
automaticCleaningFactor は、現在設定されているlifeTimeを基準に、cache_dirの中の全ての古いファイルを掃除してしまいます。
 
save() で指定した group_id の古いファイル限定で掃除してくれれば融通がき くのですが、そもそも clean() の実装がそうはなっていない様子。
 
PEAR Bugにもこの問題が報告されていますが、現在のAPIを変えずに実装するのは困難として対応打ち切りになっています。
その代わり、解決案としてキャッシュの寿命別にフォルダ分けをする方法が紹介されていました。
 

Best practice then would appear to be that you create directories for each of your caches if you want to be using this autocleanfactor.
ここでの最良の習慣は、autocleanfactorを使う場合には(用途,寿命の違う)それぞれのキャッシュごとにディレクトリを分けて作る事です。

 
参考:
– non-specific automaticCleaningFactor(PEAR Bug)
– Cache_Lite(PEARマニュアル)

Firefoxの下部の検索バーで入力中に勝手にフォーカスが外れる

サーチエンジン用の検索バー(Search Bar/Ctrl-K)でなく、ページ内検索(Find Bar/Ctrl-F)のお話。
ある時からfirefox を使ってページ内検索すると、文字入力中に時々不意に検索バーがフォーカスを失ってページへのフォーカスに勝手に切り替わってしまうようになりました。
 
不便で悩んでいたのですが、どうやら「Fast Video Download (with SearchMenu)」アドオンが悪さをしているようで、この拡張を無効にしたところ無事元通りの動作になりました。
 
Fast Video Download の、文章をドラッグなどで選択した時に、選択文字列での検索コンテキストメニューを自動で出す機能(テレビマークのアイコンをクリック)が、検索バーの動作と干渉して発生しているようです。
 
追記:Mozilla Firefoxフォーラムでも同じ現象に悩んでいる方がいました。

The Find bar for finding text on a page has changed behavior and it is frustating to use
 (訳:ページ内文章の検索バーの動作が変わって使っていてイライラするようになりました)

解決コメントを見るとやはり原因は同じで、
Firefox 3.6 を入れることで Fast Video Download の動作が変わってしまったという書き込みがありました。

 (2010年3月21日19:01書き込み)dpn:
I disabled the plug-in called Fast Video Download. The problem is gone. I don’t know for sure if there is a connection.
 (訳:Fast Video Download というプラグインを無効にしたら、この問題は解決しました。関連はあるかどうかわかりませんが。
—
 (2010年3月21日19:10書き込み) Reg:
Yes, I see. Now I tried the same thing (disabled the Fast Video Download addon) and it seems to have fixed the problem here too. Strange though, since I had used the FVD addon without problem on the older firefox, and now it interferes even with the older firefox. Thanks for the info.
 (そうなんですか。同じ事(Fast Video Download アドオンを無効にする)を今やってみたら、こちらでも問題が解決したようです。でもおかしい事に、以前のバージョンのfirefoxではFVDアドオンを使っていても前はこのような問題は起きなかったのに、今では以前のバージョンのfirefoxにも干渉しているようです。情報ありがとうございます。
—
 (2010年3月21日 19:52 書き込み)Reg:
I have now completely uninstalled search menu and FVD addons, and also uninstalled firefox 3.6 (leaving personal profile information intact when given the choice by firefox uninstaller).
 サーチメニューとFVDアドオンを完全にアンインストールしてfirefox 3.6も(個人設定情報はアンインストーラの選択でで完全に残したままにして)アンインストールしてみました。
Then I downloaded older firefox 3.5.8 from the official mozilla firefox website and reinstalled the search and FVD addons on this older platform.
 (それから以前のfirefox 3.5.8 を公式mozilla firefox ウェブサイトからダウンロードして再インストールして、FVDアドオンをそこにインストールしました。)
Now everything is working again as prior to the firefox 3.6 upgrade. I will only upgrade to firefox 3.6 again if I’m sure all my addons will work properly.
 (それでfirefox3.6にアップグレードする前のままの状態で動いてくれるようになりました。firefox 3.6 にアップグレードするのは、私が使っているアドオンがちゃんと動いてくれるのを確認できてからにしようと思います。)

 
参考:
– Fast Video Download(with SearchMenu)
– The Find bar for finding text on a page has changed behavior and it is frustating to use(Mozillaフォーラム)

ExtJS GridPanel の cellclick イベントを使う

マニュアルどおりでうまくいかなかったのでメモ。
ExtJS 3.1 で動作確認。

var grid = new Ext.grid.GridPanel({
  // 中略
  listeners: {
      cellclick: function( grid, rowIndex, columnIndex, e) {
        var record = grid.getStore().getAt(rowIndex); // rowIndex番目のレコード取得
        var fieldName = grid.getColumnModel().getColumnId(columnIndex); // columnIndex番目のフィールド名取得
        var data = record.get(fieldName); // 指定座標のセルの内容を取得。
        alert(data); // 表示。
      }
  }
});

参考:
– ExtJS GridPanel

HTTP – Locationヘッダには相対URLを使ってはいけない

HTTP の仕様(RFC2616)では、 Location ヘッダは絶対URIでなければならないと今更知りました。
Hypertext Transfer Protocol — HTTP/1.1(日本語) 14.30:

Location = “Location” “:” absoluteURI

ちなみに絶対URI(absolute URI)とはRFC2396によるとスキームから始まるURIのみを指します。
スラッシュ(“/”)から始まる URL が絶対URLと言われることがありますが、正確には絶対パス(absolute path)指定の相対URLであり、絶対URLではありません。

absoluteURI = scheme “:” ( hier_part | opaque_part )
hier_part = ( net_path | abs_path ) [ “?” query ]
relativeURI = ( net_path | abs_path | rel_path ) [ “?” query ]
net_path = “//” authority [ abs_path ]
abs_path = “/” path_segments

 
ただ、ほとんどのブラウザで相対URLへのロケーションを寛容に解釈してくれます。
lynx では警告が出るようですが、一般向けには携帯でさえ(mova など余程古いものを除けば)意図通りにリダイレクトしてくれるようになり、仕様違いでも問題がほぼなくなってしまいました。
 
相対URLが便利なのも事実。なのでもしかしたら HTTP 2.0 ができるときには相対URI可、なんてことになるかもしれませんね。

SWFObject – IE で Flash から fscommand が実行できない対策

IE で Flash ムービー(foo.swfなど)を innerHTMLなどで動的に埋め込むと, VBスクリプトでイベントを取れなくなるのが原因のようです。
 
対策は、SWFObject FAQに書かれているように

5.なぜ動的なパブリッシュを行うとインターネットエクスプローラーで fscommand が動かなくなるのか。
Adobe は fscommand をインターネットエクスプローラーで動作させるため、
FSCommand 呼び出しを受け取り JavaScript に転送するための VBScript を追加するように推奨しています。
ですが SWFObject の動的なパブリッシュメソッドで行っているように、
innerHTMLや outerHTML などを使って Flashムービーを挿入する場合には VBScript は全く動作しません。
 
運がいいことに、VBScript の代わりに JavaScript を使っても fscommand の呼び出しを受け取る方法があります。
このちょっと下にあるコードではプロプライエタリ(訳注:専用の?)属性(を、あなたのコードをおかしくさせないために、さらに条件分岐コメントで括ったもの)を使っています。
 
例として、下のVBScriptは、

<SCRIPT LANGUAGE=VBScript>
on error resume next
Sub myCom_FSCommand(ByVal command, ByVal args)
  call myCom_DoFSCommand(command, args)
end sub
</SCRIPT>

次のように置き換えることが可能です。

<!–[if IE]>
<script type=”text/javascript” event=”FSCommand(command,args)” for=”myCom”>
  myCom_DoFSCommand(command, args);
</script>
<![endif]–>

 
注意:Flash 8 以上でパブリッシュしている場合、JavaScript – ActionScript間の通信には fscommand() を利用するよりも ExternalInterface が推奨されています。
 
コードの例は SWFObject のテストスイートでも見つけることができます。

参考:
– FlashとJavaScriptの連携
– SWFObject v2.0 ドキュメント日本語訳
– Why doesn’t fscommand work in Internet Explorer with dynamic publishing ?(SWFObject FAQ)
– ExternalInterface(ActionScript 3.0 コンポーネントリファレンスガイド)

PHPでDBレコードをソートする

レコード…連想配列の配列…は、MDB::fetchAll() や DB::getAll() の結果の書式で見られるように一般的なデータ構造書式です。
たまにはコードを上げてみよう、ということで汎用関数としてレコードソート関数を作ってみました。実装コードおよびサンプルは下のほうにあります。
特に著作権等は主張しませんのでご自由にお使いください。
 
書式:

int sort_records(&$records, $key, $descent = false);


実装コード:

/**
 * DBなどのレコードを任意のキーでソートする。
 * PHP 4.4.9, PHP 5.2.8 で動作確認。
 *
 * @author ecoop.net
 * @access public
 * @param array &$records DBなどレコードの配列
 * @param string $key ソートの基準にするカラムの名前。省略時は第一カラムでソート。
 * @param boolean $descent true なら降順で結果を返す。省略時は false
 * @return bool 成功なら true を返す
 */
function sort_records(&$records, $key = null, $descent = false){
  if(!$records || !is_array($records)){ return false; }
   
  // $key が省略された場合は第一レコードの第一カラムを名前を取得
  if(is_null($key)){
    $t = array_values($records);
    $t = array_keys($t[0]);
    if(!$t){ return false; }
    $key = $t[0];
  }
  // —-
  $map = array();
  foreach($records as $i => $v){
    if(!is_array($v) || !isset($v[$key])){ return false; }
    $map[$v[$key] .’_’. $i] = $v;
  }
  
  if($descent){
    $res = krsort($map);
  }else{
    $res = ksort($map);
  }
  $records = array_values($map);
  return $res;
}

利用例:

// 元データ
$records = array(
array(‘age’ => 24, ‘name’=>’john’),
        array(‘age’ => 33, ‘name’=>’george’),
        array(‘age’ => 56, ‘name’=>’bill’),
        array(‘age’ => 50, ‘name’=>’steven’),
);
// name カラムでソート
sort_records($records, ‘name’);
print_r($records);

結果:

Array
(
    [0] => Array
        (
            [age] => 56
            [name] => bill
        )
    [1] => Array
        (
            [age] => 33
            [name] => george
        )
    [2] => Array
        (
            [age] => 24
            [name] => john
        )
    [3] => Array
        (
            [age] => 50
            [name] => steven
        )
)

PHPのsession_regeneration_id とセッションフィクシエーション対策

CSRF 対策のうち、セッションフィクセーションを避けるために使われる
session_regenerate_id() 関数について、ITProで間違い(になる場合がある)記事を見つけたのでメモ。
 
関数の知られざる引数(print_r関数、session_regenerate_id関数)[より

同じように、PHP 5.1からはsession_regenerate_id関数にも第1引数が指定されました。第1引数をtrueに指定すると、古くなったセッションは削除されるようになります。
 
もともとセッション固定攻撃を防ぐために用意された関数ではなく、PHP 5.1 までの同関数には古いセッションファイルを削除する機能が無かったため、セッション固定攻撃への対策としては不十分でした。
 
今後は、session_regenerate_id関数の引数に必ずtrueを指定することを忘れないようにしましょう。また、それまでのPHPで使う場合は、以下のコードを使うことで、セッション固定攻撃を防ぐことができます。

のように、session_regenerate_id() の第一引数に true を常に指定すべきと書かれていますが、session_regenerate_id(true) はむやみに使ってはなりません。
 
ショッピングカートなど限定的な用途でセッションを使っている場合は問題ないのですが、常にログインが必要なサイトなどで非同期で複数のリクエストを実行する可能性がある場合、古いセッションが削除されると問題になりことがあります。
 
たとえば同じ HTML 内に認証が必要な画像などの埋め込みコンテンツが複数あったり AJAX で認証が必要なデータにアクセスする場合、一つのセッションIDで複数のリクエストを行うため、2リクエスト目以降も古いセッションで認証することになるからです。
 
代替案として、session_regenerate_id(false) と session_write_close() を組み合わせて古いセッションのみ有効期間を設定してやるとよい、とsession_regenrate_idのコメント欄に書かれていました。
 
実装例:

// ユーザがリクエストしたセッションIDからセッション情報をロードする。
session_start();
// —————————————————–
// 以下セッションフィクセーション対策
if(isset($_SESSION[‘expire’]) && $_SESSION[‘expire’] < time()){
    // 過去に session_regenerate_id() で置き換えられた古いセッションによるアクセス。
    // 有効期限を過ぎていればセッション情報をクリアする。
    $_SESSION = array();
}
 
// 古いセッションは2分間で消えるように設定。
$_SESSION[‘expire’] = time() + (2*60);
// 有効期限を記録するため、一旦明示的にセッションを閉じ、$_SESSION の中身を古いセッションIDで保存する。
session_write_close();
 
// 閉じたセッションを開きなおす。
session_start();
// セッションIDを更新し、$_SESSION を古いセッションIDから切り離す。
session_regenerate_id();
// 新しいセッションID は有効期限なし。
unset($_SESSION[‘expire’]);
// ——————————————-
// セッションフィクセーション対策ここまで。
// あとは通常通り。
$_SESSION[‘user_id’] = “1234”;

 
また、session_regenerate_id() だけではセッション所有者のリクエストによる XSRF は防ぐことはできないため、こちら(開発者のための正しいCSRF対策)を参考にワンタイムトークン等も適宜組み合わせましょう。

PHPで任意のファイルデスクリプタを開く

PHP には fdopen がないので、子プロセスについては /dev/fd/<FD番号> で代用してます。
PHP の機能ではありませんが。。

<?php
// child.php: 子プロセス(parent.php から実行される)
$fd = 4; // 親プロセスとのやり取りに使うファイルデスクリプタ(0:stdin, 1:stdout, 2:stderr)
$fdfile = “/dev/fd/$fd”;
if(!file_exists($fdfile)){
   die(“ファイルデスクリプタが開かれていません”);
}
 
$pipe = fopen($fdfile, “r”);
while(!feof($pipe)){
  echo fread($pipe, 1024);
}
fclose($pipe);

 

<?php
// parent.php: 親プロセス
$fd = 4; // 子プロセスとの通信に使うファイルデスクリプタ
$fp = proc_open(“php child.php”, array(
  $fd=>array(‘pipe’, r),
),$pipes);
 
fwrite($pipes[$fd], “Hello world!!”);
fclose($pipes[$fd]);
 
proc_close($fp);

 
FreeBSD の場合、標準では /dev/fd に 0,1,2 しかないため動作しません。
次のようにしてfdescfs を /dev/fd にマウントすればプロセスごとのファイルデスクリプタを自動作成してくれるようになります。

# echo “fdescfs /dev/fd fdescfs rw 0 0” >> /etc/fstab
# mount /dev/fd

または /dev/fd を使わない実装に置き換える事でも動作します。
この場合、ファイルデスクリプタが開いているかの確認には fstat [-p PID] を使うといいかもしれません。

// child.php: FreeBSD で devfs を使っている場合の代替実装。
$fd = 4;
$pipe = popen(‘cat < &'.$fd, 'r');
echo fread($pipe, 1024)
pclose();