スニペット

DBいらず!PHPセッションだけで作る簡易ログインと限定公開ページの作り方

DB不要の“ちょい制限”ログインページをPHPだけで作る【特典ページ/限定コンテンツ】

制作中のサイトや、購入者だけに見せたい特典ページなど、

がっつり会員制ログインを作るほどではないけど、URL直打ちで誰でも見えてしまうのは困る…


という場面、けっこうありますよね。

そういうときに便利なのが、PHPのセッションだけで作る“簡易ログイン”です。
データベースもユーザー登録機能も用意せず、決め打ちのIDとパスワードを知っている人だけがページを見られるようにする、超シンプルな仕組みです。

この記事では、PHPセッションを使った簡易ログインの作り方と、ログイン画面/ログイン後画面のサンプルデザインまでまとめて紹介します。

先に大事なポイントを書いておくと、このログインはあくまで「閲覧制限」「制作中サイトの仮ロック」「特典ページの入り口」用であり、会員制サイト・個人情報を扱うサービスなどの本番認証には絶対に使わないでください。

「簡易ログイン」のデモはこちら

簡易ログイン画面のサンプルはこちら

簡易ログイン画面

上記のURLを開くとログインフォームがあります。

入力欄に書いてますが、「id」 と 「password」がそのままIDとパスワードになります。

間違った値を入力した際の入力チェックも実装しています。

今回作る「簡易ログイン」の想定ケース

今回紹介するログインフォームは、IDとパスワードが固定の簡易的なログインフォームです。
そのため、次のような用途を想定しています。

  • 制作中サイトを一時的に隠しておきたい(クライアントにだけ見せたい)
  • キャンペーン応募者・メルマガ登録者だけが見られる特典ページ
  • noteや教材などの「購入者限定おまけページ」への入口
  • 社内メンバーだけが見られるお知らせページ・マニュアル

逆に、以下のような用途には向いていません。

  • ユーザー登録フォームがある本格的な会員制サイト
  • メールアドレスや住所などの個人情報を扱うサービス
  • 決済情報・機密情報など、流出すると大きな問題になるデータがあるページ

その場合は、フレームワークや認証ライブラリを使ったちゃんとしたログイン機能を使うようにしましょう。


全体の構成イメージ

ファイル構成はシンプルにこんな感じです。

project/
├─ login.php          … ログイン処理(PHP)
├─ login-page.html    … ログイン画面テンプレート(HTML)
├─ index.php          … ログイン後のトップページ(保護対象)
└─ other-page.php     … その他の保護したいページ
  • login.php:ID・パスワードのチェックとセッションのセット、ログイン画面の表示
  • login-page.html:ログインフォームのデザイン
  • index.php / other-page.php:各ページの先頭でセッションチェックをして、未ログインなら login.php へ飛ばす

ログイン処理(login.php)のコード

まずはログイン処理のPHPファイルです。
今回の簡易ログインシステムの肝となるファイルです。

コードの重要な部分のみ解説しています。
全ソースは最後に掲載しています。

<?php

// ログインID・パスワード(ベタ書きなので本番認証には使わない)
define("LOGIN_ID", "id");
define("LOGIN_PASSWORD", "password");

// ログイン後に飛ばしたいURL(サイトのトップなど)
define("LOGIN_AFFTER_URL", "./");

session_start();

// 一旦初期化(ログイン画面を開いたらログアウト扱いにしたい場合)
$_SESSION["user_name"] = null;

$error_message  = "";
$error_message2 = "";

// ログインボタンが押されたとき
if (isset($_POST["login"])) {

    // IDとパスワードのチェック
    if ($_POST["id"] === LOGIN_ID && $_POST["password"] === LOGIN_PASSWORD) {

        // ★ログイン成功時はセッションIDを再発行しておく
        session_regenerate_id(true);

        // ログイン済みフラグとしてIDを保存
        $_SESSION["user_name"] = LOGIN_ID;

        // ログイン後URLへリダイレクト
        $login_success_url = LOGIN_AFFTER_URL;
        header("Location: {$login_success_url}");
        exit;
    }

    // 認証に失敗した場合
    $error_message  = "ログインできません。";
    $error_message2 = "ID、パスワードをご確認ください。";
    define("LOGIN_ERROR", true);

    include(dirname(__FILE__) . "/login-page.html");

} else {

    // 初回アクセス(フォーム表示)
    include(dirname(__FILE__) . "/login-page.html");
}

exit;
?>

ポイントを簡単に整理しておきます。

  • LOGIN_ID / LOGIN_PASSWORD は決め打ちの1組だけ(超シンプル)
  • ログイン成功時に session_regenerate_id(true); を呼んで、ログイン前のセッションIDを捨てるようにしています
  • 認証失敗時はフラグ LOGIN_ERRORとメッセージをセットして、login-page.html 側でエラー表示できるようにしています

ログイン画面(login-page.html)

ログイン画面(login-page.html)のフォーム部分のコードです。

<?php if (defined("LOGIN_ERROR") && LOGIN_ERROR): ?>
<div class="login__error">
	<strong><?php echo htmlspecialchars($error_message, ENT_QUOTES, "UTF-8"); ?></strong><br>
	<?php echo htmlspecialchars($error_message2, ENT_QUOTES, "UTF-8"); ?>
</div>
<?php endif; ?>

<form method="post" action="login.php">
	<div class="login__field">
		<label class="login__label-text" for="login-id">ID</label>
		<input class="login__input" type="text" name="id" id="login-id" autocomplete="off">
		<p class="login__hint">サンプル:<code>id</code></p>
	</div>

	<div class="login__field">
		<label class="login__label-text" for="login-password">パスワード</label>
		<input class="login__input" type="password" name="password" id="login-password" autocomplete="off">
		<p class="login__hint">サンプル:<code>password</code></p>
	</div>

	<div class="login__actions">
		<button class="login__button" type="submit" name="login" value="1">
		ログイン
		</button>
	</div>
</form>

エラーメッセージ部分は、login.php でセットした
$error_message / $error_message2 / LOGIN_ERROR を利用しています。

各ページでのログインチェック

ログイン後に見せたいページ(index.php や other-page.php)の先頭には、次のようなセッションチェックを入れます。

<?php
// ログインチェック
session_start();
if (!isset($_SESSION["user_name"])) {
    header("Location: login.php");
    exit;
}
?>

これが入っていれば、URL直打ちで index.php を開こうとしても、未ログインなら login.php に飛ばされるようになります。

なぜ session_regenerate_id( ) を入れておくのか

今回のような簡易ログインでも、session_regenerate_id(true); を1行入れておくと、
「ログイン前に使っていたセッションIDを捨てて、新しいIDに差し替える」 ことができます。

これによって、セッションIDの固定(攻撃者にセッションIDを決められてしまうパターン)のリスクを下げることができます。
本格的な会員制サイトでは必須に近い対応ですが、簡易ログインでも入れておいて損はないので、
ログイン成功時にセットで書いておくクセを付けておくと良いと思います。

この簡易ログインを使うときの注意点

  • パスワードはPHPファイル内にベタ書きなので、GitHubなどに公開しないように注意
  • ログインページ・保護ページは、必ずhttpsで配信する(テスト環境含む)
  • 個人情報・決済情報・機密情報を扱うページにはこの仕組みを使わず、フレームワークや認証ライブラリを利用する

あくまで、「制作中サイトの簡易的な閲覧制限」「特典ページや限定コンテンツの入り口」「社内限定ページ」など、ライトな用途向けの仕組みとして使ってもらえればと思います。

まとめ

この記事では、PHPセッションだけで作る簡易ログインの仕組みと、
ログイン画面・ログイン後画面のサンプルデザインを紹介しました。

  • ログイン処理は login.php にまとめる
  • 各ページの先頭でセッションチェックを行い、未ログインなら login.php
  • ログイン成功時には session_regenerate_id(true); を入れておく
  • 用途はあくまで「簡易的な閲覧制限」まで。本番認証には別の仕組みを使う

実務では、「そこまで厳重なログインは要らないけど、誰でも見えてしまうのは困る」という場面が意外と多いので、こういった簡易ログインのパターンを1つ持っておくと、ちょっとした案件で役に立つはずです。

全コード

login.php

<?php

// ログインID・パスワード(ベタ書きなので本番認証には使わない)
define("LOGIN_ID", "id");
define("LOGIN_PASSWORD", "password");

// ログイン後に飛ばしたいURL(サイトのトップなど)
define("LOGIN_AFFTER_URL", "./");

session_start();

// 一旦初期化(ログイン画面を開いたらログアウト扱いにしたい場合)
$_SESSION["user_name"] = null;

$error_message  = "";
$error_message2 = "";

// ログインボタンが押されたとき
if (isset($_POST["login"])) {

    // IDとパスワードのチェック
    if ($_POST["id"] === LOGIN_ID && $_POST["password"] === LOGIN_PASSWORD) {

        // ★ログイン成功時はセッションIDを再発行しておく
        session_regenerate_id(true);

        // ログイン済みフラグとしてIDを保存
        $_SESSION["user_name"] = LOGIN_ID;

        // ログイン後URLへリダイレクト
        $login_success_url = LOGIN_AFFTER_URL;
        header("Location: {$login_success_url}");
        exit;
    }

    // 認証に失敗した場合
    $error_message  = "ログインできません。";
    $error_message2 = "ID、パスワードをご確認ください。";
    define("LOGIN_ERROR", true);

    include(dirname(__FILE__) . "/login-page.html");

} else {

    // 初回アクセス(フォーム表示)
    include(dirname(__FILE__) . "/login-page.html");
}

exit;
?>

login-page.html

<!DOCTYPE html>
<html lang="ja">

<head>
	<meta charset="UTF-8">
	<title>ログイン|簡易ログインサンプル</title>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<style>
		:root {
			--bg: #0f172a;
			--card: #ffffff;
			--accent: #2563eb;
			--accent-soft: rgba(37, 99, 235, 0.15);
			--border: #e5e7eb;
			--text-main: #111827;
			--text-sub: #6b7280;
			--danger: #dc2626;
		}

		* {
			box-sizing: border-box;
		}

		body {
			margin: 0;
			min-height: 100vh;
			font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
			background: radial-gradient(circle at top, #1d4ed8 0, #0f172a 50%, #020617 100%);
			display: flex;
			align-items: center;
			justify-content: center;
			padding: 24px;
		}

		.login {
			width: 100%;
			max-width: 420px;
			background: var(--card);
			border-radius: 20px;
			padding: 28px 24px 24px;
			box-shadow: 0 24px 60px rgba(15, 23, 42, 0.4);
		}

		.login__label {
			display: inline-flex;
			align-items: center;
			gap: 6px;
			font-size: 11px;
			padding: 4px 8px;
			border-radius: 9999px;
			background: var(--accent-soft);
			color: var(--accent);
			margin-bottom: 10px;
		}

		.login__label-dot {
			width: 6px;
			height: 6px;
			border-radius: 9999px;
			background: var(--accent);
		}

		.login__title {
			font-size: 20px;
			font-weight: 600;
			margin-bottom: 4px;
			color: var(--text-main);
		}

		.login__subtitle {
			font-size: 12px;
			color: var(--text-sub);
			margin-bottom: 20px;
			line-height: 1.6;
		}

		.login__error {
			border-radius: 10px;
			padding: 10px 12px;
			background: #fef2f2;
			color: var(--danger);
			font-size: 12px;
			margin-bottom: 16px;
			border: 1px solid #fecaca;
		}

		.login__field {
			margin-bottom: 16px;
		}

		.login__label-text {
			display: block;
			font-size: 12px;
			font-weight: 500;
			margin-bottom: 4px;
			color: var(--text-main);
		}

		.login__input {
			width: 100%;
			padding: 9px 10px;
			border-radius: 10px;
			border: 1px solid var(--border);
			font-size: 14px;
			outline: none;
			transition: border-color 0.15s, box-shadow 0.15s;
		}

		.login__input:focus {
			border-color: var(--accent);
			box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.3);
		}

		.login__hint {
			font-size: 11px;
			color: var(--text-sub);
			margin-top: 4px;
		}

		.login__actions {
			margin-top: 8px;
			display: flex;
			justify-content: flex-end;
		}

		.login__button {
			border: none;
			border-radius: 9999px;
			padding: 9px 18px;
			font-size: 13px;
			font-weight: 600;
			background: var(--accent);
			color: #fff;
			cursor: pointer;
			box-shadow: 0 10px 20px rgba(37, 99, 235, 0.35);
			transition: transform 0.1s ease, box-shadow 0.1s ease, background 0.1s;
		}

		.login__button:hover {
			background: #1d4ed8;
			box-shadow: 0 14px 30px rgba(37, 99, 235, 0.45);
			transform: translateY(-1px);
		}

		.login__button:active {
			transform: translateY(0);
			box-shadow: 0 8px 18px rgba(37, 99, 235, 0.35);
		}

		.login__footer {
			margin-top: 16px;
			font-size: 10px;
			color: var(--text-sub);
			text-align: right;
		}
	</style>
</head>

<body>
	<div class="login">
		<div class="login__label">
			<span class="login__label-dot"></span>
			<span>Internal only</span>
		</div>
		<h1 class="login__title">簡易ログイン</h1>
		<p class="login__subtitle">
			制作中サイトや社内限定ページなど、URLを知っている人だけが見られれば良いページ向けの簡易ログインです。<br>
			会員制サイトや個人情報を扱うサービスでは利用しないでください。
		</p>

		<?php if (defined("LOGIN_ERROR") && LOGIN_ERROR): ?>
		<div class="login__error">
			<strong><?php echo htmlspecialchars($error_message, ENT_QUOTES, "UTF-8"); ?></strong><br>
			<?php echo htmlspecialchars($error_message2, ENT_QUOTES, "UTF-8"); ?>
		</div>
		<?php endif; ?>

		<form method="post" action="login.php">
			<div class="login__field">
				<label class="login__label-text" for="login-id">ID</label>
				<input class="login__input" type="text" name="id" id="login-id" autocomplete="off">
				<p class="login__hint">サンプル:<code>id</code></p>
			</div>

			<div class="login__field">
				<label class="login__label-text" for="login-password">パスワード</label>
				<input class="login__input" type="password" name="password" id="login-password" autocomplete="off">
				<p class="login__hint">サンプル:<code>password</code></p>
			</div>

			<div class="login__actions">
				<button class="login__button" type="submit" name="login" value="1">
					ログイン
				</button>
			</div>
		</form>

		<div class="login__footer">
			※ このログインは簡易的な閲覧制限用です。本番の会員制サイトには利用しないでください。
		</div>
	</div>
</body>

</html>

login-page.html

<?php
// ログインチェック
session_start();
if (!isset($_SESSION["user_name"])) {
    header("Location: login.php");
    exit;
}
?>
<!DOCTYPE html>
<html lang="ja">
ココはご自由に
</html>

学びを深めたいあなたへ:ガチ無料で学べるスクール紹介

そんなあなたにおすすめなのが、完全無料で受けられるプログラミングスクールです。
完全無料で学べるプログラミングスクールなら、プロ講師のサポート付きでHTMLやCSSを基礎から学べます。
私もこちらの受講生なので、体験レポートを参考にして頂けたらと思います。

✅ 初学者のスタートダッシュに最適
✅ HTML/CSSの基礎が無料で学習できる
✅ オンライン完結&未経験OK
✅ Slackで講師に何回でも質問できる

無料の理由や利用者の声を見るならこちら

-スニペット
-,