/** * Renders the output after preperation. * @see vB5_Template::render() * * @param boolean Whether to suppress the HTML comment surrounding option (for JS, etc) * @param boolean true if we are rendering for a call to /ajax/render/ and we want CSS <link>s separate * * @return string */ public function render($isParentTemplate = true, $isAjaxTemplateRender = false) { static $user = false; if (!$user) { $user = vB5_User::instance(); } $config = vB5_Config::instance(); $this->register('user', $user, true); extract(self::$globalRegistered, EXTR_SKIP | EXTR_REFS); extract($this->registered, EXTR_OVERWRITE | EXTR_REFS); $baseurl = vB5_Template_Options::instance()->get('options.frontendurl'); $baseurl_core = vB5_Template_Options::instance()->get('options.bburl'); $baseurl_login = vB5_Template_Options::instance()->get('options.frontendurl_login'); $baseurl_data = vB5_String::parseUrl($baseurl); if (isset($baseurl_data['path'])) { $baseurl_path = $baseurl_data['path']; } $baseurl_path = isset($baseurl_path) ? $baseurl_path . (substr($baseurl_path, -1) != '/' ? '/' : '') : '/'; //same as cookie path $cookie_prefix = $config->cookie_prefix; $vboptions = vB5_Template_Options::instance()->getOptions(); $vboptions = $vboptions['options']; //this assumes that core is in the core directory which is not something we've generally assumed //however as noncollapsed mode look unlikely to be as useful as we thought, we'll start making that //assumption. However setting a seperate variable means we don't spread that assumption all through //the template code. $baseurl_cdn = $vboptions['cdnurl']; if ($baseurl_cdn) { $baseurl_corecdn = $baseurl_cdn . '/core'; } else { //if we haven't set a cdn url, then let's default to the actual site urls. $baseurl_cdn = $baseurl; $baseurl_corecdn = $baseurl_core; } $vbproducts = vB::getDatastore()->getValue('products'); $preferred_styleid = vB5_Template_Stylevar::instance()->getPreferredStyleId() > 0 ? vB5_Template_Stylevar::instance()->getPreferredStyleId() : $vboptions['styleid']; $preferred_languageid = vB5_User::getLanguageId() > 0 ? vB5_User::getLanguageId() : $vboptions['languageid']; $timenow = time(); self::$renderedTemplateNames[] = $this->template; // debug info for the templates that have been used if ($config->debug) { self::$renderedTemplates[] = array('templateName' => $this->template, 'isParentTemplate' => (bool) $isParentTemplate, 'indent' => str_repeat('|----', count(self::$renderedTemplatesStack))); self::$renderedTemplatesStack[] = $this->template; } // todo: remove this once we can remove notices from template code // allow developers to turn notices off for templates -- to avoid having them turn off notices entirely if ($config->no_template_notices) { $oldReporting = error_reporting(E_ALL & ~E_NOTICE); } if ($config->render_debug) { set_exception_handler(null); set_error_handler('vberror'); // Show which template is being rendered. echo 'Template: ' . $this->template . '<br />'; } $templateCache = vB5_Template_Cache::instance(); $templateCode = $templateCache->getTemplate($this->template); if (is_array($templateCode) and !empty($templateCode['textonly'])) { $final_rendered = $templateCode['placeholder']; } else { if ($templateCache->isTemplateText()) { @eval($templateCode); } else { if ($templateCode !== false) { @(include $templateCode); } } } if ($config->render_debug) { restore_error_handler(); restore_exception_handler(); } if ($config->no_template_notices) { error_reporting($oldReporting); } // always replace placeholder for templates, as they are process by levels $templateCache->replacePlaceholders($final_rendered); if ($isParentTemplate) { // we only replace phrases/urls/nodetext, insert javascript and stylesheets at the parent template $this->renderDelayed($final_rendered, $isAjaxTemplateRender); //Store the configuration information in the session if (!empty(vB5_Config::instance()->php_sessions)) { if (session_status() == PHP_SESSION_NONE) { $expires = vB5_Config::instance()->session_expires; if (!empty($expires) and intval($expires)) { session_cache_expire(intval($expires)); } session_start(); $_SESSION['languageid'] = $preferred_languageid; $_SESSION['userid'] = vB5_User::get('userid'); } } } // debug info for the templates that have been used if ($config->debug) { array_pop(self::$renderedTemplatesStack); } // add template name to HTML source for debugging if (!empty($vboptions['addtemplatename']) and $vboptions['addtemplatename']) { $final_rendered = "<!-- BEGIN: {$this->template} -->{$final_rendered}<!-- END: {$this->template} -->"; } return $final_rendered; }
/** * Handles a [url] tag. Creates a link to another web page. * * @param string If tag has option, the displayable name. Else, the URL. * @param string If tag has option, the URL. * @param bool If this is for an image, just return the link * * @return string HTML representation of the tag. */ function handle_bbcode_url($text, $link, $image = false) { $rightlink = trim($link); if (empty($rightlink)) { // no option -- use param $rightlink = trim($text); } $rightlink = str_replace(array('`', '"', "'", '['), array('`', '"', ''', '['), $this->stripSmilies($rightlink)); // remove double spaces -- fixes issues with wordwrap $rightlink = str_replace(' ', '', $rightlink); if (!preg_match('#^[a-z0-9]+(?<!about|javascript|vbscript|data):#si', $rightlink)) { $rightlink = "http://{$rightlink}"; } if (!trim($link) or str_replace(' ', '', $text) == $rightlink) { $tmp = vB5_String::unHtmlSpecialChars($rightlink); if (vB_String::vbStrlen($tmp) > 55 and $this->isWysiwyg() == false) { $text = vB5_String::htmlSpecialCharsUni(vB5_String::vbChop($tmp, 36) . '...' . substr($tmp, -14)); } else { // under the 55 chars length, don't wordwrap this $text = str_replace(' ', '', $text); } } static $current_url, $current_host, $allowed, $friendlyurls = array(); if (!isset($current_url)) { $current_url = @vB5_String::parseUrl(self::$bbUrl); } $is_external = self::$urlNoFollow; if (self::$urlNoFollow) { if (!isset($current_host)) { $current_host = preg_replace('#:(\\d)+$#', '', self::$vBHttpHost); $allowed = preg_split('#\\s+#', self::$urlNoFollowWhiteList, -1, PREG_SPLIT_NO_EMPTY); $allowed[] = preg_replace('#^www\\.#i', '', $current_host); $allowed[] = preg_replace('#^www\\.#i', '', $current_url['host']); } $target_url = preg_replace('#^([a-z0-9]+:(//)?)#', '', $rightlink); foreach ($allowed as $host) { if (vB5_String::stripos($target_url, $host) !== false) { $is_external = false; } } } if ($image) { return array('link' => $rightlink, 'nofollow' => $is_external); } // standard URL hyperlink return "<a href=\"{$rightlink}\" target=\"_blank\"" . ($is_external ? ' rel="nofollow"' : '') . ">{$text}</a>"; }
/** * Determines if we are allowed to redirect to this URL, based * on Admin CP whitelist settings * * @param string The URL * * @return bool True if redirecting to this URL is allowed, false otherwise */ public static function allowRedirectToUrl($url) { if (empty($url)) { return false; } $options = vB5_Template_Options::instance(); if ($options->get('options.redirect_whitelist_disable')) { return true; } $foundurl = false; if ($urlinfo = @vB5_String::parseUrl($url)) { if (!$urlinfo['scheme']) { $foundurl = true; // Relative redirect. } else { $whitelist = array(); if ($options->get('options.redirect_whitelist')) { $whitelist = explode("\n", trim($options->get('options.redirect_whitelist'))); } // Add the base and core urls to the whitelist $baseinfo = @vB5_String::parseUrl(vB5_Template_Options::instance()->get('options.frontendurl')); $coreinfo = @vB5_String::parseUrl(vB5_Template_Options::instance()->get('options.bburl')); $baseurl = "{$baseinfo['scheme']}://{$baseinfo['host']}"; $coreurl = "{$coreinfo['scheme']}://{$coreinfo['host']}"; array_unshift($whitelist, strtolower($baseurl)); array_unshift($whitelist, strtolower($coreurl)); $vburl = strtolower($url); foreach ($whitelist as $urlx) { $urlx = trim($urlx); if ($vburl == strtolower($urlx) or strpos($vburl, strtolower($urlx) . '/', 0) === 0) { $foundurl = true; break; } } } } return $foundurl; }