<?php
/*
 * design/DaoTemplate.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-06-18
 */
require_once(dirname(dirname(__FILE__))
	.DIRECTORY_SEPARATOR.'system'
	.DIRECTORY_SEPARATOR.'AbstractData.class.php');
require_once(dirname(dirname(__FILE__))
	.DIRECTORY_SEPARATOR.'system'
	.DIRECTORY_SEPARATOR.'DataFileWriter.class.php');
require_once(dirname(dirname(__FILE__))
	.DIRECTORY_SEPARATOR.'content'
	.DIRECTORY_SEPARATOR.'DaoPage.class.php');
require_once(dirname(dirname(__FILE__))
	.DIRECTORY_SEPARATOR.'content'
	.DIRECTORY_SEPARATOR.'Variable.class.php');
require_once( dirname(__FILE__)
	. DIRECTORY_SEPARATOR.'package_define.inc.php');
class design_DaoTemplate extends system_AbstractData {
	/** テンプレートファイル名	*/
	var $file_name	= '';
	/** テンプレート表示名	*/
	var $view_name	= '';
	/** テンプレート名	*/
	var $name		= '';
	/** コピーライト	*/
	var $copyright	= '';
	/** URL	*/
	var $url		= '';
	/** 再配布キー(プレーン) */
	var $publish_key_plain	= '';
	/** 再配布キー	*/
	var $publish_key	= '';
	/** インストールパスワード(プレーン)	*/
	var $install_key_plain	= '';
	/** インストールパスワード	*/
	var $install_key	= '';
	/** 認証URL	*/
	var $auth_url		= '';
	/** HTML編集可否	*/
	var $html_edit		= true;
	/** 設定済みフラグ	*/
	var $isSetup		= false;
	/** 同梱ページファイル	*/
	var $include_pages	= null;
	/** 同梱指定メディアファイル	*/
	var $include_files	= null;
	/** テンプレート変数のハッシュ	*/
	var $variableHash	= array();
	/** 関連ページURIの配列	*/
	var $relatedPageUriArray	= array();
	/** 関連ページオブジェクトの配列	*/
	var $relatedPageObjectArray	= array();
	// 自動保存メンバ
	/** 作成したデザインパッケージバージョン	*/
	var $creatorVersion			= DESIGN_VERSION;
	/** 作成したリリース名	*/
	var $releaseName			= RELEASE_NAME;
	/** 作成したリリースバージョン	*/
	var $releaseVersion			= DESIGN_VERSION;
	/** サイト固有値オブジェクト一時メンバ	*/
	var $variableObject	= null;
	/**
	 * コンストラクタ
	 */
	function design_DaoTemplate( $fileName = null ) {
		$this->variableHash	= array();
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
	}
	function _getSettingSaveDir( $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		return DIR_PATH_DATA
			.DIRECTORY_SEPARATOR.'design'
			.DIRECTORY_SEPARATOR.'template'
			.DIRECTORY_SEPARATOR.$this->file_name;
	}
	function _getSettingSaveUri( $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		return '/design/template/'.$this->file_name;
	}
	/**
	 * テンプレート情報を読み込みます
	 */
	function loadInfo( & $request, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		$infoPath	= $this->_getSettingSaveDir().DIRECTORY_SEPARATOR.'info.txt';
		if( file_exists($infoPath) ) {
			$lines	= file($infoPath);
			foreach( $lines as $line ) {
				$line	= trim($line);
				if( strlen($line) > 0 ) {
					$vArray	= explode("\t",$line);
					$vName	= array_shift($vArray);
					$vValue	= implode("\t",$vArray);
					$this->$vName	= $vValue;
				}
			}
			if( preg_match('/^[fF](|[aA][lL][sS][eE])$/',$this->html_edit) > 0 ) {
				$this->html_edit	= false;
			} else {
				$this->html_edit	= true;
			}
			$this->isSetup	= true;
		} else {
			$this->isSetup	= false;
		}
		// 関連ページファイル情報があるなら読み込み
		$this->relatedPageUriArray		= array();
		$this->relatedPageObjectArray	= array();
		$pageSaveUri	= $this->_getSettingSaveUri().'/related_pages.txt';
		$pageSavePath	= system_DataFileWriter::getRealAbsolutePath( $request, $pageSaveUri, DIR_NAME_DATA );
		if( file_exists($pageSavePath) ) {
			$strings	= file_get_contents($pageSavePath);
			$strings	= str_replace("\r\n","\n",$strings);
			$strings	= str_replace("\r","\n",$strings);
			$pageUriArray	= explode("\n",$strings);
			foreach( $pageUriArray as $pageUri ) {
				$pageUri	= trim($pageUri);
				if( strlen($pageUri) > 0 ) {
					$pageObject	= new content_DaoPage($pageUri);
					$pageObject->load( $request );
					array_push($this->relatedPageObjectArray,$pageObject);
					array_push($this->relatedPageUriArray,$pageUri);
				}
			}
		}
	}
	/**
	 * オブジェクトに設定されているインフォメーションを文字列で取得します
	 */
	function getInfo( & $request, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		if( strlen($this->publish_key_plain) > 0 ) {
			$this->publish_key	= crypt($this->publish_key_plain);
		} else if( strlen($this->publish_key_new) > 0 ) {
			$this->publish_key	= crypt($this->publish_key_new);
		}
		$string	= "view_name\t".$this->view_name."\n"
			."name\t".$this->name."\n"
			."copyright\t".$this->copyright."\n"
			."url\t".$this->url."\n"
		;
		if($this->html_edit) {
			$string	.= "html_edit\ttrue\n";
		} else {
			$string	.= "html_edit\tfalse\n";
		}
		$string	.= "creatorVersion\t".DESIGN_VERSION."\n";
		$string	.= "releaseName\t".RELEASE_NAME."\n";
		$string	.= "releaseVersion\t".RELEASE_VERSION."\n";
		$string	.= "publish_key\t".$this->publish_key."\n";
		return $string;
	}
	/**
	 * テンプレート情報を保存します
	 */
	function saveInfo( & $request, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		$infoUri	= $this->_getSettingSaveUri().'/info.txt';
		$writer		= new system_DataFileWriter();
		if( $writer->open( $request, $infoUri, 'w', DIR_NAME_DATA ) ) {
			$writer->write( $this->getInfo( $request) );
			$writer->close( $request );
		}
	}
	/**
	 * 指定エージェントのテンプレート本文を保存する
	 * @param $request spider_HttpRequest
	 * @param $agent 対象ユーザーエージェント
	 * @param $body 本文
	 * @param $fileName テンプレートファイル名
	 */
	function saveBody( & $request, $agent, $body, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		$bodyFileUri	= $this->_getSettingSaveUri().'/'.$agent.'/template.tpl';
		if( strlen($body) > 0 ) {
			$writer			= new system_DataFileWriter();
			if( $writer->open( $request, $bodyFileUri, 'w', DIR_NAME_DATA ) ) {
				$writer->write( $body );
				$writer->close( $request );
			}
		} else {
			// 本文がないならファイルを削除する
			system_DataFileWriter::delete( $request, $bodyFileUri, DIR_NAME_DATA );
		}
	}
	/**
	 * 指定エージェントのテンプレート本文を取得する
	 * @param $request spider_HttpRequest
	 * @param $agent 対象ユーザーエージェント
	 * @param $fileName テンプレートファイル名
	 */
	function getBody( & $request, $agent, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		$orgPath		= $this->_getSettingSaveDir()
			.DIRECTORY_SEPARATOR.$agent
			.DIRECTORY_SEPARATOR.'template.tpl';
		$bodyStrings	= '';
		if( file_exists($orgPath) ) {
			$bodyStrings	= str_replace("\t","  ",file_get_contents($orgPath));
		}
		return $bodyStrings;
	}
	/**
	 * デザインテンプレートを全てリビルドします
	 * @param $request spider_HttpRequest
	 * @param $agent 対象ユーザーエージェント
	 * @param $fileName テンプレートファイル名
	 */
	function rebuildAll( & $request ) {
		foreach( $GLOBALS['SPIDER_USER_AGENT_CLASS_HASH'] as $agentType => $agentName ) {
			$this->rebuild( $request, $agentType );
		}
	}
	/**
	 * 指定エージェントのテンプレートをリビルドする
	 * @param $request spider_HttpRequest
	 * @param $agent 対象ユーザーエージェント
	 * @param $fileName テンプレートファイル名
	 */
	function rebuild( & $request, $agent, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		$templateUri	= '/'.$agent.'/'.$this->file_name;
		$bodyStrings	= $this->getBodyVariableReplaced( $request, $agent );
		if( strlen( $bodyStrings ) > 0 ) {
			// テンプレートディレクトリに出力
			$writer			= new system_DataFileWriter();
			if( $writer->open( $request, $templateUri, 'w', DIR_NAME_TEMPLATES ) ) {
				$writer->write( $bodyStrings );
				$writer->close( $request );
			}
		} else {
			// 本文がないならファイルを削除する
			system_DataFileWriter::delete( $request, $templateUri, DIR_NAME_TEMPLATES );
		}
	}
	/**
	 * 指定エージェントのサイト固有値を置き換えた文字列を取得します
	 */
	function getBodyVariableReplaced( & $request, $agent, $bodyStrings = null ) {
		if( is_null($bodyStrings) ) {
			$bodyStrings	= $this->getBody( $request, $agent );
		}
		if( strlen( $bodyStrings ) > 0 ) {
			$this->loadInfo( $request );
			$keyArray	= $this->getKeyArray( $request );
			// テンプレート変数をsetAttributeして置き換え
			$setStrings	= '';
			foreach( $keyArray as $key ) {
				$repWord	= '{value:'.$key.'}';
				$value	= $this->getValue( $request, $key );
				$bodyStrings	= str_replace($repWord,$value,$bodyStrings);
				$value	= str_replace("\r\n","\n",$value);
				$value	= str_replace("\r","\n",$value);
				$value	= str_replace("\n",'\\n',$value);
				$value	= str_replace("'","\\'",$value);
				$setStrings		.= '{set:'.$key.' \''.$value.'\'}';
			}
			$bodyStrings	= preg_replace('/(\\<[hH][tT][mM][lL][^\\>]*\\>)/',$setStrings.'${1}',$bodyStrings);
		}
		return $bodyStrings;
	}
	/**
	 * テンプレート関連ファイルを全て削除する
	 * アップロードファイルは削除しない
	 */
	function deleteAll( & $request, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		if( strlen( $this->file_name ) == 0 ) {
			return false;
		}
		// データファイルを全て削除
		system_DataFileWriter::deleteDir( $request, $this->_getSettingSaveUri(), DIR_NAME_DATA );
		// ビルド済みテンプレートファイルを全て削除
		$existsAgentArray	= array();
		if( is_dir(DIR_PATH_TEMPLATES) ) {
			if ($dh = opendir(DIR_PATH_TEMPLATES)) {
				while (($fileName = readdir($dh)) !== false) {
					if( $fileName != '.' && $fileName != '..' ) {
						$absolutePath	= DIR_PATH_TEMPLATES.DIRECTORY_SEPARATOR.$fileName;
						if( is_dir($absolutePath) ) {
							array_push( $existsAgentArray, $fileName );
						}
					}
				}
				closedir($dh);
			}
		}
		foreach( $existsAgentArray as $agent ) {
			$uri	= '/'.$agent.'/'.$this->file_name;
			system_DataFileWriter::delete( $request, $uri, DIR_NAME_TEMPLATES );
		}
	}
	/**
	 * このテンプレートの本文で利用されているファイルの一覧を取得します
	 */
	function getRelatedFileUriArray( & $request, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		if( strlen( $this->file_name ) == 0 ) {
			return false;
		}
		$fileUriArray	= array();
		foreach( $GLOBALS['SPIDER_USER_AGENT_CLASS_HASH'] as $agentType => $agentName ) {
			$body	= $this->getBody( $request, $agentType );
			// 外部スタイルシート
			if( preg_match_all( '/[hH][rR][eE][fF]\\=[\'\"](\\/[^\'\"]+\\.[cC][sS][sS])[\'\"]/'
				, $body
				, $matcheArray
				, PREG_PATTERN_ORDER ) > 0 ) {
				$fileUriArray	= array_merge($fileUriArray,$matcheArray[1]);
			}
			// 外部src
			if( preg_match_all( '/[sS][rR][cC]\\=[\'\"](\\/[^\'\"]+\\.[a-zA-Z]+)[\'\"]/'
				, $body
				, $matcheArray
				, PREG_PATTERN_ORDER ) > 0 ) {
				$fileUriArray	= array_merge($fileUriArray,$matcheArray[1]);
			}
		}
		// 重複削除
		$fileUriArray	= array_unique($fileUriArray);
		// スタイルシートの確認
		foreach( $fileUriArray as $fileUri ) {
			if( preg_match('/\\.[cC][sS][sS]$/',$fileUri) > 0 ) {
				$cssFileArray	= $this->_getCssLinkUriArray( $request, $fileUri );
				foreach( $cssFileArray as $cssFileUri ) {
					if( !in_array($cssFileUri,$fileUriArray) ) {
						array_push($fileUriArray,$cssFileUri);
					}
				}
			}
		}
		return array_unique($fileUriArray);
	}
	/**
	 * 指定URIのCSS内のリンクファイルURIを配列で取得します
	 */
	function _getCssLinkUriArray( & $request, $fileUri ) {
		$fileUriArray	= array();
		$strings		= system_DataFileWriter::getContents( $request, $fileUri, 'public' );
		if( strlen($strings) > 0 ) {
			// url記述を取得
			$matcheHash	= array();
			preg_match_all( '/[uU][rR][lL][\\s]*\\(([^\\)]+)\\)/'
				, $strings
				, $matcheHash
				, PREG_PATTERN_ORDER );
			if( is_array($matcheHash[1]) ) {
				$cssBase	= dirname($fileUri);
				foreach( $matcheHash[1] as $url ) {
					$url	= $this->_converRelativeUri( $url, $cssBase );
					if( $url !== false ) {
						array_push($fileUriArray,$url);
						if( preg_match('/\\.[cC][sS][sS]$/',$url) > 0 ) {
							$cssFileArray	= $this->_getCssLinkUriArray( $request, $url );
							foreach( $cssFileArray as $cssFileUri ) {
								if( !in_array($cssFileUri,$fileUriArray) ) {
									array_push($fileUriArray,$cssFileUri);
								}
							}
						}
					}
				}
			}
			// @import ""の記述を取得
			$matcheHash	= array();
			preg_match_all( '/\\@import[\\s]*[\\\'\\"]([^\\\'\\"]+)[\\\'\\"]/'
				, $strings
				, $matcheHash
				, PREG_PATTERN_ORDER );
			if( is_array($matcheHash[1]) ) {
				$cssBase	= dirname($fileUri);
				foreach( $matcheHash[1] as $url ) {
					$url	= $this->_converRelativeUri( $url, $cssBase );
					if( $url !== false ) {
						array_push($fileUriArray,$url);
						if( preg_match('/\\.[cC][sS][sS]$/',$url) > 0 ) {
							$cssFileArray	= $this->_getCssLinkUriArray( $request, $url );
							foreach( $cssFileArray as $cssFileUri ) {
								if( !in_array($cssFileUri,$fileUriArray) ) {
									array_push($fileUriArray,$cssFileUri);
								}
							}
						}
					}
				}
			}
		}
		return array_unique($fileUriArray);
	}
	/**
	 * 相対パスをベースURIからの絶対パスに書き換えます。
	 * 相対パスでない場合はfalseを返します
	 */
	function _converRelativeUri( $url, $cssBase ) {
		$url	= preg_replace('/^\'([^\']+)\'$/','${1}',$url);
		$url	= preg_replace('/^"([^"]+)"$/','${1}',$url);
		if( preg_match('/\\.\\.\\//',$url) > 0 ) {
			// 上位リンクを含む
			$upCount	= substr_count($url,'../');
			$targetBase	= $cssBase;
			$exists		= true;
			for( $i=0; $i<$upCount; $i++ ) {
				if( strlen($targetBase) > 1 ) {
					$targetBase	= dirname($targetBase);
				} else {
					$exists		= false;
					break;
				}
			}
			if( strlen($targetBase) == 1 ) {
				$targetBase	= '';
			}
			if( $exists ) {
				// 対象ファイルがルート内なら
				$targetUri	= $targetBase.'/'.str_replace('../','',$url);
				return $targetUri;
			} else {
				// 対象ファイルがアプリケーションルート外なら無視
				return false;
			}
		} else if( preg_match('/\\.\\//',$url) > 0 ) {
			// cssと同じフォルダ
			$targetUri	= $cssBase.'/'.str_replace('./','',$url);
			return $targetUri;
		} else if( preg_match('/^\\//',$url) > 0 ) {
			// 絶対URIで記述されているなら無視する
			return false;
		} else {
			// ファイル名やフォルダ名から始まっている
			$targetUri	= $cssBase.'/'.$url;
			return $targetUri;
		}
	}
	/**
	 * テンプレートアーカイブファイル作成可能かチェックします
	 */
	function createArchiveValidate( & $request, $altVariableHash=array(), $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		if( strlen( $this->file_name ) == 0 ) {
			return false;
		}
		// パブリッシュキーの一致チェック
		if( strlen($this->publish_key)>0 ) {
			if( strlen($this->publish_key_plain) == 0 ) {
				$request->addError('パブリッシュキーが必要です');
				return false;
			} else if($this->publish_key != crypt($this->publish_key_plain, $this->publish_key)) {
				$request->addError('パブリッシュキーが正しくありません');
				return false;
			}
		}
		// トータルファイルサイズチェック
		$totalFileSize		= 0;
		// インフォメーション
		$info			= $this->getInfo( $request );
		$totalFileSize	+= strlen($info);
		// 要求変数ファイル
		$items			= $this->getVariableSettingStrings( $request, $altVariableHash );
		$totalFileSize	+= strlen(base64_encode($items));
		// 本文ファイル
		foreach( $GLOBALS['SPIDER_USER_AGENT_CLASS_HASH'] as $agentType => $agentName ) {
			$orgPath		= $this->_getSettingSaveDir()
				.DIRECTORY_SEPARATOR.$agentType
				.DIRECTORY_SEPARATOR.'template.tpl';
			if( file_exists($orgPath) ) {
				$totalFileSize		+= filesize( $orgPath );
			}
		}
		// アップロードファイル
		$fileUriArray	= $this->getRelatedFileUriArray( $request );
		foreach( $fileUriArray as $fileUri ) {
			$realPath	= system_DataFileWriter::getRealAbsolutePath( $request, $fileUri, 'public' );
			if( file_exists($realPath) ) {
				$totalFileSize	+= filesize($realPath);
			}
		}
		// ページファイル(ページ内のリンク画像ファイル等は次マイナーアップデートで検討)
		$this->include_pages	= str_replace("\r\n","\n",$this->include_pages);
		$this->include_pages	= trim(str_replace("\r","\n",$this->include_pages));
		if( strlen($this->include_pages) > 0 ) {
			$includePageArray	= explode("\n",$this->include_pages);
			foreach( $includePageArray as $fileUri ) {
				$fileUri	= trim($fileUri);
				if( strlen($fileUri) > 0 ) {
					// パブリックファイル
					$realPath	= system_DataFileWriter::getRealAbsolutePath( $request, $fileUri, 'public' );
					if( file_exists($realPath) ) {
						$totalFileSize	+= filesize($realPath);
					}
					// ページファイル
					foreach( $GLOBALS['SPIDER_USER_AGENT_CLASS_HASH'] as $agentKey => $agentName ) {
						$agentPageUri	= '/'.$agentKey.$fileUri;
						$realPath	= system_DataFileWriter::getRealAbsolutePath( $request, $agentPageUri );
						if( file_exists($realPath) ) {
							$totalFileSize	+= filesize($realPath);
						} else {
							$realPath	= system_DataFileWriter::getRealAbsolutePath( $request, $agentPageUri, DIR_NAME_PAGES );
							if( file_exists($realPath) ) {
								$totalFileSize	+= filesize($realPath);
							}
						}
					}
				}
			}
		}
		
		// サイズの合計が1.5Mを超えるなら
		if( $totalFileSize > 1024 * 1024 * 1.5 ) {
			$request->addError('テンプレートファイルのサイズはアップロードファイルを含めて1.5MBまでです。');
			return false;
		}
		return true;
	}	
	/**
	 * テンプレートアーカイブファイルを作成します
	 */
	function createArchiveExecute( & $request, $createFileUri, $altVariableHash=array(), $targetRoot=DIR_NAME_TMP, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		if( strlen( $this->file_name ) == 0 ) {
			return false;
		}
		if( false === $this->createArchiveValidate( $request, $altVariableHash ) ) {
			return false;
		}
		// インフォメーションファイル
		$info			= $this->getInfo( $request );
		// 要求変数ファイル
		$items			= $this->getVariableSettingStrings( $request, $altVariableHash );
		// アップロードファイル
		$fileUriArray	= $this->getRelatedFileUriArray( $request );
		// 作成
		$writer	= new system_DataFileWriter();
		if( $writer->open( $request, $createFileUri, 'w', $targetRoot ) ) {
			// デザインテンプレートバージョン
			$writer->write( "FORMER-TEMPLATE-VERSION\r\n".DESIGN_VERSION."\r\n\r\n" );
			$writer->write( "BUILD\r\n20101109\r\n\r\n" );
			$writer->write( "FORMER-RELEASE-NAME\r\n".RELEASE_NAME."\r\n\r\n" );
			$writer->write( "FORMER-RELEASE-VERSION\r\n".RELEASE_VERSION."\r\n\r\n" );
			$writer->write( "COPYRIGHT\r\nShopformer Development Team.\r\n\r\n" );
			$writer->write( "BASENAME\r\n".$this->file_name."\r\n\r\n" );
			
			// インストールパスワード
			if( strlen($this->install_key_plain) > 0 ) {
				$writer->write( "lisence\r\n" );
				$writer->write( crypt($this->install_key_plain) );
				$writer->write( "\r\n\r\n" );
			}
			
			// 認証URLの追加
			$writer->write( "FORMER-AUTH-URL\r\n".$this->auth_url."\r\n\r\n" );
			
			// インフォ
			$writer->write( "info.txt\r\n" );
			$writer->write( base64_encode($info) );
			$writer->write( "\r\n\r\n" );
			// 要求
			$writer->write( "requires.txt\r\n" );
			$writer->write( base64_encode($items) );
			$writer->write( "\r\n\r\n" );

			// 本文ファイル
			foreach( $GLOBALS['SPIDER_USER_AGENT_CLASS_HASH'] as $agentType => $agentName ) {
				$orgPath		= $this->_getSettingSaveDir()
					.DIRECTORY_SEPARATOR.$agentType
					.DIRECTORY_SEPARATOR.'template.tpl';
				if( file_exists($orgPath) ) {
					$strings	= file_get_contents($orgPath);
					$writer->write( 'body:'.$agentType."\r\n" );
					$writer->write( base64_encode($strings) );
					$writer->write( "\r\n\r\n" );
				}
			}
			// 同梱ページ
			$this->include_pages	= str_replace("\r\n","\n",$this->include_pages);
			$this->include_pages	= trim(str_replace("\r","\n",$this->include_pages));
			if( strlen($this->include_pages) > 0 ) {
				$includePageArray	= explode("\n",$this->include_pages);
				foreach( $includePageArray as $pageUri ) {
					$pageUri	= trim($pageUri);
					if( strlen($pageUri) > 0 ) {
						// パブリックファイル
						$realPath	= system_DataFileWriter::getRealAbsolutePath( $request, $pageUri, 'public' );
						if( file_exists($realPath) ) {
							$strings	= file_get_contents($realPath);
							// 同梱前にテンプレート名を本テンプレートに書き換え
							$strings	= preg_replace('/\\{template\\:[0-9a-zA-Z]+\\.fmt\\}/','{template:'.$this->file_name.'}',$strings);
							$writer->write( 'public:'.$pageUri."\r\n" );
							$writer->write( base64_encode($strings) );
							$writer->write( "\r\n\r\n" );
							// .defaultファイルが同一階層にあるなら同梱処理
							$dotDefaultPath	= dirname($realPath).DIRECTORY_SEPARATOR.'.default';
							if( file_exists($dotDefaultPath) ) {
								$pageDirUri		= ( strlen(dirname($pageUri))==1 ) ? '' : dirname($pageUri);
								$dotDefaultUri	= $pageDirUri.'/.default';
								if( !in_array($dotDefaultUri,$fileUriArray) ) {
									array_push($fileUriArray,$dotDefaultUri);
								}
							}
						}
						// ページファイル
						foreach( $GLOBALS['SPIDER_USER_AGENT_CLASS_HASH'] as $agentKey => $agentName ) {
							$agentPageUri	= '/'.$agentKey.$pageUri;
							$realPath	= system_DataFileWriter::getRealAbsolutePath( $request, '/content/pages'.$agentPageUri );
							if( file_exists($realPath) ) {
								$strings	= file_get_contents($realPath);
								$writer->write( 'pages:'.$agentPageUri."\r\n" );
								$writer->write( base64_encode($strings) );
								$writer->write( "\r\n\r\n" );
							} else {
								$realPath	= system_DataFileWriter::getRealAbsolutePath( $request, $agentPageUri, DIR_NAME_PAGES );
								if( file_exists($realPath) ) {
									$strings	= file_get_contents($realPath);
									$writer->write( 'pages:'.$agentPageUri."\r\n" );
									$writer->write( base64_encode($strings) );
									$writer->write( "\r\n\r\n" );
								}
							}
						}
					}
				}
			}
			// アップロードファイル
			foreach( $fileUriArray as $fileUri ) {
				$realPath	= system_DataFileWriter::getRealAbsolutePath( $request, $fileUri, 'public' );
				if( file_exists($realPath) ) {
					$strings	= file_get_contents($realPath);
					$writer->write( 'public:'.$fileUri."\r\n" );
					$writer->write( base64_encode($strings) );
					$writer->write( "\r\n\r\n" );
				}
			}
			// 同梱メディアファイル
			$this->include_files	= str_replace("\r\n","\n",$this->include_files);
			$this->include_files	= trim(str_replace("\r","\n",$this->include_files));
			if( strlen(trim($this->include_files))) {
				$mediaFileArray	= explode("\n",trim($this->include_files));
				foreach( $mediaFileArray as $fileUri ) {
					if( strlen($fileUri) > 0 ) {
						$realPath	= system_DataFileWriter::getRealAbsolutePath( $request, $fileUri, 'public' );
						if( file_exists($realPath) ) {
							$strings	= file_get_contents($realPath);
							$writer->write( 'public:'.$fileUri."\r\n" );
							$writer->write( base64_encode($strings) );
							$writer->write( "\r\n\r\n" );
						}
					}
				}
			}
			$writer->close( $request );
			return true;
		}
		return false;
	}
	/**
	 * テンプレートアーカイブから復元します
	 * @param spider_HttpRequest $request
	 * @param string $realPath
	 * @param string $viewName
	 * @param string $installKeyPlain
	 * @param boolean $isDeleteIfErr エラー発生時に削除するか
	 * @param boolean $overrideContents 存在するコンテンツファイルを上書きするか
	 * @param boolean $overridePubPHP 存在するパブリックPHPファイルを上書きするか
	 * @param boolean $overridePages 存在するページファイルを上書きするか
	 */
	function recover( & $request, $realPath, $viewName,
		$installKeyPlain=null, $isDeleteIfErr=false,
		$overrideContents=true, $overridePubPHP=false, $overridePages=false, $uploadBaseName=null ) {
		if( file_exists( $realPath ) ) {
			// アーカイブファイルをサーバーに保存する
			$archiveFilePath	= $this->_getSettingSaveDir().DIRECTORY_SEPARATOR.'archive';
			if( str_replace(DIRECTORY_SEPARATOR,'/',$archiveFilePath) == str_replace(DIRECTORY_SEPARATOR,'/',$realPath) ) {
				// 同じ場合は保存しない
			} else {
				// 違うファイルの場合は保存する
				system_DataFileWriter::import( $request, $this->_getSettingSaveUri().'/archive', $realPath, DIR_NAME_DATA );
			}
			$pageArray	= array();
			$fp	= @fopen($realPath, 'r');
			if( $fp ) {
				$itemArray	= array();
				while (!feof($fp)) {
					$buffer	= trim(fgets($fp));
					if( strlen($buffer) == 0 ) {
						// 文字列長0になったら処理
						$varName	= array_shift($itemArray);
						$varValue	= implode("",$itemArray);
						if( 'lisence' == $varName && strlen(trim($varValue)) > 0 ) {
							if( strlen($installKeyPlain) == 0 ) {
								$request->addError('このテンプレートにはインストールパスワードが必要です。');
								return false;
							} else if( $varValue != crypt($installKeyPlain, $varValue) ) {
								$request->addError('インストールパスワードの入力が正しくありません。');
								return false;
							}
						} else if( 'info.txt' == $varName ) {
							// 情報設定
							$textBody	= base64_decode($varValue);
							$lines	= explode("\n",$textBody);
							foreach( $lines as $line ) {
								$line	= trim($line);
								if( strlen($line) > 0 ) {
									$vArray	= explode("\t",$line);
									$vName	= array_shift($vArray);
									$vValue	= implode("\t",$vArray);
									$this->$vName	= $vValue;
								}
							}
						} else if( 'requires.txt' == $varName ) {
							// 項目設定：変数をサイト変数に追加
							$textBody	= base64_decode($varValue);
							$lines	= explode("\n",$textBody);
							foreach( $lines as $line ) {
								$line	= trim($line);
								if( strlen($line) > 0 ) {
									$vArray	= explode("\t",$line);
									$vName	= array_shift($vArray);
									$vNote	= array_shift($vArray);
									$vValue	= implode("\t",$vArray);
									$this->setLabel( $request, $vName, $vNote );
									$this->setValue( $request, $vName, $vValue );
								}
							}
						} else if( 'BASENAME' == $varName ) {
							// ベース名称はファイル内容をパラメータ指定より優先
							if( strlen($varValue) > 0 ) {
								$uploadBaseName	= $varValue;
							}
						} else if( preg_match('/^body\\:/',$varName) > 0 ) {
							// テンプレート本文
							$agent	= preg_replace('/^body\\:/','',$varName);
							$body	= base64_decode($varValue);
							if( !is_null($uploadBaseName) && strlen($uploadBaseName) > 0 ) {
								// ベース名が取得できている場合は
								// テンプレート内部に記述されている画像リンクURIを新しい名前に書き換える
								$uploadFolderName	= preg_replace('/\\.fmt$/','',$uploadBaseName);
								$replaceName		= preg_replace('/\\.fmt$/','',$this->file_name);
								$body	= str_replace('"/upload/'.$uploadFolderName.'/','"/upload/'.$replaceName.'/',$body);
								$body	= str_replace('\'/upload/'.$uploadFolderName.'/','\'/upload/'.$replaceName.'/',$body);
							}
							$this->saveBody( $request, $agent, $body );
						} else if( preg_match('/^public\\:/',$varName) > 0 ) {
							// 公開ファイル
							$uri	= preg_replace('/^public\\:/','',$varName);
							// uploadフォルダ内のベース名称部分を登録ファイル名に書き換え
							if( !is_null($uploadBaseName) && strlen($uploadBaseName) > 0 ) {
								$uploadFolderName	= preg_replace('/\\.fmt$/','',$uploadBaseName);
								$replaceName		= preg_replace('/\\.fmt$/','',$this->file_name);
								$uri	= str_replace('/upload/'.$uploadFolderName.'/','/upload/'.$replaceName.'/',$uri);
								// ベース名フォルダ内に著作者テキストを作成
								$copyFileUri	= '/upload/'.$replaceName.'/copyright.txt';
								$writer	= new system_DataFileWriter();
								if( $writer->open( $request, $copyFileUri, 'w', 'public' ) ) {
									$writer->write( $this->copyright );
									$writer->close( $request );
								}
							}
							$bin	= base64_decode($varValue);
							$writer	= new system_DataFileWriter();
							// phpファイルの場合はテンプレート名部分を書き換え
							if( preg_match('/\\.php$/',$uri) > 0 ) {
								array_push($pageArray,$uri);
								$bin	= str_replace($uploadBaseName,$this->file_name,$bin);
							}
							// データフォルダ内にバックアップを書き込む
							$uriData	= $this->_getSettingSaveUri().'/public'.$uri;
							if( $writer->open( $request, $uriData, 'w', DIR_NAME_DATA ) ) {
								$writer->write( $bin );
								$writer->close( $request );
							}
							// 上書きモードに併せて公開フォルダ内に書き込み
							if( system_DataFileWriter::isExists( $request, $uri, 'public' ) ) {
								// ファイルが存在する場合は上書きモードなら書き込み
								if( (preg_match('/\\.php$/',$uri) == 0 && $overrideContents)
									|| (preg_match('/\\.php$/',$uri) > 0 && $overridePubPHP) ) {
									if( $writer->open( $request, $uri, 'w', 'public' ) ) {
										$writer->write( $bin );
										$writer->close( $request );
									}
								}
							} else {
								// ファイルが存在しないならそのまま書き込み
								if( $writer->open( $request, $uri, 'w', 'public' ) ) {
									$writer->write( $bin );
									$writer->close( $request );
								}
							}
						} else if( preg_match('/^pages\\:/',$varName) > 0 ) {
							// ページファイル
							$uri	= preg_replace('/^pages\\:/','',$varName);
							$bin	= base64_decode($varValue);
							if( !is_null($uploadBaseName) && strlen($uploadBaseName) > 0 ) {
								// ベース名が取得できている場合は
								// テンプレート内部に記述されている画像リンクURIを新しい名前に書き換える
								$uploadFolderName	= preg_replace('/\\.fmt$/','',$uploadBaseName);
								$replaceName		= preg_replace('/\\.fmt$/','',$this->file_name);
								$bin	= str_replace('"/upload/'.$uploadFolderName.'/','"/upload/'.$replaceName.'/',$bin);
								$bin	= str_replace('\'/upload/'.$uploadFolderName.'/','\'/upload/'.$replaceName.'/',$bin);
							}
							// dataのテンプレートフォルダ内に保存
							$orgBodyUri	= $this->_getSettingSaveUri().'/pages'.$uri;
							$writer	= new system_DataFileWriter();
							if( $writer->open( $request, $orgBodyUri, 'w', DIR_NAME_DATA ) ) {
								$writer->write( $bin );
								$writer->close( $request );
							}
							// 上書きモードならページに書き込み
							if( $overridePages ) {
								// 対象エージェント取得
								$folderArray	= explode('/',$uri);
								$top			= array_shift($folderArray);
								$agentType		= array_shift($folderArray);
								$pageUri		= '/'.implode('/',$folderArray);
								$pageObject	= new content_DaoPage( $pageUri );
								$pageObject->saveBody( $request, $agentType, $bin );
								$pageObject->rebuild( $request, $agentType );
							}
						} else {
							// その他未検討
							
						}
						$itemArray	= array();
					} else {
						array_push( $itemArray, $buffer );
					}
				}
				fclose($fp);
			}
			if( $request->isError() ) {
				// エラーがあるなら
				if( $isDeleteIfErr ) {
					$this->deleteAll( $request );
				}
				return false;
			} else {
				$this->view_name	= $viewName;
				$this->saveSetting( $request );
				$this->saveInfo( $request );
				$pageArray	= array_unique($pageArray);
				if( count($pageArray) > 0 ) {
					$str	= trim(implode("\n",$pageArray));
					if( strlen($str) > 0 ) {
						$pageSaveUri	= $this->_getSettingSaveUri().'/related_pages.txt';
						$writer	= new system_DataFileWriter();
						if( $writer->open( $request, $pageSaveUri, 'w', DIR_NAME_DATA ) ) {
							$writer->write( $str );
							$writer->close( $request );
						}
					}
				}
				return true;
			}
		} else {
			return false;
		}
	}

// サイト変数への置き換えに利用するメソッド群
	/**
	 * 本文と関連ページで利用されている全てのサイト固有値を取得します
	 * @param $request spider_HttpRequestクラスオブジェクトへの参照
	 * @return array 固有値キー配列
	 */
	function getRelatedVariableKeys( & $request ) {
		$usedVariableKeyArray	= array();
		// HTML本文からテンプレート変数の記述を抜き出す
		foreach( $GLOBALS['SPIDER_USER_AGENT_CLASS_HASH'] as $agent => $agentName ) {
			$body	= $this->getBody( $request, $agent );
			if( preg_match_all( '/\\{value\\:([a-zA-Z](|[0-9a-zA-Z\\.\\_]*[0-9a-zA-Z]))\\}/', $body, $matches, PREG_PATTERN_ORDER ) > 0) {
				if( is_array($matches[1]) ) {
					foreach( $matches[1] as $variableKey ) {
						if( strlen($variableKey) > 0 ) {
							array_push( $usedVariableKeyArray, $variableKey );
						}
					}
				}
			}
		}
		// 同梱ページ
		if( is_array($this->relatedPageObjectArray) ) {
			foreach( $this->relatedPageObjectArray as $pageObject ) {
				foreach( $GLOBALS['SPIDER_USER_AGENT_CLASS_HASH'] as $agent => $agentName ) {
					$body	= $pageObject->getBody( $request, $agent );
					if( preg_match_all( '/\\{value\\:([a-zA-Z](|[0-9a-zA-Z\\.\\_]*[0-9a-zA-Z]))\\}/', $body, $matches, PREG_PATTERN_ORDER ) > 0) {
						if( is_array($matches[1]) ) {
							foreach( $matches[1] as $variableKey ) {
								if( strlen($variableKey) > 0 ) {
									array_push( $usedVariableKeyArray, $variableKey );
								}
							}
						}
					}
				}
			}
		}
		$usedVariableKeyArray	= array_unique($usedVariableKeyArray);
		ksort($usedVariableKeyArray);
		return $usedVariableKeyArray;
	}
	/**
	 * 現在存在するキー文字列の配列を取得します
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function getKeyArray( & $request ) {
		$keyArray	= array();
		if( is_null($this->variableObject) ) {
			$this->variableObject	= new content_Variable($request);
		}
		$keyArray	= $this->variableObject->getKeyArray( $request );
		// 下位互換: テンプレート変数
		if( !is_array($this->variableHash) || count($this->variableHash) == 0 ) {
			$this->loadSettings( $request );
		}
		$keyArray	= array_merge($keyArray,array_keys($this->variableHash));
		$keyArray	= array_unique($keyArray);
		return $keyArray;
	}
	/**
	 * 指定のキーが存在するか確認します
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function existsKey( $key, & $request ) {
		if( is_null($this->variableObject) ) {
			$this->variableObject	= new content_Variable($request);
		}
		if( $this->variableObject->existsKey( $key ) ) {
			return true;
		} else if( isset($this->variableHash[$key]) ) {
			return true;
		}
		return false;
	}
	/**
	 * 固有変数値を取得します
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function getValue( & $request, $key ) {
		if( is_null($this->variableObject) ) {
			$this->variableObject	= new content_Variable($request);
		}
		$value	= $this->variableObject->getValue( $request, $key );
		if( is_null($value) || strlen($value) == 0 ) {

			if( !is_array($this->variableHash) || count($this->variableHash) == 0 ) {
				$this->loadSettings( $request );
			}
			if( isset($this->variableHash[$key]) ){
				if( isset($this->variableHash[$key]['value']) ) {
					$value	= $this->variableHash[$key]['value'];
				}
			}
		}
		return $value;
	}
	/**
	 * 固有変数値を設定します
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function setValue( & $request, $key, $value ) {
		if( is_null($this->variableObject) ) {
			$this->variableObject	= new content_Variable($request);
		}
		$this->variableObject->setValue($request, $key, $value);
	}
	/**
	 * 固有変数ラベルを取得します
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function getLabel( & $request, $key ) {
		if( is_null($this->variableObject) ) {
			$this->variableObject	= new content_Variable($request);
		}
		$label	= $this->variableObject->getLabel( $request, $key );
		if( is_null($label) || strlen($label) == 0 ) {
			if( !is_array($this->variableHash) || count($this->variableHash) == 0 ) {
				$this->loadSettings( $request );
			}
			if( isset($this->variableHash[$key]) ){
				if( isset($this->variableHash[$key]['note']) ) {
					$label	= $this->variableHash[$key]['note'];
				} else {
					$requireFilePath	= $this->_getSettingSaveDir().DIRECTORY_SEPARATOR.'requires.txt';
					if( file_exists($requireFilePath) ) {
						$lines	= file($requireFilePath);
						foreach( $lines as $line ) {
							$line	= trim($line);
							if( strlen($line) > 0 ) {
								list( $vkey, $vnote, $dValue )	= explode("\t",$line);
								if( $vkey == $key ) {
									$label	= $vnote;
									break;
								}
							}
						}
					}
				}
			}
		}
		return $label;
	}
	/**
	 * 固有変数ラベルを設定します
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function setLabel( & $request, $key, $label ) {
		if( is_null($this->variableObject) ) {
			$this->variableObject	= new content_Variable($request);
		}
		$this->variableObject->setLabel($request, $key, $label);
	}
	/**
	 * 指定キーのサイト変数を削除します
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function delete( & $request, $key ) {
		if( is_null($this->variableObject) ) {
			$this->variableObject	= new content_Variable($request);
		}
		$this->variableObject->delete($request, $key);
		if( !is_array($this->variableHash) || count($this->variableHash) == 0 ) {
			$this->loadSettings( $request );
		}
		if( isset($this->variableHash[$key]) ){
			unset($this->variableHash[$key]);
		}
	}
	/**
	 * ファイルからテンプレート設定を読み込む
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function loadSettings( & $request, $fileName = null ) {
		if( !is_null($fileName) ) {
			$this->file_name	= $fileName;
		}
		$this->variableHash	= array();
		if( file_exists($this->_getSettingSaveDir()) && is_dir($this->_getSettingSaveDir()) ) {
			// 必須項目を読み込み
			$requireFilePath	= $this->_getSettingSaveDir().DIRECTORY_SEPARATOR.'requires.txt';
			if( file_exists($requireFilePath) ) {
				$lines	= file($requireFilePath);
				foreach( $lines as $line ) {
					$line	= trim($line);
					if( strlen($line) > 0 ) {
						list( $vkey, $vnote, $dValue )	= explode("\t",$line);
						if( !isset($this->variableHash[$vkey]) || !is_array($this->variableHash[$vkey]) ) {
							$this->variableHash[$vkey]	= array();
						}
						$this->variableHash[$vkey]['note']	= $vnote;
						$this->variableHash[$vkey]['value']	= $dValue;
					}
				}
			}
			// 設定済みの項目があるなら読み込み
			$settingFilePath	= $this->_getSettingSaveDir().DIRECTORY_SEPARATOR.'settings';
			if( file_exists($settingFilePath) ) {
				$this->isSetup	= true;
				$strings	= file_get_contents($settingFilePath);
				// 項目値が空の場合の問題を回避する為3連続CRLFは置き換える
				$strings	= str_replace("\r\n\r\n\r\n","\r\n \r\n\r\n",$strings);
				$items		= explode("\r\n\r\n",$strings);
				foreach( $items as $itemStrings ) {
					if( strlen($itemStrings) > 0 ) {
						list( $vkey, $value )	= explode("\r\n",$itemStrings);
						if( strlen($vkey) > 0 ) {
							if( !is_array($this->variableHash[$vkey]) ) {
								$this->variableHash[$vkey]	= array();
							}
							// 項目値が半角スペースのみの場合は空扱い
							if( $value == ' ' ) {
								$value	= '';
							}
							$this->variableHash[$vkey]['value']	= $value;
						}
					}
				}
			} else if ( count($this->variableHash) == 0 ) {
				$this->isSetup	= true;
			} else {
				$this->isSetup	= false;
			}
		}
		return $this->variableHash;
	}
	/**
	 * テンプレート変数設定のテキスト化
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function getVariableSettingStrings( & $request, $altVariableHash=array() ) {
		if( is_null($this->file_name) ) {
			return false;
		}
		if( !is_array($altVariableHash) ) {
			$altVariableHash	= array();
		}
		$strings	= '';
		$keyArray	= $this->getRelatedVariableKeys( $request );
		foreach( $keyArray as $key ) {
			$setLabel	= null;
			if( isset($altVariableHash[$key]) && isset($altVariableHash[$key]['label']) ) {
				$setLabel	= trim($altVariableHash[$key]['label']);
			} else {
				$setLabel	= trim($this->getLabel( $request, $key ));
			}
			$setValue	= null;
			if( isset($altVariableHash[$key]) && isset($altVariableHash[$key]['value']) ) {
				$setValue	= trim($altVariableHash[$key]['value']);
			} else {
				$setValue	= trim($this->getValue( $request, $key ));
			}
			$setLabel	= str_replace( "\r", "", $setLabel );
			$setLabel	= str_replace( "\n", "", $setLabel );
			$setValue	= str_replace( "\r", "", $setValue );
			$setValue	= str_replace( "\n", "", $setValue );
			$strings	.= $key."\t".$setLabel."\t".$setValue."\n";
		}
		return $strings;
	}
	/**
	 * ファイルにテンプレート設定を書き込む
	 * 下位互換の為のメソッドです
	 * @deprecated 1.1.03 - 2010/07/23
	 */
	function saveSetting( & $request, $fileName = null ) {
		if( is_null($this->variableObject) ) {
			$this->variableObject	= new content_Variable($request);
		}
		$this->variableObject->_save( $request );
	}
}
?>