web-dev-qa-db-ja.com

mod_rewriteRewriteRuleでの相対置換

Webページがインストールされている場所から独立したmod_rewrite RewriteRuleを作成したいと思います。 .htaccessファイルで書き換えルールを定義したい。これを例として取り上げましょう。

RewriteEngine on
RewriteRule ^(.*)\.html html.php

このルールを使用して、すべての* .htmlリクエストをWebルートにあるhtml.phpスクリプトにマップします。問題は、webrootのパブリックベースURLが変更される可能性があることです。したがって、Webルートはhttp://www.somewhere.tld/またはhttp://www.somewhere.tld/foo/bar/のサブディレクトリに配置できます。

ただし、書き換えルールで相対パスを使用することはできません。だから私はこれらの1つを書かなければなりません:

/html.php (When web is located in root directory of the web)
/foo/bar/html.php (When web is located in foo/bar sub directory)

または、RewriteBaseを設定することもできますが、このパスをまったく構成したくありません。 Apacheが自動的に正しいことを実行するようにしたいので、Webをあるディレクトリにコピーするだけで、Webがどこにあるかを書き換えルールに指示しなくても機能します。これを行うにはどうすればよいですか。

7
kayahr

私の知る限り、あなたがこれを達成できる方法はありません。 RewriteBaseを構成する必要があります。 1つの方法は、PHPスクリプトを使用してRewriteBaseの設定を自動化することです。ただし、少なくとも.htaccessへの書き込み権限が必要です。ただし、.htaccessでRewriteBaseを構成する必要があります。 。

2

私は同じ問題に、同じ理由で苦労してきました。構成スクリプトや手動のユーザー介入に頼ることなく、Webアプリをインストール場所から独立させようとしています。アプリをどこかにドロップして、その機能を実行させます。

そして、少なくともApache 2については、結局のところ解決策があるようです。4行かかります。その背後にある考え方を説明するには、4行以上かかりますが;)

Tl; drこれを試してください:

_RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond $1#%{REQUEST_URI} ([^#]*)#(.*?)\1$
RewriteRule ^(.*)$ %2index.php [QSA,L]
_

これがその方法と理由です

  • RewriteBaseを動的に設定することはできないため、サーバーのルートURL _RewriteBase /_に一度だけ設定します。これは一貫性を提供しますが、現在のディレクトリへのurl-pathを自分で確立し、書き換えられたURLのプレフィックスを付ける必要があることも意味します。

  • では、どのディレクトリにいますか?/some/path/app-root/virtual/stuffの_REQUEST_URI_を想定しましょう。私たちのhtaccessはapp-rootにあります。仮想部分(virtual/stuff)を取得し、それを_REQUEST_URI_から削除すると、アプリディレクトリへのurl-pathが残ります。

  • 仮想パーツのキャプチャは簡単で、書き換えルール自体で発生する可能性があります。 RewriteRule ^(.*)$ ...は、_$1_変数で使用できるようにします。

  • ここで、小さな文字列操作を実行し、リクエストURIから仮想部分を削除します。そのための文字列コマンドはありませんが、RewriteCondは文字列を照合し、部分文字列をキャプチャできます。そのため、現在のディレクトリへのurl-pathを抽出することを唯一の目的としてRewriteCondを追加します。それ以外は、「条件」は私たちの邪魔にならないようにし、常に真実でなければなりません。

  • Mod_rewriteは実際にはルールセットを逆方向に処理するため、RewriteCondのRewriteRuleから_$1_変数を使用できます。ルール自体のパターンから始まり、一致する場合は条件のチェックに進みます。したがって、変数はそれまでに使用可能になります。

  • RewriteCondのテスト文字列は変数を使用できますが、実際の条件の正規表現は使用できません。条件内では、内部後方参照のみを使用できます。そこでまず、テスト文字列「[仮想パーツ] [一部のセパレータ] [リクエストuri]」を組み立てます。 '#'文字は、URLに表示されないため、適切な区切り文字になります。次に、の条件と照合します

    _([^#]*) - anything up to the separator, captures the virtual part
    #       - the separator
    (.*?)   - anything in the request uri up to what we've captured in group one,
              grabs the current directory url-path
    \1$     - group one again, ie the virtual part of the request uri
    _

    したがって、完全な条件は次のとおりです:RewriteCond $1#%{REQUEST_URI} ([^#]*)#(.*?)\1$

  • RewriteCond正規表現で2番目にキャプチャされたグループは私たちの場所です。書き換えられたURLの前に_%2_参照を付ける必要があります。これでRewriteRule ^(.*)$ %2index.php [QSA,L]が残ります。 Voilà。

私はまだ大規模なテストを行っていませんが、通常の仮想ホストだけでなく、大量の仮想ホスティング(VirtualDocumentRootを使用)でも機能することを確認しました。含意によって、他のエイリアスされた場所も同様に問題ないはずです。

Apache 1.3

残念ながら、Apache 1.3はまだ存在しており、RewriteCondパターンでチョークします。 Apache 1.3は、貪欲でない修飾子(_(.*?)_の「?」)をサポートしていません。

しかし、Apache 2の場合は、うまくいくはずです。ただし、特にご使用の環境で失敗した場合は、フィードバックをいただければ幸いです。

編集:この件に関するより包括的な記事を私の ブログ ( " mod_rewriteを使用してRewriteBase ")を知らなくても.htaccessファイル。詳細については、こちらをご覧ください。

11
hashchange

Apacheのドキュメント は誤解を招くと思います:

.htaccessファイルでリライトエンジンを使用する場合、ディレクトリごとのプレフィックス(特定のディレクトリでは常に同じ)RewriteRuleパターンマッチングのために自動的に削除され、相対(スラッシュまたはで始まらない)の後に自動的に追加されますプロトコル名)置換は、ルールセットの終わりに遭遇します。相対置換に追加されるプレフィックスの詳細については、RewriteBaseディレクティブを参照してください。

ただし、追加するプレフィックスは完全に異なります(元のURLではなくディスク上のパス)。これが正しい振る舞いになる状況は考えられません。

1
Jay K

この文脈で「ウェブルート」の場所を実際に決定するものは何かという質問では明確ではありませんか? (ドキュメントルートとは明らかに異なるため。)

答えるために、「Webルート」はWebアプリケーションがインストールされているディレクトリであると仮定します。これは、この「Webアプリケーション」を制御する_.htaccess_ファイルの場所でもある必要があります(ドキュメントルートではありません)。

その場合、canは単に相対パス置換を使用します。 してはいけませんRewriteBaseディレクティブを使用します(これは、後で追加され、「動的に」設定できないディレクトリプレフィックスをオーバーライドします)。

したがって、「Webルート」が_/foo/bar_の場合、_.htaccess_の_/foo/bar/.htaccess_は次のようになります。

_RewriteEngine On
RewriteRule \.html$ html.php [L]
_

RewriteRulepattern接尾辞^(.*)はここでは不要です。)

したがって、_/foo/bar/baz/something.html_の要求が与えられると、要求は内部的に_<document-root>/foo/bar/html.php_(ファイルシステムパス)に書き換えられます。 _<document-root>/foo/bar/_は、すべての相対パス置換に追加される「ディレクトリプレフィックス」(_.htaccess_ファイルの場所のファイルシステムパス)です。


標準のフロントコントローラーパターン(_.htaccess_にある_<web-application-root>/.htaccess_ファイル):

_RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
_

RewriteBaseディレクティブを設定しないでください。


このページの質問とすべての例は、外部リダイレクトではなく内部書き換えを扱っていることに注意してください。 外部リダイレクトを処理している場合にのみ、有効なベースURL(またはRewriteBase)を(動的に)設定/計算する必要があります。外部リダイレクトの場合にディレクトリプレフィックスを相対substitutionに追加し直すことを許可すると、おそらく無効なリダイレクトが発生する可能性があります。

0
MrWhite

のようなものはどうですか

RewriteEngine on
RewriteRule ^(.*)\.html $1/html.php

私の例では、htmlファイルのファイル名部分を保持していますが、たとえば、page1.htmlはpage1 /html.phpにリダイレクトされます。 (注:これはまったくテストしていません。自己責任で試してください:))

また、 mod_rewrite guide には、問題に似た例がたくさんあります。すでにそれを見ましたか?

0