PHPへのパラメータ渡しは一般的には以下のようになります。
それをこのように記述したいと考えました。
ワードプレスでもパラメータを「/」(スラッシュ)で表記する設定が可能です。
このようなパラメータ渡しをPHPでどうやれば実現できるかを調べました。
忘備録として記録いたします。
実際にできたものがこちらです
PHPでパラメータをググって調べて試行錯誤して、ディレクトリ形式で渡すことができたものがこちらです。
https://office-obata.com/sample/16/id/test/date/2021-06-16/
https://office-obata.com/sample/16/までがURLで、/id/test/date/2021-06-16/が任意パラメータです。
呼び出すと、以下のように渡されたパラメータを表示します。
サンプルはこれだけですが、スラッシュで区切ったフォルダ名をパラメータとしてPHP側で受け取れています。
できてしまうと「なんだそんなことか。」
になりますが、わからないときは本当にわからないものです。
実現の方法について以下に解説いたします。
ディレクトリ式パラメータ渡しの原理
404エラーにならないようにする仕組み
ディレクトリとはそもそも下層フォルダを示すものです。
本来URLをスラッシュで区切った部分には「実在するフォルダ名」を記述します。
実在しないフォルダ名を記述すると404エラー(存在しないエラー)になります。
今回のディレクトリ形式のパラメータ渡しも「実在しないフォルダ名」をURLに記述しています。
どうやって404エラーを回避しているのか?
最初にここでつまづきました。
ググって調べたら、.htaccessで何とかなることがわかりました。
その記述がこちらです。
RewriteEngine on
RewriteRule ^(.*)$ index.php [L]
.htaccessにたった2行付け加えるだけで、PHPにディレクトリ形式でパラメータ渡しができるようになります。
RewriteEngine on について
404エラーは「実在しないフォルダ名」を記述すると発生します。
これをOKにするための宣言になります。
.htaccessで記述するための文法と考えてOKです。
RewriteRule ^(.*)$ index.php [L]について
架空のフォルダ名をエラーにならないようにしているのがこの部分です。
見た感じ何が何だかさっぱりですが、次のような処理がされます。
「入力された記述をすべてindex.phpとして表記します。」
^(.*)$は、入力されたURL全ての文字を意味します。
これをindex.phpに書き換えます。という意味です。
存在しないディレクトリ名でも.htaccessによって書き換えされるため、404エラーにならなくなるのです。
ディレクトリ名をパラメータとして受け取る仕組み
404エラーを.htaccessで回避できるようにしたら、今度はディレクトリ名をパラメータとして受け取る仕組みについて解説いたします。
$_REQUEST変数には何も値が入らない
最初は.htaccessでパラメータを置き換えているのだと思いましたが、.htaccessでは404エラーにならないようにするだけで、パラメータ受け取りはPHP側で何とかしなければならないことがわかりました。
ただ、PHPの通常パラメータ渡しがされないため、$_REQUEST変数には一切パラメータが入っていません。
いままで、PHPでのパラメータ受け取りは$_REQUEST変数のみだと思っていたので、どうすればディレクトリ式のパラメータを受け取れるのかさらに調べました。
ディレクトリ形式でパラメータを受け取るには$_SERVER[‘REQUEST_URI’]変数をチェックする
$_REQUEST変数でパラメータを受け取れないのであれば、どこからパラメータを取得すればよいのか?
色々調べたところ、$_SEVER変数から受け取ればよいことがわかりました。
$_SERVER[’REQUEST_URI’]です。
この部分には呼び出された時点でのディレクトリ名のみ格納されています。
具体的には、
https://office-obata.com/sample/16/id/test/date/2021-06-16/
で呼び出した場合、$_SERVER[’REQUEST_URI’]には「/sample/16/id/test/date/2021-06-16/」が保存されています。
これをスラッシュで区切って分割すれば、パラメータとして取得できることになります。
PHPでは「explode()」関数を使用すれば、文字列を分割するのは良いなことです。
でも、ここで1点気になることがありました。
実物ディレクトリとパラメータディレクトリが混ざっている
https://office-obata.com/sample/16/id/test/date/2021-06-16/
上記のサンプルURLは太字の部分がパラメータで、/sample/16/は実際のディレクトリになります。
つまり、実ディレクトリと、パラメータディレクトリが混在しています。
この時にパラメータディレクトリのみを取得できるようにする必要があります。
これも$_SERVER[‘SCRIPT_NAME’]変数に物理ディレクトリ名が記載されるため、差分をとればパラメータディレクトリを抽出することができます。
「/sample/16/index.php」が入っています。
これらを踏まえてディレクトリパラメータを受ける部分を構築したもの以下になります。
PHPソースの解説
<?php
$out_para = null;
// 物理ディレクトリURLを取得
$folder_url = substr($_SERVER['SCRIPT_NAME'], 0, (strripos($_SERVER['SCRIPT_NAME'], "/")+1));
if ($folder_url == "/") // カレント?
{
$folder_url = null;
}
// 物理ディレクトリURLを省いたパラメータ部分だけを取得
$para = explode("/", str_replace($folder_url, "", $_SERVER['REQUEST_URI']));
foreach($para as $value) // パラメータがある分ループ
{
if ($value != null) // パラメータあり?
{
// パラメータをセット
$out_para .= "[${value}]";
}
}
if ($out_para != null) // パラメータあり?
{
echo "渡されたパラメータは:${out_para}です。";
}
else
{
echo "渡されたパラメータはありません。";
}
?>
内容について解説いたします。
(1)物理ディレクトリURLを取得
// 物理ディレクトリURLを取得
$folder_url = substr($_SERVER['SCRIPT_NAME'], 0, (strripos($_SERVER['SCRIPT_NAME'], "/")+1));
プログラム言語は1行にまとめるとスマートな感じがしますが、実際はわかりにくく、難解になります。
これを書き換えると以下のようになります。
// 抽出する文字サイズを取得
$cut_size = strripos($_SERVER['SCRIPT_NAME'], "/")+1;
// 物理ディレクトリ部分を抽出
$folder_url = substr($_SERVER['SCRIPT_NAME'], 0, $cut_size);
$_SERVER[‘SCRIPT_NAME’]には「/sample/16/index.php」が入っています。(物理ディレクトリ名称)
strripos()関数は指定した文字が最後に出てくる位置を返します。
この場合だと頭から11文字目に最後の「/」(スラッシュ)があります。
プログラムの配列指定は0からになるため、0を含めて11数えると10になります。
なのでこの場合は、10が返ります。
+1をしているのは、0から数える分1つずれているのを調整するためです。
物理ディレクトリ部分の抽出は、$_SERVER[‘SCRIPT_NAME’]「/sample/16/index.php」から「index.php」の文字列だけを取り除きます。
substr()は、指定した位置から指定したサイズ抽出する関数です。
strripos()関数で求めた、丁度最後の/(スラッシュ)を含めて抽出できるサイズを指定して実現しています。
1行にまとめた命令文も、分割するとわかりやすくなります。
(2)パラメータディレクトリ部分を抽出
// 物理ディレクトリURLを省いたパラメータ部分だけを取得
$para = explode("/", str_replace($folder_url, "", $_SERVER['REQUEST_URI']));
(1)では物理ディレクトリ名称を求めたので、今度はパラメータ部分を抽出します。
やり方は、$_SERVER[’REQUEST_URI’]変数に物理ディレクトリ、パラメータディレクトリ混在でセットされているので、(1)で求めた物理ディレクトリとの差分をとります。
具体的には以下のようになります。
$_SERVER[‘REQUEST_URI’]には「/sample/16/id/test/date/2021-06-16/」が入っています。
(1)で求めた物理ディレクトリ名称は「/sample/16/」です。
なので差分をとれば、パラメータディレクトリ「/id/test/date/2021-06-16/」を抽出できるという仕組みです。
上記の記述を書き換えると、以下のようになります。
// 物理ディレクトリを消去する
$para_folder = str_replace($folder_url, "", $_SERVER['REQUEST_URI']);
// スラッシュで分割しパラメータ化する
$para = explode("/", $para_folder);
str_replace()は文字列置換関数です。
指定した文字列と同じ部分を、指定した文字に置き換えます。
この場合物理ディレクトリ名が不要なため、””(空白)で上書きし削除しています。
explode()は、指定した文字で区切り配列化する関数です。
「/id/test/date/2021-06-16/」をexplode()で分割すると以下のようになります。
$para = array("", "id", "test", "date", "2021-06-16","");
最初と最後が「””」となっているのは頭のスラッシュと、最後のスラッシュ部分も変換されるためです。
最初のスラッシュの前は空欄、最後のスラッシュの後も空欄。
スラッシュで区切ると空欄になります。
ともあれ、ディレクトリ形式のパラメータを取得できました。
取得したパラメータをどう使うかは自分で考える
PHPのパラメータは、ハッシュと値がセットで渡されます。
しかしディレクトリ形式でのパラメータ渡しだと/(スラッシュ)ごとに区切られた値が渡されます。
ハッシュか値かは判断できません。
なので自分でルールを決めてパラメータ取得を行う必要があります。
例えば「/ハッシュ/値/ハッシュ/値/」と交互にする方法や「/値/値/」というふうに値だけを渡すなどです。
この辺は設計時にルールを決めておくことで解消できます。
ともあれ、パラメータをURLのように見せる方法を知ることができました。
また本記事がお役に立てば幸いです。
追記:このやり方には落とし穴があるので何とかする方法もご覧いただければ幸いです。
.htaccessを使い仮想ディレクトリ化する方法は、今回の記述のままだと画像等が表示されなくなります。それを何とかする方法について記載していますので、またご参考いただければ幸いです。