Example #1
0
 /**
 		Reassemble markup string and insert appropriate PHP code
 			@return string
 			@param $node mixed
 			@public
 	**/
 function build($node)
 {
     $out = '';
     if (is_array($node)) {
         foreach ($node as $nkey => $nval) {
             if (is_int($nkey)) {
                 $out .= $this->build($nval);
             } else {
                 $count = count($this->syms);
                 switch ($nkey) {
                     case '@attrib':
                     case 'exclude':
                         break;
                     case 'include':
                         // <include> directive
                         if (!$this->isdef($nkey, $nval, array('href'))) {
                             return;
                         }
                         $hvar = $nval['@attrib']['href'];
                         if (isset($nval['@attrib']['if'])) {
                             $ival = $nval['@attrib']['if'];
                             $cond = $this->expr($ival);
                             // Syntax check
                             if ($cond == $ival) {
                                 trigger_error(sprintf(self::TEXT_AttribInvalid, 'if="' . addcslashes($ival, '"') . '"'));
                                 return;
                             }
                         }
                         $doc = new F3markup($this->mime, $this->globals);
                         $file = self::resolve($hvar);
                         if ($hvar != $file) {
                             self::$cache = FALSE;
                         }
                         $nested = FALSE;
                         foreach (array_keys($this->syms) as $pvar) {
                             if (strstr($hvar, $pvar)) {
                                 $nested = TRUE;
                             }
                         }
                         if ($nested) {
                             $inc_var = preg_split("/[\\s]*[}}{{][\\s]*/i", $hvar, -1, PREG_SPLIT_NO_EMPTY);
                             foreach ($inc_var as &$pval) {
                                 if ($pval[0] == '@') {
                                     $pval = preg_replace(array('/<\\?php echo /', '/; \\?>/'), '', self::expr('{{' . $pval . '}}'));
                                 } else {
                                     $pval = self::stringify($pval);
                                 }
                             }
                             $text = '<?php echo Template::serve(' . implode('.', $inc_var) . ',\'text/html\',' . 'TRUE,' . self::stringify($this->syms) . '); ?>';
                             $out .= isset($ival) ? '<?php if (' . trim($cond) . '): ?>' . $text . '<?php endif; ?>' : $text;
                         } else {
                             foreach (self::split(self::$vars['GUI']) as $gui) {
                                 if (is_file($view = $gui . $file)) {
                                     $text = $doc->load(self::getfile($view), $this->syms);
                                     $out .= isset($ival) ? '<?php if (' . trim($cond) . '): ?>' . $text . '<?php endif; ?>' : $text;
                                     break;
                                 }
                             }
                         }
                         break;
                     case 'loop':
                         // <loop> directive
                         if (!$this->isdef($nkey, $nval, array('counter', 'from', 'to'))) {
                             return;
                         }
                         $cvar = self::remix(preg_replace('/{{\\s*@(.+?)\\s*}}/', '\\1', $nval['@attrib']['counter']));
                         foreach ($nval['@attrib'] as $akey => $aval) {
                             ${$akey[0] . 'att'} = $aval;
                             ${$akey[0] . 'str'} = $this->expr($aval);
                             // Syntax check
                             if (${$akey[0] . 'str'} == $aval) {
                                 trigger_error(sprintf(self::TEXT_AttribInvalid, $akey . '="' . addcslashes($aval, '"') . '"'));
                                 return;
                             }
                         }
                         unset($nval['@attrib']);
                         $this->syms['_' . $cvar] = eval('return ' . $fstr . ';');
                         $out .= '<?php for (' . '$_' . $cvar . '=' . $fstr . ';' . '$_' . $cvar . '<=' . $tstr . ';' . '$_' . $cvar . '+=' . (isset($satt) ? $sstr : '1') . '): ?>' . $this->build($nval) . '<?php endfor; ?>';
                         break;
                     case 'repeat':
                         // <repeat> directive
                         if (!$this->isdef($nkey, $nval, array('group')) && (!$this->isdef($nkey, $nval, array('key')) || !$this->isdef($nkey, $nval, array('value')))) {
                             return;
                         }
                         $gval = $nval['@attrib']['group'];
                         $gstr = trim($this->expr($gval));
                         // Syntax check
                         if ($gstr == $gval) {
                             trigger_error(sprintf(self::TEXT_AttribInvalid, 'group="' . addcslashes($gval, '"') . '"'));
                             return;
                         }
                         foreach ($nval['@attrib'] as $akey => $aval) {
                             ${$akey[0] . 'var'} = self::remix(preg_replace('/{{\\s*@(.+?)\\s*}}/', '\\1', $aval));
                             // Syntax check
                             if (${$akey[0] . 'var'} == $aval) {
                                 trigger_error(sprintf(self::TEXT_AttribInvalid, $akey . '=' . '"' . addcslashes($aval, '"') . '"'));
                                 return;
                             }
                         }
                         unset($nval['@attrib']);
                         if (isset($vvar)) {
                             $this->syms['_' . $vvar] = NULL;
                         } else {
                             $vvar = self::hash($gvar);
                         }
                         if (isset($kvar)) {
                             $this->syms['_' . $kvar] = NULL;
                         }
                         if (isset($cvar)) {
                             $this->syms['_' . $cvar] = NULL;
                         }
                         $out .= '<?php ' . (isset($cvar) ? '$_' . $cvar . '=0; ' : '') . 'if (is_array(' . $gstr . ')):' . 'foreach ((' . $gstr . '?:array()) as ' . (isset($kvar) ? '$_' . $kvar . '=>' : '') . '$_' . $vvar . '):' . (isset($cvar) ? '$_' . $cvar . '++; ' : '') . '?>' . $this->build($nval) . '<?php ' . 'endforeach;' . 'endif;' . '?>';
                         break;
                     case 'check':
                         // <check> directive
                         if (!$this->isdef($nkey, $nval, array('if'))) {
                             return;
                         }
                         $ival = $nval['@attrib']['if'];
                         $cond = $this->expr($ival);
                         // Syntax check
                         if ($cond == $ival) {
                             trigger_error(sprintf(self::TEXT_AttribInvalid, 'if="' . addcslashes($ival, '"') . '"'));
                             return;
                         }
                         // Is <true> is defined ahead of <false>?
                         foreach ($nval as $pos => $blk) {
                             if (is_array($blk)) {
                                 foreach ($blk as $ckey => $cval) {
                                     if (preg_match('/(?:F3:)?' . '(?:true|false)/i', $ckey)) {
                                         ${$ckey[0] . 'block'} = array($pos, $blk);
                                     }
                                 }
                             }
                         }
                         if (isset($tblock) && isset($fblock) && $tblock[0] > $fblock[0]) {
                             // Swap <true> and <false> blocks
                             // <false> is defined ahead of <true>
                             list($nval[$tblock[0]], $nval[$fblock[0]]) = array($fblock[1], $tblock[1]);
                         }
                         $out .= '<?php if (' . trim($cond) . '): ?>' . $this->build($nval) . '<?php endif; ?>';
                         break;
                     case 'true':
                         // <true> block of <check> directive
                         $out .= $this->build($nval);
                         break;
                     case 'false':
                         // <false> block of <check> directive
                         $out .= '<?php else: ?>' . $this->build($nval);
                         break;
                     default:
                         // Custom template tag
                         $out .= new $nkey($nval);
                         break;
                 }
                 // Reset scope
                 while (count($this->syms) > $count) {
                     end($this->syms);
                     unset($this->syms[key($this->syms)]);
                 }
             }
         }
     } else {
         $out .= preg_match('/<\\?php/', $node) ? $node : $this->expr($node, TRUE);
     }
     return $out;
 }
Example #2
0
 /**
 		Reassemble markup string and insert appropriate PHP code
 			@return string
 			@param $node mixed
 			@public
 	**/
 function build($node)
 {
     $out = '';
     if (is_array($node)) {
         foreach ($node as $nkey => $nval) {
             if (is_int($nkey)) {
                 $out .= $this->build($nval);
             } else {
                 $count = count($this->syms);
                 switch ($nkey) {
                     case 'include':
                         // <include> directive
                         if (!$this->isdef($nkey, $nval, array('href'))) {
                             return;
                         }
                         $hvar = $nval['@attrib']['href'];
                         if (isset($nval['@attrib']['if'])) {
                             $ival = $nval['@attrib']['if'];
                             $cond = $this->expr($ival);
                             // Syntax check
                             if ($cond == $ival) {
                                 trigger_error(sprintf(self::TEXT_AttribInvalid, 'if="' . addcslashes($ival, '"') . '"'));
                                 return;
                             }
                         }
                         $doc = new F3markup($this->mime, $this->globals);
                         $file = self::resolve($hvar);
                         if ($hvar != $file) {
                             $this->cache = FALSE;
                         }
                         $file = self::$vars['GUI'] . $file;
                         if (is_file($file)) {
                             $text = $doc->load(self::getfile($file), $this->syms);
                             $out .= isset($ival) ? '<?php if (' . trim($cond) . '): ?>' . $text . '<?php endif; ?>' : $text;
                         }
                         break;
                     case 'loop':
                         // <loop> directive
                         if (!$this->isdef($nkey, $nval, array('counter', 'from', 'to'))) {
                             return;
                         }
                         $cvar = self::remix(preg_replace('/{{\\s*@(.+?)\\s*}}/', '\\1', $nval['@attrib']['counter']));
                         foreach ($nval['@attrib'] as $akey => $aval) {
                             ${$akey[0] . 'att'} = $aval;
                             ${$akey[0] . 'str'} = $this->expr($aval);
                             // Syntax check
                             if (${$akey[0] . 'str'} == $aval) {
                                 trigger_error(sprintf(self::TEXT_AttribInvalid, $akey . '="' . addcslashes($aval, '"') . '"'));
                                 return;
                             }
                         }
                         unset($nval['@attrib']);
                         $this->syms[] = $cvar;
                         $out .= '<?php for (' . '$_' . $cvar . '=' . $fstr . ';' . '$_' . $cvar . '<=' . $tstr . ';' . '$_' . $cvar . '+=' . (isset($satt) ? $sstr : '1') . '): ?>' . $this->build($nval) . '<?php endfor; ?>';
                         break;
                     case 'repeat':
                         // <repeat> directive
                         if (!$this->isdef($nkey, $nval, array('group')) && (!$this->isdef($nkey, $nval, array('key')) || !$this->isdef($nkey, $nval, array('value')))) {
                             return;
                         }
                         $gval = $nval['@attrib']['group'];
                         $gstr = $this->expr($gval);
                         // Syntax check
                         if ($gstr == $gval) {
                             trigger_error(sprintf(self::TEXT_AttribInvalid, 'group="' . addcslashes($gval, '"') . '"'));
                             return;
                         }
                         foreach ($nval['@attrib'] as $akey => $aval) {
                             ${$akey[0] . 'var'} = self::remix(preg_replace('/{{\\s*@(.+?)\\s*}}/', '\\1', $aval));
                             // Syntax check
                             if (${$akey[0] . 'var'} == $aval) {
                                 trigger_error(sprintf(self::TEXT_AttribInvalid, $akey . '=' . '"' . addcslashes($aval, '"') . '"'));
                                 return;
                             }
                         }
                         unset($nval['@attrib']);
                         if (isset($vvar)) {
                             $this->syms[] = $vvar;
                         } else {
                             $vvar = self::hash($gvar);
                         }
                         if (isset($kvar)) {
                             $this->syms[] = $kvar;
                         }
                         if (isset($cvar)) {
                             $this->syms[] = $cvar;
                         }
                         $out .= '<?php ' . (isset($cvar) ? '$_' . $cvar . '=0; ' : '') . 'foreach ((' . trim($gstr) . '?:array()) as ' . (isset($kvar) ? '$_' . $kvar . '=>' : '') . '$_' . $vvar . '): ' . (isset($cvar) ? '$_' . $cvar . '++; ' : '') . '?>' . $this->build($nval) . '<?php endforeach; ?>';
                         break;
                     case 'check':
                         // <check> directive
                         if (!$this->isdef($nkey, $nval, array('if'))) {
                             return;
                         }
                         $ival = $nval['@attrib']['if'];
                         $cond = $this->expr($ival);
                         // Syntax check
                         if ($cond == $ival) {
                             trigger_error(sprintf(self::TEXT_AttribInvalid, 'if="' . addcslashes($ival, '"') . '"'));
                             return;
                         }
                         // Is <true> is defined ahead of <false>?
                         foreach ($nval as $pos => $blk) {
                             if (is_array($blk)) {
                                 foreach ($blk as $ckey => $cval) {
                                     if (preg_match('/(?:F3:)?' . '(?:true|false)/i', $ckey)) {
                                         ${$ckey[0] . 'block'} = array($pos, $blk);
                                     }
                                 }
                             }
                         }
                         if (isset($tblock) && isset($fblock) && $tblock[0] > $fblock[0]) {
                             // Swap <true> and <false> blocks
                             // <false> is defined ahead of <true>
                             list($nval[$tblock[0]], $nval[$fblock[0]]) = array($fblock[1], $tblock[1]);
                         }
                         $out .= '<?php if (' . trim($cond) . '): ?>' . $this->build($nval) . '<?php endif; ?>';
                         break;
                     case 'true':
                         // <true> block of <check> directive
                         $out .= $this->build($nval);
                         break;
                     case 'false':
                         // <false> block of <check> directive
                         $out .= '<?php else: ?>' . $this->build($nval);
                         break;
                 }
                 // Reset scope
                 $this->syms = array_slice($this->syms, 0, $count);
             }
         }
     } else {
         $out .= preg_match('/<\\?php/', $node) ? $node : $this->expr($node, TRUE);
     }
     return $out;
 }
Example #3
0
 /**
 		Render template
 			@return string
 			@param $file string
 			@param $mime string
 			@param $globals boolean
 			@param $syms array
 			@public
 	**/
 static function serve($file, $mime = 'text/html', $globals = TRUE, $syms = array())
 {
     $file = self::resolve($file);
     $found = FALSE;
     foreach (preg_split('/[\\|;,]/', self::$vars['GUI'], 0, PREG_SPLIT_NO_EMPTY) as $gui) {
         if (is_file($view = self::fixslashes($gui . $file))) {
             $found = TRUE;
             break;
         }
     }
     if (!$found) {
         trigger_error(sprintf(self::TEXT_Render, $file));
         return '';
     }
     if (PHP_SAPI != 'cli' && !headers_sent()) {
         // Send HTTP header with appropriate character set
         header(self::HTTP_Content . ': ' . $mime . '; ' . 'charset=' . self::$vars['ENCODING']);
     }
     $hash = 'tpl.' . self::hash($view);
     $cached = Cache::cached($hash);
     if ($cached && filemtime($view) < $cached) {
         if (self::$vars['CACHE']) {
             // Retrieve PHP-compiled template from cache
             $text = Cache::get($hash);
         }
     } else {
         // Parse raw template
         $doc = new F3markup($mime, $globals);
         $text = $doc->load(self::getfile($view), $syms);
         if (self::$vars['CACHE'] && $doc::$cache) {
             // Save PHP-compiled template to cache
             Cache::set($hash, $text);
         }
     }
     // Render in a sandbox
     $instance = new F3instance();
     ob_start();
     if (ini_get('allow_url_fopen') && ini_get('allow_url_include')) {
         // Stream wrap
         $instance->sandbox('data:text/plain,' . urlencode($text), $syms);
     } else {
         // Save PHP-equivalent file in temporary folder
         if (!is_dir(self::$vars['TEMP'])) {
             self::mkdir(self::$vars['TEMP']);
         }
         $temp = self::$vars['TEMP'] . $_SERVER['SERVER_NAME'] . '.' . $hash;
         if (!$cached || !is_file($temp) || filemtime($temp) < Cache::cached($view)) {
             // Create semaphore
             $hash = 'sem.' . self::hash($view);
             while ($cached = Cache::cached($hash)) {
                 // Locked by another process
                 usleep(mt_rand(0, 100));
             }
             Cache::set($hash, TRUE);
             self::putfile($temp, $text);
             // Remove semaphore
             Cache::clear($hash);
         }
         $instance->sandbox($temp, $syms);
     }
     $out = ob_get_clean();
     unset($instance);
     return self::$vars['TIDY'] ? self::tidy($out) : $out;
 }