そうだ、コアを読もう3 -CakePHP-
今日はバッチ処理の開発を行った。
一定時間ごとに cron で叩いて、API を利用してデータを取得してくるという、よくあるもの。
app/Console/Command/の直下に AppShell を継承したファイルを置けばいい。
今回は、LAMP 環境に TeraTerm で接続してコマンドラインからテストを行っていて、すぐにはまった。
どばーっとエラーが出た。
うわ、やっちまった。
一瞬血の気が引いたけど、よく読んだらそんなに致命的な(サーバーの設定壊したり、ファイル削除したり)などはなかった。
良かった良かった。
良くないけど。
じっくり読んでいくと、なにやらログを出力するための権限がないよ、と言っているらしい。
すぐに chmod で権限を変更しようと思ったが、ふと思い直す。
ログファイルなんだから、削除したりファイル名を動的に切り替えたりするはず。
一時的に権限を得ただけじゃダメだろう。
と言うことでコアを読みにいってみよう。
今回はコンソールにエラーがばりばり出ていたおかげで目的のファイルはすぐ見つかった。
lib/Cake/Log/Engin/FileLog.php の file_put_contents() がエラーの源だ。
さてその付近を見てみると、 148行目で chomod をしている。
if (empty($this->_config['mask'])) {
return file_put_contents($pathname, $output, FILE_APPEND);
}
$exists = file_exists($pathname);
$result = file_put_contents($pathname, $output, FILE_APPEND);
static $selfError = false;
if (!$selfError && !$exists && !chmod($pathname, (int)$this->_config['mask'])) {
$selfError = true;
trigger_error(__d(
'cake_dev', 'Could not apply permission mask "%s" on log file "%s"',
array($this->_config['mask'], $pathname)), E_USER_WARNING);
$selfError = false;
}
設定している値は $this->_config['mask'] だ。
この変数は141行目でも使っていて、値の取得元は コンストラクタ。
さてさて、一体どこでインスタンスを作っているのだろうか。
ぶっちゃけ良くわからんけど、こういうシステム全体に関わりそうなものを設定しているところは大抵 app/Config/ の下にあるはず。
core.php と bootstrap.php あたりが怪しい。
やあやあ、発見しましたよ bootstrap.php の一番下に。
/**
* Configures default file logging options
*/
App::uses('CakeLog', 'Log');
CakeLog::config('debug', array(
'engine' => 'File',
'types' => array('notice', 'info', 'debug'),
'file' => 'debug',
));
CakeLog::config('error', array(
'engine' => 'File',
'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
'file' => 'error',
));
インスタンス作って持ち回ってるのかと思いきや、親クラスを静的に呼び出して設定している?
まぁ、今回は細かいことはいい。
ログが吐ければいいのだ。
ここの両方の配列の中に
'mask' => 0666,
を書き足して終わり。
ここは文字列ではなく数字列。
先頭が 0 で始まるのは 8進数の印。
何で8進数なの?っていう人は、ググった方がいいでしょう。
さて、これでログファイルは書けるようになった(すでに出力されていたログファイルは一度削除した)。
が、まだエラーは止まらない。
今度はキャッシュが書き込めないぞ、とのことらしい。
キャッシュも大体おんなじで、 lib/Cake/Cache/Engine/FileEngine.php で chmod しているところを360行に発見。
if (!$exists && !chmod($this->_File->getPathname(), (int)$this->settings['mask'])) {
trigger_error(__d(
'cake_dev', 'Could not apply permission mask "%s" on cache file "%s"',
array($this->_File->getPathname(), $this->settings['mask'])), E_USER_WARNING);
}
mask よ、またおぬしか。
さて、今度はどこで設定してるのだろう。
bootstrap.php には見つからなかったので、 core.php を読んでみると、ありましたありました。
エラーログでなんか見た _cake_model_ って文字が書いてるところ。
こちらもやはり一番下にあった。
同様に
'mask' => 0666,
を書き足して、キャッシュファイルを削除して終わり。
はい、これでエラーはキレイに消えました。
というか、なんで両方ともデフォルトで 0666 指定しておいてくれないのかな。
まぁコアの配置によっては、危ないからかもしれないけど。
危ないといえば OpenSSL の脆弱性が指摘されてたなぁ。
その前は iOS の SSL が昔からずっと脆弱性抱えてたっていうのが発覚したばっかりだし。
なんか SSL ぜんぜんセキュアじゃないね!