帰ってきた・たぶん難しくないApache2・挑戦!RewriteRule・その3~RewriteMapを使う~ [Linux(Apache)]
そうか…。もう6年とか経過していたのか…。
何もかもが懐かしい…。(遠い目
URLの読み替えをしたい場合にRewriteRuleを使う…という話をしてましたが、ファイルが決め打ちできるとか、正規表現で一定のルールに従って読み替えができる…というようなケースでは割と簡単にお役に立ってくれました。
ところが…。
たまに有りませんか?
サイトのデザインを一新したんだけど、ページにリンクされている画像ファイルとかバナーとかも全部差し替えたい。でも、他のサイトで直リンクしているバナーもあるようなんだけどもう把握出来ていないので、古いバナーについては新しいバナーにサーバ側で読み替えて欲しいんですけど。
…みたいな話。で、『あ…。シンボリックリンクを張っておくかRewriteRuleで読み替えちゃえばいいかな…』なんて考えていたら読み替えるべきファイル名が数百個もあった件について…みたいな事例。
しかも、正規表現で美しく読み替えようにもそんなこと出来ませんよセンセイ…みたいな事例。
…え?ない?
…ソウデスカ…アリマセンカ…orz
ここでは、「あー。あるある!」と大人の対応をした人に向けて、「RewriteMap」を簡単に使って解決する方法を書いておきたいと思います。
例えば、たった一つのファイルを読み替えたいときはどうするか?を考えます。
img/fileA.jpg を、img/fileB.jpg に読み替えるとしましょう。この場合はチョー簡単です。
RewriteRule img/fileA.jpg img/fileB.jpg [L]
とかやっておけば事足ります。ところが、これを何百個も書きたくない訳です。このような場合には、「RewriteMap」ディレクティブを使います。手順としてはこんな感じです。
手順①:旧ファイル名 → 新ファイル名の読み替え一覧をテキストファイルで作成する
手順②:手順①で作成したテキストファイルをdbm型式に変換する
手順③:手順②のファイルを、「RewriteMap」ディレクティブで読み込み、条件を設定してRewriteRuleで読み替える
手順①:旧ファイル名 → 新ファイル名の読み替え一覧をテキストファイルで作成する
まず、新旧ファイル名の読み替えをする一覧をテキストファイルに作成します。フォーマットは、「旧ファイル名」と「新ファイル名」とを1行に記述します。半角スペースやタブで区切ります。
なお、半角「#」がコメントとして使用可能です。
手順②:手順①で作成したテキストファイルをdbm型式に変換する
次に、手順①で作成したテキストファイルをdbm型式に変換します。実のところ、変換しなくてもいけるんですが、読み替えるべきファイルが多い場合は変換した方がサーバ負荷が下がってオススメです。
コマンドとしては、httxt2dbmコマンドを使用します。
httxt2dbm -i (入力ファイル名) -o (出力ファイル名)
です。入力ファイルには手順①で作成したファイル名を指定します。出力ファイル名にはdbm型式のファイル名をそれっぽい名前で指定すればよいでしょう。
このコマンドを実行すると、拡張子「.dir」というファイルと「.pag」というファイルが作成されます。
手順③:手順②のファイルを、「RewriteMap」ディレクティブで読み込み、条件を設定してRewriteRuleで読み替える
次に、httpd.confを調製します。
まず、手順②で指定したdbm型式のファイルをRewriteMapディレクティブで読み込みます。
RewriteMap imgurl dbm:/usr/local/apache2/conf/yomikaelist
imgurlは単なる識別子です。次のRewriteRuleディレクティブで使用しますが名前は何でも構いません。
dbm:/usr/local/apache2/conf/yomikaelistは、「dbm:」に続いて手順②で作成したファイル名を指定します。拡張子は必要ありません。
で、これをRewriteRuleディレクティブで実際に読み替えます。
RewruteRule ^/?(img/.*\.(gif|jpe?g)) /${imgurl:$1|$1} [L]
これくらいの正規表現はちゃっちゃと読めないとねー。(笑)
まず、RewruteRuleディレクティブの最初のパラメータ^/?(img/.*\.(gif|jpe?g))は、「img/」ディレクトリの下にある「ナントカ.gif」「ナントカ.jpg」「ナントカ.jpeg」を読み替えたいのでこのような記述をしています。ここで、丸括弧が2組出ているのが「なんじゃこりゃ」の原因になっていると思いますので解説しておきます。
RewriteRuleの過去の記事にもしれっと記述してたりするんですが、丸括弧で囲んだ範囲はRewriteRuleディレクティブの内部的な「変数」に格納することが出来ます。(img/.*\.(gif|jpe?g))の外側の部分はそのための丸括弧で、丸括弧の中身は「$1」という変数に格納されます。
内側の丸括弧部分(gif|jpe?g)/font>は拡張子「gif」または「jpe?g」のどちらかという記号「|」の範囲を特定するための物です。
で、この正規表現によって、次のようなリクエストがあったなら、赤文字の部分が変数$1に格納されることとなります。
http://server/img/fileA.jpg
さて。この赤文字部分。そういえば手順①で作成したファイルの中にありましたよね?
この変数$1の内容をRewriteMapディレクティブで読み込んだアレに渡すと、見事img/fileB.jpgに化けて出てくる…という処理をしているのが、RewriteRuleディレクティブの二つ目の引数である /${imgurl:$1|$1} です。
${(RewriteMapの識別子名):(読み替え前の名前)}
としておくと、読み替え前の名前を読み替えた後の名前が取得できます。つまり、
${imgurl:img/fileA.jpg}
という指定をすれば、この変数は結果的にimg/fileB.jpgという値になって機能するということなのです。
ただし、ここで一つ注意すべきポイントがあります。それは…
読み替え「前」の名前が無い場合は、空っぽの値が返ってくる
という点です。つまり、
${imgurl:img/fileAHO.jpg}
という指定をした場合、この結果は「」という状態になってしまいます。このため、RewriteMapで読み込んだファイルの中に記述が無い場合は、RewriteRuleが「」に読み替えようとしてしまいますので非常に都合が悪いのです。
#そもそも、「読み替えたいファイルの一覧」があるということは、
#その中に「無い」ファイルは「読み替えて欲しくない」
#と解釈すべきでしょ?
と言うわけで、imgurlに値が「ない」場合の振る舞いも一緒に指定しておく必要があります。そのための記述が、「|$1」の部分なのです。
${imgurl:img/fileAHO.jpg|img/fileAHO.jpg}
という指定をすると、imgurlに「img/fileAHO.jpg」があれば、読み替えたその文字列を返す。(「|」の前の部分)
しかし、imgurlで読み替えた結果が「空っぽ」だった場合は「img/fileAHO.jpg」を返す。(「|」の後ろの部分)
という処理を行うことになります。
実際には、RewriteRuleで使用している変数「$1」の中身に応じて読み替えをしたいので、結果的に/${imgurl:$1|$1}という指定になっている訳です。
これで、ファイルが読み替えるべき対象であるならファイル名を読み替え、そうでない(リストに無い)場合はそのままの名前でアクセスを通す…という事が出来るようになります。
何もかもが懐かしい…。(遠い目
URLの読み替えをしたい場合にRewriteRuleを使う…という話をしてましたが、ファイルが決め打ちできるとか、正規表現で一定のルールに従って読み替えができる…というようなケースでは割と簡単にお役に立ってくれました。
ところが…。
たまに有りませんか?
サイトのデザインを一新したんだけど、ページにリンクされている画像ファイルとかバナーとかも全部差し替えたい。でも、他のサイトで直リンクしているバナーもあるようなんだけどもう把握出来ていないので、古いバナーについては新しいバナーにサーバ側で読み替えて欲しいんですけど。
…みたいな話。で、『あ…。シンボリックリンクを張っておくかRewriteRuleで読み替えちゃえばいいかな…』なんて考えていたら読み替えるべきファイル名が数百個もあった件について…みたいな事例。
しかも、正規表現で美しく読み替えようにもそんなこと出来ませんよセンセイ…みたいな事例。
…え?ない?
…ソウデスカ…アリマセンカ…orz
ここでは、「あー。あるある!」と大人の対応をした人に向けて、「RewriteMap」を簡単に使って解決する方法を書いておきたいと思います。
例えば、たった一つのファイルを読み替えたいときはどうするか?を考えます。
img/fileA.jpg を、img/fileB.jpg に読み替えるとしましょう。この場合はチョー簡単です。
RewriteRule img/fileA.jpg img/fileB.jpg [L]
とかやっておけば事足ります。ところが、これを何百個も書きたくない訳です。このような場合には、「RewriteMap」ディレクティブを使います。手順としてはこんな感じです。
手順①:旧ファイル名 → 新ファイル名の読み替え一覧をテキストファイルで作成する
手順②:手順①で作成したテキストファイルをdbm型式に変換する
手順③:手順②のファイルを、「RewriteMap」ディレクティブで読み込み、条件を設定してRewriteRuleで読み替える
手順①:旧ファイル名 → 新ファイル名の読み替え一覧をテキストファイルで作成する
まず、新旧ファイル名の読み替えをする一覧をテキストファイルに作成します。フォーマットは、「旧ファイル名」と「新ファイル名」とを1行に記述します。半角スペースやタブで区切ります。
img/fileA.jpg img/fileB.jpg img/fileC.jpg img/fileX.jpg img/fileD.jpg img/fileY.jpg img/fileE.jpg img/fileZ.jpg
なお、半角「#」がコメントとして使用可能です。
手順②:手順①で作成したテキストファイルをdbm型式に変換する
次に、手順①で作成したテキストファイルをdbm型式に変換します。実のところ、変換しなくてもいけるんですが、読み替えるべきファイルが多い場合は変換した方がサーバ負荷が下がってオススメです。
コマンドとしては、httxt2dbmコマンドを使用します。
httxt2dbm -i (入力ファイル名) -o (出力ファイル名)
です。入力ファイルには手順①で作成したファイル名を指定します。出力ファイル名にはdbm型式のファイル名をそれっぽい名前で指定すればよいでしょう。
このコマンドを実行すると、拡張子「.dir」というファイルと「.pag」というファイルが作成されます。
手順③:手順②のファイルを、「RewriteMap」ディレクティブで読み込み、条件を設定してRewriteRuleで読み替える
次に、httpd.confを調製します。
まず、手順②で指定したdbm型式のファイルをRewriteMapディレクティブで読み込みます。
RewriteMap imgurl dbm:/usr/local/apache2/conf/yomikaelist
imgurlは単なる識別子です。次のRewriteRuleディレクティブで使用しますが名前は何でも構いません。
dbm:/usr/local/apache2/conf/yomikaelistは、「dbm:」に続いて手順②で作成したファイル名を指定します。拡張子は必要ありません。
で、これをRewriteRuleディレクティブで実際に読み替えます。
RewruteRule ^/?(img/.*\.(gif|jpe?g)) /${imgurl:$1|$1} [L]
これくらいの正規表現はちゃっちゃと読めないとねー。(笑)
まず、RewruteRuleディレクティブの最初のパラメータ^/?(img/.*\.(gif|jpe?g))は、「img/」ディレクトリの下にある「ナントカ.gif」「ナントカ.jpg」「ナントカ.jpeg」を読み替えたいのでこのような記述をしています。ここで、丸括弧が2組出ているのが「なんじゃこりゃ」の原因になっていると思いますので解説しておきます。
RewriteRuleの過去の記事にもしれっと記述してたりするんですが、丸括弧で囲んだ範囲はRewriteRuleディレクティブの内部的な「変数」に格納することが出来ます。(img/.*\.(gif|jpe?g))の外側の部分はそのための丸括弧で、丸括弧の中身は「$1」という変数に格納されます。
内側の丸括弧部分(gif|jpe?g)/font>は拡張子「gif」または「jpe?g」のどちらかという記号「|」の範囲を特定するための物です。
で、この正規表現によって、次のようなリクエストがあったなら、赤文字の部分が変数$1に格納されることとなります。
http://server/img/fileA.jpg
さて。この赤文字部分。そういえば手順①で作成したファイルの中にありましたよね?
img/fileA.jpg img/fileB.jpg img/fileC.jpg img/fileX.jpg img/fileD.jpg img/fileY.jpg img/fileE.jpg img/fileZ.jpg
この変数$1の内容をRewriteMapディレクティブで読み込んだアレに渡すと、見事img/fileB.jpgに化けて出てくる…という処理をしているのが、RewriteRuleディレクティブの二つ目の引数である /${imgurl:$1|$1} です。
${(RewriteMapの識別子名):(読み替え前の名前)}
としておくと、読み替え前の名前を読み替えた後の名前が取得できます。つまり、
${imgurl:img/fileA.jpg}
という指定をすれば、この変数は結果的にimg/fileB.jpgという値になって機能するということなのです。
ただし、ここで一つ注意すべきポイントがあります。それは…
読み替え「前」の名前が無い場合は、空っぽの値が返ってくる
という点です。つまり、
${imgurl:img/fileAHO.jpg}
という指定をした場合、この結果は「」という状態になってしまいます。このため、RewriteMapで読み込んだファイルの中に記述が無い場合は、RewriteRuleが「」に読み替えようとしてしまいますので非常に都合が悪いのです。
#そもそも、「読み替えたいファイルの一覧」があるということは、
#その中に「無い」ファイルは「読み替えて欲しくない」
#と解釈すべきでしょ?
と言うわけで、imgurlに値が「ない」場合の振る舞いも一緒に指定しておく必要があります。そのための記述が、「|$1」の部分なのです。
${imgurl:img/fileAHO.jpg|img/fileAHO.jpg}
という指定をすると、imgurlに「img/fileAHO.jpg」があれば、読み替えたその文字列を返す。(「|」の前の部分)
しかし、imgurlで読み替えた結果が「空っぽ」だった場合は「img/fileAHO.jpg」を返す。(「|」の後ろの部分)
という処理を行うことになります。
実際には、RewriteRuleで使用している変数「$1」の中身に応じて読み替えをしたいので、結果的に/${imgurl:$1|$1}という指定になっている訳です。
これで、ファイルが読み替えるべき対象であるならファイル名を読み替え、そうでない(リストに無い)場合はそのままの名前でアクセスを通す…という事が出来るようになります。
コメント 0