初心忘るべからず

新米システムライブラリアンの備忘録

申請した利用者だけがサイトを閲覧できるようにするには(PHP認証)

図書館には知る人ぞ知るコンテンツがある。WEB目録(PDF)を、閲覧申請をした人にのみアクセスさせたいという要望があった。閲覧申請をした人にはID/PWを発行し、認証を経た上で閲覧させると。

 

利用の流れはこの通り。
ログイン画面→(認証)→PDFファイル一覧ページ→個々のPDFファイル

 

この認証を実現させる上で様々な図書やブログ記事を見てみたが(会員制サイトのアクセス制限が多いようだ)、どの方法もうまくいかなかった。
知識がない状態でサイト構築を任せられてしまった人のためにコードを以下にメモしておく。

 

それぞれの処理はこの通り。
1.ログイン処理はPHPのセッション変数を用いる
2.PDFのアクセス制限を.htaccessphpを用いて行う

 

1.はログイン認証をしてPDFファイル一覧ページを表示させる処理。
2.では個々のPDFファイルへ直アクセスされた場合の所作を指定している。

 

2.PDFのアクセス制限をphpにしたのは、Basic認証だと1ファイルを開く都度、ID/PWを入れねばならず煩雑なためである。
また、.htaccessを用いているので、PDFのみならずあるディレクトリに来たものは、認証を経るようにといった汎用的な使い方ができそうだ。

 

 

1.認証→PDFファイル一覧ページの表示

これについては大部分をこの図書に頼った。

ci.nii.ac.jp

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

<?php
include('./includes/kiroku.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」を設置する。

.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日がかり。
四苦八苦な日々はまだまだ続く…。