WordPressと携帯とPHPのBasic認証(セーフモード版も)

WordPressにおいて、特定の投稿・カテゴリーなどを登録ユーザーのみに閲覧させたいという要望はよくあること。
通常であれば、header.php の初めあたりで is_user_logged_in や is_singular などの条件分岐タグと auth_redirect で特定の条件の場合はログイン画面に遷移するコードを書けばOKです。

<?php
// カスタム投稿タイプ member はログイン済みのユーザーのみ閲覧可能にする
if ( !is_user_logged_in() && is_singular('member') ) {
	auth_redirect();
}
?>

ところが、そこに携帯端末(フィーチャーフォン)も対応させようとして、少しはまりました。

要望

  1. サイト自体はWordPressで構築。PC、スマートフォン、携帯で閲覧できるように。
  2. カスタム投稿タイプ「member」の内容はID・パスワードを入力しないと閲覧できない(ただしタイトルはトップページ等にも表示させたい)。
  3. ユーザーの管理はWordPressで行う。

先に書いたコードはPC、スマートフォンでは何ら問題なく動作します。
(プラグイン「Theme My Login」を使い固定ページにログインフォームをつけたり、権限毎にログイン・アウト後の挙動を変更しています)

携帯での実装

さて携帯です。(なお、表示には「Ktai Style 」+独自テーマを使っています。)
Ktai Styleにも管理画面へのログイン機能がついているのですが、私の環境で上手く動作しなかったことと(もしかすると Theme My Login のせいかも)、閲覧の制限だけできればよいこと、そもそも携帯の機種によってはCookieに対応していないことからPHPでBasic認証を行うようにしました。

phpでベーシック認証 – bnote」を参考に 携帯用テーマのfunctions.phpにコードを追加。

<?php
/**
* Basic認証をかける
*/
function basic_auth(){
	if(!isset($_SERVER["PHP_AUTH_USER"])) {
		header('WWW-Authenticate: Basic realm="User Only"');
		header('HTTP/1.0 401 Unauthorized');
		header('Content-type: text/html; charset='.mb_internal_encoding());
		die('認証に失敗しました<br><a href="'.ks_blogurl(false).'">HOME</a>');
	} else {
		if(AuthenticateUser($_SERVER["PHP_AUTH_USER"],$_SERVER["PHP_AUTH_PW"])){ // この行で入力されたID・パスワードのチェックを行う
			// 認証成功後の処理
			return true;
		} else {
			// 認証エラーの処理
			header('WWW-Authenticate: Basic realm="User Only"');
			header('HTTP/1.0 401 Unauthorized');
			header('Content-type: text/html; charset='.mb_internal_encoding());
			die('認証に失敗しました<br><a href="/".ks_blogurl(false).'">HOME</a>');
		}
	}
}

/**
* 入力された情報がWordPressの登録ユーザーかどうか判定
*/
function AuthenticateUser($user,$pwd){
	$flg = false;

	// 入力されたユーザー名(ID)からWordPressのユーザー情報を取得
	$user_data = get_userdatabylogin($user);

	if(!$user_data){ // ユーザー情報がなかったら
		return $flg;
	}

	// WordPressの関数を使って入力されたパスワードとユーザー情報のパスワードをチェック
	if(wp_check_password($pwd,$user_data->user_pass,$user)) {
		//認証成功時の処理
		$flg = true;
	} else {
		//認証失敗時の処理
	$flg = false;
	}

	return $flg;
}
?>

さらに携帯用テーマのheader.php に以下を追記。

<?php
/* カスタム投稿タイプ member の時のみBasic認証 */
if ( is_singular('member') ) {
	basic_auth();
}

これで無事、閲覧制限をかけられました。

落とし穴:PHPがセーフモードの場合、BASIC認証できない

これでOKと思いきや、セーフモード(CGI版のPHP)ではBasic認証を行えません
最後までこれに気づかなかったのは、テスト用と実際に運用する サーバーとでPHPの環境が違ったためです。
そこで「ヒットアーツ -日記ブログ- » CGI版PHPにおけるHTTP認証(Basic認証)」 を参考に、.htaccess に追記(WordPressのパーマリンクをカスタムにしている場合)。

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*) # ←追記
RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1] # ←追記
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

WordPressのリライトルールより上に書かないと上手く動かないようでしたが、これでようやく終了です。

参考にしたサイト