<?php
/**
 * アクセス制御マネージャー
 *
 * PHP versions 5
 *
 * LICENSE: This source file is licensed under the terms of the GNU General Public License.
 *
 * @package    Magic3 Framework
 * @author     平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
 * @copyright  Copyright 2006-2009 Magic3 Project.
 * @license    http://www.gnu.org/copyleft/gpl.html  GPL License
 * @version    SVN: $Id: accessManager.php 2991 2010-03-30 12:43:38Z fishbone $
 * @link       http://www.magic3.org
 */
require_once(M3_SYSTEM_INCLUDE_PATH . '/common/core.php');

class AccessManager extends Core
{
	private $db;						// DBオブジェクト
	private $_clientId;					// クライアントID(クッキー用)
	private $_oldSessionId;				// 古いセッションID
	private $_accessLogSerialNo;		// アクセスログのシリアルNo
   	const LOG_REQUEST_PARAM_MAX_LENGTH	= 1024;				// ログに保存するリクエストパラメータの最大長

	/**
	 * コンストラクタ
	 */
	function __construct()
	{
		// 親クラスを呼び出す
		parent::__construct();
		
		// システムDBオブジェクト取得
		$this->db = $this->gInstance->getSytemDbObject();
	}
	/**
	 * アクセスログ初期化処理(直接呼出し用)
	 *
	 * @return なし
	 */
	function initAccessLog()
	{
		if (empty($this->_accessLogSerialNo)) $this->accessLog();
	}
	/**
	 * ログイン処理
	 *
	 * ログイン処理を行う。可能な場合はユーザ情報を読み込む
	 *
	 * @param RequestManager $request		HTTPリクエスト処理クラス
	 * @return bool   						true=アクセス可能、false=アクセス不可
	 */
	function userLogin($request)
	{
		// アカウント、パスワード取得
		$account = $request->trimValueOf('account');
		$password = $request->trimValueOf('password');
		return $this->userLoginByAccount($account, $password);
	}
	/**
	 * ログイン処理
	 *
	 * ログイン処理を行う。可能な場合はユーザ情報を読み込む
	 *
	 * @param string $account		アカウント
	 * @param string $password		パスワード
	 * @param bool $checkUser		ユーザのアクセス権をチェックするかどうか
	 * @return bool   				true=アクセス可能、false=アクセス不可
	 */
	function userLoginByAccount($account, $password, $checkUser=true)
	{
		global $gInstanceManager;
		global $gRequestManager;
		
		// 戻り値初期化
		$retValue = false;
		
		// アカウントが空のときはアクセス不可
		if (empty($account)) return false;
		
		$accessIp = $gRequestManager->trimServerValueOf('REMOTE_ADDR');		// アクセスIP
		
		// ユーザ情報取得
		if ($this->db->getLoginUserRecord($account, $row)){
			// ******** ユーザのログインチェック             ********
			// ******** ログインのチェックを行うのはここだけ ********
			$pass  = $row['lu_password'];
			if ($pass == $password){			// パスワード一致のとき
				// ユーザチェックが必要な場合は承認済みユーザのみ許可する
				if (($checkUser && $row['lu_user_type'] >= 0 && $row['lu_enable_login']) || // 承認済みユーザ、ログイン可能
					!$checkUser){			// ユーザのアクセス権をチェックしない場合
					
					// ログインした場合はセッションIDを変更する
					$this->setOldSessionId(session_id());		// 古いセッションIDを保存
					session_regenerate_id(true);
			
					// ユーザ情報オブジェクトを作成
					$userInfo = new UserInfo();
					$userInfo->userId	= $row['lu_id'];		// ユーザID
					$userInfo->account	= $row['lu_account'];	// ユーザアカウント
					$userInfo->name		= $row['lu_name'];		// ユーザ名
					$userInfo->userType	= $row['lu_user_type'];	// ユーザタイプ
					$userInfo->_recordSerial = $row['lu_serial'];	// レコードシリアル番号
				
					// 管理者の場合は、管理者キーを発行
					if ($userInfo->isSystemAdmin()){
					//if ($userInfo->userType >= UserInfo::USER_TYPE_MANAGER){	// システム運用可能ユーザのとき
						$adminKey = $this->createAdminKey();
						if ($this->db->addAdminKey($adminKey, $accessIp)) $userInfo->_adminKey = $adminKey;
					} else {
						$userInfo->_adminKey = '';
					}
				
					// インスタンスマネージャーとセッションに保存
					$gInstanceManager->setUserInfo($userInfo);
					$gRequestManager->setSessionValueWithSerialize(M3_SESSION_USER_INFO, $userInfo);
				
					// ログインのログを残す
					$this->db->updateLoginLog($userInfo->userId, $this->_accessLogSerialNo);
					$retValue = true;
				}
			}
		}
		// ログインのログを残す
		if ($retValue){
			// ユーザログインログを残す
			$this->gOpeLog->writeUserInfo(__METHOD__, 'ユーザがログインしました。アカウント: ' . $account, 2100, 'account=' . $account . ', passward=' . $password . ', userid=' . $this->gEnv->getCurrentUserId());
		} else {
			// ユーザエラーログを残す
			$this->gOpeLog->writeUserErr(__METHOD__, 'ユーザがログインに失敗しました。アカウント: ' . $account, 2100, 'account=' . $account . ', passward=' . $password);
			
			// 入力アカウントを保存
			$this->db->addErrorLoginLog($account, $accessIp, $this->_accessLogSerialNo);
		}
		return $retValue;
	}
	/**
	 * ユーザログアウト処理
	 *
	 * @param bool $delSession		セッションを削除するかどうか
	 */
	function userLogout($delSession = false)
	{
		// ユーザ情報取得
		$userInfo = $this->gEnv->getCurrentUserInfo();
		
		// ログアウトログを残す
		if (!is_null($userInfo)){
			$this->gOpeLog->writeUserInfo(__METHOD__, 'ユーザがログアウトしました。アカウント: ' . $userInfo->account, 2100, 'account=' . $userInfo->account . ', userid=' . $userInfo->userId);
		}
		
		// ログアウトしたとき、管理者のセッション値は削除。一般ユーザの場合はログアウトしても残しておくセッション値があるので(テンプレート等)ユーザ情報のみ削除。
		// セッション終了
		if ($delSession){
//			session_start();
			session_destroy();
		}
			
		// ユーザ情報を削除
		$this->gInstance->setUserInfo(null);
	}
	/**
	 * アクセスログの記録
	 *
	 * アクセスログを記録する
	 *
	 * @return なし
	 */
	function accessLog()
	{
		global $gRequestManager;
		global $gEnvManager;
		
		// ユーザ情報が存在しているときは、ユーザIDを登録する
		$userId = 0;
		$userInfo = $gEnvManager->getCurrentUserInfo();
		if (!is_null($userInfo)){		// ユーザ情報がある場合
			$userId = $userInfo->userId;
		}
		$cookieVal	= isset($this->_clientId) ? $this->_clientId : '';			// アクセス管理用クッキー
		$ip			= $gRequestManager->trimServerValueOf('REMOTE_ADDR');		// クライアントIP
		$method		= $gRequestManager->trimServerValueOf('REQUEST_METHOD');	// アクセスメソッド
		$uri		= $gRequestManager->trimServerValueOf('REQUEST_URI');
		$referer	= $gRequestManager->trimServerValueOf('HTTP_REFERER');
		$agent		= $gRequestManager->trimServerValueOf('HTTP_USER_AGENT');		// クライアントアプリケーション
		$language	= $gRequestManager->trimServerValueOf('HTTP_ACCEPT_LANGUAGE');	// クライアント認識可能言語
		
		$request = '';
		foreach ($_REQUEST as $strKey => $strValue ) {
			$request .= sprintf("%s=%s" . M3_TB, $strKey, $strValue);		// タブ区切り
		}
		$request = rtrim($request, M3_TB);		// 最後のタブを消去
		$request = substr($request, 0, self::LOG_REQUEST_PARAM_MAX_LENGTH);	// 格納長を制限
		
		// アクセスパスを取得
		$path = $gEnvManager->getAccessPath();
		
		// アクセスログのシリアルNoを保存
		$this->_accessLogSerialNo = $this->db->accessLog($userId, $cookieVal, $ip, $method, $uri, $referer, $request, $agent, $language, $path);
	}
	
	/**
	 * アクセスログユーザの記録
	 *
	 * アクセスログユーザを記録する
	 *
	 * @return なし
	 */
	function accessLogUser()
	{
		global $gEnvManager;
				
		$userId = 0;
		$userInfo = $gEnvManager->getCurrentUserInfo();
		if (!is_null($userInfo)){		// ユーザ情報がある場合
			$userId = $userInfo->userId;
		}
		// ユーザ情報が存在しているときは、ユーザIDを登録する
		if ($userId != 0) $this->db->updateAccessLogUser($this->_accessLogSerialNo, $userId);
	}
	/**
	 * クッキーに保存するクライアントIDを生成
	 */
	function createClientId()
	{
		global $gRequestManager;
			
		// アクセスログの最大シリアルNoを取得
		$max = $this->db->getMaxSerialOfAccessLog();
		$this->_clientId = md5(time() . $gRequestManager->trimServerValueOf('REMOTE_ADDR') . ($max + 1));
		return $this->_clientId;				// クライアントID(クッキー用)
	}
	/**
	 * クッキーから取得したクライアントIDを設定
	 *
	 * @param string $clientId		クライアントID
	 */
	function setClientId($clientId)
	{
		$this->_clientId = $clientId;				// クライアントID(クッキー用)
	}
	/**
	 * クッキーから取得したクライアントIDを取得
	 *
	 * @return string		クライアントID
	 */
	function getClientId()
	{
		return $this->_clientId;				// クライアントID(クッキー用)
	}
	/**
	 * 管理者用一時キーを作成
	 */
	function createAdminKey()
	{
		global $gRequestManager;
			
		return md5($gRequestManager->trimServerValueOf('REMOTE_ADDR') . time());
	}
	/**
	 * 変更前のセッションIDを設定
	 *
	 * @param string $sessionId		セッションID
	 */
	function setOldSessionId($sessionId)
	{
		$this->_oldSessionId = $sessionId;
	}
	
	/**
	 * アクセスログのシリアルNoを取得
	 *
	 * @return int		シリアルNo
	 */
	function getAccessLogSerialNo()
	{
		return $this->_accessLogSerialNo;
	}
	/**
	 * システム管理者の認証が完了しているかどうか判断(フレームワーク以外のアクセス制御用)
	 *
	 * @return bool		true=完了、false=未完了
	 */
	function loginedByAdmin()
	{
		global $gRequestManager;
		global $gSystemManager;
		
		// セッション変数を取得可能にする
		session_cache_limiter('none');		// IE対策(暫定対応20070703)
		session_start();
		
		// セッションを再生成する(セキュリティ対策)
		if ($gSystemManager->regenerateSessionId()){
			$this->setOldSessionId(session_id());		// 古いセッションIDを保存
			session_regenerate_id(true);
		}

		// セッションからユーザ情報を取得
		// セッションが残っていない場合がある(IEのみ)→アクセスできない(原因不明)
		$userInfo = $gRequestManager->getSessionValueWithSerialize(M3_SESSION_USER_INFO);
		if (is_null($userInfo)) return false;		// ログインしていない場合

		if ($userInfo->isSystemAdmin()){	// システム管理者の場合
			return true;
		} else {
			return false;
		}
	}
	/**
	 * ユーザの認証が完了しているかどうか判断(フレームワーク以外のアクセス制御用)
	 *
	 * @return bool		true=完了、false=未完了
	 */
	function loginedByUser()
	{
		global $gRequestManager;
		global $gSystemManager;
		global $gInstanceManager;
		
		// セッション変数を取得可能にする
		session_cache_limiter('none');		// IE対策(暫定対応20070703)
		session_start();
		
		// セッションを再生成する(セキュリティ対策)
		if ($gSystemManager->regenerateSessionId()){
			$this->setOldSessionId(session_id());		// 古いセッションIDを保存
			session_regenerate_id(true);
		}

		// セッションからユーザ情報を取得
		// セッションが残っていない場合がある(IEのみ)→アクセスできない(原因不明)
		$userInfo = $gRequestManager->getSessionValueWithSerialize(M3_SESSION_USER_INFO);
		if (is_null($userInfo)) return false;		// ログインしていない場合
		
		// ユーザ情報を保存
		$gInstanceManager->setUserInfo($userInfo);
		
		return true;
		/*if ($userInfo->userType >= UserInfo::USER_TYPE_MANAGER){	// システム運用可能ユーザのとき
			return true;
		} else {
			return false;
		}*/
	}
	/**
	 * 管理者認証用一時キーが存在するかどうか
	 *
	 * @param RequestManager $request		HTTPリクエスト処理クラス
	 * @return bool			true=完了、false=未完了
	 */
	function isValidAdminKey($request)
	{
		// 管理者一時キーを取得
		$adminKey = $request->trimValueOf(M3_REQUEST_PARAM_ADMIN_KEY);
		if (empty($adminKey)) return false;

		$ret = $this->db->isValidAdminKey($adminKey, $request->trimServerValueOf('REMOTE_ADDR'));
		return $ret;
	}
	/**
	 * URL用のパラメータとして使用するセッションIDを取得
	 *
	 * @return string			セッションIDパラメータ文字列
	 */	
	function getSessionIdUrlParam()
	{
		return session_name() . '=' . session_id();
	}
}
?>
