サーバ移転の舞台裏を少し。
実は、せっかくなので多言語プラグインの動作URLを、サブフォルダ(domain.com/??/)からサブドメイン(??.domain.com/)へ変更しようとしたのですが……結果、惨敗しました。何にか、といえばMod_Rewriteに、です。
ご存じない方のためにカンタンに紹介しておくと、「Mod_Rewrite」とは、URLを書き換えて、見た目のURLと実際のアクセス先を自在に操作できるようにするプラグインのことです。一般のユーザの方が意識することはまずないと思いますが、気づかぬところで様々な恩恵を受けているはずです。例えば、https://から打たずにURLをドメイン名から打ち込んでも、自動的にhttps://で始まる暗号化されたページに飛ぶようにして、利便性を向上する働きをしています。
しかしながらこの使い方が難しい。ぐぐれば、解説やサンプルは沢山あるのですが、複数ルール組み合わせたときの挙動がいまひとつ掴みきれません。
参考サイト各種
mod_rewrite モジュール – URL 書き換えエンジン
mod_rewriteリファレンス – dawgsdk.org
最終的なアクセス先URLは、「http://catswhiskers.jp/記事URL?lang=言語」というのは確定しています。
そこでまず、サブドメイン部分に言語指定を入れていた場合、例えば「http://en.catswhiskers.jp/」を「http://catswhiskers.jp/lang=en」に変換する必要があります。ここで重要なのがドメイン部分が変わるということは、たとえサブドメインのみといえど、別のサーバとして扱われる点です。つまり[P]オプションで内部プロキシ経由にしないと、リダイレクトされて見た目のURLが変わります。そのため、下記のような設定にすればOK、なはずなんですが…
RewriteCond %{HTTP_HOST} ^(en|fr|de ..中略.. |ja )
RewriteRule (.*) http://catswhiskers.jp/$1?lang=%1 [QSA,P]
この結果が何故か「404 Not Found.」 しかも通常の404とは違い、その一文のみが小さく表示されている状態です(XREAサーバでは)。ここでいきなり躓きました。ためしに[P]オプションを外して、普通にリダイレクトさせると問題なく表示されます。ということは書き換えルールは間違っていないとは思うのですが……XREAサーバはMod_Proxyが有効でないのかも?
あ、横道にそれますが、もう一つの[QSA]オプションは、その他のクエリを引き継ぐため(例えば他に?id=1がついてた場合)のものです。RewriteRuleの判定部分にクエリは含まれません。CMSなどを使っているときは、忘れるとハマりがちなので注意しましょう。ちなみにクエリ部分で何かしらマッチさせたいときは、RewriteCond %{QUERY_STRING}で判定させてください。
閑話休題。[P]オプションについてあれこれ試してみたのですが、何をやっても駄目。どう書き換わって404と言っているのか分かればと思い、ログを取ろうとRewriteLogおよびRewriteLogLevelを設定してみたのですが、XREAはどうもこのオプションは使用できないようで…… となると想像で試すしかなく、いい加減精神的限界に近づいてきたので諦めた次第であります。
さて、ではあっさり終わりかと言うとそうではなく、サブフォルダの言語指定をクエリに変換しなくてはいけません。その設定が以下です。
RewriteCond %{REQUEST_URI} ^/(en|fr|de..中略..|ja)
RewriteRule ^[-a-zA-Z]+/(.*) /index.php/$1?lang=%1 [QSA,L]
また、このサイト特有のURLとして、/blog/の下に、カテゴリ名/年月日/記事名.htmlという構造になっています。そして実はカテゴリ名はあってもなくてもきちんと表示されるようにしています。これは将来的にカテゴリ名を変更したときでも、以前のURLで記事にアクセスできるようにするためです。これを実現するために、実体はカテゴリ名なし(画像を見るとよく分かると思います)、プラグインでリンクにカテゴリ名を挿入する、という処理を内部的に行っています。そのためのリライトルールが……
RewriteCond %{REQUEST_URI} ^/(en|fr|de..中略..|ja)/blog/[^/]+/([0-9_]+/.*)$
RewriteRule (.*) /index.php/blog/%2?lang=%1 [QSA,L]
これ(上)とこれ(下)です。
RewriteCond %{REQUEST_URI} ^/blog/[^/]+/([0-9_]+/.*)$
RewriteRule (.*) /inde.php/blog/%1 [QSA,L]
さらにその後に続けて、Word Press標準のルール(下)が入ります。
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [QSA,L]
だいぶ混乱してきましたよね。ええ、私も混乱してます(笑)。おそらく私の理解が不足してるせいなのですが、書き換えたURLを次のルールにうまく渡せないのです。本来は、「言語指定部分の書き換え」->「カテゴリ名の書き換え」と順番に渡せれば、もっとすっきり書けるのですが…… 結局、
- 言語指定あり、かつ、カテゴリ名の入るURL
- 言語指定あり、かつ、カテゴリ名の入らないURL
- 言語指定なし、かつ、カテゴリ名の入るURL
- 言語指定なし、かつ、カテゴリ名の入らないURL
という4通りのルールを別個に書く羽目になっています。原因追求には、RewriteLogの取れるテストサーバを立てて実験してみるしかないかもしれません。URLと書き換えルールを入力すると、結果が出てくるようなWebツールを切望しております。。
ちなみに、WordPress標準のルールのRewriteRuleの「(.*)」ではなく「.」で済んでいるところが、個人的にはすごく不思議なのです。これだと「/test.html」へのアクセスが最初の一文字だけ変換されて「/index.phpest.html」(RewriteRuleでは最初の/は判定に含まれない)となる気がするのですが…… 実際に記事を見てみるとこれで見れているので、間違ってはいないのでしょうけど。
これで一応完成なのですが、どうもディレクトリなのに最後を/で終えないURLでアクセスするとエラーがでるので、アクセス先がファイルではない場合(拡張子がついていない場合)、最後に/を補うようにもしてたりします。……リライトだけでそれなりの負荷になりそう。
ついでにXREA特有のお話ですが、PHPがセーフモードで動いていて色々と動かないものがあったりすることが多く、CGIモードと呼ばれる形態でPHPを動かすことが定番になっています。それには.htaccessに「AddHandler application/x-httpd-phpcgi .php」を記述しておきます。
が、WordPressを動かすときは要注意です。Mod_Rewriteと組み合わせて使った場合、CGIモードのPHPはPathInfoの情報がうまく取れなくなるらしく、記事URLの形式によっては個別記事が見れなくなります(ました)。結局、セーフモードに戻して運用しています。記事の閲覧には問題ないですが、自動アップグレードができなかったりします。その他の制限についてはPHP: セーフモード – Manualを参考にしてください。
あ、そうそう。コメント投稿後にエラーが出るのもついでに直しました(ようやく…そしてたぶん)。記事URLの形式のせいか、投稿後にhttp://~//~とスラッシュを2つ連続して含むアドレスに飛ばされてしまうようなので、それを書き換えるだけのプラグインを作っていれてます(わざわざ…苦笑)。もっと根本的な直し方をご存知の方は教えてくださいm(_ _)m