포럼

게시판 EX 에서도 업데이트가 아직 없는 가운데..

호환성이 어디에 문제가 있는지 잘 모르겠습니다.

 

다만 확실하건, 1.4.5.10 버전의 TemplateHandler.class.php를 1.5.0.8 버전의 TemplateHandler.class.php로 교체하면,

게시판 EX가 표시됩니다.

 

 1.4.5.10 버전

 

 

<?php
    /**
     * @class TemplateHandler
     * @author NHN (developers@xpressengine.com)
     * @brief template compiler
     * @version 0.1
     * @remarks It compiles template file by using regular expression into php
     *          code, and XE caches compiled code for further uses
     **/

    class TemplateHandler extends Handler {

        var $compiled_path = './files/cache/template_compiled/'; ///< path of compiled caches files

        var $path = null; ///< target directory
        var $filename = null; ///< target filename
        var $file = null; ///< target file (fullpath)
  var $xe_path = null;  ///< XpressEngine base path
  var $web_path = null; ///< tpl file web path
  var $compiled_file = null; ///< tpl file web path
  var $buff = null; ///< tpl file web path

  var $handler_mtime = 0;

        /**
         * @brief returns TemplateHandler's singleton object
         * @return TemplateHandler instance
         **/
        function &getInstance() {
            if(__DEBUG__==3 ) {
                if(!isset($GLOBALS['__TemplateHandlerCalled__'])) $GLOBALS['__TemplateHandlerCalled__']=1;
                else $GLOBALS['__TemplateHandlerCalled__']++;
            }

            if(!$GLOBALS['__TemplateHandler__']) {
                $GLOBALS['__TemplateHandler__'] = new TemplateHandler();
            }
            return $GLOBALS['__TemplateHandler__'];
        }

  /**
   * @brief set variables for template compile
   **/
  function init($tpl_path, $tpl_filename, $tpl_file) {
            // verify arguments
            if(substr($tpl_path,-1)!='/') $tpl_path .= '/';
   if(!file_exists($tpl_path.$tpl_filename)&&file_exists($tpl_path.$tpl_filename.'.html')) $tpl_filename .= '.html';

            // create tpl_file variable
            if(!$tpl_file) $tpl_file = $tpl_path.$tpl_filename;

   // set template file infos.
   $info = pathinfo($tpl_file);
   //$this->path = preg_replace('/^\.\//','',$info['dirname']).'/';
   $this->path = $tpl_path;
   $this->filename = $tpl_filename;
   $this->file = $tpl_file;

   $this->xe_path = preg_replace('/([^\.^\/]+)\.php$/i'+ ','',$_SERVER['SCRIPT_NAME']);
   $this->web_path = $this->xe_path.str_replace(_XE_PATH_,'',$this->path);

   // get compiled file name
   $this->compiled_file = sprintf('%s%s.compiled.php',$this->compiled_path, md5($this->file));

   // compare various file's modified time for check changed
   $this->handler_mtime = filemtime(_XE_PATH_.'classes/template/TemplateHandler.class.php');

   $this->buff = null;
  }

        /**
         * @brief compiles specified tpl file and execution result in Context into resultant content
         * @param[in] $tpl_path path of the directory containing target template file
         * @param[in] $tpl_filename target template file's name
         * @param[in] $tpl_file if specified use it as template file's full path
         * @return Returns compiled result in case of success, NULL otherwise
         */
        function compile($tpl_path, $tpl_filename, $tpl_file = '') {
            // store the starting time for debug information
            if(__DEBUG__==3 ) $start = getMicroTime();

   // initiation
   $this->init($tpl_path, $tpl_filename, $tpl_file);

            // if target file does not exist exit
            if(!$this->file || !file_exists($this->file)) return sprintf('Err : "%s" template file does not exists.', $this->file);

            $source_template_mtime = filemtime($this->file);
   $latest_mtime = $source_template_mtime>$this->handler_mtime?$source_template_mtime:$this->handler_mtime;

   // cache controll
   $oCacheHandler = &CacheHandler::getInstance('template');

   // get cached buff
   if($oCacheHandler->isSupport()){
    $cache_key = 'template:'.$this->file;
    $this->buff = $oCacheHandler->get($cache_key, $latest_mtime);
   } else {
    if(file_exists($this->compiled_file) && filemtime($this->compiled_file)>$latest_mtime) {
     $this->buff = FileHandler::readFile($this->compiled_file);
    }
   }

   if(!$this->buff) {
    $this->parse();
    if($oCacheHandler->isSupport()) $oCacheHandler->put($cache_key, $this->buff);
    else FileHandler::writeFile($this->compiled_file, $this->buff);
   }

   $output = $this->_fetch();

   // store the ending time for debug information
            if(__DEBUG__==3 ) $GLOBALS['__template_elapsed__'] += getMicroTime() - $start;

            return $output;
        }

        /**
         * @brief compile specified file and immediately return
         * @param[in] $tpl_path path of the directory containing target template file
         * @param[in] $tpl_filename target template file's name
         * @return Returns compiled content in case of success or NULL in case of failure
         **/
        function compileDirect($tpl_path, $tpl_filename) {
   $this->init($tpl_path, $tpl_filename, null);

            // if target file does not exist exit
            if(!$this->file || !file_exists($this->file)) {
    Context::close();
    printf('"%s" template file is not exists.', $this->file);
    exit();
   }

            $this->parse();
   return $this->buff;
        }

        /**
         * @brief compile a template file specified in $tpl_file and
         * @pre files specified by $tpl_file exists.
         * @param[in] $tpl_file path of tpl file
         * @param[in] $compiled_tpl_file if specified, write compiled result into the file
         * @return compiled result in case of success or NULL in case of error
         **/
        function parse() {
   if(!file_exists($this->file)) return;

            // read tpl file
            $buff = FileHandler::readFile($this->file);

   // replace value of src in img/input/script tag
   $buff = preg_replace_callback('/<(img|input|script)([^>]*)src="([^"]*?)"/is', array($this, '_replacePath'), $buff);

   // loop 템플릿 문법을 변환
   $buff = $this->_replaceLoop($buff);

   // cond 템플릿 문법을 변환
   $buff = $this->_replaceCond($buff);

   // |cond 템플릿 문법을 변환
   $buff = preg_replace_callback("/<\/?(\w+)((\s+\w+(\s*=\s*(?:\".*?\"|'.*?'|[^'\">\s]+))?)+\s*|\s*)\/?>/i", array($this, '+ '_replacePipeCond'), $buff);

   // include 태그의 변환
   $buff = preg_replace_callback('!<include ([^>]+)>!is', array($this, '_replaceInclude'), $buff);

   // unload/ load 태그의 변환
   $buff = preg_replace_callback('!<(unload|load) ([^>]+)>!is', array($this, '_replaceLoad'), $buff);

   // 가상 태그인 block의 변환
   $buff = preg_replace('/<block([ ]*)>|<\/block>/is','',$buff);

            // replace include <!--#include($filename)-->
            $buff = preg_replace_callback('!<\!--#include\(([^\)]*?)\)-->!is', array($this, '_compileIncludeToCode'), $buff);

            // replace <!--@, -->
            $buff = preg_replace_callback('!<\!--@(.*?)-->!is', array($this, '_compileFuncToCode'), $buff);

            // remove comments <!--// ~ -->
            $buff = preg_replace('!(\n?)( *?)<\!--//(.*?)-->!is', '', $buff);

            // import xml filter/ css/ js/ files <!--%import("filename"[,optimized=true|false][,media="media"][,targetie="lt IE 6|IE 7|gte IE 8|..."])--> (media is applied to only css)
            $buff = preg_replace_callback('!<\!--%import\(\"([^\"]*?)\"(,optimized\=(true|false))?(,media\=\"([^\"]*)\")?(,targetie=\"([^\"]*)\")?(,index=\"([^\"]*)\")?(,type=\"([^\"]*)\")?\)-->!is', array($this, '_compileImportCode'+ '), $buff);

            // unload css/ js <!--%unload("filename"[,optimized=true|false][,media="media"][,targetie="lt IE 6|IE 7|gte IE 8|..."])--> (media is applied to only css)
            $buff = preg_replace_callback('+ '!<\!--%unload\(\"([^\"]*?)\"(,optimized\=(true|false))?(,media\=\"([^\"]*)\")?(,targetie=\"([^\"]*)\")?\)-->!is', array($this, '_compileUnloadCode'), $buff);

            // javascript plugin import
            $buff = preg_replace_callback('!<\!--%load_js_plugin\(\"([^\"]*?)\"\)-->!is', array($this, '_compileLoadJavascriptPlugin'), $buff);

            // replace variables
            $buff = preg_replace_callback('/\{[^@^ ]([^\{\}\n]+)\}/i', array($this, '_compileVarToContext'), $buff);

   // PHP 변수형의 변환 ($문자등을 공유 context로 변환)
   $buff = $this->_replaceVarInPHP($buff);

            // replace parts not displaying results
            $buff = preg_replace_callback('/\{\@([^\{\}]+)\}/i', array($this, '_compileVarToSilenceExecute'), $buff);

            // prevent from calling directly before writing into file
            $this->buff = '<?php if(!defined("__ZBXE__")) exit();?>'.$buff;
        }

        /**
         * @brief fetch using ob_* function
         * @param[in] $compiled_tpl_file path of compiled template file
         * @param[in] $buff if buff is not null, eval it instead of including compiled template file
         * @param[in] $tpl_path set context's tpl path
         * @return result string
         **/
        function _fetch() {
   if(!$this->buff) return;

            $__Context = &$GLOBALS['__Context__'];
            $__Context->tpl_path = $this->path;

            if($_SESSION['is_logged']) $__Context->logged_info = $_SESSION['logged_info'];

            ob_start();
   $eval_str = "?>".$this->buff;
   eval($eval_str);
            return ob_get_clean();
        }

        /**
         * @brief change image path
         * @pre $matches is an array containg three elements
         * @param[in] $matches match
         * @return changed result
         **/
  function _replacePath($matches)
  {
   preg_match_all('/src="([^"]*?)"/is', $matches[0], $m);
   for($i=0,$c=count($m[0]);$i<$c;$i++) {
    $path = trim($m[1][$i]);
    if(substr($path,0,1)=='/' || substr($path,0,1)=='{' || strpos($path,'://')!==false) continue;
    if(substr($path,0,2)=='./') $path = substr($path,2);
    $target = $this->web_path.$path;
    while(strpos($target,'/../')!==false)
    {
     $target = preg_replace('/\/([^\/]+)\/\.\.\//','/',$target);
    }
    $target = str_replace('/./','/',$target);
    $matches[0] = str_replace($m[0][$i], 'src="'.$target.'"'+ ', $matches[0]);
   }
   return $matches[0];
  }

  /**
   * @brief loop 문법의 변환
   **/
  function _replaceLoop($buff)
  {
   while(false !== $pos = strpos($buff, ' loop="'))
   {
    $pre = substr($buff,0,$pos);
    $next = substr($buff,$pos);

    $pre_pos = strrpos($pre, '<');

    preg_match('/^ loop="([^"]+)"/i',$next,$m);
    $orgTag = $tag = substr($next,0,strlen($m[0]));
    $next = substr($next,strlen($m[0]));
    $next_pos = strpos($next, '<');

    $tag = substr($pre, $pre_pos). $tag. substr($next, 0, $next_pos);
    // search end tag
    /* tag as '<br cond="condition"/>blahblah' to be '<br cond="condition"/>' */
    preg_match('/\/>(\w+)/',$tag, $mm);
    if ($mm[1]){
     $next_pos = strpos($next, $mm[1]);
     $tag = substr($pre, $pre_pos). $orgTag. substr($next, 0, $next_pos);
    }
    $pre = substr($pre, 0, $pre_pos);
    $next  = substr($next, $next_pos);

    $tag_name = trim(substr($tag,1,strpos($tag,' ')));
    $tag_head = $tag_tail = ''+ ';

    if(!preg_match('/ loop="([^"]+)"/is',$tag)) {
     print "<strong>Invalid XpressEngine Template Syntax</strong><br/>";
     print "File : ".$this->file."<br/>";
     print "Code : ".htmlspecialchars($tag);
     exit();
    }

    preg_match_all('/ loop="([^"]+)"/is',$tag,$m);
    $tag = preg_replace('/ loop="([^"]+)"/is','', $tag);

    for($i=0,$c=count($m[0]);$i<$c;$i++)
    {
     $loop = $m[1][$i];
     if(false!== $fpos = strpos($loop,'=>'))
     {
      $target = trim(substr($loop,0,$fpos));
      if(substr($target, 0, 1) == '$') $target = sprintf('+ '$__Context->%s ', substr($target, 1));

      $vars = trim(substr($loop,$fpos+2));
      if(false===strpos($vars,','))
      {
       if(substr($vars, 0, 1) == '$') $vars = sprintf('$__Context->%s ', substr($vars, 1));

       $tag_head .= '<?php if(count('.$target.')) { foreach('+ '.$target.' as '.$vars.') { ?>';
       $tag_tail .= '<?php } } ?>';
      }
      else
      {
       $t = explode(',',$vars);
       foreach($t as $key => $val){
        if(substr(trim($val), 0, 1) == '$') $val = sprintf('$__Context->%s ', substr(trim($val), 1));
        $t[$key] = trim($val);
       }
       $tag_head .= '<?php if(count('.$target.')) { foreach('.$target.' as '.trim($t[0]).' => '.trim($t[1]).') { ?>';
       $tag_tail .= '<?php } } ?>';
      }
     }
     elseif(false!==strpos($loop,';'))
     {
      $loop = preg_replace('/\$(\w+)/', '$__Context->$1', $loop);
      $tag_head .= '<?php for('.$loop.'){ ?>';
      $tag_tail .= '<?php } ?>';
     }
     else
     {
      $t = explode('=',$loop);
      if(count($t)==2)
      {
       $tag_head .= '<?php while('.trim($t[0]).' = '.trim($t[1]).') { ?>'+ ';
       $tag_tail .= '<?php } ?>';
      }
     }
    }

    if(substr(trim($tag),-2)!='/>')
    {
     while(false !== $close_pos = strpos($next, '</'.$tag_name))
     {
      $tmp_buff = substr($next, 0, $close_pos+strlen('</'.$tag_name.'>'));
      $tag .= $tmp_buff;
      $next = substr($next, strlen($tmp_buff));
      if(substr_count($tag, '<'.$tag_name) == substr_count($tag,'</'.$tag_name)) break;
     }
    }

    $buff = $pre.$tag_head.$tag.$tag_tail.$next;
   }
   return $buff;
  }

  /**
   * @brief pipe cond, |cond= 의 변환
   **/
  function _replacePipeCond($matches)
  {
   if(strpos($matches[0],'|cond')!==false) {
    while(strpos($matches[0],'|cond="')!==false) {
     if(preg_match('/ (\w+)=\"([^\"]+)\"\|cond=\"([^\"]+)\"/is', $matches[0], $m)){
      $m[3] = preg_replace('/^\$(\w+)/', '$__Context->$1', $m[3]);
      $matches[0] = str_replace($m[0], sprintf('<?php if(%s) {?> %s="%s"<?php }?>', $m[3], $m[1], $m[2]), $matches[0]);
     }
    }
   }

   return $matches[0];
  }

  /**
   * @brief cond 문법의 변환
   **/
  function _replaceCond($buff)
  {
   while(false !== ($pos = strpos($buff, ' cond="')))
   {
    $pre = substr($buff,0,$pos);
    $next = substr($buff,$pos);

    $pre_pos = strrpos($pre, '<');

    preg_match('/<(\/|[a-z])/i',$next,$m);
    if(!$m[0]) return $buff;
    $next_pos = strpos($next, $m[0]);

    $tag = substr($pre, $pre_pos). substr($next, 0, $next_pos);

    // search end tag
    /* tag as '+ '<br cond="condition"/>blahblah' to be '<br cond="condition"/>' */
    preg_match('/\/>(\w+)/',$tag, $mm);
    if ($mm[1]){
     $next_pos = strpos($next, $mm[1]);
     $tag = substr($pre, $pre_pos). substr($next, 0, $next_pos);
    }
    $pre = substr($pre, 0, $pre_pos);
    $next  = substr($next, $next_pos);
    $tag_name = trim(substr($tag,1,strpos($tag,' ')));
    $tag_head = $tag_tail = '';

    if(preg_match_all('/ cond=\"([^\"]+)"/is',$tag,$m))
    {
     for($i=0,$c=count($m[0]);$i<$c;$i++)
     {
      $m[1][$i] = preg_replace('/^\$(\w+)/', '$__Context->$1', $m[1][$i]);
      $tag_head .= '<?php if('.$m[1][$i].') { ?>';
      $tag_tail .= '<?php } ?>';
     }
    }

    if(!preg_match('/ cond="([^"]+)"/is',$tag)) {
     print "<strong>Invalid XpressEngine Template Syntax</strong><br/>";
     print "File : ".$this->file."<br/>";
     print "Code : ".htmlspecialchars($tag);
     exit();
    }

    $tag = preg_replace('/ cond="([^"]+)"/is','', $tag);
    if(substr(trim($tag),-2)=='/>')
    {
     $buff = $pre.$tag_head.$tag.$tag_tail.$next;
    }
    else
    {
     while(false !== $close_pos = strpos($next, '</'.$tag_name))
     {
      $tmp_buff = substr($next, 0, $close_pos+strlen('</'.$tag_name.'>'));
      $tag .= $tmp_buff;
      $next = substr($next, strlen($tmp_buff));

      if(substr_count($tag, '<'.$tag_name) == substr_count($tag,'</'.$tag_name)) break;
     }
     $buff = $pre.$tag_head.$tag.$tag_tail.$next;
    }
   }
   
   return $buff;
  }

  /**
   * @brief 다른 template파일을 include하는 include tag의 변환
   **/
  function _replaceInclude($matches)
  {
   if(!preg_match('/target=\"([^\"]+)\"/is',$matches[0], $m)) {
    print '"target" attribute missing in "'.htmlspecialchars($matches[0]);
    exit();
   }

   $target = $m[1];
            if(substr($target,0,1)=='/')
   {
    $target = substr($target,1);
    $pos = strrpos('/',$target);
    $filename = substr($target,$pos+1);
    $path = substr($target,0,$pos);
   } else {
    if(substr($target,0,2)=='./') $target = substr($target,2);
    $pos = strrpos('/',$target);
    $filename = substr($target,$pos);
    $path = $this->path.substr($target,0,$pos);
   }

   return sprintf(
                '<?php%s'.
                '$oTemplate = &TemplateHandler::getInstance();%s'.
                'print $oTemplate->compile(\'%s\',\'%s\');%s'.
                '?>%s',
                "\n",
                "\n",
                $path, $filename, "\n",
                "\n"
            );
  }

  /**
   * @brief load 태그의 변환
   **/
  function _replaceLoad($matches) {
   $output = $matches[0];
   if(!preg_match_all('/ ([^=]+)=\"([^\"]+)\"/is',$matches[0], $m)) return $matches[0];

   $type = $matches[1];
   for($i=0,$c=count($m[1]);$i<$c;$i++)
   {
    if(!trim($m[1][$i])) continue;
    $attrs[trim($m[1][$i])] = trim($m[2][$i]);
   }

   if(!$attrs['target']) return $matches[0];

   $web_path = $this->web_path;
   $base_path = $this->path;

   $target = $attrs['target'];
            if(!preg_match('/^(http|https)/i',$target))
            {
                if(substr($target,0,2)=='./') $target = substr($target,2);
                if(substr($target,0,1)!='/') $target = $web_path.$target;
            }

   if(!$attrs['index']) $attrs['index'] = 'null';
   if($attrs['type']!='body') $attrs['type'] = 'head';

            // if target ends with lang, load language pack
            if(substr($target, -4)=='lang') {
                if(substr($target,0,2)=='./') $target = substr($target, 2);
                $lang_dir = $base_path.$target;
                if(is_dir($lang_dir)) $output = sprintf('<?php Context::loadLang("%s"); ?>', $lang_dir);

   // otherwise try to load xml, css, js file
   } else {
    if(substr($target,0,1)!='/' && !preg_match('/^(http|https)/i',$target)) $source_filename = $base_path.$target;
    else $source_filename = $target;

    if(!preg_match('/^(http|https)/i',$source_filename))
     $source_filename = str_replace(array('/./','//'),'/',$source_filename);

    // get filename and path
    $tmp_arr = explode("/",$source_filename);
    $filename = array_pop($tmp_arr);

    //$base_path = implode("/",$tmp_arr)."/";

    // get the ext
    $tmp_arr = explode(".",$filename);
    $ext = strtolower(array_pop($tmp_arr));

    // according to ext., import the file
    switch($ext) {
     // xml js filter
     case 'xml' :
       if(preg_match('/^(http|https)/i',$source_filename)) return;
       // create an instance of XmlJSFilter class, then create js and handle Context::addJsFile
       $output = sprintf(
        '<?php%s'.
        'require_once("./classes/xml/XmlJsFilter.class.php");%s'.
        '$oXmlFilter = new XmlJSFilter("%s","%s");%s'.
        '$oXmlFilter->compile();%s'.
        '?>%s',
        "\n",
        "\n",
        dirname($base_path . $attrs['target']).'/',
        $filename,
        "\n",
        "\n",
        "\n"
        );
      break;
     // css file
     case 'css' :
       if($type == 'unload') {
        $output = '<?php Context::unloadCSSFile("'.$source_filename.'"); ?>';
       } else {
        $meta_file = $source_filename;
        $output = '<?php Context::addCSSFile("'.$source_filename.'",false,"'.$attrs['media'].'","'.$attrs['targetie'].'",'.$attrs['index'].'); ?>';
       }
      break;
     // js file
     case 'js' :
       if($type == 'unload') {
        $output = '<?php Context::unloadJsFile("'.$source_filename.'"); ?>';
       } else {
        $meta_file = $source_filename;
        $output = '<?php Context::addJsFile("'.$source_filename.'",false,"'.$attrs['targetie'].'",'.$attrs['index'].',"'.$attrs['type'].'"); ?>';
       }
      break;
    }
   }

   if($meta_file) $output = '<!--#Meta:'.$meta_file.'-->'.$output;
   return $output;
  }

  /**
   * @brief $문자 의 PHP 변수 변환
   **/
  function _replaceVarInPHP($buff) {
   $head = $tail = '';
   while(false !== $pos = strpos($buff, '<?php'))
   {
    $head .= substr($buff,0,$pos);
    $buff = substr($buff,$pos);
    $pos = strpos($buff,'?>');
    $body = substr($buff,0,$pos+2);
    $head .= preg_replace_callback('/(.?)\$(\w+[a-z0-9\_\-\[\]\'\"]+)/is',array($this, '_replaceVarString'), $body);

    $buff = substr($buff,$pos+2);
   }
   return $head.$buff;
  }


  /**
   * @brief php5의 class::$변수명의 경우 context를 사용하지 않아야 하기에 함수로 대체
   **/
  function _replaceVarString($matches)
  {
   if($matches[1]==':') return $matches[0];
   if(substr($matches[2],0,1)=='_') return $matches[0];
   return $matches[1].'$__Context->'.$matches[2];
  }

        /**
         * @brief replace <!--#include $path--> with php code
         * @param[in] $matches match
         * @return replaced result
         **/
        function _compileIncludeToCode($matches) {
            // if target string to include contains variables handle them
            $arg = str_replace(array('"','\''), '', $matches[1]);
            if(!$arg) return;

            $tmp_arr = explode("/", $arg);
            for($i=0;$i<count($tmp_arr);$i++) {
                $item1 = trim($tmp_arr[$i]);
                if($item1=='.'||substr($item1,-5)=='.html') continue;

                $tmp2_arr = explode(".",$item1);
                for($j=0;$j<count($tmp2_arr);$j++) {
                    $item = trim($tmp2_arr[$j]);
                    if(substr($item,0,1)=='$') $item = Context::get(substr($item,1));
                    $tmp2_arr[$j] = $item;
                }
                $tmp_arr[$i] = implode(".",$tmp2_arr);
            }
            $arg = implode("/",$tmp_arr);
            if(substr($arg,0,2)=='./') $arg = substr($arg,2);

            // step1: check files in the template directory
            //$source_filename = sprintf("%s/%s", dirname($this->file), $arg);
   $path = substr($this->path,-1)=='/'?substr($this->path,0,-1):$this->path;
            $source_filename = sprintf("%s/%s", $path, $arg);

            // step2: check path from root
            if(!file_exists($source_filename)) $source_filename = './'.$arg;
            if(!file_exists($source_filename)) return;

            // split into path and filename
            $tmp_arr = explode('/', $source_filename);
            $filename = array_pop($tmp_arr);
            $path = implode('/', $tmp_arr).'/';

            // try to include
            $output = sprintf(
                '<?php%s'.
                '$oTemplate = &TemplateHandler::getInstance();%s'.
                'print $oTemplate->compile(\'%s\',\'%s\');%s'.
                '?>%s',
                "\n",
                "\n",
                $path, $filename, "\n",
                "\n"
            );

            return $output;
        }

        /**
         * @brief replace $... variables in { } with Context::get(...)
         * @param[in] $matches match
         * @return replaced result in case of success or NULL in case of error
         **/
        function _compileVarToContext($matches) {
            $str = trim(substr($matches[0],1,strlen($matches[0])-2));
            if(!$str) return $matches[0];
            if(!in_array(substr($str,0,1),array('(','$','\'','"'))) {
                if(preg_match('/^([^\( \.]+)(\(| \.)/i',$str,$m)) {
                    $func = trim($m[1]);
                    if(strpos($func,'::')===false) {
                        if(!function_exists($func)) {
                            return $matches[0];
                        }
                    } else {
                        list($class, $method) = explode('::',$func);
                        // FIXME regardless of whether class/func name is case-sensitive, it is safe
                        // to assume names are case sensitive. We don't have compare twice.
                        if(!class_exists($class)  || !in_array($method, get_class_methods($class))) {
                            // In some environment, the name of classes and methods may be case-sensitive
                            list($class, $method) = explode('::',strtolower($func));
                            if(!class_exists($class)  || !in_array($method, get_class_methods($class))) {
                                return $matches[0];
                            }
                        }
                    }
                } else {
                    if(!defined($str)) return $matches[0];
                }
            }
            return '<?php @print('.preg_replace('/\$([a-zA-Z0-9\_\-\>]+)/i','$__Context->\\1', $str).');?>';
        }

        /**
         * @brief replace @... function in { } into print func(..)
         * @param[in] $matches match
         * @return replaced result
         **/
        function _compileVarToSilenceExecute($matches) {
            if(strtolower(trim(str_replace(array(';',' '),'', $matches[1])))=='return') return '<?php return; ?>';
            return '<?php @'.preg_replace('/\$([a-zA-Z0-9\_\-\>]+)/i','$__Context->\\1', trim($matches[1])).';?>';
        }

        /**
         * @brief replace code in <!--@, --> with php code
         * @param[in] $matches match
         * @return changed result
         **/
        function _compileFuncToCode($matches) {
            static $idx = 0;
            $code = trim($matches[1]);
            if(!$code) return;

            switch(strtolower($code)) {
                case 'else' :
                        $output = '}else{';
                    break;
                case 'end' :
                case 'endif' :
                case 'endfor' :
                case 'endforeach' :
                case 'endswitch' :
                        $output = '}';
                    break;
                case 'break' :
                        $output = 'break;';
                    break;
                case 'default' :
                        $output = 'default :';
                    break;
                case 'break@default' :
                        $output = 'break; default :';
                    break;
                default :
                        $suffix = '{';

                        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];
                            $prefix = '$Context->__idx['.$idx.']=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);
                            }
                            $idx++;
                            $suffix .= '$__idx['.$idx.']=($__idx['.$idx.']+1)%2; $cycle_idx = $__idx['.$idx.']+1;';
                        } elseif(substr($code, 0, 4) == 'case') {
                            $suffix = ':';
                        } elseif(substr($code, 0, 10) == 'break@case') {
                            $code = 'break; case'.substr($code, 10);
                            $suffix = ':';
                        }
                        $output = preg_replace('/\$([a-zA-Z0-9\_\-]+)/i', '$__Context->\\1', $code.$suffix);
                    break;
            }

            return sprintf('<?php %s %s ?>', $prefix, $output);
        }


        /**
         * @brief replace xe specific code, "<!--%filename-->" with appropriate php code
         * @param[in] $matches match
         * @return Returns modified result or NULL in case of error
         **/
        function _compileImportCode($matches) {
            // find xml file
            $base_path = $this->path;
            $given_file = trim($matches[1]);
            if(!$given_file) return;
            if(isset($matches[3])) $optimized = strtolower(trim($matches[3]));
            if(!$optimized) $optimized = 'true';
            if(isset($matches[5])) $media = trim($matches[5]);
            if(!$media) $media = 'all';
            if(isset($matches[7])) $targetie = trim($matches[7]);
            if(!$targetie) $targetie = '';
            else $optimized = 'false';

            if(isset($matches[9])) $index = intval($matches[9]);
   if(!$index) $index = 'null';
            if(isset($matches[11])) $type = strtolower(trim($matches[11]));
   if($type!='body') $type = 'head';

            // if given_file ends with lang, load language pack
            if(substr($given_file, -4)=='lang') {
                if(substr($given_file,0,2)=='./') $given_file = substr($given_file, 2);
                $lang_dir = $base_path.$given_file;
                if(is_dir($lang_dir)) $output = sprintf('<?php Context::loadLang("%s"); ?>', $lang_dir);

            // otherwise try to load xml, css, js file
            } else {
    if(preg_match('/^(http|https):/i',$given_file)) $source_filename = $given_file;
                elseif(substr($given_file,0,1)!='/') $source_filename = sprintf("%s%s",$base_path, $given_file);
                else $source_filename = $given_file;

                // get filename and path
                $tmp_arr = explode("/",$source_filename);
                $filename = array_pop($tmp_arr);

                $base_path = implode("/",$tmp_arr)."/";

                // get the ext
                $tmp_arr = explode(".",$filename);
                $ext = strtolower(array_pop($tmp_arr));

                // according to ext., import the file
                switch($ext) {
                    // xml js filter
                    case 'xml' :
                            // create an instance of XmlJSFilter class, then create js and handle Context::addJsFile
                            $output = sprintf(
                                '<?php%s'.
                                'require_once("./classes/xml/XmlJsFilter.class.php");%s'.
                                '$oXmlFilter = new XmlJSFilter("%s","%s");%s'.
                                '$oXmlFilter->compile();%s'.
                                '?>%s',
                                "\n",
                                "\n",
                                $base_path,
                                $filename,
                                "\n",
                                "\n",
                                "\n"
                                );
                        break;
                    // css file
                    case '+ 'css' :
                            if(preg_match('/^(http|\/)/i',$source_filename)) {
                                $output = sprintf('<?php Context::addCSSFile("%s", %s, "%s", "%s", %s); ?>', $source_filename, 'false', $media, $targetie, $index);
                            } else {
        $meta_file = $base_path.$filename;
                                $output = sprintf('<?php Context::addCSSFile("%s%s", %s, "%s", "%s", %s); ?>', $base_path, $filename, $optimized, $media, $targetie, $index);
                            }
                        break;
                    // js file
                    case 'js' :
                            if(preg_match('/^(http|\/)/i',$source_filename)) {
                                $output = sprintf('<?php Context::addJsFile("%s", %s, "%s", %s,"%s"); ?>', $source_filename, 'false', $targetie, $index, $type);
                            } else {
        $meta_file = $base_path.$filename;
                                $output = sprintf('<?php Context::addJsFile("%s%s", %s, "%s", %s, "%s"); ?>', $base_path, $filename, $optimized, $targetie, $index, $type);
                            }
                        break;
                }
            }

   if($meta_file) $output = '<!--#Meta:'.$meta_file.'-->'.$output;
            return $output;
        }

        /**
         * @brief import javascript plugin
         * @param[in] $matches match
         * @return result loading the plugin
         * @remarks javascript plugin works as optimized = false
         **/
        function _compileLoadJavascriptPlugin($matches) {
            $base_path = $this->path;
            $plugin = trim($matches[1]);
            return sprintf('<?php Context::loadJavascriptPlugin("%s"); ?>', $plugin);
        }

        /**
         * @brief remove loading part of css/ js file
         * @param[in] $matches match
         * @return removed result
         **/
        function _compileUnloadCode($matches) {
            // find xml file
            $base_path = $this->path;
            $given_file = trim($matches[1]);
            if(!$given_file) return;
            if(isset($matches[3])) $optimized = strtolower(trim($matches[3]));
            if(!$optimized) $optimized = 'true';
            if(isset($matches[5])) $media = trim($matches[5]);
            if(!$media) $media = 'all';
            if(isset($matches[7])) $targetie = trim($matches[7]);
            if(!$targetie) $targetie = '';
            else $optimized = 'false';

            if(substr($given_file,0,1)!='/') $source_filename = sprintf("%s%s",$base_path, $given_file);
            else $source_filename = $given_file;

            // get path and file nam
            $tmp_arr = explode("/",$source_filename);
            $filename = array_pop($tmp_arr);

            $base_path = implode("/",$tmp_arr)."/";

            // get an ext.
            $tmp_arr = explode(".",$filename);
            $ext = strtolower(array_pop($tmp_arr));

            switch($ext) {
                // css file
                case 'css' :
                        if(preg_match('/^(http|https|\/)/i',$source_filename)) {
                            $output = sprintf('<?php Context::unloadCSSFile("%s", %s, "%s", "%s"); ?>', $source_filename, 'false', $media, $targetie);
                        } else {
                            $output = sprintf('+ '<?php Context::unloadCSSFile("%s%s", %s, "%s", "%s"); ?>', $base_path, $filename, $optimized, $media, $targetie);
                        }
                    break;
                // js file
                case 'js' :
                        if(preg_match('/^(http|https|\/)/i',$source_filename)) {
                            $output = sprintf('<?php Context::unloadJsFile("%s", %s, "%s"); ?>', $source_filename, 'false', $targetie);
                        } else {
                            $output = sprintf('<?php Context::unloadJsFile("%s%s", %s, "%s"); ?>', $base_path, $filename, $optimized, $targetie);
                        }
                    break;
            }

            return $output;
        }
    }
?>

 

 

1.5.0.8 버전

 

 

<?php
/**
 * @class TemplateHandler
 * @author NHN (developers@xpressengine.com)
 * @brief template compiler
 * @version 0.1
 * @remarks It compiles template file by using regular expression into php
 *          code, and XE caches compiled code for further uses
 **/

class TemplateHandler {

 var $compiled_path = './files/cache/template_compiled/'; ///< path of compiled caches files

 var $path = null; ///< target directory
 var $filename = null; ///< target filename
 var $file = null; ///< target file (fullpath)
 var $xe_path = null;  ///< XpressEngine base path
 var $web_path = null; ///< tpl file web path
 var $compiled_file = null; ///< tpl file web path
 var $skipTags = null;

 var $handler_mtime = 0;

 function TemplateHandler()
 {
  // TODO: replace this with static variable in PHP5
  global $__templatehandler_root_tpl;

  $__templatehandler_root_tpl = null;

  $this->xe_path  = rtrim(preg_replace('/([^\.^\/]+)\.php$/i','',$_SERVER['SCRIPT_NAME']),'/');
 }

 /**
  * @brief returns TemplateHandler's singleton object
  * @return TemplateHandler instance
  **/
 function &getInstance()
 {
  static $oTemplate = null;

  if(__DEBUG__==3 ) {
   if(!isset($GLOBALS['__TemplateHandlerCalled__'])) $GLOBALS['__TemplateHandlerCalled__']=1;
   else $GLOBALS['__TemplateHandlerCalled__']++;
  }

  if(!$oTemplate) $oTemplate = new TemplateHandler();

  return $oTemplate;
 }

 /**
  * @brief set variables for template compile
  **/
 function init($tpl_path, $tpl_filename, $tpl_file='')
 {
  // verify arguments
  if(substr($tpl_path,-1)!='/') $tpl_path .= '/';
  if(!file_exists($tpl_path.$tpl_filename)&&file_exists($tpl_path.$tpl_filename.'.html')) $tpl_filename .= '.html';

  // create tpl_file variable
  if(!$tpl_file) $tpl_file = $tpl_path.$tpl_filename;

  // set template file infos.
  $this->path = $tpl_path;
  $this->filename = $tpl_filename;
  $this->file = $tpl_file;

  $this->web_path = $this->xe_path.'/'.ltrim(preg_replace(path),'/'">'@^'.preg_quote(_XE_PATH_,'@').'|\./@','',$this->path),'/');

  // get compiled file name
  $hash = md5($this->file . __ZBXE_VERSION__);
  $this->compiled_file = "{$this->compiled_path}{$hash}.compiled.php";

  // compare various file's modified time for check changed
  $this->handler_mtime = filemtime(__FILE__);

  $skip = array('');
 }

 /**
  * @brief compiles specified tpl file and execution result in Context into resultant content
  * @param[in] $tpl_path path of the directory containing target template file
  * @param[in] $tpl_filename target template file'+ 's name
  * @param[in] $tpl_file if specified use it as template file's full path
  * @return Returns compiled result in case of success, NULL otherwise
  */
 function compile($tpl_path, $tpl_filename, $tpl_file='') {
  global $__templatehandler_root_tpl;

  $buff = '';

  // store the starting time for debug information
  if(__DEBUG__==3 ) $start = getMicroTime();

  // initiation
  $this->init($tpl_path, $tpl_filename, $tpl_file);

  // if target file does not exist exit
  if(!$this->file || !file_exists($this->file)) return "Err : '{$this->file}' template file does not exists.";

  // for backward compatibility
  if(is_null($__templatehandler_root_tpl)) {
   $__templatehandler_root_tpl = $this->file;
  }

  $source_template_mtime = filemtime($this->file);
  $latest_mtime = $source_template_mtime>$this->handler_mtime?$source_template_mtime:$this->handler_mtime;

  // cache control
  $oCacheHandler = &CacheHandler::getInstance('template');

  // get cached buff
  if($oCacheHandler->isSupport()){
   $cache_key = 'template:'.$this->file;
   $buff = $oCacheHandler->get($cache_key, $latest_mtime);
  } else {
   if(is_readable($this->compiled_file) && filemtime($this->compiled_file)>$latest_mtime && filesize($this->compiled_file)) {
    $buff = 'file://'.$this->compiled_file;
   }
  }

  if(!$buff) {
   $buff = $this->parse();
   if($oCacheHandler->isSupport()) $oCacheHandler->put($cache_key, $buff);
   else FileHandler::writeFile($this->compiled_file, $buff);
  }

  $output = $this->_fetch($buff);

  if($__templatehandler_root_tpl == $this->file) {
   $__templatehandler_root_tpl = null;
  }

  // store the ending time for debug information
  if(__DEBUG__==3 ) $GLOBALS['__template_elapsed__'] += getMicroTime() - $start;

  return $output;
 }

 /**
  * @brief compile specified file and immediately return
  * @param[in] $tpl_path path of the directory containing target template file
  * @param[in] $tpl_filename target template file's name
  * @return Returns compiled content in case of success or NULL in case of failure
  **/
 function compileDirect($tpl_path, $tpl_filename) {
  $this->init($tpl_path, $tpl_filename, null);

  // if target file does not exist exit
  if(!$this->file || !file_exists($this->file)) {
   Context::close();
   exit("Cannot find the template file: '{$this->file}'");
  }

  return $this->parse();
 }

 /**
  * @brief compile a template file specified in $tpl_file and
  * @pre files specified by $tpl_file exists.
  * @param[in] $tpl_file path of tpl file
  * @param[in] $compiled_tpl_file if specified, write compiled result into the file
  * @return compiled result in case of success or NULL in case of error
  **/
 function parse($buff=null) {
  if(is_null($buff)) {
   if(!is_readable($this->file)) return;

   // read tpl file
   $buff = FileHandler::readFile($this->file);
  }

  // HTML tags to skip
  if(is_null($this->skipTags)) {
   $this->skipTags = array('marquee');
  }

  // replace comments
  $buff = preg_replace(@s'">'@<!--//.*?-->@s', '', $buff);

  // replace value of src in img/input/script tag
  $buff = preg_replace_callback('/<(?:img|input|script)(?:(?!["\'\/]\s*>).)* src="(?!https?:\/\/|[\/\{])([^"]+)"/is', array($this, '_replacePath'), $buff);

  // replace loop and cond template syntax
  $buff = $this->_parseInline($buff);

  // include, unload/load, import
  $buff = preg_replace_callback('/{(@[\s\S]+?|(?=\$\w+|_{1,2}[A-Z]+|[!\(+-]|\w+(?:\(|::)|\d+|[\'"].*?[\'"]).+?)}|<(!--[#%])?(include|import|(un)?load(?(4)|(?:_js_plugin)?))(?(2)\("([^"]+)")(.*?)(?(2)\)--|\/)>|<!--(@[a-z@]+)(.*?)-->(\s*)/', array($this, '_parseResource'), $buff);

  // remove block which is a virtual tag and remove comments
  $buff = preg_replace(|\s?@is','',$buff">'@</?block\s*>|\s?<!--//(.*?)-->@is','',$buff);

  // form auto generation
  $buff = preg_replace_callback('/(<form(?:<\?php.+?\?>|[^<>]+)*?>)(.*?)(<\/form>)/is', array($this, '_compileFormAuthGeneration'), $buff);

  // prevent from calling directly before writing into file
  $buff = '<?php if(!defined("__XE__"))exit;?>'.$buff;

  return $buff;
 }

 /**
  * @brief 1. remove ruleset from form tag
  * 2. add hidden tag with ruleset value
  * 3. if empty default hidden tag, generate hidden tag (ex:mid, vid, act...)
  * 4. generate return url, return url use in server side validator
  **/
 function _compileFormAuthGeneration($matches)
 {
  // form ruleset attribute move to hidden tag
  if($matches[1])
  {
   preg_match('/ruleset="([^"]*?)"/is', $matches[1], $m);
   if($m[0])
   {
    $matches[1] = preg_replace('/'.$m[0].'/i', '', $matches[1]);
    $matches[2] = '<input type="hidden" name="ruleset" value="'.$m[1].'" />'.$matches[2];

    if (strpos($m[1],'@') !== false){
     $path = str_replace('@', '', $m[1]);
     $path = './files/ruleset/'.$path.'.xml';
    }else if(preg_match('@(?:^|\.?/)(modules/[\w-]+)@', $this->path, $mm)) {
     $module_path = $mm[1];
     $path = $module_path.'/ruleset/'.$m[1].'.xml';
    }
    //assign to addJsFile method for js dynamic recache
    $matches[1]  = '<?php Context::addJsFile("'.$path.'", false, "", 0, "head", true) ?'.'>'.$matches[1];
   }
  }

  // if not exists default hidden tag, generate hidden tag
  preg_match_all('/<input[^>]* name="(act|mid|vid)"/is', $matches[2], $m2);
  $checkVar = array('act', 'mid', 'vid');
  $resultArray = array_diff($checkVar, $m2[1]);
  if(is_array($resultArray))
  {
   $generatedHidden = '';
   foreach($resultArray AS $key=>$value)
   {
    $generatedHidden .= '<input type="hidden" name="'.$value.'" value="<?php echo $__Context->'.$value.' ?>">';
   }
   $matches[2] = $generatedHidden.$matches[2];
  }

  // return url generate
  preg_match('/<input[^>]*name="error_return_url"[^>]*>/is', $matches[2], $m3);
  if(!$m3[0]) $matches[2] = '<input type="hidden" name="error_return_url" value="<?php echo getRequestUriByServerEnviroment() ?>" />'.$matches[2];

  $matches[0] = '';
  return implode($matches);
 }

 /**
  * @brief fetch using ob_* function
  * @param[in] $compiled_tpl_file path of compiled template file
  * @param[in] $buff if buff is not null, eval it instead of including compiled template file
  * @param[in] $tpl_path set context's tpl path
  * @return result string
  **/
 function _fetch($buff) {
  if(!$buff) return;

  $__Context = &$GLOBALS['__Context__'];
  $__Context->tpl_path = $this->path;

  if($_SESSION['is_logged']) {
   $__Context->logged_info = Context::get('logged_info');
  }

  ob_start();
  if(substr($buff, 0, 7) == 'file://') {
   include(substr($buff, 7));
  } else {
   $eval_str = "?>".$buff;
   eval($eval_str);
  }

  return ob_get_clean();
 }

 /**
  * @brief change image path
  * @pre $matches is an array containg three elements
  * @param[in] $matches match
  * @return changed result
  **/
 function _replacePath($match)
 {
  $src = preg_replace('@^(\./)+@', '+ '', trim($match[1]));

  $src = $this->web_path.$src;
  $src = str_replace('/./', '/', $src);

  // for backward compatibility
  $src = preg_replace('@((?:[\w-]+/)+)\1@', '\1', $src);

  while(($tmp=preg_replace('@[^/]+/\.\./@', '', $src))!==$src) $src = $tmp;

  return substr($match[0],0,-strlen($match[1])-6)."src=\"{$src}\"";
 }

 function _parseInline($buff)
 {
  if(preg_match_all('/<([a-zA-Z]+\d?)(?>(?!<[a-z]+\d?[\s>]).)*?(?:[ \|]cond| loop)="/s', $buff, $match) === false) return $buff;

  $tags = array_diff(array_unique($match[1]), $this->skipTags);

  if(!count($tags)) return $buff;

  $tags = '(?:'.implode('|',$tags).')';
  $split_regex = "@(<(?>/?{$tags})(?>[^<>\{\}\"']+|<!--.*?-->|{[^}]+}|\".*?\"|'.*?'|.)*?>)@s";

  $nodes = preg_split($split_regex, $buff, -1, PREG_SPLIT_DELIM_CAPTURE);

  // list of self closing tags
  $self_closing = explode(',', 'area,base,basefont,br,hr,input,img,link,meta,param,frame,col');

  for($idx=1,$node_len=count($nodes); $idx < $node_len; $idx+=2) {
   if(!($node=$nodes[$idx])) continue;

   if(preg_match_all('@\s(loop|cond)="([^"]+)"@', $node, $matches)) {
    // this tag
    $tag = substr($node, 1, strpos($node, ' ')-1);

    // if the vale of $closing is 0, it means 'skipping'
    $closing = 0;

    // process opening tag
    foreach($matches[1] as $n=>$stmt) {
     $expr = $matches[2][$n];
     $expr = $this->_replaceVar($expr);
     $closing++;

     switch($stmt) {
     case 'cond':
      $nodes[$idx-1] .= "<?php if({$expr}){ ?>";
      break;
     case 'loop':
      if(!preg_match((.+?)(?:,(.+?))?|(.*?;.*?;.*?)|(.+?)\s*=\s*(.+?))$@'">'@^(?:(.+?)=>(.+?)(?:,(.+?))?|(.*?;.*?;.*?)|(.+?)\s*=\s*(.+?))$@', $expr, $expr_m)) break;
      if($expr_m[1]) {
       $expr_m[1] = trim($expr_m[1]);
       $expr_m[2] = trim($expr_m[2]);
       if($expr_m[3]) $expr_m[2] .= '=>'.trim($expr_m[3]);
       $nodes[$idx-1] .= "<?php if({$expr_m[1]}&&count({$expr_m[1]}))foreach({$expr_m[1]} as {$expr_m[2]}){ ?>";
      }elseif($expr_m[4]) {
       $nodes[$idx-1] .= "<?php for({$expr_m[4]}){ ?>";
      }elseif($expr_m[5]) {
       $nodes[$idx-1] .= "<?php while({$expr_m[5]}={$expr_m[6]}){ ?>";
      }
      break;
     }
    }
    $node = preg_replace('@\s(loop|cond)="([^"]+)"@', '', $node);

    // find closing tag
    $close_php = '<?php '.str_repeat('}', $closing).' ?>';
    if($node{1} == '!' || substr($node,-2,1) == '/' || in_array($tag, $self_closing)) { //  self closing tag
     $nodes[$idx+1] = $close_php.$nodes[$idx+1];
    } else {
     $depth = 1;
     for($i=$idx+2; $i < $node_len; $i+=2) {
      $nd = $nodes[$i];
      if(strpos($nd, $tag) === 1) {
       $depth++;
      } elseif(strpos($nd, '/'.$tag) === 1) {
       $depth--;
       if(!$depth) {
        $nodes[$i-1] .= $nodes[$i].$close_php;
        $nodes[$i] = '';
        break;
       }
      }
     }
    }
   }

   if(strpos($node, '|cond="') !== false) {
    $node = preg_replace('@(\s[\w:]+="[^"]+?")\|cond="(.+?)"@s', '+ '<?php if($2){ ?>$1<?php } ?>', $node);
    $node = $this->_replaceVar($node);
   }

   if($nodes[$idx] != $node) $nodes[$idx] = $node;
  }

  $buff = implode('', $nodes);

  return $buff;
 }

 function _parseResource($m)
 {
  // {@ ... } or {$var} or {func(...)}
  if($m[1])
  {
   if(preg_match('@^(\w+)\(@', $m[1], $mm) && !function_exists($mm[1])) return $m[0];

   $echo = 'echo ';
   if($m[1]{0} == '@') {
    $echo = '';
    $m[1] = substr($m[1], 1);
   }
   return '<?php '.$echo.$this->_replaceVar($m[1]).' ?>';
  }

  if($m[3])
  {
   $attr = array();
   if($m[5]) {
    if(preg_match_all('@,(\w+)="([^"]+)"@', $m[6], $mm)) {
     foreach($mm[1] as $idx=>$name) {
      $attr[$name] = $mm[2][$idx];
     }
    }
    $attr['target'] = $m[5];
   } else {
    if(!preg_match_all('+ '@ (\w+)="([^"]+)"@', $m[6], $mm)) return $m[0];
    foreach($mm[1] as $idx=>$name) {
     $attr[$name] = $mm[2][$idx];
    }
   }

   switch($m[3])
   {
    // <!--#include--> or <include ..>
    case 'include'+ ':
     if(!$this->file || !$attr['target']) return '';

     $pathinfo = pathinfo($attr['target']);
     $fileDir  = $this->_getRelativeDir($pathinfo['dirname']);

     if(!$fileDir) return '';

     return "<?php \$__tpl=TemplateHandler::getInstance();echo \$__tpl->compile('{$fileDir}','{$pathinfo['basename']}') ?>";

    // <!--%load_js_plugin-->
    case 'load_js_plugin':
     $plugin = $this->_replaceVar($m[5]);
     if(strpos($plugin, '$__Context') === false) $plugin = "'{$plugin}'";

     return "<?php Context::loadJavascriptPlugin({$plugin}); ?>";

    // <load ...> or <unload ...> or <!--%import ...--> or <!--%unload ...-->
    case 'import':
    case 'load':
    case 'unload':
     $metafile = '';
     $pathinfo = pathinfo($attr['target']);
     $doUnload = ($m[3] === 'unload');
     $isRemote = !!preg_match('@^https?://@i', $attr['target']);

     if(!$isRemote) {
      if(!preg_match('@^\.?/@',$attr['target'])) $attr['target'] = './'.$attr['target'];
      if(substr($attr['target'], -5) == '/lang') {
       $pathinfo['dirname']  .= '/lang';
       $pathinfo['basename']  = '';
       $pathinfo['extension'] = 'xml';
      }

      $relativeDir = $this->_getRelativeDir($pathinfo['dirname']);

      $attr['target'] = $relativeDir.'/'.$pathinfo['basename'];
     }

     switch($pathinfo['extension'])
     {
      case 'xml':
       if($isRemote || $doUnload) return '';
       // language file?
       if($pathinfo['basename'] == 'lang.xml' || substr($pathinfo['dirname'],-5) == '/lang') {
        $result = "Context::loadLang('{$relativeDir}');";
       } else {
        $result = "require_once('./classes/xml/XmlJsFilter.class.php');\$__xmlFilter=new XmlJsFilter('{$relativeDir}','{$pathinfo['basename']}');\$__xmlFilter->compile();";
       }
       break;
      case 'js':
       if($doUnload) {
        $result = "Context::unloadFile('{$attr['target']}','{$attr['targetie']}');";
       } else {
        $metafile = $attr['target'];
        $result = "\$__tmp=array('{$attr['target']}','{$attr['type']}','{$attr['targetie']}','{$attr['index']}');Context::loadFile(\$__tmp,'{$attr['usecdn']}','{$attr['cdnprefix']}','{$attr['cdnversion']}');unset(\$__tmp);";
       }
       break;
      case 'css':
       if($doUnload) {
        $result = "Context::unloadFile('{$attr['target']}','{$attr['targetie']}','{$attr['media']}');";
       } else {
        $metafile = $attr['target'];
        $result = "\$__tmp=array('{$attr['target']}','{$attr['media']}','{$attr['targetie']}','{$attr['index']}');Context::loadFile(\$__tmp,'{$attr['usecdn']}','{$attr['cdnprefix']}','{$attr['cdnversion']}');unset(\$__tmp);";
       }
       break;
     }

     $result = "<?php {$result} ?>";
     if($metafile) $result = "<!--#Meta:{$metafile}-->".$result;

     return $result;
   }
  }

  // <!--@..--> such as <!--@if($cond)-->, <!--@else-->, <!--@end-->
  if($m[7])
  {
   $m[7] = substr($m[7],1);
   if(!preg_match('/^(?:((?:end)?(?:if|switch|for(?:each)?|while)|end)|(else(?:if)?)|(break@)?(case|default)|(break))$/', $m[7], $mm)) return '';
   if($mm[1]) {
    if($mm[1]{0} == 'e') return '<?php } ?>';

    $precheck = '';
    if($mm[1] == 'switch') {
     $m[9] = '';
    } elseif($mm[1] == 'foreach') {
     $var = preg_replace('/^\s*\(\s*(.+?) .*$/', '$1', $m[8]);
     $precheck = "if({$var}&&count({$var}))";
    }
    return '<?php '.$this->_replaceVar($precheck.$m[7].$m[8]).'{ ?>'.$m[9];
   }
   if($mm[2]) return "<?php }{$m[7]}".$this->_replaceVar($m[8])."{ ?>".$m[9];
   if($mm[4]) return "<?php ".($mm[3]?'break;':'')."{$m[7]} ".trim($m[8],'()').": ?>".$m[9];
   if($mm[5]) return "<?php break; ?>";
   return '';
  }

  return $m[0];
 }

 function _getRelativeDir($path)
 {
  $_path = $path;

  $fileDir = strtr(realpath($this->path),'\\','/');
  if($path{0} != '/') $path = strtr(realpath($fileDir.'/'.$path),'\\','/');

  // for backward compatibility
  if(!$path) {
   $dirs  = explode('/', $fileDir);
   $paths = explode('/', $_path);
   $idx   = array_search($paths[0], $dirs);

   if($idx !== false) {
    while($dirs[$idx] && $dirs[$idx] === $paths[0]) {
     array_splice($dirs, $idx, 1);
     array_shift($paths);
    }
    $path = strtr(realpath($fileDir.'/'.implode('/', $paths)),'\\','/');
   }
  }

  $path = preg_replace('/^'.preg_quote(_XE_PATH_,'/').'/', '', $path);

  return $path;
 }

 /**
  * @brief replace PHP variables of $ character
  **/
 function _replaceVar($php) {
  if(!strlen($php)) return '';
  return preg_replace('@(?<!::|\\\\|\')\$([a-z]|_[a-z0-9])@i', '\$__Context->$1', $php);
 }
}

/* End of File: TemplateHandler.class.php */

 

 

위에서도 확실하게 차이가 있고, 바꾸면 아래와 같은 문제가 있습니다.

정확하게 어느 값이 없는지 알고 싶습니다. 아시는 분 계신가요?

 

 

1. 일부 스킨에서는 게시판 관리 버튼과 목록 버튼이 겹쳐집니다.

2. FAQ, 각종 게시판에서 게시판 생성시 모듈 이름, 다국어 설정 등을 비롯하여 일부 목록이 보이지 않습니다.

3. 로그온 관리, 개인 정보 수정 등이 제대로 표시되지 않습니다.

4. 게시글 작성시 에디터가 정상적으로 표시되지 않습니다

5. DB 오류가 간혈적으로 발생합니다.

 

 

1.5.0.8이 나오기 전에 XE나 EX 게시판이 호환이 되어야 할것 같습니다만,

EX 게시판의 업데이트 중단 선언 게시글이 오래전에 적혀있어서,

 

 

게시판에 추가되었으면 하는 사항을 몇 가지 적습니다.

 

1. 분류관리의 새로워짐이 있다면 좋겠습니다. EX의 좌측메뉴, 우측메뉴, 콤보박스등이 대표적으로 좋았습니다.

2. 포인트를 등록해서 자료나, 전송이 가능한 포인트샵을 만들수 있어서 운영에 좋았습니다.

 

 

 

 

외 1가지 추가

회원 가입후 닉네임 간에 스페이스 공간이 갑자기 인식되지 않습니다.

예를 들어 희망과의 서약 이라 가입 하면 희망과의서약으로 정정됩니다.

이리 되면  DB에서 일일히 수정을 해야하는데.,

다음 버전에서 이부분 수정 부탁드리겠습니다.

글쓴이 제목 최종 글
코뿔소2020 XE-Core 데모 사이트(테스트 전용) [33] 2011.11.08 by 양파농부
銀童 innodb 와 myisam 에 대한 비교 [2] 2011.11.08 by 지투스
BlogJh 텍스타일은 정말 버려진건가요? [11] 2020.03.14 by ㅠ도라에몽ㅠ
집으로.. 업그레이드 이후 게시판 ex가 이상합니다. [4] 2011.11.07 by 집으로..
sarahkim 서버이전 [2] 2011.11.07 by sarahkim
ForHanbi 1.5.0.8부터 상대경로를 절대경로로 바꾼건가요?? [2] 2011.11.07 by 집으로..
thisend XE + mysqli 조합에 어떤가요? [1] 2011.11.07 by 銀童
카마또 버전 업그레이드 후 홈페이지 접속이 되질 않습니다. [2] 2011.11.07 by 비나무
희망과의서약 xe 1.5로 업그레이드 이후, 플래닛 덧글 작성 되시나요? file  
이키나_ 사이트 검색 잘 되시나요? [2] 2011.11.06 by 손주사랑
코뿔소2020 한국의 인터넷 전용회선의 평균 최고속도가 얼마정도나 되나요. [3] 2011.11.06 by ToFinder
클라데스 XE에 버전정책을 변경해야 한다고 생각합니다. [4] 2011.11.06 by 순수의시절
실실 Parse error: syntax error, unexpected '}' in ......./classes/template/TemplateHandler.class.php(277) : eval()'d code on line 143 [11] 2011.11.05 by 배워서남준다
가브리엘조 xe포럼 사이트 - 사이트맵 위젯은 사용할 수 없나요? file  
희망과의서약 게시판 EX 호환 부분 문제 질문 안내 외 1가지  
銀童 ob_gzhandler 옵션에 관해서 [6] file 2011.11.05 by 쏘프티
roks821 페이지 편집을 html 편집 가능하게 [3] file 2011.11.05 by roks821
misol 저작권 어떻게 생각하세요? [3] 2020.03.14 by Garon
Yosida_sakura 1.5 미만 사용자들을 위한 보안패치는 게속 해줄까요? [5] 2011.11.04 by snows96
Community 혹시 DB에 자동으로 게시판 분류 사용과....