/** * search * * @param array $pSearchHash basically the same parameters as a regular list * @access public * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure */ function search(&$pSearchHash) { // PHP compatability issues include_once UTIL_PKG_PATH . 'PHP_Compat/Compat/Function/stripos.php'; global $gLibertySystem, $gBitSystem, $gBitUser, $gBitDbType; // initiate stuff BitBase::prepGetList($pSearchHash); $ret = $bindVars = array(); $selectSql = $whereSql = $orderSql = $joinSql = ''; // if all content has been selected, there is an empty value in the array if (isset($pSearchHash['content_type_guid']) && !is_array($pSearchHash['content_type_guid'])) { $pSearchHash['content_type_guid'] = array($pSearchHash['content_type_guid']); } if (!empty($pSearchHash['content_type_guid']) && in_array('', $pSearchHash['content_type_guid'])) { $pSearchHash['content_type_guid'] = array(); } // check if the user has the required permissions to view the requested content type foreach ($gLibertySystem->mContentTypes as $contentType) { if ((empty($pSearchHash['content_type_guid']) || in_array($contentType["content_type_guid"], $pSearchHash['content_type_guid'])) && $this->hasViewPermission($contentType["content_type_guid"])) { $allowed[] = $contentType["content_type_guid"]; } } if (in_array('bitcomment', $allowed)) { $pSearchHash['include_comments'] = TRUE; } if (!empty($allowed)) { $whereSql .= empty($whereSql) ? ' WHERE ' : ' AND '; $whereSql .= " lc.`content_type_guid` IN( " . implode(',', array_fill(0, count($allowed), '?')) . " ) "; $bindVars = array_merge($bindVars, $allowed); } else { $this->mErrors['permission'] = tra("You don't have the required permissions to search the requested content types."); } // create valid search SQL if ($errors = $this->prepareSearchSql($pSearchHash, $whereSql, $bindVars)) { $this->mErrors = $errors; } // get service SQL LibertyContent::getServicesSql('content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars, NULL, $pSearchHash); if (!empty($pSearchHash['sort_mode'])) { $orderSql = " ORDER BY lc." . $this->mDb->convertSortmode($pSearchHash['sort_mode']); } // only continue if we haven't choked so far if (empty($this->mErrors)) { $query = "\n\t\t\t\tSELECT \n\t\t\t\tuue.`login` AS `modifier_user`,\n\t\t\t\tuue.`real_name` AS `modifier_real_name`,\n\t\t\t\tuue.`user_id` AS `modifier_user_id`,\n\t\t\t\tuuc.`login` AS `creator_user`,\n\t\t\t\tuuc.`real_name` AS `creator_real_name`,\n\t\t\t\tuuc.`user_id` AS `creator_user_id`,\n\t\t\t\tlc.`data`, \n\t\t\t\tlc.`content_id`, \n\t\t\t\tlc.`title`, \n\t\t\t\tlcds.`data` AS `summary`, \n\t\t\t\tlct.`content_name`, \n\t\t\t\tlct.`content_name_plural`, \n\t\t\t\tlch.`hits`, \n\t\t\t\tlc.`last_modified`,\n\t\t\t\tlc.`created`,\n\t\t\t\tlc.`content_type_guid`\n\t\t\t\t{$selectSql}\n\t\t\t\tFROM `" . BIT_DB_PREFIX . "liberty_content` lc\n\t\t\t\t\tINNER JOIN `" . BIT_DB_PREFIX . "users_users` uuc ON (lc.`user_id`=uuc.`user_id`)\n\t\t\t\t\tINNER JOIN `" . BIT_DB_PREFIX . "users_users` uue ON (lc.`modifier_user_id`=uue.`user_id`)\n\t\t\t\t\tLEFT OUTER JOIN `" . BIT_DB_PREFIX . "liberty_content_data` lcds ON ( lc.`content_id` = lcds.`content_id` AND lcds.`data_type` = 'summary' )\n\t\t\t\t\tLEFT OUTER JOIN `" . BIT_DB_PREFIX . "liberty_content_types` lct ON ( lc.`content_type_guid` = lct.`content_type_guid` )\n\t\t\t\t\tLEFT OUTER JOIN `" . BIT_DB_PREFIX . "liberty_content_hits` lch ON ( lc.`content_id` = lch.`content_id` )\n\t\t\t\t{$joinSql} {$whereSql} {$orderSql}"; $result = $this->mDb->query($query, $bindVars, $pSearchHash['max_records'], $pSearchHash['offset']); while ($aux = $result->fetchRow()) { $data = $aux['summary'] . "\n" . $aux['data']; $aux['len'] = strlen($data); $lines = explode("\n", strip_tags($data)); foreach ($pSearchHash['findHash'] as $val) { $val = trim($val, "%"); $i = 0; foreach ($lines as $number => $line) { if ($i < 3 && !empty($line) && stripos($line, $val) !== FALSE) { $aux['display_lines'][$number + 1] = encode_email_addresses($line); $i++; } } if (!empty($aux['display_lines'])) { ksort($aux['display_lines']); } } $aux['display_url'] = BIT_ROOT_URL . "index.php?content_id=" . $aux['content_id']; $ret[] = $aux; } // do some custom sorting usort($ret, 'ilike_relevance_sort'); $query = "\n\t\t\t\tSELECT COUNT( lc.`content_id` )\n\t\t\t\tFROM `" . BIT_DB_PREFIX . "liberty_content` lc\n\t\t\t\t\tLEFT OUTER JOIN `" . BIT_DB_PREFIX . "liberty_content_data` lcds ON ( lc.`content_id` = lcds.`content_id` )\n\t\t\t\t\tLEFT OUTER JOIN `" . BIT_DB_PREFIX . "liberty_content_types` lct ON ( lc.`content_type_guid` = lct.`content_type_guid` )\n\t\t\t\t{$joinSql} {$whereSql}"; $pSearchHash['cant'] = $this->mDb->getOne($query, $bindVars); BitBase::postGetList($pSearchHash); return $ret; } else { return FALSE; } }
function parseData($pParseHash, &$pCommonObject) { global $gBitSystem, $gLibertySystem, $gBitUser, $page; $data = $pParseHash['data']; $contentId = $pParseHash['content_id']; // this is used for setting the links when section editing is enabled $section_count = 1; if ($gBitSystem->isPackageActive('wiki')) { require_once WIKI_PKG_PATH . 'BitPage.php'; } // if the object isn't loaded, we'll try and get the content prefs manually if (!empty($pCommonObject->mPrefs)) { $contentPrefs = $pCommonObject->mPrefs; } elseif (empty($pCommonObject->mContentId) && !empty($contentId)) { $contentPrefs = $pCommonObject->loadPreferences($contentId); } // only strip out html if needed if ($gBitSystem->isFeatureActive('content_allow_html') || $gBitSystem->isFeatureActive('content_force_allow_html')) { // we allow html unconditionally with this parser } elseif (!empty($contentPrefs['content_enter_html'])) { // we allow html on a per page basis } else { // we are parsing this page and we either have no way of checking permissions or we have no need for html $data = htmlspecialchars($data, ENT_NOQUOTES, 'UTF-8'); } // Extract [link] sections (to be re-inserted later) $noparsedlinks = array(); // This section matches [...]. // Added handling for [[foo] sections. -rlpowell preg_match_all("/(?<!\\[)\\[([^\\[][^\\]]+)\\]/", $data, $noparseurl); foreach (array_unique($noparseurl[1]) as $np) { $key = md5(BitSystem::genPass()); $aux["key"] = $key; $aux["data"] = $np; $noparsedlinks[] = $aux; $data = str_replace("{$np}", $key, $data); } // Replace special characters //done after url catching because otherwise urls of dyn. sites will be modified $this->parseHtmlchar($data); //$data = strip_tags($data); // BiDi markers $bidiCount = 0; $bidiCount = preg_match_all("/(\\{l2r\\})/", $data, $pages); $bidiCount += preg_match_all("/(\\{r2l\\})/", $data, $pages); $data = preg_replace("/\\{l2r\\}/", "<div dir='ltr'>", $data); $data = preg_replace("/\\{r2l\\}/", "<div dir='rtl'>", $data); $data = preg_replace("/\\{lm\\}/", "‎", $data); $data = preg_replace("/\\{rm\\}/", "‏", $data); // Parse MediaWiki-style pipe syntax tables. if ((strpos($data, "{|") === 0 || strpos($data, "\n{|") !== FALSE) && strpos($data, "\n|}") !== FALSE) { $data = $this->parseMediawikiTables($data); } // ============================================= this should go - xing // Replace dynamic variables // Dynamic variables are similar to dynamic content but they are editable // from the page directly, intended for short data, not long text but text // will work too // Now won't match HTML-style '%nn' letter codes. /* if (preg_match_all("/%([^% 0-9][^% 0-9][^% ]*)%/",$data,$dvars)) { // remove repeated elements $dvars = array_unique($dvars[1]); // Now replace each dynamic variable by a pair composed of the // variable value and a text field to edit the variable. Each foreach($dvars as $dvar) { $query = "select `data` from `".BIT_DB_PREFIX."liberty_dynamic_variables` where `name`=?"; $result = $this->mDb->query($query,Array($dvar)); if($result->numRows()) { $value = $result->fetchRow(); $value = $value["data"]; } else { //Default value is NULL $value = "NaV"; } // Now build 2 divs $id = 'dyn_'.$dvar; if( $gBitUser->hasPermission( 'p_wiki_edit_dynvar' ) ) { $span1 = "<span style='display:inline;' id='dyn_".$dvar."_display'><a class='dynavar' onclick='javascript:toggle_dynamic_var(\"$dvar\");' title='".tra('Click to edit dynamic variable').": $dvar'>$value</a></span>"; $span2 = "<span style='display:none;' id='dyn_".$dvar."_edit'><input type='text' name='dyn_".$dvar."' value='".$value."' /></span>"; } else { $span1 = "<span class='dynavar' style='display:inline;' id='dyn_".$dvar."_display'>$value</span>"; $span2 = ''; } $html = $span1.$span2; //It's important to replace only once $dvar_preg = preg_quote( $dvar ); $data = preg_replace("+%$dvar_preg%+",$html,$data,1); //Further replacements only with the value $data = str_replace("%$dvar%",$value,$data); } //At the end put an update button //<br /><div style="text-align:center"><input type="submit" name="dyn_update" value="'.tra('Update variables').'"/></div> $data='<form method="post" name="dyn_vars">'.$data.'<div style="display:none;"><input type="submit" name="_dyn_update" value="'.tra('Update variables').'"/></div></form>'; } */ // Replace boxes - add a new line that we can have something like: ^!heading^ without the need for a \n after the initial ^ - \n will be removed below $data = preg_replace("/\\^([^\\^]+)\\^/", "<div class=\"alert alert-info bitbox\"><!-- bitremovebr -->\n\$1</div>", $data); // Replace colors ~~color:text~~ $data = preg_replace("/\\~\\~([^\\:]+):([^\\~]+)\\~\\~/", "<span style=\"color:\$1;\">\$2</span>", $data); // Replace background colors ++color:text++ $data = preg_replace("/\\+\\+([^\\s][^\\: ]+):([^\\+]+)\\+\\+/", "<span style=\"background:\$1;\">\$2</span>", $data); // Underlined text $data = preg_replace("/===([^\\=]+)===/", "<span style=\"text-decoration:underline;\">\$1</span>", $data); // Center text $data = preg_replace("/::(.+?)::/", "<div style=\"text-align:center;\">\$1</div>", $data); // Line breaks $data = preg_replace('/%%%/', '<br />', $data); // reinsert hash-replaced links into page foreach ($noparsedlinks as $np) { $data = str_replace($np["key"], $np["data"], $data); } $links = $this->getLinks($data); // Note that there're links that are replaced foreach ($links as $link) { if (strstr($link, $_SERVER["SERVER_NAME"]) || !strstr($link, '//')) { $attributes = ''; } else { $attributes = 'class="external"'; } // comments and anonymously created pages get nofollow if ($pCommonObject && (get_class($pCommonObject) == 'comments' || isset($pCommonObject->mInfo['user_id']) && $pCommonObject->mInfo['user_id'] == ANONYMOUS_USER_ID)) { $attributes .= ' rel="nofollow" '; } // The (?<!\[) stuff below is to give users an easy way to // enter square brackets in their output; things like [[foo] // get rendered as [foo]. -rlpowell // prepare link for pattern usage $link2 = str_replace("/", "\\/", preg_quote($link)); $pattern = "/(?<!\\[)\\[{$link2}\\|([^\\]\\|]+)([^\\]])*\\]/"; $data = preg_replace($pattern, "<a {$attributes} href='{$link}'>\$1</a>", $data); $pattern = "/(?<!\\[)\\[{$link2}\\]/"; $data = preg_replace($pattern, "<a {$attributes} href='{$link}'>{$link}</a>", $data); } // Handle double square brackets. -rlpowell $data = str_replace("[[", "[", $data); // now that all links have been taken care of, we can replace all email addresses with the encoded form // this will also encode email addressed that have not been linked using [] $data = encode_email_addresses($data); if ($gBitSystem->getConfig('wiki_tables') != 'new') { // New syntax for tables if (preg_match_all("/\\|\\|(.*)\\|\\|/", $data, $tables)) { $maxcols = 1; $cols = array(); for ($i = 0; $i < count($tables[0]); $i++) { $rows = explode('||', $tables[0][$i]); $col[$i] = array(); for ($j = 0; $j < count($rows); $j++) { $cols[$i][$j] = explode('|', $rows[$j]); if (count($cols[$i][$j]) > $maxcols) { $maxcols = count($cols[$i][$j]); } } } for ($i = 0; $i < count($tables[0]); $i++) { $repl = '<table class="table">'; for ($j = 0; $j < count($cols[$i]); $j++) { $ncols = count($cols[$i][$j]); if ($ncols == 1 && !$cols[$i][$j][0]) { continue; } $repl .= '<tr class="' . ($j % 2 ? 'even' : 'odd') . '">'; for ($k = 0; $k < $ncols; $k++) { $repl .= '<td '; if ($k == $ncols - 1 && $ncols < $maxcols) { $repl .= ' colspan="' . ($maxcols - $k) . '"'; } $repl .= '>' . $cols[$i][$j][$k] . '</td>'; } $repl .= '</tr>'; } $repl .= '</table>'; $data = str_replace($tables[0][$i], $repl, $data); } } } else { // New syntax for tables // REWRITE THIS CODE if (preg_match_all("/\\|\\|(.*?)\\|\\|/s", $data, $tables)) { $maxcols = 1; $cols = array(); for ($i = 0; $i < count($tables[0]); $i++) { $rows = preg_split("/(\n|\\<br\\/\\>)/", $tables[0][$i]); $col[$i] = array(); for ($j = 0; $j < count($rows); $j++) { $rows[$j] = str_replace('||', '', $rows[$j]); $cols[$i][$j] = explode('|', $rows[$j]); if (count($cols[$i][$j]) > $maxcols) { $maxcols = count($cols[$i][$j]); } } } for ($i = 0; $i < count($tables[0]); $i++) { $repl = '<table class="table table-striped">'; if (preg_match("#^~#", $cols[$i][0][0]) && ($cols[$i][0][0] = preg_replace("#^~#", "", $cols[$i][0][0]))) { $th = TRUE; } else { $th = FALSE; } for ($j = 0; $j < count($cols[$i]); $j++) { $ncols = count($cols[$i][$j]); if ($ncols == 1 && !$cols[$i][$j][0]) { continue; } if ($j == 0 && $th) { $repl .= '<tr>'; } else { $repl .= '<tr class="' . ($j % 2 ? 'odd' : 'even') . '">'; } for ($k = 0; $k < $ncols; $k++) { $thd = $j == 0 && $th ? 'th' : 'td'; $repl .= "<{$thd}"; if ($k == $ncols - 1 && $ncols < $maxcols) { $repl .= ' colspan="' . ($maxcols - $k) . '"'; } $repl .= ">" . str_replace("\\n", "<br />", $cols[$i][$j][$k]) . "</{$thd}>"; } $repl .= '</tr>'; } $repl .= '</table>'; $data = str_replace($tables[0][$i], $repl, $data); } } } // Now tokenize the expression and process the tokens // Use tab and newline as tokenizing characters as well //// $lines = explode("\n", $data); $data = ''; $listbeg = array(); $divdepth = array(); $inTable = 0; // loop: process all lines foreach ($lines as $line) { // bitweaver now ignores leading space because it is *VERY* disturbing to unaware users - spiderr // unless 'feature_wiki_preserve_leading_blanks is set'. This is used for sites that have // migrated from TikiWiki and have lots of pages whose formatting depends on the presevation of leading spaces if (!$gBitSystem->isFeatureActive('wiki_preserve_leading_blanks')) { $line = trim($line); } // check if we are inside a table, if so, ignore monospaced and do // not insert <br/> $inTable += substr_count($line, "<table"); $inTable -= substr_count($line, "</table"); // If the first character is ' ' and we are not in pre then we are in pre // bitweaver now ignores leading space because it is *VERY* disturbing to unaware users - spiderr if (substr($line, 0, 1) == ' ' && $gBitSystem->isFeatureActive('wiki_monosp') && $inTable == 0) { // This is not list item -- must close lists currently opened while (count($listbeg)) { $data .= array_shift($listbeg); } // If the first character is space then // change spaces for $line = '<span style="font-family:monospace;">' . str_replace(' ', ' ', substr($line, 1)) . '</span>'; } // Title bars $line = preg_replace("/\\-\\=([^=]+)\\=\\-/", "<div class='bitbar'>\$1</div><!-- bitremovebr -->", $line); // Monospaced text $line = preg_replace("/-\\+(.*?)\\+-/", "<code>\$1</code>", $line); // Bold text $line = preg_replace("/__(.*?)__/", "<strong>\$1</strong>", $line); // Italics $line = preg_replace("/''(.*?)''/", "<em>\$1</em>", $line); // Definition lists $line = preg_replace("/^;([^:]+):(.+)/", "<dl><dt>\$1</dt><dd>\$2</dd></dl><!-- bitremovebr -->", $line); // This line is parseable then we have to see what we have if (substr($line, 0, 3) == '---') { // This is not list item -- must close lists currently opened while (count($listbeg)) { $data .= array_shift($listbeg); } $line = '<hr/>'; } else { $litype = substr($line, 0, 1); if ($litype == '*' || $litype == '#') { $listlevel = $this->howManyAtStart($line, $litype); $liclose = '</li>'; $addremove = 0; if ($listlevel < count($listbeg)) { while ($listlevel != count($listbeg)) { $data .= array_shift($listbeg); } if (substr(current($listbeg), 0, 5) != '</li>') { $liclose = ''; } } elseif ($listlevel > count($listbeg)) { $listyle = ''; while ($listlevel != count($listbeg)) { array_unshift($listbeg, $litype == '*' ? '</ul>' : '</ol>'); if ($listlevel == count($listbeg)) { $listate = substr($line, $listlevel, 1); if (($listate == '+' || $listate == '-') && !($litype == '*' && !strstr(current($listbeg), '</ul>') || $litype == '#' && !strstr(current($listbeg), '</ol>'))) { $thisid = 'id' . microtime() * 1000000; $data .= '<br /><a id="flipper' . $thisid . '" href="javascript:flipWithSign(\'' . $thisid . '\',1)">[' . ($listate == '-' ? '+' : '-') . ']</a>'; $listyle = ' id="' . $thisid . '" style="display:' . ($listate == '+' ? 'block' : 'none') . ';"'; $addremove = 1; } } $data .= $litype == '*' ? "<ul{$listyle}>" : "<ol{$listyle}>"; } $liclose = ''; } if ($litype == '*' && !strstr(current($listbeg), '</ul>') || $litype == '#' && !strstr(current($listbeg), '</ol>')) { $data .= array_shift($listbeg); $listyle = ''; $listate = substr($line, $listlevel, 1); if ($listate == '+' || $listate == '-') { $thisid = 'id' . microtime() * 1000000; $data .= '<br /><a id="flipper' . $thisid . '" href="javascript:flipWithSign(\'' . $thisid . '\',1)">[' . ($listate == '-' ? '+' : '-') . ']</a>'; $listyle = ' id="' . $thisid . '" style="display:' . ($listate == '+' ? 'block' : 'none') . ';"'; $addremove = 1; } $data .= $litype == '*' ? "<ul{$listyle}>" : "<ol{$listyle}>"; $liclose = ''; array_unshift($listbeg, $litype == '*' ? '</li></ul>' : '</li></ol>'); } $line = $liclose . '<li>' . substr($line, $listlevel + $addremove); if (substr(current($listbeg), 0, 5) != '</li>') { array_unshift($listbeg, '</li>' . array_shift($listbeg)); } } elseif ($litype == '+') { // Must append paragraph for list item of given depth... $listlevel = $this->howManyAtStart($line, $litype); // Close lists down to requested level while ($listlevel < count($listbeg)) { $data .= array_shift($listbeg); } if (count($listbeg)) { if (substr(current($listbeg), 0, 5) != '</li>') { array_unshift($listbeg, '</li>' . array_shift($listbeg)); $liclose = '<li>'; } else { $liclose = '<br />'; } } else { $liclose = ''; } $line = $liclose . substr($line, count($listbeg)); } else { // This is not list item -- must close lists currently opened while (count($listbeg)) { $data .= array_shift($listbeg); } // Get count of (possible) header signs at start $hdrlevel = $this->howManyAtStart($line, '!'); // If 1st char on line is '!' and its count less than 6 (max in HTML) if ($litype == '!' && $hdrlevel > 0 && $hdrlevel <= 6) { // OK. Parse headers here... $aclose = ''; $edit_link = ''; $addremove = 0; // Close lower level divs if opened for (; current($divdepth) >= $hdrlevel; array_shift($divdepth)) { $data .= '</div>'; } // May be spesial signs present after '!'s? $divstate = substr($line, $hdrlevel, 1); if ($divstate == '+' || $divstate == '-') { // OK. Must insert flipper after HEADER, and then open new div... $thisid = 'id' . microtime() * 1000000; $aclose = '<a id="flipper' . $thisid . '" href="javascript:flipWithSign(\'' . $thisid . '\',1)">[' . ($divstate == '-' ? '+' : '-') . ']</a>'; $aclose .= '<div id="' . $thisid . '" style="display:' . ($divstate == '+' ? 'block' : 'none') . ';">'; array_unshift($divdepth, $hdrlevel); $addremove = 1; } if ($gBitSystem->isFeatureActive('wiki_section_edit') && $gBitUser->hasPermission('p_wiki_update_page')) { if ($hdrlevel == $gBitSystem->getConfig('wiki_section_edit')) { $edit_url = WIKI_PKG_URL . "edit.php?content_id=" . $contentId . "&section=" . $section_count++; $edit_link = '<span class="editsection" style="float:right;margin-left:5px;">[<a href="' . $edit_url . '">' . tra("edit") . '</a>]</span>'; } } $hTagLevel = $hdrlevel + 1; // there should only be 1 <h1> per html document $line = $edit_link . "<h{$hTagLevel}>" . substr($line, $hdrlevel + $addremove) . "</h{$hTagLevel}>" . $aclose; } elseif (!strcmp($line, "...page...")) { // Close lists and divs currently opened while (count($listbeg)) { $data .= array_shift($listbeg); } while (count($divdepth)) { $data .= '</div>'; array_shift($divdepth); } // Leave line unchanged... index.php will split wiki here $line = "...page..."; } else { // Usual paragraph. if ($inTable == 0) { $line .= '<br />'; } } } } $data .= $line; } // Close lists may remains opened while (count($listbeg)) { $data .= array_shift($listbeg); } // Close header divs may remains opened for ($i = 1; $i <= count($divdepth); $i++) { $data .= '</div>'; } // Close BiDi DIVs if any for ($i = 0; $i < $bidiCount; $i++) { $data .= "</div>"; } $data = str_replace("<!-- bitremovebr --><br />", "", $data); return $data; }