The version of vichan running on lainchan.org
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

175 lignes
5.3KB

  1. <?php
  2. require 'inc/functions.php';
  3. if (!$config['search']['enable']) {
  4. die(_("Post search is disabled"));
  5. }
  6. $queries_per_minutes = $config['search']['queries_per_minutes'];
  7. $queries_per_minutes_all = $config['search']['queries_per_minutes_all'];
  8. $search_limit = $config['search']['search_limit'];
  9. if (isset($config['search']['boards'])) {
  10. $boards = $config['search']['boards'];
  11. } else {
  12. $boards = listBoards(TRUE);
  13. }
  14. $body = Element('search_form.html', Array('boards' => $boards, 'b' => isset($_GET['board']) ? $_GET['board'] : false, 'search' => isset($_GET['search']) ? str_replace('"', '&quot;', utf8tohtml($_GET['search'])) : false));
  15. if(isset($_GET['search']) && !empty($_GET['search']) && isset($_GET['board']) && in_array($_GET['board'], $boards)) {
  16. $phrase = $_GET['search'];
  17. $_body = '';
  18. $query = prepare("SELECT COUNT(*) FROM ``search_queries`` WHERE `ip` = :ip AND `time` > :time");
  19. $query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
  20. $query->bindValue(':time', time() - ($queries_per_minutes[1] * 60));
  21. $query->execute() or error(db_error($query));
  22. if($query->fetchColumn() > $queries_per_minutes[0])
  23. error(_('Wait a while before searching again, please.'));
  24. $query = prepare("SELECT COUNT(*) FROM ``search_queries`` WHERE `time` > :time");
  25. $query->bindValue(':time', time() - ($queries_per_minutes_all[1] * 60));
  26. $query->execute() or error(db_error($query));
  27. if($query->fetchColumn() > $queries_per_minutes_all[0])
  28. error(_('Wait a while before searching again, please.'));
  29. $query = prepare("INSERT INTO ``search_queries`` VALUES (:ip, :time, :query)");
  30. $query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
  31. $query->bindValue(':time', time());
  32. $query->bindValue(':query', $phrase);
  33. $query->execute() or error(db_error($query));
  34. _syslog(LOG_NOTICE, 'Searched /' . $_GET['board'] . '/ for "' . $phrase . '"');
  35. // Cleanup search queries table
  36. $query = prepare("DELETE FROM ``search_queries`` WHERE `time` <= :time");
  37. $query->bindValue(':time', time() - ($queries_per_minutes_all[1] * 60));
  38. $query->execute() or error(db_error($query));
  39. openBoard($_GET['board']);
  40. $filters = Array();
  41. function search_filters($m) {
  42. global $filters;
  43. $name = $m[2];
  44. $value = isset($m[4]) ? $m[4] : $m[3];
  45. if(!in_array($name, array('id', 'thread', 'subject', 'name'))) {
  46. // unknown filter
  47. return $m[0];
  48. }
  49. $filters[$name] = $value;
  50. return $m[1];
  51. }
  52. $phrase = trim(preg_replace_callback('/(^|\s)(\w+):("(.*)?"|[^\s]*)/', 'search_filters', $phrase));
  53. if(!preg_match('/[^*^\s]/', $phrase) && empty($filters)) {
  54. _syslog(LOG_WARNING, 'Query too broad.');
  55. $body .= '<p class="unimportant" style="text-align:center">(Query too broad.)</p>';
  56. echo Element('page.html', Array(
  57. 'config'=>$config,
  58. 'title'=>'Search',
  59. 'body'=>$body,
  60. ));
  61. exit;
  62. }
  63. // Escape escape character
  64. $phrase = str_replace('!', '!!', $phrase);
  65. // Remove SQL wildcard
  66. $phrase = str_replace('%', '!%', $phrase);
  67. // Use asterisk as wildcard to suit convention
  68. $phrase = str_replace('*', '%', $phrase);
  69. // Remove `, it's used by table prefix magic
  70. $phrase = str_replace('`', '!`', $phrase);
  71. $like = '';
  72. $match = Array();
  73. // Find exact phrases
  74. if(preg_match_all('/"(.+?)"/', $phrase, $m)) {
  75. foreach($m[1] as &$quote) {
  76. $phrase = str_replace("\"{$quote}\"", '', $phrase);
  77. $match[] = $pdo->quote($quote);
  78. }
  79. }
  80. $words = explode(' ', $phrase);
  81. foreach($words as &$word) {
  82. if(empty($word))
  83. continue;
  84. $match[] = $pdo->quote($word);
  85. }
  86. $like = '';
  87. foreach($match as &$phrase) {
  88. if(!empty($like))
  89. $like .= ' AND ';
  90. $phrase = preg_replace('/^\'(.+)\'$/', '\'%$1%\'', $phrase);
  91. $like .= '`body` LIKE ' . $phrase . ' ESCAPE \'!\'';
  92. }
  93. foreach($filters as $name => $value) {
  94. if(!empty($like))
  95. $like .= ' AND ';
  96. $like .= '`' . $name . '` = '. $pdo->quote($value);
  97. }
  98. $like = str_replace('%', '%%', $like);
  99. $query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE " . $like . " ORDER BY `time` DESC LIMIT :limit", $board['uri']));
  100. $query->bindValue(':limit', $search_limit, PDO::PARAM_INT);
  101. $query->execute() or error(db_error($query));
  102. if($query->rowCount() == $search_limit) {
  103. _syslog(LOG_WARNING, 'Query too broad.');
  104. $body .= '<p class="unimportant" style="text-align:center">('._('Query too broad.').')</p>';
  105. echo Element('page.html', Array(
  106. 'config'=>$config,
  107. 'title'=>'Search',
  108. 'body'=>$body,
  109. ));
  110. exit;
  111. }
  112. $temp = '';
  113. while($post = $query->fetch()) {
  114. if(!$post['thread']) {
  115. $po = new Thread($post);
  116. } else {
  117. $po = new Post($post);
  118. }
  119. $temp .= $po->build(true) . '<hr/>';
  120. }
  121. if(!empty($temp))
  122. $_body .= '<fieldset><legend>' .
  123. sprintf(ngettext('%d result in', '%d results in', $query->rowCount()),
  124. $query->rowCount()) . ' <a href="/' .
  125. sprintf($config['board_path'], $board['uri']) . $config['file_index'] .
  126. '">' .
  127. sprintf($config['board_abbreviation'], $board['uri']) . ' - ' . $board['title'] .
  128. '</a></legend>' . $temp . '</fieldset>';
  129. $body .= '<hr/>';
  130. if(!empty($_body))
  131. $body .= $_body;
  132. else
  133. $body .= '<p style="text-align:center" class="unimportant">('._('No results.').')</p>';
  134. }
  135. echo Element('page.html', Array(
  136. 'config'=>$config,
  137. 'title'=>_('Search'),
  138. 'body'=>'' . $body
  139. ));