[ Index ]

PHP Cross Reference of MyBB 1.8.36

title

Body

[close]

/inc/ -> functions_search.php (source)

   1  <?php
   2  /**
   3   * MyBB 1.8
   4   * Copyright 2014 MyBB Group, All Rights Reserved
   5   *
   6   * Website: http://www.mybb.com
   7   * License: http://www.mybb.com/about/license
   8   *
   9   */
  10  
  11  /**
  12   * Build a select box list of forums the current user has permission to search
  13   *
  14   * @param int $pid The parent forum ID to start at
  15   * @param int $selitem The selected forum ID
  16   * @param int $addselect Add select boxes at this call or not
  17   * @param string $depth The current depth
  18   * @return string The forum select boxes
  19   */
  20  function make_searchable_forums($pid=0, $selitem=0, $addselect=1, $depth='')
  21  {
  22      global $db, $pforumcache, $permissioncache, $mybb, $selecteddone, $forumlist, $forumlistbits, $theme, $templates, $lang, $forumpass;
  23      $pid = (int)$pid;
  24  
  25      if(!is_array($pforumcache))
  26      {
  27          // Get Forums
  28          $query = $db->simple_select("forums", "pid,disporder,fid,password,name", "linkto='' AND active!=0", array('order_by' => "pid, disporder"));
  29          while($forum = $db->fetch_array($query))
  30          {
  31              $pforumcache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum;
  32          }
  33      }
  34      if(!is_array($permissioncache))
  35      {
  36          $permissioncache = forum_permissions();
  37      }
  38      if(is_array($pforumcache[$pid]))
  39      {
  40          foreach($pforumcache[$pid] as $key => $main)
  41          {
  42              foreach($main as $key => $forum)
  43              {
  44                  $perms = $permissioncache[$forum['fid']];
  45                  if(($perms['canview'] == 1 || $mybb->settings['hideprivateforums'] == 0) && $perms['cansearch'] != 0)
  46                  {
  47                      if($selitem == $forum['fid'])
  48                      {
  49                          $optionselected = "selected";
  50                          $selecteddone = "1";
  51                      }
  52                      else
  53                      {
  54                          $optionselected = '';
  55                          $selecteddone = "0";
  56                      }
  57                      if(forum_password_validated($forum, true))
  58                      {
  59                          eval("\$forumlistbits .= \"".$templates->get("search_forumlist_forum")."\";");
  60                      }
  61                      if(!empty($pforumcache[$forum['fid']]))
  62                      {
  63                          $newdepth = $depth."&nbsp;&nbsp;&nbsp;&nbsp;";
  64                          $forumlistbits .= make_searchable_forums($forum['fid'], $selitem, 0, $newdepth);
  65                      }
  66                  }
  67              }
  68          }
  69      }
  70      if($addselect)
  71      {
  72          eval("\$forumlist = \"".$templates->get("search_forumlist")."\";");
  73      }
  74      return $forumlist;
  75  }
  76  
  77  /**
  78   * Build a comma separated list of the forums this user cannot search
  79   *
  80   * @param int $pid The parent ID to build from
  81   * @param int $first First rotation or not (leave at default)
  82   * @return string return a CSV list of forums the user cannot search
  83   */
  84  function get_unsearchable_forums($pid=0, $first=1)
  85  {
  86      global $forum_cache, $permissioncache, $mybb, $unsearchableforums, $unsearchable, $templates, $forumpass;
  87  
  88      $pid = (int)$pid;
  89  
  90      if(!is_array($forum_cache))
  91      {
  92          cache_forums();
  93      }
  94      if(!is_array($permissioncache))
  95      {
  96          $permissioncache = forum_permissions();
  97      }
  98      foreach($forum_cache as $fid => $forum)
  99      {
 100          if($permissioncache[$forum['fid']])
 101          {
 102              $perms = $permissioncache[$forum['fid']];
 103          }
 104          else
 105          {
 106              $perms = $mybb->usergroup;
 107          }
 108  
 109          $parents = explode(",", $forum['parentlist']);
 110          if(is_array($parents))
 111          {
 112              foreach($parents as $parent)
 113              {
 114                  if($forum_cache[$parent]['active'] == 0)
 115                  {
 116                      $forum['active'] = 0;
 117                  }
 118              }
 119          }
 120  
 121          if($perms['canview'] != 1 || $perms['cansearch'] != 1 || !forum_password_validated($forum, true) || $forum['active'] == 0)
 122          {
 123              if($unsearchableforums)
 124              {
 125                  $unsearchableforums .= ",";
 126              }
 127              $unsearchableforums .= "'{$forum['fid']}'";
 128          }
 129      }
 130      $unsearchable = $unsearchableforums;
 131  
 132      // Get our unsearchable password protected forums
 133      $pass_protected_forums = get_password_protected_forums();
 134  
 135      if($unsearchable && $pass_protected_forums)
 136      {
 137          $unsearchable .= ",";
 138      }
 139  
 140      if($pass_protected_forums)
 141      {
 142          $unsearchable .= implode(",", $pass_protected_forums);
 143      }
 144  
 145      return $unsearchable;
 146  }
 147  
 148  /**
 149   * Build query condition for threads/posts the user is allowed to see.
 150   * Will return for example:
 151   *  - visible = 1 - for normal users
 152   *  - visible >= -1 - for admins & super mods
 153   *  - (visible = 1 OR (visible = ? AND fid IN ...)) - for forum moderators
 154   * 
 155   * @param string $table_alias The alias of the table eg t to use t.visible instead of visible
 156   * @return string the query condition 
 157   */
 158  function get_visible_where($table_alias = null)
 159  {
 160      global $db, $mybb;
 161  
 162      $aliasdot = '';
 163      if(!empty($table_alias))
 164      {
 165          $aliasdot = $table_alias.'.';
 166      }
 167  
 168      if($mybb->usergroup['issupermod'] == 1)
 169      {
 170          // Super moderators (and admins)
 171          return "{$aliasdot}visible >= -1";
 172      }
 173      elseif(is_moderator())
 174      {
 175          // Normal moderators
 176          $unapprove_forums = array();
 177          $deleted_forums = array();
 178          $unapproved_where = "({$aliasdot}visible = 1";
 179          
 180          $moderated_fids = get_moderated_fids($mybb->user['uid']);
 181  
 182          if($moderated_fids !== false)
 183          {
 184              foreach($moderated_fids as $fid)
 185              {
 186                  if(!is_moderator($fid))
 187                  {
 188                      // Shouldn't occur.
 189                      continue;
 190                  }
 191      
 192                  // Use moderates this forum
 193                  $modperms = get_moderator_permissions($fid, $mybb->user['uid']);
 194      
 195                  if($modperms['canviewunapprove'] == 1)
 196                  {
 197                      $unapprove_forums[] = $fid;
 198                  }
 199      
 200                  if($modperms['canviewdeleted'] == 1)
 201                  {
 202                      $deleted_forums[] = $fid;
 203                  }
 204              }
 205      
 206              if(!empty($unapprove_forums))
 207              {
 208                  $unapproved_where .= " OR ({$aliasdot}visible = 0 AND {$aliasdot}fid IN(".implode(',', $unapprove_forums)."))";
 209              }
 210              if(!empty($deleted_forums))
 211              {
 212                  $unapproved_where .= " OR ({$aliasdot}visible = -1 AND {$aliasdot}fid IN(".implode(',', $deleted_forums)."))";
 213              }
 214              $unapproved_where .= ')';
 215      
 216              return $unapproved_where;
 217          }
 218      }
 219  
 220      // Normal users
 221      if($mybb->user['uid'] > 0 && $mybb->settings['showownunapproved'] == 1)
 222      {
 223          return "({$aliasdot}visible = 1 OR ({$aliasdot}visible = 0 AND {$aliasdot}uid = {$mybb->user['uid']}))";
 224      }
 225      return "{$aliasdot}visible = 1";
 226  }
 227  
 228  /**
 229   * Build a array list of the forums this user cannot search due to password protection
 230   *
 231   * @param array $fids the fids to check (leave blank to check all forums)
 232   * @return array return a array list of password protected forums the user cannot search
 233   */
 234  function get_password_protected_forums($fids=array())
 235  {
 236      global $forum_cache, $mybb;
 237  
 238      if(!is_array($fids))
 239      {
 240          return false;
 241      }
 242  
 243      if(!is_array($forum_cache))
 244      {
 245          $forum_cache = cache_forums();
 246          if(!$forum_cache)
 247          {
 248              return false;
 249          }
 250      }
 251  
 252      if(empty($fids))
 253      {
 254          $fids = array_keys($forum_cache);
 255      }
 256  
 257      $pass_fids = array();
 258      foreach($fids as $fid)
 259      {
 260          if(!forum_password_validated($forum_cache[$fid], true))
 261          {
 262              $pass_fids[] = $fid;
 263              $pass_fids = array_merge($pass_fids, get_child_list($fid));
 264          }
 265      }
 266      return array_unique($pass_fids);
 267  }
 268  
 269  /**
 270   * Clean search keywords and make them safe for querying
 271   *
 272   * @param string $keywords The keywords to be cleaned
 273   * @return string The cleaned keywords
 274   */
 275  function clean_keywords($keywords)
 276  {
 277      global $db, $lang;
 278  
 279      $keywords = my_strtolower($keywords);
 280      $keywords = $db->escape_string_like($keywords);
 281      $keywords = preg_replace("#\*{2,}#s", "*", $keywords);
 282      $keywords = str_replace("*", "%", $keywords);
 283      $keywords = preg_replace("#\s+#s", " ", $keywords);
 284      $keywords = str_replace('\\"', '"', $keywords);
 285  
 286      // Search for "and" or "or" and remove if it's at the beginning
 287      $keywords = trim($keywords);
 288      if(my_strpos($keywords, "or") === 0)
 289      {
 290          $keywords = substr_replace($keywords, "", 0, 2);
 291          $keywords = " ".$keywords;
 292      }
 293  
 294      if(my_strpos($keywords, "and") === 0)
 295      {
 296          $keywords = substr_replace($keywords, "", 0, 3);
 297          $keywords = " ".$keywords;
 298      }
 299  
 300      if(!$keywords)
 301      {
 302          error($lang->error_nosearchterms);
 303      }
 304  
 305      return $keywords;
 306  }
 307  
 308  /**
 309   * Clean search keywords for fulltext searching, making them safe for querying
 310   *
 311   * @param string $keywords The keywords to be cleaned
 312   * @return string|bool The cleaned keywords or false on failure
 313   */
 314  function clean_keywords_ft($keywords)
 315  {
 316      if(!$keywords)
 317      {
 318          return false;
 319      }
 320      $keywords = my_strtolower($keywords);
 321      $keywords = str_replace("%", "\\%", $keywords);
 322      $keywords = preg_replace("#\*{2,}#s", "*", $keywords);
 323      $keywords = preg_replace("#([\[\]\|\.\,:])#s", " ", $keywords);
 324      // Separate braces for further processing
 325      $keywords = preg_replace("#((\+|-|<|>|~)?\(|\))#s", " $1 ", $keywords);
 326      $keywords = preg_replace("#\s+#s", " ", $keywords);
 327  
 328      global $mybb;
 329  
 330      $min_word_length = (int) $mybb->settings['minsearchword'];
 331      if($min_word_length <= 0)
 332      {
 333          $min_word_length = 3;
 334      }
 335      $min_word_length -= 1;
 336  
 337      $word_length_regex = '';
 338      if($min_word_length > 1)
 339      {
 340          $word_length_regex = "{1,{$min_word_length}}";
 341      }
 342  
 343      // Replaces less than 3 characters
 344      $keywords = preg_replace("/(\b.{$word_length_regex})(\s)|(\b.{$word_length_regex}$)/u", '$2', $keywords);
 345      // Collapse multiple spaces
 346      $keywords = preg_replace('/(\s)+/', '$1', $keywords);
 347      $keywords = trim($keywords);
 348  
 349      $words = array(array());
 350  
 351      // Fulltext search syntax validation: http://dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html
 352      // Search for phrases
 353      $keywords = explode("\"", $keywords);
 354      $boolean = array('+');
 355      // Brace depth
 356      $depth = 0;
 357      $phrase_operator = '+';
 358      foreach($keywords as $phrase)
 359      {
 360          $phrase = trim($phrase);
 361          if($phrase != '')
 362          {
 363              if($inquote)
 364              {
 365                  if($phrase_operator)
 366                  {
 367                      $boolean[$depth] = $phrase_operator;
 368                  }
 369                  // Phrases do not need further processing
 370                  $words[$depth][] = "{$boolean[$depth]}\"{$phrase}\"";
 371                  $boolean[$depth] = $phrase_operator = '+';
 372              }
 373              else
 374              {
 375                  // Split words
 376                  $split_words = preg_split("#\s{1,}#", $phrase, -1);
 377                  if(!is_array($split_words))
 378                  {
 379                      continue;
 380                  }
 381                  if(!$inquote)
 382                  {
 383                      // Save possible operator in front of phrase
 384                      $last_char = substr($phrase, -1);
 385                      if($last_char == '+' || $last_char == '-' || $last_char == '<' || $last_char == '>' || $last_char == '~')
 386                      {
 387                          $phrase_operator = $last_char;
 388                      }
 389                  }
 390                  foreach($split_words as $word)
 391                  {
 392                      $word = trim($word);
 393                      if($word == "or")
 394                      {
 395                          $boolean[$depth] = '';
 396                          // Remove "and" operator from previous element
 397                          $last = array_pop($words[$depth]);
 398                          if($last)
 399                          {
 400                              if(substr($last, 0, 1) == '+')
 401                              {
 402                                  $last = substr($last, 1);
 403                              }
 404                              $words[$depth][] = $last;
 405                          }
 406                      }
 407                      elseif($word == "and")
 408                      {
 409                          $boolean[$depth] = "+";
 410                      }
 411                      elseif($word == "not")
 412                      {
 413                          $boolean[$depth] = "-";
 414                      }
 415                      // Closing braces
 416                      elseif($word == ")")
 417                      {
 418                          // Ignore when no brace was opened
 419                          if($depth > 0)
 420                          {
 421                              $words[$depth-1][] = $boolean[$depth-1].'('.implode(' ', $words[$depth]).')';
 422                              --$depth;
 423                          }
 424                      }
 425                      // Valid operators for opening braces
 426                      elseif($word == '+(' || $word == '-(' || $word == '<(' || $word == '>(' || $word == '~(' || $word == '(')
 427                      {
 428                          if(strlen($word) == 2)
 429                          {
 430                              $boolean[$depth] = substr($word, 0, 1);
 431                          }
 432                          $words[++$depth] = array();
 433                          $boolean[$depth] = '+';
 434                      }
 435                      else
 436                      {
 437                          $operator = substr($word, 0, 1);
 438                          switch($operator)
 439                          {
 440                              // Allowed operators
 441                              case '-':
 442                              case '+':
 443                              case '>':
 444                              case '<':
 445                              case '~':
 446                                  $word = substr($word, 1);
 447                                  break;
 448                              default:
 449                                  $operator = $boolean[$depth];
 450                                  break;
 451                          }
 452                          // Removed operators that are only allowed at the beginning
 453                          $word = preg_replace("#(-|\+|<|>|~|@)#s", '', $word);
 454                          // Removing wildcards at the beginning http://bugs.mysql.com/bug.php?id=72605
 455                          $word = preg_replace("#^\*#s", '', $word);
 456                          $word = $operator.$word;
 457                          if(strlen($word) <= 1)
 458                          {
 459                              continue;
 460                          }
 461                          $words[$depth][] = $word;
 462                          $boolean[$depth] = '+';
 463                      }
 464                  }
 465              }
 466          }
 467          $inquote = !$inquote;
 468      }
 469  
 470      // Close mismatching braces
 471      while($depth > 0)
 472      {
 473          $words[$depth-1][] = $boolean[$depth-1].'('.implode(' ', $words[$depth]).')';
 474          --$depth;
 475      }
 476  
 477      $keywords = implode(' ', $words[0]);
 478      return $keywords;
 479  }
 480  
 481  /* Database engine specific search functions */
 482  
 483  /**
 484   * Perform a thread and post search under MySQL or MySQLi
 485   *
 486   * @param array $search Array of search data
 487   * @return array Array of search data with results mixed in
 488   */
 489  function privatemessage_perform_search_mysql($search)
 490  {
 491      global $mybb, $db, $lang;
 492  
 493      $keywords = clean_keywords($search['keywords']);
 494      if(!$keywords && !$search['sender'])
 495      {
 496          error($lang->error_nosearchterms);
 497      }
 498  
 499      if($mybb->settings['minsearchword'] < 1)
 500      {
 501          $mybb->settings['minsearchword'] = 3;
 502      }
 503  
 504      $subject_lookin = "";
 505      $message_lookin = "";
 506      $searchsql = "uid='{$mybb->user['uid']}'";
 507  
 508      if($keywords)
 509      {
 510          // Complex search
 511          $keywords = " {$keywords} ";
 512  
 513          switch($db->type)
 514          {
 515              case 'mysql':
 516              case 'mysqli':
 517                  $sfield = 'subject';
 518                  $mfield = 'message';
 519                  break;
 520              default:
 521                  $sfield = 'LOWER(subject)';
 522                  $mfield = 'LOWER(message)';
 523                  break;
 524          }
 525  
 526          if(preg_match("#\s(and|or)\s#", $keywords))
 527          {
 528              $string = "AND";
 529              if($search['subject'] == 1)
 530              {
 531                  $string = "OR";
 532                  $subject_lookin = " AND (";
 533              }
 534  
 535              if($search['message'] == 1)
 536              {
 537                  $message_lookin = " {$string} (";
 538              }
 539  
 540              // Expand the string by double quotes
 541              $keywords_exp = explode("\"", $keywords);
 542              $inquote = false;
 543              $boolean = '';
 544  
 545              foreach($keywords_exp as $phrase)
 546              {
 547                  // If we're not in a double quoted section
 548                  if(!$inquote)
 549                  {
 550                      // Expand out based on search operators (and, or)
 551                      $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
 552                      $count_matches = count($matches);
 553  
 554                      for($i=0; $i < $count_matches; ++$i)
 555                      {
 556                          $word = trim($matches[$i]);
 557                          if(empty($word))
 558                          {
 559                              continue;
 560                          }
 561                          // If this word is a search operator set the boolean
 562                          if($i % 2 && ($word == "and" || $word == "or"))
 563                          {
 564                              if($i <= 1)
 565                              {
 566                                  if($search['subject'] && $search['message'] && $subject_lookin == " AND (")
 567                                  {
 568                                      // We're looking for anything, check for a subject lookin
 569                                      continue;
 570                                  }
 571                                  elseif($search['subject'] && !$search['message'] && $subject_lookin == " AND (")
 572                                  {
 573                                      // Just in a subject?
 574                                      continue;
 575                                  }
 576                                  elseif(!$search['subject'] && $search['message'] && $message_lookin == " {$string} (")
 577                                  {
 578                                      // Just in a message?
 579                                      continue;
 580                                  }
 581                              }
 582  
 583                              $boolean = $word;
 584                          }
 585                          // Otherwise check the length of the word as it is a normal search term
 586                          else
 587                          {
 588                              $word = trim($word);
 589                              // Word is too short - show error message
 590                              if(my_strlen($word) < $mybb->settings['minsearchword'])
 591                              {
 592                                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 593                                  error($lang->error_minsearchlength);
 594                              }
 595  
 596                              // Add terms to search query
 597                              if($search['subject'] == 1)
 598                              {
 599                                  $subject_lookin .= " $boolean {$sfield} LIKE '%{$word}%'";
 600                              }
 601                              if($search['message'] == 1)
 602                              {
 603                                  $message_lookin .= " $boolean {$mfield} LIKE '%{$word}%'";
 604                              }
 605                              $boolean = 'AND';
 606                          }
 607                      }
 608                  }
 609                  // In the middle of a quote (phrase)
 610                  else
 611                  {
 612                      $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
 613                      if(my_strlen($phrase) < $mybb->settings['minsearchword'])
 614                      {
 615                          $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 616                          error($lang->error_minsearchlength);
 617                      }
 618                      // Add phrase to search query
 619                      $subject_lookin .= " $boolean {$sfield} LIKE '%{$phrase}%'";
 620                      if($search['message'] == 1)
 621                      {
 622                          $message_lookin .= " $boolean {$mfield} LIKE '%{$phrase}%'";
 623                      }
 624                      $boolean = 'AND';
 625                  }
 626  
 627                  // Check to see if we have any search terms and not a malformed SQL string
 628                  $error = false;
 629                  if($search['subject'] && $search['message'] && $subject_lookin == " AND (")
 630                  {
 631                      // We're looking for anything, check for a subject lookin
 632                      $error = true;
 633                  }
 634                  elseif($search['subject'] && !$search['message'] && $subject_lookin == " AND (")
 635                  {
 636                      // Just in a subject?
 637                      $error = true;
 638                  }
 639                  elseif(!$search['subject'] && $search['message'] && $message_lookin == " {$string} (")
 640                  {
 641                      // Just in a message?
 642                      $error = true;
 643                  }
 644  
 645                  if($error == true)
 646                  {
 647                      // There are no search keywords to look for
 648                      $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 649                      error($lang->error_minsearchlength);
 650                  }
 651  
 652                  $inquote = !$inquote;
 653              }
 654  
 655              if($search['subject'] == 1)
 656              {
 657                  $subject_lookin .= ")";
 658              }
 659  
 660              if($search['message'] == 1)
 661              {
 662                  $message_lookin .= ")";
 663              }
 664  
 665              $searchsql .= "{$subject_lookin} {$message_lookin}";
 666          }
 667          else
 668          {
 669              $keywords = str_replace("\"", '', trim($keywords));
 670              if(my_strlen($keywords) < $mybb->settings['minsearchword'])
 671              {
 672                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 673                  error($lang->error_minsearchlength);
 674              }
 675  
 676              // If we're looking in both, then find matches in either the subject or the message
 677              if($search['subject'] == 1 && $search['message'] == 1)
 678              {
 679                  $searchsql .= " AND ({$sfield} LIKE '%{$keywords}%' OR {$mfield} LIKE '%{$keywords}%')";
 680              }
 681              else
 682              {
 683                  if($search['subject'] == 1)
 684                  {
 685                      $searchsql .= " AND {$sfield} LIKE '%{$keywords}%'";
 686                  }
 687  
 688                  if($search['message'] == 1)
 689                  {
 690                      $searchsql .= " AND {$mfield} LIKE '%{$keywords}%'";
 691                  }
 692              }
 693          }
 694      }
 695  
 696      if($search['sender'])
 697      {
 698          $userids = array();
 699          $search['sender'] = my_strtolower($search['sender']);
 700  
 701          switch($db->type)
 702          {
 703              case 'mysql':
 704              case 'mysqli':
 705                  $field = 'username';
 706                  break;
 707              default:
 708                  $field = 'LOWER(username)';
 709                  break;
 710          }
 711          $query = $db->simple_select("users", "uid", "{$field} LIKE '%".$db->escape_string_like($search['sender'])."%'");
 712          while($user = $db->fetch_array($query))
 713          {
 714              $userids[] = $user['uid'];
 715          }
 716  
 717          if(count($userids) < 1)
 718          {
 719              error($lang->error_nosearchresults);
 720          }
 721          else
 722          {
 723              $userids = implode(',', $userids);
 724              $searchsql .= " AND fromid IN (".$userids.")";
 725          }
 726      }
 727  
 728      if(!is_array($search['folder']))
 729      {
 730          $search['folder'] = array($search['folder']);
 731      }
 732  
 733      if(!empty($search['folder']))
 734      {
 735          $folderids = array();
 736  
 737          $search['folder'] = array_map("intval", $search['folder']);
 738  
 739          $folderids = implode(',', $search['folder']);
 740  
 741          if($folderids)
 742          {
 743              $searchsql .= " AND folder IN (".$folderids.")";
 744          }
 745      }
 746  
 747      if($search['status'])
 748      {
 749          $searchsql .= " AND (";
 750          if($search['status']['new'])
 751          {
 752              $statussql[] = " status='0' ";
 753          }
 754          if($search['status']['replied'])
 755          {
 756              $statussql[] = " status='3' ";
 757          }
 758          if($search['status']['forwarded'])
 759          {
 760              $statussql[] = " status='4' ";
 761          }
 762          if($search['status']['read'])
 763          {
 764              $statussql[] = " (status != '0' AND readtime > '0') ";
 765          }
 766          // Sent Folder
 767          if(in_array(2, $search['folder']))
 768          {
 769              $statussql[] = " status='1' ";
 770          }
 771          $statussql = implode("OR", $statussql);
 772          $searchsql .= $statussql.")";
 773      }
 774  
 775      $limitsql = "";
 776      if((int)$mybb->settings['searchhardlimit'] > 0)
 777      {
 778          $limitsql = " LIMIT ".(int)$mybb->settings['searchhardlimit'];
 779      }
 780      $searchsql .= $limitsql;
 781  
 782      // Run the search
 783      $pms = array();
 784      $query = $db->simple_select("privatemessages", "pmid", $searchsql);
 785      while($pm = $db->fetch_array($query))
 786      {
 787          $pms[$pm['pmid']] = $pm['pmid'];
 788      }
 789  
 790      if(count($pms) < 1)
 791      {
 792          error($lang->error_nosearchresults);
 793      }
 794      $pms = implode(',', $pms);
 795  
 796      return array(
 797          "querycache" => $pms
 798      );
 799  }
 800  
 801  /**
 802   * Perform a help document search under MySQL or MySQLi
 803   *
 804   * @param array $search Array of search data
 805   * @return array Array of search data with results mixed in
 806   */
 807  function helpdocument_perform_search_mysql($search)
 808  {
 809      global $mybb, $db, $lang;
 810  
 811      $keywords = clean_keywords($search['keywords']);
 812      if(!$keywords && !$search['sender'])
 813      {
 814          error($lang->error_nosearchterms);
 815      }
 816  
 817      if($mybb->settings['minsearchword'] < 1)
 818      {
 819          $mybb->settings['minsearchword'] = 3;
 820      }
 821  
 822      $name_lookin = "";
 823      $document_lookin = "";
 824      $searchsql = "enabled='1'";
 825  
 826      if($keywords)
 827      {
 828          switch($db->type)
 829          {
 830              case 'mysql':
 831              case 'mysqli':
 832                  $nfield = 'name';
 833                  $dfield = 'document';
 834                  break;
 835              default:
 836                  $nfield = 'LOWER(name)';
 837                  $dfield = 'LOWER(document)';
 838                  break;
 839          }
 840  
 841          // Complex search
 842          $keywords = " {$keywords} ";
 843          if(preg_match("#\s(and|or)\s#", $keywords))
 844          {
 845              $string = "AND";
 846              if($search['name'] == 1)
 847              {
 848                  $string = "OR";
 849                  $name_lookin = " AND (";
 850              }
 851  
 852              if($search['document'] == 1)
 853              {
 854                  $document_lookin = " {$string} (";
 855              }
 856  
 857              // Expand the string by double quotes
 858              $keywords_exp = explode("\"", $keywords);
 859              $inquote = false;
 860  
 861              foreach($keywords_exp as $phrase)
 862              {
 863                  // If we're not in a double quoted section
 864                  if(!$inquote)
 865                  {
 866                      // Expand out based on search operators (and, or)
 867                      $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
 868                      $count_matches = count($matches);
 869  
 870                      for($i=0; $i < $count_matches; ++$i)
 871                      {
 872                          $word = trim($matches[$i]);
 873                          if(empty($word))
 874                          {
 875                              continue;
 876                          }
 877                          // If this word is a search operator set the boolean
 878                          if($i % 2 && ($word == "and" || $word == "or"))
 879                          {
 880                              if($i <= 1)
 881                              {
 882                                  if($search['name'] && $search['document'] && $name_lookin == " AND (")
 883                                  {
 884                                      // We're looking for anything, check for a name lookin
 885                                      continue;
 886                                  }
 887                                  elseif($search['name'] && !$search['document'] && $name_lookin == " AND (")
 888                                  {
 889                                      // Just in a name?
 890                                      continue;
 891                                  }
 892                                  elseif(!$search['name'] && $search['document'] && $document_lookin == " {$string} (")
 893                                  {
 894                                      // Just in a document?
 895                                      continue;
 896                                  }
 897                              }
 898  
 899                              $boolean = $word;
 900                          }
 901                          // Otherwise check the length of the word as it is a normal search term
 902                          else
 903                          {
 904                              $word = trim($word);
 905                              // Word is too short - show error message
 906                              if(my_strlen($word) < $mybb->settings['minsearchword'])
 907                              {
 908                                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 909                                  error($lang->error_minsearchlength);
 910                              }
 911                              // Add terms to search query
 912                              if($search['name'] == 1)
 913                              {
 914                                  $name_lookin .= " $boolean {$nfield} LIKE '%{$word}%'";
 915                              }
 916                              if($search['document'] == 1)
 917                              {
 918                                  $document_lookin .= " $boolean {$dfield} LIKE '%{$word}%'";
 919                              }
 920                          }
 921                      }
 922                  }
 923                  // In the middle of a quote (phrase)
 924                  else
 925                  {
 926                      $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
 927                      if(my_strlen($phrase) < $mybb->settings['minsearchword'])
 928                      {
 929                          $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 930                          error($lang->error_minsearchlength);
 931                      }
 932                      // Add phrase to search query
 933                      $name_lookin .= " $boolean {$nfield} LIKE '%{$phrase}%'";
 934                      if($search['document'] == 1)
 935                      {
 936                          $document_lookin .= " $boolean {$dfield} LIKE '%{$phrase}%'";
 937                      }
 938                  }
 939  
 940                  // Check to see if we have any search terms and not a malformed SQL string
 941                  $error = false;
 942                  if($search['name'] && $search['document'] && $name_lookin == " AND (")
 943                  {
 944                      // We're looking for anything, check for a name lookin
 945                      $error = true;
 946                  }
 947                  elseif($search['name'] && !$search['document'] && $name_lookin == " AND (")
 948                  {
 949                      // Just in a name?
 950                      $error = true;
 951                  }
 952                  elseif(!$search['name'] && $search['document'] && $document_lookin == " {$string} (")
 953                  {
 954                      // Just in a document?
 955                      $error = true;
 956                  }
 957  
 958                  if($error == true)
 959                  {
 960                      // There are no search keywords to look for
 961                      $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 962                      error($lang->error_minsearchlength);
 963                  }
 964  
 965                  $inquote = !$inquote;
 966              }
 967  
 968              if($search['name'] == 1)
 969              {
 970                  $name_lookin .= ")";
 971              }
 972  
 973              if($search['document'] == 1)
 974              {
 975                  $document_lookin .= ")";
 976              }
 977  
 978              $searchsql .= "{$name_lookin} {$document_lookin}";
 979          }
 980          else
 981          {
 982              $keywords = str_replace("\"", '', trim($keywords));
 983              if(my_strlen($keywords) < $mybb->settings['minsearchword'])
 984              {
 985                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 986                  error($lang->error_minsearchlength);
 987              }
 988  
 989              // If we're looking in both, then find matches in either the name or the document
 990              if($search['name'] == 1 && $search['document'] == 1)
 991              {
 992                  $searchsql .= " AND ({$nfield} LIKE '%{$keywords}%' OR {$dfield} LIKE '%{$keywords}%')";
 993              }
 994              else
 995              {
 996                  if($search['name'] == 1)
 997                  {
 998                      $searchsql .= " AND {$nfield} LIKE '%{$keywords}%'";
 999                  }
1000  
1001                  if($search['document'] == 1)
1002                  {
1003                      $searchsql .= " AND {$dfield} LIKE '%{$keywords}%'";
1004                  }
1005              }
1006          }
1007      }
1008  
1009      // Run the search
1010      $helpdocs = array();
1011      $query = $db->simple_select("helpdocs", "hid", $searchsql);
1012      while($help = $db->fetch_array($query))
1013      {
1014          $helpdocs[$help['hid']] = $help['hid'];
1015      }
1016  
1017      if(count($helpdocs) < 1)
1018      {
1019          error($lang->error_nosearchresults);
1020      }
1021      $helpdocs = implode(',', $helpdocs);
1022  
1023      return array(
1024          "querycache" => $helpdocs
1025      );
1026  }
1027  
1028  /**
1029   * Perform a thread and post search under MySQL or MySQLi
1030   *
1031   * @param array $search Array of search data
1032   * @return array Array of search data with results mixed in
1033   */
1034  function perform_search_mysql($search)
1035  {
1036      global $mybb, $db, $lang, $cache;
1037  
1038      $keywords = clean_keywords($search['keywords']);
1039  
1040      if($mybb->settings['minsearchword'] < 1)
1041      {
1042          $mybb->settings['minsearchword'] = 3;
1043      }
1044  
1045      $subject_lookin = $message_lookin = '';
1046      if($keywords)
1047      {
1048          switch($db->type)
1049          {
1050              case 'mysql':
1051              case 'mysqli':
1052                  $tfield = 't.subject';
1053                  $pfield = 'p.message';
1054                  break;
1055              default:
1056                  $tfield = 'LOWER(t.subject)';
1057                  $pfield = 'LOWER(p.message)';
1058                  break;
1059          }
1060  
1061          // Complex search
1062          $keywords = " {$keywords} ";
1063          if(preg_match("#\s(and|or)\s#", $keywords))
1064          {
1065              $subject_lookin = " AND (";
1066              $message_lookin = " AND (";
1067  
1068              // Expand the string by double quotes
1069              $keywords_exp = explode("\"", $keywords);
1070              $inquote = false;
1071              $boolean = '';
1072  
1073              foreach($keywords_exp as $phrase)
1074              {
1075                  // If we're not in a double quoted section
1076                  if(!$inquote)
1077                  {
1078                      // Expand out based on search operators (and, or)
1079                      $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
1080                      $count_matches = count($matches);
1081  
1082                      for($i=0; $i < $count_matches; ++$i)
1083                      {
1084                          $word = trim($matches[$i]);
1085                          if(empty($word))
1086                          {
1087                              continue;
1088                          }
1089                          // If this word is a search operator set the boolean
1090                          if($i % 2 && ($word == "and" || $word == "or"))
1091                          {
1092                              if($i <= 1 && $subject_lookin == " AND (")
1093                              {
1094                                  continue;
1095                              }
1096  
1097                              $boolean = $word;
1098                          }
1099                          // Otherwise check the length of the word as it is a normal search term
1100                          else
1101                          {
1102                              $word = trim($word);
1103                              // Word is too short - show error message
1104                              if(my_strlen($word) < $mybb->settings['minsearchword'])
1105                              {
1106                                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1107                                  error($lang->error_minsearchlength);
1108                              }
1109                              // Add terms to search query
1110                              $subject_lookin .= " $boolean {$tfield} LIKE '%{$word}%'";
1111                              if($search['postthread'] == 1)
1112                              {
1113                                  $message_lookin .= " $boolean {$pfield} LIKE '%{$word}%'";
1114                              }
1115                              $boolean = 'AND';
1116                          }
1117                      }
1118                  }
1119                  // In the middle of a quote (phrase)
1120                  else
1121                  {
1122                      $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
1123                      if(my_strlen($phrase) < $mybb->settings['minsearchword'])
1124                      {
1125                          $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1126                          error($lang->error_minsearchlength);
1127                      }
1128                      // Add phrase to search query
1129                      $subject_lookin .= " $boolean {$tfield} LIKE '%{$phrase}%'";
1130                      if($search['postthread'] == 1)
1131                      {
1132                          $message_lookin .= " $boolean {$pfield} LIKE '%{$phrase}%'";
1133                      }
1134                      $boolean = 'AND';
1135                  }
1136  
1137                  if($subject_lookin == " AND (")
1138                  {
1139                      // There are no search keywords to look for
1140                      $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1141                      error($lang->error_minsearchlength);
1142                  }
1143  
1144                  $inquote = !$inquote;
1145              }
1146              $subject_lookin .= ")";
1147              $message_lookin .= ")";
1148          }
1149          else
1150          {
1151              $keywords = str_replace("\"", '', trim($keywords));
1152              if(my_strlen($keywords) < $mybb->settings['minsearchword'])
1153              {
1154                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1155                  error($lang->error_minsearchlength);
1156              }
1157              $subject_lookin = " AND {$tfield} LIKE '%{$keywords}%'";
1158              if($search['postthread'] == 1)
1159              {
1160                  $message_lookin = " AND {$pfield} LIKE '%{$keywords}%'";
1161              }
1162          }
1163      }
1164      $post_usersql = '';
1165      $thread_usersql = '';
1166      if($search['author'])
1167      {
1168          $userids = array();
1169          $search['author'] = my_strtolower($search['author']);
1170          if($search['matchusername'])
1171          {
1172              $user = get_user_by_username($search['author']);
1173              if($user)
1174              {
1175                  $userids[] = $user['uid'];
1176              }
1177          }
1178          else
1179          {
1180              switch($db->type)
1181              {
1182                  case 'mysql':
1183                  case 'mysqli':
1184                      $field = 'username';
1185                      break;
1186                  default:
1187                      $field = 'LOWER(username)';
1188                      break;
1189              }
1190              $query = $db->simple_select("users", "uid", "{$field} LIKE '%".$db->escape_string_like($search['author'])."%'");
1191              while($user = $db->fetch_array($query))
1192              {
1193                  $userids[] = $user['uid'];
1194              }
1195          }
1196  
1197          if(count($userids) < 1)
1198          {
1199              error($lang->error_nosearchresults);
1200          }
1201          else
1202          {
1203              $userids = implode(',', $userids);
1204              $post_usersql = " AND p.uid IN (".$userids.")";
1205              $thread_usersql = " AND t.uid IN (".$userids.")";
1206          }
1207      }
1208      $datecut = $post_datecut = $thread_datecut = '';
1209      if($search['postdate'])
1210      {
1211          if($search['pddir'] == 0)
1212          {
1213              $datecut = "<=";
1214          }
1215          else
1216          {
1217              $datecut = ">=";
1218          }
1219          $now = TIME_NOW;
1220          $datelimit = $now-(86400 * $search['postdate']);
1221          $datecut .= "'$datelimit'";
1222          $post_datecut = " AND p.dateline $datecut";
1223          $thread_datecut = " AND t.dateline $datecut";
1224      }
1225  
1226      $thread_replycut = '';
1227      if($search['numreplies'] != '' && $search['findthreadst'])
1228      {
1229          if((int)$search['findthreadst'] == 1)
1230          {
1231              $thread_replycut = " AND t.replies >= '".(int)$search['numreplies']."'";
1232          }
1233          else
1234          {
1235              $thread_replycut = " AND t.replies <= '".(int)$search['numreplies']."'";
1236          }
1237      }
1238  
1239      $thread_prefixcut = '';
1240      $prefixlist = array();
1241      if($search['threadprefix'] && $search['threadprefix'][0] != 'any')
1242      {
1243          foreach($search['threadprefix'] as $threadprefix)
1244          {
1245              $threadprefix = (int)$threadprefix;
1246              $prefixlist[] = $threadprefix;
1247          }
1248      }
1249      if(count($prefixlist) == 1)
1250      {
1251          $thread_prefixcut .= " AND t.prefix='$threadprefix' ";
1252      }
1253      else
1254      {
1255          if(count($prefixlist) > 1)
1256          {
1257              $thread_prefixcut = " AND t.prefix IN (".implode(',', $prefixlist).")";
1258          }
1259      }
1260  
1261      $forumin = '';
1262      $fidlist = array();
1263      if(!empty($search['forums']) && (!is_array($search['forums']) || $search['forums'][0] != "all"))
1264      {
1265          if(!is_array($search['forums']))
1266          {
1267              $search['forums'] = array((int)$search['forums']);
1268          }
1269          foreach($search['forums'] as $forum)
1270          {
1271              $forum = (int)$forum;
1272              if($forum > 0)
1273              {
1274                  $fidlist[] = $forum;
1275                  $child_list = get_child_list($forum);
1276                  if(is_array($child_list))
1277                  {
1278                      $fidlist = array_merge($fidlist, $child_list);
1279                  }
1280              }
1281          }
1282          $fidlist = array_unique($fidlist);
1283          if(count($fidlist) >= 1)
1284          {
1285              $forumin = " AND t.fid IN (".implode(',', $fidlist).")";
1286          }
1287      }
1288  
1289      $permsql = "";
1290      $onlyusfids = array();
1291  
1292      // Check group permissions if we can't view threads not started by us
1293      if($group_permissions = forum_permissions())
1294      {
1295          foreach($group_permissions as $fid => $forum_permissions)
1296          {
1297              if(isset($forum_permissions['canonlyviewownthreads']) && $forum_permissions['canonlyviewownthreads'] == 1)
1298              {
1299                  $onlyusfids[] = $fid;
1300              }
1301          }
1302      }
1303      if(!empty($onlyusfids))
1304      {
1305          $permsql .= "AND ((t.fid IN(".implode(',', $onlyusfids).") AND t.uid='{$mybb->user['uid']}') OR t.fid NOT IN(".implode(',', $onlyusfids)."))";
1306      }
1307  
1308      $unsearchforums = get_unsearchable_forums();
1309      if($unsearchforums)
1310      {
1311          $permsql .= " AND t.fid NOT IN ($unsearchforums)";
1312      }
1313      $inactiveforums = get_inactive_forums();
1314      if($inactiveforums)
1315      {
1316          $permsql .= " AND t.fid NOT IN ($inactiveforums)";
1317      }
1318  
1319      $visiblesql = $post_visiblesql = $plain_post_visiblesql = $unapproved_where_t = $unapproved_where_p = "";
1320      if(isset($search['visible']))
1321      {
1322          if($search['visible'] == 1)
1323          {
1324              $visiblesql = " AND t.visible = '1'";
1325  
1326              if($search['postthread'] == 1)
1327              {
1328                  $post_visiblesql = " AND p.visible = '1'";
1329                  $plain_post_visiblesql = " AND visible = '1'";
1330              }
1331          }
1332          elseif($search['visible'] == -1)
1333          {
1334              $visiblesql = " AND t.visible = '-1'";
1335  
1336              if($search['postthread'] == 1)
1337              {
1338                  $post_visiblesql = " AND p.visible = '-1'";
1339                  $plain_post_visiblesql = " AND visible = '-1'";
1340              }
1341          }
1342          else
1343          {
1344              $visiblesql = " AND t.visible == '0'";
1345  
1346              if($search['postthread'] == 1)
1347              {
1348                  $post_visiblesql = " AND p.visible == '0'";
1349                  $plain_post_visiblesql = " AND visible == '0'";
1350              }
1351          }
1352      }
1353  
1354      // Moderators can view unapproved threads and deleted threads from forums they moderate
1355      $unapproved_where_t = get_visible_where('t');
1356      $unapproved_where_p = get_visible_where('p');
1357  
1358      // Searching a specific thread?
1359      $tidsql = '';
1360      if(!empty($search['tid']))
1361      {
1362          $tidsql = " AND t.tid='".(int)$search['tid']."'";
1363      }
1364  
1365      $limitsql = '';
1366      if((int)$mybb->settings['searchhardlimit'] > 0)
1367      {
1368          $limitsql = "LIMIT ".(int)$mybb->settings['searchhardlimit'];
1369      }
1370  
1371      // Searching both posts and thread titles
1372      $threads = array();
1373      $posts = array();
1374      $firstposts = array();
1375      if($search['postthread'] == 1)
1376      {
1377          // No need to search subjects when looking for results within a specific thread
1378          if(empty($search['tid']))
1379          {
1380              $query = $db->query("
1381                  SELECT t.tid, t.firstpost
1382                  FROM ".TABLE_PREFIX."threads t
1383                  WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} AND ({$unapproved_where_t}) AND t.closed NOT LIKE 'moved|%' {$subject_lookin}
1384                  {$limitsql}
1385              ");
1386              while($thread = $db->fetch_array($query))
1387              {
1388                  $threads[$thread['tid']] = $thread['tid'];
1389                  if($thread['firstpost'])
1390                  {
1391                      $posts[$thread['tid']] = $thread['firstpost'];
1392                  }
1393              }
1394          }
1395  
1396          $query = $db->query("
1397              SELECT p.pid, p.tid
1398              FROM ".TABLE_PREFIX."posts p
1399              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
1400              WHERE 1=1 {$post_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$post_usersql} {$permsql} {$tidsql} {$visiblesql} {$post_visiblesql} AND ({$unapproved_where_t}) AND ({$unapproved_where_p}) AND t.closed NOT LIKE 'moved|%' {$message_lookin}
1401              {$limitsql}
1402          ");
1403          while($post = $db->fetch_array($query))
1404          {
1405              $posts[$post['pid']] = $post['pid'];
1406              $threads[$post['tid']] = $post['tid'];
1407          }
1408  
1409          if(count($posts) < 1 && count($threads) < 1)
1410          {
1411              error($lang->error_nosearchresults);
1412          }
1413          $threads = implode(',', $threads);
1414          $posts = implode(',', $posts);
1415  
1416      }
1417      // Searching only thread titles
1418      else
1419      {
1420          $query = $db->query("
1421              SELECT t.tid, t.firstpost
1422              FROM ".TABLE_PREFIX."threads t
1423              WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} {$subject_lookin}
1424              {$limitsql}
1425          ");
1426          while($thread = $db->fetch_array($query))
1427          {
1428              $threads[$thread['tid']] = $thread['tid'];
1429              if($thread['firstpost'])
1430              {
1431                  $firstposts[$thread['tid']] = $thread['firstpost'];
1432              }
1433          }
1434          if(count($threads) < 1)
1435          {
1436              error($lang->error_nosearchresults);
1437          }
1438  
1439          $threads = implode(',', $threads);
1440          $firstposts = implode(',', $firstposts);
1441          if($firstposts)
1442          {
1443              $query = $db->simple_select("posts", "pid", "pid IN ($firstposts) {$plain_post_visiblesql} {$limitsql}");
1444              while($post = $db->fetch_array($query))
1445              {
1446                  $posts[$post['pid']] = $post['pid'];
1447              }
1448              $posts = implode(',', $posts);
1449          }
1450      }
1451      return array(
1452          "threads" => $threads,
1453          "posts" => $posts,
1454          "querycache" => ''
1455      );
1456  }
1457  
1458  /**
1459   * Perform a thread and post search under MySQL or MySQLi using boolean fulltext capabilities
1460   *
1461   * @param array $search Array of search data
1462   * @return array Array of search data with results mixed in
1463   */
1464  function perform_search_mysql_ft($search)
1465  {
1466      global $mybb, $db, $lang;
1467  
1468      $keywords = clean_keywords_ft($search['keywords']);
1469  
1470      if($mybb->settings['minsearchword'] < 1)
1471      {
1472          $mybb->settings['minsearchword'] = 4;
1473      }
1474  
1475      $message_lookin = $subject_lookin = '';
1476      if($keywords)
1477      {
1478          $keywords_exp = explode("\"", $keywords);
1479          $inquote = false;
1480          foreach($keywords_exp as $phrase)
1481          {
1482              if(!$inquote)
1483              {
1484                  $split_words = preg_split("#\s{1,}#", $phrase, -1);
1485                  foreach($split_words as $word)
1486                  {
1487                      $word = str_replace(array("+", "-", "*"), '', $word);
1488                      if(!$word)
1489                      {
1490                          continue;
1491                      }
1492                      if(my_strlen($word) < $mybb->settings['minsearchword'])
1493                      {
1494                          $all_too_short = true;
1495                      }
1496                      else
1497                      {
1498                          $all_too_short = false;
1499                          break;
1500                      }
1501                  }
1502              }
1503              else
1504              {
1505                  $phrase = str_replace(array("+", "-", "*"), '', $phrase);
1506                  if(my_strlen($phrase) < $mybb->settings['minsearchword'])
1507                  {
1508                      $all_too_short = true;
1509                  }
1510                  else
1511                  {
1512                      $all_too_short = false;
1513                      break;
1514                  }
1515              }
1516              $inquote = !$inquote;
1517          }
1518          // Show the minimum search term error only if all search terms are too short
1519          if($all_too_short == true)
1520          {
1521              $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1522              error($lang->error_minsearchlength);
1523          }
1524          $message_lookin = "AND MATCH(message) AGAINST('".$db->escape_string($keywords)."' IN BOOLEAN MODE)";
1525          $subject_lookin = "AND MATCH(subject) AGAINST('".$db->escape_string($keywords)."' IN BOOLEAN MODE)";
1526      }
1527      $post_usersql = '';
1528      $thread_usersql = '';
1529      if($search['author'])
1530      {
1531          $userids = array();
1532          $search['author'] = my_strtolower($search['author']);
1533          if($search['matchusername'])
1534          {
1535              $user = get_user_by_username($search['author']);
1536              if($user)
1537              {
1538                  $userids[] = $user['uid'];
1539              }
1540          }
1541          else
1542          {
1543              $query = $db->simple_select("users", "uid", "username LIKE '%".$db->escape_string_like($search['author'])."%'");
1544  
1545              while($user = $db->fetch_array($query))
1546              {
1547                  $userids[] = $user['uid'];
1548              }
1549          }
1550  
1551          if(count($userids) < 1)
1552          {
1553              error($lang->error_nosearchresults);
1554          }
1555          else
1556          {
1557              $userids = implode(',', $userids);
1558              $post_usersql = " AND p.uid IN (".$userids.")";
1559              $thread_usersql = " AND t.uid IN (".$userids.")";
1560          }
1561      }
1562      $datecut = $thread_datecut = $post_datecut = '';
1563      if($search['postdate'])
1564      {
1565          if($search['pddir'] == 0)
1566          {
1567              $datecut = "<=";
1568          }
1569          else
1570          {
1571              $datecut = ">=";
1572          }
1573          $now = TIME_NOW;
1574          $datelimit = $now-(86400 * $search['postdate']);
1575          $datecut .= "'$datelimit'";
1576          $post_datecut = " AND p.dateline $datecut";
1577          $thread_datecut = " AND t.dateline $datecut";
1578      }
1579  
1580      $thread_replycut = '';
1581      if($search['numreplies'] != '' && $search['findthreadst'])
1582      {
1583          if((int)$search['findthreadst'] == 1)
1584          {
1585              $thread_replycut = " AND t.replies >= '".(int)$search['numreplies']."'";
1586          }
1587          else
1588          {
1589              $thread_replycut = " AND t.replies <= '".(int)$search['numreplies']."'";
1590          }
1591      }
1592  
1593      $thread_prefixcut = '';
1594      $prefixlist = array();
1595      if($search['threadprefix'] && $search['threadprefix'][0] != 'any')
1596      {
1597          foreach($search['threadprefix'] as $threadprefix)
1598          {
1599              $threadprefix = (int)$threadprefix;
1600              $prefixlist[] = $threadprefix;
1601          }
1602      }
1603      if(count($prefixlist) == 1)
1604      {
1605          $thread_prefixcut .= " AND t.prefix='$threadprefix' ";
1606      }
1607      else
1608      {
1609          if(count($prefixlist) > 1)
1610          {
1611              $thread_prefixcut = " AND t.prefix IN (".implode(',', $prefixlist).")";
1612          }
1613      }
1614  
1615      $forumin = '';
1616      $fidlist = array();
1617      $searchin = array();
1618      if(!empty($search['forums']) && (!is_array($search['forums']) || $search['forums'][0] != "all"))
1619      {
1620          if(!is_array($search['forums']))
1621          {
1622              $search['forums'] = array((int)$search['forums']);
1623          }
1624          foreach($search['forums'] as $forum)
1625          {
1626              $forum = (int)$forum;
1627              if($forum > 0)
1628              {
1629                  $fidlist[] = $forum;
1630                  $child_list = get_child_list($forum);
1631                  if(is_array($child_list))
1632                  {
1633                      $fidlist = array_merge($fidlist, $child_list);
1634                  }
1635              }
1636          }
1637          $fidlist = array_unique($fidlist);
1638          if(count($fidlist) >= 1)
1639          {
1640              $forumin = " AND t.fid IN (".implode(',', $fidlist).")";
1641          }
1642      }
1643      $permsql = "";
1644      $onlyusfids = array();
1645  
1646      // Check group permissions if we can't view threads not started by us
1647      $group_permissions = forum_permissions();
1648      foreach($group_permissions as $fid => $forum_permissions)
1649      {
1650          if(isset($forum_permissions['canonlyviewownthreads']) && $forum_permissions['canonlyviewownthreads'] == 1)
1651          {
1652              $onlyusfids[] = $fid;
1653          }
1654      }
1655      if(!empty($onlyusfids))
1656      {
1657          $permsql .= "AND ((t.fid IN(".implode(',', $onlyusfids).") AND t.uid='{$mybb->user['uid']}') OR t.fid NOT IN(".implode(',', $onlyusfids)."))";
1658      }
1659  
1660      $unsearchforums = get_unsearchable_forums();
1661      if($unsearchforums)
1662      {
1663          $permsql .= " AND t.fid NOT IN ($unsearchforums)";
1664      }
1665      $inactiveforums = get_inactive_forums();
1666      if($inactiveforums)
1667      {
1668          $permsql .= " AND t.fid NOT IN ($inactiveforums)";
1669      }
1670  
1671      $visiblesql = $post_visiblesql = $plain_post_visiblesql = $unapproved_where_t = $unapproved_where_p = "";
1672      if(isset($search['visible']))
1673      {
1674          if($search['visible'] == 1)
1675          {
1676              $visiblesql = " AND t.visible = '1'";
1677  
1678              if($search['postthread'] == 1)
1679              {
1680                  $post_visiblesql = " AND p.visible = '1'";
1681                  $plain_post_visiblesql = " AND visible = '1'";
1682              }
1683          }
1684          elseif($search['visible'] == -1)
1685          {
1686              $visiblesql = " AND t.visible = '-1'";
1687  
1688              if($search['postthread'] == 1)
1689              {
1690                  $post_visiblesql = " AND p.visible = '-1'";
1691                  $plain_post_visiblesql = " AND visible = '-1'";
1692              }
1693          }
1694          else
1695          {
1696              $visiblesql = " AND t.visible != '1'";
1697  
1698              if($search['postthread'] == 1)
1699              {
1700                  $post_visiblesql = " AND p.visible != '1'";
1701                  $plain_post_visiblesql = " AND visible != '1'";
1702              }
1703          }
1704      }
1705  
1706      // Moderators can view unapproved threads and deleted threads from forums they moderate
1707      $unapproved_where_t = get_visible_where('t');
1708      $unapproved_where_p = get_visible_where('p');
1709  
1710      // Searching a specific thread?
1711      $tidsql = '';
1712      if(!empty($search['tid']))
1713      {
1714          $tidsql = " AND t.tid='".(int)$search['tid']."'";
1715      }
1716  
1717      $limitsql = '';
1718      if((int)$mybb->settings['searchhardlimit'] > 0)
1719      {
1720          $limitsql = "LIMIT ".(int)$mybb->settings['searchhardlimit'];
1721      }
1722  
1723      // Searching both posts and thread titles
1724      $threads = array();
1725      $posts = array();
1726      $firstposts = array();
1727      if($search['postthread'] == 1)
1728      {
1729          // No need to search subjects when looking for results within a specific thread
1730          if(empty($search['tid']))
1731          {
1732              $query = $db->query("
1733                  SELECT t.tid, t.firstpost
1734                  FROM ".TABLE_PREFIX."threads t
1735                  WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} AND ({$unapproved_where_t}) AND t.closed NOT LIKE 'moved|%' {$subject_lookin}
1736                  {$limitsql}
1737              ");
1738              while($thread = $db->fetch_array($query))
1739              {
1740                  $threads[$thread['tid']] = $thread['tid'];
1741                  if($thread['firstpost'])
1742                  {
1743                      $posts[$thread['tid']] = $thread['firstpost'];
1744                  }
1745              }
1746          }
1747  
1748          $query = $db->query("
1749              SELECT p.pid, p.tid
1750              FROM ".TABLE_PREFIX."posts p
1751              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
1752              WHERE 1=1 {$post_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$post_usersql} {$permsql} {$tidsql} {$post_visiblesql} {$visiblesql} AND ({$unapproved_where_t}) AND {$unapproved_where_p} AND t.closed NOT LIKE 'moved|%' {$message_lookin}
1753              {$limitsql}
1754          ");
1755          while($post = $db->fetch_array($query))
1756          {
1757              $posts[$post['pid']] = $post['pid'];
1758              $threads[$post['tid']] = $post['tid'];
1759          }
1760          if(count($posts) < 1 && count($threads) < 1)
1761          {
1762              error($lang->error_nosearchresults);
1763          }
1764          $threads = implode(',', $threads);
1765          $posts = implode(',', $posts);
1766  
1767      }
1768      // Searching only thread titles
1769      else
1770      {
1771          $query = $db->query("
1772              SELECT t.tid, t.firstpost
1773              FROM ".TABLE_PREFIX."threads t
1774              WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} {$subject_lookin}
1775              {$limitsql}
1776          ");
1777          while($thread = $db->fetch_array($query))
1778          {
1779              $threads[$thread['tid']] = $thread['tid'];
1780              if($thread['firstpost'])
1781              {
1782                  $firstposts[$thread['tid']] = $thread['firstpost'];
1783              }
1784          }
1785          if(count($threads) < 1)
1786          {
1787              error($lang->error_nosearchresults);
1788          }
1789  
1790          $threads = implode(',', $threads);
1791          $firstposts = implode(',', $firstposts);
1792          if($firstposts)
1793          {
1794              $query = $db->simple_select("posts", "pid", "pid IN ($firstposts) {$plain_post_visiblesql} {$limitsql}");
1795              while($post = $db->fetch_array($query))
1796              {
1797                  $posts[$post['pid']] = $post['pid'];
1798              }
1799              $posts = implode(',', $posts);
1800          }
1801      }
1802      return array(
1803          "threads" => $threads,
1804          "posts" => $posts,
1805          "querycache" => ''
1806      );
1807  }


2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup Cross-referenced by PHPXref