前言撤回日記

Fixing a CakePHP 404 error

080823cakephp.jpg
CakePHPというPHPフレームワークが便利で重宝しているのだけれども、ローカル環境で動いていた物がサーバにアップロードしたら動かなくなった。特定のactionで「The requested address was not found on this server」と表示される。
いろいろと原因を探っているうちに、app/config/core.phpでDEBUG定数を0(production)にした際に、controllerで$usesにセットしたmodelが読み込まれなくなり、そのためNot foundになるらしい所まで判明。

で、解決方法として、こちらに
CakePHPのdebugレベルをproductionにするとThe requested address was not found on this server.になる問題 (山本隆の開発日誌)

問題があったのは、app/tmpフォルダとその下のフォルダのアクセス権でした。
tmpフォルダの下には、cacheフォルダやlogフォルダがあります。
おそらく、ここにファイルを作成できなかったためエラーが発生していたのではないかと思います。


とあったので、とりあえずパーミッションを777に変更してみたものの残念ながらウチでは解決せず。
で、結果的にapp/tmp/cache/models/に入っているDB Listのキャッシュファイルを削除したら問題なく動作した。
どうやらmodelを追加する前の状態がキャッシュされていたため、新規に追加したmodelが読み込まれなかったようだ。

けっこうハマったので同じ悩みを抱えた人のためにもメモっておきます。

参考:Nabble – Re: 404 Not found on existing controller and action(ここでは特にpersistent/をクリーニングする、と書かれてますな。)

MT3@localhost(まとめ)

さて、ここまでの長い道のりを経て思うのは、知識と実践の隔たり、という物だ。
やった事のない人ほど「そんなのローカルにサーバ立ててMT突っ込んでテスト運用すればいーじゃん」とか簡単に言いがち。
知識としてそれが「可能である」という事を知っているからだ。

けれどもそれを「実現する」という時には整理された知識などでは想定し得ない、様々なトラブルに遭遇する。
マニュアルにはウソが書いてあり、ある環境ではうまくいった事も環境が変わると少しもうまくいかず、ネットの情報はどんどん古くなってゆく。

googleという有名な会社があるが、そこではアイディアを出す事自体はさほど評価されないそうだ。
そのアイディアをとりあえず「動く状態」にして初めて評価の対象になるという。
考えてみれば確かにそれは現実的な評価方法だ。
おそらく世のアイディアと称される物は、自分に可能だから、という「提案」は存外に少なくて、どうせやるのは自分じゃないし、というスタンスでの「思いつき」がほとんどだと思うから。

というワケで目の前の問題に対して「こーすればいーじゃん」「あーしたら解決じゃん」「そんな事しなくてもできると思うけど」とかいう人にはとりあえず「じゃあ、やってみて」と言おう。

MT3@localhost(後編)

とりあえず正常に稼働しているのでこれで完了か、と思ったのだが、実はこの設定だとLAN上の他のマシンからの運用がしづらい。
理由はスタティックファイルやアーカイブなどの参照先として指定しているIP127.0.0.1がlocalhostであり、他のマシンでアクセスした場合にはそのマシン自体を指している事になってしまうからだ。
これを解決するために、ルータのIP割り当てをDHCP経由ではなく手入力で行い、そこで割り振ったサーバ機のIPアドレスを指定してやる必要がある。

例えばサーバに割り振ったIPアドレスが192.168.100.253だとしたら~ユーザー名/hogehoge/cgi-bin/mt/mt-config.cgiを以下のように設定する。

CGIPath  http://192.168.100.253/~ユーザー名/hogehoge/cgi-bin/mt

StaticWebPath  http://192.168.100.253/~ユーザー名/hogehoge/blog/mt-static


さらにMovable Typeの設定画面でサイトURL:を

http://192.168.100.253/~ユーザー名/hogehoge/blog/


に設定する。

これでLAN上の他のマシンから見てもサーバ機で見るのと同じように編集、運用ができる。

MT3@localhost(中編)

さてどうやらMTとモジュールのインストールが完了した。

ログインしてブログを作成し、設定画面へ移る。
サイトURL:には

http://127.0.0.1/~ユーザー名/hogehoge/blog/


サイト・パス:には

http://127.0.0.1/~ユーザー名/hogehoge/blog


と入れて変更を保存。
読み込み/書き出し画面>エントリーの読み込みでバックアップファイルを読み込む。

phpMyAdminからデータベースを参照すると、無事テーブルが追加されている。メデタシメデタシ。

それからサイトを再構築する。
完了したのでサイトの確認でhttp://127.0.0.1/~ユーザー名/hogehoge/blog/を見るも、index.htmlではなくファイルリストが表示される。
実際フォルダの中を見ても、サイトはまったく構築されていない。
自分で放り込んだmt-staticフォルダが淋しくぽつんと置かれているのみである。

何度も設定を書き換えてトライしたがまったく進展しない。
探しまわってみると~/hogehoge/cgi-bin/mt/の中に「http/」という名前の付いた不吉なフォルダがある。
中を見ると「127.0.0.1」、さらにその中に「~ユーザー名」……。
何の事はない、設定したパスに相当するフォルダをmtフォルダ内に勝手に生成してサイトを構築している。

とりあえずその中にアクセスする限り、ブラウザでも確認はできた。だがローカルのリンクがすべてhttp://127.0.0.1/~ユーザー名/hogehoge/blog/に張ってあるのでアーカイブなどが根こそぎ「Not Found」になってしまう。
サイトの確認でも「Not Found」なので不便な事この上ない。

で、試行錯誤の結果、設定画面でサイト・パス:をmtフォルダからの相対パス(この場合「../../blog」)にしたらやっと解決した。
注釈には

絶対パス (/で始まる) をお勧めしますが、Movable Typeがインストールされた場所からの相対パスも使えます。


と書いてあったのだが。
実際お勧めされている「/」からの絶対パスも試したがエラーになり、ますます事態が悪化しただけである。ワケ判らん。

MT3@localhost(前編)

phpMyAdmin経由でのバックアップに挫折したのでMovable Typeをインストールしてバックアップ用のサイトをローカルに構築する事にした。その方がテンプレートの編集やプラグインのテストも手元でできて都合がいいだろう。
ちなみにOSはMacOS X 10.4.7 Tiger、DBはmySQL。

まずはMovable Type3.33の個人ライセンス版をECバイヤーズからダウンロード。

ワーキングディレクトリに展開してフォルダ名をmtへリネーム。
以下のサイト構成で、かつCGIが使えるようにシンボリックリンクも作成してあると仮定する。

サイトルート

├―hogehoge
  |
  ├―blog
  |
  ├―cgi-bin

まずmtフォルダを~ユーザ名/hogehoge/cgi-bin/に置き、さらにその中のmt-staticフォルダを外に出して、~ユーザ名/hogehoge/blog/に置く。
それぞれパーミッションを777に。

~ユーザ名/hogehoge/cgi-bin/mt/mt-config.cgi-originalを~ユーザ名/hogehoge/cgi-bin/mt/mt-config.cgiにリネームして編集。

CGIPath http://www.example.com/path/to/mt/



CGIPath http://127.0.0.1/~ユーザ名/hogehoge/cgi-bin/mt



StaticWebPath http://www.example.com/mt-static

StaticWebPath http://127.0.0.1/~ユーザ名/hogehoge/blog/mt-static

Database DATABASE_NAME

Database ブログで使用するDB名

DBUser DATABASE_USERNAME

DBUser ブログで使うDBのユーザー名

DBPassword DATABASE_PASSWORD

DBPassword ブログで使うDBユーザのパスワード


さらにその他の各DB用の設定をコメントアウトする。

ブラウザからhttp://127.0.0.1/~ユーザ名/hogehoge/cgi-bin/mt/mt-upgrade.cgiを実行。

さらにhttp://127.0.0.1/~ユーザ名/hogehoge/cgi-bin/mt/にアクセスして初期画面からmt-check.cgiを実行する。

Movable Typeのシステム・チェックは、無事に完了しました。

と出るので初期画面からログインしようとするもエラー。

Can’t locate DBI/DBD.pm in @INC

とか言っている。
再度システムチェック画面を見ると、どうやらDBIモジュールとDBD::mysqlモジュールがインストールされていないという事のようだ。

060930error02.jpg
というワケでCPANからのモジュールインストール初体験。
しかし案の定ここでもドハマりした。面倒くさいので手順のみメモっておく。

まずデフォルトのOSXにはmakeコマンドがない(!)。makeコマンドを追加するためにはWebObjectsをインストールする必要があるのだが、WebObjectsをインストールするためにはその前にXcodeToolsをインストールしなくてはならない(ややこしい)。
なのでまずAppleのサイトからXcodeToolsをダウンロードし、同梱されているmpkgをXcodeTools.mpkg、WebObjects.mpkgの順でインストールする。

その後ターミナルからsudo suでルートになり、

# perl -MCPAN -e shell

と打ち込んでリターン。
初期設定の項目がズラズラ出て来るが基本的にはリターンキーを押し続ければいい。
CPANサーバの選択の時は適当なサーバを選択して先頭の数字をタイプし、リターン。
プロンプトが「cpan> 」に変わったら準備完了。
まず、

cpan> install DBI

とタイプ。
インストールログがダラダラ出たあと大概エラーになるので
qとタイプしてリターンでcpanから抜け、

# cd ~/.cpan/build/DBI-1.52/

でcpanディレクトリのダウンロードフォルダ内にあるDBI-1.52(今さっきダウンロードしたフォルダ)へ降りて

# perl Makefile.PL

とタイプ。またもやダラダラとログが表示されるがプロンプトが出てくるまでボンヤリ待つ。

その後

# make
# make test
# make install

の順でコマンドを実行する。
成功したら(失敗したらやりなおそう)今度はDBD::mysqlモジュールのインストール。

# cpan

でcpanに入り、

cpan> install DBD::mysql

どうせ失敗するので先ほどと同じように

# cd ~/.cpan/build/DBD-mysql-3.0007/
# perl Makefile.PL
# make
# make test
# make install

の順で実行する。エラーが出たら日頃の行いを悔い改め、再ダウンロードしてやり直す。

成功したらmt-check.cgiを実行。

DBI (version >= 1.21)
サーバーには、DBIがインストールされています。(バージョン: 1.52)

DBD::mysql
サーバーには、DBD::mysqlがインストールされています。(バージョン: 3.0007)

となっていれば無事Movable Typeが起動できるハズ。
060930error03.jpg
ところがそれで終わりじゃないんである。
以下次回。

phpMyAdmin

修理に出したG4が帰ってきた。修理費は一律で51,450円らしい。で、前回せっかく立てたwebサーバとmySQLサーバもすべて初期化してしまったので再度設定。

ついでに普段作業しているワーキングディレクトリでもCGIが動作するようにシンボリックリンクを作っておく。
/etc/httpd/users/ユーザー名.confを編集。

Options Indexes MultiViews ExecCGI Includes

Options Indexes MultiViews ExecCGI Includes FollowSymLinks


ターミナルから

$ ls -l ワーキングディレクトリへのパス サイトルートへのパス

以上で完了。

その後このblogのデータをローカルのデータベースにバックアップする事にした。
まずレンタルサーバで用意されているphpMyAdminを使ってファイルをエクスポート。

で、インポートするのにローカルにも同じ環境があった方がよかろうとphpMyAdminをインストール。
サイトルートに展開してフォルダネームをphpMyAdminにリネームする。
まあ、そのままじゃ動きっこないよな、と思いながらブラウザでアクセスすると、案の定エラー。期待を裏切らない。

060930error01.jpg
セットアップスクリプトとやらでウダウダやるも、ちっともうまく行かない。
とりあえずmySQLが動作している事は確認。さらにphpMyAdminディレクトリにphpinfo.phpを放り込み、パスが通っている事もPHPが正常に動作している事も確認。

そこでまずドキュメントに従ってphpMyAdminディレクトリ直下のconfig.sample.inc.phpをconfig.inc.phpにリネーム。

このconfig.inc.phpを以下のように編集。

$cfg['blowfish_secret'] = ”

$cfg['blowfish_secret'] = ‘半角英数モードでキーボードを適当に(48回以内で)タイプ’


$cfg['Servers'][$i]['controluser'] = ‘pmausr’;


$cfg['Servers'][$i]['controluser'] = ‘自分で決めたユーザーネーム’;

$cfg['Servers'][$i]['controlpass'] = ‘pmapass’;

$cfg['Servers'][$i]['controlpass'] = ‘自分で決めたパスワード’;


まだ動かないのでさらに調べてみると、どうやらlocalhostではなく127.0.0.1でアクセスする必要があるらしい。
なので続けてconfig.inc.phpを

$cfg['Servers'][$i]['host'] = ‘localhost’;

$cfg['Servers'][$i]['host'] = ’127.0.0.1′;

に書き換えた。

再度アクセスすると今度はベーシック認証のポップアップでパスワードを聞かれる。
ユーザ名とパスワードを入力。
エラー。メッセージは#2002以降、文字化けしていて不明。
でもエラーナンバーは最初に出たヤツと同じだから事態は好転してはいないようだ。

で、あれこれ調べた結果、phpのMYSQL_SOCKETのパスがmySQLのsocketのパスと食い違っているのが原因だった。

ターミナルから

sudo su

でrootになり

# /usr/local/mysql/bin/mysql -p

してMySql monitorに入る。

mysql>status;

で調べると

UNIX socket: /tmp/mysql.sock

となっている。

一方、phpinfo()でMYSQL_SOCKETを確認すると

/var/mysql/mysql.sock

となっていた。

というワケで/ect/php.iniを編集。
661行目を

mysql.default_socket =

mysql.default_socket =/tmp/mysql.sock

に編集し、apacheを再起動。phpinfo()でmysql.default_socketの項目を見るとno valueから/tmp/mysql.sockに変更されている。

これでようやくphpMyAdminのインストールが完了した。

……のだが、肝心のバックアップデータがインポートできない。
新規のデータベースも作れるし、特権も設定できるのに、何度トライしてもテーブルは0のままだ。
仕方がないのでローカルにMovable Typeをインストールして、そこから読み込む事にした(心地よい徒労感)。

足踏みSQL

さて仕事も少し詰まってきたものの、しばしそれらをうっちゃったままサーバ関連をいじくっていた。
まずはDBで遊ぼうと思ってmySQLをインストール。
これは公式サイトからパッケージをダウンロードしてダブルクリックするだけだったのでめちゃくちゃ簡単。おそらくMac OSX版が一番簡単なのではないだろうか。起動や停止もMySQL.prefPaneを使えばシステム環境設定パネルから行える。

そのあとがハマった。

PHP本の巻末に載っていたmySQLのインストール手順を見ながらrootのパスワードを設定し、anonymousユーザーを削除した。

mysql> SELECT Host,User,Password FROM mysql.user;

とすると、Userはrootのみになり、先ほど設定したパスワードが表示されている。
よしよし、今日はこれぐらいにしておこう。

翌日、さてテスト用のDBでもCREATEするか、と思ったらmysqlにアクセスできない。前日に設定したパスワードを間違いなく入力しているのにである。

$ /usr/local/mysql/bin/mysql
ERROR 1045 (28000): Access denied for user ‘kohashijunji’@'localhost’ (using password: NO)

$ /usr/local/mysql/bin/mysql -p
Enter password:
ERROR 1045 (28000): Access denied for user ‘kohashijunji’@'localhost’ (using password: YES)

$ /usr/local/mysql/bin/mysql -u root
ERROR 1045 (28000): Access denied for user ‘root’@'localhost’ (using password: NO)

$ /usr/local/mysql/bin/mysql -u root -p
Enter password:
ERROR 1045 (28000): Access denied for user ‘root’@'localhost’ (using password: YES)

と言った具合。
suしてroot権限で実行しても結果は同じ。ことごとくアクセス拒否される。
さんざん悩んで、とりあえずパスワードを確認する事にした。
mySQLは起動時に–skip-grant-tablesオプションを指定するとユーザー確認用のデータを読み込まずに起動できる。
一旦mySQLを終了してからターミナルで

$ /usr/local/mysql/bin/mysqld_safe –skip-grant-tables

と打ち込んで起動する。
新規シェルを開いて

$ /usr/local/mysql/bin/mysql

でmySQLに無事アクセス。
前日のようにmysql> SELECTするとやはりrootユーザーと昨日設定したパスワードが表示される。でもアクセスはできない。さっぱり判らん。

再度あきらめてさらに翌日。ハタと思いついてMySQLのリファレンスに沿ってパスワードを再設定したところ、今度はちゃんとrootでアクセスできるようになった。
つまり、本に書かれていたパスワード設定のコマンドが間違っているようなのだ。
mySQLは設定されたパスワードを符号化してから入力されたものと比較する(あるいは入力された物を暗号化してから比較するのかも)。
本の解説ではrootのパスワード設定は

mysql> UPDATE mysql.user SET Password=’abcd’ WHERE User=’root’;
mysql> FLUSH PRIVILEGES;

となっている。だがそれではパスワードは暗号化されないのだ。暗号化されていないパスワードをさらに符号化して入力と比較しても当然一致するはずがない。
正しくは

mysql> UPDATE mysql.user SET Password=PASSWORD(‘abcd’) WHERE User=’root’;
mysql> FLUSH PRIVILEGES;

なんである。

こうした後でmysql> SELECTすると今度は暗号化されたパスワードが表示された。

ひとまずはメデタシであるが、仕事が詰まってきていまだにテスト用DBは構築できていない。すなわちスタートラインから一歩も進んでいない状態。
まるで免許を取ったのにずっと駐車場の中でエンジンをかけたり切ったりブレーキ踏んでみたりしているようだ。
はやく公道に出るところまで行ってみたいです。

宗旨替え

この間までこのカテゴリーではPerlでウニウニやってみようかと思ってたんだけど、やっぱまずPHPからイジる事にする。
理由はカンタンそうだから。

あれだけ単純なファイル構成の「YukiWikiMini」でさえセッティングにえらく手間取ったので、より高機能な「PukiWiki」にいたっては相当ハマるに違いない、と思ったら拍子抜けするほどあっさり動いた。
単に初期設定ファイルに管理パスワードを書き込み、サーバに放り込んだら添付されているテキストの指示にしたがってディレクトリのパーミッションを設定していくだけ。
いじってるうちに2回くらいエラーが出たがそこに書かれているファイルのパーミッションを変更したら完了。

で、「YukiWikiMini」はPerl、「PukiWiki」はPHPで書かれていたんですな。
俄然PHPに興味がわいたので初心者向けPHP解説サイトをのぞき、サンプルコードをいくつも試したところ何一つ手こずる事がなかったという。

前回どハマりしたおかげで作業に慣れたせいもあるけど、なにせパスを通す必要すらないというのがいい。phpinfo.phpも何もしなくても動いたし、クソいまいましいInternal Server Errorを見なくて済むのもうれしい。

では何をするかというと具体的にはまだ決まってないのだが、とりあえずデータ送受信とDBとのやり取りを、サンプルコードの切り貼りでどこまでできるか試してみようかと思う。
って結局コード書かないのかよ、というハナシなのだが、僕がおもしろそうだな、と思うようなことは大抵、たとえばDBとやり取りした「先」にあるのだ。ところが僕のような単なるデザイナー風情にはそのDBとのやり取り、という所までの敷居がとんでもなく高い。プログラマーにはなんてことない作業がじつにシンドイ苦行なんである。
そんな面白くも何ともない所で足踏みしていたらやる気なくなっちゃいます。

あと、既存の物を組み合わせるだけでけっこう色んな事できちゃいそうな気がする、というのもある。

というワケでさっそくPHPサンプルコードの本とMySQLの本を一冊づつ買ってきた。さーて遊ぶぞー。

感動の完動

とりあえず動いたので何か書き込んでみる。
で、書き込んだあと「write」ボタンをクリック。

Error (dbmopen)

かーっまたエラーか!
どうもデータベースファイルが開けないっぽい。
フォルダをみるとそれらしいファイルがない。
いぶかしく思いながら探し回ると、なぜか一つ上の階層にデータベースファイルが作られている。

これをプログラムソースと同じフォルダに移動。
だがまだエラー。ソースの中のデータベースファイル名をフルパスに書き換える。再度エラー。
結局データベースファイルのパーミッションを777に設定したらようやく動いた。

長い道のりである。プロが作った、完成されたプログラムを設置するだけでこの有様。
プログラミングってただごとじゃないですね(ソース一行も書いてない)。

YukiWikiMini

さて、CGIの動作も確認できたので、Web上で配布されているプログラムをローカルサーバで動かしてみることにする。

不特定多数の人が閲覧だけではなく編集する事を前提に作られたサイトがある。
例えばウィキペディアなどだ。
こういったサイトはwikiエンジンと呼ばれるプログラムを使って作られている。
僕は結城浩さん作のwikiエンジン「YukiWikiMini」をレンタルサーバ上で動かしてメモ帳代わりにしているのだが、これをローカルで動かしてみよう。……って順序が逆のような気もするけれども。

まずプログラムソースをダウンロードする。中身は以下の3つのファイル。

「ykwkmini.cgi」 プログラム本体
「jcode.pl」 perlで日本語を扱うためのライブラリ
「ykwkmini.txt」 プログラムの簡単な説明とか

この中で稼働に必要なのは上の2つだけ。いたってシンプル。

これらの入ったフォルダを/ユーザー/(ユーザー名)/サイト/に置いてブラウザからアクセスしてみる。

「Not Found」

なんでだよ! どう見てもあるじゃんココに!
もしかしてサブディレクトリに入ってるとダメとか?
で、出してみて再アクセス。

「Internal Server Error」

……少しマシになった。
とりあえずパーミッションを設定。

「Internal Server Error」

ダメか。
このぶっきらぼうなエラーメッセージでは何の事やら分からないのでターミナルで動かしてみる。

「Can’t locate jcode.pl in @INC」

jcode.plが@INCの中に見つかりません?
なんのこっちゃ。
試しに「ykwkmini.cgi」をmiで開いてみると
require ‘jcode.pl’;
の一行がある。外部ソースを読み込むにはrequire ‘ファイル名’;という命令文を使うのだろう。
でも「jcode.pl」はちゃんと同じディレクトリに入ってるじゃないの……。

改行コードを確認するとCRになっていた。
これをLFに修正。

おお、動いた動いた。

Copyright © 2004 elbro.net