[CakePHPのバグ]キャッシュ処理でunserializeエラーが発生する
CakePHP バージョン1系をLinuxサーバで動作させているときに、shellバッチを使っているとウェブアクセスでごくまれに次のようなエラーが出ることがあります。
ごくまれにしか発生しない現象で、気づきにくくリロードすると解消されるため調査・検証がしづらいです。
[参考記事] キャッシュ処理でunlinkエラーが発生する
Notice (8): unserialize() [http://php.net/function.unserialize]: Error at offset 4080 of 4085 bytes [CORE/cake/libs/cache/file.php, line 187] unserialize - [internal], line ?? FileEngine::read() - CORE/cake/libs/cache/file.php, line 187 Cache::read() - CORE/cake/libs/cache.php, line 362 DataSource::__cacheDescription() - CORE/cake/libs/model/datasources/datasource.php, line 477 DboMysqlBase::describe() - CORE/cake/libs/model/datasources/dbo/dbo_mysql.php, line 155 Model::schema() - CORE/cake/libs/model/model.php, line 929 Model::setSource() - CORE/cake/libs/model/model.php, line 780 Model::__construct() - CORE/cake/libs/model/model.php, line 474 ClassRegistry::init() - CORE/cake/libs/class_registry.php, line 142 Controller::loadModel() - CORE/cake/libs/controller/controller.php, line 637 Controller::constructClasses() - CORE/cake/libs/controller/controller.php, line 502 Dispatcher::_invoke() - CORE/cake/dispatcher.php, line 186 Dispatcher::dispatch() - CORE/cake/dispatcher.php, line 171 [main] - /xxxxx/html/index.php, line xxx
これはTMP cache models以下のデータベース用キャッシュファイルがシェル実行権限のユーザーにより644でファイルが作成されたものを
ウェブアクセス実行権限のユーザーが処理しようとしてエラーとなっていることが考えられます。
apacheの権限ユーザーやシェル実行権限ユーザーを変更できる場合はユーザーを共通にすることで対処できますが、これは難しいことが多々あります。
そもそもこれが起こる理由はCakePHPのバグです。
エラーが発生している箇所をたどっていくと次のようなコードになっています。
エラーの該当箇所付近
CORE/cake/libs/cache/file.php, line 187
$data = $this->_File->read(true); if ($data !== '' && !empty($this->settings['serialize'])) { if ($this->settings['isWindows']) { $data = str_replace('¥¥¥¥¥¥¥¥', '¥¥', $data); } $data = unserialize((string)$data); }
$this->_File->read(true)の戻り値$dataを扱っています。
この$this->_Fileが定義されている箇所
CORE/cake/libs/cache/file.php, line 82
if (!isset($this->_File)) { $this->_File =& new File($this->settings['path'] . DS . 'cake'); }
つまり$this->_FileはFileオブジェクトでCORE/cake/libs/file.phpにあります。
$this->_File->read()が書かれている箇所
CORE/cake/libs/file.php, line 168
function read($bytes = false, $mode = 'rb', $force = false) { if ($bytes === false && $this->lock === null) { return file_get_contents($this->path); } if ($this->open($mode, $force) === false) { return false; } if ($this->lock !== null && flock($this->handle, LOCK_SH) === false) { return false; } if (is_int($bytes)) { return fread($this->handle, $bytes); } $data = ''; while (!feof($this->handle)) { $data .= fgets($this->handle, 4096); } if ($this->lock !== null) { flock($this->handle, LOCK_UN); } if ($bytes === false) { $this->close(); } return trim($data); }
つまり$this->_File->read()の戻り値にはfalseが返ってくることがあります。
ところが
CORE/cake/libs/cache/file.php, line 184
if ($data !== '' && !empty($this->settings['serialize'])) {
となっているため、falseでもunserialize関数に進んでしまいます。
この箇所を次のように変更することで、このバグは修正することができます。
if ($data !== false && $data !== '' && !empty($this->settings['serialize'])) {
CakePHPバージョン2系でも
CORE/cake/lib/Cake/Cache/Engine/FileEngine.php, line 195
に同じコードがありますが、$dataは文字列型(String)で扱われているので問題はないです。
関連記事
- 複数カラムのユニーク制約バリデーション
- 標準のValidatorを拡張してカスタマイズする方法
- テンプレート(template)側でログイン情報を取得する方法
- フォームの必須エラーメッセージをHTML5標準にする方法、カスタマイズする方法
- 標準のHelperを拡張してカスタマイズする方法 CakePHP2
- 国際化i18n(多言語化)
- URLをハイフン区切りからアンダーバー区切りやキャメルケースにする方法
- CakePHP5系の入手方法・インストール方法
- CakePHP4系の入手方法・インストール方法
- CakePHP3系の入手方法・インストール方法
- CakePHP2系の入手方法・インストール方法
- CakePHP1系(CakePHP1.3)をPHP7・PHP8以降に対応させる方法
- CakePHP1系(CakePHP1.3)の入手方法・インストール方法
- Composerコマンドでウクライナへのメッセージが表示されたことがあります
- Composerをインストールする方法と使い方
- コーディング規約のチェックを行う・整形する標準ツール(PHP CodeSniffer)の使い方
- Seedの実行順(外部キー制約などを先に実行させる方法) Foreign key violation
- PostgreSQLでERROR: duplicate key value violates unique constraint "hoge_pkey" DETAIL: Key (id)=(10) already exists.と出る場合
- PostgreSQLで自動採番をするシーケンス(sequence)とは【AUTO INCREMENT】
- Apacheで所有権や書き込み権限があるにも関わらずPermissions deniedが出る場合
- CakePHPのバージョンごとのシステム要件
- 1つのフィールドにバリデーションエラーを1つだけ表示させる方法
- PHP Strict Standards: Non-static method と出る場合の対処法
- CakePHPでカラムを比較してSELECTする方法
- [CakePHPのバグ]キャッシュ処理でunlinkエラーが発生する
- 『id』以外のプライマリキーのカラム名を使用する方法
- プライマリキーIDを連番数字ではなく推測しにくい文字列にする方法
- 複数のデータベースを切り替える方法(別データベースを使用する)
- MySQLで文字化けを防ぐ方法
- action名にlistは使えない listを使う方法
- ログイン認証処理をする方法
- CakePHP、Symfony、Zend Frameworkの比較
- CakePHPのDB接続情報設定
- ファイル読み込みPATHを設定
- デバッグレベルを設定
- セキュリティレベルの設定
- キャッシュを有効にする
- CakePHPのエラーテンプレートの一覧
- データベーステーブルを参照しないページを作る
- TOPページはIndexControllerではない Cannot redeclare config()
- ディレクトリ構成
- CakePHP
スポンサーリンク