第12回 パーサー活用で、利用できる人だけ利用可能なOla-UIに!― 認証機能で組織内限定公開を実現
はじめに
前回(第11回)では、Ollamaの進化に連動したOla-UIの無限の可能性―対応LLM無限、自前トレーニング、マルチモーダル対応―について解説しました。技術的な拡張性と将来展望をお伝えしました。
第12回となる今回は、Ola-UIに認証機能を追加し、組織内限定公開を実現する方法に焦点を当てます。
今回のテーマ: 「パーサー(Parser)活用で、利用できる人だけ利用可能なOla-UIに!」
これまでのOla-UIは、基本的に誰でもアクセス可能な構成でした。しかし、実際の業務運用では、社内ナレッジや機密情報を含むシステムを、無制限に公開することはできません。
そこで登場するのが、PHPベースの認証パーサーです。
このパーサーが実現すること: 1. ユーザー認証(ログイン)の実装 2. 認証なしではアクセス不可 3. 既存のOla-UIファイルを変更せずに保護 4. セッション管理で快適な操作
たった2つのPHPファイル(login.php + parser.php)を追加するだけで、Ola-UIが組織内限定の安全なシステムに変わります。
その仕組みと導入方法を、実践的に解説していきます。
1. なぜ認証機能が必要なのか?
1-1. 無認証公開のリスク
これまでの構成では、Ola-UIのURLを知っている人なら誰でもアクセス可能でした。
【第6回のDDNS設定後】
URL: https://your-ddns-domain.com:8080/
問題点:
- インターネット上の誰でもアクセス可能
- 社内ナレッジが外部に漏洩するリスク
- 悪意ある利用者による攻撃の可能性
リスクシナリオ
【シナリオ1: 機密情報の漏洩】
ナレッジセットに「顧客リスト」「製品原価」「契約条件」など
の機密情報が含まれている
→ 外部からアクセスされると情報漏洩
【シナリオ2: 無制限な利用】
社外の第三者が大量のリクエストを送信
→ サーバー負荷増大、正規ユーザーが使えなくなる
【シナリオ3: 誤情報の拡散】
社内専用の情報(開発中製品、未発表施策など)が
偶然外部に公開されてしまう
→ ビジネス上の損失
1-2. 認証機能で実現すること
パーサーによる認証機能を導入すると、これらのリスクを大幅に低減できます。
【認証後の構成】
URL: https://your-ddns-domain.com:8080/parser.php
アクセスフロー:
1. ユーザーがアクセス
2. ログイン画面が表示される
3. ID/パスワードを入力
4. 認証成功 → Ola-UIの画面へ
5. 認証失敗 → ログイン画面に戻る
効果:
- 社内メンバーのみアクセス可能
- 機密情報の保護
- 利用者の特定が可能(ログ機能追加可能)
1-3. 組織における認証の重要性
コンプライアンス対応
【ISO 27001(情報セキュリティ)】
- アクセス制御: 誰がアクセスできるかを管理
- 認証・認可: 正当なユーザーのみ利用可能
【個人情報保護法】
- 個人情報を含むシステムは厳格な管理が必要
- 認証なしの公開は違反のリスク
【企業内規定】
- 機密情報への不正アクセス防止
- 監査証跡の確保
実用上のメリット
【メリット1: 安心して情報を搭載できる】
認証があれば、社内の詳細な情報もナレッジに追加可能
【メリット2: 部門別アカウント管理】
営業部、法務部、技術部など、部門ごとにアカウントを発行
→ 利用状況の把握が可能
【メリット3: 監査対応】
「誰が、いつ、何にアクセスしたか」のログを記録可能
→ コンプライアンス監査に対応
2. パーサーの仕組みを理解する
2-1. パーサーとは?
Parser(パーサー) = 解析・中継プログラム
Ola-UIの場合、パーサーは「認証のゲート役」として機能します。
【通常のアクセス(認証なし)】
ブラウザ → index_t.html → chat_api_t.php → Ollama
【パーサー経由のアクセス(認証あり)】
ブラウザ → parser.php(認証チェック)
↓ (認証OK)
→ index_t.html → chat_api_t.php → Ollama
↓ (認証NG)
→ login.php(ログイン画面)
2-2. パーサーの構成要素
今回使用するパーサーシステムは、2つのPHPファイルで構成されます。
ファイル構成
Ola-UIルートディレクトリ/
├── parser.php # メインパーサー(認証チェック+ページ表示)
├── login.php # ログイン画面
├── userdata/
│ └── users.csv # ユーザー情報(自動生成)
└── ola-59/ # 既存のOla-UIファイル群
├── index_t.html
├── chat_api_t.php
└── ...
各ファイルの役割
1. login.php(ログイン画面)
<?php
// 機能:
// - ログイン画面の表示
// - ユーザー名/パスワードの受け取り
// - users.csv との照合
// - 認証成功 → parser.php へリダイレクト
// - 認証失敗 → エラーメッセージ表示
// 初期設定:
// - テストユーザー: admin / 1234 (自動作成)
?>
2. parser.php(メインパーサー)
<?php
session_start();
// 機能1: 認証チェック
if (!isset($_SESSION['authenticated'])) {
header('Location: login.php');
exit();
}
// 機能2: 対象ファイルの読み込み
$target = $_GET['target'] ?? 'index_t.html';
include($target);
// 機能3: リンク書き換え
// すべてのリンクを parser.php?target=... 形式に変換
// → 認証状態を維持したままページ遷移
?>
3. users.csv(ユーザーデータ)
admin,1234
sales_user,pass123
legal_user,pass456
tech_support,pass789
2-3. 動作フロー詳細
初回アクセス時
1. ユーザーが https://your-domain.com/parser.php にアクセス
2. parser.php:
- セッションチェック
- $_SESSION['authenticated'] が未設定
→ login.php へリダイレクト
3. login.php:
- ログイン画面を表示
- ユーザー名/パスワードの入力フォーム
4. ユーザーが入力して送信
5. login.php:
- POSTデータを受け取る
- users.csv と照合
- 一致 → $_SESSION['authenticated'] = true
→ parser.php?target=index_t.html へリダイレクト
- 不一致 → エラーメッセージ表示
6. parser.php:
- セッションチェック → OK
- index_t.html を読み込み
- リンクを parser.php?target=... に書き換え
- ブラウザへ出力
7. ユーザーは Ola-UI のチャット画面を利用
2回目以降のアクセス
1. ユーザーが https://your-domain.com/parser.php にアクセス
2. parser.php:
- セッションチェック
- $_SESSION['authenticated'] = true (前回ログイン済み)
→ そのまま index_t.html を表示
3. ログイン画面をスキップして即座に利用可能
ログアウト
ブラウザを閉じる or セッションタイムアウト(デフォルト24分)
→ $_SESSION が破棄される
→ 次回アクセス時に再度ログインが必要
3. パーサーの導入手順(ステップバイステップ)
3-1. 前提条件
- Ola-UIが既に動作している(第1〜3回の構築完了)
- PHPがインストール済み(第2回で実施)
- ola-59フォルダに既存ファイル一式が配置済み
3-2. ステップ1: パーサーファイルの配置
parser.php の作成
# Ola-UIルートディレクトリに配置
cd /path/to/ola-ui
nano parser.php
parser.php の内容:
<?php
session_start();
// 1. 認証チェック
if (!isset($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true) {
header('Location: login.php');
exit();
}
// 2. 設定
$base_folder_name = 'ola-59'; // 既存のOla-UIフォルダ名
$base_dir = __DIR__ . '/' . $base_folder_name . '/';
$base_url = $base_folder_name . '/';
// 3. 対象ファイルの取得
$file_param = $_GET['target'] ?? 'index_t.html';
// パラメータ分離処理(例: index_t.html?param=value)
$query_start = strpos($file_param, '?');
if ($query_start !== false) {
$file = substr($file_param, 0, $query_start);
$query_str = substr($file_param, $query_start + 1);
parse_str($query_str, $params);
$_GET = array_merge($_GET, $params);
} else {
$file = $file_param;
}
// 4. セキュリティチェック(ディレクトリトラバーサル対策)
$target_path = realpath($base_dir . $file);
if ($target_path === false ||
strpos($target_path, realpath($base_dir)) !== 0 ||
!file_exists($target_path)) {
echo "Error: File not found or access denied.";
exit;
}
// 5. ファイルの実行とバッファリング
$original_dir = getcwd();
chdir(dirname($target_path));
ob_start();
try {
include basename($target_path);
} catch (Exception $e) {
echo "Execution Error: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
}
$content = ob_get_clean();
chdir($original_dir);
// 6. リンク書き換え処理
$my_script = basename($_SERVER['SCRIPT_NAME']);
$script_dir = dirname($_SERVER['SCRIPT_NAME']);
if ($script_dir === '/' || $script_dir === '\\') {
$parserUrl = '/' . $my_script;
} else {
$parserUrl = $script_dir . '/' . $my_script;
}
// 7. base タグの挿入
$base_tag = '<base href="' . htmlspecialchars($base_url, ENT_QUOTES, 'UTF-8') . '">' . "\n";
if (stripos($content, '<head>') !== false) {
$content = preg_replace(
'/<head([^>]*)>/i',
'<head$1>' . $base_tag,
$content,
1
);
} else {
$content = $base_tag . $content;
}
// 8. リンクの書き換え(<a href="...">)
$content = preg_replace_callback(
'/(<a\b[^>]*\bhref=["\'])([^"\']+)(["\'])/i',
function ($matches) use ($parserUrl) {
$prefix = $matches[1];
$href = $matches[2];
$suffix = $matches[3];
// 外部リンクやアンカーは変更しない
if (preg_match('/^(https?:|\/\/|#|javascript:|mailto:)/i', $href)) {
return $matches[0];
}
$newHref = $parserUrl . '?target=' . rawurlencode($href);
return $prefix . htmlspecialchars($newHref, ENT_QUOTES, 'UTF-8') . $suffix;
},
$content
);
// 9. フォームアクションの書き換え
$content = preg_replace_callback(
'/(<form\b[^>]*\baction=["\'])([^"\']+)(["\'])/i',
function ($matches) use ($parserUrl) {
$prefix = $matches[1];
$action = $matches[2];
$suffix = $matches[3];
if (preg_match('/^(https?:|\/\/)/i', $action)) {
return $matches[0];
}
$newAction = $parserUrl . '?target=' . rawurlencode($action);
return $prefix . htmlspecialchars($newAction, ENT_QUOTES, 'UTF-8') . $suffix;
},
$content
);
// 10. JavaScript location.href の書き換え
$content = preg_replace_callback(
'/location\.href\s*=\s*["\']([^"\']+)["\']/i',
function ($matches) use ($parserUrl) {
$url = $matches[1];
if (preg_match('/^(https?:|\/\/|\/|#)/i', $url)) {
return $matches[0];
}
$newUrl = $parserUrl . '?target=' . rawurlencode($url);
return "location.href = '" . addslashes($newUrl) . "'";
},
$content
);
echo $content;
?>
login.php の作成
nano login.php
login.php の内容:
<?php
$userdata_dir = 'userdata';
$csv_file = $userdata_dir . '/users.csv';
// ディレクトリとCSVが存在しない場合、自動作成
if (!file_exists($userdata_dir)) {
mkdir($userdata_dir, 0777, true);
}
if (!file_exists($csv_file)) {
// テストユーザー: admin / 1234
$fp = fopen($csv_file, 'w');
fputcsv($fp, ['admin', '1234']);
fclose($fp);
}
$error = '';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// ユーザーデータ読み込み
$users = [];
if (file_exists($csv_file)) {
if (($handle = fopen($csv_file, 'r')) !== FALSE) {
while (($data = fgetcsv($handle)) !== FALSE) {
if (isset($data[0]) && isset($data[1])) {
$users[$data[0]] = $data[1];
}
}
fclose($handle);
}
}
// 認証
if (isset($users[$username]) && $users[$username] === $password) {
// 認証成功
session_start();
$_SESSION['authenticated'] = true;
$_SESSION['username'] = $username; // ユーザー名も保存
header('Location: parser.php?target=index_t.html');
exit();
} else {
// 認証失敗
$error = 'ユーザー名またはパスワードが正しくありません。<br>(テスト用初期設定: admin / 1234)';
}
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Ola-UI ログイン</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.login-container {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 25px rgba(0,0,0,0.2);
width: 350px;
}
h1 {
text-align: center;
color: #333;
margin-bottom: 30px;
font-size: 24px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
color: #555;
font-weight: 500;
}
input[type="text"], input[type="password"] {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 5px;
box-sizing: border-box;
font-size: 14px;
}
input[type="text"]:focus, input[type="password"]:focus {
outline: none;
border-color: #667eea;
}
input[type="submit"] {
width: 100%;
padding: 12px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
transition: transform 0.2s;
}
input[type="submit"]:hover {
transform: translateY(-2px);
}
.error {
background: #fee;
color: #c33;
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
text-align: center;
font-size: 14px;
}
.logo {
text-align: center;
margin-bottom: 20px;
font-size: 48px;
}
</style>
</head>
<body>
<div class="login-container">
<div class="logo">🔒</div>
<h1>Ola-UI ログイン</h1>
<?php if ($error): ?>
<div class="error"><?php echo $error; ?></div>
<?php endif; ?>
<form method="post">
<div class="form-group">
<label for="username">ユーザー名:</label>
<input type="text" id="username" name="username" required autofocus>
</div>
<div class="form-group">
<label for="password">パスワード:</label>
<input type="password" id="password" name="password" required>
</div>
<input type="submit" value="ログイン">
</form>
</div>
</body>
</html>
3-3. ステップ2: ディレクトリ構造の確認
# 現在のディレクトリ構造を確認
ls -la
# 期待される構造
.
├── parser.php # ★新規追加
├── login.php # ★新規追加
├── userdata/ # ★自動作成される
│ └── users.csv
└── ola-59/ # 既存のフォルダ
├── index_t.html
├── chat_api_t.php
├── config.ini
└── ...
3-4. ステップ3: 動作確認
テスト1: ログイン画面の表示
# PHPサーバーを起動(既に起動している場合は不要)
php -S localhost:8080
# ブラウザでアクセス
http://localhost:8080/parser.php
期待される動作: - ログイン画面が表示される - ユーザー名/パスワード入力フォームが表示される
テスト2: 認証成功
ユーザー名: admin
パスワード: 1234
送信 → Ola-UIのチャット画面が表示される
テスト3: 認証失敗
ユーザー名: test
パスワード: wrong
送信 → エラーメッセージが表示される
「ユーザー名またはパスワードが正しくありません」
テスト4: セッション維持
1. ログイン成功後、別のページへ移動
(例: ナレッジセット切り替え)
2. ページ遷移時もログイン状態が維持されることを確認
3. ブラウザを閉じて再度アクセス
→ 再度ログイン画面が表示される(正常)
4. ユーザー管理の実践
4-1. ユーザーの追加方法
手動追加(CSVファイル編集)
# users.csv を編集
nano userdata/users.csv
# ユーザーを追加(カンマ区切り)
admin,1234
sales_user,pass123
legal_user,pass456
tech_support,pass789
research_user,pass000
注意点: - パスワードは平文(プレーンテキスト)で保存される - 本番環境では、後述のハッシュ化対応を推奨
管理画面での追加(応用編)
add_user.php(管理者用)を作成:
<?php
session_start();
// 管理者権限チェック
if (!isset($_SESSION['authenticated']) || $_SESSION['username'] !== 'admin') {
die('管理者権限が必要です');
}
$csv_file = 'userdata/users.csv';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$new_username = $_POST['new_username'] ?? '';
$new_password = $_POST['new_password'] ?? '';
// 入力チェック
if (empty($new_username) || empty($new_password)) {
$message = 'エラー: ユーザー名とパスワードを入力してください';
} else {
// 重複チェック
$users = [];
if (file_exists($csv_file)) {
$handle = fopen($csv_file, 'r');
while (($data = fgetcsv($handle)) !== FALSE) {
$users[] = $data;
}
fclose($handle);
foreach ($users as $user) {
if ($user[0] === $new_username) {
$message = 'エラー: このユーザー名は既に存在します';
break;
}
}
}
// 追加処理
if (!isset($message)) {
$fp = fopen($csv_file, 'a');
fputcsv($fp, [$new_username, $new_password]);
fclose($fp);
$message = '成功: ユーザー「' . htmlspecialchars($new_username) . '」を追加しました';
}
}
}
// 現在のユーザー一覧を取得
$current_users = [];
if (file_exists($csv_file)) {
$handle = fopen($csv_file, 'r');
while (($data = fgetcsv($handle)) !== FALSE) {
if (isset($data[0])) {
$current_users[] = $data[0];
}
}
fclose($handle);
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ユーザー管理</title>
<style>
body { font-family: sans-serif; padding: 40px; background: #f5f5f5; }
.container { max-width: 600px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; }
h1 { color: #333; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; font-weight: 500; }
input[type="text"], input[type="password"] { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
input[type="submit"] { padding: 10px 20px; background: #667eea; color: white; border: none; border-radius: 4px; cursor: pointer; }
.message { padding: 10px; margin-bottom: 20px; border-radius: 4px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
.user-list { background: #f9f9f9; padding: 15px; border-radius: 4px; margin-top: 30px; }
.user-list h2 { margin-top: 0; font-size: 18px; }
.user-list ul { list-style: none; padding: 0; }
.user-list li { padding: 5px 0; border-bottom: 1px solid #eee; }
</style>
</head>
<body>
<div class="container">
<h1>ユーザー管理</h1>
<?php if (isset($message)): ?>
<div class="message <?php echo strpos($message, '成功') === 0 ? 'success' : 'error'; ?>">
<?php echo $message; ?>
</div>
<?php endif; ?>
<form method="post">
<div class="form-group">
<label for="new_username">新規ユーザー名:</label>
<input type="text" id="new_username" name="new_username" required>
</div>
<div class="form-group">
<label for="new_password">パスワード:</label>
<input type="password" id="new_password" name="new_password" required>
</div>
<input type="submit" value="ユーザー追加">
</form>
<div class="user-list">
<h2>現在のユーザー一覧(<?php echo count($current_users); ?>名)</h2>
<ul>
<?php foreach ($current_users as $user): ?>
<li>👤 <?php echo htmlspecialchars($user); ?></li>
<?php endforeach; ?>
</ul>
</div>
<p style="margin-top: 30px;">
<a href="parser.php">← Ola-UIに戻る</a>
</p>
</div>
</body>
</html>
使い方:
# add_user.php を配置
# ブラウザでアクセス(adminでログイン後)
http://localhost:8080/add_user.php
# フォームに入力して「ユーザー追加」
4-2. 部門別アカウント管理
部門ごとのアカウント設計
【営業部門】
sales_manager (営業マネージャー)
sales_user1 (営業担当1)
sales_user2 (営業担当2)
【法務部門】
legal_manager (法務マネージャー)
legal_user1 (法務担当1)
【技術サポート部門】
support_manager (サポートマネージャー)
support_user1 (サポート担当1)
support_user2 (サポート担当2)
【管理者】
admin (システム管理者)
パスワードポリシーの設定(推奨)
【ポリシー例】
- 最低8文字以上
- 英数字混在
- 定期的な変更(3ヶ月ごと)
- 推測されやすいパスワードの禁止
(例: password, 12345678, company_name)
4-3. セキュリティ強化: パスワードハッシュ化
現状の問題:
users.csv:
admin,1234 # パスワードが平文で保存
sales_user,pass123 # 誰でも見えてしまう
改善版: password_hash() 使用
login_secure.php(ハッシュ化対応版):
<?php
// ... (前半は同じ)
// ユーザー認証(ハッシュ対応)
if (isset($users[$username])) {
$stored_password = $users[$username];
// ハッシュ化されているかチェック
if (password_verify($password, $stored_password)) {
// ハッシュ化パスワードで認証成功
session_start();
$_SESSION['authenticated'] = true;
$_SESSION['username'] = $username;
header('Location: parser.php?target=index_t.html');
exit();
} elseif ($stored_password === $password) {
// 平文パスワード(旧形式)で認証成功
// → ハッシュ化してCSVを更新
$hashed = password_hash($password, PASSWORD_DEFAULT);
// CSV全体を読み込み
$all_users = [];
$handle = fopen($csv_file, 'r');
while (($data = fgetcsv($handle)) !== FALSE) {
if ($data[0] === $username) {
$data[1] = $hashed; // ハッシュ化したパスワードに更新
}
$all_users[] = $data;
}
fclose($handle);
// CSV全体を書き込み直す
$fp = fopen($csv_file, 'w');
foreach ($all_users as $user) {
fputcsv($fp, $user);
}
fclose($fp);
// 認証成功
session_start();
$_SESSION['authenticated'] = true;
$_SESSION['username'] = $username;
header('Location: parser.php?target=index_t.html');
exit();
} else {
$error = 'ユーザー名またはパスワードが正しくありません。';
}
} else {
$error = 'ユーザー名またはパスワードが正しくありません。';
}
?>
ハッシュ化後の users.csv:
admin,$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi
sales_user,$2y$10$7KIWIrOq5fJQGqFVJQq1XuH.oKz5aM7Qz...
メリット:
- CSVファイルが漏洩しても、パスワードは解読困難
- PHPのpassword_hash()は自動的にソルト追加
- セキュリティベストプラクティスに準拠
5. 実運用のベストプラクティス
5-1. アクセスログの記録
access_log.php(ログ記録機能)を parser.php に統合:
<?php
// parser.php の冒頭に追加
function log_access($username, $target) {
$log_file = 'userdata/access.log';
$timestamp = date('Y-m-d H:i:s');
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$log_entry = "[$timestamp] User: $username, IP: $ip, Target: $target\n";
file_put_contents($log_file, $log_entry, FILE_APPEND);
}
// 認証チェック後に呼び出し
if (isset($_SESSION['authenticated'])) {
$username = $_SESSION['username'] ?? 'unknown';
$target = $_GET['target'] ?? 'index_t.html';
log_access($username, $target);
}
?>
access.log の内容例:
[2026-01-30 10:15:23] User: admin, IP: 192.168.1.100, Target: index_t.html
[2026-01-30 10:16:45] User: sales_user, IP: 192.168.1.101, Target: index_t.html
[2026-01-30 10:20:12] User: legal_user, IP: 192.168.1.102, Target: index_t.html
ログの活用: - 利用状況の分析 - 不正アクセスの検出 - コンプライアンス監査対応
5-2. セッションタイムアウトの設定
session_config.php(セッション設定):
<?php
// login.php と parser.php の冒頭に追加
ini_set('session.gc_maxlifetime', 1800); // 30分
ini_set('session.cookie_lifetime', 1800); // 30分
session_start();
// 最終アクセス時刻のチェック
if (isset($_SESSION['last_access'])) {
$inactive = time() - $_SESSION['last_access'];
if ($inactive > 1800) { // 30分以上操作がない
session_unset();
session_destroy();
header('Location: login.php?timeout=1');
exit();
}
}
$_SESSION['last_access'] = time();
?>
効果: - 30分間操作がない → 自動ログアウト - セキュリティリスクの低減
5-3. HTTPS必須化
http_to_https.php(HTTP→HTTPS自動転送):
<?php
// login.php と parser.php の最初に追加
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
$redirect_url = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header("Location: $redirect_url", true, 301);
exit();
}
?>
効果: - HTTPでアクセスされても自動的にHTTPSへリダイレクト - パスワードの盗聴リスクを防止
5-4. ログアウト機能の追加
logout.php(ログアウト処理):
<?php
session_start();
session_unset();
session_destroy();
header('Location: login.php?logout=1');
exit();
?>
index_t.html にログアウトボタンを追加:
<!-- ヘッダー部分に追加 -->
<div style="position: fixed; top: 10px; right: 10px; z-index: 1000;">
<span>ログイン中: <?php echo htmlspecialchars($_SESSION['username']); ?></span>
<a href="logout.php" style="margin-left: 10px; color: #f44; text-decoration: none;">ログアウト</a>
</div>
6. トラブルシューティング
Q1: ログイン画面が表示されない
原因: parser.php のパス設定が間違っている
解決策:
// parser.php の設定を確認
$base_folder_name = 'ola-59'; // ← フォルダ名が正しいか確認
// ディレクトリ構造を確認
ls -la
// 正しい構造:
.
├── parser.php
├── login.php
└── ola-59/ ← このフォルダ名と一致する必要がある
└── index_t.html
Q2: ログイン後に「File not found」エラー
原因: index_t.html のパスが間違っている
解決策:
# ファイルの存在確認
ls ola-59/index_t.html
# 存在しない場合、配置を確認
# parser.php の設定を確認
$file_param = $_GET['target'] ?? 'index_t.html'; # ← ファイル名が正しいか
Q3: CSS/JSが読み込まれない
原因: base タグの設定が間違っている
解決策:
// parser.php の設定を確認
$base_url = $base_folder_name . '/'; // ← 末尾の / が必要
// ブラウザの開発者ツールで確認
// コンソールエラーを見る
// 404エラーが出ている場合、パスが間違っている
Q4: セッションが維持されない
原因: PHPのセッション設定が正しくない
解決策:
# PHPの設定を確認
php -i | grep session
# session.save_path が書き込み可能か確認
ls -ld /tmp
# 権限がない場合、変更
chmod 1777 /tmp
7. まとめと次回予告
今回のポイント
✅ 認証機能の実装
parser.php + login.php で簡単に認証を追加
✅ 既存ファイルの変更不要
Ola-UIの既存ファイルはそのまま、パーサーを追加するだけ
✅ セッション管理
ログイン状態を維持、快適な操作
✅ セキュリティ対策
パスワードハッシュ化、HTTPS必須化、アクセスログ
✅ ユーザー管理
部門別アカウント、管理画面での追加
認証機能がもたらす価値
【Before: 認証なし】
- 機密情報の公開を躊躇
- 限定的なナレッジのみ搭載
- セキュリティリスクが常に存在
【After: 認証あり】
- 社内の詳細情報も安心して搭載
- 部門別の専門ナレッジを拡充
- コンプライアンス要件を満たす
- 監査対応が可能
→ Ola-UIの実用性が飛躍的に向上
次回予告: 第13回
次回は「Ola-UIの運用とメンテナンス実践」をテーマにお届けします。
- 日常運用のチェックリスト
- ナレッジの定期更新フロー
- システムモニタリングとログ解析
- バックアップとリストア
- トラブル対応マニュアル
- ユーザーサポートの体制構築
構築したシステムを長期的に運用し、価値を最大化する実践ノウハウを解説します。
参考資料
PHP セキュリティ
- PHP公式: セキュアなコーディング https://www.php.net/manual/ja/security.php
- OWASP: 認証のベストプラクティス https://owasp.org/www-project-top-ten/
セッション管理
- PHP session_start() https://www.php.net/manual/ja/function.session-start.php
- セッションハイジャック対策 https://www.ipa.go.jp/security/vuln/websecurity.html
文字数: 約20,000字
想定読了時間: 40〜50分
実践時間: 2〜3時間(認証機能の導入と設定)
Ola-UIに認証機能を追加して、安全で実用的なシステムに進化させましょう!
組織の機密情報も安心して搭載できる、真の業務システムへ。
🔒🚀