PHPによるURLの書き換え


139

次のようなURLがあります。

url.com/picture.php?id=51

そのURLを次のように変換するにはどうすればよいですか。

picture.php/Some-text-goes-here/51

WordPressも同じだと思います。

PHPでわかりやすいURLを作成するにはどうすればよいですか?


1
Apacheファイルの設定を大幅に調整する必要があります...実際に必要なものの例を挙げてください。このテキストをどのように挿入しますか?事前定義されているか、動的に作成されていますか?正しい答えを得るためにできるだけ多くの情報を提供してください...そして、
はい

1
なぜPHPなのか?mod_rewriteこれに必要なのはApache だけです。SOについては、Apache について多くの質問があります。そして、あなたがそのワードプレスが同じことを「考える」なら、なぜそれを単に調べてみませんか?;)
nietonfir 2013


なぜあなたはこれをやっている?URLを書き換えるのが目標ですが、そうであれば.htaccessなどを使用してください。文字列を変更するだけの場合、$ _ GETはクエリ文字列のみを取得しますか?
adeneo 2013

テキストは画像のタイトルで、スラッシュの後のIDになります:)私は、apacheのmod_rewriteが提供する必要があるものを調べる必要があります。それほど難しくないことを願っています:D
Jazerix 2013

回答:


194

基本的に、次の2つの方法で行うことができます。

mod_rewriteによる.htaccessルート

.htaccessルートフォルダーにというファイルを追加し、次のようなものを追加します。

RewriteEngine on
RewriteRule ^/?Some-text-goes-here/([0-9]+)$ /picture.php?id=$1

これにより、Apacheはこのフォルダーに対してmod_rewriteを有効にするように指示され、正規表現に一致するURLが要求された場合、エンドユーザーに表示されることなく、希望する内容に内部的に書き換えられます。簡単ですが柔軟性に欠けるため、さらにパワーが必要な場合:

PHPルート

代わりに以下を.htaccessに入れてください:(先頭のスラッシュに注意してください)

FallbackResource /index.php

これによりindex.php、通常はサイトで見つけることができないすべてのファイルに対して実行するように指示されます。そこで、たとえば次のことができます。

$path = ltrim($_SERVER['REQUEST_URI'], '/');    // Trim leading slash(es)
$elements = explode('/', $path);                // Split path on slashes
if(empty($elements[0])) {                       // No path elements means home
    ShowHomepage();
} else switch(array_shift($elements))             // Pop off first item and switch
{
    case 'Some-text-goes-here':
        ShowPicture($elements); // passes rest of parameters to internal function
        break;
    case 'more':
        ...
    default:
        header('HTTP/1.1 404 Not Found');
        Show404Error();
}

これは、大規模なサイトとCMSシステムがこれを行う方法です。これにより、URL、構成、データベースに依存するURLなどを解析する際の柔軟性が大幅に向上します.htaccess


それをハードコーディングする代わりに、正規表現を使用して文字列を完全に無視することができます。つまり、カウントされるのはID部分だけです。に移動picture.php/invalid-text/51すると、同じ場所にリダイレクトされます。文字列が正しいかどうかを確認するチェックを追加し、正しくない場合は、正しい場所に再度リダイレクトすることもできます。それは私がhtaccessを使用して私のサイトの1つでそれをした方法です。
マイク

7
小規模なサイトには便利ですが/blog/25/picture/51およびと同様に解析する必要がある場合は、実際的ではありません/download/684。また、(GoogleのPRがペナルティとあなたを取得!)非常に悪い習慣と考えられていますすべてのランダムに生成されたURLが正しく404戻らない場合
ニールスKeurentjes

5
少なくとも私のシステムでは、それはFallbackResource /index.php(先頭のスラッシュに注意)
ジャックジェームス

4
@olli:悪い習慣のコメントは、具体的には「存在しないURLに対して404を返さない」ことを指しますが、これは回答自体のソリューションによって解決されます。最初の質問と同様に、FallbackResource実際にはファイルシステムに存在しないファイルのみが起動するため、フォールバックが発生します。したがって、ファイルが/static/styles.cssありhttp://mydomain.tld/static/styles.css、コードが実行されることはないため、ファイルを参照すると、ファイルは期待どおりに意図したとおりに透過的に機能します。
Niels Keurentjes 2014年

if($elements[0] === NULL)代わりに使用する必要があります$elements。空の場合でも、1のカウントが返されます。
fireinspace 2016

57

ルートを変更するだけの場合picture.phpは、書き換えルールを追加.htaccessすることでニーズに対応できますが、WordpressのようにURLを書き換えたい場合は、PHPが適しています。以下は、簡単な例です。

フォルダー構造

そこルートフォルダに必要な2つのファイルがあり、.htaccessそしてindex.php、残りの置くのが良いだろう.phpと同じように、別のフォルダ内のファイルをinc/

root/
  inc/
  .htaccess
  index.php

.htaccess

RewriteEngine On
RewriteRule ^inc/.*$ index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]

このファイルには4つのディレクティブがあります。

  1. RewriteEngine -書き換えエンジンを有効にする
  2. RewriteRule- inc/フォルダ内のすべてのファイルへのアクセスを拒否し、そのフォルダへの呼び出しをリダイレクトしますindex.php
  3. RewriteCond -他のすべてのファイル(画像、CSS、スクリプトなど)への直接アクセスを許可する
  4. RewriteRule -他に何かをリダイレクトする index.php

index.php

これですべてがindex.phpにリダイレクトされるため、URLが正しいかどうか、すべてのパラメーターが存在するかどうか、パラメーターのタイプが正しいかどうかが判断されます。

URLをテストするには、一連のルールが必要です。そのための最適なツールは正規表現です。正規表現を使用して、1回の打撃で2つのハエを殺します。URL、このテストに合格するには、許可された文字でテストされるすべての必須パラメーターが必要です。ルールの例をいくつか示します。

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);

次にリクエストuriを準備します。

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );

これでリクエストuriができたので、最後のステップは、正規表現ルールでuriをテストすることです。

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
    }
}

マッチが成功すると、正規表現で名前付きサブパターンを使用するため、$paramsPHPが$_GET配列を埋めるのとほぼ同じように配列を埋めます。ただし、動的URLを使用する場合、$_GET配列はパラメーターのチェックなしで入力されます。

    / picture / some + text / 51

    アレイ
    (
        [0] => / picture / some text / 51
        [テキスト] =>いくつかのテキスト
        [1] =>テキスト
        [ID] => 51
        [2] => 51
    )

    picture.php?text = some + text&id = 51

    アレイ
    (
        [テキスト] =>いくつかのテキスト
        [ID] => 51
    )

これらの数行のコードと正規表現の基本的な知識があれば、確実なルーティングシステムの構築を開始できます。

完全なソース

define( 'INCLUDE_DIR', dirname( __FILE__ ) . '/inc/' );

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
        include( INCLUDE_DIR . $action . '.php' );

        // exit to avoid the 404 message 
        exit();
    }
}

// nothing is found so handle the 404 error
include( INCLUDE_DIR . '404.php' );

2
パラメータをどのように読み取りますか?$ post_id = htmlentities($ _ GET ['post']);では機能しません。
andrebruton 2014年

@Danijel完全なソースコードを入手できますか?上記のコードを試しましたが、テキストのみが出力され、CSSは効果がありません。ありがとうございました。
4カバーを残す

6

これは、ほぼすべてをindex.phpに転送する.htaccessファイルです。

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} !-l
RewriteCond %{REQUEST_FILENAME} !\.(ico|css|png|jpg|gif|js)$ [NC]
# otherwise forward it to index.php
RewriteRule . index.php

次に$ _SERVER ["REQUEST_URI"]を解析して、picture.phpなどにルーティングします


8
Apache FallbackResourceはいくつかのメジャーバージョン前にこのディレクティブを導入しました。これは、書き換えエンジン全体を起動する必要がないため、この動作をより低いパフォーマンスコストで実装するための好ましい方法です。ドキュメントはこちら。ディレクトリ(!-d)を参照せず、すべての拡張フィルターが廃止されているため、ルールにも問題があり-fます。
Niels Keurentjes 2013


2

既に回答されていますが、著者の意図はフロントコントローラータイプのアプリを作成することですが、質問された問題について文字通りのルールを投稿しています。同じ問題が発生した場合。

RewriteEngine On
RewriteRule ^([^/]+)/([^/]+)/([\d]+)$ $1?id=$3 [L]

上記はurlで機能しpicture.php/Some-text-goes-here/51ます。リダイレクトアプリとしてindex.phpを使用しません。


hrefに書き込む必要のあるURLを知る必要がありますか?私は404を取得しているため
questionbank
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.