tpl_path = $tpl_path; // 디버그를 위한 컴파일 시작 시간 저장 if(__DEBUG__) $start = getMicroTime(); // 변수 체크 if(substr($tpl_path,-1)!='/') $tpl_path .= '/'; if(substr($tpl_filename,-5)!='.html') $tpl_filename .= '.html'; // tpl_file 변수 생성 $tpl_file = $tpl_path.$tpl_filename; // tpl_file이 비어 있거나 해당 파일이 없으면 return if(!$tpl_file || !file_exists($tpl_file)) return; $this->tpl_file = $tpl_file; // compiled된(or 될) 파일이름을 구함 $compiled_tpl_file = $this->_getCompiledFileName($tpl_file); // 일단 컴파일 $buff = $this->_compile($tpl_file, $compiled_tpl_file); if(__DEBUG__) { $template_elapsed = getMicroTime() - $start; $GLOBALS['__template_elapsed__'] += $template_elapsed; } // Context와 compiled_tpl_file로 컨텐츠 생성 $output = $this->_fetch($compiled_tpl_file, $buff); // 컴파일된 파일을 실행 return $output; } /** * @brief tpl_file이 컴파일이 되어 있는 것이 있는지 체크 **/ function _compile($tpl_file, $compiled_tpl_file) { if(!file_exists($compiled_tpl_file)) return $this->_compileTplFile($tpl_file, $compiled_tpl_file); $source_ftime = filectime($tpl_file); $target_ftime = filectime($compiled_tpl_file); if($source_ftime>$target_ftime) return $this->_compileTplFile($tpl_file, $compiled_tpl_file); } /** * @brief tpl_file을 compile **/ function _compileTplFile($tpl_file, $compiled_tpl_file) { // tpl 파일을 읽음 $buff = FileHandler::readFile($tpl_file); if(!$buff) return; // 변수를 변경 $buff = preg_replace_callback('/\{[^@^ ]([^\}]+)\}/i', array($this, '_compileVarToContext'), $buff); // 이미지 태그 img의 src의 값이 ./ 로 시작하면 {$tpl_path}로 변경 $buff = preg_replace_callback('!src=[\'"]{1}(.*?)[\'"]{1}!is', array($this, '_compileImgPath'), $buff); // 결과를 출력하지 않는 구문 변경 $buff = preg_replace_callback('/\{\@([^\}]+)\}/i', array($this, '_compileVarToSilenceExecute'), $buff); // 의 변경 $buff = preg_replace_callback('!<\!--@(.*?)-->!is', array($this, '_compileFuncToCode'), $buff); // include 변경 $buff = preg_replace_callback('!<\!--#include\(([^\)]*?)\)-->!is', array($this, '_compileIncludeToCode'), $buff); // import xml filter/ css/ js $buff = preg_replace_callback('!<\!--%import\(\"([^\"]*?)\"\)-->!is', array($this, '_compileImportCode'), $buff); // plugin 코드 변경 $buff = preg_replace_callback('!
!is', array($this, '_compilePluginCode'), $buff); // 파일에 쓰기 전에 직접 호출되는 것을 방지 $buff = sprintf('%s%s%s','',"\n",$buff); // 컴파일된 코드를 파일에 저장 FileHandler::writeFile($compiled_tpl_file, $buff); return $buff; } /** * @brief {$와 } 안의 $... 변수를 Context::get(...) 으로 변경 **/ function _compileVarToContext($matches) { $str = trim(substr($matches[0],1,strlen($matches[0])-2)); return ']+)/i','$__Context->\\1', $str).');?>'; } /** * @brief {$와 } 안의 $... 변수를 Context::get(...) 으로 변경 **/ function _compileImgPath($matches) { $str1 = $matches[0]; $str2 = $matches[1]; $path = $str2; if(!eregi("^\.\/(images|img)",$path)) return $str1; $path = 'tpl_path?>'.substr($path,2); return str_replace($str2, $path, $str1); } /** * @brief {@와 } 안의 @... 함수를 print func(..)로 변경 **/ function _compileVarToSilenceExecute($matches) { return ']+)/i','$__Context->\\1', trim($matches[1])).';?>'; } /** * @brief 사이의 구문을 php코드로 변경 **/ function _compileFuncToCode($matches) { $code = trim($matches[1]); if(!$code) return; switch(strtolower($code)) { case 'else' : $output = '}else{'; break; case 'end' : case 'endif' : case 'endfor' : case 'endforeach' : $output = '}'; break; default : if(substr($code,0,4)=='else') { $code = '}'.$code; } elseif(substr($code,0,7)=='foreach') { $tmp_str = substr($code,8); $tmp_arr = explode(' ', $tmp_str); $var_name = $tmp_arr[0]; if(substr($var_name,0,1)=='$') $prefix = sprintf('if(count($__Context->%s)) ', substr($var_name,1)); else $prefix = sprintf('if(count(%s)) ', $var_name); } $output = preg_replace('/\$([a-zA-Z0-9\_\-]+)/i','$__Context->\\1', $code).'{'; break; } return sprintf('', $prefix, $output); } /** * @brief 를 변환 **/ function _compileIncludeToCode($matches) { // include하려는 대상문자열에 변수가 있으면 변수 처리 $arg = str_replace(array('"','\''), '', $matches[1]); if(!$arg) return; $tmp_arr = explode("/", $arg); for($i=0;$itpl_file), $arg); // 2단계로 root로부터 경로를 체크 if(!file_exists($filename)) $filename = './'.$arg; if(!file_exists($filename)) return; // path, filename으로 분리 $tmp_arr = explode('/', $filename); $filename = array_pop($tmp_arr); $path = implode('/', $tmp_arr).'/'; // include 시도 $output = sprintf( 'compile(\'%s\',\'%s\');%s'. '?>%s', "\n", "\n", $path, $filename, "\n", "\n" ); return $output; } /** * @brief 의 확장자를 봐서 js filter/ css/ js 파일을 include하도록 수정 **/ function _compileImportCode($matches) { // 현재 tpl 파일의 위치를 구해서 $base_path에 저장하여 적용하려는 xml file을 찾음 $base_path = dirname($this->tpl_file).'/'; $given_file = trim($matches[1]); if(!$given_file) return; $filename = sprintf("%s%s",$base_path, $given_file); // path와 파일이름을 구함 $tmp_arr = explode("/",$filename); $filename = array_pop($tmp_arr); $base_path = implode("/",$tmp_arr)."/"; // 확장자를 구함 $tmp_arr = explode(".",$filename); $ext = strtolower(array_pop($tmp_arr)); // 확장자에 따라서 파일 import를 별도로 switch($ext) { // xml js filter case 'xml' : // XmlJSFilter 클래스의 객체 생성후 js파일을 만들고 Context::addJsFile처리 $output = sprintf( 'compile();%s'. '?>%s', "\n", "\n", $base_path, $filename, "\n", "\n", "\n" ); break; // css file case 'css' : $output = sprintf('', $base_path, $filename); break; // js file case 'js' : $output = sprintf('', $base_path, $filename); break; } return $output; } /** * @brief 플러그인 코드를 실제 php코드로 변경 **/ function _compilePluginCode($matches) { $oXmlParser = new XmlParser(); $xml_doc = $oXmlParser->parse($matches[0]); $vars = $xml_doc->div->attrs; if(!$vars->plugin) return ""; // 플러그인의 이름을 구함 $plugin = $vars->plugin; unset($vars->plugin); // className, style attribute를 구해 놓음 $className = $vars->class; $style = $vars->style; unset($vars->class); unset($vars->style); // 플러그인의 변수들을 세팅 $vars_count = get_object_vars($vars); if($vars_count) { foreach($vars as $key => $val) { $key = str_replace('"','\"', $key); $val = str_replace('"','\"', $val); $args_list[] = sprintf('"%s"=>"%s"', $key, $val); } $args = sprintf('array(%s)', implode(',',$args_list)); } if(!$args) $args = null; // 플러그인 실행코드를 삽입 return sprintf('
', $className?'class="'.$className.'" ':'', $style?'style="'.$style.'" ':'',$plugin, $args); } /** * @brief $tpl_file로 compiled_tpl_file이름을 return **/ function _getCompiledFileName($tpl_file) { return sprintf('%s%s.compiled.php',$this->compiled_path, md5($tpl_file)); } /** * @brief ob_* 함수를 이용하여 fetch... **/ function _fetch($compiled_tpl_file, $buff = NULL) { $__Context = &$GLOBALS['__Context__']; if($_SESSION['is_logged']) $__Context->logged_info = $_SESSION['logged_info']; // ob_start를 시킨후 컴파일된 tpl파일을 include하고 결과를 return ob_start(); // tpl파일을 compile하지 못할 경우 $buff로 넘어온 값을 eval시킴 (미설치시에나..) if($buff) { $eval_str = "?>".$buff; eval($eval_str); } else { @include $compiled_tpl_file; } $output = ob_get_contents(); ob_end_clean(); return $output; } } ?>