config_file = $dataDir . '/data/_site/config_search.php';
$this->GetConfig();
if( $this->Admin() ){
return;
}
//admin popup or visitor
$_REQUEST += array('q' => '');
if( \gp\tool::LoggedIn() && isset($_REQUEST['gpx_content']) && $_REQUEST['gpx_content'] == 'gpabox' ){
$this->AdminSearch();
}else{
$this->Search();
}
}
public function AdminSearch(){
global $langmessage;
$this->gpabox = true;
$this->show_stats = true;
$this->search_hidden = true;
echo '
';
echo '
';
echo '
';
echo '
';
if( !empty($_REQUEST['q']) ){
$this->RunQuery();
}
echo '
';
if( $this->search_count > 0 ){
echo '
' . $this->search_count . ' files searched
';
}
echo '
';
echo '
';
}
public function Search(){
global $langmessage;
$placeholder = $langmessage['Search'] . '…';
$custom_text = \gp\tool\Output::SelectText('Search');
if( $custom_text != '' ){
$placeholder = htmlspecialchars($custom_text) . '…';
}
echo '';
echo '
' . \gp\tool\Output::GetAddonText('Search') . '
';
echo '';
if( \gp\tool::LoggedIn() ){
$this->search_hidden = true;
}else{
$this->search_hidden = $this->search_config['search_hidden'];
}
$this->RunQuery();
if( \gp\tool::LoggedIn() ){
echo \gp\tool::Link(
'special_gpsearch',
$langmessage['configuration'],
'cmd=config',
['data-cmd' => 'gpabox', 'class' => 'search-config-link']
);
}
echo '';
}
public static function Gadget(){
global $langmessage;
$query = '';
if( isset($_GET['q']) ){
$query = $_GET['q'];
}
$placeholder = $langmessage['Search'] . '…';
$custom_text = \gp\tool\Output::SelectText('Search');
if( $custom_text != '' ){
$placeholder = htmlspecialchars($custom_text) . '…';
}
echo '';
echo \gp\tool\Output::GetAddonText('Search');
echo '
';
echo '';
}
public function RunQuery(){
if( !empty($_REQUEST['q']) ){
$this->SearchPattern();
$this->SearchPages();
\gp\tool\Plugins::Action('Search', array($this));
}
$this->ShowResults();
}
public function ShowResults(){
global $langmessage;
if( !count($this->results) ){
if( !empty($_REQUEST['q']) ){
echo '';
echo \gp\tool\Output::GetAddonText($langmessage['search_no_results']);
echo '
';
}
return;
}
$this->RemoveDups();
usort( $this->results, array($this, 'sort') );
$total = count($this->results);
$len = 20;
$total_pages = ceil($total/$len);
$current_page = self::ReqPage('pg', $total_pages );
$start = $current_page * $len;
$end = min($start+$len, $total);
$this->results = array_slice($this->results, $start, $len, true);
echo '';
echo sprintf($langmessage['SHOWING'], ($start + 1), $end, $total);
echo '
';
echo '';
foreach($this->results as $result){
echo '
';
echo isset($result['link']) ? $result['link'] : \gp\tool::Link(
$result['slug'],
$result['label'],
'highlight=' . rawurlencode($_REQUEST['q'])
); // $result['query']
if( $this->show_stats ){
echo ' ' . $result['matches'] . '' ;
}
echo '
';
echo $result['content'];
if( $this->show_stats ){
echo ' ';
echo $result['matches'] . ' match(es) out of ' . $result['words'] . ' words ';
echo ' ';
}
echo '';
}
echo '
';
$attr = 'class="page-link"';
if( $this->gpabox ){
$attr .= ' data-cmd="gpabox"';
echo '
';
}
$query = 'q=' . rawurlencode($_REQUEST['q']);
self::PaginationLinks($current_page, $total_pages, 'special_gpsearch', $query, 'pg', $attr);
}
/**
* Get the requested page number
*
* @param string $key
* @param int $total_pages
*/
public static function ReqPage($key='pg', $total_pages=null){
if( isset($_REQUEST[$key]) ){
$pg = (int)$_REQUEST[$key];
if( !is_null($total_pages) && $total_pages > 0 ){
$pg = min($pg, $total_pages - 1);
}
return max(0,$pg);
}
return 0;
}
/**
* Pagination links
*
*/
public static function PaginationLinks($current_page, $total_pages, $slug, $query, $page_key='pg', $attr=''){
global $langmessage;
if( $total_pages < 1 ){
return;
}
$prev_text = $langmessage['Previous'];
$next_text = $langmessage['Next'];
$current_text = $langmessage['Current Page'];
echo '';
}
public static function PaginationLink($slug, $label, $query, $page_key, $attr, $page){
if( $page > 0){
$query .= '&' . $page_key . '=' . $page;
}
echo '' . \gp\tool::Link($slug, $label, $query, $attr) . '';
}
/**
* Remove duplicate matches
*
*/
public function RemoveDups(){
$links = array();
foreach($this->results as $key => $result){
$link = isset($result['url']) ? $result['url'] : \gp\tool::GetUrl($result['slug'], $result['query']);
// $link = mb_strtolower($link);
if( in_array($link,$links) ){
unset($this->results[$key]);
}else{
$links[] = $link;
}
}
}
public function Sort($resulta,$resultb){
return $resulta['strength'] < $resultb['strength'];
}
public function SearchPattern(){
// $query = mb_strtolower($_REQUEST['q']);
$query = $_REQUEST['q'];
// Search for the exact query when it is doubled quoted
if (substr($query, 0, 1) == '"' && substr($query, -1) == '"') {
$query = substr($query, 1, -1);
$words = array($query);
} else {
preg_match_all("/\S+/", $query, $words);
$words = array_unique($words[0]);
}
$sub_pattern1 = $sub_pattern2 = array();
foreach($words as $word){
$sub_pattern1[] = '\b' . preg_quote($word, '#') . '\b';
$sub_pattern2[] = preg_quote($word, '#');
}
$this->search_pattern = '#(?:(' . implode('|', $sub_pattern1) . ')|(' . implode('|', $sub_pattern2) . '))#Siu';
}
public function Admin(){
global $langmessage;
if( !\gp\tool::LoggedIn() ){
return false;
}
$this->page->admin_links[] = array(
'special_gpsearch',
$langmessage['configuration'],
'cmd=config',
[ 'data-cmd' => 'gpabox', 'class' => 'admin-link-search-config' ]
);
$cmd = \gp\tool::GetCommand();
switch($cmd){
case 'save_config':
if( $this->SaveConfig() ){
break;
}
return true;
case 'config':
$this->Config($this->search_config);
return true;
}
return false;
}
/**
* Get the search configuration
*
*/
public function GetConfig(){
$this->search_config = \gp\tool\Files::Get($this->config_file, 'search_config');
$this->search_config += array('search_hidden' => false);
}
public function SaveConfig(){
global $langmessage;
if( isset($_POST['search_hidden']) ){
$search_config['search_hidden'] = true;
}else{
$search_config['search_hidden'] = false;
}
if( \gp\tool\Files::SaveData($this->config_file, 'search_config', $search_config) ){
msg($langmessage['SAVED']);
$this->search_config = $search_config;
return true;
}
msg($langmessage['OOPS']);
$this->Config($_POST);
return false;
}
public function Config($array=array()){
global $langmessage, $addonFolderName, $gp_index;
echo '' . $langmessage['Search'] . ' » ' . $langmessage['configuration'] . '
';
echo '';
}
public function SearchPages(){
global $gp_index;
ob_start();
foreach($gp_index as $title => $index){
if( \gp\tool::SpecialOrAdmin($title) === false ){
$this->SearchPage($title, $index);
}
}
ob_get_clean();
}
public function SearchPage($title, $index){
global $gp_menu, $gp_titles;
//search hidden?
if( !$this->search_hidden && !isset($gp_menu[$index]) ){
return;
}
//private pages
if( !\gp\tool::LoggedIn() && isset($gp_titles[$index]['vis']) ){
return;
}
$full_path = \gp\tool\Files::PageFile($title);
$file_sections = \gp\tool\Files::Get($full_path, 'file_sections');
if( !$file_sections ){
return;
}
$content = \gp\tool\Output\Sections::Render($file_sections, $title, \gp\tool\Files::$last_stats);
$label = \gp\tool::GetLabel($title);
$this->FindString($content, $label, $title);
}
public function FindString(&$content, $label, $slug, $link_query=''){
$this->search_count++;
//search all of the content include html
// $content = mb_strtolower($content);
$content = $label . ' ' . $content;
$match_count = preg_match_all($this->search_pattern, $content, $matches, PREG_OFFSET_CAPTURE);
if( $match_count < 1 ){
return;
}
$words = str_word_count($content);
$strength = $this->Strength($matches,$words);
//format content, remove html
$label_len = strlen($label);
$content = preg_replace('##si', '', $content);
$content = preg_replace('##si', '', $content);
$content = substr($content, $label_len);
$content = str_replace('>', '> ', $content);
$content = preg_replace('/\s+/', ' ', $content);
$content = strip_tags($content);
preg_match($this->search_pattern, $content, $matches, PREG_OFFSET_CAPTURE);
$start = isset($matches[0][1]) ? $matches[0][1] : 0;
//find a space at the beginning to start from
$i = 0;
do{
$i++;
$start_offset = $i * 10;
$start = max(0, $start - $start_offset);
$trimmed = substr($content, $start, 300);
$space = strpos($trimmed, ' ');
if( $space < $start_offset ){
$content = substr($trimmed, $space);
break;
}
}while( ($start-$start_offset) > 0);
//find a space at the end
if( strlen($content) > 250 ){
$space2 = strpos($content, ' ', $space + 220);
if( $space2 > 0 ){
$content = substr($content, 0, $space2);
}
}
$result = array();
$result['label'] = $label;
$result['slug'] = $slug;
$result['query'] = $link_query;
$result['content'] = preg_replace($this->search_pattern, '\1\2', $content);
$result['words'] = $words;
$result['matches'] = $match_count;
$result['strength'] = $strength;
$this->results[] = $result;
}
function Strength($matches, $len){
//space around search terms
$factor = 0;
foreach((array)$matches[1] as $match){
if( is_array($match) && $match[1] >= 0 ){
$factor += 3;
}
}
//no space around search term
foreach((array)$matches[2] as $match){
if( is_array($match) && $match[1] >= 0 ){
$factor += 1;
}
}
$strength = $factor / $len;
return round($strength, 8);
}
}