PHPでフレームワーク使わずにルーティング

こんにちは、noteサボりがちな細音 希です。

最近、新しくPHPでサイトを作ったので、それの紹介と技術解説です。

まず、作成したサイトはこちら。

beyVというVTuberエージェントの非公式ファンサイトです。

公式が全然仕事しないのでデビュー情報とか各ライバーの情報がわからなくて、自分でデータベース作って公開したってかんじです。

こちらのサイト、素のPHPで作ってあるのですが、データベースに登録したライバーさんそれぞれにURLを振って個別ページを実現させています。

これの実現方法を解説していきます。

やることは大きく以下の2つ。

1. .htaccessを使ってすべてのアクセスを一つのindex.phpに集める

2. index.php内でURLを解析してそれぞれの処理、ページの表示をする

意外と簡単でした。

PHPと.htaccessが利用できるサーバーならどこでも使えます。

.htaccessを使ってすべてのアクセスを一つのindex.phpに集める

.htaccessはディレクトリ単位での設定をするファイルなので、特に理由がなければルートディレクトリに設置してください。

内容は以下をコピペすれば大丈夫です。

最後の行のあとに空行を入れておきましょう。

RewriteEngine on
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} !=localhost
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

1行目でRewiteEngineをonにすることで、そこから下のコードが有効になります。

2, 3, 4行目はhttpでのアクセスをhttpsにリダイレクトさせるものなので、無くても大丈夫です。

5, 6行目は、リクエストされたURLがファイルやディレクトリだった場合にindex.phpに飛ばさないようにするためのものです。

css, js, メディアファイルなどをサイトで参照するのに必要です。

7行目で、アクセス先をindex.phpに変更させています。

この.htaccessを設置することで、ファイルやディレクトリを除いたどんなURLのアクセスでもindex.phpが実行されるようになります。

ローカルのApache24で実行すると、デフォルトではエラーになると思います。

httpd.confを編集して、RewriteEngineを有効にしましょう。

僕の場合は、rewrite_moduleのコメントアウトを外して有効にし、

画像1

AllowOverrideをAllに変更したりで対応できました。

画像2

index.php内でURLを解析してそれぞれの処理、ページの表示をする

ここからはプログラミングです。

必要な部分を抜粋して載せます。

<?php
include('config.php');

$url = $_SERVER['REQUEST_URI'];
if (strpos($url, '?') > 0)
{
	$url = substr($url, 0, strpos($url, '?'));
}
if ($url == '/') defaultHandle('/index');
else if (strpos($url, '/members/') === 0) membersHandle($url);
else viewPage('/404');

function defaultHandle($url)
{
	viewPage($url);
}

function membersHandle($url)
{
	$link = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
	$mem = substr($url, strlen('/members/'));
	if (substr($mem, strlen($mem) - 1) == '/') $mem = substr($mem, 0, strlen($mem) - 1);
	if ($mem != '')
	{
        //メンバー情報を取得して個別ページを表示
	}
	else if ($result = $link->query('SELECT文'))
	{
		$ret = [];
		while ($row = $result->fetch_assoc())
		{
			if (substr($row['theme_color'], 0, 1) != '#') $row['theme_color'] = '#'.$row['theme_color'];
			array_push($ret, $row);
		}
        //テンプレートHTMLファイルにデータを送る
		viewPage('/members', ['data'=>$ret]);
	}
	else
	{
		viewPage('/500');
	}
	$link->close();
}

function viewPage($page, $data = [])
{
	if (!file_exists('./templates'.$page.'.html'))
	{
		$page = '/404';
	}
	if ($page == '/403')
	{
		http_response_code(403);
	}
	else if ($page == '/404')
	{
		http_response_code(404);
	}
	else if ($page == '/500')
	{
		http_response_code(500);
	}
	$html = file_get_contents('./templates'.$page.'.html');
	foreach ($data as $k => $v)
	{
		if (is_array($v)) $html = str_replace('$'.$k, json_encode($v), $html);
		else $html = str_replace('$'.$k, $v, $html);
	}
	echo $html;
}?>

大体こんなかんじです。

実際はページ数が多いのでもっとごちゃごちゃしてます。

まず、$_SERVER['REQUEST_URI']でリクエストURIを取得します。

この値は、/から始まります。ドメインルートなら/のみです。

GETクエリがあると邪魔なので、if (strpos($url, '?') > 0)の部分で省いています。

そのあとif文でパスがマッチする関数を呼び出してそれぞれの処理、ページ表示を行っています。

viewPage関数では、表示したいテンプレートHTMLファイルの名前と、HTML内に表示させたいデータを受け取っています。

file_get_contents()でHTMLファイルの中身を取得し、str_replace()で適当に中身を調整して、echoで表示しています。

僕はGo言語でWeb開発をすることが多いので、書き方がそれに近いと思います。

templatesフォルダを作ってhtmlファイルを置き、その中にデータを表示させます。

たとえば、viewPage('/members', ['data'=>$ret]);とすると、./templates/members.htmlファイルを表示します。

このhtmlファイル内では、<script>タグ内にlet data = $data;と書いてあります。

これはPHPのviewPage関数内で$dataの文字列がメンバーの情報のJSON文字列に置き換えられるので、それをフロントのJSを使ってドキュメントに表示するような処理をしています。

こうすることで、DBに保存されたメンバーごとの個別URLのページを実現させています。

僕にとってはGo言語で書きなれた書き方なのでこれで特に不満はないのですが、多分人によっては汚いコードに見えるとおもうので、その時は適切にファイルを分けるとかクラスを作るとかしてうまく書き換えてください。



というわけで、PHPでルーティングして若干フレームワークっぽいサイトを作成することが出来ました。

僕はフレームワークってのがどうにも好きになれなくてこんなことしてますが、LaravelとかCakePHPとか好きな人はそれ使ったほうが楽だと思います。

ちょっとだけPHPが楽しくなりました。

おわり

この記事が気に入ったらサポートをしてみませんか?