. // Copyright © 2007-2014 Erwan Briand // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, version 3 only. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public // License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /** * @file * This file contains the Template class * * It parses the request of the user.and renders an output. * This one can be outpute in XHTML (HTTP default), RSS, ATOM, SVG, CSS or * XML/OpenForge. */ /** * Template class */ class Template { private $tpl, $page, $ct_session, $ct_db, $langlist, $lang, $error, $start_time; function __construct ($tpl, $page, $ct_session, $ct_db, $langlist, $lang, $error, $start_time) { $this->tpl = $tpl; $this->ct_session = $ct_session; $this->ct_db = $ct_db; $this->langlist = $langlist; $this->lang = $lang; $this->error = $error; $this->start_time = $start_time; // Remove empty data $page = explode('/', $page); foreach ($page as $key => $value) if (!empty($value) || $value == 0) $this->page[$key] = $value; /* Popularity contest. * Each projects have a popularity score and this score is resetted * each months. */ $cfg = getClass('config', $this->ct_db); $timestamp = $cfg->get('projects', 'popularity-timestamp'); if (!$timestamp || ( $timestamp + (86400 * 30) ) < time()) { // Reset popularity for each projects $this->ct_db->update('projects', array('popularity' => 0), FALSE); // Reset contest $cfg->update('projects', 'popularity-timestamp', time()); $cfg->update('projects', 'overall-popularity', 0); } // Cache maximum $this->cache_max_files = (int)$cfg->get('global', 'cache-max-files'); // Title $this->forge_title = $cfg->get('global', 'title'); // Prepare switch ($this->page[1]) { case 'api': Header('Content-Type: application/xml; charset=UTF-8'); $this->parseAPI(); break; case 'atom': Header('Content-Type: application/atom+xml; charset=UTF-8'); $this->parseAtom(); break; case 'rss': Header('Content-Type: application/rss+xml; charset=UTF-8'); $this->parseRSS(); break; case 'svg': Header('Content-Type: image/svg+xml; charset=UTF-8'); $this->parseSVG(); break; case 'inc': if ($this->page[2] == 'templates' && explode('.', end($this->page), 2)[1] == 'css') $this->parseCSS(); break; default: Header('Content-Type: text/html; charset=UTF-8'); $this->parseXHTML(); } } /** * Parse API * * Print the XML output (OpenForge format) */ function parseAPI () { /* TODO: REPLACE THIS: EVERYTHING MUST HAVE A XML OUTPUT! // Find the module that can generate the request if ($this->page[2] == 'user') // OpenForge user $mod = CT_BASEDIR.'/inc/modules/users/views/show.php'; elseif ($this->page[2] == 'project') // OpenForge project $mod = CT_BASEDIR.'/inc/modules/project/views/default.php'; elseif ($this->page[2] == 'search') // OpenForge research $mod = CT_BASEDIR.'/inc/modules/search/views/default.php'; elseif ($this->page[2] == 'users') // Private $mod = CT_BASEDIR.'/inc/modules/users/views/messages.php'; else exit('CodingTeam OpenForge API'); */ $mod = CT_BASEDIR.'/inc/modules/'.$this->page[2]; if (isset($this->page[3])) $mod .= '/views/'.$this->page[3].'.php'; else $mod .= '/views/default.php'; // Open the module view in the CodingTeam way if (is_file($mod)) { require($mod); $view_api = new View($this->ct_session, $this->ct_db, $this->page, $this->error, $this->langlist, $this->lang); if (method_exists($view_api, 'showAPI')) $view_api->showAPI(); else { $xml = new DOMDocument('1.0', 'utf-8'); $openforge = $xml->createElement('openforge'); $xml->appendChild($openforge); // Append the forge info $version = file_get_contents(CT_BASEDIR.'/VERSION'); $forge = $openforge->appendChild($xml->createElement('forge')); $forge->appendChild($xml->createElement('name', 'CodingTeam')); $forge->appendChild($xml->createElement('url', CT_BASEURL)); $forge->appendChild($xml->createElement('version', $version)); $forge->appendChild($xml->createElement('apiversion', '0.1')); $error = $openforge->appendChild($xml->createElement('error')); $error->appendChild($xml->createElement('code', '001')); $error->appendChild($xml->createElement('context', 'Nothing to show')); // Show XML error $xml->formatOutput = TRUE; echo $xml->saveXML(); } } else exit('Error.'); } /** * Parse Atom * * Print the Atom output and save it in the cache for 7 days */ function parseAtom () { // Converting page tags $j = 1; for ($i=1; $i<=count($this->page); $i++) if (isset($this->page[$i]) && $this->page[$i] != 'atom') { $newpage[$j] = $this->page[$i]; $j ++; } $this->page = $newpage; // Cache Atom feed for 7 days max. $cachenamefile = CT_BASEDIR.'/public/cache/atom/'. mb_substr($this->lang, 0, 2).'-'. str_replace('/', '-', getURLbyTags($this->page)); if ( (file_exists($cachenamefile) && filemtime($cachenamefile) < time() - ( 3600 * 24 * 7 )) || !file_exists($cachenamefile) ) { // Find the requested module view if ($this->page[1] == 'project') if (empty($this->page[3])) $mod = CT_BASEDIR.'/inc/modules/'.$this->page[1]. '/views/default.php'; else $mod = CT_BASEDIR.'/inc/modules/'.$this->page[1]. '/views/'.$this->page[3].'.php'; elseif ($this->page[1] == 'admin') $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); else if (empty($this->page[2])) $mod = CT_BASEDIR.'/inc/modules/'.$this->page[1]. '/views/default.php'; else $mod = CT_BASEDIR.'/inc/modules/'.$this->page[1]. '/views/'.$this->page[2].'.php'; // Load the module if (is_file($mod)) { require($mod); $view_atom = new View($this->ct_session, $this->ct_db, $this->page, $this->error, $this->langlist, $this->lang); $atom_array = $view_atom->showFeed(); if (!is_array($atom_array)) $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); } else $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); // Create the Atom document Header("Content-Type: application/atom+xml; charset=utf-8"); $xml = new DOMDocument('1.0', 'utf-8'); $atom = $xml->createElement('feed'); $atom->setAttribute('xmlns', 'http://www.w3.org/2005/Atom'); $atom->setAttribute('xml:lang', mb_substr($this->lang, 0, 2)); $xml->appendChild($atom); $atom->appendChild($xml->createElement('id', CT_BASEURL.'atom/'. urlencode(getURLByTags($this->page)))); $atom->appendChild($xml->createElement('title', $atom_array['title'])); $atom->appendChild($xml->createElement('subtitle', $atom_array['description'])); $atom->appendChild($xml->createElement('updated', convertDate(time(), 'timestamp', 'rfc.3339'))); $link = $xml->createElement('link'); $link->setAttribute('rel', 'self'); $link->setAttribute('href', CT_BASEURL.'atom/'. getURLByTags($this->page)); $link->setAttribute('type', 'application/atom+xml'); $atom->appendChild($link); // Add latest items to the feed if (isset($atom_array['threads']) && is_array($atom_array['threads'])) { foreach ($atom_array['threads'] as $thread) { $item = $xml->createElement('entry'); $item->appendChild($xml->createElement('title', $thread['title'])); $time = convertDate($thread['pubDate'], 'datetime', 'timestamp'); $tim = convertDate($time, 'timestamp', 'rfc.3339'); $item->appendChild($xml->createElement('updated', $tim)); $item->appendChild($xml->createElement('id', $thread['guid'])); $link = $xml->createElement('link'); $link->setAttribute('href', $thread['link']); $item->appendChild($link); $author = $xml->createElement('author'); $author->appendChild($xml->createElement('name', $thread['dc:creator'])); $author->appendChild($xml->createElement('uri', CT_BASEURL.'users/show/'.$thread['dc:creator'])); $item->appendChild($author); $link = $xml->createElement('content', $thread['description']); $link->setAttribute('type', 'html'); $item->appendChild($link); $atom->appendChild($item); } } // Prepare the output $xml->formatOutput = true; $tpl_show = $xml->saveXML(); // Maximum files in cache $cachedir_ = CT_BASEDIR.'/public/cache/atom/'; $cachedir = opendir($cachedir_); $counter = 0; $cache_files = array(); // Count files in cache and create array while($f = readdir($cachedir)) if (is_file($cachedir_.$f)) { $cache_files[filemtime($cachedir_.$f)] = $cachedir_.$f; $counter ++; } closedir($cachedir); ksort($cache_files); // If we need to delete the oldest file before save our new one if ((count($cache_files) - 1) > ($this->cache_max_files / 2)) if (file_exists(reset($cache_files))) unlink(reset($cache_files)); if (mb_substr(getURLbyTags($this->page), 0, 17) != 'dashboard/default') { // Write in the cache $filec = fopen($cachenamefile, 'w'); fwrite($filec, $tpl_show); fclose($filec); } } else $tpl_show = file_get_contents($cachenamefile); // Show the result echo $tpl_show; } /** * Parse RSS * * Print the RSS output and save it in the cache for 7 days */ function parseRSS () { // Converting page tags $j = 1; for ($i=1; $i<=count($this->page); $i++) if (isset($this->page[$i]) && $this->page[$i] != 'rss') { $newpage[$j] = $this->page[$i]; $j ++; } $this->page = $newpage; // Cache RSS feed for 7 days max. $cachenamefile = CT_BASEDIR.'/public/cache/rss/'. mb_substr($this->lang, 0, 2).'-'. str_replace('/', '-', getURLbyTags($this->page)); if ( (file_exists($cachenamefile) && filemtime($cachenamefile) < time() - ( 3600 * 24 * 7 )) || !file_exists($cachenamefile)) { // Find the requested module view if ($this->page[1] == 'project') if (empty($this->page[3])) $mod = CT_BASEDIR.'/inc/modules/'.$this->page[1]. '/views/default.php'; else $mod = CT_BASEDIR.'/inc/modules/'.$this->page[1]. '/views/'.$this->page[3].'.php'; elseif ($this->page[1] == 'admin') $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); else if (empty($this->page[2])) $mod = CT_BASEDIR.'/inc/modules/'.$this->page[1]. '/views/default.php'; else $mod = CT_BASEDIR.'/inc/modules/'.$this->page[1]. '/views/'.$this->page[2].'.php'; // Load the module if (is_file($mod)) { require($mod); $view_rss = new View($this->ct_session, $this->ct_db, $this->page, $this->error, $this->langlist, $this->lang); $rss_array = $view_rss->showFeed(); if (!is_array($rss_array)) $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); } else $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); // Create the RSS document Header("Content-Type: application/rss+xml; charset=utf-8"); $xml = new DOMDocument('1.0', 'utf-8'); $rss = $xml->createElement('rss'); $rss->setAttribute('version', '2.0'); $rss->setAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); $xml->appendChild($rss); $channel = $xml->createElement('channel'); $rss->appendChild($channel); // Add informations on the feed $channel->appendChild($xml->createElement('title', $rss_array['title'])); $channel->appendChild($xml->createElement('link', $rss_array['link'])); $channel->appendChild($xml->createElement('description', $rss_array['description'])); $channel->appendChild($xml->createElement('language', mb_substr($this->lang, 0, 2))); // Add latest items to the feed if (isset($rss_array['threads']) && is_array($rss_array['threads'])) { foreach ($rss_array['threads'] as $thread) { $item = $xml->createElement('item'); $item->appendChild($xml->createElement('title', $thread['title'])); $item->appendChild($xml->createElement('pubDate', convertDate($thread['pubDate'], 'datetime', 'rfc'))); $item->appendChild($xml->createElement('guid', $thread['guid'])); $item->appendChild($xml->createElement('link', $thread['link'])); $item->appendChild($xml->createElement('dc:creator', $thread['dc:creator'])); $item->appendChild($xml->createElement('description', $thread['description'])); $channel->appendChild($item); } } // Prepare the output $xml->formatOutput = true; $tpl_show = $xml->saveXML(); // Maximum files in cache $cachedir_ = CT_BASEDIR.'/public/cache/rss/'; $cachedir = opendir($cachedir_); $counter = 0; $cache_files = array(); // Count files in cache and create array while($f = readdir($cachedir)) if (is_file($cachedir_.$f)) { $cache_files[filemtime($cachedir_.$f)] = $cachedir_.$f; $counter ++; } closedir($cachedir); ksort($cache_files); // If we need to delete the oldest file before save our new one if ((count($cache_files) - 1) > ($this->cache_max_files / 2)) if (file_exists(reset($cache_files))) unlink(reset($cache_files)); if (mb_substr(getURLbyTags($this->page), 0, 17) != 'dashboard/default') { // Write in the cache $filec = fopen($cachenamefile, 'w'); fwrite($filec, $tpl_show); fclose($filec); } } else $tpl_show = file_get_contents($cachenamefile); // Show the result echo $tpl_show; } /** * Parse SVG * * Print the SVG output. */ function parseSVG () { require(CT_BASEDIR.'/inc/classes/svg.php'); new SVG($this->ct_db, $this->page); } /** * Parse XHTML * * Print the XHTML output and save it in the cache for 7 days if user is * not logged. */ function parseXHTML () { // Change the path to the .tpl file $wtpl = CT_BASEDIR.'/inc/templates/'.CT_TEMPLATE_THEME.'/main.tpl'; if (file_exists($wtpl)) $this->tpl = $wtpl; // Test if URL contains _GET datas and delete them from the page array $_page_ = array(); $back = $this->page; foreach ($this->page as $arg) { if (mb_substr($arg, 0, 1) != '?') array_push($_page_, $arg); } $this->page = $_page_; // If a > 0 the page cannot be stored in the cache $a = 0; $nocache_keywords = array('register', 'logout', 'password', 'delete', 'admin', 'new', 'add', 'edit', 'answer', 'search', 'join', 'vote'); foreach ($nocache_keywords as $key) if (in_array($key, $this->page)) $a ++; if (in_array('bugs', $this->page) && in_array('show', $this->page)) $a ++; if (in_array('project', $this->page) && in_array('timeline', $this->page)) $a ++; // Also, no cache if an user try to login if ((isset($_POST['login_nickname']) && isset($_POST['login_password'])) OR isset($_POST['login_jabberid'])) $a ++; // If cache score equals zero and the user is not logged if (!$this->ct_session->isLogged($this->ct_db) && $a == 0) { // Set default expire time to one week (3600 * 24 * 7) $time = 604800; // Set the name of the file stored in cache $file = CT_BASEDIR.'/public/cache/xhtml/'. mb_substr($this->lang, 0, 2).str_replace('/', '-', getURLbyTags($back)); // If the page is already stored in the cache if (is_file($file)) { // Get meta information $cachefile = fopen($file, 'r'); $firstline = htmlspecialchars(fgets($cachefile, 1024)); // Set new expire time $info = explode('=', $firstline); if ($info[0] == 'expire') $time = $info[1]; fclose($cachefile); } // Rewrite the page in cache if expired or not exists if ( ( is_file($file) && filemtime($file) < ( time() - $time ) ) || !is_file($file) ) { $view = $this->loadView(); // Write meta information if expired time is not default if ($view['expire'] != $time) $additional = "expire=".$view['expire']."\n"; else $additional = ''; // Maximum files in cache $cachedir_ = CT_BASEDIR.'/public/cache/xhtml/'; $cachedir = opendir($cachedir_); $counter = 0; $cache_files = array(); // Count files in cache and create array while($f = readdir($cachedir)) if (is_file($cachedir_.$f)) { $cache_files[filemtime($cachedir_.$f)] = $cachedir_.$f; $counter ++; } closedir($cachedir); ksort($cache_files); // If we need to delete the oldest file before save our new // one. if ((count($cache_files) - 1) > $this->cache_max_files) if (file_exists(reset($cache_files))) unlink(reset($cache_files)); // Save in cache file_put_contents($file, $additional.$view['content']); $content = $view['content']; } // Just include the cache version else { $cachefile = file($file); $content = ''; // Check if the first line contains meta information $satanized = htmlspecialchars($cachefile[0]); if (mb_substr($satanized, 0, 7) == 'expire=') $start = 1; else $start = 0; for ($i=$start; $iloadView(); $content = $view['content']; } // Show the page echo str_replace('{tpl:baseurl}', CT_BASEURL, $content); } /** * Load view * * Load view from module or plugin and return it in a view for parseXHTML. * @return * An array that contains XHTML string and expire time. */ function loadView() { // Set default expire time to one week (3600 * 24 * 7) $time_expire = 604800; // Find all "head modules" $headmodules = array(); $head = array(); $dir = CT_BASEDIR.'/inc/modules/'; $headmodulesdir = opendir($dir); while ($mod = readdir($headmodulesdir)) if (substr($mod, 0, 5) == 'head_') array_push($headmodules, $mod); // Load all head modules for($i=0; $ict_session, $this->ct_db, $this->page); $head[$headmodules[$i]]->treatForms(); } // Load asked module $xmlfile = CT_BASEDIR.'/inc/modules/'.$this->page[1].'/infos.xml'; if (is_file($xmlfile)) { // Start SimpleXML for parsing module informations $modxml = simplexml_load_file($xmlfile); $is_active = $modxml['active']; // If module is active if ($is_active == 'TRUE' && isset($modxml->views)) { // Get position of module and view in the URL $behavior_module = (int)($modxml->behavior['module-position']); $behavior_view = (int)($modxml->behavior['view-position']); // Set the module if (!isset($this->page[$behavior_module])) $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); else $module = $this->page[$behavior_module]; // Set the view if (!isset($this->page[$behavior_view])) $wished_view = 'default'; else if (!empty($this->page[$behavior_view])) $wished_view = $this->page[$behavior_view]; else { Header('Location: '.CT_BASEURL.$this->page[1]); exit(); } // Fetch all views foreach ($modxml->views->view as $view) { // If this the requested view if ($view['name'] == $wished_view) { $moduleview = 'views/'.$wished_view; // Exit if view is disabled $is_active = $view['active']; if ($is_active == 'FALSE') $this->error->displayError(i18n('This feature has'. ' been disabled by an administrator.'), 0); // Use another expire time if set if (!empty($view['expire'])) $time_expire = $view['expire']; } } } else $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); $is_this_admin = FALSE; } // If this is the admin module elseif ($this->page[1] == 'admin') { if (!isset($this->page[2])) { $module = 'admin'; $moduleview = 'views/default'; } else { $module = $this->page[2]; $moduleview = '_admin/'.$this->page[3]; } $is_this_admin = TRUE; } else $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); if (!isset($moduleview)) $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); // Load the wished view $view = CT_BASEDIR.'/inc/modules/'.$module.'/'.$moduleview.'.php'; if (is_file($view)) { require($view); $view_loaded = new View($this->ct_session, $this->ct_db, $this->page, $this->error, $this->langlist, $this->lang); // Do treatment for POST datas $view_loaded->treatForms(); } else $this->error->displayError(i18n('404 Document not found.'), 0, '404 Not Found'); // Get the content of the page $constructed_view = $view_loaded->constructView(); // Include template file $tpl_base = CT_BASEDIR.'/inc/modules/'.$module.'/templates/'; $tpl_file = $tpl_base.$constructed_view['__tpl__']; // Fills template ob_start(); unset($constructed_view['__tpl__']); extract($constructed_view); include($tpl_file); $page_content = ob_get_contents(); ob_end_clean(); /* Ok. Now, we have generated our view based on the template and the * view class related to the request. * The next work is to integrate this content in the layout template. * Once we do that, our work will be ended. */ // Import the .tpl file $this->tpl_file = file_get_contents($this->tpl); $temp['tpl:lang'] = mb_substr($this->lang, 0, 2); $temp['tpl:cssdir'] = 'inc/templates/'.CT_TEMPLATE_THEME.'/'; $temp['tpl:images'] = 'public/images/'; $temp['tpl:logosimages'] = 'public/images/logos/'; // Generate the menu $tabs = array(); $modlist = array(); $modulesdir = opendir(CT_BASEDIR.'/inc/modules/'); while ($module_ = readdir($modulesdir)) { $xmlfile = CT_BASEDIR.'/inc/modules/'.$module_.'/infos.xml'; if (is_file($xmlfile)) { $modxml = simplexml_load_file($xmlfile); $is_active = $modxml['active']; if ($is_active == 'TRUE') { require_once(CT_BASEDIR.'/inc/modules/'. $module_.'/menu.php'); $classname = ucfirst($module_).'Menu'; $modmenu = new $classname($this->ct_db, $this->lang, $this->ct_session, $this->page, $modxml->views->view); $mmenu = $modmenu->getNotepadMenu(); if (is_array($mmenu) && $mmenu['force_login'] && !$this->ct_session->isLogged()) continue; if ($module_ == $module) $menu = $modmenu; if (is_array($mmenu)) { array_push($tabs, $mmenu); array_push($modlist, $module_); } } } } // Sort tabs $tabs_ = array(); foreach ($tabs as $tab_) { if (isset($tab_['position'])) $tabs_[$tab_['position']] = $tab_; else $tabs_[count($tabs_) + 1] = $tab_; } ksort($tabs_); // Show the tabs $npmenu = ''; foreach ($tabs_ as $tab) { if ($tab['module'] == $this->page[1] || ($tab['module'] == 'projects' && $this->page[1] == 'project') || ($tab['module'] == 'index' && $this->page[1] != 'project' && !in_array($this->page[1], $modlist))) $npmenu .= '
  • '. mb_substr(htmlspecialchars($tab['title']), 0, 2). ''.htmlspecialchars($tab['title']). '
  • '; else $npmenu .= '
  • '. mb_substr(htmlspecialchars($tab['title']), 0, 2). ''. htmlspecialchars($tab['title']).'
  • '; } $temp['tpl:notepadmenu'] = $npmenu; // Set global values $temp['forge_title'] = $this->forge_title; $v = file_get_contents(CT_BASEDIR.'/VERSION'); $temp['poweredby'] = i18n('Powered by CodingTeam %(version)s', array('version' => ''.$v.'')); $temp['forge'] = i18n('Forge'); $temp['link_about'] = i18n('About'); $temp['link_tou'] = i18n('Terms of Use'); $temp['link_admin'] = i18n('Administration'); // Set global views if (array_key_exists('head_member', $head)) { ob_start(); $head['head_member']->getPageContent(); $temp['view:head_member'] = ob_get_clean(); } if (array_key_exists('head_search', $head)) { ob_start(); $head['head_search']->getPageContent(); $temp['view:head_search'] = ob_get_clean(); } // Set page Meta-Tags $meta = ''; foreach ($view_loaded->metatags as $key => $value) { switch ($key) { case 'title': $temp['title'] = $value; break; case 'feed': if (!empty($value)) $meta .= ''."\n". ' '."\n"; break; case 'javascript': if (is_string($value)) $value = array($value); foreach ($value as $item) $meta .= "\n"; break; default: if (!empty($value)) $meta .= ' '."\n"; } } $temp['htmlmeta'] = $meta; // Load the menu if administration interface if ($is_this_admin) { require_once(CT_BASEDIR.'/inc/modules/admin/menu.php'); $classname = 'AdminMenu'; $menu = new $classname($this->ct_db, $this->lang, $this->ct_session, $this->page); } // Get page title $tmp_title = explode(' - ', $temp['title'], 2); // Get page menu if (isset($menu)) { $basemenu = $menu->getPageMenu($tmp_title[0]); $temp['view:pagemenu'] = $basemenu[0]; if (isset($basemenu[1][0])) $temp['view:pagename'] = '

    '.$basemenu[1][1].'

    '; else $temp['view:pagename'] = ''; $temp['view:additionalmenu'] = $basemenu[2]; $temp['view:pagelogo'] = $basemenu[3]; } else $temp['view:pagemenu'] = ''; // Add the page main content $temp['view:pagecontent'] = $page_content; // Finally, stop the execution time here $cfg = getClass('config', $this->ct_db); $sec = round(microtime(true) - $this->start_time, 2); $sqlsec = $this->ct_db->getExecutionTime(); if ($cfg->get('global', 'show-exectime')) $temp['execution_time'] = ''. i18n('Executed in %(sec)d seconds '. '(%(sqlsec)d for SQL).', array('sec' => $sec, 'sqlsec' => $sqlsec)). ''; else $temp['execution_time'] = ''; // Edit the template foreach ($temp as $key => $value) { $search[] = '{'.$key.'}'; $replace[] = $value; } $this->tpl_show = str_replace($search, $replace, $this->tpl_file); return array('content' => $this->tpl_show, 'expire' => $time_expire); } /** * Parse CSS * * Print the CSS output. #TODO: save it in the cache? it would be nice! */ function parseCSS () { $colorpalette = CT_TEMPLATE_COLORPALETTE; $input_css = file_get_contents(CT_BASEDIR.implode('/', $this->page)); require_once(CT_BASEDIR.'/inc/templates/'.CT_TEMPLATE_THEME.'/color.php'); $palette = $color_palette[$colorpalette]; // Edit the CSS foreach ($palette as $key => $value) { $search[] = '{'.$key.'}'; $replace[] = $value; } $css = str_replace($search, $replace, $input_css); // Create the CSS document Header("Content-Type: text/css; charset=utf-8"); echo $css; } } ?>