/** * Receives either a template name or an array of template names to be fetched from the API * @param mixed $templateName */ protected function fetchTemplate($templateName) { if (!is_array($templateName)) { $templateName = array($templateName); } $response = Api_InterfaceAbstract::instance()->callApi('template', 'getTemplateIds', array('template_names' => $templateName)); $template_path = vB5_Template_Options::instance()->get('options.template_cache_path'); if (isset($response['ids'])) { foreach ($response['ids'] as $name => $templateid) { $file_name = "template{$templateid}.php"; //this matches the filename logic from template library saveTemplateToFileSystem and needs to //so that we come up with the same file in both cases. $real_path = realpath($template_path); if ($real_path === false) { $real_path = realpath(vB5_Config::instance()->core_path . '/' . $template_path); } if ($real_path === false) { $file = false; } else { $file = $real_path . "/{$file_name}"; } if ($templateid and $file and array_key_exists($templateid, $this->textOnlyTemplates)) { $placeholder = $this->getPlaceholder($templateid, '_to'); $this->textOnlyReplace[$placeholder] = file_get_contents($file); $this->cache[$name] = array('textonly' => 1, 'placeholder' => $placeholder); } else { $this->cache[$name] = $file; } } } }
public static function instance() { if (!isset(self::$instance)) { $c = __CLASS__; self::$instance = new $c(); self::$instance->getOptions(); } return self::$instance; }
public static function instance() { if (!isset(self::$instance)) { $c = __CLASS__; if (vB5_Template_Options::instance()->get('options.cache_templates_as_files')) { $c .= '_Filesystem'; } self::$instance = new $c(); } return self::$instance; }
/** * Gets the styles to be used ordered by preference */ protected function getStylePreference() { $this->stylePreference = array(); try { $router = vB5_ApplicationAbstract::instance()->getRouter(); if (!empty($router)) { $arguments = $router->getArguments(); // #1 check for a forced style in current route if (!empty($arguments) and !empty($arguments['forceStyleId']) and intval($arguments['forceStyleId'])) { $this->stylePreference[] = $arguments['forceStyleId']; } } } catch (vB5_Exception $e) { // the application instance might not be initialized yet, so just ignore this first check } // #2 check for a style cookie (style chooser in footer) // If style is set in querystring, the routing component will set this cookie (VBV-3322) $cookieStyleId = vB5_Cookie::get('userstyleid', vB5_Cookie::TYPE_UINT); if (!empty($cookieStyleId)) { $this->stylePreference[] = $cookieStyleId; } // #3 check for user defined style $userStyleId = vB5_User::get('styleid'); if (!empty($userStyleId)) { $this->stylePreference[] = $userStyleId; } // #4 check for a route style which is not forced if (!empty($arguments) and isset($arguments['routeStyleId']) and is_int($arguments['routeStyleId'])) { $this->stylePreference[] = $arguments['routeStyleId']; } // #5 check for the overall site default style $defaultStyleId = vB5_Template_Options::instance()->get('options.styleid'); if ($defaultStyleId) { $this->stylePreference[] = $defaultStyleId; } // Moved from Api_Interface_Collapsed::init, it was calling getPreferredStyleId when the forced // style set by the route wasn't ready yet. (see VBV-3324) if (!empty($this->stylePreference[0])) { // If style is -1 then fetch site default styleid if ($this->stylePreference[0] == '-1') { $this->stylePreference[0] = $defaultStyleId; } vB::getCurrentSession()->set('styleid', $this->stylePreference[0]); } }
/** * Redirects the user back to where they were after logging in */ public static function doLoginRedirect() { $url = ''; if (isset($_POST['url']) && $_POST['url']) { $url = base64_decode(trim($_POST['url'])); } if ($url) { $parse = parse_url($url); if (!$parse or empty($parse['scheme']) or $parse['scheme'] != 'http' and $parse['scheme'] != 'https') { $url = NULL; } } if (!$url or strpos($url, '/auth/') !== false or strpos($url, '/register') !== false) { $url = vB5_Template_Options::instance()->get('options.frontendurl'); } if (isset($_POST['associatefb'])) { $joinchar = strpos($url, '?') !== false ? '&' : '?'; $url = $url . $joinchar . 'dofbredirect=1'; } $templater = new vB5_Template('login_redirect'); $templater->register('url', filter_var($url, FILTER_SANITIZE_STRING)); echo $templater->render(); }
/** * Trims a string to the specified length while keeping whole words. * * @param string String to be trimmed. * @param integer Number of characters to aim for in the trimmed string. * @param boolean Append "..." to shortened text. * * @return string Trimmed string. */ public static function fetchTrimmedTitle($title, $chars = -1, $append = true) { if ($chars == -1) { $options = vB5_Template_Options::instance()->getOptions(); $chars = $options['options']['lastthreadchars']; } if ($chars) { // limit to 10 lines (\n{240}1234567890 does weird things to the thread preview) $titlearr = preg_split('#(\\r\\n|\\n|\\r)#', $title); $title = ''; $i = 0; foreach ($titlearr as $key) { $title .= "{$key} \n"; $i++; if ($i >= 10) { break; } } $title = trim($title); unset($titlearr); if (self::vbStrlen($title) > $chars) { $title = self::vbChop($title, $chars); if (($pos = strrpos($title, ' ')) !== false) { $title = substr($title, 0, $pos); } if ($append) { $title .= '...'; } } } return $title; }
/** * Activate an user who is in "Users Awaiting Email Confirmation" usergroup * This action is for Activate form submission */ public function actionActivateForm() { $post = array('username' => !empty($_POST['username']) ? trim($_POST['username']) : '', 'activateid' => !empty($_POST['activateid']) ? trim($_POST['activateid']) : ''); $api = Api_InterfaceAbstract::instance(); $result = $api->callApi('user', 'activateUserByUsername', array('username' => $post['username'], 'activateid' => $post['activateid'])); if (empty($result['errors'])) { $response['msg'] = $result; if ($response['msg'] == 'registration_complete') { $userinfo = $api->callApi('user', 'fetchByUsername', array('username' => $post['username'])); $routeProfile = $api->callApi('route', 'getUrl', array('route' => 'profile', 'data' => array('userid' => $userinfo['userid']), array())); $routeuserSettings = $api->callApi('route', 'getUrl', array('route' => 'settings', 'data' => array('tab' => 'profile'), array())); $routeAccount = $api->callApi('route', 'getUrl', array('route' => 'settings', 'data' => array('tab' => 'account'), array())); $response['msg_params'] = array($post['username'], vB5_Template_Options::instance()->get('options.frontendurl') . $routeProfile, vB5_Template_Options::instance()->get('options.frontendurl') . $routeAccount, vB5_Template_Options::instance()->get('options.frontendurl') . $routeuserSettings, vB5_Template_Options::instance()->get('options.frontendurl')); } else { $response['msg_params'] = array(); } } else { $response = $result; } $this->sendAsJson(array('response' => $response)); }
public function setRoutes() { $this->processQueryString(); //TODO: this is a very basic and straight forward way of parsing the URI, we need to improve it //$path = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : ''; if (isset($_GET['routestring'])) { $path = $_GET['routestring']; // remove it from $_GET unset($_GET['routestring']); // remove it from $_SERVER parse_str($_SERVER['QUERY_STRING'], $queryStringParameters); unset($queryStringParameters['routestring']); $_SERVER['QUERY_STRING'] = http_build_query($queryStringParameters, '', '&'); // Additional parameters of http_build_query() is required. See VBV-6272. } else { if (isset($_SERVER['PATH_INFO'])) { $path = $_SERVER['PATH_INFO']; } else { $path = ''; } } if (strlen($path) and $path[0] == '/') { $path = substr($path, 1); } //If there is an invalid image, js, or css request we wind up here. We can't process any of them if (strlen($path) > 2) { $ext = strtolower(substr($path, -4)); if ($ext == '.gif' or $ext == '.png' or $ext == '.jpg' or $ext == '.css' or strtolower(substr($path, -3)) == '.js') { header("HTTP/1.0 404 Not Found"); die(''); } } try { $message = ''; // Start with no error. $route = Api_InterfaceAbstract::instance()->callApi('route', 'getRoute', array('pathInfo' => $path, 'queryString' => $_SERVER['QUERY_STRING'])); } catch (Exception $e) { $message = $e->getMessage(); if ($message != 'no_vb5_database') { /* Some other exception happened */ vB5_ApplicationAbstract::handleException($e, true); } } if (isset($route['errors'])) { $message = $route['errors'][0][1]; if ($message != 'no_vb5_database') { /* Some other exception happened */ throw new vB5_Exception($message); } } if ($message == 'no_vb5_database') { /* Seem we dont have a valid vB5 database */ // TODO: as we removed baseurl from config.php, we need to find a way redirecting user to installer correctly. header('Location: core/install/index.php'); exit; } if (!empty($route)) { if (isset($route['redirect'])) { header('Location: ' . vB5_Template_Options::instance()->get('options.frontendurl') . $route['redirect'], true, 301); exit; } else { if (isset($route['internal_error'])) { vB5_ApplicationAbstract::handleException($route['internal_error']); } else { if (isset($route['banned_info'])) { vB5_ApplicationAbstract::handleBannedUsers($route['banned_info']); } else { if (isset($route['no_permission'])) { vB5_ApplicationAbstract::handleNoPermission(); } else { if (isset($route['forum_closed'])) { vB5_ApplicationAbstract::showMsgPage('', $route['forum_closed'], 'bbclosedreason'); // Use 'bbclosedreason' as state param here to match the one specified in vB_Api_State::checkBeforeView() die; } else { $this->routeId = $route['routeid']; $this->routeGuid = $route['routeguid']; $this->controller = $route['controller']; $this->action = $route['action']; $this->template = $route['template']; $this->arguments = $route['arguments']; $this->queryParameters = $route['queryParameters']; $this->pageKey = $route['pageKey']; if (!empty($route['userAction']) and is_array($route['userAction'])) { $this->userAction['action'] = array_shift($route['userAction']); $this->userAction['params'] = $route['userAction']; } else { $this->userAction = false; } $this->breadcrumbs = $route['breadcrumbs']; $this->headlinks = $route['headlinks']; if (!in_array($this->action, $this->whitelist)) { vB5_ApplicationAbstract::checkState($route); } return; } } } } } } else { // if no route was matched, try to parse route as /controller/method $stripped_path = preg_replace('/[^a-z0-9\\/-]+/i', '', trim(strval($path), '/')); if (strpos($stripped_path, '/')) { list($controller, $method) = explode('/', strtolower($stripped_path), 2); } else { $controller = $stripped_path; $method = 'index'; } $controller = preg_replace_callback('#(?:^|-)(.)#', function ($matches) { return strtoupper($matches[1]); }, strtolower($controller)); $method = preg_replace_callback('#(?:^|-)(.)#', function ($matches) { return strtoupper($matches[1]); }, strtolower($method)); $controllerClass = 'vB5_Frontend_Controller_' . $controller; $controllerMethod = 'action' . $method; if (class_exists($controllerClass) and method_exists($controllerClass, $controllerMethod)) { $this->controller = strtolower($controller); $this->action = $controllerMethod; $this->template = ''; $this->arguments = array(); $this->queryParameters = array(); if (!in_array($this->action, $this->whitelist)) { vB5_ApplicationAbstract::checkState(array('controller' => $this->controller, 'action' => $this->action)); } return; } } //this could be a legacy file that we need to proxy. The relay controller will handle //cases where this is not a valid file. Only handle files in the "root directory". We'll //handle deeper paths via more standard routes. if (strpos($path, '/') === false) { $this->controller = 'relay'; $this->action = 'legacy'; $this->template = ''; $this->arguments = array($path); $this->queryParameters = array(); return; } vB5_ApplicationAbstract::checkState(); throw new vB5_Exception_404("invalid_page_url"); }
public function actionLogout() { $api = Api_InterfaceAbstract::instance(); $api->callApi('user', 'logout', array($_REQUEST['logouthash'])); //delete all cookies with cookiePrefix vB5_Cookie::deleteAll(); // @todo: this should redirect the user back to where they were header('Location: ' . vB5_Template_Options::instance()->get('options.frontendurl')); exit; }
/** gets a gallery and returns in json format for slideshow presentation. * ***/ public function actionGallery() { //We need a nodeid if (!empty($_REQUEST['nodeid'])) { $nodeid = $_REQUEST['nodeid']; } else { if (!empty($_REQUEST['id'])) { $nodeid = $_REQUEST['id']; } else { return ''; } } //get the raw data. $api = Api_InterfaceAbstract::instance(); $config = vB5_Config::instance(); $phraseApi = vB5_Template_Phrase::instance(); $gallery = array('photos' => array()); switch (intval($nodeid)) { case 0: case -1: //All Videos throw new vB_Exception_Api('invalid_request'); case -2: //All non-Album photos and attachments if ((empty($_REQUEST['userid']) or !intval($_REQUEST['userid'])) and (empty($_REQUEST['channelid']) or !intval($_REQUEST['channelid']))) { throw new vB_Exception_Api('invalid_request'); } $galleryData = $api->callApi('profile', 'getSlideshow', array(array('userid' => isset($_REQUEST['userid']) ? intval($_REQUEST['userid']) : 0, 'channelid' => isset($_REQUEST['channelid']) ? intval($_REQUEST['channelid']) : 0, 'dateFilter' => isset($_REQUEST['dateFilter']) ? $_REQUEST['dateFilter'] : '', 'searchlimit' => isset($_REQUEST['perpage']) ? $_REQUEST['perpage'] : '', 'startIndex' => isset($_REQUEST['startIndex']) ? $_REQUEST['startIndex'] : ''))); if (empty($galleryData)) { return array(); } foreach ($galleryData as $photo) { $titleVm = !empty($photo['parenttitle']) ? $photo['parenttitle'] : $photo['startertitle']; $route = $photo['routeid']; if ($photo['parenttitle'] == 'No Title' and $photo['parentsetfor'] > 0) { $titleVm = $phraseApi->getPhrase('visitor_message_from_x', array($photo['authorname'])); $route = 'visitormessage'; } $userLink = vB5_Template_Options::instance()->get('options.frontendurl') . $api->callApi('route', 'getUrl', array('route' => 'profile', 'data' => array('userid' => $photo['userid'], 'username' => $photo['authorname']), 'extra' => array())); $topicLink = vB5_Template_Options::instance()->get('options.frontendurl') . '/' . $api->callApi('route', 'getUrl', array('route' => $route, 'data' => array('title' => $titleVm, 'nodeid' => $photo['parentnode']), 'extra' => array())); $title = $photo['title'] != null ? $photo['title'] : ''; $htmltitle = $photo['htmltitle'] != null ? $photo['htmltitle'] : ''; $photoTypeid = vB_Types::instance()->getContentTypeID('vBForum_Photo'); $attachTypeid = vB_Types::instance()->getContentTypeID('vBForum_Attach'); if ($photo['contenttypeid'] === $photoTypeid) { $queryVar = 'photoid'; } else { if ($photo['contenttypeid'] === $attachTypeid) { $queryVar = 'id'; } } $gallery['photos'][] = array('title' => $title, 'htmltitle' => $htmltitle, 'url' => vB5_Template_Options::instance()->get('options.frontendurl') . '/filedata/fetch?' . $queryVar . '=' . intval($photo['nodeid']), 'thumb' => vB5_Template_Options::instance()->get('options.frontendurl') . '/filedata/fetch?' . $queryVar . '=' . intval($photo['nodeid']) . "&thumb=1", 'links' => $phraseApi->getPhrase('photos_by_x_in_y_linked', array($userLink, $photo['authorname'], $topicLink, htmlspecialchars($titleVm))) . "<br />\n"); } $this->sendAsJson($gallery); return; default: $galleryData = $api->callApi('content_gallery', 'getContent', array('nodeid' => $nodeid)); if (!empty($galleryData) and !empty($galleryData[$nodeid]['photo'])) { foreach ($galleryData[$nodeid]['photo'] as $photo) { $userLink = vB5_Template_Options::instance()->get('options.frontendurl') . $api->callApi('route', 'getUrl', array('route' => 'profile', 'data' => array('userid' => $photo['userid'], 'username' => $photo['authorname']), 'extra' => array())); $gallery['photos'][] = array('title' => $photo['title'], 'htmltitle' => $photo['htmltitle'], 'url' => vB5_Template_Options::instance()->get('options.frontendurl') . '/filedata/fetch?photoid=' . intval($photo['nodeid']), 'thumb' => vB5_Template_Options::instance()->get('options.frontendurl') . '/filedata/fetch?photoid=' . intval($photo['nodeid']) . "&thumb=1", 'links' => $phraseApi->getPhrase('photos_by_x_in_y_linked', array($userLink, $photo['authorname'], 'javascript:$(\'#slideshow-dialog\').dialog(\'close\');void(0);', htmlspecialchars($photo['startertitle']))) . "<br />\n"); } $this->sendAsJson($gallery); } return; } }
function __construct() { $vboptions = vB5_Template_Options::instance()->getOptions(); $this->vboptions = $vboptions['options']; }
/** * Returns the height of a block of text in pixels (assuming 16px per line). * Limited by your "codemaxlines" setting (if > 0). * * @param string Block of text to find the height of * * @return int Number of lines */ protected function fetchBlockHeight($code) { $options = vB5_Template_Options::instance(); $codeMaxLines = $options->get('options.codemaxlines'); // establish a reasonable number for the line count in the code block $numlines = max(substr_count($code, "\n"), substr_count($code, "<br />")) + 1; // set a maximum number of lines... if ($numlines > $codeMaxLines and $codeMaxLines > 0) { $numlines = $codeMaxLines; } else { if ($numlines < 1) { $numlines = 1; } } // return height in pixels return $numlines; // removed multiplier }
/** * Get facebook related options to pass to the add node apis * * @return array * */ protected function getFacebookOptionsForAddNode() { return array('fbpublish' => isset($_POST['fbpublish']) && intval($_POST['fbpublish']) === 1, 'baseurl' => vB5_Template_Options::instance()->get('options.frontendurl')); }
public function index($pageid) { //the api init can redirect. We need to make sure that happens before we echo anything $api = Api_InterfaceAbstract::instance(); $top = ''; // We should not cache register page for guest. See VBV-7695. if (vB5_Request::get('cachePageForGuestTime') > 0 and !vB5_User::get('userid') and (empty($_REQUEST['routestring']) or $_REQUEST['routestring'] != 'register' and $_REQUEST['routestring'] != 'lostpw')) { // languageid should be in the pagekey to fix VBV-8095 $fullPageKey = 'vBPage_' . md5(serialize($_REQUEST)) . '_' . vB::getCurrentSession()->get('languageid'); $styleid = vB5_Cookie::get('userstyleid', vB5_Cookie::TYPE_UINT); if (!empty($styleid)) { $fullPageKey .= '_' . $styleid; } $fullPage = vB_Cache::instance(vB_Cache::CACHE_LARGE)->read($fullPageKey); if (!empty($fullPage)) { echo $fullPage; exit; } } $preheader = vB5_ApplicationAbstract::getPreheader(); $top .= $preheader; if (vB5_Request::get('useEarlyFlush')) { echo $preheader; flush(); } $router = vB5_ApplicationAbstract::instance()->getRouter(); $arguments = $router->getArguments(); $userAction = $router->getUserAction(); $pageKey = $router->getPageKey(); $api->callApi('page', 'preload', array($pageKey)); if (!empty($userAction)) { $api->callApi('wol', 'register', array($userAction['action'], $userAction['params'], $pageKey, vB::getRequest()->getScriptPath(), !empty($arguments['nodeid']) ? $arguments['nodeid'] : 0)); } if (isset($arguments['pagenum'])) { $arguments['pagenum'] = intval($arguments['pagenum']) > 0 ? intval($arguments['pagenum']) : 1; } $pageid = (int) (isset($arguments['pageid']) ? $arguments['pageid'] : (isset($arguments['contentid']) ? $arguments['contentid'] : 0)); if ($pageid < 1) { // @todo This needs to output a user-friendly "page not found" page throw new Exception('Could not find page.'); } $page = $api->callApi('page', 'fetchPageById', array($pageid, $arguments)); if (!$page) { // @todo This needs to output a user-friendly "page not found" page throw new Exception('Could not find page.'); } // Go to the first new / unread post for this user in this topic if (!empty($_REQUEST['goto']) and $_REQUEST['goto'] == 'newpost' and !empty($arguments['nodeid']) and !empty($arguments['channelid'])) { if ($this->vboptions['threadmarking'] and vB5_User::get('userid')) { // Database read marking $channelRead = $api->callApi('node', 'getNodeReadTime', array($arguments['channelid'])); $topicRead = $api->callApi('node', 'getNodeReadTime', array($arguments['nodeid'])); $topicView = max($topicRead, $channelRead, time() - $this->vboptions['markinglimit'] * 86400); } else { // Cookie read marking $topicView = intval(vB5_Cookie::fetchBbarrayCookie('discussion_view', $arguments['nodeid'])); if (!$topicView) { $topicView = vB5_User::get('lastvisit'); } } $topicView = intval($topicView); // Get the first unread reply $goToNodeId = $api->callApi('node', 'getFirstChildAfterTime', array($arguments['nodeid'], $topicView)); if (empty($goToNodeId)) { $thread = $api->callApi('node', 'getNodes', array(array($arguments['nodeid']))); if (!empty($thread) and isset($thread[$arguments['nodeid']])) { $goToNodeId = $thread[$arguments['nodeid']]['lastcontentid']; } } if ($goToNodeId) { // Redirect to the new post $urlCache = vB5_Template_Url::instance(); $urlKey = $urlCache->register($router->getRouteId(), array('nodeid' => $arguments['nodeid']), array('p' => $goToNodeId)); $replacements = $urlCache->finalBuildUrls(array($urlKey)); $url = $replacements[$urlKey]; if ($url) { $url .= '#post' . $goToNodeId; if (headers_sent()) { echo '<script type="text/javascript">window.location = "' . $url . '";</script>'; } else { header('Location: ' . $url); } exit; } } } $page['routeInfo'] = array('routeId' => $router->getRouteId(), 'arguments' => $arguments, 'queryParameters' => $router->getQueryParameters()); $page['crumbs'] = $router->getBreadcrumbs(); $page['headlinks'] = $router->getHeadLinks(); $page['pageKey'] = $pageKey; // default value for pageSchema $page['pageSchema'] = 'http://schema.org/WebPage'; $queryParameters = $router->getQueryParameters(); /* * VBV-12506 * this is where we would add other things to clean up dangerous query params. * For VBV-12486, I'll just unset anything here that can't use vb:var in the templates, * but really we should just make a whitelist of expected page object parameters that * come from the query string and unset EVERYTHING else. For the expected ones, we * should also force the value into the expected (and hopefully safer) range */ /* * VBV-12506 * $doNotReplaceWithQueryParams is a list of parameters that the page object usually * gets naturally/internally, and we NEVER want to replace with a user provided query * parameter. (In fact, *when* exactly DO we want to do this???) * If we don't do this, it's a potential XSS vulnerability for the items that we * cannot send through vb:var for whatever reason (title for ex) * and even if they *are* sent through vb:var, the replacements can sometimes just * break the page even when it's sent through vb:var (for example, ?pagetemplateid=%0D, * the new line this inserts in var pageData = {...} in the header template tends to * break things (tested on Chrome). * Furthermore, any script that uses the pageData var would get the user injected data * that might cause more problems down the line. * Parameter Notes: * 'titleprefix' * As these two should already be html escaped, we don't want to double escape * them. So we can't us vb:var in the templates. As such, we must prevent a * malicious querystring from being injected into the page object here. * 'title' * Similar to above, but channels are allowed to have HTML in the title, so * they are intentinoally not escaped in the DB, and the templates can't use * vb:var. * 'pageid', 'channelid', 'nodeid' * These are usually set in the arguments, so the array_merge below usually * takes care of not passing a pageid query string through to the page object, * but I'm leaving them in just in case. */ $doNotReplaceWithQueryParams = array('titleprefix', 'title', 'pageid', 'channelid', 'nodeid', 'pagetemplateid', 'url', 'pagenum', 'tagCloudTitle'); foreach ($doNotReplaceWithQueryParams as $key) { unset($queryParameters[$key]); } $arguments = array_merge($queryParameters, $arguments); foreach ($arguments as $key => $value) { $page[$key] = $value; } $options = vB5_Template_Options::instance(); $page['phrasedate'] = $options->get('miscoptions.phrasedate'); $page['optionsdate'] = $options->get('miscoptions.optionsdate'); // if no meta description, use node data or global one instead, prefer node data if (empty($page['metadescription']) and !empty($page['nodedescription'])) { $page['metadescription'] = $page['nodedescription']; } if (empty($page['metadescription'])) { $page['metadescription'] = $options->get('options.description'); } $config = vB5_Config::instance(); // Non-persistent notices @todo - change this to use vB_Cookie $page['ignore_np_notices'] = vB5_ApplicationAbstract::getIgnoreNPNotices(); $templateCache = vB5_Template_Cache::instance(); $templater = new vB5_Template($page['screenlayouttemplate']); //IMPORTANT: If you add any variable to the page object here, // please make sure you add them to other controllers which create page objects. // That includes at a minimum the search controller (in two places currently) // and vB5_ApplicationAbstract::showErrorPage $templater->registerGlobal('page', $page); $page = $this->outputPage($templater->render(), false); $fullPage = $top . $page; if (!empty($fullPageKey) and is_string($fullPageKey)) { vB_Cache::instance(vB_Cache::CACHE_LARGE)->write($fullPageKey, $fullPage, vB5_Request::get('cachePageForGuestTime'), 'vbCachedFullPage'); } // these are the templates rendered for this page $loadedTemplates = vB5_Template::getRenderedTemplates(); $api->callApi('page', 'savePreCacheInfo', array($pageKey)); if (!vB5_Request::get('useEarlyFlush')) { echo $fullPage; } else { echo $page; } }
/** * Determines the correct base path for CSS links in the markup * * @param bool Whether or not CSS templates are stored as files * @param string Text direction, 'ltr' or 'rtl' * @param int Style ID for the current style * * @return string The base path for CSS links. */ private function getCssPath($storecssasfile, $textdirection, $styleid) { $vboptions = vB5_Template_Options::instance()->getOptions(); $vboptions = $vboptions['options']; $csspath = ""; if ($storecssasfile) { if (!empty($vboptions['cssfilelocation'])) { $fileLocation = 'core' . $vboptions['cssfilelocation'] . '/style'; } else { $fileLocation = 'core/clientscript/vbulletin_css/style'; } $csspath = $fileLocation . str_pad($styleid, 5, '0', STR_PAD_LEFT) . $textdirection[0] . '/'; } else { $csspath = 'css.php?styleid=' . $styleid . '&td=' . $textdirection . '&sheet='; } $baseurl = $vboptions['cdnurl']; if (!$baseurl) { $baseurl = $vboptions['frontendurl']; } // Ensure that the scheme (http or https) matches the current page request we're on. // If the login URL uses https, then the resources on that page, in this case the // CSS, need to use it as well. VBV-12286 $baseurl = preg_replace('#^https?://#i', '', $baseurl); $baseurl = vB::getRequest()->getVbUrlScheme() . '://' . $baseurl; return $baseurl . '/' . $csspath; }
/** Fetch the photo tab content for the photo selector * ***/ public function actiongetPhotoTabContent() { $user = vB::getCurrentSession()->fetch_userinfo(); if (empty($user) or empty($user['userid'])) { //@TODO: return not logged in status? return; } $nodeid = isset($_GET['nodeid']) ? intval($_GET['nodeid']) : 0; $nodeid = $nodeid ? $nodeid : -2; $photosPerRow = isset($_GET['ppr']) ? intval($_GET['ppr']) : 2; $tabContent = ""; $api = Api_InterfaceAbstract::instance(); $nodes = $api->callApi('profile', 'getAlbum', array(array('nodeid' => $nodeid, 'page' => 1, 'perpage' => 60, 'userid' => $user['userid']))); foreach ($nodes as $nodeid => $node) { $items = array(); $photoFiledataids = array(); $attachFiledataids = array(); $photoCount = 0; foreach ($node['photo'] as $photoid => $photo) { // if it's an attachment, we use the 'id=' param. If it's a photo, 'photoid=' $paramname = (isset($photo['isAttach']) and $photo['isAttach']) ? 'id' : 'photoid'; $items[$photoid] = array('title' => $photo['title'], 'imgUrl' => vB5_Template_Options::instance()->get('options.frontendurl') . '/filedata/fetch?' . $paramname . '=' . $photoid . '&type=thumb'); if (!isset($photo['filedataid']) or !$photo['filedataid']) { if ($photo['isAttach']) { $attachFiledataids[] = $photoid; } else { $photoFiledataids[] = $photoid; } } else { $items[$photoid]['filedataid'] = $photo['filedataid']; } if ($photosPerRow and ++$photoCount % $photosPerRow == 0) { $items[$photoid]['lastinrow'] = true; } } if (!empty($photoFiledataids)) { $photoFileids = $api->callApi('filedata', 'fetchPhotoFiledataid', array($photoFiledataids)); foreach ($photoFileids as $nodeid => $filedataid) { $items[$nodeid]['filedataid'] = $filedataid; } } if (!empty($attachFiledataids)) { $attachFileids = $api->callApi('filedata', 'fetchAttachFiledataid', array($attachFiledataids)); foreach ($attachFileids as $nodeid => $filedataid) { $items[$nodeid]['filedataid'] = $filedataid; } } $templater = new vB5_Template('photo_item'); $templater->register('items', $items); $templater->register('photoSelector', 1); $tabContent = $templater->render(); } $this->outputPage($tabContent); }
protected static function loadConfig() { if (self::$cookiePrefix !== null) { return; } $config = vB5_Config::instance(); // these could potentially all be config options self::$enabled = $config->cookie_enabled !== false; self::$cookiePrefix = $config->cookie_prefix; $options = vB5_Template_Options::instance(); self::$path = $options->get('options.cookiepath'); self::$domain = $options->get('options.cookiedomain'); self::$secure = ((isset($_SERVER['SERVER_PORT']) and 443 === intval($_SERVER['SERVER_PORT']) or isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] and $_SERVER['HTTPS'] != 'off') and (isset($url['scheme']) and $url['scheme'] == 'https')); }
/** * Handle any delayed rendering. Currently delayed urls and node texts. * * @param string * @param boolean true if we are rendering for a call to /ajax/render/ and we want CSS <link>s separate * * @return string */ protected function renderDelayed(&$final_rendered_orig, $isAjaxTemplateRender = false) { $javascript = vB5_Template_Javascript::instance(); $javascript->insertJs($final_rendered_orig); $javascript->resetPending(); $stylesheet = vB5_Template_Stylesheet::instance(); $stylesheet->insertCss($final_rendered_orig, $isAjaxTemplateRender); $stylesheet->resetPending(); $link = vB5_Template_Headlink::instance(); $link->insertLinks($final_rendered_orig); $link->resetPending(); $phrase = vB5_Template_Phrase::instance(); $phrase->replacePlaceholders($final_rendered_orig); $phrase->resetPending(); // we do not reset pending urls, since they may be required by nodetext vB5_Template_Url::instance()->replacePlaceholders($final_rendered_orig); $nodeText = vB5_Template_NodeText::instance(); $nodeText->replacePlaceholders($final_rendered_orig); $nodeText->resetPending(); $templateCache = vB5_Template_Cache::instance(); $templateCache->replaceTextOnly($final_rendered_orig); //We should keep the debug info for truly last. if (vB5_Frontend_Controller_Bbcode::needDebug()) { $config = vB5_Config::instance(); if (!$config->debug) { return $final_rendered_orig; } self::$renderedTemplateNames[] = 'debug_info'; self::$renderedTemplates[] = array('templateName' => 'debug_info', 'isParentTemplate' => (bool) 0, 'indent' => str_repeat('|----', 2)); $user = vB5_User::instance(); $this->register('user', $user, true); extract(self::$globalRegistered, EXTR_SKIP | EXTR_REFS); extract($this->registered, EXTR_OVERWRITE | EXTR_REFS); $vboptions = vB5_Template_Options::instance()->getOptions(); $vboptions = $vboptions['options']; $renderedTemplates = array('count' => count(self::$renderedTemplates), 'countUnique' => count(array_unique(self::$renderedTemplateNames)), 'templates' => self::$renderedTemplates, 'styleid' => vB5_Template_Stylevar::instance()->getPreferredStyleId()); $cssDebugLog = vB5_Template_Stylesheet::getDebugLog(); $jsDebugLog = vB5_Template_Javascript::instance()->getDebugLog(); $templateCode = $templateCache->getTemplate('debug_info'); if ($templateCache->isTemplateText()) { @eval($templateCode); } else { @(include $templateCode); } $phrase->replacePlaceholders($final_rendered); $phrase->resetPending(); $final_rendered_orig = str_replace('<!-DebugInfo-->', $final_rendered, $final_rendered_orig); } }
/** inserts the Bing Ownership Verification Meta Tag, if set * * @return string Either empty string to the Bing Ownership Verification Meta tag **/ public static function getBingVerificationTag() { $vboptions = vB5_Template_Options::instance()->getOptions(); if (empty($vboptions['options']['bing_ownership_verification_enable']) or empty($vboptions['options']['bing_ownership_verification_tag'])) { return ''; } return $vboptions['options']['bing_ownership_verification_tag']; }
/** * * @param array $schemaInfo * - id (string) * - itemprop (string) * - itemscope (bool) * - itemref (string) * - itemtype (string) * - datetime (int) * - tag (string) * @return string */ public static function parseSchema($schemaInfo = array()) { $schemaEnabled = vB5_Template_Options::instance()->get('options.schemaenabled'); $attributes = array('id', 'itemprop', 'itemscope', 'itemref', 'itemtype', 'datetime', 'content', 'rel'); $allowedTags = array('meta', 'link'); if ($schemaEnabled and !empty($schemaInfo) and is_array($schemaInfo)) { $output = ''; foreach ($attributes as $name) { if (!empty($schemaInfo[$name])) { switch ($name) { case 'itemscope': $output .= " itemscope"; break; case 'datetime': $output .= " {$name}=\"" . date('Y-m-d\\TH:i:s', $schemaInfo[$name]) . '"'; break; default: $output .= " {$name}=\"{$schemaInfo[$name]}\""; break; } } } if (!empty($schemaInfo['tag']) and in_array($schemaInfo['tag'], $allowedTags)) { return "<{$schemaInfo['tag']} {$output} />"; } else { return trim($output); } } else { return ''; } }
public function actionSavepage() { $input = $_POST['input']; $url = $_POST['url']; //parse_url doesn't work on relative urls and I don't want to assume that //we have an absolute url. We probably don't have a query string, but bad assumptions //about the url are what got us into this problem to begin with. $parts = explode('?', $url, 2); $url = $parts[0]; $query = ''; if (sizeof($parts) == 2) { $query = $parts[1]; } if (preg_match('#^http#', $url)) { $base = vB5_Template_Options::instance()->get('options.frontendurl'); if (preg_match('#^' . preg_quote($base, '#') . '#', $url)) { $url = substr($url, strlen($base) + 1); } } $api = Api_InterfaceAbstract::instance(); $route = $api->callApi('route', 'getRoute', array('pathInfo' => $url, 'queryString' => $query)); //if we have a redirect try to find the real route -- this should only need to handle one layer //and if that also gets a redirect things are broken somehow. if (!empty($route['redirect'])) { $route = $api->callApi('route', 'getRoute', array('pathInfo' => ltrim($route['redirect'], '/'), 'queryString' => $query)); } $result = $api->callApi('page', 'pageSave', array($input)); if (empty($result['errors'])) { //$url = $api->callApi('route', 'getUrl', array('route' => 'profile', 'data' => array('userid' => $loginInfo['userid']), array())); $page = $api->callApi('page', 'fetchPageById', array('pageid' => $result['pageid'], 'routeData' => $route['arguments'])); $result['url'] = $page['url']; } $this->sendAsJson($result); }
/** * Fetch node's preview * */ public function actionFetchNodePreview() { $preview = ''; $nodeid = isset($_REQUEST['nodeid']) ? intval($_REQUEST['nodeid']) : array(); if (!empty($nodeid)) { if (!vb::getUserContext()->getChannelPermission('forumpermissions', 'canviewthreads', $nodeid)) { return ''; } $contenttypes = vB_Types::instance()->getContentTypes(); $typelist = array(); foreach ($contenttypes as $key => $type) { $typelist[$type['id']] = $key; } $api = Api_InterfaceAbstract::instance(); $contentTypes = array('vBForum_Text', 'vBForum_Gallery', 'vBForum_Poll', 'vBForum_Video', 'vBForum_Link'); $nodes = $api->callApi('node', 'getNodeContent', array($nodeid)); $node = $nodes[$nodeid]; $contentType = $typelist[$node['contenttypeid']]; if (in_array($contentType, $contentTypes)) { $preview = vB5_Template_NodeText::instance()->fetchOneNodePreview($nodeid, $api); } $previewLength = vB5_Template_Options::instance()->get('options.threadpreview'); if (strlen($preview) > $previewLength) { $preview = substr($preview, 0, $previewLength); } } return $preview; }
/** * Handles an [img] tag. * * @param string The text to search for an image in. * @param string Whether to parse matching images into pictures or just links. * * @return string HTML representation of the tag. */ function handle_bbcode_img($bbcode, $do_imgcode, $has_img_code = false, $fulltext = '', $forceShowImages = false) { $sessionurl = self::$sessionUrl; $showImages = (self::getUserValue('userid') == 0 or self::getUserValue('showimages') or $forceShowImages); /* Do search on $fulltext, which would be the entire article, not just a page of the article which would be in $page */ if (!$fulltext) { $fulltext = $bbcode; } if ($has_img_code & self::BBCODE_HAS_ATTACH and preg_match_all('#\\[attach(?:=(right|left|config))?\\]([[:alnum:]]+)\\[/attach\\]#i', $fulltext, $matches)) { $legacyIds = $attachmentIds = array(); foreach ($matches[2] as $key => $attachmentid) { $align = $matches[1]["{$key}"]; $search[] = '#\\[attach(' . (!empty($align) ? '=' . $align : '') . ')\\](' . $attachmentid . ')\\[/attach\\]#i'; // We need to decide whether it's a legacy attachment or a vB5 one if (preg_match('#^n(\\d+)$#', $attachmentid, $matches2)) { // if the id has 'n' as prefix, it's a nodeid $attachmentIds[] = intval($matches2[1]); } else { // it's a legacy attachmentid $legacyIds[] = intval($attachmentid); } } if (!empty($legacyIds)) { $this->oldAttachments = vB_Api::instanceInternal('filedata')->fetchLegacyAttachments($legacyIds); $attachmentIds += array_values($this->oldAttachments); } // we may already have the attachments (see vB5_Template_NodeText) if (!empty($this->attachments)) { $attachmentIds = array_diff(array_unique($attachmentIds), array_keys($this->attachments)); } if (!empty($attachmentIds)) { $attachments = vB_Api::instanceInternal('filedata')->fetchFiledataByid($attachmentIds); $this->setAttachments($attachments); } $bbcode = preg_replace_callback($search, array($this, 'attachReplaceCallback'), $bbcode); } /* VBV-12051 - Check for legacy [IMG] code using filedataid Since we know that the filedata/fetch?filedataid URL only works for publicview filedata (generally channel icons, forum logo, sigpics, theme icons and the like), let's assume that any [IMG] tag with a filedataid that's used by any *remaining* attachments (after above attachReplaceCallback) is an incorrect inline-inserted attachment image, and replace them with the proper image tags. This can cause some weirdness, like multiple [attach] bbcodes with the same nodeid, but I think this is better than the current broken behavior (where filedataid img will only show for the poster, and the attachment associated with the filedataid is listed in the bbcode_attachment_list) */ $baseURL = vB5_Template_Options::instance()->get('options.frontendurl'); /* $expectedPrefix = preg_quote($baseURL . '/filedata/fetch?filedataid=', '#'); $regex = '#\[img\]\s*' . $expectedPrefix . '(?<filedataid>[0-9]+?)(?<extra>[&\#][^*\r\n]*|[a-z0-9/\\._\- !]*)\[/img\]#iU'; */ $expectedPrefix = preg_quote($baseURL . '/filedata/fetch?', '#'); $regex = '#\\[img\\]\\s*' . $expectedPrefix . '(?<querystring>[^\\s]*filedataid=(?<filedataid>[0-9]+?)[^\\s]*)\\s*\\[/img\\]#iU'; if ($has_img_code & self::BBCODE_HAS_IMG and preg_match_all($regex, $bbcode, $matches)) { if (!empty($matches['filedataid'])) { $searchForCallback = array(); $searchForStrReplace = array(); $replaceForStrReplace = array(); $this->delayedUnsetAttachments = array(); $oldUnsetattach = $this->unsetattach; $this->unsetattach = false; foreach ($matches['filedataid'] as $key => $filedataid) { if (!empty($this->filedataidsToAttachmentids[$filedataid])) { // There might be multiple attachments using the filedataid, but we just have // no way of knowing which this one is supposed to be. Let's just walk through them. $nodeid = current($this->filedataidsToAttachmentids[$filedataid]); if (false === next($this->filedataidsToAttachmentids[$filedataid])) { reset($this->filedataidsToAttachmentids[$filedataid]); } $searchForStrReplace[$key] = $matches[0][$key]; // 1 is align/config, 2 is "n{nodeid}" $matchesForCallback = array(1 => '', 2 => "n{$nodeid}"); // grab size if provided in query string. $querydata = array(); $querystring = vB_String::unHtmlSpecialChars($matches['querystring'][$key]); parse_str($querystring, $querydata); if (!empty($querydata['type'])) { $matchesForCallback['settings'] = array('size' => $querydata['type']); } elseif (!empty($querydata['thumb'])) { $matchesForCallback['settings'] = array('size' => 'thumb'); } $replaceForStrReplace[$key] = $this->attachReplaceCallback($matchesForCallback); } } $this->unsetattach = $oldUnsetattach; /* Temporarily turning off unsetattach & then doing the unset at the very end is required to handle the edge case where multiple [img] bbcodes with the SAME filedataid exists. If we don't turn off unsetattach, only the first instance will be replaced with an image tag. If we turn off unsetattach and don't do this delayed unsetting, the attachment that was "used" by the [img] matches will still remain to be listed in the attachments box. */ if (!empty($this->delayedUnsetAttachments) and $this->unsetattach) { foreach ($this->delayedUnsetAttachments as $arr) { $attachmentid = $arr['attachmentid']; $filedataid = $arr['filedataid']; unset($this->attachments["{$attachmentid}"], $this->filedataidsToAttachmentids[$filedataid][$attachmentid]); } } if (!empty($replaceForStrReplace)) { $bbcode = str_replace($searchForStrReplace, $replaceForStrReplace, $bbcode); } } } if ($has_img_code & self::BBCODE_HAS_IMG) { if ($do_imgcode and $showImages) { // do [img]xxx[/img] $bbcode = preg_replace_callback('#\\[img\\]\\s*(https?://([^*\\r\\n]+|[a-z0-9/\\._\\- !]+))\\[/img\\]#iU', array($this, 'handleBbcodeImgMatchCallback'), $bbcode); } else { $bbcode = preg_replace_callback('#\\[img\\]\\s*(https?://([^*\\r\\n]+|[a-z0-9/\\._\\- !]+))\\[/img\\]#iU', array($this, 'handleBbcodeUrlCallback'), $bbcode); } } if ($has_img_code & self::BBCODE_HAS_SIGPIC) { $bbcode = preg_replace_callback('#\\[sigpic\\](.*)\\[/sigpic\\]#siU', array($this, 'handleBBCodeSicpicPregReplace'), $bbcode); } if ($has_img_code & self::BBCODE_HAS_RELPATH) { $bbcode = str_replace('[relpath][/relpath]', vB_String::htmlSpecialCharsUni(vB5_Request::get('vBUrlClean')), $bbcode); } return $bbcode; }
/** * Builds the Javascript links needed to include the passed JS files in the markup. * * @param array Array of Javascript files * * @return string The complete Javascript links to insert into the markup. */ public function insertJsInclude($scripts) { $this->previouslyIncluded = array_unique(array_merge($this->previouslyIncluded, $scripts)); $config = vB5_Config::instance(); $vboptions = vB5_Template_Options::instance()->getOptions(); $vboptions = $vboptions['options']; if (!isset($this->jsbundles)) { $this->loadJsBundles(); } if ($config->no_js_bundles) { foreach ($scripts as $bundle) { $removed = false; if (strpos($bundle, 'js/') === 0) { $removed = true; $bundle = substr($bundle, 3); } if (isset($this->jsbundles[$bundle])) { foreach ($this->jsbundles[$bundle] as $jsfile) { $expanded[] = $jsfile; } } else { if ($removed) { $expanded[] = 'js/' . $bundle; } else { $expanded[] = $bundle; } } } if (!empty($expanded)) { $scripts = $expanded; } } $baseurl_cdn = $vboptions['cdnurl']; if (empty($baseurl_cdn)) { $baseurl_cdn = $vboptions['frontendurl']; } // Ensure that the scheme (http or https) matches the current page request we're on. // If the login URL uses https, then the resources on that page, in this case the // Javascript, need to use it as well. VBV-12286 $baseurl_cdn = preg_replace('#^https?://#i', '', $baseurl_cdn); $baseurl_cdn = vB::getRequest()->getVbUrlScheme() . '://' . $baseurl_cdn; $simpleversion = $vboptions['simpleversion']; $prescripts = $scripts; $scripts = array(); foreach ($prescripts as $js) { $rollupname = substr($js, 3); if (isset($this->jsbundles[$rollupname])) { $scripts[] = preg_replace("#/([^\\.]+).js#", "/\$1-{$simpleversion}.js", $js); } else { $joinChar = strpos($js, '?') === false ? '?' : '&'; $scripts[] = $js . $joinChar . 'v=' . $simpleversion; } } $replace = ''; $loaded = array(); foreach ($scripts as $js) { if (!in_array($js, $loaded)) { $replace .= '<script type="text/javascript" src="' . $baseurl_cdn . "/{$js}\"></script>\n"; $loaded[] = $js; } } return $replace; }
public static function handleException($exception, $simple = false) { $config = vB5_Config::instance(); if ($config->debug) { $message = $exception->getMessage(); if (!$simple) { $api = Api_InterfaceAbstract::instance(); $phrase = $api->callApi('phrase', 'fetch', array('phrase' => $message)); if (!empty($phrase)) { $message = array_pop($phrase); } } else { $message = $exception->getMessage(); } $error = array('message' => $message, 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'trace' => $exception->getTrace()); } else { $error = false; } if (!headers_sent()) { // Set HTTP Headers if ($exception instanceof vB5_Exception_404) { $redirect_404_to_root = vB5_Template_Options::instance()->get('options.redirect_404_to_root'); if ($redirect_404_to_root == '1') { header('Location: ' . vB5_Template_Options::instance()->get('options.frontendurl'), true, 301); } else { header("HTTP/1.0 404 Not Found"); header("Status: 404 Not Found"); // if it's a 404, let's have a slightly more appropriate // error message than pm_ajax_error_desc if (!$error) { $error = array('message' => $exception->getMessage()); } } } else { header('HTTP/1.1 500 Internal Server Error'); header("Status: 500 Internal Server Error"); } } self::showErrorPage($error, $simple); die; }
function __construct($options = null, $api) { $this->api = $api; $this->baseurl = vB5_Template_Options::instance()->get('options.frontendurl'); $this->options = array('script_url' => $_SERVER['PHP_SELF'], 'param_name' => 'files', 'max_file_size' => 500000, 'min_file_size' => 1, 'accept_file_types' => '/.+$/i', 'max_number_of_files' => 5, 'discard_aborted_uploads' => true, 'image_versions' => array()); if ($options) { $this->options = array_merge($this->options, $options); } }