PHP

Скрипт форума на PHP своими руками. Часть 7

Какой же форум без поиска? Вот о нем и поговорим сегодня. Функция searchForm() возвращает html формы для поиска по форуму.
<?php 
// Функция возвращает html формы для поиска по форуму 
function searchForm() 
{ 
  $html = ''; 
   
  $query = "SELECT id_forum, name FROM ".TABLE_FORUMS." WHERE 1 ORDER BY pos"; 
  $res = mysql_query( $query ); 
  if ( !$res ) { 
    $msg = 'Ошибка при формировании формы для поиска'; 
    $err = 'Ошибка при выполнении запроса: <br/>'. 
           $query.'<br/>'.mysql_errno().': '.mysql_error().'<br/>'. 
           '(Файл '. __FILE__ .', строка '. __LINE__ .')'; 
    return showErrorMessage( $msg, $err, true, '' ); 
  } 
  if ( mysql_num_rows( $res ) > 0 ) { 
    $options = '<option value="0">Все имеющиеся</option>'."\n"; 
    while( $forum = mysql_fetch_row( $res ) ) { 
      $options = $options.'<option value="'.$forum[0].'">'.$forum[1].'</option>'."\n"; 
    } 
    $html = file_get_contents( './templates/searchForm.html' ); 
    $action = $_SERVER['PHP_SELF'].'?action=searchResult'; 
    $html = str_replace( '{options}', $options, $html ); 
    $html = str_replace( '{action}', $action, $html ); 
  } 
   
  return $html; 
} 
?>

Файл шаблона поиска по форуму:
<form action="{action}" method="POST" name="searchForm"> 

<table class="showTable"> 
<tr> 
  <th colspan="2">Поиск по форуму</th> 
</tr> 
<tr> 
   <td width="30%" align="right">Что искать:</td> 
   <td width="70%"><input type="text" name="words" maxlength="64" value="" style="width:300px" /></td> 
</tr> 
<tr> 
   <td align="right">Форум:</td> 
   <td> 
   <select name="id_forum" style="width:300px"> 
   {options} 
   </select> 
   </td> 
</tr> 
<tr> 
   <td align="right">Где искать:</td> 
   <td> 
   <input type="radio" name="where" value="themes" checked /> Искать только в названиях тем<br/> 
   <input type="radio" name="where" value="posts" /> Искать только в текстах сообщений<br/> 
   <input type="radio" name="where" value="everywhere" /> Искать в названиях тем и текстах сообщений
   </td> 
</tr> 
<tr> 
  <td> </td> 
  <td><input type="submit" name="sendForm" value="Искать" /></td> 
</tr> 
</table> 

</form>

Функция searchResult() возвращает результат поиска по форуму:
<?php 
// Функция возвращает результат поиска по форуму 
function searchResult() 
{ 

  if ( isset( $_POST['words'] ) and 
       isset( $_POST['id_forum'] ) and 
       isset( $_POST['where'] ) ) 
  {     
    if ( empty( $_POST['words'] ) ) { 
      header( 'Location: '.$_SERVER['PHP_SELF'].'?action=searchForm' ); 
      die();   
    } 
    // Обрезаем строку до длины, указанной в атрибуте maxlength 
    $search = substr( $_POST['words'], 0, 64 ); 
    // Убираем пробелы в начале и конце строки поиска 
    $search = trim( $search ); 
    // Убираем все "ненормальные" символы 
    $good = preg_replace("#[^-a-zа-я\s]#i", " ", $search); 
    $good = trim( $good ); 
    if ( empty( $good ) ) { 
      header( 'Location: '.$_SERVER['PHP_SELF'].'?action=searchForm' ); 
      die();   
    } 
    // Сжимаем двойные пробелы 
    $good = ereg_replace(" +", " ", $good); 
         
    // Получаем корни искомых слов 
    $stemmer = new Lingua_Stem_Ru(); 
    $tmp = explode( " ", $good ); 
    foreach ( $tmp as $wrd ) { 
      // Если слово слишком короткое - не используем его 
      if ( strlen($wrd) < 3 ) continue; 
      $words[] = $stemmer->stem_word($wrd); 
    } 
    // Склеиваем массив $words обратно в строку 
    $string = implode( "* ", $words ); 
    $string = $string."*"; 
   
    // Теперь надо выяснить, где будем искать 
    $where = $_POST['where']; 
    $whereArray = array( 'themes', 'posts', 'everywhere' ); 
    if ( !in_array( $where, $whereArray ) ) $where = 'themes'; 
     
    // Записываем все данные в сессию - это нам понадобится при  
    // построении постраничной навигации результатов поиска 
    $_SESSION['search']['query'] = $search; 
    $_SESSION['search']['good'] = $good; 
    $_SESSION['search']['words'] = $words; 
    // Это нам потребуется для подсветки искомых слов 
    $_SESSION['search']['words'] = implode( '|', $words ); 
    $_SESSION['search']['string'] = $string; 
    $_SESSION['search']['where'] = $where; 
    $id_forum = (int)$_POST['id_forum']; 
    if ( $id_forum < 0 ) $id_forum = 0; 
    $_SESSION['search']['id_forum'] = $id_forum; 
     
    header( 'Location: '.$_SERVER['PHP_SELF'].'?action=searchResult' ); 
    die(); 
  } 
   
  if ( !isset( $_SESSION['search'] ) ) { 
    header( 'Location: '.$_SERVER['PHP_SELF'] ); 
    die();   
  } 
     
   
  if ( $_SESSION['search']['where'] == 'themes' ) 
    $result = searchResultThemes(); // Если поиск только по названиям тем 
  else if ( $_SESSION['search']['where'] == 'posts' ) 
    $result = searchResultPosts(); // Если поиск только в сообщениях (постах) 
  else 
    $result = searchResultEverywhere(); // Если поиск в названиях тем и сообщениях 
     
  $html = '<table class="showTable">'."\n"; 
  $html = $html.'<tr>'."\n"; 
  $html = $html.'<th>Результаты поиска</th>'."\n"; 
  $html = $html.'<tr>'."\n"; 
  $html = $html.'</table>'."\n"; 

  $html = $html.$result."\n"; 

  return $html; 
} 
?>

Для извлечения корней русских слов используется стеммер Портера.

Дальше - три вспомогательные функции. Функция searchResultThemes() возвращает результат поиска только в названиях тем:
<?php 
// Поиск только в названиях тем 
function searchResultThemes() 
{ 
  // Составляем запрос к БД, чтобы узнать количество записей в результатах поиска -  
  // это нужно для построения постраничной навигации 
  $forum = ''; 
  if ( $_SESSION['search']['id_forum'] ) $forum = ' AND id_forum='.$_SESSION['search']['id_forum']; 
  $query = "SELECT COUNT(*) 
            FROM ".TABLE_THEMES."  
            WHERE MATCH (name) AGAINST ('".$_SESSION['search']['string']."' IN BOOLEAN MODE)".$forum;            
  $res = mysql_query( $query ); 
  $total = mysql_result( $res, 0, 0 ); 
  if ( $total == 0 ) return 'По вашему запросу ничего не найдено'; 
  
  // Число страниц результатов поиска (постраничная навигация) 
  $cntPages = ceil( $total / SEARCH_THEMES_PER_PAGE ); 
   
  // Проверяем передан ли номер текущей страницы (постраничная навигация) 
  if ( isset($_GET['page']) ) { 
    $page = (int)$_GET['page']; 
    if ( $page < 1 ) $page = 1; 
  } else { 
    $page = 1; 
  } 

  if ( $page > $cntPages ) $page = $cntPages; 
  // Начальная позиция (постраничная навигация) 
  $start = ( $page - 1 ) * SEARCH_THEMES_PER_PAGE; 

  // Строим постраничную навигацию, если это необходимо 
  if ( $cntPages > 1 ) { 
    // Функция возвращает html меню для постраничной навигации 
    $pages = pageIterator( $page, $cntPages, $_SERVER['PHP_SELF'].'?action=searchResult' );            
  } 

  $query = "SELECT id_theme, name, id_forum  
            FROM ".TABLE_THEMES."  
            WHERE MATCH (name) AGAINST ('".$_SESSION['search']['string']."' IN BOOLEAN MODE)".$forum." 
            ORDER BY MATCH (name) AGAINST ('".$_SESSION['search']['string']."' IN BOOLEAN MODE) DESC  
            LIMIT ".$start.", ".SEARCH_THEMES_PER_PAGE;             
  $res = mysql_query( $query ); 
  $html = "<ul>\n"; 
  while ( $theme = mysql_fetch_array( $res ) ) { 
    $html = $html.'<li><a class="topictitle" href="'.$_SERVER["PHP_SELF"]."?action=showTheme". 
            '&idForum='.$theme['id_forum'].'&id_theme='.$theme['id_theme'].'&page=1">'. 
            $theme['name'].'</a></li>'."\n";     
  } 
  $html = $html."</ul>\n"; 

  // Постраничная навигация 
  if ( isset( $pages ) ) $html = $html.$pages."\n"; 
   
  return $html;     
} 
?>

Функция searchResultPosts() возвращает результат поиска только в сообщениях (постах):
<?php 
// Поиск только в сообщениях (постах) 
function searchResultPosts() 
{ 
  // Составляем запрос к БД, чтобы узнать количество записей в результатах поиска -  
  // это нужно для построения постраничной навигации 
  $forum = ''; 
  if ( $_SESSION['search']['id_forum'] ) $forum = ' AND b.id_forum='.$_SESSION['search']['id_forum']; 
  $query = "SELECT COUNT(*)  
            FROM ".TABLE_POSTS." a INNER JOIN ".TABLE_THEMES." b 
            ON a.id_theme=b.id_theme  
            WHERE MATCH (a.name) AGAINST ('".$_SESSION['search']['string']."' IN BOOLEAN MODE)".$forum; 
             
  $res = mysql_query( $query ); 
  $total = mysql_result( $res, 0, 0 ); 

  if ( $total == 0 ) return 'По вашему запросу ничего не найдено'; 
  
  // Число страниц результатов поиска (постраничная навигация) 
  $cntPages = ceil( $total / SEARCH_POSTS_PER_PAGE ); 
   
  // Проверяем передан ли номер текущей страницы (постраничная навигация) 
  if ( isset($_GET['page']) ) { 
    $page = (int)$_GET['page']; 
    if ( $page < 1 ) $page = 1; 
  } else { 
    $page = 1; 
  } 

  if ( $page > $cntPages ) $page = $cntPages; 
  // Начальная позиция (постраничная навигация) 
  $start = ( $page - 1 ) * SEARCH_POSTS_PER_PAGE; 

  // Строим постраничную навигацию, если это необходимо 
  if ( $cntPages > 1 ) { 
    // Функция возвращает html меню для постраничной навигации 
    $pages = pageIterator( $page, $cntPages, $_SERVER['PHP_SELF'].'?action=searchResult' );            
  } 

  $query = "SELECT a.id_post, a.name, a.id_theme, b.id_forum, b.name  
            FROM ".TABLE_POSTS." a INNER JOIN ".TABLE_THEMES." b 
            ON a.id_theme=b.id_theme  
            WHERE MATCH (a.name) AGAINST ('".$_SESSION['search']['string']."' IN BOOLEAN MODE)".$forum." 
            ORDER BY MATCH (a.name) AGAINST ('".$_SESSION['search']['string']."' IN BOOLEAN MODE) DESC 
            LIMIT ".$start.", ".SEARCH_POSTS_PER_PAGE; 
         
  $res = mysql_query( $query ); 
  $html = ''; 
  while ( $post = mysql_fetch_row( $res ) ) { 
     
    $html = $html.'<div style="margin: 5px 0 5px 0">'."\n"; 
    $html = $html.'<img src="./images/folder.gif" width="19" height="18" alt="" align="top" /> 
            <a class="topictitle" href="'.$_SERVER["PHP_SELF"]."?action=showTheme". 
            '&idForum='.$post[3].'&id_theme='.$post[2].'&page=1">'.$post[4].'</a>'."\n"; 
    $html = $html.'</div>'."\n";         
     
    $html = $html.'<table class="postTable">'."\n"; 
    $html = $html.'<tr>'."\n"; 
    $html = $html.'<td>'."\n"; 
    $message = print_page( $post[1] ); 
    $message = preg_replace("/\b(".$_SESSION['search']['words'].")(.*?)\b/i",  
               "<span style='color:red; font-weight:bold'>\\0</span>", $message); 
    $html = $html.$message."\n"; 
    $html = $html.'</td>'."\n"; 
    $html = $html.'</tr>'."\n"; 
    $html = $html."</table>\n"; 
  } 

  // Постраничная навигация 
  if ( isset( $pages ) ) $html = $html.$pages."\n"; 
   
  return $html;     
} 
?>

Функция searchResultEverywhere() возвращает результат поиска в названиях тем и сообщениях (постах):
<?php 
// Поиск в названиях тем и сообщениях 
function searchResultEverywhere() 
{ 
  // Составляем запрос к БД, чтобы узнать количество записей в результатах поиска -  
  // это нужно для построения постраничной навигации 
  $forum = ''; 
  if ( $_SESSION['search']['id_forum'] ) $forum = ' AND b.id_forum='.$_SESSION['search']['id_forum']; 
  $query = "SELECT COUNT(*)  
            FROM ".TABLE_POSTS." a INNER JOIN ".TABLE_THEMES." b 
            ON a.id_theme=b.id_theme  
            WHERE MATCH (a.name, b.name) AGAINST ('".$_SESSION['search']['string']."' IN BOOLEAN MODE)".$forum; 
             
  $res = mysql_query( $query ); 
  $total = mysql_result( $res, 0, 0 ); 

  if ( $total == 0 ) return 'По вашему запросу ничего не найдено'; 
  
  // Число страниц результатов поиска (постраничная навигация) 
  $cntPages = ceil( $total / SEARCH_EVERYWHERE_PER_PAGE ); 
   
  // Проверяем передан ли номер текущей страницы (постраничная навигация) 
  if ( isset($_GET['page']) ) { 
    $page = (int)$_GET['page']; 
    if ( $page < 1 ) $page = 1; 
  } else { 
    $page = 1; 
  } 

  if ( $page > $cntPages ) $page = $cntPages; 
  // Начальная позиция (постраничная навигация) 
  $start = ( $page - 1 ) * SEARCH_EVERYWHERE_PER_PAGE; 

  // Строим постраничную навигацию, если это необходимо 
  if ( $cntPages > 1 ) { 
    // Функция возвращает html меню для постраничной навигации 
    $pages = pageIterator( $page, $cntPages, $_SERVER['PHP_SELF'].'?action=searchResult' );            
  } 

  $query = "SELECT a.id_post, a.name, a.id_theme, b.id_forum, b.name  
            FROM ".TABLE_POSTS." a INNER JOIN ".TABLE_THEMES." b 
            ON a.id_theme=b.id_theme  
            WHERE MATCH (a.name, b.name) AGAINST ('".$_SESSION['search']['string']."' IN BOOLEAN MODE)".$forum." 
            ORDER BY MATCH (a.name, b.name) AGAINST ('".$_SESSION['search']['string']."' IN BOOLEAN MODE) DESC 
            LIMIT ".$start.", ".SEARCH_EVERYWHERE_PER_PAGE; 
         
  $res = mysql_query( $query ); 
  $html = '';  
  while ( $post = mysql_fetch_row( $res ) ) { 
   
    $html = $html.'<div style="margin: 5px 0 5px 0">'."\n"; 
    $html = $html.'<img src="./images/folder.gif" width="19" height="18" alt="" align="top" /> 
            <a class="topictitle" href="'.$_SERVER["PHP_SELF"]."?action=showTheme". 
            '&idForum='.$post[3].'&id_theme='.$post[2].'&page=1">'.$post[4].'</a>'."\n"; 
    $html = $html.'</div>'."\n";         
     
    $html = $html.'<table class="postTable">'."\n";     
    $html = $html.'<tr>'."\n"; 
    $html = $html.'<td>'."\n"; 
    $message = print_page( $post[1] ); 
    $message = preg_replace("/\b(".$_SESSION['search']['words'].")(.*?)\b/i",  
               "<span style='color:red; font-weight:bold'>\\0</span>", $message); 
    $html = $html.$message."\n"; 
    $html = $html.'</td>'."\n"; 
    $html = $html.'</tr>'."\n"; 
    $html = $html."</table>\n"; 
  } 
   
  // Постраничная навигация 
  if ( isset( $pages ) ) $html = $html.$pages."\n"; 
   
  return $html; 
} 
?>

Продолжение следует...
Теги:
форум
Добавлено: 22 Сентября 2013 01:35:55 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...