/** * Singleton instance getter * * @return vB5_User */ public static function instance() { if (self::$instance === null) { $class = __CLASS__; self::$instance = new $class(); } return self::$instance; }
public function replacePlaceholders(&$content) { $this->fetchPhrases(); $placeholders = array(); end($this->stack); while (!is_null($placeholder_id = key($this->stack))) { $phraseName = current($this->stack); $phraseInfo = $this->pending[$phraseName][$placeholder_id]; $phraseInfo[0] = isset($this->cache[$phraseName]) ? $this->cache[$phraseName] : $phraseInfo[0]; // do parameter replacements in phrases for notices, since we don't want // the extra overhead of pulling these phrases in the api method if (strpos($phraseName, 'notice_') === 0 and preg_match('/^notice_[0-9]+_html$/', $phraseName)) { $phraseInfo[0] = str_replace(array('{musername}', '{username}', '{userid}', '{sessionurl}', '{sessionurl_q}', '{register_page}', '{help_page}'), array(vB5_User::get('musername'), vB5_User::get('username'), vB5_User::get('userid'), vB::getCurrentSession()->get('sessionurl'), vB::getCurrentSession()->get('sessionurl_q'), vB5_Template_Runtime::buildUrl('register'), vB5_Template_Runtime::buildUrl('help')), $phraseInfo[0]); } $replace = $this->constructPhraseFromArray($phraseInfo); $placeholders[$placeholder_id] = $replace; //$content = str_replace($placeholder_id, $replace, $content); prev($this->stack); } // If we passed any phrases as parameters to other phrases, we will // still have those placeholders in the "replace" content, for example: // {vb:phrase have_x_posts_in_topic_last_y, {vb:var topic.dot_postcount}, {vb:date {vb:var topic.dot_lastpostdate}}} // since the date call can return phrases (today, yesterday, etc.). // This only goes one level deep (e.g., it's not recursive), since that's // all we need at this time. // This searches the replace text to see if there are any placeholders // left in them, and if so, replaces those placeholders with the phrase text. foreach ($placeholders as $k => $replace) { if (strpos($replace, '<!-- ##phrase_') !== false or strpos($replace, '<!-- ##phrase_') !== false) { if (preg_match_all('/(?:<|<)!-- ##phrase_([a-z0-9_]+)_[0-9]+## --(?:>|>)/siU', $replace, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $placeholder_id = $match[0]; $phrase_varname = $match[1]; $placeholder_id_lookup = str_replace(array('<', '>'), array('<', '>'), $placeholder_id); $phraseInfo = $this->pending[$phrase_varname][$placeholder_id_lookup]; $phraseInfo[0] = isset($this->cache[$phrase_varname]) ? $this->cache[$phrase_varname] : $phraseInfo[0]; $phraseText = $this->constructPhraseFromArray($phraseInfo); $placeholders[$k] = str_replace($placeholder_id, $phraseText, $placeholders[$k]); } } } } if (!empty($placeholders)) { $content = str_replace(array_keys($placeholders), $placeholders, $content); } }
public function actionLoadPreview() { $input = array('parentid' => isset($_POST['parentid']) ? intval($_POST['parentid']) : 0, 'channelid' => isset($_POST['channelid']) ? intval($_POST['channelid']) : 0, 'pagedata' => isset($_POST['pagedata']) ? (array) $_POST['pagedata'] : array(), 'conversationtype' => isset($_POST['conversationtype']) ? trim(strval($_POST['conversationtype'])) : '', 'posttags' => isset($_POST['posttags']) ? trim(strval($_POST['posttags'])) : '', 'rawtext' => isset($_POST['rawtext']) ? trim(strval($_POST['rawtext'])) : '', 'filedataid' => isset($_POST['filedataid']) ? (array) $_POST['filedataid'] : array(), 'link' => isset($_POST['link']) ? (array) $_POST['link'] : array(), 'poll' => isset($_POST['poll']) ? (array) $_POST['poll'] : array(), 'video' => isset($_POST['video']) ? (array) $_POST['video'] : array(), 'htmlstate' => isset($_POST['htmlstate']) ? trim(strval($_POST['htmlstate'])) : '', 'disable_bbcode' => isset($_POST['disable_bbcode']) ? intval($_POST['disable_bbcode']) : 0); $results = array(); if ($input['parentid'] < 1) { $results['error'] = 'invalid_parentid'; $this->sendAsJson($results); return; } if (!in_array($input['htmlstate'], array('off', 'on_nl2br', 'on'), true)) { $input['htmlstate'] = 'off'; } // when creating a new content item, channelid == parentid $input['channelid'] = $input['channelid'] == 0 ? $input['parentid'] : $input['channelid']; $templateName = 'display_contenttype_conversationreply_'; $templateName .= ucfirst($input['conversationtype']); $api = Api_InterfaceAbstract::instance(); $channelBbcodes = $api->callApi('content_channel', 'getBbcodeOptions', array($input['channelid'])); // The $node['starter'] and $node['nodeid'] values are just there to differentiate starters and replies $node = array('rawtext' => '', 'userid' => vB5_User::get('userid'), 'authorname' => vB5_User::get('username'), 'tags' => $input['posttags'], 'taglist' => $input['posttags'], 'approved' => true, 'created' => time(), 'avatar' => $api->callApi('user', 'fetchAvatar', array('userid' => vB5_User::get('userid'))), 'parentid' => $input['parentid'], 'starter' => $input['channelid'] == $input['parentid'] ? 0 : $input['parentid'], 'nodeid' => $input['channelid'] == $input['parentid'] ? 0 : 1); if ($input['conversationtype'] == 'gallery') { $node['photopreview'] = array(); foreach ($input['filedataid'] as $filedataid) { $node['photopreview'][] = array('nodeid' => $filedataid, 'htmltitle' => isset($_POST['title_' . $filedataid]) ? vB_String::htmlSpecialCharsUni($_POST['title_' . $filedataid]) : ''); //photo preview is up to 3 photos only if (count($node['photopreview']) == 3) { break; } } $node['photocount'] = count($input['filedataid']); } if ($input['conversationtype'] == 'link') { $node['url_title'] = !empty($input['link']['title']) ? $input['link']['title'] : ''; $node['url'] = !empty($input['link']['url']) ? $input['link']['url'] : ''; $node['meta'] = !empty($input['link']['meta']) ? $input['link']['meta'] : ''; $node['previewImage'] = !empty($input['link']['url_image']) ? $input['link']['url_image'] : ''; } if ($input['conversationtype'] == 'poll') { $node['multiple'] = !empty($input['poll']['mutliple']); $node['options'] = array(); if (!empty($input['poll']['options']) and is_array($input['poll']['options'])) { $optionIndex = 1; foreach ($input['poll']['options'] as $option) { $node['options'][] = array('polloptionid' => $optionIndex, 'title' => $option); $optionIndex++; } } $node['permissions']['canviewthreads'] = 1; //TODO: Fix this!! } if ($input['conversationtype'] == 'video') { $node['url_title'] = !empty($input['video']['title']) ? $input['video']['title'] : ''; $node['url'] = !empty($input['video']['url']) ? $input['video']['url'] : ''; $node['meta'] = !empty($input['video']['meta']) ? $input['video']['meta'] : ''; $node['items'] = !empty($input['video']['items']) ? $input['video']['items'] : ''; } try { $results = vB5_Template::staticRenderAjax($templateName, array('nodeid' => $node['nodeid'], 'conversation' => $node, 'currentConversation' => $node, 'bbcodeOptions' => $channelBbcodes, 'pagingInfo' => array(), 'postIndex' => 0, 'reportActivity' => false, 'showChannelInfo' => false, 'showInlineMod' => false, 'commentsPerPage' => 1, 'view' => 'stream', 'previewMode' => true)); } catch (Exception $e) { if (vB5_Config::instance()->debug) { $results['error'] = 'error_rendering_preview_template ' . (string) $e; } else { $results['error'] = 'error_rendering_preview_template'; } $this->sendAsJson($results); return; } $bbcodeoptions = array('allowhtml' => in_array($input['htmlstate'], array('on', 'on_nl2br'), true), 'allowbbcode' => !$input['disable_bbcode'], 'htmlstate' => $input['htmlstate']); $results = array_merge($results, $this->parseBbCodeForPreview(fetch_censored_text($input['rawtext']), $bbcodeoptions)); $this->sendAsJson($results); }
protected function fetchStyleVars() { $res = Api_InterfaceAbstract::instance()->callApi('style', 'fetchStyleVars', array($this->stylePreference)); // api method returns unserealized stylevars if (empty($res) or !empty($res['errors'])) { return; } $user = vB5_User::instance(); if (is_null($user['lang_options']) or isset($user['lang_options']) and is_array($user['lang_options']) and !empty($user['lang_options']['direction'])) { // if user has a LTR language selected $res['textdirection'] = array('datatype' => 'string', 'string' => 'ltr'); $res['left'] = array('datatype' => 'string', 'string' => 'left'); $res['right'] = array('datatype' => 'string', 'string' => 'right'); } else { // if user has a RTL language selected $res['textdirection'] = array('datatype' => 'string', 'string' => 'rtl'); $res['left'] = array('datatype' => 'string', 'string' => 'right'); $res['right'] = array('datatype' => 'string', 'string' => 'left'); } foreach ($res as $key => $value) { $this->cache[$key] = $value; } }
/** gets the key used for storing page information * * @param int the nodeid * * @return string the cache key string */ protected function getPagingCacheKey($nodeid) { return 'vB_ArtPaging_' . $nodeid . '_' . vB5_User::getLanguageId(); }
/** * This gets the charset based on the current language * * @return string, stylevar charset value */ public static function getCharset() { // first check for user info $encoding = vB5_User::get('lang_charset'); if (!$encoding) { $encoding = Api_InterfaceAbstract::instance()->callApi('phrase', 'getLanguageid', array('getCharset' => true)); if (empty($encoding['charset'])) { return 'UTF-8'; } $encoding = $encoding['charset']; } return strtoupper($encoding); }
public function actionInlinemodLogin() { $api = Api_InterfaceAbstract::instance(); $currentuser = vB5_User::instance(); if (empty($currentuser['userid'])) { if (!empty($_POST['username'])) { $loginInfo = $api->callApi('user', 'login', array($_POST['username'], $_POST['password'])); if (empty($loginInfo['errors']) and !empty($loginInfo['userid'])) { $userInfo = $api->callApi('user', 'fetchUserinfo', array($loginInfo['userid'])); $username = $userInfo['username']; vB5_Auth::setLoginCookies($loginInfo, '', !empty($_POST['rememberme'])); } else { $this->sendAsJson(array('error' => 'inlinemod_auth_login_failed')); return false; } } if (empty($username)) { $this->sendAsJson(array('error' => 'inlinemod_auth_login_first')); return false; } } else { $username = $currentuser['username']; } if (empty($_POST['password'])) { $this->sendAsJson(array('error' => 'inlinemod_auth_password_empty')); return false; } $loginInfo = $api->callApi('user', 'login', array($username, $_POST['password'], '', '', 'cplogin')); if (isset($loginInfo['errors']) and !empty($loginInfo['errors'])) { $this->sendAsJson(array('error' => 'inlinemod_auth_login_failed')); return false; } else { vB5_Auth::setLoginCookies($loginInfo, 'cplogin', !empty($_POST['rememberme'])); $this->sendAsJson(true); return true; } }
/** * Handles the parsing of a signature picture. Most of this is handled * based on the $parseUserinfo member. * * @param string Description for the sig pic * * @return string HTML representation of the sig pic */ function handle_bbcode_sigpic($description) { // remove unnecessary line breaks and escaped quotes $description = str_replace(array('<br>', '<br />', '\\"'), array('', '', '"'), $description); // permissions are checked on API method if (empty($this->parseUserinfo['userid']) or empty($this->parseUserinfo['sigpic'])) { // unknown user or no sigpic return ''; } if (self::$useFileAvatar) { $sigpic_url = $this->registry->options['sigpicurl'] . '/sigpic' . $this->parseUserinfo['userid'] . '_' . $this->parseUserinfo['sigpicrevision'] . '.gif'; } else { $sigpic_url = 'image.php?' . vB::getCurrentSession()->get('sessionurl') . 'u=' . $this->parseUserinfo['userid'] . "&type=sigpic&dateline=" . $this->parseUserinfo['sigpicdateline']; } /* if (defined('VB_AREA') AND VB_AREA != 'Forum') { // in a sub directory, may need to move up a level if ($sigpic_url[0] != '/' AND !preg_match('#^[a-z0-9]+:#i', $sigpic_url)) { $sigpic_url = '../' . $sigpic_url; } } */ $description = str_replace(array('\\"', '"'), '', trim($description)); if (vB5_User::get('userid') == 0 or vB5_User::get('showimages')) { return "<img src=\"{$sigpic_url}\" alt=\"{$description}\" border=\"0\" />"; } else { if (!$description) { $description = $sigpic_url; if (vB5_String::vB_Strlen($description) > 55 and $this->isWysiwyg() == false) { $description = substr($description, 0, 36) . '...' . substr($description, -14); } } return "<a href=\"{$sigpic_url}\">{$description}</a>"; } }
public function getCssFile($filename) { $options = vB5_Template_Options::instance(); $storecssasfile = $options->get('options.storecssasfile'); $user = vB5_User::instance(); $textdirection = $user['lang_options']['direction'] ? 'ltr' : 'rtl'; // we cannot query user directly for styleid, we need to consider other parameters $styleid = vB5_Template_Stylevar::instance()->getPreferredStyleId(); $vbcsspath = $this->getCssPath($storecssasfile, $textdirection, $styleid); if ($storecssasfile) { $cssfiledate = $this->getCssFileDate($options, $styleid); $file = htmlspecialchars($vbcsspath . $cssfiledate . '-' . $filename); } else { if (!($cssdate = intval($options->get('miscoptions.cssdate')))) { $cssdate = time(); // fallback so we get the latest css } $joinChar = strpos($vbcsspath, '?') === false ? '?' : '&'; $file = htmlspecialchars($vbcsspath . $filename . "{$joinChar}ts={$cssdate}"); } return $file; }
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; } }
/** * 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); } }
/** * Formats a UNIX timestamp into a human-readable string according to vBulletin prefs * * Note: Ifvbdate() is called with a date format other than than one in $vbulletin->options[], * set $locale to false unless you dynamically set the date() and strftime() formats in the vbdate() call. * * @param string Date format string (same syntax as PHP's date() function). It also supports the following vB specific date/time format: * 'registered' - Format For Registration Date * 'cal1' - Format For Birthdays with Year Specified * 'cal2' - Format For Birthdays with Year Unspecified * 'log' - Log Date Format * @param integer Unix time stamp * @param boolean If true, attempt to show strings like "Yesterday, 12pm" instead of full date string * @param boolean If true, and user has a language locale, use strftime() to generate language specific dates * @param boolean If true, don't adjust time to user's adjusted time .. (think gmdate instead of date!) * @param boolean If true, uses gmstrftime() and gmdate() instead of strftime() and date() * * @return string Formatted date string */ protected static function vbdate($format, $timestamp = 0, $doyestoday = false, $locale = true, $adjust = true, $gmdate = false) { $timenow = time(); if (!$timestamp) { $timestamp = $timenow; } $options = vB5_Template_Options::instance(); $uselocale = false; $timezone = vB5_User::get('timezoneoffset'); if (vB5_User::get('dstonoff') || (vB5_User::get('dstauto') and $options->get('options.dstonoff'))) { // DST is on, add an hour $timezone++; } $hourdiff = (date('Z', time()) / 3600 - $timezone) * 3600; if (vB5_User::get('lang_locale')) { $userLangLocale = vB5_User::get('lang_locale'); } if (!empty($userLangLocale)) { $uselocale = true; $currentlocale = setlocale(LC_TIME, 0); setlocale(LC_TIME, $userLangLocale); if (substr($userLangLocale, 0, 5) != 'tr_TR') { setlocale(LC_CTYPE, $userLangLocale); } } if ($uselocale and $locale) { if ($gmdate) { $datefunc = 'gmstrftime'; } else { $datefunc = 'strftime'; } } else { if ($gmdate) { $datefunc = 'gmdate'; } else { $datefunc = 'date'; } } // vB Specified format switch ($format) { case 'registered': if (($uselocale or vB5_User::get('lang_registereddateoverride')) and $locale) { $format = vB5_User::get('lang_registereddateoverride'); } else { $format = $options->get('options.registereddateformat'); } break; case 'cal1': if (($uselocale or vB5_User::get('lang_calformat1override')) and $locale) { $format = vB5_User::get('lang_calformat1override'); } else { $format = $options->get('options.calformat1'); } break; case 'cal2': if (($uselocale or vB5_User::get('lang_calformat2override')) and $locale) { $format = vB5_User::get('lang_calformat2override'); } else { $format = $options->get('options.calformat2'); } break; case 'log': if (($uselocale or vB5_User::get('lang_logdateoverride')) and $locale) { $format = vB5_User::get('lang_logdateoverride'); } else { $format = $options->get('options.logdateformat'); } break; } if (!$adjust) { $hourdiff = 0; } if ($timestamp < 0) { $timestamp_adjusted = $timestamp; } else { $timestamp_adjusted = max(0, $timestamp - $hourdiff); } if ($format == $options->get('options.dateformat') and ($uselocale or vB5_User::get('lang_dateoverride')) and $locale) { $format = vB5_User::get('lang_dateoverride'); } if (!$uselocale and $format == vB5_User::get('lang_dateoverride')) { if ($gmdate) { $datefunc = 'gmstrftime'; } else { $datefunc = 'strftime'; } } if (!$uselocale and $format == vB5_User::get('lang_timeoverride')) { if ($gmdate) { $datefunc = 'gmstrftime'; } else { $datefunc = 'strftime'; } } if (($format == $options->get('options.dateformat') or $format == vB5_User::get('lang_dateoverride')) and $doyestoday and $options->get('options.yestoday')) { if ($options->get('options.yestoday') == 1) { if (!defined('TODAYDATE')) { define('TODAYDATE', self::vbdate('n-j-Y', $timenow, false, false)); define('YESTDATE', self::vbdate('n-j-Y', $timenow - 86400, false, false)); define('TOMDATE', self::vbdate('n-j-Y', $timenow + 86400, false, false)); } $datetest = @date('n-j-Y', $timestamp - $hourdiff); if ($datetest == TODAYDATE) { $returndate = self::parsePhrase('today'); } else { if ($datetest == YESTDATE) { $returndate = self::parsePhrase('yesterday'); } else { $returndate = $datefunc($format, $timestamp_adjusted); } } } else { $timediff = $timenow - $timestamp; if ($timediff >= 0) { if ($timediff < 120) { $returndate = self::parsePhrase('1_minute_ago'); } else { if ($timediff < 3600) { $returndate = self::parsePhrase('x_minutes_ago', intval($timediff / 60)); } else { if ($timediff < 7200) { $returndate = self::parsePhrase('1_hour_ago'); } else { if ($timediff < 86400) { $returndate = self::parsePhrase('x_hours_ago', intval($timediff / 3600)); } else { if ($timediff < 172800) { $returndate = self::parsePhrase('1_day_ago'); } else { if ($timediff < 604800) { $returndate = self::parsePhrase('x_days_ago', intval($timediff / 86400)); } else { if ($timediff < 1209600) { $returndate = self::parsePhrase('1_week_ago'); } else { if ($timediff < 3024000) { $returndate = self::parsePhrase('x_weeks_ago', intval($timediff / 604900)); } else { $returndate = $datefunc($format, $timestamp_adjusted); } } } } } } } } } else { $returndate = $datefunc($format, $timestamp_adjusted); } } } else { if ($format == 'Y' and $uselocale and $locale) { $format = '%Y'; // For copyright year } if ($format == 'r' and $uselocale and $locale) { $datefunc = 'date'; // For debug } $returndate = $datefunc($format, $timestamp_adjusted); } if (!empty($userLangLocale)) { setlocale(LC_TIME, $currentlocale); if (substr($currentlocale, 0, 5) != 'tr_TR') { setlocale(LC_CTYPE, $currentlocale); } } return $returndate; }
function actionResult() { //the api init can redirect. We need to make sure that happens before we echo anything $api = Api_InterfaceAbstract::instance(); $top = ''; if (vB5_Request::get('cachePageForGuestTime') > 0 and !vB5_User::get('userid')) { $fullPageKey = md5(serialize($_REQUEST)); $fullPage = vB_Cache::instance()->read($fullPageKey); if (!empty($fullPage)) { echo $fullPage; exit; } } $preheader = vB5_ApplicationAbstract::getPreheader(); $top .= $preheader; if (vB5_Request::get('useEarlyFlush')) { echo $preheader; flush(); } $serverData = array_merge($_GET, $_POST); $router = vB5_ApplicationAbstract::instance()->getRouter(); $arguments = $router->getArguments(); $userAction = $router->getUserAction(); if (!empty($userAction)) { $api->callApi('wol', 'register', array($userAction['action'], $userAction['params'])); } // if Human verification is required, and we don't have 'q' set in serverData (means the user is using // the quick search box), we redirect user to advanced search page with HV $requirehv = $api->callApi('hv', 'fetchRequireHvcheck', array('search')); if (!empty($serverData['AdvSearch']) or $requirehv and isset($serverData['q'])) { $adv_search = $api->callApi('route', 'getRoute', array('pathInfo' => 'advanced_search', 'queryString' => ''), true); $arguments = $adv_search['arguments']; } elseif ($requirehv) { // Advanced search form submitted if (empty($serverData['humanverify'])) { $serverData['humanverify'] = array(); } $return = $api->callApi('hv', 'verifyToken', array($serverData['humanverify'], 'search')); if ($return !== true) { $adv_search = $api->callApi('route', 'getRoute', array('pathInfo' => 'advanced_search', 'queryString' => ''), true); $arguments = $adv_search['arguments']; $error = $return['errors'][0][0]; } } $pageid = (int) (isset($arguments['pageid']) ? $arguments['pageid'] : $arguments['contentid']); $page = $api->callApi('page', 'fetchPageById', array($pageid, $arguments)); if (!$page) { echo 'Could not find page.'; exit; } $phrases = $api->callApi('phrase', 'fetch', array(array('advanced_search', 'search_results'))); $page['crumbs'] = array(0 => array('title' => $phrases['advanced_search'], 'url' => vB5_Template_Runtime::buildUrl('advanced_search', array(), array(), array('noBaseUrl' => true))), 1 => array('title' => $phrases['search_results'], 'url' => '')); // avoid search page itself being indexed $page['noindex'] = 1; if (!empty($serverData['cookie'])) { $serverData['searchJSON'] = '{"specific":[' . $_COOKIE[$serverData['cookie']] . ']}'; } if (!empty($serverData['searchJSON'])) { if (is_string($serverData['searchJSON'])) { if (preg_match('/[^\\x00-\\x7F]/', $serverData['searchJSON'])) { $serverData['searchJSON'] = vB5_String::toUtf8($serverData['searchJSON'], vB5_String::getTempCharset()); } $serverData['searchJSON'] = json_decode($serverData['searchJSON'], true); } if (!empty($serverData['searchJSON'])) { if (!empty($serverData['searchJSON']['keywords'])) { $serverData['searchJSON']['keywords'] = str_replace(array('"', '\\'), '', $serverData['searchJSON']['keywords']); $serverData['searchJSON']['keywords'] = filter_var($serverData['searchJSON']['keywords'], FILTER_SANITIZE_STRING); } $serverData['searchJSON'] = json_encode($serverData['searchJSON']); } else { $serverData['searchJSON'] = ''; } $page['searchJSON'] = $serverData['searchJSON']; $extra = array('searchJSON' => !empty($serverData['searchJSON']) ? $serverData['searchJSON'] : '{}'); if (!empty($serverData['AdvSearch'])) { $extra['AdvSearch'] = 1; } $page['url'] = str_replace('&', '&', vB5_Route::buildUrl('search', array(), $extra)); //$page['searchJSONStructure'] = json_decode($page['searchJSON'],true); $page['crumbs'][0]['url'] = vB5_Template_Runtime::buildUrl('advanced_search', array(), array('searchJSON' => $page['searchJSON']), array('noBaseUrl' => true)); } elseif (!empty($serverData['q'])) { $serverData['q'] = str_replace(array('"', '\\'), '', $serverData['q']); $serverData['q'] = filter_var($serverData['q'], FILTER_SANITIZE_STRING); $searchType = ''; if (!empty($serverData['type'])) { $serverData['type'] = str_replace(array('"', '\\'), '', $serverData['type']); $serverData['type'] = filter_var($serverData['type'], FILTER_SANITIZE_STRING); $searchType = ',"type":"' . $serverData['type'] . '"'; } $page['searchJSON'] = '{"keywords":"' . $serverData['q'] . '","sort":"title"' . $searchType . '}'; $extra = array('q' => $serverData['q']); if (!empty($serverData['AdvSearch'])) { $extra['AdvSearch'] = 1; } $page['url'] = str_replace('&', '&', vB5_Route::buildUrl('search', array(), $extra)); $page['searchStr'] = $serverData['q']; $page['crumbs'][0]['url'] = vB5_Template_Runtime::buildUrl('advanced_search', array(''), array('searchJSON' => $page['searchJSON']), array('noBaseUrl' => true)); } elseif (!empty($serverData['r'])) { unset($page['crumbs'][0]); $page['url'] = str_replace('&', '&', vB5_Route::buildUrl('search', array(), array('r' => $serverData['r']))); $page['resultId'] = $serverData['r']; if (!empty($serverData['p']) && is_numeric($serverData['p'])) { $page['currentPage'] = intval($serverData['p']); } $page['crumbs'][0]['url'] = vB5_Template_Runtime::buildUrl('advanced_search', array(), array('r' => $serverData['r']), array('noBaseUrl' => true)); } else { return $this->actionIndex(); } $page['ignore_np_notices'] = vB5_ApplicationAbstract::getIgnoreNPNotices(); if (!empty($error)) { $page['error'] = $error; } $templater = new vB5_Template($page['screenlayouttemplate']); $templater->registerGlobal('page', $page); $page = $this->outputPage($templater->render(), false); $fullPage = $top . $page; if (vB5_Request::get('cachePageForGuestTime') > 0 and !vB5_User::get('userid')) { vB_Cache::instance()->write($fullPageKey, $fullPage, vB5_Request::get('cachePageForGuestTime')); } if (!vB5_Request::get('useEarlyFlush')) { echo $fullPage; } else { echo $page; } }
public function actionGet() { $filters = isset($_POST['filters']) ? $_POST['filters'] : array(); if (empty($filters['view'])) { $result = array('error' => 'invalid_request'); $this->sendAsJson($result); return; } $search = array(); $stickySearchOptions = array('sticky_only' => 1); $stickynodes = array(); $incrementNodeview = false; // call node API's incrementNodeview if we're viewing a thread if (isset($filters['q']) and trim($filters['q']) != '') { $search['keywords'] = $filters['q']; } else { $filters['q'] = false; } if (!empty($filters['exclude_type'])) { $search['exclude_type'] = $filters['exclude_type']; } if (!empty($filters['userid'])) { $search['authorid'] = $filters['userid']; } else { if (!empty($filters['filter_blogs']) and $filters['filter_blogs'] == 'show_my') { $search['authorid'] = vB5_User::get('userid'); } } if (isset($filters['filter_prefix'])) { if (!empty($filters['filter_prefix'])) { if ($filters['filter_prefix'] == '-1') { $search['no_prefix'] = 1; } else { if ($filters['filter_prefix'] == '-2') { $search['has_prefix'] = 1; } else { $search['prefix'] = $filters['filter_prefix']; } } } else { // Any thread, regardless of prefix, don't set $search['prefix'] } } if (isset($filters['nodeid']) and intval($filters['nodeid']) > 0) { $search['channel'] = $filters['nodeid']; } switch ($filters['view']) { case 'topic': $search['view'] = vB_Api_Search::FILTER_VIEW_TOPIC; $search['exclude_sticky'] = true; $search['nolimit'] = !empty($filters['nolimit']); if (!empty($filters['depth'])) { $search['depth'] = $filters['depth']; } $search['depth_exact'] = !empty($filters['depth_exact']); break; case 'channel': //Channel view is the same with Activity view except that Channel view's search scope is within that channel only as specified by the channel nodeid in the 'channel' filter $search['include_sticky'] = true; // drop through to 'activity' // drop through to 'activity' case 'activity': //Per Product, if New Topics filter in activity stream is ON, display latest starters only. //if OFF, display latest starter, reply or comment per topic if (isset($filters['filter_new_topics']) and $filters['filter_new_topics'] == '1') { $search['starter_only'] = true; } $search['view'] = vB_Api_Search::FILTER_VIEW_ACTIVITY; break; case 'stream': $search['view'] = vB_Api_Search::FILTER_VIEW_CONVERSATION_STREAM; $search['include_starter'] = true; $search['depth'] = 2; break; case 'thread': $search['view'] = vB_Api_Search::FILTER_VIEW_CONVERSATION_THREAD; $search['include_sticky'] = true; $search['include_starter'] = true; $search['depth'] = 1; $search['nolimit'] = !empty($filters['nolimit']); if ($filters['q']) { $search['view'] = vB_Api_Search::FILTER_VIEW_CONVERSATION_THREAD_SEARCH; } $incrementNodeview = true; break; case 'article': $search['starter_only'] = true; $search['view'] = vB_Api_Search::FILTER_VIEW_ACTIVITY; $search['include_sticky'] = true; $search['include_starter'] = true; //$search['depth'] = 1; //$search['nolimit'] = !empty($filters['nolimit']); break; } if (!empty($filters[vB_Api_Node::FILTER_DEPTH])) { $search['depth'] = intval($filters[vB_Api_Node::FILTER_DEPTH]); } if (isset($filters['filter_sort'])) { switch ($filters['filter_sort']) { case vB_Api_Node::FILTER_SORTFEATURED: $search['featured'] = 1; break; case vB_Api_Node::FILTER_SORTPOPULAR: $search['sort']['votes'] = 'desc'; break; case vB_Api_Node::FILTER_SORTOLDEST: if (isset($filters['view']) and $filters['view'] == 'topic') { $search['sort']['lastcontent'] = 'asc'; } else { $search['sort']['created'] = 'asc'; } break; case vB_Api_Node::FILTER_SORTMOSTRECENT: default: if (empty($filters['filter_order'])) { $filters['filter_order'] = 'desc'; } if (isset($filters['view']) and $filters['view'] == 'topic') { $search['sort'][$filters['filter_sort']] = $filters['filter_order']; } else { $search['sort']['created'] = 'desc'; } break; } } elseif ($filters['view'] == 'thread') { $search['sort']['created'] = 'asc'; } elseif ($filters['view'] == 'topic') { $search['sort']['lastcontent'] = 'desc'; } if (isset($filters['checkSince']) and is_numeric($filters['checkSince'])) { $search['date']['from'] = $filters['checkSince'] + 1; } elseif (isset($filters['date']) or isset($filters['filter_time'])) { $date_filter = empty($filters['date']) ? $filters['filter_time'] : $filters['date']; switch ($date_filter) { case 'time_today': $search['date']['from'] = 'lastDay'; //vB_Api_Search::FILTER_LASTDAY; break; case 'time_lastweek': $search['date']['from'] = 'lastWeek'; //vB_Api_Search::FILTER_LASTWEEK; break; case 'time_lastmonth': $search['date']['from'] = 'lastMonth'; //vB_Api_Search::FILTER_LASTMONTH; break; case 'time_lastyear': $search['date']['from'] = 'lastYear'; //vB_Api_Search::FILTER_LASTYEAR; break; case 'time_all': default: $search['date'] = 'all'; break; } } if (isset($filters[vB_Api_Node::FILTER_SHOW]) and strcasecmp($filters[vB_Api_Node::FILTER_SHOW], vB_Api_Node::FILTER_SHOWALL) != 0) { $search['type'] = $filters[vB_Api_Node::FILTER_SHOW]; } $search['ignore_protected'] = 1; $nodes = Api_InterfaceAbstract::instance()->callApi('search', 'getInitialResults', array($search, empty($filters['per-page']) ? false : $filters['per-page'], empty($filters['pagenum']) ? false : $filters['pagenum'], true)); if ($incrementNodeview) { Api_InterfaceAbstract::instance()->callApi('node', 'incrementNodeview', array($filters['nodeid'])); } if (!empty($nodes) and !empty($nodes['errors'])) { $result = array('error' => $nodes['errors'][0][0]); $this->sendAsJson($result); return; } //the same selected search filters except 'exclude_sticky' should also be applied when fetching sticky topics if ($filters['view'] == 'topic' and (empty($filters['pagenum']) or $filters['pagenum'] == 1 or vB::getDatastore()->getOption('showstickies'))) { $stickySearchOptions = array_merge($search, $stickySearchOptions); unset($stickySearchOptions['exclude_sticky']); $stickynodes = Api_InterfaceAbstract::instance()->callApi('search', 'getInitialResults', array($stickySearchOptions)); } if (empty($filters['maxpages'])) { $filters['maxpages'] = 0; } switch ($filters['view']) { case 'activity': $result = $this->processActivityStream($nodes, true, $filters['maxpages']); break; case 'thread': case 'stream': $result = $this->processConversationDetail($nodes, $filters, $filters['maxpages']); break; case 'topic': $result = $this->processTopics($nodes, $stickynodes, $filters['maxpages']); break; case 'article': $articleDisplayColumns = !empty($_POST['article_display_columns']) ? strval($_POST['article_display_columns']) : ''; $result = $this->processArticles($nodes, $filters['maxpages'], $articleDisplayColumns); break; case 'channel': default: $result = $this->processActivityStream($nodes, false, $filters['maxpages']); break; } if (!$result['lastDate']) { $result['lastDate'] = time(); } $this->sendAsJson($result); }