今回より複数回に分けてhtml/css、javascript、PHP/MySQLを利用した「CMSと動的ホームページの完全自作」についてまとようと思います。
簡単に言えば、ワードプレス(CMS)と、テーマの双方を全て自作するような内容です。(もちろんワードプレスには及びませんが、、)
けっこうなボリュームがありますが、フロントからサーバーサイドまでの幅広い範囲で知識を得られるかと思いますので、少し大変かもしれませんがこれからプログラミングを勉強しようとしている方々の参考になれば幸いです。
※過去に、ここのブログにて「ECサイトのフルスクラッチ開発」をまとめているので、そちらの方を一通り進めてもらえれば、今回のCMS自作にとっかかりやすいかと思います。↓
はじめに、これから作成する「CMSと動的ホームページの完全自作」の完成形を載せておきます。前半がCMSで、後半がCMSで作成した動的WEBページになります。↓
今回、自作CMSで作成した動的サイトは下記URLにて公開していますので、是非ご覧ください。
※CMSは操作できません。
それではまず、これから作成するサイトの概要から説明いたします。
目次
概要
全体像
おおまかに分けると、3つのブロックから成り立ちます。
1つは、「公開する動的サイトのページ」個人ブログのような形式とします。
2つ目は「CMS」動的サイトの管理ページ。
3つ目は「データベース」
になります。
ユーザーが閲覧するサイトの内容は、ユーザーのリクエストに対して、1つのページをデータベースの情報によって動的に変化させる「動的ページ」なります。
全体の仕組みとしては、
①管理者がCMSで記事の投稿、各種メニューの配置などサイトに必要な内容を入力。
②CMSで入力した内容がデータベースに反映。
③公開ページは、ユーザーのリクエストの応じてデータベースに登録された情報を反映。
ざくっとですが、このような流れの仕組みをhtml/css、javascript、PHP/MySQLで作ります。
それでは、まず「CMS」の作成を進めて行こうと思います。CMSが完成後、動的ページの作成に移りたいと思います。
今回は、CMSの「ログインページ」と、「トップ」ページを作成します。
開発環境
PCはWindowsを使用する事前提で進めますが、Macでもほぼ同じだと思います。
WEBサーバーとデータベースは「XAMPP」を使用し、ローカルで開発します。
XAMPPについては過去記事でインストール方法をまとめていますので、分からなければ参照してください。↓
CMS画面作成の流れ
図のような流れの登録画面を作成します。
各ファイルの作成にあたり、基礎的な内容については端折っていきますので、説明足らずな部分があれば、冒頭の過去記事「ECサイトのフルスクラッチ開発」を先に、参考にしてもらえれば幸いです。
とりあえず今回は、星マークのset_login.php~set_top_done.phpまでを作成します。
まだdbに管理者情報がないので、とりあえず1人作成します。
データベース、テーブルの作成
それではまず、データベースを作成します。
XAMPPのMySQLを立ち上げて、データベースを作成します。データベース名は「test」とします。
続いてtestの配下に、管理者情報のテーブルを作成します。テーブル名は「login」とします。
カラムは3とし、下図のように「code」「name」「password」のカラム名、データ型、AI(AUTO_INCREMENT)を設定します。
ちなみに、今回管理者の登録ページは作成していないので、php myadminからsqlで直接管理者情報を登録しておいてください。
※パスワードはmd5で暗号化させた値を登録させておきます。今気づきましたが、上の画像ではpasswordのデータ型がintになってますが、正しくは下記表のvarcharになります。
カラム名 | データ型 | その他 |
code | int | AI |
name | varchar 値50 | – |
password | varchar 値32 | – |
cmsのPHPファイルの作成場所
ここからphpファイルの作成に入ります。
xamppのApache(WEBサーバー)のドキュメントルート(サーバーのアクセス先)は図の通りxamppフォルダのhtdocs配下になります。
デフォルトでindex.htmlが入っていると思うので、ローカルホストのipをブラウザで打ち込めばそれが開くはずです。ちなみにローカルホストは「127.0.0.1」でもアクセス出来ます。
今回はここに「cmsディレクトリ」を作成し、その配下に公開サイトのphpファイルを今後作成していきます。
cmsのファイルは、cmsディレクトリ配下に「settingディレクトリ」を作成し、その配下にphpファイルを格納していきます。今回はまず「set_login.php」~「set_top_done.php」のファイルを作成します。
CMSログイン画面
set_login.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cmsログイン</title> <link rel="stylesheet" href="../style.css"> </head> <body> ログイン情報を入力してください。 <br><br> 管理者名<br> <form action="login_check.php" method="post"> <input type="text" name="name"> <br> パスワード<br> <input type="password" name="pass"> <br> パスワード再入力<br> <input type="password" name="pass2"> <br><br> <input type="submit" value="OK"> </form> </body> </html> |
settingディレクトリ配下にset_login.phpを作成します。
特に説明はいらないかと思います、ただformタグで管理者の名前、パスワード、パスワードの再入力欄を作っているだけです。
submitボタンで、次ページのlogin_check.phpに値をpostします。
このページ、拡張子はhtmlでも問題ありませんね。
Apacheを起動させて、127.0.0.1/cms/setting/set_login.phpにアクセスするとこのような画面が出るはずです。↓
ログインチェック画面
login_check.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?php try{ require_once("../common/common.php"); $post = sanitize($_POST); $name = $post["name"]; $pass = $post["pass"]; $pass2 = $post["pass2"]; if(empty($name) === true or empty($pass) === true or $pass != $pass2) { print "ログイン情報が間違っています。<br><br>"; print "<form>"; print "<input type='button' onclick='history.back()' value='戻る'>"; print "</form>"; exit(); } $dsn = "mysql:host=localhost;dbname=test;charset=utf8"; $user = "root"; $password = ""; $dbh = new PDO($dsn, $user, $password); $dbh -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $sql = "SELECT name FROM login WHERE name=? && password=?"; $stmt = $dbh -> prepare($sql); $data[] = $name; $data[] = $pass; $stmt -> execute($data); $rec = $stmt -> fetch(PDO::FETCH_ASSOC); if(empty($rec["name"]) === true) { print "ログイン情報が間違っています。<br><br>"; print "<form>"; print "<input type='button' onclick='history.back()' value='戻る'>"; print "</form>"; exit(); } session_start(); $_SESSION["login"] = 1; $_SESSION["name"] = $rec["name"]; header("Location:set_top.php"); } catch(Exception $e) { print "只今障害が発生しております。<br><br>"; print "<a href='set_login.php'>戻る</a>"; } ?> |
settingディレクトリ配下にlogin_check.phpを作成します。
このページで、入力に誤りがないかをチェックします。
先頭のrequire_onceで、エスケープの関数(sanitize)をインクルードしています。
今後、この関数は頻繁に使用するので、このファイルを1つ上の階層「cms」に、「commonディレクトリ」を作って、その中に関数ファイルとなる「commonファイル」を格納します。
common.php
1 2 3 4 5 6 7 8 9 10 |
<?php function sanitize($before) { foreach($before as $key => $value) { $after[$key] = htmlspecialchars($value, ENT_QUOTES,"UTF-8"); } return $after; } ?> |
sanitizeの引数に$_POSTが入ります。foreachで、$_POSTの各添え字の値を順番に抜き出し、htmlspecialcharsでエスケープさせて、仮の変数の同じ添え字に戻します。つまり、この結果をリターンすれば、$_POSTの値が全てエスケープ処理される事になります。
postの値を受け取った後、名前の入力の有無、パスワードの有無、再入力の不一致を確認しています。
入力に問題が無ければデータベース接続し、loginテーブルの管理者情報と、入力された値が一致するかを確認します。
ログイン情報が一致すれば、セッションを開始させて、headerでCMS管理のトップページへ遷移させます。
CMSトップ画面
set_top.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<?php session_start(); session_regenerate_id(true); if(isset($_SESSION["login"]) === false) { print "ログインしていません。<br><br>"; print "<a href='set_login.php'>ログイン画面へ</a>"; exit(); } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cms</title> <link rel="stylesheet" href="style.css"> </head> <body> <strong>カテゴリー追加</strong><br><br> <a href="o_menu_add.php">親カテゴリ追加</a> <br><br> <a href="k_menu_add.php">子カテゴリ追加</a> <br><br><br> <strong>記事投稿</strong><br><br> <a href="../edit_single.php">新規記事作成</a> <br><br><br> <strong>メニュー追加</strong><br><br> <a href="../edit_page.php">固定ページ作成</a> <br><br><br> <strong>プロフィール</strong><br><br> <a href="pro.php">プロフィール作成</a> <br><br><br> <strong>スポンサー</strong><br><br> <a href="sp.php">スポンサーリンク作成</a> <br><br><br> <strong>コメントチェック</strong><br><br> <a href="comment_check.php">コメント認証・削除</a> <br><br> <a href="comment_list.php">コメントリスト・返信</a> <br><br><br> <strong>ログアウト</strong><br><br> <a href="logout.php">ログアウト</a> </body> </html> |
settingディレクトリ配下にset_top.phpを作成します。
ここがCMSの管理画面トップになるので、各メニュー画面へのリンクを貼りつけていきます。
先頭のセッションIDの確認は、ログイン後のCMS関連のすべてのページで実施します。権限がないのに、CMSをいじくられるのは非常にまずいからです。
それでは、ログインしてみましょう。下のような画面になるはずです。
ログアウト画面
logout.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?php session_start(); $_SESSION = array(); if(isset($_COOKIE[session_name()]) === true) { setcookie(session_name(), "", time()-42000, "/"); } session_destroy(); ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ログアウト</title> <link rel="stylesheet" href="style.css"> </head> <body> ログアウトしました。<br><br> <a href="set_login.php">ログイン画面へ</a> </body> </html> |
settingディレクトリ配下にlogout.phpを作成します。
cmsログアウトの画面になります。
セッションの解除、ブラウザに残っているcookieの情報を消去しています。
それでは、トップ画面の下部にあるログアウトをクリックしてみます。下記のようになればOKです。
次回は、カテゴリー追加画面を作成します。
初めまして。kといいます。
phpを独学で習得しているものです。
こちらのcmsを、コードを見ながら手打ちしているのですが、ローカル環境にて
「Warning: Undefined variable $after in C:\xampp\htdocs\cms\common\common.php on line 7
Warning: Trying to access array offset on value of type null in C:\xampp\htdocs\cms\setting\login_check.php on line 7
Warning: Trying to access array offset on value of type null in C:\xampp\htdocs\cms\setting\login_check.php on line 8
Warning: Trying to access array offset on value of type null in C:\xampp\htdocs\cms\setting\login_check.php on line 9」
このように表示されます。
dlしたコードを直接コピペしても、同様の結果でした。
調べたところ、phpのバージョンアップによるローカルでのみの現象でした。
valueをarrayを使って配列宣言して回避するとのことですが、記述の仕方が分かりません。
図々しいとは思いますが、記述を教えていただけませんか?
恐縮ですが、何卒よろしくお願いします。
kさま、はじめまして管理人です。
問い合わせ頂きました内容をこちらの環境で試してみましたが、エラーは出ておりません。(PHP ver 7.4.27)
PHP 7.4以降は配列は初期指定しないとエラーとなる(しないと変数を連想配列として参照できない)、との情報がありますが、上記common.phpでは該当する箇所が無い気が。。申し訳ありませんが、同じ環境でないためエラーの原因は分からないです。
見当違いのアドバイスになるかもしれませんが、以下コードをforeachの前に記述すれば、一応valueとafter変数を連想配列として初期設定できます。(関係ないと思われますが。。)
う~ん、、値はpostされてきてますかね?そっちの方があやしいかもです。
パッとしない答えですみません。(-_-;)
$value = array(“test”=>null);
$after = array(“test”=>null);
>ketunorobioさま
詳しいご回答、ありがとうございます。
ketunorobioさまの環境、またコードに問題ないとのこと。
こちらで手打ちしたときに、ミスをしているかもしれません。
もう一度、dlしたコードとの比較・ローカル動作を確認してみます。
また、小規模のプログラムを作って、コードの動きを把握できるよう学習していきます。
丁寧かつ迅速なご回答、心から感謝いたします。
本当にありがとうございました。
すみません、追加です。
自分の環境はphp8です。
一度バージョンを落として、ketunorobioさまと同じ環境で試してみます。
結果が出たら、またこちらにコメントさせていただきます。
kです。
ログイン出来るようになりました!
sqlにて、管理者情報を登録出来ていなかったのが原因でした。
お手数おかけして申し訳ありませんでした。
初めまして。
PHPの勉強をしており、初めての自作WEBアプリでCMSを作りたいと思いこの記事にたどり着きました。
CMS作成にとりかかるとき、どのように調べて作業を進めていますか?
例えば、親カテゴリと子カテゴリの作り方など、自身で考えて作られたのか、作り方がどこかに載っていて参考にされたのか知りたいです。
参考にしている書籍や記事がありましたら、教えていただきたいです。
お手数ですが、よろしくお願いいたします。
ななし様はじめまして、管理人です。
お返事がおくれてしまい申し訳ありません(-_-;)
CMSにつきましては、基本自力で考えて作成しました。(のでかなりコードとかは汚いと思います汗)
お役に立てるか分かりませんが、下記にてご質問に対しての回答をまとめます。
下地1:簡単な静的WEBページを作成できるレベル(HTML/css,js)を身につけました。
書籍はあまり見てなかったきがします。ググって調べてました。
下地2:簡単な動的ページ(ECサイト)を作成できるレベルを身につけました。参考にしたのは「気づけばプロ並みPHP」です。
私は未だに基礎しか知りませんが、PHPやデータベースに関する基礎知識はほぼこの書籍で学びました。
この2つの下地があれば、オリジナルのCMSを作成できるかと思います。
あとは自分で作成したいCMSの全体像を決めて、それを作りこんでいくだけですが、
なにかと躓くポイントか出てきますので、そこはその都度ググって解決していく感じでした。
(ググったサイトはたくさんあるので忘れてしまいました、スイマセン)
親カテゴリ子カテゴリも自力で作成しましたが、下地があれば実装方法のアイデアも思い浮かぶかと思います。
以上でございます。
。。
なんか回答になってないですね、申し訳ないです(;^ω^)
ふわっとした質問にご丁寧にお答えいただき有難うございました!!!
参考にさせていただきます!
コメント失礼します。
こちらgithubなどでデータは公開していないでしょうか?
コメントありがとうございます。
githubに公開はしておりませんが、当該cms記事の12にてデータをDL出来るようリンクを貼り付けております。
もし宜しければそちらのデータをお使いください。
管理人