web-dev-qa-db-ja.com

参照:mod_rewrite、URL書き換え、および「きれいなリンク」の説明

「プリティリンク」はよくリクエストされるトピックですが、完全に説明されることはめったにありません。 mod_rewriteは「きれいなリンク」を作成する方法の1つですが、複雑で構文が非常に簡潔でわかりにくいため、ドキュメントではHTTPのある程度の習熟度を前提としています。誰かが「きれいなリンク」の仕組みとmod_rewriteを使用してそれらを作成する方法を簡単な用語で説明できますか?

他の一般名、エイリアス、クリーンURLの用語:RESTful URL、ユーザーフレンドリーURL、SEOフレンドリーURL、スラッギング、MVC URL(おそらく誤った名前)

137
deceze

Mod_rewriteが何を行うかを理解するには、最初にWebサーバーの動作を理解する必要があります。 Webサーバーは HTTPリクエスト に応答します。最も基本的なレベルのHTTPリクエストは次のようになります。

GET /foo/bar.html HTTP/1.1

これは、URL/foo/bar.htmlを要求するWebサーバーへのブラウザーの単純な要求です。 ファイルを要求せず、任意のURLのみを要求することを強調することが重要です。リクエストは次のようにもなります。

GET /foo/bar?baz=42 HTTP/1.1

これはURLのリクエストと同じくらい有効であり、ファイルとはまったく関係ありません。

Webサーバーは、ポートでリッスンし、そのポートから着信するHTTP要求を受け入れて応答を返すアプリケーションです。 Webサーバーは、適切と思われる方法で、または応答するように構成した方法で、要求に自由に応答できます。この応答はファイルではなく、HTTP応答であり、ディスク上の物理ファイルと関係がある場合とない場合があります。 WebサーバーはApacheである必要はありません。他の多くのWebサーバーはすべて、持続的に実行され、HTTP要求に応答するポートに接続されている単なるプログラムです。自分で作成できます。この段落は、URLがファイルに直接等しいという概念からあなたを引き離すことを意図していました。これは理解することが本当に重要です。 :)

ほとんどのWebサーバーのデフォルト設定では、ハードディスク上のURLと一致するファイルを検索します。サーバーのdocument rootが例えば/var/wwwに設定されている場合、ファイル/var/www/foo/bar.htmlが存在するかどうかを調べ、存在する場合はそれを提供します。ファイルが「.php」で終わる場合、PHPインタープリターが呼び出され、thenが結果を返します。この関連付けはすべて完全に構成可能です。 WebサーバーがPHPインタープリターを介して実行するために、ファイルの末尾が「.php」である必要はなく、ディスク上の特定のファイルと一致させる必要はありません。

mod_rewriteは、内部リクエスト処理をrewriteする方法です。 WebサーバーがURL /foo/barのリクエストを受信すると、Webサーバーがディスク上のファイルを検索する前に、そのURLを他の何かにrewriteできますそれに一致します。簡単な例:

RewriteEngine On
RewriteRule   /foo/bar /foo/baz

このルールは、リクエストが「/ foo/bar」に一致するたびに、「/ foo/baz」に書き換えます。リクエストは、あたかも処理されます代わりに/foo/bazが要求されていました。これは、たとえば次のようなさまざまな効果に使用できます。

RewriteRule (.*) $1.html

このルールは、すべて(.*)およびcapturesに一致し((..))、その後「.html」を追加するように書き換えます。つまり、/foo/barが要求されたURLであった場合、/foo/bar.htmlが要求されたものとして処理されます。正規表現のマッチング、キャプチャ、および置換の詳細については、 http://regular-expressions.info を参照してください。

別のよくあるルールは次のとおりです。

RewriteRule (.*) index.php?url=$1

これもまた、あらゆるものに一致し、最初に要求されたURLをurlクエリパラメーターに追加して、index.phpファイルに書き換えます。つまり、着信するすべてのリクエストに対して、ファイルindex.phpが実行され、このファイルは$_GET['url']の元のリクエストにアクセスできるため、必要なことは何でもできます。

主に、これらの書き換えルールをWebサーバー構成ファイルに配置します。また、Apacheでは、ドキュメントルート内の.htaccessというファイル(つまり、.phpファイルの隣)にそれらを配置することもできます。

*IfプライマリApache設定ファイルで許可;オプションですが、多くの場合有効になっています。

Mod_rewriteが行うことnot

mod_rewriteは、すべてのURLを魔法のように「きれい」にするわけではありません。これはよくある誤解です。 Webサイトにこのリンクがある場合:

<a href="/my/ugly/link.php?is=not&amp;very=pretty">

mod_rewriteがそれをきれいにするためにできることは何もありません。これをきれいなリンクにするには、次のことをする必要があります。

  1. リンクをきれいなリンクに変更します。

    <a href="/my/pretty/link">
    
  2. サーバーでmod_rewriteを使用して、上記の方法のいずれかを使用して、URL /my/pretty/linkへの要求を処理します。

mod_substitute を使用して、発信HTMLページとそれに含まれるリンクを変換できます。これは通常、HTMLリソースを更新するよりも手間がかかります。)

Mod_rewriteには多くのことができ、いくつかの書き換えのチェーン、完全に異なるサービスまたはマシンへのリクエストのプロキシ、特定のHTTPステータスコードの応答としてのリクエスト、リクエストのリダイレクトなど、作成できる非常に複雑なマッチングルールがあります。基本的なHTTP要求/応答メカニズムを理解している場合、非常に役立ちます。 notは自動的にリンクをきれいにします。

可能なすべてのフラグとオプションについては、 公式ドキュメント を参照してください。

103
deceze

decezeの答え を拡張するために、いくつかの他のmod_rewrite機能の例と説明を提供したいと思いました。

以下の例はすべて、RewriteEngine Onファイルに.htaccessがすでに含まれていることを前提としています。

書き換えの例

この例を見てみましょう:

RewriteRule ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ /blog/index.php?id=$1&title=$2 [NC,L,QSA]

ルールは4つのセクションに分かれています。

  1. RewriteRule-書き換えルールを開始します
  2. ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$-これはパターンと呼ばれますが、ルールの左側と呼ぶことにします-書き直したいもの
  3. blog/index.php?id=$1&title=$2-置換と呼ばれる、または書き換えルールの右側-書き換え先
  4. [NC,L,QSA]は書き換えルールのフラグで、コンマで区切られます。これについては後で詳しく説明します

上記の書き換えにより、/blog/1/foo/のようなものにリンクでき、実際に/blog/index.php?id=1&title=fooをロードします。

ルールの左側

  • ^はページ名の開始を示します。したがって、example.com/blog/...は書き換えられますが、example.com/foo/blog/...は書き換えられません。
  • (…)括弧の各セットは、ルールの右側で変数としてキャプチャできる正規表現を表します。この例では:
    • ブラケットの最初のセット-([0-9]+)-は、長さが1文字以上で、数値(0-9)のみの文字列に一致します。これは、ルールの右側の$1で参照できます
    • 2番目の括弧のセットは、英数字(AZ、az、または0-9)または-または++のみ)を含む、長さが1文字以上の文字列に一致しますこれは、エスケープせずに 正規表現の繰り返し文字 )として実行されるため、バックスラッシュでエスケープされます。これは、ルールの右側の$2で参照できます
  • ?は、先行する文字がオプションであることを意味するため、この場合は/blog/1/foo//blog/1/fooの両方が同じ場所に書き換えられます
  • $は、これが一致する文字列の終わりであることを示します

これらは、特定の条件を指定するために、書き換えルールの最後に角かっこで追加されたオプションです。繰り返しますが、 ドキュメント で読むことができる多くの異なるフラグがありますが、私はいくつかのより一般的なフラグを見ていきます:

NC

No caseフラグは、書き換えルールが大文字と小文字を区別しないことを意味します。したがって、上記の例のルールでは、これは/blog/1/foo//BLOG/1/foo/(またはこのバリエーション)の両方が一致することを意味します。

L

最後のフラグは、これが処理されるべき最後のルールであることを示します。これは、このルールが一致する場合にのみ、現在の書き換え処理の実行でそれ以上のルールが評価されないことを意味します。ルールが一致しない場合、他のすべてのルールは通常どおり順番に試行されます。 Lフラグを設定しない場合、以下のすべてのルールがrewrittenURLに適用されます。

END

Apache 2.4以降では、[END]フラグも使用できます。それに一致するルールは、completelyさらにエイリアス/書き換え処理を終了します。 (一方、[L]フラグは、たとえばサブディレクトリへの書き込みやサブディレクトリからの書き換えの場合など、2回目のラウンドをトリガーすることがよくあります。)

QSA

クエリ文字列追加フラグを使用すると、指定されたURLに追加の変数を渡して、元のgetパラメーターに追加できます。この例では、これは/blog/1/foo/?comments=15のようなものが/blog/index.php?id=1&title=foo&comments=15をロードすることを意味します

R

このフラグは、上記の例で使用したものではありませんが、言及する価値があると考えたものです。これにより、ステータスコード(例:R=301)を含めるオプションを使用して、httpリダイレクトを指定できます。たとえば、/ myblog /から/ blog /への301リダイレクトを実行する場合は、次のようなルールを記述します。

RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]

書き換え条件

書き換え条件 書き換えをさらに強力にし、より具体的な状況に合わせて書き換えを指定できるようにします。 ドキュメント で読むことができる多くの条件がありますが、いくつかの一般的な例に触れて説明します:

# if the Host doesn't start with www. then add it and redirect
RewriteCond %{HTTP_Host} !^www\.
RewriteRule ^ http://www.%{HTTP_Host}%{REQUEST_URI} [L,R=301]

これは非常に一般的な方法で、ドメインにwww.が追加され(まだない場合)、301リダイレクトが実行されます。たとえば、http://example.com/blog/をロードすると、http://www.example.com/blog/にリダイレクトされます

# if it cant find the image, try find the image on another domain
RewriteCond %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)$ http://www.example.com/$1 [L]

これは少し一般的ではありませんが、ファイル名がサーバー上に存在するディレクトリまたはファイルである場合に実行されないルールの良い例です。

  • %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC]は、jpg、jpeg、gif、またはpng(大文字と小文字を区別しない)のファイル拡張子を持つファイルに対してのみ書き換えを実行します。
  • %{REQUEST_FILENAME} !-fは、ファイルが現在のサーバーに存在するかどうかを確認し、存在しない場合にのみ書き換えを実行します
  • %{REQUEST_FILENAME} !-dは、ファイルが現在のサーバーに存在するかどうかを確認し、存在しない場合にのみ書き換えを実行します
  • 書き換えは、同じファイルを別のドメインにロードしようとします
76
Nick

Mod_rewriteの代替

RewriteRulesを使用せずに、多くの基本的な仮想URLスキームを実現できます。 Apacheでは、PHPスクリプトを.php拡張なしで、また仮想PATH_INFO引数を使用して呼び出すことができます。

  1. PATH_INFO 、Lukeを使用します

    最近では、デフォルトで AcceptPathInfo On が有効になっています。基本的に、.phpおよびその他のリソースURLが仮想引数を保持できます。

    http://example.com/script.php/virtual/path
    

    これで、この/virtual/pathはPHPに $_SERVER["PATH_INFO"] として表示されます。ここで、任意の追加引数を処理できます。

    これは、Apacheが$1$2$3に別々の入力パスセグメントを持ち、それらを別個の$_GET変数としてPHPに渡すほど便利ではありません。それは、より少ない設定労力で「きれいなURL」をエミュレートするだけです。

  2. MultiViews を有効にして、.php拡張機能を非表示にします

    URLで.php「ファイル拡張子」を回避する最も簡単なオプションは、次を有効にすることです。

    Options +MultiViews
    

    これにより、Apacheは、ベース名が一致するため、article.phpのHTTPリクエストに/articleを選択します。そして、これは前述のPATH_INFO機能とうまく機能します。したがって、http://example.com/article/virtual/titleのようなURLを使用できます。複数のPHP呼び出しポイント/スクリプトを持つ従来のWebアプリケーションがある場合、これは理にかなっています。

    ただし、MultiViewsにはさまざまな目的があります。 Apacheは常に一致するベース名を持つ他のファイルを探すため、非常にマイナーなパフォーマンスの低下を招きます。実際には Content-Negotiation を対象としているため、ブラウザは利用可能なリソース(article.en.phparticle.fr.phparticle.jp.mp4など)の中から最適な選択肢を受け取ります。

  3. 拡張機能のない.phpスクリプトのSetTypeまたはSetHandler

    URLで.php接尾辞を持ち歩くことを避けるためのより指示されたアプローチは、 PHPハンドラーの設定 他のファイルスキーム用です。最も簡単なオプションは、.htaccessを介してデフォルトのMIME/handlerタイプをオーバーライドすることです。

    DefaultType application/x-httpd-php
    

    この方法では、article.phpスクリプトの名前をarticle(拡張子なし)に変更するだけで、PHPスクリプトとして処理できます。

    これで、すべての拡張機能のないファイルがPHPを介してパイプされるため、セキュリティとパフォーマンスに影響を与える可能性があります。したがって、代わりに、個々のファイルに対してのみこの動作を設定できます。

    <Files article>
      SetHandler application/x-httpd-php
      # or SetType 
    </Files>
    

    これは、サーバーのセットアップと使用されるPHP SAPIに多少依存します。一般的な代替には、ForceType application/x-httpd-phpまたはAddHandler php5-scriptが含まれます。

    繰り返しますが、このような設定は1つの.htaccessからサブフォルダーに伝播することに注意してください。静的リソース、およびupload /ディレクトリなどのスクリプトの実行(SetHandler NoneおよびOptions -Execまたはphp_flag engine offなど)は常に無効にする必要があります。

  4. その他のApache書き換えスキーム

    その多くのオプションの中で、Apacheはmod_alias機能を提供します-これは時々mod_rewrites RewriteRulesと同じように機能します。ただし、これらのほとんどは、ディレクトリごとの<VirtualHost>構成ファイルではなく、.htaccessセクションで設定する必要があります。

    • ScriptAliasMatch は主にCGIスクリプト用ですが、PHPでも機能するはずです。 RewriteRuleと同様に正規表現を使用できます。実際、これはおそらくキャッチオールフロントコントローラーを構成する最も堅牢なオプションです。

    • そして、単純な Alias は、いくつかの簡単な書き換えスキームにも役立ちます。

    • 単純な ErrorDocument ディレクティブでも、PHPスクリプトに仮想パスを処理させることができます。ただし、これは厄介な回避策であり、GETリクエスト以外は禁止し、定義によりerror.logをフラッディングすることに注意してください。

    詳細なヒントについては、 http://httpd.Apache.org/docs/2.2/urlmapping.html を参照してください。

5
mario