0

私は、これまで多くの人によって何度も行われてきたことをやろうとしていますが、うまくいかないようです。私は2日近く試してみました.インターネットで実際の例を探していて、非常によく似たSOの質問をたくさん見つけましたが、どれも私のために働いていません-それらのほとんどはキー/値アプローチの後です.値のリスト。


私が欲しいもの:

検索エンジンに適した URL を使用できるようにしたい。問題のサイトが現在動作している方法の性質上、このリクエスト URI を変換したいと思います。

/this/is/a/random/path

...に:

/index.php?p[]=これ&p[]=is&p[]=a&p[]=ランダム&p[]=パス

そのため、PHP に到着すると、 でインデックス付き配列として使用できるようになります$_GET['p']。また、末尾のスラッシュにも寛容であるようにしたいので、次から同じ結果が得られます。

/this/is/a/random/path/

私がそれをやろうとした方法:

私は正規表現が苦手というわけではなく、mod_rewrite がどのように機能するかについては十分に理解していますが、間違った道を行き過ぎて姿を消してしまい、もはや戻る道が見えなくなったと思います。

これが私が現在持っているものです:

# mod_rewrite をオンにする
RewriteEngine オン

# /static ディレクトリ内のファイルを直接ロードできるようにする
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^/?static/(.+)$ - [L]

# すべてのパス コンポーネントを再帰的にキャプチャする
RewriteCond %{REQUEST_URI} !^/?(?:index\.php)?$
RewriteRule ^/?([^/]+)(?:/(.+)$|/?$) $2?p[]=$1 [QSA,L]

# コントローラーにリクエストを送る
RewriteRule ^.*$ index.php [QSA]

どうしたの:

最初のRewriteCond/RewriteRuleペアはうまく機能します。/staticディレクトリに存在するファイルを要求すると、要求はそのまま残され、ファイルが提供されます。ファイルが存在しない場合は、2 番目の一連のルールが適用されるため、PHP ベースのセクシーなエラー ページの 1 つを表示できます。

問題は 2 番目のRewriteCond/RewriteRuleペアにあり、おそらく 3 番目RewriteRuleにもあります。最終的な反復によってスクリプト名が配列に追加されないようにするために、条件が存在するはずです-そしてこれはうまくいくようです。これが秒がやっていることだと思いますRewriteRule。ここで明らかなことを見逃していると思います:

           ^/? # オプションの先行スラッシュを含む文字列の開始
       ([^/]+) # 次のスラッシュまでのすべての文字をキャプチャ
(?:/(.+)$|/?$) # 次のスラッシュの後のすべての文字を取得するか、最後に一致させる

     $2?p[]=$1 # 取得したパス コンポーネントを配列にプッシュし、URI を下にシフトします
       [QSA,L] # 前のクエリ文字列をマージし、次の繰り返しに進みます

これは 90% 動作しています。私が抱えている問題:

  • 配列コンポーネントの順序が逆になります。私はこれがなぜなのかを理解しており、おそらく避けられないことを理解しています.PHPでarray_reverse(). 私ができない mod_rewrite ソリューションを誰かが思いつく場合にのみ言及します。
  • 最後の 2 つの位置にパス コンポーネントが繰り返されると、失敗します。たとえば、最後の 2 つのパス コンポーネントが見つからないという標準の Apache 404を要求した/home/home場合、または取得した場合 (上記の2 つの例では) 。ただし、最後に別のパスコンポーネントを追加すると、再び機能します。これを引き起こしている原因に頭を悩ませることはできません。/some/path/path/home/home/path/path/home/home/something

なぜこれが起こっているのか、またはこれを行うためのより良い方法を提案できる人はいますか?

4

1 に答える 1

1

これは無限に簡単ではないでしょうか:

 RewriteCond ${REQUEST_FILENAME} !-f
 RewriteCond ${REQUEST_FILENAME} !-d
 RewriteRule .* rewrite.php [L]

rewrite.php:

 <?php
 $p = array_filter(explode('/',parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)));
 // you _could_ of course do an EVIL $_GET['p'] = $p, but I prefer to leave 
 // the superglobals 'read-only'. Not touching $_GET does however mean
 // that index.php needs to be altered somewhat, allowing for a check on isset($p) 
 // and using that as input
 include 'index.php';
 ?>

apache での書き換えはすべてうまくいきますが、多くの場合、PHP 自体でアクションを解析して決定するだけで、はるかに簡単になり、後で維持/変更するのも簡単になります。

質問・備考:

あなたの htaccess は、パスで要求した場合、ファイルへの直接アクセスを許可しますが、/static にない限り、やりたくありません。

現時点では、それ以上または以下のアクセスは許可されません。あなたの index.php と rewrite.php だけが到達可能であるため、アクセスを許可したくないファイルが存在する必要があるドキュメントルートの外に他のものを置くことができます。この入力を使用して盲目的にファイルをindex.php.... に含める場合を除きます。パイプする必要がある既存のファイルの要求に関する部分を見逃していましたindex.php。その場合、次のようなことができます。

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^/?static/(.+)$ - [L]

RewriteCond ${REQUEST_URI} !^/?(index\.php)?$
RewriteRule .* rewrite.php [L,QSA]

ところで、コールバックのない array_filter() は何ですか? 私が見る限りでは、空のコンポーネントと 0 のコンポーネントを削除するだけで、おそらく 0 を許可したいと思うでしょう。

これは、/foo//bar(double //.

preg_split('#/+#', $str, -1, PREG_SPLIT_NO_EMPTY); でしょうか。良くなる?

0 / によってフィルタリングされるその他のものを許可したい場合はarray_filter、はい、その解決策が優れています。

于 2012-06-14T21:58:07.447 に答える