<?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-2008 Magic3 Project.
 * @license    http://www.gnu.org/copyleft/gpl.html  GPL License
 * @version    SVN: $Id: baseFrameContainer.php 1018 2008-09-17 10:19:22Z fishbone $
 * @link       http://www.magic3.org
 */
require_once(M3_SYSTEM_INCLUDE_PATH . '/db/systemDb.php');		// システムDBアクセスクラス

class BaseFrameContainer
{
	var $_db;	// DB接続オブジェクト
	const ADMIN_TEMPLATE = '_admin';
	const ERR_MESSAGE_ACCESS_DENY = 'Access denied.';		// ウィジェットアクセスエラーのメッセージ
	const SITE_IN_PUBLIC = 'site_in_public';			// サイト公開状況
	const SITE_ACCESS_EXCEPTION_IP = 'site_access_exception_ip';		// アクセス制御、例外とするIP
	
	/**
	 * コンストラクタ
	 */
	function __construct()
	{
		global $gInstanceManager;
		
		// DBオブジェクト作成
		$this->_db = $gInstanceManager->getSytemDbObject();
	}
	/**
	 * 起動マネージャから呼ばれる唯一のメソッド
	 *
	 * @param RequestManager $request		HTTPリクエスト処理クラス
	 */
	function process($request)
	{
		global $gLogManager;
		global $gPageManager;
		global $gEnvManager;
		global $gAccessManager;
		global $gConfigManager;
		global $gSystemManager;
		global $gFileManager;

		// 実行コマンドを取得
		$cmd = $request->trimValueOf(M3_REQUEST_PARAM_OPERATION_COMMAND);
				
		// インストール画面への制御は、install.phpファイルの作成、削除で制御する
		// 最小限の設定が行われていない場合,DBに接続できない場合は、インストール画面へ
		if (!defined('M3_STATE_IN_INSTALL')){
			if (($gEnvManager->canUseDb() && $gSystemManager->canInitSystem()) ||		// システム初期化モードのとき
				!$gConfigManager->isConfigured() || 									// 設定ファイルに設定がないとき
				!$gEnvManager->canUseDb()){											// DBがまだ作成されていないとき
				
				// インストーラファイルがない場合は回復
				$gFileManager->recoverInstaller();

				$gPageManager->redirectToInstall();
				return;
			}
		}

		// 開始ログ出力
		//$gLogManager->info(__METHOD__, 'フレーム作成開始');

		// ページ作成開始
		// セッション変数読み込み
		$gPageManager->start($request);
		
		if (!defined('M3_STATE_IN_INSTALL')){		// インストールモード以外のとき
			// ############## ユーザごとの設定の読み込み ###################
			// クッキー読み込み、カレント言語設定等
			$clientId = $request->getCookieValue(M3_COOKIE_CLIENT_ID);
			if ($clientId == ''){	// クライアントIDが設定されていないとき
				// クライアントIDを生成
				$clientId = $gAccessManager->createClientId();
			} else {
				$gAccessManager->setClientId($clientId);	// クライアントIDを設定
			}
			$request->setCookieValue(M3_COOKIE_CLIENT_ID, $clientId);
			
			// 引数での言語設定取得、言語変更可能な場合は変更
			$lang = $request->trimValueOf(M3_REQUEST_PARAM_OPERATION_LANG);
			if (!empty($lang) && $gEnvManager->getCanChangeLang()){
				$gEnvManager->setCurrentLanguage($lang);
			}
			// ################### URLアクセス制御 ######################
			// 非公開URLへは管理権限がないとアクセスできない
			$canAccess = true;
			$toAdmin = false;		// 管理画面へ遷移するかどうか
			$isPublicUrl = $gPageManager->canAccessUrl();
			if (!$isPublicUrl && !$gEnvManager->isSystemAdmin()) $canAccess = false;

			// ################### ユーザアクセス制御 ######################
			if ($canAccess){
				if (method_exists($this, '_checkAccess')){
					$canAccess = $this->_checkAccess($request);		// サブクラスメソッドの呼び出し
				} else {			// _checkAccess()がないときは、標準のアクセス制御
					$canAccess = $this->_accessSite($request);		// サイト公開制御
					if ($canAccess){
						if ($cmd != '' &&										// コマンドなし
							$cmd != M3_REQUEST_CMD_CHANGE_TEMPLATE &&			// テンプレート変更
							$cmd != M3_REQUEST_CMD_SHOW_POSITION &&				// 表示位置を表示するとき
							$cmd != M3_REQUEST_CMD_SHOW_POSITION_WITH_WIDGET &&	// 表示位置を表示するとき(ウィジェット付き)
							$cmd != M3_REQUEST_CMD_FIND_WIDGET &&				// ウィジェットを検索
							$cmd != M3_REQUEST_CMD_DO_WIDGET){					// ウィジェット単体実行
							// 標準のアクセスでは、上記コマンド以外は受け付けない
							$canAccess = false;
						}
					} else {		// サイトアクセスできない場合は、管理画面でメッセージを表示
						$toAdmin = true;
					}
				}
			}
			// #################### アクセスログ記録 #######################
			// DBが使用可能であれば、ログイン処理終了後、アクセスログを残す
			if ($gEnvManager->canUseDb()) $gAccessManager->accessLog();
		
			// アクセス不可のときはここで終了
			if (!$canAccess){
				if ($toAdmin){
					// システム制御モードに変更
					$gPageManager->setSystemHandleMode(1/*サイト非公開中*/);
					
					// システム制御画面を表示
					$this->_showSystemPage($request);
				}
				return;
			}
		}
		// ################## 実行コマンドを取得 ##################
		// 画面作成モードか、ウィジェット単体処理モードかを決定
		$createPage = true;		// 画面作成モード
		if ($cmd == M3_REQUEST_CMD_INIT_DB){	// DB初期化オペレーションのとき
		} else if ($cmd == M3_REQUEST_CMD_SHOW_POSITION){		// 表示位置を表示するとき
			// 管理者権限がある場合のみ実行可能
			if ($gEnvManager->isSystemAdmin()){
				// ポジションの表示画面のアクセスは、すべて管理機能URLで受け付ける
				// ページIDを再設定
				$pageId = $request->trimValueOf(M3_REQUEST_PARAM_PAGE_ID);
				if (empty($pageId)) $pageId = $gEnvManager->getDefaultPageId();		// 値がないときはデフォルトのページIDを設定
				$gEnvManager->setCurrentPageId($pageId);
				
				$gPageManager->showPosition(1);			// ポジションを表示
			} else {
				return;
			}
		} else if ($cmd == M3_REQUEST_CMD_SHOW_POSITION_WITH_WIDGET){		// 表示位置を表示するとき(ウィジェット付き)
			// 管理者権限がある場合のみ実行可能
			if ($gEnvManager->isSystemAdmin()){
				// ポジションの表示画面のアクセスは、すべて管理機能URLで受け付ける
				// ページIDを再設定
				$pageId = $request->trimValueOf(M3_REQUEST_PARAM_PAGE_ID);
				if (empty($pageId)) $pageId = $gEnvManager->getDefaultPageId();		// 値がないときはデフォルトのページIDを設定
				$gEnvManager->setCurrentPageId($pageId);
				
				$gPageManager->showPosition(2);			// ウィジェット付きポジションを表示
			} else {
				return;
			}
		} else if ($cmd == M3_REQUEST_CMD_GET_WIDGET_INFO){		// ウィジェット各種情報取得(AJAX用)
			// ウィジェット情報取得
			$gPageManager->getWidgetInfoByAjax($request);
			return;
		} else if ($cmd == M3_REQUEST_CMD_SHOW_PHPINFO){	// phpinfoの表示
			// phpinfo画面を表示
			$this->_showPhpinfoPage($request);
			return;
		} else if ($cmd == M3_REQUEST_CMD_FIND_WIDGET){		// ウィジェットを検索し、前面表示
			// 目的のウィジェットのあるページサブIDへ遷移
			$gPageManager->redirectToUpdatedPageSubId($request);
			return;
		} else if ($cmd == M3_REQUEST_CMD_SHOW_WIDGET){		// ウィジェットの単体表示
			$createPage = false;		// ウィジェット単体処理モードに設定
			$gPageManager->showWidget();	// ウィジェット表示
		} else if ($cmd == M3_REQUEST_CMD_CONFIG_WIDGET){		// ウィジェットの設定管理
			$createPage = false;		// ウィジェット単体処理モードに設定
			$gPageManager->showWidget();	// ウィジェット表示
		} else if ($cmd == M3_REQUEST_CMD_DO_WIDGET){		// ウィジェット単体オペレーション
			$createPage = false;		// ウィジェット単体処理モードに設定
		}

		// ################### クライアントへの出力方法の制御 ######################
		// ウィジェットIDの取得
		$widgetId = $request->trimValueOf(M3_REQUEST_PARAM_WIDGET_ID);
		if ($createPage){				// 通常の画面作成の場合
			// カレントのテンプレートを決定
			$curTemplate = $this->_defineTemplate($request);

			// カレントのテンプレートIDを設定
			$gEnvManager->setCurrentTemplateId($curTemplate);

			// バッファリングの準備
			if (method_exists($this, '_prepareBuffer')) $this->_prepareBuffer($request);
			
			// ################### バッファリング開始 ######################
			// ob_end_flush()までの出力をバッファリングする
			if ($gEnvManager->getIsMobile()){// 携帯用サイトの場合は出力エンコーディングを変更
				$mobileEncoding = $gEnvManager->getMobileEncoding();		// 携帯用エンコーディングを取得
				//mb_internal_encoding("UTF-8");
				mb_http_output($mobileEncoding);
				ob_start("mb_output_handler"); // 出力のバッファリング開始
			} else {
				ob_start();
			}

			// サブクラスの前処理を実行
			$this->_preBuffer($request);
		
			// Joomlaテンプレート用定義
			global $mosConfig_absolute_path;
			global $mosConfig_live_site;
			global $mosConfig_sitename;
			global $mosConfig_favicon;
			global $mosConfig_sef;
			global $cur_template;
			global $mainframe;
			$GLOBALS['cur_template'] = $curTemplate;
			require_once($gEnvManager->getJoomlaRootPath() . '/mosFunc.php');
			require_once($gEnvManager->getJoomlaRootPath() . '/includes/sef.php');
		
			// ################### テンプレート読み込み ###################
			// テンプレートのポジションタグからウィジェットが実行される
			$templateIndexFile = $gEnvManager->getTemplatesPath() . '/' . $curTemplate . '/index.php';
			if (file_exists($templateIndexFile)){
				require_once($templateIndexFile);
				//echo '<!-- ' . time() . ' -->' . M3_NL;
			} else {
				echo 'template not found error: ' . $curTemplate;
			}

			// サブクラスの後処理の呼び出し
			$this->_postBuffer($request);
		
			// 現在の出力内容を取得し、一旦内容をクリア
			$srcContents = ob_get_contents();
			ob_clean();
			
			// 遅延実行ウィジェットの出力を埋め込む
			$destContents = $gPageManager->lateLaunchWidget($request, $srcContents);
			
			// 携帯インターフェイスのときのときは、手動変換後、バイナリコード(絵文字等)を埋め込む
			if ($gEnvManager->getIsMobile()){
				// コンテンツ変換メソッドがある場合は実行
				if (method_exists($this, '_convContents')){		
					$destContents = mb_convert_encoding($destContents, $mobileEncoding, M3_ENCODING);		// 出力するコードに変換
				}
				
				// 絵文字埋め込み処理
				$destContents = $this->_convContents($destContents);
				
				// ページ作成終了処理(HTTPヘッダ出力)
				$destContents .= $gPageManager->end($request, true/*出力を取得*/);		// 最終HTMLを追加
				
				// バッファを破棄
				ob_end_flush();
				
				// クライアントにデータを送信
				echo $destContents;
			} else {
				echo $destContents;
			
				// ページ作成終了処理(HTTPヘッダ出力)
				$gPageManager->end($request);
		
				// mb_http_outputで設定したエンコーディングに変換して、バッファ内容を送信(クライアントへの送信完了)
				ob_end_flush();
			}
		} else {		// ウィジェット単体実行モードのとき
			// ###################ウィジェット指定で出力の場合####################
			// ウィジェット単体を直接実行するインターフェイスで、HTTPヘッダは送信しない。
			// 以下のパターンで使用する。
			// ・Ajaxを使って、データをやり取りしたい場合
			// ・ウィジェット単体での実行(ウィジェットが生成したタグのみ)
			// ・ウィジェット単体での実行(HTMLやJavascriptの追加あり)
			// ・ウィジェット個別の設定(セキュリティの必要あり)

			// ################# アクセスチェック ################
			// ウィジェット単体オペレーションのときはウィジェット単体実行許可があるかどうか判断(管理権限にかかわらず同じ動作)
			if ($cmd == M3_REQUEST_CMD_DO_WIDGET){
				if ($this->_db->getWidgetInfo($widgetId, $row)){
					if (!$row['wd_enable_operation']){
						// アクセスエラーのログを残す
						$this->_db->writeWidgetLog($widgetId, 1/*単体実行*/, $cmd, self::ERR_MESSAGE_ACCESS_DENY);
						return;
					}
				}
			}
			// 管理権限がない場合は、ウィジェットのアクセス権限をチェックする
			if (!$gEnvManager->isSystemAdmin() && !$gAccessManager->isValidAdminKey($request) && !$this->_db->canAccessWidget($widgetId)){
				// アクセスエラーのログを残す
				$this->_db->writeWidgetLog($widgetId, 1/*単体実行*/, $cmd, self::ERR_MESSAGE_ACCESS_DENY);
				return;
			}

			// ウィジェットの単体表示の場合だけ、カレントのテンプレートを設定する(テンプレートチェンジャー用)
			if ($cmd == M3_REQUEST_CMD_SHOW_WIDGET){		// ウィジェット単体表示のとき
				// カレントのテンプレートを決定
				$curTemplate = $this->_defineTemplate($request, false);

				// カレントのテンプレートIDを設定
				$gEnvManager->setCurrentTemplateId($curTemplate);
			}
			
			// ################### バッファリング開始 ######################
			// ob_end_flush()までの出力をバッファリングする
			ob_start();
			
			// サブクラスの前処理を実行
			$this->_preBuffer($request);
		
			// 作業中のウィジェットIDを設定
			$gEnvManager->setCurrentWidgetId($widgetId);
			
			// ウィジェット用のHTMLヘッダを出力
			$gPageManager->startWidget($cmd);

			// 指定のウィジェットを実行
			if ($cmd == M3_REQUEST_CMD_CONFIG_WIDGET){		// ウィジェット設定のとき
				$widgetIndexFile = $gEnvManager->getWidgetsPath() . '/' . $widgetId . '/admin/index.php';		// 管理用画面
			} else {
				$widgetIndexFile = $gEnvManager->getWidgetsPath() . '/' . $widgetId . '/index.php';
			}
			if (file_exists($widgetIndexFile)){
				// 実行のログを残す
				$this->_db->writeWidgetLog($widgetId, 1/*単体実行*/, $cmd);

				require_once($widgetIndexFile);
			} else {
				echo 'file not found: ' . $widgetIndexFile;
			}
			
			// ウィジェット用のタグを閉じる
			$gPageManager->endWidget($cmd);
		
			// 作業中のウィジェットIDを解除
			$gEnvManager->setCurrentWidgetId('');
			
			// サブクラスの後処理の呼び出し
			$this->_postBuffer($request);
			
			if ($cmd == M3_REQUEST_CMD_SHOW_WIDGET ||		// ウィジェットの単体表示
				$cmd == M3_REQUEST_CMD_CONFIG_WIDGET){ 		// ウィジェット設定のとき
				// 現在の出力内容を取得し、一旦内容をクリア
				$srcContents = ob_get_contents();
				ob_clean();
				
				// 追加変換処理
				$destContents = $gPageManager->lateLaunchWidget($request, $srcContents);
				
				echo $destContents;
			}
			
			// ページ作成終了処理(HTTPヘッダ出力)
			$gPageManager->end($request);
			
			// バッファ内容を送信(クライアントへの送信完了)
			ob_end_flush();
		}
		if (!defined('M3_STATE_IN_INSTALL')){		// インストールモード以外のとき
			// #################### アクセスログ記録 #######################
			// DBが使用可能であれば、アクセスログのユーザを登録
			if ($gEnvManager->canUseDb()) $gAccessManager->accessLogUser();
		}
			
		// 終了ログ出力
		//$gLogManager->info(__METHOD__, 'フレーム作成終了');
	}
	/**
	 * テンプレートを決定
	 *
	 * @param RequestManager $request		HTTPリクエスト処理クラス
	 * @param bool $useSubClassDefine		サブクラスでの定義を使用するかどうか
	 * @return string		テンプレート名
	 */
	function _defineTemplate($request, $useSubClassDefine = true)
	{
		global $gEnvManager;
		
		// ########### テンプレートID(ディレクトリ名)を設定 ############
		// テンプレートIDの指定の方法は2パターン
		// 　1.サブクラスで固定に指定
		// 　2.セッションに保持
		// テンプレートIDの優先順位
		// 　1.サブクラスの_setTemplate()で固定設定にしている場合の固定値
		// 　2.セッションに持っている値
		// 　3.DBのデフォルト値
		$curTemplate = '';
		
		// テンプレート変更のときは、セッションのテンプレートIDを変更
		$cmd = $request->trimValueOf(M3_REQUEST_PARAM_OPERATION_COMMAND);		// 実行コマンドを取得
		if ($cmd == M3_REQUEST_CMD_CHANGE_TEMPLATE){
			$request->setSessionValue(M3_SESSION_CURRENT_TEMPLATE, $request->trimValueOf(M3_SYSTEM_TAG_CHANGE_TEMPLATE));
		}

		// サブクラスでテンプレートIDを指定している場合はそちらを使用
		$isSubclassDefined = false;		// サブクラスでの固定かどうか
		if ($useSubClassDefine){
			$tmplStr = trim($this->_setTemplate($request));
			if (strlen($tmplStr) > 0){
				$curTemplate = $tmplStr;
				$isSubclassDefined = true;		// サブクラスでの固定かどうか
			}
		}
		
		// セッションにあるときは、セッションの値を使用(携帯でないとき)
		$pageId = $request->trimValueOf(M3_REQUEST_PARAM_PAGE_ID);
		if ($curTemplate == ''){
			if ($cmd == M3_REQUEST_CMD_SHOW_POSITION ||				// 表示位置を表示するとき
				$cmd == M3_REQUEST_CMD_SHOW_POSITION_WITH_WIDGET){	// 表示位置を表示するとき(ウィジェット付き)
				
				// URLの引数として、ページIDとページサブIDが指定されてくる
				if ($pageId == $gEnvManager->getDefaultPageId()){		// 通常サイトのとき
					$curTemplate = $this->_db->getDefaultTemplateId();
				} else if ($pageId == $gEnvManager->getDefaultMobilePageId()){		// 携帯サイトのとき
					$curTemplate = $this->_db->getDefaultMobileTemplateId();		// 携帯用デフォルトテンプレート
				} else if ($pageId == $gEnvManager->getDefaultAdminPageId()){		// 管理サイトのとき
					$curTemplate = '_admin';
				} else if (empty($pageId)){			// ページIDが指定されていないときは、ウィジェットを表示しないテンプレートのみの表示
					// テンプレートIDが指定されている場合はテンプレートを変更
					$template = $request->trimValueOf(M3_REQUEST_PARAM_TEMPLATE_ID);		// テンプレートIDを取得
					if (!empty($template)) $curTemplate = $template;
				}
			} else {
				if (!$gEnvManager->getIsMobile()) $curTemplate = $request->getSessionValue(M3_SESSION_CURRENT_TEMPLATE);// 携帯サイトでないときはセッション値を取得
			}
		}

		// セッションにないときは、DBより取得
		if ($curTemplate == ''){
			if ($gEnvManager->getIsMobile()){// 携帯用サイトの場合
				$curTemplate = $this->_db->getDefaultMobileTemplateId();		// 携帯用デフォルトテンプレート
			} else {
				$curTemplate = $this->_db->getDefaultTemplateId();
			}
		}
		if ($curTemplate == ''){
			// テンプレートが１つもみつからないときは、管理用テンプレートを使用
			$curTemplate = self::ADMIN_TEMPLATE;
			echo 'template not found. viewing by administration template. [' . $curTemplate . ']';
		} else {	// セッションにテンプレートIDを保存
			if ($cmd == M3_REQUEST_CMD_SHOW_POSITION ||				// 表示位置を表示するとき
				$cmd == M3_REQUEST_CMD_SHOW_POSITION_WITH_WIDGET){	// 表示位置を表示するとき(ウィジェット付き)
			} else {
				if (!$gEnvManager->getIsMobile() && !$isSubclassDefined){		// PC用画面でサブクラス固定でないとき場合は保存
					$request->setSessionValue(M3_SESSION_CURRENT_TEMPLATE, $curTemplate);
				}
			}
		}
		return $curTemplate;
	}
	/**
	 * サイト公開制御
	 *
	 * @param RequestManager $request		HTTPリクエスト処理クラス
	 * @return bool							サイトにアクセスできるかどうか
	 */
	function _accessSite($request)
	{
		// サイトの公開状況を取得
		$isOpen = $this->_db->getSystemConfig(self::SITE_IN_PUBLIC);
		if ($isOpen){
			return true;
		} else {
			// 例外とするIPアドレスをチェック
			$ip = $this->_db->getSystemConfig(self::SITE_ACCESS_EXCEPTION_IP);
			if (!empty($ip) && $ip = $request->trimServerValueOf('REMOTE_ADDR')){
				return true;
			} else {
				return false;
			}
		}
	}
	/**
	 * システム制御画面表示
	 *
	 * @param RequestManager $request		HTTPリクエスト処理クラス
	 * @return なし
	 */
	function _showSystemPage($request)
	{
		global $gEnvManager;
		global $gPageManager;
		
		// ページIDを設定
		$basename = 'admin_index';
		$gEnvManager->setCurrentPageId($basename);
		
		// 管理用テンプレート
		$curTemplate = self::ADMIN_TEMPLATE;

		// カレントのテンプレートIDを設定
		$gEnvManager->setCurrentTemplateId($curTemplate);

		// ################### バッファリング開始 ######################
		// ob_end_flush()までの出力をバッファリングする
		ob_start();

		// サブクラスの前処理を実行
		$this->_preBuffer($request);
			
		// Joomlaテンプレート用定義
		global $mosConfig_absolute_path;
		global $mosConfig_live_site;
		global $mosConfig_sitename;
		global $mosConfig_favicon;
		global $mosConfig_sef;
		global $cur_template;
		global $mainframe;
		$GLOBALS['cur_template'] = $curTemplate;
		require_once($gEnvManager->getJoomlaRootPath() . '/mosFunc.php');
		require_once($gEnvManager->getJoomlaRootPath() . '/includes/sef.php');
	
		// ################### テンプレート読み込み ###################
		// テンプレートのポジションタグからウィジェットが実行される
		$templateIndexFile = $gEnvManager->getTemplatesPath() . '/' . $curTemplate . '/index.php';
		if (file_exists($templateIndexFile)){
			require_once($templateIndexFile);
		} else {
			echo 'template not found error: ' . $curTemplate;
		}
		
		// サブクラスの後処理の呼び出し
		$this->_postBuffer($request);
	
		// 現在の出力内容を取得し、一旦内容をクリア
		$srcContents = ob_get_contents();
		ob_clean();
		
		// 遅延実行ウィジェットの出力を埋め込む
		$destContents = $gPageManager->lateLaunchWidget($request, $srcContents);
		echo $destContents;
		
		// ページ作成終了処理(HTTPヘッダ出力)
		$gPageManager->end($request);
	
		// バッファ内容を送信(クライアントへの送信完了)
		ob_end_flush();
	}
	/**
	 * phpinfo画面表示
	 *
	 * @param RequestManager $request		HTTPリクエスト処理クラス
	 * @return なし
	 */
	function _showPhpinfoPage($request)
	{
		global $gEnvManager;
		global $gPageManager;
		
		// ################### バッファリング開始 ######################
		// ob_end_flush()までの出力をバッファリングする
		ob_start();
		
		phpinfo();
		
		// バッファ内容を送信(クライアントへの送信完了)
		ob_end_flush();
	}
}
?>
