申請した利用者だけがサイトを閲覧できるようにするには(PHP認証)
図書館には知る人ぞ知るコンテンツがある。WEB目録(PDF)を、閲覧申請をした人にのみアクセスさせたいという要望があった。閲覧申請をした人にはID/PWを発行し、認証を経た上で閲覧させると。
利用の流れはこの通り。
ログイン画面→(認証)→PDFファイル一覧ページ→個々のPDFファイル
この認証を実現させる上で様々な図書やブログ記事を見てみたが(会員制サイトのアクセス制限が多いようだ)、どの方法もうまくいかなかった。
知識がない状態でサイト構築を任せられてしまった人のためにコードを以下にメモしておく。
それぞれの処理はこの通り。
1.ログイン処理はPHPのセッション変数を用いる
2.PDFのアクセス制限を.htaccessとphpを用いて行う
1.はログイン認証をしてPDFファイル一覧ページを表示させる処理。
2.では個々のPDFファイルへ直アクセスされた場合の所作を指定している。
2.PDFのアクセス制限をphpにしたのは、Basic認証だと1ファイルを開く都度、ID/PWを入れねばならず煩雑なためである。
また、.htaccessを用いているので、PDFのみならずあるディレクトリに来たものは、認証を経るようにといった汎用的な使い方ができそうだ。
1.認証→PDFファイル一覧ページの表示
これについては大部分をこの図書に頼った。
PHP初心者にとってサンプルコードが付いているのはありがたい。
この処理で使うファイルは以下の通り。
・login.html:ログイン画面
・ninsho.php:認証チェックプログラム
・data/pw.txt:ID・PWを保存したファイル
・ichiran.php:PDFファイル一覧ページ
・includes/kiroku.php:インクルードファイル。ログインしているかどうかをチェックする処理。
それぞれのファイルにどのように書いたか記す。
「login.html」
<form action='ninsho.php' method='POST'>
ユーザーID
<input type="text" width="20" name="id" maxlength="10" /><br>
パスワード
<input type="password" width="20" name="pass" maxlength="10" /><br>
<input type="submit" value="送信"/>
</form>
このフォームは利用者がID/PWを入力する(だけの)画面。このフォームでID/PWを受け取り、1行目で指定した「ninsho.php」に受け取ったID/PWを投げている。
「pw.txt」
id pw
id2 pw2
IDとパスワードをタブと改行で区切っている。
このファイルは誰にも参照されないように、.htaccessで制限する。
「ninsho.php」
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>WEB目録</title>
</head>
<body>
<?php
session_start();
$fname = 'data/pw.txt';
$result = @file($fname);
$flg = FALSE;
foreach($result as $val){
$id = strtok($val,"\t");
$pass = strtok("\t");
if (trim($id) == $_POST['id'] and trim($pass) == $_POST['pass']){
$_SESSION['ID'] = $id;
$flg = TRUE;
$url = "ichiran.php";
header("Location: $url");
}
}
if (!$flg){
unset($_SESSION['ID']);
echo "ID・パスワードが正しいかご確認ください。<br>もしくはCookieが有効になっているか確認ください。<br>";
}
?>
「login.html」で利用者が入力したID/PWを「pw.txt」と照合し、合っていればセッションを保存して、PDFファイル一覧ページへ飛ばす、間違っていればセッションを消してエラーメッセージを出すという処理を行っている。詳しくは図書を参照。
「kiroku.php」
<?php
tu_checkLogin();
function tu_checkLogin(){
session_start();
if (isset($_SESSION['ID']) == FALSE){
header("Location:http://○○/○○.jp/△△/△△/includes/error.html");
}
}
?>
セッションの存在有無を確認するファイル。
「ninsho.php」でID/PWが間違っている場合、セッションを削除していた。FALSEであれば(認証情報(セッション)が空であれば)エラーに飛ばすという処理。
「error.html」
認証されていません。<br>
必ず、認証を経てからアクセスしてください。<br>
<a href="login.php">戻る</a>
認証されていない場合はこちらのファイルが表示される。
「ichiran.php」
HTMLコンテンツの前にこれを書くことで、まずkiroku.phpの処理が実行されるようにしている。直にこの「ichiran.php」ファイルにアクセスされた場合でも、この処理によりセッションの確認が行われる。OKであればそのまま表示し、NGであれば「error.html」に飛ばす。
2.個々のPDFファイルへ直アクセスされた場合の所作を指定
PDFの場合、「ichiran.php」のようにファイルの冒頭に処理を書くことができない。
そこで、PDFにアクセスされた場合、認証用のphpへリダイレクトし、それを通過した場合だけアクセスを可能にするように設定する。
この処理で使うファイルは以下の通り。
・.htaccess:制限の記述
・includes/kiroku2.php:インクルードファイル。ログインしているかどうかをチェックする処理。
・PDF/○○.pdf:個々のPDFファイル達
まずはリダイレクトさせるために、PDFを置いているディレクトリ「pdf」に「.htaccess」を設置する。
Action application/pdf http://○○/○○.jp/△△/△△/includes/kiroku2.php
パスの書き方が分からなかった(varから書くのか?htmlフォルダのrootから書くのか?)のでURLで記入。PDFにアクセスされた場合は、「kiroku2.php」に飛ばしますよ、という処理。
別法として、こちらでもいけるかも。画像とかwordも制限したい時は、pdfの隣に「|」で拡張子をつなげばいい。(pdf|png)
RewriteEngine on
RewriteRule ^.*\.(pdf)$ /△△/△△/includes/kiroku2.php
検索エンジンに収集されたくないので
<Files ~ "\.(pdf)$">
deny from all
</Files>
を書いてみたが、認証されている場合でも拒否してしまったので削除。
そしてここからが肝心の、セッションがなければ「error.html」に飛ばし、あれば指定のPDFにアクセスさせるという処理。ファイルパスの取得に四苦八苦したが、この方法でうまく渡すことができた。
「$_SERVER['SCRIPT_NAME']」(現在のスクリプトのパス)だとkiroku2.phpを見てしまうようなので、「$_SERVER["REQUEST_URI"]」(ページにアクセスするために指定されたURI)にしている。
「kiroku2.php」
<?php
tu_checkLogin();
function tu_checkLogin(){
session_start();
if (isset($_SESSION['ID']) == FALSE){
readfile(dirname(__FILE__) . "/error.html");
}else{
$file_path = $_SERVER["DOCUMENT_ROOT"] . $_SERVER["REQUEST_URI"];
$file_size = filesize($file_path);
header("Content-Type: application/pdf");
header("Content-Length: $file_size");
readfile($file_path);
}
}
?>
ファイルパスの取得方法については
Apacheで、PDFファイルへのアクセスをフォーム認証へリダイレクトさせたい − Linux Square − @IT
を使わせてもらった。感謝。
以上でちゃんと動作するようになった。ここまで作るのに丸2日がかり。
四苦八苦な日々はまだまだ続く…。