<?php
/*
 * system/AbstructData.class.php
 * 
 * CopyRight(C) 2010 Shopformer Development Team. All Right Reserved
 * URL: http://sourceforge.jp/projects/shopformer/
 * 
 * 
 * Mail: m_nakashima@users.sourceforge.jp
 * Auther: Masanori Nakashima
 * Last Update: 2010-07-23
 * 
 * [変更履歴]
 * 2010-7-23
 * 配列を改行でつないでインストールフォームに表示する機能追加
 * 改行の入った文字列のdefineに対応
 * 2010-4-16
 * login_ModuleBaseクラスにsetLoginUserObjectメソッドを追加しました。
 * 2010-03-31
 * system_package_PackageConfigBaseクラスのinstallメソッドのデフォルト動作を作成しました。
 * パッケージ/installフォルダ内にdata/pages/templates/widgets/publicフォルダが存在
 * した場合、それぞれのフォルダを対象フォルダにコピーします。
 * なかった場合は何もしません。
 * 併せてuninstall時にdataフォルダ内の関連ファイルを全て削除するデフォルト動作を追加しました。
 * 
 */
require_once(dirname(__FILE__)
.DIRECTORY_SEPARATOR.'define.inc.php');
require_once(dirname(__FILE__)
.DIRECTORY_SEPARATOR.'login'
.DIRECTORY_SEPARATOR.'ModuleBase.class.php');
require_once(dirname(__FILE__)
.DIRECTORY_SEPARATOR.'DataFileWriter.class.php');
require_once(dirname(__FILE__)
.DIRECTORY_SEPARATOR.'package'
.DIRECTORY_SEPARATOR.'PackageConfigBase.class.php' );
require_once(dirname(dirname( __FILE__ ))
.DIRECTORY_SEPARATOR.'util'
.DIRECTORY_SEPARATOR.'CharUtility.class.php' );
/**
 * システム設定パッケージ基本情報保持クラス
 * 
 * - 概要
 * 
 *   MDSマネージャのパッケージ管理パッケージ
 * 
 * - パッケージの詳細
 * 
 * 管理パネルの基本機能と他パッケージへの設定インターフェース提供、ユーザーへのログイン機能とインターフェースを提供します。
 * 他パッケージは本パッケージ内のクラスsystem_package_PackageConfigBaesクラスを同様に拡張してパッケージ情報クラスを実装することで、
 * formerシリーズウェイブアプリケーションの管理パネルでインストールや設定をおこなうことができるようになります。パッケージ情報クラスで実装すべき内容に関しては、
 * {@link system_package_PackageConfigBase system_package_PackageConfigBase}のドキュメントをご覧ください。システム設定情報保持する
 * 本クラスもsystem_package_PackageConfigBaseの拡張クラスとして実装されています。
 * @package system
 * @category DAO
 * @version 1.2.00
 * @copyright Copyright(c)2011, Shopformer Development Team. <shopformer-dev@lists.sourceforge.jp>
 * @author Masanori Nakashima
 * @access public
 * @see system_package_PackageConfigBase
 * {@inheritdoc}
 */
class system_PackageConfig extends system_package_PackageConfigBase {
	/**
	 * コンストラクタ
	 * @access public
	 */
	function system_PackageConfig() {
		$this->definitionHash	=array(
		'SYSTEM_NAME'							=> '',
		'SYSTEM_LOG_LEVEL'						=> '2',
		'SYSTEM_MOUNT_ROOT_SPIDER'				=> '',
		'SYSTEM_MOUNT_ROOT_PUBLIC'				=> '',
		'SYSTEM_CRYPT_METHOD'					=> 'sha1',
		'SYSTEM_CRYPT_KEY'						=> 'mdstools',
		'SYSTEM_ADMIN_LOGIN_ID'					=> 'admin',
		'SYSTEM_ADMIN_LOGIN_PASSWORD'			=> 'admin',
		'SYSTEM_ADMIN_LOGIN_MODULE'				=> '',
		'SYSTEM_MAIL_FROM_NAME'					=> 'Administrator',
		'SYSTEM_MAIL_FROM_ADDRESS'				=> '',
		'SYSTEM_MAIL_REPLY_ADDRESS'				=> '',
		'SYSTEM_MAIL_RETURN_ADDRESS'			=> '',
		'SYSTEM_MAIL_REPORT_TO_ADDRESSES'		=> array(),
		'SYSTEM_MAIL_SUBJECT_PREFIX'			=> '',
		'SYSTEM_MAIL_SEND_METHOD'				=> 'sendmail',
		'SYSTEM_UPDATE_SVN_URL'					=> 'http://svn.mds-tools.com/pub/',
		'SYSTEM_UPDATE_SVN_ID'					=> 'guest',
		'SYSTEM_UPDATE_SVN_PW'					=> 'guest',
		'SYSTEM_MAIL_SEND_METHOD_OPTIONS'		=> array('smtp_port'=>25,'sendmail_path'=>'/usr/sbin/sendmail'),
		);
	}
	/**
	 * パッケージの表示順序を取得
	 * @return int パッケージ順序
	 * @access public
	 */
	function getPackageOrder() {
		return -1;
	}
	/**
	 * パッケージの表示名を取得
	 * @return string パッケージ名称
	 * @access public
	 */
	function getPackageViewName() {
		return 'システム設定';
	}
	/**
	 * パッケージ概要説明を取得します。
	 * @return string パッケージの概要説明文字列
	 * @access public
	 */
	function getPackageDescription() {
		return 'システムの基本設定やインストール済みパッケージの管理、パスワードリマインダーメール文言の編集をおこないます。';
	}
	/**
	 * definitionHashに設定された値の妥当性検査を行います。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return boolean エラーがあるならfalse
	 * @access public
	 */
	function validateDifinitionHash( & $request ) {
		// ログインIDのチェック
		if( strlen(trim($this->definitionHash['SYSTEM_ADMIN_LOGIN_ID'])) == 0 ) {
			$request->addLocaledError('system.error.config.nologinid',SPIDER_LOG_LEVEL_ERROR,array());
		} else if ( strlen(trim($this->definitionHash['SYSTEM_ADMIN_LOGIN_ID'])) < 4 || strlen(trim($this->definitionHash['SYSTEM_ADMIN_LOGIN_ID'])) >16 ) {
			$request->addLocaledError('system.error.config.invalidloginid',SPIDER_LOG_LEVEL_ERROR,array());
		} else if( defined('SYSTEM_LOGIN_PROCESS_MODULE') && strlen(SYSTEM_LOGIN_PROCESS_MODULE) > 0  ) {
			// 外部ログインモジュール定義が有効なら外部モジュールでログインIDの重複チェック
			$login_class_name	= str_replace('.','_',SYSTEM_LOGIN_PROCESS_MODULE);
			$login_class_file	= DIR_PATH_LIB.DIRECTORY_SEPARATOR.str_replace('_',DIRECTORY_SEPARATOR,$login_class_name).'.class.php';
			if( file_exists($login_class_file) ) {
				require_once( $login_class_file );
				$login_class_obj			= new $login_class_name;
				if( !$login_class_obj->is_available_login_id( $request, $this->definitionHash['SYSTEM_ADMIN_LOGIN_ID'] ) ) {
					$request->addLocaledError('system.error.config.duplicatedloginid',SPIDER_LOG_LEVEL_ERROR,array());
				}
			} else {
				$request->addLocaledError('system.error.config.nologinclass',SPIDER_LOG_LEVEL_ERROR,array());
			}
		}
		// ログインパスワードのチェック
		if( strlen(trim($this->definitionHash['SYSTEM_ADMIN_LOGIN_PASSWORD'])) == 0 ) {
			if( !defined('SYSTEM_ADMIN_LOGIN_PASSWORD') || strlen(SYSTEM_ADMIN_LOGIN_PASSWORD) == 0 ) {
				$request->addLocaledError('system.error.config.nopassword',SPIDER_LOG_LEVEL_ERROR,array());
			} else if( 'admin' == $this->definitionHash['SYSTEM_ADMIN_LOGIN_PASSWORD'] ) {
				$request->addLocaledError('system.error.config.nopasswordadmin',SPIDER_LOG_LEVEL_ERROR,array());
			}
		} else if ( strlen(trim($this->definitionHash['SYSTEM_ADMIN_LOGIN_PASSWORD'])) < 4
		|| strlen(trim($this->definitionHash['SYSTEM_ADMIN_LOGIN_PASSWORD'])) >16 ) {
				$request->addLocaledError('system.error.config.invalidpassword',SPIDER_LOG_LEVEL_ERROR,array());
		}
		
		// システム管理者名のチェック
		if( strlen(trim($this->definitionHash['SYSTEM_MAIL_FROM_NAME'])) == 0 ) {
			$request->addLocaledError('system.error.config.noviewname',SPIDER_LOG_LEVEL_ERROR,array());
		} else if ( strlen(trim($this->definitionHash['SYSTEM_MAIL_FROM_NAME'])) < 1 || strlen(trim($this->definitionHash['SYSTEM_MAIL_FROM_NAME'])) >120 ) {
			$request->addLocaledError('system.error.config.invalidviewname',SPIDER_LOG_LEVEL_ERROR,array());
		}
		
		if( strlen(trim($this->definitionHash['SYSTEM_MAIL_FROM_ADDRESS'])) == 0 ) {
			$request->addLocaledError('system.error.config.nomailaddress',SPIDER_LOG_LEVEL_ERROR,array());
		} else if( preg_match('/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/'
			,$this->definitionHash['SYSTEM_MAIL_FROM_ADDRESS']) == 0 ) {
			$request->addLocaledError('system.error.config.invalidmailaddress',SPIDER_LOG_LEVEL_ERROR,array());
		}
		if( strlen(trim($this->definitionHash['SYSTEM_MAIL_REPLY_ADDRESS'])) == 0 ) {
			$this->definitionHash['SYSTEM_MAIL_REPLY_ADDRESS']	= $this->definitionHash['SYSTEM_MAIL_FROM_ADDRESS'];
		} else if( preg_match('/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/'
			,$this->definitionHash['SYSTEM_MAIL_REPLY_ADDRESS']) == 0 ) {
			$request->addLocaledError('system.error.config.invalidreplyladdress',SPIDER_LOG_LEVEL_ERROR,array());
		}
		if( strlen(trim($this->definitionHash['SYSTEM_MAIL_RETURN_ADDRESS'])) == 0 ) {
			$this->definitionHash['SYSTEM_MAIL_RETURN_ADDRESS']	= $this->definitionHash['SYSTEM_MAIL_FROM_ADDRESS'];
		} else if( preg_match('/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/'
			,$this->definitionHash['SYSTEM_MAIL_RETURN_ADDRESS']) == 0 ) {
			$request->addLocaledError('system.error.config.invalidreturnladdress',SPIDER_LOG_LEVEL_ERROR,array());
		}
		if( count( $this->definitionHash['SYSTEM_MAIL_REPORT_TO_ADDRESSES'] ) == 0 ) {
			$request->addLocaledError('system.error.config.noreportaddress',SPIDER_LOG_LEVEL_ERROR,array());
		} else {
			foreach( $this->definitionHash['SYSTEM_MAIL_REPORT_TO_ADDRESSES'] as $num => $address ) {
				if( preg_match('/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/'
					,$address) == 0 ) {
				$request->addLocaledError('system.error.config.invalidreportaddress',SPIDER_LOG_LEVEL_ERROR,array($num+1));
				}
			}
		}
		$send_defs	= $GLOBALS['SYSTEM_SEND_METHOD'][$this->definitionHash['SYSTEM_MAIL_SEND_METHOD']];
		if( !is_array( $send_defs ) ) {
			$request->addLocaledError('system.error.config.invalidsendmethod',SPIDER_LOG_LEVEL_ERROR,array());
		} else {
			$send_class_name	= $send_defs['class_name'];
			$send_view_name		= $send_defs['view_name'];
			$send_class_path	= DIR_PATH_LIB.DIRECTORY_SEPARATOR.'util'
				.DIRECTORY_SEPARATOR.'mail'.DIRECTORY_SEPARATOR.$send_class_name.'.class.php';
			if( !file_exists( $send_class_path ) ) {
				$request->addLocaledError('system.error.config.invalidsendclass',SPIDER_LOG_LEVEL_ERROR,array());
			} else {
				require_once($send_class_path);
				$send_class_name	= 'util_mail_' . $send_class_name;
				$send_object		= new $send_class_name;
				$errors				= $send_object->validate_options( $this->definitionHash['SYSTEM_MAIL_SEND_METHOD_OPTIONS'] );
				if( count($errors) > 0 ) {
					foreach( $errors as $msg ) {
						$request->addLocaledError($msg,SPIDER_LOG_LEVEL_ERROR,array());
					}
				}
			}
		}
		if( $request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	//
	// system_AbstractDataから
	//
	/**
	 * 本オブジェクトの設定情報を保存します。このメソッドはsystem_package_PackageConfigBaseクラスからオーバーライドされた実装です。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return boolean エラーがあるならfalse
	 * @access public
	 */
	function save( & $request ) {
		// システム管理者ユーザ
		$adminUser	= spider_Controller::createObject('system_login_UserAdministrator');
		// 旧ログインIDがあるなら削除する
		$systemDefineFile	= DIR_PATH_DATA.DIRECTORY_SEPARATOR.'system.define.inc.php';
		if( file_exists($systemDefineFile) ) {
			// 定義ファイルがあれば読み込み
			require_once($systemDefineFile);
			if( defined('SYSTEM_ADMIN_LOGIN_ID') ) {
				if( $adminUser->loadLoginUser( $request, SYSTEM_ADMIN_LOGIN_ID ) ) {
					// ファイルが存在するならファイルを削除
					$adminUser->delete( $request, SYSTEM_ADMIN_LOGIN_ID );
				}
			}
		}
		// システム管理者ログイン情報を保存
		$adminUser->loginId			= $this->definitionHash['SYSTEM_ADMIN_LOGIN_ID'];
		$adminUser->viewName		= $this->definitionHash['SYSTEM_MAIL_FROM_NAME'];
		// システム管理者パスワードを暗号化する
		$this->definitionHash['SYSTEM_ADMIN_LOGIN_PASSWORD']
		= $adminUser->encodePassword($request,$this->definitionHash['SYSTEM_ADMIN_LOGIN_PASSWORD'],
		$this->definitionHash['SYSTEM_CRYPT_KEY'],
		$this->definitionHash['SYSTEM_CRYPT_METHOD'] );
		$adminUser->loginPassword	= $this->definitionHash['SYSTEM_ADMIN_LOGIN_PASSWORD'];
		// 管理者情報を保存
		if( $adminUser->save( $request ) ) {
			return parent::save( $request );
		} else {
			return false;
		}
	}
	//
	// 固有メソッド
	//
	/**
	 * システムユーザー指定ログインIDのユーザーオブジェクトを取得します
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @param string $loginId ログインID
	 * @return mixed system_login_AbstractUserの実装クラスインスタンス エラーがあるならfalse
	 * @access public
	 * @static
	 */
	function getUserObjectByLoginId( & $request, $loginId ) {
		$userClassNameArray	= array();
		if( !$request->isError() ) {
			// 全てのユーザー定義クラスの読み込み
			$userClassNameArray	= system_PackageConfig::loadAllUserClassFile( $request );
		}
		if( !$request->isError() ) {
			// 全ての定義クラスで優先順に指定ログインIDの情報を読み込めるか確認
			foreach( $userClassNameArray as $userClassName ) {
				if( class_exists($userClassName) ) {
					$loginInformationObject	= new $userClassName;
					if( is_a($loginInformationObject,'system_login_AbstractUser') ) {
						// ユーザークラスの実装として定義されている
						if( $loginInformationObject->loadLoginUser( $request, $loginId ) ) {
							// 読み込みに成功したら存在する
							return $loginInformationObject;
						} else {
							// 読み込めなかったら次の定義クラスを確認する為エラーにしない
						}
					} else {
						// AbstractUserの実装ではないクラスが設定されている場合
						$request->addLocaledError('system.error.config.invalidsendclassname',SPIDER_LOG_LEVEL_ERROR,array($userClassName));
						return false;
					}
				}
			}
		}
		return false;
	}
	/**
	 * 指定されたログインIDがシステム上に存在するか確認します
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @param string $loginId ログインID
	 * @return boolean 存在するならtrue / 存在しないかエラーが発生した場合にはfalse
	 * @access public
	 * @static
	 */
	function isExistLoginId( & $request, $loginId ){
		if( $this->getUserObjectByLoginId( $request, $loginId ) ) {
			return true;
		} else {
			return false;
		}
	}
	/**
	 * 指定されたユーザユニークIDユーザーオブジェクトを取得します
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @param string $uniqueId 固有ID
	 * @return mixed 存在するならユーザーオブジェクト / 存在しないかエラーが発生した場合にはfalse
	 * @access public
	 * @static
	 */
	function getUserObjectByUniqueId( & $request, $uniqueId ) {
		$userClassNameArray	= array();
		if( !$request->isError() ) {
			// 全てのユーザー定義クラスの読み込み
			$userClassNameArray	= system_PackageConfig::loadAllUserClassFile( $request );
		}
		if( !$request->isError() ) {
			// 全ての定義クラスで優先順に指定ログインIDの情報を読み込めるか確認
			foreach( $userClassNameArray as $userClassName ) {
				if( class_exists($userClassName) ) {
					$loginInformationObject	= new $userClassName;
					if( is_a($loginInformationObject,'system_login_AbstractUser') ) {
						// ユーザークラスの実装として定義されている
						if( $loginInformationObject->loadLoginUserByUniqueId( $request, $uniqueId ) ) {
							// 読み込みに成功したら存在する
							return $loginInformationObject;
						} else {
							// 読み込めなかったら次の定義クラスを確認する為エラーにしない
						}
					} else {
						// AbstractUserの実装ではないクラスが設定されている場合
						$request->addLocaledError('system.error.config.invalidsendclassname',SPIDER_LOG_LEVEL_ERROR,array($userClassName));
						return false;
					}
				}
			}
		}
		return false;
	}
	/**
	 * 指定されたユーザユニークIDがシステム上に存在するか確認します
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @param string $uniqueId 固有ID
	 * @return boolean 存在するならtrue / 存在しないかエラーが発生した場合にはfalse
	 * @access public
	 * @static
	 */
	function isExistUniqueId( & $request, $uniqueId ){
		if( $this->getUserObjectByUniqueId( $request, $uniqueId ) ) {
			return true;
		} else {
			return false;
		}
	}
	/**
	 * 指定されたユーザー定義クラス名からユーザー定義クラス記述ファイルを読み込みます
	 * 本メソッドは今後のバージョンアップでprotectedスコープへと変更する予定ですので外部から利用しないでください。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @param string $userClassName system_login_AbstractUser実装のログインユーザー定義クラス名。
	 * @return boolean 成功したらtrue,それ以外はfalse
	 * @access public
	 * @static
	 */
	function loadUserClassFile( & $request, $userClassName ) {
		if( !class_exists( $userClassName ) ) {
			$userClassFilePath	= DIR_PATH_LIB.DIRECTORY_SEPARATOR
				.str_replace('_',DIRECTORY_SEPARATOR,$userClassName).'.class.php';
			if( file_exists( $userClassFilePath ) ) {
				require_once($userClassFilePath);
				if( !class_exists( $userClassName ) ) {
					$request->addLocaledError('system.error.config.invalidsendclassname',SPIDER_LOG_LEVEL_ERROR,array($userClassName));
					return false;
				}
			} else {
				$request->addLocaledError('system.error.config.invalidsendclassname',SPIDER_LOG_LEVEL_ERROR,array($userClassName));
				return false;
			}
		}
		return true;
	}
	/**
	 * 必要とされる全てのユーザー定義クラスのクラス記述ファイルを読み込んで定義クラス名の配列を取得します。
	 * 本メソッドは今後のバージョンアップでprotectedスコープへと変更する予定ですので外部から利用しないでください。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return boolean 成功したらtrue,それ以外はfalse
	 * @access public
	 * @static
	 */
	function loadAllUserClassFile( & $request ) {
		$userClassNameArray	= array();
		$installedPackageObjectHash	= $request->getAttribute('system.package.installedPackageObjectHash');
		if( !is_array($installedPackageObjectHash) ) {
			spider_Controller::loadClassDefinition('system_package_LoadListExists');
			spider_Controller::loadClassDefinition('system_package_LoadList');
			system_package_LoadListExists::execute( $request );
			system_package_LoadList::execute( $request );
			$installedPackageObjectHash	= $request->getAttribute('system.package.installedPackageObjectHash');
		}
		foreach( $installedPackageObjectHash as $packageId => $packageObject ) {
			$loginUserClassNameArray	= $packageObject->getLoginClassNameArray($request);
			foreach( $loginUserClassNameArray as $userClassName ) {
				if( system_PackageConfig::loadUserClassFile( $request, $userClassName ) ) {
					array_push( $userClassNameArray, $userClassName );
				}
			}
		}
		// 例外設定 - 'system_login_UserAdministrator'だけはインストールされていなくてもログインできる
		if( !in_array('system_login_UserAdministrator',$userClassNameArray) ) {
			array_unshift($userClassNameArray,'system_login_UserAdministrator');
		}
		return $userClassNameArray;
	}
	/**
	 * ログインユーザーとして利用できるクラス名称を取得するインターフェースメソッドの実装
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return array 作成パッケージ内でsystem_login_AbstractUserを拡張実装しログインユーザー定義として利用できるオブジェクトクラス名。
	 * @access public
	 */
	function getLoginClassNameArray( & $request ) {
		return array('system_login_UserAdministrator');
	}
}
?>