<?php
/*
 * framework-spider
 * spider/tags/Write.class.php
 * 
 * CopyRight(C)Framework-Spider Developer Team. 2010. All Right Reserved. 
 * URL         : http://sourceforge.jp/projects/frameworkspider/
 * Mail        : frameworkspider-dev@lists.sourceforge.jp
 * Auther      : Masanori Nakashima
 * Modifier    : Masanori Nakashima
 * Last Updated: 2010.06.23
 * 
 */
require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'TagBase.class.php');
/**
 * HTML用変換タグ：writeタグクラス
 * 
 * {write:[出力したいrequest属性名 etc]}
 * 
 * request属性に登録された値をページ内に出力するタグです。
 * 通常の状態では値をhtmlspecialchars関数にてHTMLエスケープした状態で出力します。
 * 
 * またwriteタグ内では
 * 
 * ・引数ひとつのグローバル関数で属性を処理して出力できます。
 *   例）
 *      {write:number_format(example.Hello.message)}
 * 
 * ・値が数値の場合演算結果を出力できます。演算子と属性名の間に空白は入れないでください。
 *   例）
 *      {write:count+1}
 *      {write:example.counta+example.countb}
 * 
 * ・配列、オブジェクトはprint_r()します
 * 
 * ・以下のオプションを出力文字の後に空白区切りで指定できます。
 *   ルールが相反するものでなければ複数同時に指定可能です。
 * noescape
 *   htmlspecialchars関数によるHTMLエスケープを行わずにHTMLタグもそのまま出力します。
 * nl2br
 *   改行文字を<br />[改行文字]に変換して出力します。
 * nl2null
 *   改行文字を削除して出力します。
 * escape-nl
 *   改行文字\nをそのまま\n表記で出力します。(JavaScript利用時などに有効です)
 * escape-sq
 *   'シングルクォートを\'にエスケープして出力します。(JavaScript利用時などに有効です)
 * escape-dq
 *   "ダブルクォートを\"にエスケープして出力します。(JavaScript利用時などに有効です)
 * urlencode
 *   値をURLエンコードして出力します。
 * 
 * @package spider spiderのコアパッケージ
 * @version 1.2.00
 * @copyright Copyright &copy; 2008, <m_nakashima@users.sourceforge.jp> http://sourceforge.jp/projects/shopformer/
 * @author  m.nakashima <m_nakashima@users.sourceforge.jp>
 * @since PHP 4.3
 */
class spider_tags_Write extends spider_tags_TagBase {

	/**
	 * コンストラクタ
	 */
	function spider_tags_Write() {
	}
	/**
	 * コンバートメソッド
	 */
	function convert( &$result_strings, &$build_information ){
		// 変数タグ
		$vars_tags_aray			= array();
		preg_match_all( '/\\{write\\:[^\\}]*?}/'
			, $result_strings
			, $vars_tags_aray
			, PREG_PATTERN_ORDER );
		$valiable_counter	= 0;
		foreach ( $vars_tags_aray as $vars_tags ) {
			foreach ( $vars_tags as $vars_tag ) {
				$var_name	= preg_replace( '/\\{write\\:/','', $vars_tag );
				$var_name	= preg_replace( '/\\}$/','', $var_name );
				$var_name	= trim( $var_name );
				// 下位互換の為::を含むなら旧ロジック
				$repstr		= '';
				if( preg_match('/\\:\\:/',$var_name) > 0 ) {
					$repstr	= $this->parseString( $var_name, $valiable_counter );
				} else {
					$repstr	= $this->tagOption2code( $var_name );
				}
				$result_strings	= str_replace( $vars_tag, $repstr, $result_strings );
				$valiable_counter++;
			}
		}
	}
	/**
	 * 
	 */
	function tagOption2code( $strings ) {
		// 最初に文字列化コード
		$ret_strings			= 'print_r( '.$strings.', true )';
		// 出力オプション指定文字の処理
		if( strpos( $ret_strings, 'nl2null' ) !== false ) {
			$ret_strings		= 'str_replace("\\n","",str_replace("\\r","",str_replace("\\r\\n","",'.$ret_strings.')))';
			$ret_strings		= str_replace('nl2null','',$ret_strings);
		}
		if( strpos( $ret_strings, 'escape-nl' ) !== false ) {
			$ret_strings		= 'str_replace("\\n","\\\n",str_replace("\\r","\\n",str_replace("\\r\\n","\\n",'.$ret_strings.')))';
			$ret_strings		= str_replace('escape-nl','',$ret_strings);
		}
		if( strpos( $ret_strings, 'escape-sq' ) !== false ) {
			$ret_strings		= 'str_replace("\'","\\\'",'.$ret_strings.')';
			$ret_strings		= str_replace('escape-sq','',$ret_strings);
		}
		if( strpos( $ret_strings, 'escape-dq' ) !== false ) {
			$ret_strings		= 'str_replace(\'"\',\'\\"\','.$ret_strings.')';
			$ret_strings		= str_replace('escape-dq','',$ret_strings);
		}
		if( strpos( $ret_strings, 'noescape' ) !== false ) {
			$ret_strings		= str_replace('noescape','',$ret_strings);
		} else {
			$ret_strings		= 'htmlspecialchars('.$ret_strings.')';
		}
		if( strpos( $ret_strings, 'nl2br' ) !== false ) {
			$ret_strings		= str_replace('nl2br','',$ret_strings);
			$ret_strings		= 'nl2br('.$ret_strings.')';
		}
		if( strpos( $ret_strings, 'urlencode' ) !== false ) {
			$ret_strings		= str_replace('urlencode','',$ret_strings);
			$ret_strings		= 'urlencode('.$ret_strings.')';
		}
		// ネイティブコード化
		$attribute_name_array	= array();
		$ret_strings			= $this->tagCode2NativeCode( $ret_strings, $attribute_name_array );
		$attribute_exist_confirm_array	= array();
		foreach( $attribute_name_array as $attribute_name ) {
			array_push( $attribute_exist_confirm_array, 'isset($GLOBALS[\''.$attribute_name.'\'])');
		}
		// 最後にecho
		$result_string		= '<?php if( ';
		$result_string		.= implode(' && ', $attribute_exist_confirm_array );
		$result_string		.= ' ) {';
		$result_string		.= 'echo '.$ret_strings.';';
		$result_string		.= '} ?>';
		return $result_string;
	}
	/**
	 * 文字列解析
	 * 旧バージョン互換::を利用できる
	 */
	function parseString(  $strings, $prefix=1  ) {

		// 出力オプションの確認
		$is_noescape	= false;
		$is_nl2br		= false;
		$is_nl2null		= false;
		$is_escape_nl	= false;
		$is_escape_sq	= false;
		$is_escape_dq	= false;
		$is_urlencode	= false;
		if( strpos( $strings, 'noescape' ) !== false ) {
			$is_noescape	= true;
			$strings		= str_replace('noescape','',$strings);
		}
		if( strpos( $strings, 'ln2br' ) !== false || strpos( $strings, 'nl2br' ) !== false ) {
			$is_nl2br		= true;
			$strings		= str_replace('ln2br','',$strings);
			$strings		= str_replace('nl2br','',$strings);
		}
		if( strpos( $strings, 'nl2null' ) !== false ) {
			$is_nl2null		= true;
			$strings		= str_replace('nl2null','',$strings);
		}
		if( strpos( $strings, 'escape-nl' ) !== false ) {
			$is_escape_nl	= true;
			$strings		= str_replace('escape-nl','',$strings);
		}
		if( strpos( $strings, 'escape-sq' ) !== false ) {
			$is_escape_sq	= true;
			$strings		= str_replace('escape-sq','',$strings);
		}
		if( strpos( $strings, 'escape-dq' ) !== false ) {
			$is_escape_dq	= true;
			$strings		= str_replace('escape-dq','',$strings);
		}
		if( strpos( $strings, 'urlencode' ) !== false ) {
			$is_urlencode	= true;
			$strings		= str_replace('urlencode','',$strings);
		}

		// 内部で利用されている変数を全て取り出す
		$var_name_array		= array();
		// 単一要素式
		$pos=0;
		for( $i=0; $i<strlen($strings); $i++ ) {
			$char	= substr($strings,$i,1);
			if( '+' == $char || '-' == $char
				|| '*' == $char || '/' == $char
				|| '(' == $char || ')' == $char
				|| '[' == $char || ']' == $char
				|| ',' == $char ) {
				// 演算子が登場したらひとつ前までを文字列切り出し
				$str	= substr( $strings, $pos, $i-$pos );
				$pos	= $i+1;
				if( '(' != $char && strlen( trim($str) ) > 0 ) {
					// 関数名でなければ追加
					$var_name_array[trim($str)]	= '';
				} else if( '(' == $char && strlen( trim($str) ) > 0 ) {
					// 関数名の場合
					if( preg_match('/\\:\\:/',$str) > 0 ) {
						// オブジェクトメソッドの場合はオブジェクト名のみ追加
						list( $obj_name, $method_name ) = explode('::',$str);
						$var_name_array[trim($obj_name)]	= '';
					}
				}
			}
		}
		// ループ最後のポジションから最後の要素を切り出し
		$str	= substr( $strings, $pos, $i-$pos );
		if( strlen( trim($str) ) > 0 ) {
			$var_name_array[trim($str)]	= '';
		}

		// 変数一時格納配列
		$temporary_valiable_getter_array	= array();
		
		// 変数の変換を確認
		$vcounter	= 0;
		foreach( $var_name_array as $key => $value ) {
			if( strlen($key) > 0 ) {
				if( is_numeric( $key ) ) {
					// 変数が数字なら変換対象としない
					$var_name_array[$key]	= $key;
				} else if( preg_match( '/^$[^0-9][.]*$/', $key ) > 0 ) {
					// 変数名なら変換対象としない
					$var_name_array[$key]	= $key;
				} else {
					// 変数が文字列の場合
					$tmp_name	= '$____tw__' . sprintf('%03d',$prefix) . sprintf('%03d',$vcounter);
					$var_name_array[$key]	= $tmp_name;
					if( preg_match('/^\\\'(.)*\\\'$/',$key) > 0 ) {
						// シングルクォートされているなら固定文字列
						$str	= $tmp_name. '='.$key.';'."\n";
						array_push( $temporary_valiable_getter_array, $str );
					} else {
						list( $vname, $vparam )		= explode('::',$key);
						// 一時編集取得文字列作成
						$str	= $tmp_name. '=$request_object->getAttribute(\''.$vname.'\');'."\n";
						$str	.= 'if( is_null('.$tmp_name.') ){'."\n";
						$str	.= "\t".$tmp_name. '=\''.$vname.'\';'."\n";
						$str	.= '} else if(\'array\'==gettype('.$tmp_name.')) {'."\n";
						if( is_numeric($vparam) ) {
							$str	.= "\t".$tmp_name. '='.$tmp_name.'['.$vparam.'];'."\n";
						} else if( strlen(trim($vparam)) > 0 ){
							$str	.= "\t".$tmp_name. '='.$tmp_name.'[\''.$vparam.'\'];'."\n";
						}
						$str	.= '} else if(\'object\'==gettype('.$tmp_name.')) {'."\n";
						if( is_numeric($vparam) ) {
							// オブジェクトの場合、数値は許可できません。(変数名、メソッド名は数値から始められない)
							$str	.= '$GLOBALS[\'request\']->addLocaledError(\'spider.tags.write.objectcanthasnumericmember\',SPIDER_LOG_LEVEL_FATAL);'."\n";
						} else if( strlen(trim($vparam)) > 0 ){
							$str	.= "\t".$tmp_name. '='.$tmp_name.'->'.$vparam.';'."\n";
						}
						$str	.= '}'."\n";
						array_push( $temporary_valiable_getter_array, $str );
					}
					$vcounter++;
				}
			}
		}
		// 変数配列を文字列の長い順にソート
		$order_array	= array();
		foreach( $var_name_array as $key => $value ) {
			if( !isset($order_array[strlen($key)]) || !is_array( $order_array[strlen($key)] ) ) {
				$order_array[strlen($key)]	= array();
			}
			array_push($order_array[strlen($key)],$key);
		}
		krsort($order_array);
		$new_var_name_array		= array();
		foreach( $order_array as $item_array ) {
			foreach( $item_array as $name ) {
				$new_var_name_array[$name]	= $var_name_array[$name];
			}
		}
		
		// 渡された文字列の置換
		foreach( $new_var_name_array as $key => $value ) {
			$strings	= str_replace( $key, $value, $strings );
			$strings	= str_replace( $value.'::', $value.'->', $strings );
		}
		
		// 変数取り出し文字列を冒頭に追加
		$retstring	= '<?php ' . implode("",$temporary_valiable_getter_array);
		$retstring	.= ' if(is_object('.$strings.')||is_array('.$strings.')){ ';
			$retstring	.= 'echo ';
			if( $is_urlencode ) { $retstring	.= 'urlencode('; }
			if( $is_nl2br ) { $retstring		.= 'nl2br('; }
			if( !$is_noescape ) { $retstring	.= 'htmlspecialchars('; }
			if( $is_escape_sq ) { $retstring	.= 'str_replace("\'","\\\'",'; }
			if( $is_escape_dq ) { $retstring	.= 'str_replace(\'"\',\'\\"\','; }
			if( $is_escape_nl ) { $retstring	.= 'str_replace("\\n","\\\n",str_replace("\\r","\\n",str_replace("\\r\\n","\\n",'; }
			if( $is_nl2null ) { $retstring	.= 'str_replace("\\n","",str_replace("\\r","",str_replace("\\r\\n","",'; }
			$retstring		.= 'print_r( '.$strings.', true )';
			if( $is_nl2null ) { $retstring	.= ')'; }
			if( $is_escape_nl ) { $retstring	.= ')'; }
			if( $is_escape_dq ) { $retstring	.= ')'; }
			if( $is_escape_sq ) { $retstring	.= ')'; }
			if( !$is_noescape ) { $retstring	.= ')'; }
			if( $is_nl2br ) { $retstring	.= ')'; }
			if( $is_urlencode ) { $retstring	.= ')'; }
			$retstring	.= ';';
		$retstring	.= ' }else{ ';
			$retstring	.= 'echo ';
			if( $is_urlencode ) { $retstring	.= 'urlencode('; }
			if( $is_nl2br ) { $retstring		.= 'nl2br('; }
			if( !$is_noescape ) { $retstring	.= 'htmlspecialchars('; }
			if( $is_escape_sq ) { $retstring	.= 'str_replace("\'","\\\'",'; }
			if( $is_escape_dq ) { $retstring	.= 'str_replace(\'"\',\'\\"\','; }
			if( $is_escape_nl ) { $retstring	.= 'str_replace("\\n","\\\n",str_replace("\\r","\\n",str_replace("\\r\\n","\\n",'; }
			if( $is_nl2null ) { $retstring	.= 'str_replace("\\n","",str_replace("\\r","",str_replace("\\r\\n","",'; }
			$retstring		.= $strings;
			if( $is_nl2null ) { $retstring	.= ')'; }
			if( $is_escape_nl ) { $retstring	.= ')'; }
			if( $is_escape_dq ) { $retstring	.= ')'; }
			if( $is_escape_sq ) { $retstring	.= ')'; }
			if( !$is_noescape ) { $retstring	.= ')'; }
			if( $is_nl2br ) { $retstring	.= ')'; }
			if( $is_urlencode ) { $retstring	.= ')'; }
			$retstring	.= ';';
		$retstring	.= ' } ?>';
		
		return $retstring;

	}
}
?>