概要
開発環境がWin+Xamppなんですが、この環境でログイン・ログアウト・会員登録時のリダイレクトに失敗してしまう問題があって困っておりました。同じ構成のEC-CUBEでLinuxサーバで動かすと問題は起きません。今日ようやく原因がわかったのでメモしておきますね。
このTIPSはWindowsでEC-CUBEを使っており、なおかつログイン後のリダイレクトに失敗する*1 方が対象になっておりますので、該当しない場合はこのTIPSの実践はおやめください。
後述の「解説」に事の次第を書いておきますので該当しない場合でも何かの参考にはなるかもしれません*2 。
もしかするとXamppのバージョンに依存するかもしれないので、
Xamppバージョン:1.7.0
+ Apache 2.2.11
+ MySQL 5.1.30 (Community Server)
+ PHP 5.2.8 + PEAR (Support for PHP 4 has been discontinued)
+ PHP-Switch win32 1.0 (use “php-switch.bat” in the xampp main directory)
+ XAMPP Control Version 2.5 from www.nat32.com
+ XAMPP Security 1.0
+ SQLite 2.8.15
+ OpenSSL 0.9.8i
+ phpMyAdmin 3.1.1
+ ADOdb 4.990
+ Mercury Mail Transport System v4.52
+ FileZilla FTP Server 0.9.29
+ Webalizer 2.01-10
+ Zend Optimizer 3.3.0
+ eAccelerator 0.9.5.3 f・ PHP 5.2.8 (but not activated in the php.ini)
あと、もしかするとEC-CUBEをインストールするときに僕が間違ったことをしているという可能性もありますので、この点については「あとがき」を参照してください。
解決策
解決策から書きますね。お急ぎの方はこちらだけチェックしていただければOKです。
まずは、/data/class/pages/LC_Page.phpのgetRootPathメソッドを開いてください。
定数:PHP_OSの頭三文字が’WIN’の場合の$htmlPathの代入部分の式を以下のように変更します。
変更前
function getRootPath($path) { // $path が / で始まっている場合 if (substr($path, 0, 1) == "/") { $realPath = realpath(HTML_PATH . substr_replace($path, "", 0, strlen(URL_DIR))); // 相対パスの場合 } else { $realPath = realpath($path); } // HTML_PATH を削除した文字列を取得. // FIXME OS依存の処理は別クラスに分ける? // Windowsの場合は, ディレクトリの区切り文字を\から/に変換する if (substr(PHP_OS, 0, 3) == 'WIN') { $realPath = str_replace("\\", "/", $realPath); $htmlPath = str_replace("\\", "/", HTML_PATH); $rootPath = str_replace($htmlPath, "", $realPath); } else { $htmlPath = rtrim(HTML_PATH, "/"); $rootPath = str_replace($htmlPath, "", $realPath); $rootPath = ltrim($rootPath, "/"); } return $rootPath; }
変更後
function getRootPath($path) { // $path が / で始まっている場合 if (substr($path, 0, 1) == "/") { $realPath = realpath(HTML_PATH . substr_replace($path, "", 0, strlen(URL_DIR))); // 相対パスの場合 } else { $realPath = realpath($path); } // HTML_PATH を削除した文字列を取得. // FIXME OS依存の処理は別クラスに分ける? // Windowsの場合は, ディレクトリの区切り文字を\から/に変換する if (substr(PHP_OS, 0, 3) == 'WIN') { $realPath = str_replace("\\", "/", $realPath); $htmlPath = str_replace("\\", "/", rtrim(HTML_PATH, "/")); $rootPath = str_replace($htmlPath, "", $realPath); } else { $htmlPath = rtrim(HTML_PATH, "/"); $rootPath = str_replace($htmlPath, "", $realPath); $rootPath = ltrim($rootPath, "/"); } return $rootPath; }
str_replaceの中の$subjectに定数:HTML_PATHがありますが、この定数の最後の’/’をトリムしてあげてください。これでリダイレクトに失敗することがなくなると思います。
解説
何かトラブルがあるときには処理を順に追っていけばおのずと答えは見つかります。
まずはどこで問題が起こっているかを調べるためにログインを例にして処理を追ってみましょう。
- ログインフォームのログインボタンを押すと/html/frontparts/login_check.php読みにいきます。
- /html/frontparts/login_check.phpではLC_Page_FrontParts_LoginCheck_Exクラスのインスタンスを作成してinitメソッドやprocessメソッドを呼んでますね。
- 各ページの_Exクラスは/data/class_extends/page_extendsにあるので、探します。元ファイルは/frontparts/login_check.phpでしたので、/data/class_extends/page_extends/frontparts/LC_Page_FrontParts_LoginCheck_ex.phpですね。
- もちろんここには通常何も書かれておらずLC_Page_FrontParts_LoginCheckクラスを継承しているだけですから、その継承元を見なければいけません。/data/class/pages/frontparts/LC_Page_FrontParts_LonginCheck.phpですね。慣れれば自分がメソッドを追加してなければclassを見ればいいというのがわかると思います。
- LC_Page_FrontParts_LoginCheckのprocessメソッドを見ると$this->sendRedirectを呼んでいるところがあります。「おそらくsendRdirectにURLを渡してリダイレクトするんだな」と当たりがつきますね?そしたら渡しているURLの部分「$this->getLocation」のほうに注目しましょう。どうやらこのメソッドがURLを組み立てるようです。「$this->getLocation」LC_Page_FrontParts_LoginCheckクラスが継承しているLC_Pageクラスにありますので/data/class/pages/LC_Page.phpを見てみましょう。
- LC_Page.phpにgetLocationメソッドがありましたね?このメソッドの冒頭で「$this->getRootPath()」を呼んで$rootPathに代入していますね。そして、SSLを使っているのかどうかを判定して定数:SSL_URLか定数:SITE_URLと$rootPathを結合してさいごにNet_URLクラスのaddQueryStringメソッドを追加して最終的に同クラスのgetURLメソッドの返り値をreturnしていることがわかります*3 。
つまりは確認するのはLC_PageクラスのgetLocationメソッドとgetRootPathメソッドということになりますね。
このあたりを実際に動作させながらデバッグしていけば問題がはっきりするんですが、ここで注意していただきたいのは伝家の宝刀であるデバッグ用のメソッド「SC_Utils::sfPrintR( $var );」が使えないんです。なぜならこの後リダイレクトしちゃうから。
なので、ここでは「die( $var );」を使うことにします。これならdieした後の処理は走りませんからね。
一通り怪しい変数を拾って「die」してみてください。$pathはどうか?$rootPathは?$realPath,$htmlPathは?
そうこうしているうちにわかると思います。
「$this->getRootPath」で代入される$rootPathが素の$realPathになっていることに。
本来であれば$realPathの$htmlPathにあたる部分を””(空文字)でリプレースされなきゃいけないのに、$htmlPathの元である定数:HTML_PATHの最後の「/」が残っているからマッチせずにそのまま出ちゃってるんですね。
だからリダイレクトに渡すURLがおかしなことになっていたというわけです。
問題は定数:HTML_PATHの最後の「/」にあることがわかりましたので、「解決策」でも書いたように$htmlPathへの代入の際に「rtrim(HTML_PATH, “/”)」してあげたというわけです。
あとがき
この問題を調べていてまず思ったのが、インストール時に設定する「WEBサーバの設定」の「HTMLパス」の設定が間違っているのかな?ということでした。
EC-CUBEのインストール時には、自動的に「C:?xampp?htdocs?ectest?html/」のような感じで埋められているので気にせずインストールをすると、インストール後に生成されるinstall.php*4 には
define ('HTML_PATH', 'C:/xampp/htdocs/ectest/html/');
という感じで、「?」が「/」に置き換わった形で定義されることがわかりますね。
ここで疑問に思ったわけです。
先ほどの/data/class/pages/LC_Page.phpのgetRootPathメソッドでは、わざわざOS判定して「?」を「/」に置き換える処理が書かれてましたがこれって機能するの?と。
もしかしたらデフォルトで入力されていた「C:?xampp?htdocs?ectest?html/」の書き方ではいけないのではないかと思ったわけです。PHP_OSがWINの場合は最後の「/」もあえてトリムしていませんし。
でも、どのような書き方が正しいのかは良くわかりません。
定数:HTML_PATHから最後の「/」を削ってもエラーになるし、「?」はどのみちgetRootPathで「/」に変換するから関係ないし、と考えるとEC-CUBEのバグ?なんて事も思ってしまったのですが、どうなんでしょう。
もしわかる方がいらっしゃいましたら教えていただけるとありがたいです。
最後に…
読み返してみましたがやっぱり僕の記事は読みにくいですよね。。orz
どうすればわかりやすく正確に記事が書けるか考えていないわけじゃないんですが、正確に書こうと思うとこんな感じになっちゃうんですよね。他の方の記事を参考にして精進しなきゃと思っております。
記事を読んで何かお気づきの点やツッコミなどありましたらどうぞ僕を育てると思って厳しくコメントいただけるととても嬉しいです。
コメント
コメントさせていただきます。<EC?CUBE新米の者より>
リダイレクトに失敗する原因がわかり易く書いてあると思います。こうした記事がきっかけかわかりませんがec?cubeのver2.4.1ではソースが見直され『ログイン』のリダイレクト失敗が回避されている模様です。ただデバッグについて書かれている部分はよくわかりません。そのシステム環境や操作がよく見えないので。こうした改善の動きにもかかわらず、まだリダイレクトの不具合は解決しておりません。『会員登録』については、入力チェック後、登録するタイミングで『不正なページ移動です』という顧客に対して礼を欠いたメーセッジが相変わらず表示されているからです。原因が『/』以外にもあるのではと思っていますが、さっぱりわかりません。Win+Xamppの記事と同様の環境ですので解決策を載せていただけるとありがたいです。
こんにちは、石垣様。
記事を読んでいただきありがとうございます。
4月以降はほとんどEC-CUBEに触っていないので、ご期待に沿える記事をかけそうにありません。申し訳ありません。
EC-CUBE 開発コミュニティサイト – 日本発のECオープンソース
http://xoops.ec-cube.net/
こちらでは私よりもずっと深くEC-CUBEにかかわっている方もたくさんおりますので、コミュニティに参加してみてはいかがでしょうか。
私もEC-CUBEには手を焼きました。現在2.3.3を使っていますが、バグの対応や新機能の追加でかなりカスタマイズをしてしまったので、最新版にアップデートもできずホトホト困っている有様。。
現在はEC-CUBEで運用しているのとは別のサイト向けにECシステムを自社開発しているので、いずれはEC-CUBEからそのシステムに乗り換える予定です。お役に立てず申し訳ありません。