예제 #1
0
 /**
  * Sends the response as a JSON encoded string
  *
  * @param	mixed	The data (usually an array) to send
  */
 public function sendAsJson($data)
 {
     //This function needs to be kept in sync with the implmentation in applicationlight.php
     if (headers_sent($file, $line)) {
         throw new Exception("Cannot send response, headers already sent. File: {$file} Line: {$line}");
     }
     // We need to convert $data charset if we're not using UTF-8
     if (vB5_String::getTempCharset() != 'UTF-8') {
         $data = vB5_String::toCharset($data, vB5_String::getTempCharset(), 'UTF-8');
     }
     //If this is IE9, IE10, or IE11 -- we also need to work around the deliberate attempt to break "is IE" logic by the
     //IE dev team -- we need to send type "text/plain". Yes, we know that's not the standard.
     if (isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false or strpos($_SERVER['HTTP_USER_AGENT'], 'Trident') !== false)) {
         header('Content-type: text/plain; charset=UTF-8');
     } else {
         header('Content-type: application/json; charset=UTF-8');
     }
     // IE will cache ajax requests, and we need to prevent this - VBV-148
     header('Cache-Control: max-age=0,no-cache,no-store,post-check=0,pre-check=0');
     header('Expires: Sat, 1 Jan 2000 01:00:00 GMT');
     header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
     header("Pragma: no-cache");
     if (isset($data['template']) and !empty($data['template'])) {
         $data['template'] = $this->outputPage($data['template'], false);
     }
     echo vB5_String::jsonEncode($data);
 }
예제 #2
0
 public function actionOutput()
 {
     $api = Api_InterfaceAbstract::instance();
     $response = $api->callApi('session', 'getGuestSession');
     if (is_array($response) and !empty($response['errors'])) {
         return '';
     }
     $type = !empty($_REQUEST['type']) ? $_REQUEST['type'] : '';
     // default rss2
     switch ($type) {
         case 'rss2':
         case 'rss1':
         case 'rss':
         case 'xml':
         case 'js':
             $type = $_REQUEST['type'];
             break;
         default:
             $type = 'rss2';
             break;
     }
     if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) and !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
         $response = $api->callApi('external', 'getCacheData', array('type' => $type, 'options' => $_REQUEST));
         if (is_array($response) and !empty($response['errors'])) {
             return '';
         }
         if ($_SERVER['HTTP_IF_NONE_MATCH'] == "\"{$response['cachehash']}\"") {
             $timediff = strtotime(gmdate('D, d M Y H:i:s') . ' GMT') - strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
             if ($timediff <= $response['cachetime']) {
                 if (SAPI_NAME == 'cgi' or SAPI_NAME == 'cgi-fcgi') {
                     header('Status: 304 Not Modified');
                 } else {
                     header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
                 }
                 exit;
             }
         }
     }
     // always disable nohtml
     $_REQUEST['nohtml'] = 0;
     $response = $api->callApi('external', 'createExternalOutput', array('type' => $type, 'options' => $_REQUEST));
     if (is_array($response) and !empty($response['errors'])) {
         return '';
     }
     $data = $_REQUEST + array('Pragma' => '', 'Content-Type' => vB5_String::getTempCharset());
     $headers = $api->callApi('external', 'getHeadersFromLastOutput', array('type' => $type, 'data' => $data));
     if (is_array($headers) and !empty($headers['errors'])) {
         return '';
     }
     foreach ($headers as $name => $value) {
         header("{$name}: {$value}");
     }
     return $response;
 }
예제 #3
0
 /** Responds to a request to create a new user.
  *
  **/
 public function actionRegistration()
 {
     //We need at least a username, email, and password.
     if (empty($_REQUEST['username']) or empty($_REQUEST['password']) or empty($_REQUEST['email'])) {
         $this->sendAsJson(array('error' => 'insufficient data'));
         return;
     }
     $username = trim($_REQUEST['username']);
     $password = trim($_REQUEST['password']);
     $postdata = array('username' => $username, 'email' => $_REQUEST['email']);
     if (isset($_REQUEST['month']) and isset($_REQUEST['day']) and !empty($_REQUEST['year'])) {
         $postdata['birthday'] = $_REQUEST['year'] . '-' . str_pad($_REQUEST['month'], 2, '0', STR_PAD_LEFT) . '-' . str_pad($_REQUEST['day'], 2, '0', STR_PAD_LEFT);
     }
     if (!empty($_REQUEST['guardian'])) {
         $postdata['parentemail'] = $_REQUEST['guardian'];
     }
     $vboptions = vB5_Template_Options::instance()->getOptions();
     $vboptions = $vboptions['options'];
     // Coppa cookie check
     $coppaage = vB5_Cookie::get('coppaage', vB5_Cookie::TYPE_STRING);
     if ($vboptions['usecoppa'] and $vboptions['checkcoppa']) {
         if ($coppaage) {
             $dob = explode('-', $coppaage);
             $month = $dob[0];
             $day = $dob[1];
             $year = $dob[2];
             $postdata['birthday'] = $year . '-' . str_pad($month, 2, '0', STR_PAD_LEFT) . '-' . str_pad($day, 2, '0', STR_PAD_LEFT);
         } else {
             vB5_Cookie::set('coppaage', $_REQUEST['month'] . '-' . $_REQUEST['day'] . '-' . $_REQUEST['year'], 365, 0);
         }
     }
     // Fill in ReCaptcha data
     $recaptchaData = array();
     if (!empty($_REQUEST['recaptcha_challenge_field'])) {
         $recaptchaData['recaptcha_challenge_field'] = $_REQUEST['recaptcha_challenge_field'];
     }
     if (!empty($_REQUEST['recaptcha_response_field'])) {
         $recaptchaData['recaptcha_response_field'] = $_REQUEST['recaptcha_response_field'];
     }
     if (!empty($recaptchaData)) {
         $_REQUEST['humanverify'] = $recaptchaData + (isset($_REQUEST['humanverify']) ? (array) $_REQUEST['humanverify'] : array());
     }
     $api = Api_InterfaceAbstract::instance();
     $data = array('userid' => 0, 'password' => $password, 'user' => $postdata, array(), array(), 'userfield' => !empty($_REQUEST['userfield']) ? $_REQUEST['userfield'] : false, array(), isset($_REQUEST['humanverify']) ? $_REQUEST['humanverify'] : '', array('registration' => true));
     // add facebook data
     if ($api->callApi('facebook', 'isFacebookEnabled') && $api->callApi('facebook', 'userIsLoggedIn')) {
         $fbUserInfo = $api->callApi('facebook', 'getFbUserInfo');
         $data['user']['fbuserid'] = $fbUserInfo['id'];
         $data['user']['fbname'] = $fbUserInfo['name'];
         $data['user']['timezoneoffset'] = $fbUserInfo['timezone'];
         $data['user']['fbjoindate'] = time();
         $fb_profilefield_info = $this->getFacebookProfileinfo($fbUserInfo);
         if (!empty($fb_profilefield_info['birthday']) and empty($data['user']['birthday'])) {
             $data['user']['birthday'] = $fb_profilefield_info['birthday'];
         }
         if (empty($data['userfield'])) {
             $data['userfield'] = array();
         }
         if ($vboptions['fb_userfield_biography']) {
             $data['userfield'] += array($vboptions['fb_userfield_biography'] => $fb_profilefield_info['biography']);
         }
         if ($vboptions['fb_userfield_location']) {
             $data['userfield'] += array($vboptions['fb_userfield_location'] => $fb_profilefield_info['location']);
         }
         if ($vboptions['fb_userfield_occupation']) {
             $data['userfield'] += array($vboptions['fb_userfield_occupation'] => $fb_profilefield_info['occupation']);
         }
     }
     // save data
     $response = $api->callApi('user', 'save', $data);
     if (!empty($response) and (!is_array($response) or !isset($response['errors']))) {
         // try to login
         $loginInfo = $api->callApi('user', 'login', array($username, $password, '', '', ''));
         if (!isset($loginInfo['errors']) or empty($loginInfo['errors'])) {
             // browser session expiration
             vB5_Cookie::set('sessionhash', $loginInfo['sessionhash'], 0, true);
             vB5_Cookie::set('password', $loginInfo['password'], 0);
             vB5_Cookie::set('userid', $loginInfo['userid'], 0);
             $urlPath = '';
             if (!empty($_POST['urlpath'])) {
                 $urlPath = base64_decode(trim($_POST['urlpath']), true);
             }
             if (!$urlPath or strpos($urlPath, '/auth/') !== false or strpos($urlPath, '/register') !== false or !vB5_Template_Runtime::allowRedirectToUrl($urlPath)) {
                 $urlPath = vB5_Template_Options::instance()->get('options.frontendurl');
             }
             $response = array('urlPath' => $urlPath);
         } else {
             if (!empty($loginInfo['errors'])) {
                 $response = array('errors' => $loginInfo['errors']);
             }
         }
         if ($api->callApi('user', 'usecoppa')) {
             $response['usecoppa'] = true;
             $response['urlPath'] = vB5_Route::buildUrl('coppa-form|bburl');
         } else {
             if ($vboptions['verifyemail']) {
                 $response['msg'] = 'registeremail';
                 $response['msg_params'] = array(vB5_String::htmlSpecialCharsUni($postdata['username']), $postdata['email'], vB5_Template_Options::instance()->get('options.frontendurl'));
             } else {
                 if ($vboptions['moderatenewmembers']) {
                     $response['msg'] = 'moderateuser';
                     $response['msg_params'] = array(vB5_String::htmlSpecialCharsUni($postdata['username']), vB5_Template_Options::instance()->get('options.frontendurl'));
                 } else {
                     $frontendurl = vB5_Template_Options::instance()->get('options.frontendurl');
                     $routeProfile = $api->callApi('route', 'getUrl', array('route' => 'profile', 'data' => array('userid' => $loginInfo['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'] = 'registration_complete';
                     $response['msg_params'] = array(vB5_String::htmlSpecialCharsUni($postdata['username']), $frontendurl . $routeProfile, $frontendurl . $routeAccount, $frontendurl . $routeuserSettings, $frontendurl);
                 }
             }
         }
     }
     $this->sendAsJson(array('response' => $response));
 }
예제 #4
0
 /**
  * Converts Unicode entities of the format %uHHHH where each H is a hexadecimal
  * character to &#DDDD; or the appropriate UTF-8 character based on current charset.
  *
  * @param	Mixed		array or text
  *
  * @return	string	Decoded text
  */
 public static function convertUrlencodedUnicode($text)
 {
     if (is_array($text)) {
         foreach ($text as $key => $value) {
             $text["{$key}"] = self::convertUrlencodedUnicode($value);
         }
         return $text;
     }
     $charset = self::getTempCharset();
     $return = preg_replace_callback('#%u([0-9A-F]{1,4})#i', function ($matches) use($charset) {
         return vB5_String::convertUnicodeCharToCharset(hexdec($matches[1]), $charset);
     }, $text);
     $lower_charset = strtolower($charset);
     if ($lower_charset != 'utf-8' and function_exists('html_entity_decode')) {
         // this converts certain &#123; entities to their actual character
         // set values; don't do this if using UTF-8 as it's already done above.
         // note: we don't want to convert &gt;, etc as that undoes the effects of STR_NOHTML
         $return = preg_replace('#&([a-z]+);#i', '&amp;$1;', $return);
         if ($lower_charset == 'windows-1251') {
             // there's a bug in PHP5 html_entity_decode that decodes some entities that
             // it shouldn't. So double encode them to ensure they don't get decoded.
             $return = preg_replace('/&#(128|129|1[3-9][0-9]|2[0-4][0-9]|25[0-5]);/', '&amp;#$1;', $return);
         }
         $return = @html_entity_decode($return, ENT_NOQUOTES, $charset);
     }
     return $return;
 }
예제 #5
0
 /**
  * Callback for preg_replace_callback used in handle_bbcode_html
  */
 protected function handleBBCodeTagPregMatch2($matches)
 {
     return $this->handle_bbcode_html_tag(vB5_String::htmlSpecialCharsUni($matches[1]));
 }
 public static function getPreheader()
 {
     $templater = new vB5_Template('preheader');
     if (self::$needCharset) {
         $templater->register('charset', vB5_String::getTempCharset());
     } else {
         $templater->register('charset', false);
     }
     return $templater->render();
 }
예제 #7
0
 /**
  * Determines whether a string contains an [img] tag.
  *
  * @param	string	Text to search
  *
  * @return	bool	Whether the text contains an [img] tag
  */
 protected function containsBbcodeImgTags($text)
 {
     // use a bitfield system to look for img, attach, and sigpic tags
     $hasimage = 0;
     if (vB5_String::stripos($text, '[/img]') !== false) {
         $hasimage += self::BBCODE_HAS_IMG;
     }
     if (vB5_String::stripos($text, '[/attach]') !== false) {
         $hasimage += self::BBCODE_HAS_ATTACH;
     }
     if (vB5_String::stripos($text, '[/sigpic]') !== false) {
         // permissions are checked on API method
         if (!empty($this->parseUserinfo['userid']) and !empty($this->parseUserinfo['sigpic'])) {
             $hasimage += self::BBCODE_HAS_SIGPIC;
         }
     }
     if (vB5_String::stripos($text, '[/relpath]') !== false) {
         $hasimage += self::BBCODE_HAS_RELPATH;
     }
     return $hasimage;
 }
예제 #8
0
 /**
  *	Break the keyword search into words
  * @param string keywords -- keyword string as entered by the user
  * @return array -- array of word records
  *  array('word' => $word,  'joiner' => {'', 'NOT', 'AND', 'OR'})
  *  The search implementation is expected to use these to build the search
  *	 query.
  */
 private function get_words($keywords)
 {
     $is_mb = preg_match('/&#([0-9]+);|[^\\x00-\\x7F]/siU', $keywords);
     // @todo handleing for thousand and decimal separators for numbers
     // removing punctuation
     $origKeywords = $keywords;
     $keywords = preg_replace('#(?!-)[\\p{Pd}\\p{Pe}\\p{Pf}\\p{Pi}\\p{Po}\\p{Ps}]#' . ($is_mb ? 'u' : ''), ' ', $keywords);
     // a tokenizing based approach to building a search query
     preg_match_all('#("[^"]*"|[^\\s]+)#', $keywords, $matches, PREG_SET_ORDER);
     $token_joiner = null;
     $words = array();
     foreach ($matches as $match) {
         if ($is_mb) {
             $match = preg_replace_callback('/&#([0-9]+);/siU', function ($matches) {
                 return vB5_String::convertIntToUtf8($matches[1]);
             }, $match);
         }
         if ($is_mb) {
             $token = vB_String::vBStrToLower($match[1]);
         } else {
             $token = strtolower($match[1]);
         }
         //this means that we implicitly have a not joiner.
         if ($token[0] == '-') {
             //this effectively means two joiners, which is bad.
             if ($token_joiner) {
                 $this->add_error('invalid_search_syntax');
             } else {
                 $token = substr($token, 1);
                 $token_joiner = 'not';
             }
         }
         switch ($token) {
             case 'or':
             case 'and':
             case 'not':
                 // this isn't a searchable word, but a joiner
                 $token_joiner = strtoupper($token);
                 break;
             default:
                 //$lowWord = strtolower($token);
                 if (vB_Api_Search::is_index_word($token, true)) {
                     $words[] = array('word' => $token, 'joiner' => strtoupper($token_joiner));
                 } else {
                     $this->ignored_keywords[] = $match[1];
                 }
                 $token_joiner = null;
                 break;
         }
     }
     if (empty($matches) and !empty($origKeywords)) {
         $this->ignored_keywords[] = $origKeywords;
     }
     return $words;
 }
예제 #9
0
 /**
  * Performs the actual merging, using edited input from UI.
  * @param type $data - Contains pairs (value, name) from edit form in addition to the following fields:
  *						* mergePosts - posts to be merged
  *						* destnodeid - target post
  *						* destauthorid - author to be used
  *						* contenttype - target contenttype
  */
 public function mergePosts($input)
 {
     $this->inlinemodAuthCheck();
     $cleaner = vB::getCleaner();
     $data = array();
     foreach ($input as $i) {
         $name = $cleaner->clean($i['name'], vB_Cleaner::TYPE_NOHTML);
         //mostly the data is either integer or string, although the possibility exists of a
         //'url_image'
         switch ($name) {
             case 'nodeid':
             case 'url_nopreview':
             case 'nodeuserid':
             case 'filedataid':
             case 'destauthorid':
             case 'destnodeid':
                 $value = $cleaner->clean($i['value'], vB_Cleaner::TYPE_UINT);
                 break;
             case 'title':
             case 'text':
             case 'reason':
                 $value = $cleaner->clean($i['value'], vB_Cleaner::TYPE_STR);
                 break;
             case 'url_title':
             case 'authorname':
             case 'url':
             case 'url_image':
             case 'url_meta':
                 $value = $cleaner->clean($i['value'], vB_Cleaner::TYPE_NOHTML);
                 break;
             case 'mergePosts':
                 if (!is_array($i['value'])) {
                     $i['value'] = explode(',', $i['value']);
                 }
                 $value = $cleaner->clean($i['value'], vB_Cleaner::TYPE_ARRAY_UINT);
                 break;
             case 'filedataid[]':
                 //The filedata records are passed as
                 //input[xx][name]	filedataid[]
                 //input[xx][value]	<integer>
                 $value = $cleaner->clean($i['value'], vB_Cleaner::TYPE_UINT);
                 if (!isset($data['filedataid'])) {
                     $data['filedataid'] = array();
                 }
                 if (!isset($data['filedataid'][$value])) {
                     $data['filedataid'][$value] = '';
                 }
                 continue;
             default:
                 //The title records are passed as
                 //input[xx][name]	title_<filedataid>
                 //input[xx][value]	<title>
                 if (empty($name)) {
                     continue;
                 }
                 if (substr($name, 0, 6) == 'title_') {
                     $filedataid = substr($name, 6);
                     $filedataid = $cleaner->clean($filedataid, vB_Cleaner::TYPE_UINT);
                     if ($filedataid) {
                         if (!isset($data['filedataid'])) {
                             $data['filedataid'] = array();
                         }
                         $data['filedataid'][$filedataid] = $cleaner->clean($i['value'], vB_Cleaner::TYPE_NOHTML);
                     }
                     continue;
                 } else {
                     if (preg_match('#^videoitems\\[([\\d]+)#', $name, $matches)) {
                         if (!isset($data['videoitems'])) {
                             $data['videoitems'] = array();
                         }
                         $videoitems[] = array('videoitemid' => intval($matches[1]), 'url' => $i['value']);
                     } else {
                         if (preg_match('^videoitems\\[new^', $name, $matches)) {
                             if (!isset($data['videoitems'])) {
                                 $data['videoitems'] = array();
                             }
                             foreach ($matches as $video) {
                                 $data['videoitems'][] = array('url' => $video['url']);
                             }
                         }
                     }
                 }
                 continue;
         }
         if (isset($data[$name])) {
             if (!is_array($data[$name])) {
                 $data[$name] = array($data[$name]);
             }
             $data[$name][] = $value;
         } else {
             $data[$name] = $value;
         }
     }
     if (empty($data['mergePosts'])) {
         throw new vB_Exception_Api('please_select_at_least_one_post');
     }
     // check that the user has permission
     $nodesToCheck = $data['mergePosts'];
     $nodesToCheck[] = $data['destnodeid'];
     foreach ($nodesToCheck as $key => $nodeid) {
         // this is here just in case for some reason, a nodeid is 0. Shouldn't happen, but
         // I don't want getChannelPermission to go bonkers from it.
         if (empty($nodeid)) {
             unset($nodesToCheck[$key]);
             continue;
         }
         if (!vB::getUserContext()->getChannelPermission('moderatorpermissions', 'canmanagethreads', $nodeid)) {
             // perhaps we could generate a list of unmergeable nodes and return a warning instead, but
             // I don't think there's a real use case where a moderator can manage only *some* of the
             // nodes they're trying to merge. I think that would require multiple channels being involved, and
             // we don't have a UI for that so I can't test it. As such I'm just going to throw an exception if
             // *any* of the nodes fail the check.
             throw new vB_Exception_Api('no_permission');
         }
     }
     // validate that selected nodes can be merged
     $mergeInfo = $this->validateMergePosts($data['mergePosts']);
     if (isset($mergeInfo['error'])) {
         throw new vB_Exception_Api($mergeInfo['error']);
     }
     // validate form fields
     if (empty($data['destnodeid']) || !array_key_exists($data['destnodeid'], $mergeInfo['destnodes'])) {
         throw new vB_Exception_Api('invalid_data');
     }
     if (empty($data['destauthorid']) || !array_key_exists($data['destauthorid'], $mergeInfo['destauthors'])) {
         throw new vB_Exception_Api('invalid_data');
     }
     $destnode = $this->library->getNodeFullContent($data['destnodeid']);
     $destnode = array_pop($destnode);
     if ($destnode['starter'] != $destnode['nodeid'] and $destnode['starter'] != $destnode['parentid']) {
         if (isset($data['tags'])) {
             unset($data['tags']);
         }
     }
     $type = vB_Types::instance()->getContentTypeClass($destnode['contenttypeid']);
     $response = vB_Library::instance("content_{$type}")->mergeContent($data);
     if ($response) {
         $sources = array_diff($data['mergePosts'], array($data['destnodeid']));
         $origDestnode = $destnode;
         if (!empty($destnode['rawtext'])) {
             $origRawText = $destnode['rawtext'];
         } else {
             if (!empty($destnode['content']['rawtext'])) {
                 $origRawText = $destnode['content']['rawtext'];
             } else {
                 $origRawText = '';
             }
         }
         $destnode = $this->getNode($data['destnodeid']);
         if (!empty($destnode['rawtext'])) {
             $rawText = $destnode['rawtext'];
         } else {
             if (!empty($destnode['content']['rawtext'])) {
                 $rawText = $destnode['content']['rawtext'];
             } else {
                 $rawText = '';
             }
         }
         $destnode = $this->getNode($data['destnodeid']);
         $loginfo = array('nodeid' => $destnode['nodeid'], 'nodetitle' => $destnode['title'], 'nodeusername' => $destnode['authorname'], 'nodeuserid' => $destnode['userid']);
         // move children to target node
         $children = vB::getDbAssertor()->assertQuery('vBForum:closure', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'parent' => $sources, 'depth' => 1));
         $childrenIds = array();
         foreach ($children as $child) {
             $childrenIds[] = $child['child'];
         }
         if (!empty($childrenIds)) {
             $this->moveNodes($childrenIds, $data['destnodeid'], false, false, false);
         }
         // remove merged nodes
         $this->deleteNodes($sources, true, null, false);
         //  Dont log the deletes
         $loginfo['action'] = array('merged_nodes' => implode(',', $sources));
         $vboptions = vB::getDatastore()->getValue('options');
         if (vB_Api::instanceInternal('user')->hasPermissions('genericoptions', 'showeditedby') and $destnode['publishdate'] > 0 and $destnode['publishdate'] < vB::getRequest()->getTimeNow() - $vboptions['noeditedbytime'] * 60 or !empty($data['reason'])) {
             $userinfo = vB::getCurrentSession()->fetch_userinfo();
             if ($vboptions['postedithistory']) {
                 $record = vB::getDbAssertor()->getRow('vBForum:postedithistory', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'original' => 1, 'nodeid' => $destnode['nodeid']));
                 // insert original post on first edit
                 if (empty($record)) {
                     vB::getDbAssertor()->assertQuery('vBForum:postedithistory', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT, 'nodeid' => $origDestnode['nodeid'], 'userid' => $origDestnode['userid'], 'username' => $origDestnode['authorname'], 'dateline' => $origDestnode['publishdate'], 'pagetext' => $origRawText, 'original' => 1));
                 }
                 // insert the new version
                 vB::getDbAssertor()->assertQuery('vBForum:postedithistory', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT, 'nodeid' => $destnode['nodeid'], 'userid' => $userinfo['userid'], 'username' => $userinfo['username'], 'dateline' => vB::getRequest()->getTimeNow(), 'reason' => isset($data['reason']) ? vB5_String::htmlSpecialCharsUni($data['reason']) : '', 'pagetext' => $rawText));
             }
             vB::getDbAssertor()->assertQuery('editlog_replacerecord', array('nodeid' => $destnode['nodeid'], 'userid' => $userinfo['userid'], 'username' => $userinfo['username'], 'timenow' => vB::getRequest()->getTimeNow(), 'reason' => isset($data['reason']) ? vB5_String::htmlSpecialCharsUni($data['reason']) : '', 'hashistory' => intval($vboptions['postedithistory'])));
         }
         vB_Library_Admin::logModeratorAction($loginfo, 'node_merged_by_x');
         return true;
     }
 }
예제 #10
0
 /**
  * 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;
 }
예제 #11
0
 /**
  * updates a record
  *
  *	@param	mixed		array of nodeid's
  *	@param	mixed		array of permissions that should be checked.
  *
  * 	@return	boolean
  */
 public function update($nodeid, $data)
 {
     $channelContentTypeId = vB_Types::instance()->getContentTypeId('vBForum_Channel');
     // Verify prefixid
     if ($this->contenttypeid != $channelContentTypeId and isset($data['prefixid'])) {
         $this->verifyPrefixid($data['prefixid']);
     } else {
         // Channel can't have a prefix
         unset($data['prefixid']);
     }
     // Verify post iconid
     if ($this->contenttypeid != $channelContentTypeId and isset($data['iconid'])) {
         $this->verifyPostIconid($data['iconid']);
     } else {
         // Channels can't have a post icon
         unset($data['iconid']);
     }
     $timeNow = vB::getRequest()->getTimeNow();
     $userContext = vB::getUserContext();
     //If this user doesn't have the featured permission and they are trying to set it,
     //Let's just quietly unset it.
     if (isset($data['featured'])) {
         if (!$userContext->getChannelPermission('moderatorpermissions', 'cansetfeatured', $data['parentid'])) {
             unset($data['featured']);
         }
     }
     //We can't allow directly setting parentid. That should only happen through the node api move function
     //And there are number of other fields that shouldn't be changed here. We have methods for the ones that can be changed at all.
     foreach (array('open', 'showopen', 'approved', 'showapproved', 'protected') as $field) {
         if (isset($data[$field])) {
             unset($data[$field]);
         }
     }
     if (isset($data['parentid'])) {
         //Only allow for articles.
         $content = $this->nodeApi->getNodeFullContent($nodeid);
         $content = array_pop($content);
         // you can't move it to the category it's already in
         if ($data['parentid'] != $content['parentid']) {
             // only allow this for articles (currently)
             if ($content['channeltype'] == 'article') {
                 if (!$userContext->getChannelPermission('forumpermissions', 'canmove', $data['parentid']) and !$userContext->getChannelPermission('moderatorpermissions', 'canmassmove', $data['parentid'])) {
                     throw new vB_Exception_Api('no_permission');
                 }
                 //If we got here, we're O.K. to move. let's do that now.
                 vB_Library::instance('node')->moveNodes($nodeid, $data['parentid']);
             }
         }
         unset($data['parentid']);
     }
     //We need to see if we need to update.
     $prior = vB_Library::instance('node')->getNodeBare($nodeid);
     if ($this->contenttypeid != $channelContentTypeId) {
         $content = $this->getFullContent($nodeid);
     }
     if (isset($data['publish_now']) and !empty($data['publish_now'])) {
         $data['publishdate'] = vB::getRequest()->getTimeNow();
     }
     if (empty($data['htmltitle']) and !empty($data['title'])) {
         $data['htmltitle'] = vB_String::htmlSpecialCharsUni(vB_String::stripTags($data['title']), false);
     }
     if (empty($data['urlident']) and !empty($data['title'])) {
         $data['urlident'] = vB_String::getUrlIdent($data['title']);
     }
     // Do not change publishdate or showpublished status unless it was explicitly set while calling update().
     if ((!isset($data['publishdate']) or empty($data['publishdate']) and $data['publishdate'] !== 0) and !empty($prior['publishdate'])) {
         $data['publishdate'] = $prior['publishdate'];
     }
     if ($this->isPublished($data)) {
         $published = 1;
     } else {
         $published = 0;
     }
     $nodevals = array();
     if ($published != $prior['showpublished']) {
         $nodevals['showpublished'] = $published;
     }
     // set default node options
     if ((empty($data['nodeoptions']) or !is_numeric($data['nodeoptions'])) and $prior['contenttypeid'] != $channelContentTypeId) {
         $parentFullContent = vB_Library::instance('node')->getNodeFullContent($prior['parentid']);
         if (!empty($parentFullContent[$prior['parentid']]['channeltype'])) {
             $data['nodeoptions'] = self::$defaultNodeOptions[$parentFullContent[$prior['parentid']]['channeltype']];
         } else {
             $data['nodeoptions'] = self::$defaultNodeOptions['default'];
         }
         // Add or remove any nodeoptions that have been explicitly passed in.
         // This would have otherwise happened in updateNodeOptions/setNodeOptions
         // (which is where it happens when adding a node as opposed to updating
         // a node), but since $data['nodeoptions'] is now defined, setNodeOptions
         // won't take care of setting these (it will just apply the int
         // nodeoptions value).
         $baseNodeOptions = vB_Api::instanceInternal('node')->getOptions();
         foreach ($baseNodeOptions as $baseOptionKey => $baseOptionVal) {
             if (isset($data[$baseOptionKey])) {
                 if (intval($data[$baseOptionKey])) {
                     $data['nodeoptions'] = $data['nodeoptions'] | intval($baseOptionVal);
                 } else {
                     $data['nodeoptions'] = $data['nodeoptions'] & ~intval($baseOptionVal);
                 }
             }
         }
     }
     //node table data.
     $data[vB_dB_Query::TYPE_KEY] = vB_dB_Query::QUERY_UPDATE;
     $data['nodeid'] = $nodeid;
     $data['lastupdate'] = $timeNow;
     //If the field passed is in the $nodeFields array then we update the node table.
     foreach ($data as $field => $value) {
         if (in_array($field, $this->nodeFields)) {
             $nodevals[$field] = $value;
         }
     }
     $index = empty($data['noIndex']);
     unset($data['noIndex']);
     // Update the content-type specific data
     if (!is_array($this->tablename)) {
         $tables = array($this->tablename);
     } else {
         $tables = $this->tablename;
     }
     $success = true;
     foreach ($tables as $table) {
         $structure = $this->assertor->fetchTableStructure('vBForum:' . $table);
         if (empty($structure) or empty($structure['structure'])) {
             throw new vB_Exception_Api('invalid_query_parameters');
         }
         $queryData = array();
         $queryData[vB_dB_Query::TYPE_KEY] = vB_dB_Query::QUERY_UPDATE;
         $queryData['nodeid'] = $nodeid;
         foreach ($structure['structure'] as $fieldname) {
             if (isset($data[$fieldname])) {
                 $queryData[$fieldname] = $data[$fieldname];
             }
         }
         //Now we have at least a query type and a nodeid. We put those in above. So if we don't
         //have at least one other value there's no reason to try an update.
         if (count($queryData) > 2) {
             $success = $success and $this->assertor->assertQuery('vBForum:' . $table, $queryData);
         }
     }
     if ($success) {
         // Handle Attachments
         // The text library (and most derivatives) can have attachments,
         // for the others, this is a no-op.
         $this->handleAttachments('update', $nodeid, $data);
         //Clear cached query info that would be significantly impacted
         $events = array('fUserContentChg_' . $prior['userid']);
         if ($prior['starter']) {
             $starterNodeInfo = vB_Library::instance('node')->getNodeBare($prior['starter']);
             $events[] = 'fUserContentChg_' . $starterNodeInfo['userid'];
         } else {
             if ($prior['parentid']) {
                 $starterNodeInfo = vB_Library::instance('node')->getNodeBare($prior['parentid']);
                 $events[] = 'fUserContentChg_' . $starterNodeInfo['userid'];
             }
         }
         $this->nodeApi->clearCacheEvents($nodeid);
         vB_Cache::instance()->allCacheEvent($events);
         if (isset($nodevals['publishdate']) and $nodevals['publishdate'] > $timeNow) {
             if (empty($nodevals['unpublishdate']) or $nodevals['unpublishdate'] > $nodevals['publishdate']) {
                 $nodevals['nextupdate'] = $nodevals['publishdate'];
             }
         } else {
             if (isset($nodevals['unpublishdate']) and $nodevals['unpublishdate'] > $timeNow) {
                 $nodevals['nextupdate'] = $nodevals['unpublishdate'];
             }
         }
         // handle approved
         if (isset($nodevals['approved'])) {
             if ($nodevals['approved']) {
                 $approved = 1;
                 $queryName = 'approveNode';
             } else {
                 $approved = 0;
                 $queryName = 'unapproveNode';
             }
             // set approved to parent...
             $this->assertor->assertQuery('vBForum:node', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_UPDATE, 'nodeid' => $nodeid, 'approved' => $approved));
             // and handle showapproved
             $this->assertor->assertQuery('vBForum:' . $queryName, array('nodeid' => $nodeid));
             unset($nodevals['approved']);
         }
         if (isset($nodevals)) {
             $nodevals[vB_dB_Query::TYPE_KEY] = vB_dB_Query::QUERY_UPDATE;
             $nodevals['nodeid'] = $nodeid;
             $success = $this->assertor->assertQuery('vBForum:node', $nodevals);
         }
         //We need to compare the current publishdate and unpublishdate values against the
         // parent.
         //But we can skip this if neither publish or unpublishdate is set
         $updateParents = false;
         if ($published != $prior['showpublished']) {
             $updateParents = true;
             //We are concerned about two possibilities. It could have gone from published to unpublished.
             //In either case we change by totalcount +1 (for ourselves.
             //Remember that published is always unpublished.
             //From unpublished to published.
             if ($published) {
                 $nodeUpdates = $this->nodeLibrary->publishChildren($nodeid);
                 // if $nodeUpdates is empty, that means no change was made to this node or its descendants,
                 // and no parent count changes are necessary. If it's not empty but doesn't have totalcount set,
                 // that means it possibly failed with a DB error. In such a case, we will just not update the
                 // counts but continue updating the node.
                 if (!empty($nodeUpdates) and isset($nodeUpdates['totalcount'])) {
                     // text-counts only change by 1 (or 0 for non-text types), because it only affects the immediate parent
                     $textChange = $this->textCountChange;
                     $textUnPubChange = -1 * $textChange;
                     // Note, below assumes that a DB had been diligent about
                     // keeping track of the count fields correctly.
                     $totalPubChange = $nodeUpdates['totalcount'] - $prior['totalcount'] + $textChange;
                     // we add the text change because self counts for ancestors' total counts
                     $totalUnPubChange = -1 * $totalPubChange;
                 } else {
                     $updateParents = false;
                 }
             } else {
                 $nodeUpdates = $this->nodeLibrary->unpublishChildren($nodeid);
                 if (!empty($nodeUpdates) and isset($nodeUpdates['totalunpubcount'])) {
                     $textUnPubChange = $this->textCountChange;
                     $textChange = -1 * $textUnPubChange;
                     $totalUnPubChange = $nodeUpdates['totalunpubcount'] - $prior['totalunpubcount'] + $textUnPubChange;
                     $totalPubChange = -1 * $totalUnPubChange;
                 } else {
                     $updateParents = false;
                 }
             }
             vB_Library::instance('node')->clearChildCache($nodeid);
         }
         //update the parent count if necessary
         if ($updateParents) {
             vB_Library::instance('node')->updateParentCounts($nodeid, $textChange, $textUnPubChange, $totalPubChange, $totalUnPubChange, $published);
         }
         //update viewperms from childs if needed, do we want this channel specific?
         if (isset($nodevals['viewperms']) and isset($prior['viewperms']) and $nodevals['viewperms'] != $prior['viewperms']) {
             vB_Api::instanceInternal('node')->setNodePerms($nodeid, array('viewperms' => $nodevals['viewperms']));
         }
         if ($index) {
             vB_Api::instanceInternal('Search')->index($nodeid);
         }
         // update user tags
         $tags = !empty($data['tags']) ? explode(',', $data['tags']) : array();
         $tagRet = vB_Api::instanceInternal('tags')->updateUserTags($nodeid, $tags);
         $this->updateNodeOptions($nodeid, $data);
         // Update childs nodeoptions
         $this->assertor->assertQuery('vBForum:updateChildsNodeoptions', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_STORED, 'parentid' => $nodeid));
         $this->nodeApi->clearCacheEvents(array($nodeid, $prior['parentid']));
         $loginfo = array('nodeid' => $prior['nodeid'], 'nodetitle' => $prior['title'], 'nodeusername' => $prior['authorname'], 'nodeuserid' => $prior['userid']);
         $extra = array();
         if ($nodevals !== null && isset($nodevals['title'])) {
             if ($prior['title'] != $nodevals['title']) {
                 $extra = array('newtitle' => $nodevals['title']);
             }
         }
         vB_Library_Admin::logModeratorAction($loginfo, 'node_edited_by_x', $extra);
         $updateEditLog = true;
         if (!vB::getUserContext()->hasPermission('genericoptions', 'showeditedby') and (isset($content[$nodeid]['edit_reason']) and $data['reason'] == $content[$nodeid]['edit_reason'] or !isset($content[$nodeid]['edit_reason']) and empty($data['reason']))) {
             $updateEditLog = false;
         }
         // Clear autosave table of this items entry
         if (vB::getCurrentSession()->get('userid') and !empty($data['rawtext'])) {
             $this->assertor->delete('vBForum:autosavetext', array('userid' => vB::getCurrentSession()->get('userid'), 'nodeid' => $nodeid, 'parentid' => $content[$nodeid]['parentid']));
         }
         // Log edit by info
         if ($updateEditLog and $this->contenttypeid != $channelContentTypeId and isset($content[$nodeid]['rawtext']) and isset($data['rawtext']) and $content[$nodeid]['rawtext'] != $data['rawtext'] and !empty($data['publishdate']) and $prior['publishdate'] and (!empty($data['reason']) or $data['publishdate'] < vB::getRequest()->getTimeNow() - $this->options['noeditedbytime'] * 60)) {
             $userinfo = vB::getCurrentSession()->fetch_userinfo();
             // save the postedithistory
             if ($this->options['postedithistory']) {
                 $record = $this->assertor->getRow('vBForum:postedithistory', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'original' => 1, 'nodeid' => $nodeid));
                 // insert original post on first edit
                 if (empty($record)) {
                     $this->assertor->assertQuery('vBForum:postedithistory', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT, 'nodeid' => $nodeid, 'userid' => $content[$nodeid]['userid'], 'username' => $content[$nodeid]['authorname'], 'dateline' => $data['publishdate'], 'pagetext' => $content[$nodeid]['rawtext'], 'original' => 1));
                 }
                 // insert the new version
                 $this->assertor->assertQuery('vBForum:postedithistory', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT, 'nodeid' => $nodeid, 'userid' => $userinfo['userid'], 'username' => $userinfo['username'], 'dateline' => vB::getRequest()->getTimeNow(), 'reason' => isset($data['reason']) ? vB5_String::htmlSpecialCharsUni($data['reason']) : '', 'pagetext' => isset($data['rawtext']) ? $data['rawtext'] : ''));
             }
             $this->assertor->assertQuery('editlog_replacerecord', array('nodeid' => $nodeid, 'userid' => $userinfo['userid'], 'username' => $userinfo['username'], 'timenow' => vB::getRequest()->getTimeNow(), 'reason' => isset($data['reason']) ? vB5_String::htmlSpecialCharsUni($data['reason']) : '', 'hashistory' => intval($this->options['postedithistory'])));
         }
         return true;
     }
     $this->nodeApi->clearCacheEvents(array($nodeid, $prior['parentid']));
     return false;
 }
예제 #12
0
 public static function vBVar($value)
 {
     return vB5_String::htmlSpecialCharsUni($value);
 }
예제 #13
0
 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('&amp;', '&', 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('&amp;', '&', 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('&amp;', '&', 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;
     }
 }