[ Index ]

PHP Cross Reference of MyBB 1.8.38

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      $inquote = false;
 359      foreach($keywords as $phrase)
 360      {
 361          $phrase = trim($phrase);
 362          if($phrase != '')
 363          {
 364              if($inquote)
 365              {
 366                  if($phrase_operator)
 367                  {
 368                      $boolean[$depth] = $phrase_operator;
 369                  }
 370                  // Phrases do not need further processing
 371                  $words[$depth][] = "{$boolean[$depth]}\"{$phrase}\"";
 372                  $boolean[$depth] = $phrase_operator = '+';
 373              }
 374              else
 375              {
 376                  // Split words
 377                  $split_words = preg_split("#\s{1,}#", $phrase, -1);
 378                  if(!is_array($split_words))
 379                  {
 380                      continue;
 381                  }
 382                  if(!$inquote)
 383                  {
 384                      // Save possible operator in front of phrase
 385                      $last_char = substr($phrase, -1);
 386                      if($last_char == '+' || $last_char == '-' || $last_char == '<' || $last_char == '>' || $last_char == '~')
 387                      {
 388                          $phrase_operator = $last_char;
 389                      }
 390                  }
 391                  foreach($split_words as $word)
 392                  {
 393                      $word = trim($word);
 394                      if($word == "or")
 395                      {
 396                          $boolean[$depth] = '';
 397                          // Remove "and" operator from previous element
 398                          $last = array_pop($words[$depth]);
 399                          if($last)
 400                          {
 401                              if(substr($last, 0, 1) == '+')
 402                              {
 403                                  $last = substr($last, 1);
 404                              }
 405                              $words[$depth][] = $last;
 406                          }
 407                      }
 408                      elseif($word == "and")
 409                      {
 410                          $boolean[$depth] = "+";
 411                      }
 412                      elseif($word == "not")
 413                      {
 414                          $boolean[$depth] = "-";
 415                      }
 416                      // Closing braces
 417                      elseif($word == ")")
 418                      {
 419                          // Ignore when no brace was opened
 420                          if($depth > 0)
 421                          {
 422                              $words[$depth-1][] = $boolean[$depth-1].'('.implode(' ', $words[$depth]).')';
 423                              --$depth;
 424                          }
 425                      }
 426                      // Valid operators for opening braces
 427                      elseif($word == '+(' || $word == '-(' || $word == '<(' || $word == '>(' || $word == '~(' || $word == '(')
 428                      {
 429                          if(strlen($word) == 2)
 430                          {
 431                              $boolean[$depth] = substr($word, 0, 1);
 432                          }
 433                          $words[++$depth] = array();
 434                          $boolean[$depth] = '+';
 435                      }
 436                      else
 437                      {
 438                          $operator = substr($word, 0, 1);
 439                          switch($operator)
 440                          {
 441                              // Allowed operators
 442                              case '-':
 443                              case '+':
 444                              case '>':
 445                              case '<':
 446                              case '~':
 447                                  $word = substr($word, 1);
 448                                  break;
 449                              default:
 450                                  $operator = $boolean[$depth];
 451                                  break;
 452                          }
 453                          // Removed operators that are only allowed at the beginning
 454                          $word = preg_replace("#(-|\+|<|>|~|@)#s", '', $word);
 455                          // Removing wildcards at the beginning http://bugs.mysql.com/bug.php?id=72605
 456                          $word = preg_replace("#^\*#s", '', $word);
 457                          $word = $operator.$word;
 458                          if(strlen($word) <= 1)
 459                          {
 460                              continue;
 461                          }
 462                          $words[$depth][] = $word;
 463                          $boolean[$depth] = '+';
 464                      }
 465                  }
 466              }
 467          }
 468          $inquote = !$inquote;
 469      }
 470  
 471      // Close mismatching braces
 472      while($depth > 0)
 473      {
 474          $words[$depth-1][] = $boolean[$depth-1].'('.implode(' ', $words[$depth]).')';
 475          --$depth;
 476      }
 477  
 478      $keywords = implode(' ', $words[0]);
 479      return $keywords;
 480  }
 481  
 482  /* Database engine specific search functions */
 483  
 484  /**
 485   * Perform a thread and post search under MySQL or MySQLi
 486   *
 487   * @param array $search Array of search data
 488   * @return array Array of search data with results mixed in
 489   */
 490  function privatemessage_perform_search_mysql($search)
 491  {
 492      global $mybb, $db, $lang;
 493  
 494      $keywords = clean_keywords($search['keywords']);
 495      if(!$keywords && !$search['sender'])
 496      {
 497          error($lang->error_nosearchterms);
 498      }
 499  
 500      if($mybb->settings['minsearchword'] < 1)
 501      {
 502          $mybb->settings['minsearchword'] = 3;
 503      }
 504  
 505      $subject_lookin = "";
 506      $message_lookin = "";
 507      $searchsql = "uid='{$mybb->user['uid']}'";
 508  
 509      if($keywords)
 510      {
 511          // Complex search
 512          $keywords = " {$keywords} ";
 513  
 514          switch($db->type)
 515          {
 516              case 'mysql':
 517              case 'mysqli':
 518                  $sfield = 'subject';
 519                  $mfield = 'message';
 520                  break;
 521              default:
 522                  $sfield = 'LOWER(subject)';
 523                  $mfield = 'LOWER(message)';
 524                  break;
 525          }
 526  
 527          if(preg_match("#\s(and|or)\s#", $keywords))
 528          {
 529              $string = "AND";
 530              if($search['subject'] == 1)
 531              {
 532                  $string = "OR";
 533                  $subject_lookin = " AND (";
 534              }
 535  
 536              if($search['message'] == 1)
 537              {
 538                  $message_lookin = " {$string} (";
 539              }
 540  
 541              // Expand the string by double quotes
 542              $keywords_exp = explode("\"", $keywords);
 543              $inquote = false;
 544              $boolean = '';
 545  
 546              foreach($keywords_exp as $phrase)
 547              {
 548                  // If we're not in a double quoted section
 549                  if(!$inquote)
 550                  {
 551                      // Expand out based on search operators (and, or)
 552                      $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
 553                      $count_matches = count($matches);
 554  
 555                      for($i=0; $i < $count_matches; ++$i)
 556                      {
 557                          $word = trim($matches[$i]);
 558                          if(empty($word))
 559                          {
 560                              continue;
 561                          }
 562                          // If this word is a search operator set the boolean
 563                          if($i % 2 && ($word == "and" || $word == "or"))
 564                          {
 565                              if($i <= 1)
 566                              {
 567                                  if($search['subject'] && $search['message'] && $subject_lookin == " AND (")
 568                                  {
 569                                      // We're looking for anything, check for a subject lookin
 570                                      continue;
 571                                  }
 572                                  elseif($search['subject'] && !$search['message'] && $subject_lookin == " AND (")
 573                                  {
 574                                      // Just in a subject?
 575                                      continue;
 576                                  }
 577                                  elseif(!$search['subject'] && $search['message'] && $message_lookin == " {$string} (")
 578                                  {
 579                                      // Just in a message?
 580                                      continue;
 581                                  }
 582                              }
 583  
 584                              $boolean = $word;
 585                          }
 586                          // Otherwise check the length of the word as it is a normal search term
 587                          else
 588                          {
 589                              $word = trim($word);
 590                              // Word is too short - show error message
 591                              if(my_strlen($word) < $mybb->settings['minsearchword'])
 592                              {
 593                                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 594                                  error($lang->error_minsearchlength);
 595                              }
 596  
 597                              // Add terms to search query
 598                              if($search['subject'] == 1)
 599                              {
 600                                  $subject_lookin .= " $boolean {$sfield} LIKE '%{$word}%'";
 601                              }
 602                              if($search['message'] == 1)
 603                              {
 604                                  $message_lookin .= " $boolean {$mfield} LIKE '%{$word}%'";
 605                              }
 606                              $boolean = 'AND';
 607                          }
 608                      }
 609                  }
 610                  // In the middle of a quote (phrase)
 611                  else
 612                  {
 613                      $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
 614                      if(my_strlen($phrase) < $mybb->settings['minsearchword'])
 615                      {
 616                          $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 617                          error($lang->error_minsearchlength);
 618                      }
 619                      // Add phrase to search query
 620                      $subject_lookin .= " $boolean {$sfield} LIKE '%{$phrase}%'";
 621                      if($search['message'] == 1)
 622                      {
 623                          $message_lookin .= " $boolean {$mfield} LIKE '%{$phrase}%'";
 624                      }
 625                      $boolean = 'AND';
 626                  }
 627  
 628                  // Check to see if we have any search terms and not a malformed SQL string
 629                  $error = false;
 630                  if($search['subject'] && $search['message'] && $subject_lookin == " AND (")
 631                  {
 632                      // We're looking for anything, check for a subject lookin
 633                      $error = true;
 634                  }
 635                  elseif($search['subject'] && !$search['message'] && $subject_lookin == " AND (")
 636                  {
 637                      // Just in a subject?
 638                      $error = true;
 639                  }
 640                  elseif(!$search['subject'] && $search['message'] && $message_lookin == " {$string} (")
 641                  {
 642                      // Just in a message?
 643                      $error = true;
 644                  }
 645  
 646                  if($error == true)
 647                  {
 648                      // There are no search keywords to look for
 649                      $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 650                      error($lang->error_minsearchlength);
 651                  }
 652  
 653                  $inquote = !$inquote;
 654              }
 655  
 656              if($search['subject'] == 1)
 657              {
 658                  $subject_lookin .= ")";
 659              }
 660  
 661              if($search['message'] == 1)
 662              {
 663                  $message_lookin .= ")";
 664              }
 665  
 666              $searchsql .= "{$subject_lookin} {$message_lookin}";
 667          }
 668          else
 669          {
 670              $keywords = str_replace("\"", '', trim($keywords));
 671              if(my_strlen($keywords) < $mybb->settings['minsearchword'])
 672              {
 673                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 674                  error($lang->error_minsearchlength);
 675              }
 676  
 677              // If we're looking in both, then find matches in either the subject or the message
 678              if($search['subject'] == 1 && $search['message'] == 1)
 679              {
 680                  $searchsql .= " AND ({$sfield} LIKE '%{$keywords}%' OR {$mfield} LIKE '%{$keywords}%')";
 681              }
 682              else
 683              {
 684                  if($search['subject'] == 1)
 685                  {
 686                      $searchsql .= " AND {$sfield} LIKE '%{$keywords}%'";
 687                  }
 688  
 689                  if($search['message'] == 1)
 690                  {
 691                      $searchsql .= " AND {$mfield} LIKE '%{$keywords}%'";
 692                  }
 693              }
 694          }
 695      }
 696  
 697      if($search['sender'])
 698      {
 699          $userids = array();
 700          $search['sender'] = my_strtolower($search['sender']);
 701  
 702          switch($db->type)
 703          {
 704              case 'mysql':
 705              case 'mysqli':
 706                  $field = 'username';
 707                  break;
 708              default:
 709                  $field = 'LOWER(username)';
 710                  break;
 711          }
 712          $query = $db->simple_select("users", "uid", "{$field} LIKE '%".$db->escape_string_like($search['sender'])."%'");
 713          while($user = $db->fetch_array($query))
 714          {
 715              $userids[] = $user['uid'];
 716          }
 717  
 718          if(count($userids) < 1)
 719          {
 720              error($lang->error_nosearchresults);
 721          }
 722          else
 723          {
 724              $userids = implode(',', $userids);
 725              $searchsql .= " AND fromid IN (".$userids.")";
 726          }
 727      }
 728  
 729      if(!is_array($search['folder']))
 730      {
 731          $search['folder'] = array($search['folder']);
 732      }
 733  
 734      if(!empty($search['folder']))
 735      {
 736          $folderids = array();
 737  
 738          $search['folder'] = array_map("intval", $search['folder']);
 739  
 740          $folderids = implode(',', $search['folder']);
 741  
 742          if($folderids)
 743          {
 744              $searchsql .= " AND folder IN (".$folderids.")";
 745          }
 746      }
 747  
 748      if($search['status'])
 749      {
 750          $searchsql .= " AND (";
 751          if($search['status']['new'])
 752          {
 753              $statussql[] = " status='0' ";
 754          }
 755          if($search['status']['replied'])
 756          {
 757              $statussql[] = " status='3' ";
 758          }
 759          if($search['status']['forwarded'])
 760          {
 761              $statussql[] = " status='4' ";
 762          }
 763          if($search['status']['read'])
 764          {
 765              $statussql[] = " (status != '0' AND readtime > '0') ";
 766          }
 767          // Sent Folder
 768          if(in_array(2, $search['folder']))
 769          {
 770              $statussql[] = " status='1' ";
 771          }
 772          $statussql = implode("OR", $statussql);
 773          $searchsql .= $statussql.")";
 774      }
 775  
 776      $limitsql = "";
 777      if((int)$mybb->settings['searchhardlimit'] > 0)
 778      {
 779          $limitsql = " LIMIT ".(int)$mybb->settings['searchhardlimit'];
 780      }
 781      $searchsql .= $limitsql;
 782  
 783      // Run the search
 784      $pms = array();
 785      $query = $db->simple_select("privatemessages", "pmid", $searchsql);
 786      while($pm = $db->fetch_array($query))
 787      {
 788          $pms[$pm['pmid']] = $pm['pmid'];
 789      }
 790  
 791      if(count($pms) < 1)
 792      {
 793          error($lang->error_nosearchresults);
 794      }
 795      $pms = implode(',', $pms);
 796  
 797      return array(
 798          "querycache" => $pms
 799      );
 800  }
 801  
 802  /**
 803   * Perform a help document search under MySQL or MySQLi
 804   *
 805   * @param array $search Array of search data
 806   * @return array Array of search data with results mixed in
 807   */
 808  function helpdocument_perform_search_mysql($search)
 809  {
 810      global $mybb, $db, $lang;
 811  
 812      $keywords = clean_keywords($search['keywords']);
 813      if(!$keywords && !$search['sender'])
 814      {
 815          error($lang->error_nosearchterms);
 816      }
 817  
 818      if($mybb->settings['minsearchword'] < 1)
 819      {
 820          $mybb->settings['minsearchword'] = 3;
 821      }
 822  
 823      $name_lookin = "";
 824      $document_lookin = "";
 825      $searchsql = "enabled='1'";
 826  
 827      if($keywords)
 828      {
 829          switch($db->type)
 830          {
 831              case 'mysql':
 832              case 'mysqli':
 833                  $nfield = 'name';
 834                  $dfield = 'document';
 835                  break;
 836              default:
 837                  $nfield = 'LOWER(name)';
 838                  $dfield = 'LOWER(document)';
 839                  break;
 840          }
 841  
 842          // Complex search
 843          $keywords = " {$keywords} ";
 844          if(preg_match("#\s(and|or)\s#", $keywords))
 845          {
 846              $string = "AND";
 847              if($search['name'] == 1)
 848              {
 849                  $string = "OR";
 850                  $name_lookin = " AND (";
 851              }
 852  
 853              if($search['document'] == 1)
 854              {
 855                  $document_lookin = " {$string} (";
 856              }
 857  
 858              // Expand the string by double quotes
 859              $keywords_exp = explode("\"", $keywords);
 860              $inquote = false;
 861  
 862              foreach($keywords_exp as $phrase)
 863              {
 864                  // If we're not in a double quoted section
 865                  if(!$inquote)
 866                  {
 867                      // Expand out based on search operators (and, or)
 868                      $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
 869                      $count_matches = count($matches);
 870  
 871                      for($i=0; $i < $count_matches; ++$i)
 872                      {
 873                          $word = trim($matches[$i]);
 874                          if(empty($word))
 875                          {
 876                              continue;
 877                          }
 878                          // If this word is a search operator set the boolean
 879                          if($i % 2 && ($word == "and" || $word == "or"))
 880                          {
 881                              if($i <= 1)
 882                              {
 883                                  if($search['name'] && $search['document'] && $name_lookin == " AND (")
 884                                  {
 885                                      // We're looking for anything, check for a name lookin
 886                                      continue;
 887                                  }
 888                                  elseif($search['name'] && !$search['document'] && $name_lookin == " AND (")
 889                                  {
 890                                      // Just in a name?
 891                                      continue;
 892                                  }
 893                                  elseif(!$search['name'] && $search['document'] && $document_lookin == " {$string} (")
 894                                  {
 895                                      // Just in a document?
 896                                      continue;
 897                                  }
 898                              }
 899  
 900                              $boolean = $word;
 901                          }
 902                          // Otherwise check the length of the word as it is a normal search term
 903                          else
 904                          {
 905                              $word = trim($word);
 906                              // Word is too short - show error message
 907                              if(my_strlen($word) < $mybb->settings['minsearchword'])
 908                              {
 909                                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 910                                  error($lang->error_minsearchlength);
 911                              }
 912                              // Add terms to search query
 913                              if($search['name'] == 1)
 914                              {
 915                                  $name_lookin .= " $boolean {$nfield} LIKE '%{$word}%'";
 916                              }
 917                              if($search['document'] == 1)
 918                              {
 919                                  $document_lookin .= " $boolean {$dfield} LIKE '%{$word}%'";
 920                              }
 921                          }
 922                      }
 923                  }
 924                  // In the middle of a quote (phrase)
 925                  else
 926                  {
 927                      $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
 928                      if(my_strlen($phrase) < $mybb->settings['minsearchword'])
 929                      {
 930                          $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 931                          error($lang->error_minsearchlength);
 932                      }
 933                      // Add phrase to search query
 934                      $name_lookin .= " $boolean {$nfield} LIKE '%{$phrase}%'";
 935                      if($search['document'] == 1)
 936                      {
 937                          $document_lookin .= " $boolean {$dfield} LIKE '%{$phrase}%'";
 938                      }
 939                  }
 940  
 941                  // Check to see if we have any search terms and not a malformed SQL string
 942                  $error = false;
 943                  if($search['name'] && $search['document'] && $name_lookin == " AND (")
 944                  {
 945                      // We're looking for anything, check for a name lookin
 946                      $error = true;
 947                  }
 948                  elseif($search['name'] && !$search['document'] && $name_lookin == " AND (")
 949                  {
 950                      // Just in a name?
 951                      $error = true;
 952                  }
 953                  elseif(!$search['name'] && $search['document'] && $document_lookin == " {$string} (")
 954                  {
 955                      // Just in a document?
 956                      $error = true;
 957                  }
 958  
 959                  if($error == true)
 960                  {
 961                      // There are no search keywords to look for
 962                      $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 963                      error($lang->error_minsearchlength);
 964                  }
 965  
 966                  $inquote = !$inquote;
 967              }
 968  
 969              if($search['name'] == 1)
 970              {
 971                  $name_lookin .= ")";
 972              }
 973  
 974              if($search['document'] == 1)
 975              {
 976                  $document_lookin .= ")";
 977              }
 978  
 979              $searchsql .= "{$name_lookin} {$document_lookin}";
 980          }
 981          else
 982          {
 983              $keywords = str_replace("\"", '', trim($keywords));
 984              if(my_strlen($keywords) < $mybb->settings['minsearchword'])
 985              {
 986                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 987                  error($lang->error_minsearchlength);
 988              }
 989  
 990              // If we're looking in both, then find matches in either the name or the document
 991              if($search['name'] == 1 && $search['document'] == 1)
 992              {
 993                  $searchsql .= " AND ({$nfield} LIKE '%{$keywords}%' OR {$dfield} LIKE '%{$keywords}%')";
 994              }
 995              else
 996              {
 997                  if($search['name'] == 1)
 998                  {
 999                      $searchsql .= " AND {$nfield} LIKE '%{$keywords}%'";
1000                  }
1001  
1002                  if($search['document'] == 1)
1003                  {
1004                      $searchsql .= " AND {$dfield} LIKE '%{$keywords}%'";
1005                  }
1006              }
1007          }
1008      }
1009  
1010      // Run the search
1011      $helpdocs = array();
1012      $query = $db->simple_select("helpdocs", "hid", $searchsql);
1013      while($help = $db->fetch_array($query))
1014      {
1015          $helpdocs[$help['hid']] = $help['hid'];
1016      }
1017  
1018      if(count($helpdocs) < 1)
1019      {
1020          error($lang->error_nosearchresults);
1021      }
1022      $helpdocs = implode(',', $helpdocs);
1023  
1024      return array(
1025          "querycache" => $helpdocs
1026      );
1027  }
1028  
1029  /**
1030   * Perform a thread and post search under MySQL or MySQLi
1031   *
1032   * @param array $search Array of search data
1033   * @return array Array of search data with results mixed in
1034   */
1035  function perform_search_mysql($search)
1036  {
1037      global $mybb, $db, $lang, $cache;
1038  
1039      $keywords = clean_keywords($search['keywords']);
1040  
1041      if($mybb->settings['minsearchword'] < 1)
1042      {
1043          $mybb->settings['minsearchword'] = 3;
1044      }
1045  
1046      $subject_lookin = $message_lookin = '';
1047      if($keywords)
1048      {
1049          switch($db->type)
1050          {
1051              case 'mysql':
1052              case 'mysqli':
1053                  $tfield = 't.subject';
1054                  $pfield = 'p.message';
1055                  break;
1056              default:
1057                  $tfield = 'LOWER(t.subject)';
1058                  $pfield = 'LOWER(p.message)';
1059                  break;
1060          }
1061  
1062          // Complex search
1063          $keywords = " {$keywords} ";
1064          if(preg_match("#\s(and|or)\s#", $keywords))
1065          {
1066              $subject_lookin = " AND (";
1067              $message_lookin = " AND (";
1068  
1069              // Expand the string by double quotes
1070              $keywords_exp = explode("\"", $keywords);
1071              $inquote = false;
1072              $boolean = '';
1073  
1074              foreach($keywords_exp as $phrase)
1075              {
1076                  // If we're not in a double quoted section
1077                  if(!$inquote)
1078                  {
1079                      // Expand out based on search operators (and, or)
1080                      $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
1081                      $count_matches = count($matches);
1082  
1083                      for($i=0; $i < $count_matches; ++$i)
1084                      {
1085                          $word = trim($matches[$i]);
1086                          if(empty($word))
1087                          {
1088                              continue;
1089                          }
1090                          // If this word is a search operator set the boolean
1091                          if($i % 2 && ($word == "and" || $word == "or"))
1092                          {
1093                              if($i <= 1 && $subject_lookin == " AND (")
1094                              {
1095                                  continue;
1096                              }
1097  
1098                              $boolean = $word;
1099                          }
1100                          // Otherwise check the length of the word as it is a normal search term
1101                          else
1102                          {
1103                              $word = trim($word);
1104                              // Word is too short - show error message
1105                              if(my_strlen($word) < $mybb->settings['minsearchword'])
1106                              {
1107                                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1108                                  error($lang->error_minsearchlength);
1109                              }
1110                              // Add terms to search query
1111                              $subject_lookin .= " $boolean {$tfield} LIKE '%{$word}%'";
1112                              if($search['postthread'] == 1)
1113                              {
1114                                  $message_lookin .= " $boolean {$pfield} LIKE '%{$word}%'";
1115                              }
1116                              $boolean = 'AND';
1117                          }
1118                      }
1119                  }
1120                  // In the middle of a quote (phrase)
1121                  else
1122                  {
1123                      $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
1124                      if(my_strlen($phrase) < $mybb->settings['minsearchword'])
1125                      {
1126                          $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1127                          error($lang->error_minsearchlength);
1128                      }
1129                      // Add phrase to search query
1130                      $subject_lookin .= " $boolean {$tfield} LIKE '%{$phrase}%'";
1131                      if($search['postthread'] == 1)
1132                      {
1133                          $message_lookin .= " $boolean {$pfield} LIKE '%{$phrase}%'";
1134                      }
1135                      $boolean = 'AND';
1136                  }
1137  
1138                  if($subject_lookin == " AND (")
1139                  {
1140                      // There are no search keywords to look for
1141                      $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1142                      error($lang->error_minsearchlength);
1143                  }
1144  
1145                  $inquote = !$inquote;
1146              }
1147              $subject_lookin .= ")";
1148              $message_lookin .= ")";
1149          }
1150          else
1151          {
1152              $keywords = str_replace("\"", '', trim($keywords));
1153              if(my_strlen($keywords) < $mybb->settings['minsearchword'])
1154              {
1155                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1156                  error($lang->error_minsearchlength);
1157              }
1158              $subject_lookin = " AND {$tfield} LIKE '%{$keywords}%'";
1159              if($search['postthread'] == 1)
1160              {
1161                  $message_lookin = " AND {$pfield} LIKE '%{$keywords}%'";
1162              }
1163          }
1164      }
1165      $post_usersql = '';
1166      $thread_usersql = '';
1167      if($search['author'])
1168      {
1169          $userids = array();
1170          $search['author'] = my_strtolower($search['author']);
1171          if($search['matchusername'])
1172          {
1173              $user = get_user_by_username($search['author']);
1174              if($user)
1175              {
1176                  $userids[] = $user['uid'];
1177              }
1178          }
1179          else
1180          {
1181              switch($db->type)
1182              {
1183                  case 'mysql':
1184                  case 'mysqli':
1185                      $field = 'username';
1186                      break;
1187                  default:
1188                      $field = 'LOWER(username)';
1189                      break;
1190              }
1191              $query = $db->simple_select("users", "uid", "{$field} LIKE '%".$db->escape_string_like($search['author'])."%'");
1192              while($user = $db->fetch_array($query))
1193              {
1194                  $userids[] = $user['uid'];
1195              }
1196          }
1197  
1198          if(count($userids) < 1)
1199          {
1200              error($lang->error_nosearchresults);
1201          }
1202          else
1203          {
1204              $userids = implode(',', $userids);
1205              $post_usersql = " AND p.uid IN (".$userids.")";
1206              $thread_usersql = " AND t.uid IN (".$userids.")";
1207          }
1208      }
1209      $datecut = $post_datecut = $thread_datecut = '';
1210      if($search['postdate'])
1211      {
1212          if($search['pddir'] == 0)
1213          {
1214              $datecut = "<=";
1215          }
1216          else
1217          {
1218              $datecut = ">=";
1219          }
1220          $now = TIME_NOW;
1221          $datelimit = $now-(86400 * $search['postdate']);
1222          $datecut .= "'$datelimit'";
1223          $post_datecut = " AND p.dateline $datecut";
1224          $thread_datecut = " AND t.dateline $datecut";
1225      }
1226  
1227      $thread_replycut = '';
1228      if($search['numreplies'] != '' && $search['findthreadst'])
1229      {
1230          if((int)$search['findthreadst'] == 1)
1231          {
1232              $thread_replycut = " AND t.replies >= '".(int)$search['numreplies']."'";
1233          }
1234          else
1235          {
1236              $thread_replycut = " AND t.replies <= '".(int)$search['numreplies']."'";
1237          }
1238      }
1239  
1240      $thread_prefixcut = '';
1241      $prefixlist = array();
1242      if(!empty($search['threadprefix']) && $search['threadprefix'][0] != 'any')
1243      {
1244          foreach($search['threadprefix'] as $threadprefix)
1245          {
1246              $threadprefix = (int)$threadprefix;
1247              $prefixlist[] = $threadprefix;
1248          }
1249      }
1250      if(count($prefixlist) == 1)
1251      {
1252          $thread_prefixcut .= " AND t.prefix='$threadprefix' ";
1253      }
1254      else
1255      {
1256          if(count($prefixlist) > 1)
1257          {
1258              $thread_prefixcut = " AND t.prefix IN (".implode(',', $prefixlist).")";
1259          }
1260      }
1261  
1262      $forumin = '';
1263      $fidlist = array();
1264      if(!empty($search['forums']) && (!is_array($search['forums']) || $search['forums'][0] != "all"))
1265      {
1266          if(!is_array($search['forums']))
1267          {
1268              $search['forums'] = array((int)$search['forums']);
1269          }
1270          foreach($search['forums'] as $forum)
1271          {
1272              $forum = (int)$forum;
1273              if($forum > 0)
1274              {
1275                  $fidlist[] = $forum;
1276                  $child_list = get_child_list($forum);
1277                  if(is_array($child_list))
1278                  {
1279                      $fidlist = array_merge($fidlist, $child_list);
1280                  }
1281              }
1282          }
1283          $fidlist = array_unique($fidlist);
1284          if(count($fidlist) >= 1)
1285          {
1286              $forumin = " AND t.fid IN (".implode(',', $fidlist).")";
1287          }
1288      }
1289  
1290      $permsql = "";
1291      $onlyusfids = array();
1292  
1293      // Check group permissions if we can't view threads not started by us
1294      if($group_permissions = forum_permissions())
1295      {
1296          foreach($group_permissions as $fid => $forum_permissions)
1297          {
1298              if(isset($forum_permissions['canonlyviewownthreads']) && $forum_permissions['canonlyviewownthreads'] == 1)
1299              {
1300                  $onlyusfids[] = $fid;
1301              }
1302          }
1303      }
1304      if(!empty($onlyusfids))
1305      {
1306          $permsql .= "AND ((t.fid IN(".implode(',', $onlyusfids).") AND t.uid='{$mybb->user['uid']}') OR t.fid NOT IN(".implode(',', $onlyusfids)."))";
1307      }
1308  
1309      $unsearchforums = get_unsearchable_forums();
1310      if($unsearchforums)
1311      {
1312          $permsql .= " AND t.fid NOT IN ($unsearchforums)";
1313      }
1314      $inactiveforums = get_inactive_forums();
1315      if($inactiveforums)
1316      {
1317          $permsql .= " AND t.fid NOT IN ($inactiveforums)";
1318      }
1319  
1320      $visiblesql = $post_visiblesql = $plain_post_visiblesql = $unapproved_where_t = $unapproved_where_p = "";
1321      if(isset($search['visible']))
1322      {
1323          if($search['visible'] == 1)
1324          {
1325              $visiblesql = " AND t.visible = '1'";
1326  
1327              if($search['postthread'] == 1)
1328              {
1329                  $post_visiblesql = " AND p.visible = '1'";
1330                  $plain_post_visiblesql = " AND visible = '1'";
1331              }
1332          }
1333          elseif($search['visible'] == -1)
1334          {
1335              $visiblesql = " AND t.visible = '-1'";
1336  
1337              if($search['postthread'] == 1)
1338              {
1339                  $post_visiblesql = " AND p.visible = '-1'";
1340                  $plain_post_visiblesql = " AND visible = '-1'";
1341              }
1342          }
1343          else
1344          {
1345              $visiblesql = " AND t.visible == '0'";
1346  
1347              if($search['postthread'] == 1)
1348              {
1349                  $post_visiblesql = " AND p.visible == '0'";
1350                  $plain_post_visiblesql = " AND visible == '0'";
1351              }
1352          }
1353      }
1354  
1355      // Moderators can view unapproved threads and deleted threads from forums they moderate
1356      $unapproved_where_t = get_visible_where('t');
1357      $unapproved_where_p = get_visible_where('p');
1358  
1359      // Searching a specific thread?
1360      $tidsql = '';
1361      if(!empty($search['tid']))
1362      {
1363          $tidsql = " AND t.tid='".(int)$search['tid']."'";
1364      }
1365  
1366      $limitsql = '';
1367      if((int)$mybb->settings['searchhardlimit'] > 0)
1368      {
1369          $limitsql = "LIMIT ".(int)$mybb->settings['searchhardlimit'];
1370      }
1371  
1372      // Searching both posts and thread titles
1373      $threads = array();
1374      $posts = array();
1375      $firstposts = array();
1376      if($search['postthread'] == 1)
1377      {
1378          // No need to search subjects when looking for results within a specific thread
1379          if(empty($search['tid']))
1380          {
1381              $query = $db->query("
1382                  SELECT t.tid, t.firstpost
1383                  FROM ".TABLE_PREFIX."threads t
1384                  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}
1385                  {$limitsql}
1386              ");
1387              while($thread = $db->fetch_array($query))
1388              {
1389                  $threads[$thread['tid']] = $thread['tid'];
1390                  if($thread['firstpost'])
1391                  {
1392                      $posts[$thread['tid']] = $thread['firstpost'];
1393                  }
1394              }
1395          }
1396  
1397          $query = $db->query("
1398              SELECT p.pid, p.tid
1399              FROM ".TABLE_PREFIX."posts p
1400              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
1401              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}
1402              {$limitsql}
1403          ");
1404          while($post = $db->fetch_array($query))
1405          {
1406              $posts[$post['pid']] = $post['pid'];
1407              $threads[$post['tid']] = $post['tid'];
1408          }
1409  
1410          if(count($posts) < 1 && count($threads) < 1)
1411          {
1412              error($lang->error_nosearchresults);
1413          }
1414          $threads = implode(',', $threads);
1415          $posts = implode(',', $posts);
1416  
1417      }
1418      // Searching only thread titles
1419      else
1420      {
1421          $query = $db->query("
1422              SELECT t.tid, t.firstpost
1423              FROM ".TABLE_PREFIX."threads t
1424              WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} {$subject_lookin}
1425              {$limitsql}
1426          ");
1427          while($thread = $db->fetch_array($query))
1428          {
1429              $threads[$thread['tid']] = $thread['tid'];
1430              if($thread['firstpost'])
1431              {
1432                  $firstposts[$thread['tid']] = $thread['firstpost'];
1433              }
1434          }
1435          if(count($threads) < 1)
1436          {
1437              error($lang->error_nosearchresults);
1438          }
1439  
1440          $threads = implode(',', $threads);
1441          $firstposts = implode(',', $firstposts);
1442          if($firstposts)
1443          {
1444              $query = $db->simple_select("posts", "pid", "pid IN ($firstposts) {$plain_post_visiblesql} {$limitsql}");
1445              while($post = $db->fetch_array($query))
1446              {
1447                  $posts[$post['pid']] = $post['pid'];
1448              }
1449              $posts = implode(',', $posts);
1450          }
1451      }
1452      return array(
1453          "threads" => $threads,
1454          "posts" => $posts,
1455          "querycache" => ''
1456      );
1457  }
1458  
1459  /**
1460   * Perform a thread and post search under MySQL or MySQLi using boolean fulltext capabilities
1461   *
1462   * @param array $search Array of search data
1463   * @return array Array of search data with results mixed in
1464   */
1465  function perform_search_mysql_ft($search)
1466  {
1467      global $mybb, $db, $lang;
1468  
1469      $keywords = clean_keywords_ft($search['keywords']);
1470  
1471      if($mybb->settings['minsearchword'] < 1)
1472      {
1473          $mybb->settings['minsearchword'] = 4;
1474      }
1475  
1476      $message_lookin = $subject_lookin = '';
1477      if($keywords)
1478      {
1479          $keywords_exp = explode("\"", $keywords);
1480          $inquote = false;
1481          foreach($keywords_exp as $phrase)
1482          {
1483              if(!$inquote)
1484              {
1485                  $split_words = preg_split("#\s{1,}#", $phrase, -1);
1486                  foreach($split_words as $word)
1487                  {
1488                      $word = str_replace(array("+", "-", "*"), '', $word);
1489                      if(!$word)
1490                      {
1491                          continue;
1492                      }
1493                      if(my_strlen($word) < $mybb->settings['minsearchword'])
1494                      {
1495                          $all_too_short = true;
1496                      }
1497                      else
1498                      {
1499                          $all_too_short = false;
1500                          break;
1501                      }
1502                  }
1503              }
1504              else
1505              {
1506                  $phrase = str_replace(array("+", "-", "*"), '', $phrase);
1507                  if(my_strlen($phrase) < $mybb->settings['minsearchword'])
1508                  {
1509                      $all_too_short = true;
1510                  }
1511                  else
1512                  {
1513                      $all_too_short = false;
1514                      break;
1515                  }
1516              }
1517              $inquote = !$inquote;
1518          }
1519          // Show the minimum search term error only if all search terms are too short
1520          if($all_too_short == true)
1521          {
1522              $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1523              error($lang->error_minsearchlength);
1524          }
1525          $message_lookin = "AND MATCH(message) AGAINST('".$db->escape_string($keywords)."' IN BOOLEAN MODE)";
1526          $subject_lookin = "AND MATCH(subject) AGAINST('".$db->escape_string($keywords)."' IN BOOLEAN MODE)";
1527      }
1528      $post_usersql = '';
1529      $thread_usersql = '';
1530      if(!empty($search['author']))
1531      {
1532          $userids = array();
1533          $search['author'] = my_strtolower($search['author']);
1534          if($search['matchusername'])
1535          {
1536              $user = get_user_by_username($search['author']);
1537              if($user)
1538              {
1539                  $userids[] = $user['uid'];
1540              }
1541          }
1542          else
1543          {
1544              $query = $db->simple_select("users", "uid", "username LIKE '%".$db->escape_string_like($search['author'])."%'");
1545  
1546              while($user = $db->fetch_array($query))
1547              {
1548                  $userids[] = $user['uid'];
1549              }
1550          }
1551  
1552          if(count($userids) < 1)
1553          {
1554              error($lang->error_nosearchresults);
1555          }
1556          else
1557          {
1558              $userids = implode(',', $userids);
1559              $post_usersql = " AND p.uid IN (".$userids.")";
1560              $thread_usersql = " AND t.uid IN (".$userids.")";
1561          }
1562      }
1563      $datecut = $thread_datecut = $post_datecut = '';
1564      if(!empty($search['postdate']))
1565      {
1566          if($search['pddir'] == 0)
1567          {
1568              $datecut = "<=";
1569          }
1570          else
1571          {
1572              $datecut = ">=";
1573          }
1574          $now = TIME_NOW;
1575          $datelimit = $now-(86400 * $search['postdate']);
1576          $datecut .= "'$datelimit'";
1577          $post_datecut = " AND p.dateline $datecut";
1578          $thread_datecut = " AND t.dateline $datecut";
1579      }
1580  
1581      $thread_replycut = '';
1582      if(!empty($search['numreplies']) && $search['findthreadst'])
1583      {
1584          if((int)$search['findthreadst'] == 1)
1585          {
1586              $thread_replycut = " AND t.replies >= '".(int)$search['numreplies']."'";
1587          }
1588          else
1589          {
1590              $thread_replycut = " AND t.replies <= '".(int)$search['numreplies']."'";
1591          }
1592      }
1593  
1594      $thread_prefixcut = '';
1595      $prefixlist = array();
1596      if(!empty($search['threadprefix']) && $search['threadprefix'][0] != 'any')
1597      {
1598          foreach($search['threadprefix'] as $threadprefix)
1599          {
1600              $threadprefix = (int)$threadprefix;
1601              $prefixlist[] = $threadprefix;
1602          }
1603      }
1604      if(count($prefixlist) == 1)
1605      {
1606          $thread_prefixcut .= " AND t.prefix='$threadprefix' ";
1607      }
1608      else
1609      {
1610          if(count($prefixlist) > 1)
1611          {
1612              $thread_prefixcut = " AND t.prefix IN (".implode(',', $prefixlist).")";
1613          }
1614      }
1615  
1616      $forumin = '';
1617      $fidlist = array();
1618      $searchin = array();
1619      if(!empty($search['forums']) && (!is_array($search['forums']) || $search['forums'][0] != "all"))
1620      {
1621          if(!is_array($search['forums']))
1622          {
1623              $search['forums'] = array((int)$search['forums']);
1624          }
1625          foreach($search['forums'] as $forum)
1626          {
1627              $forum = (int)$forum;
1628              if($forum > 0)
1629              {
1630                  $fidlist[] = $forum;
1631                  $child_list = get_child_list($forum);
1632                  if(is_array($child_list))
1633                  {
1634                      $fidlist = array_merge($fidlist, $child_list);
1635                  }
1636              }
1637          }
1638          $fidlist = array_unique($fidlist);
1639          if(count($fidlist) >= 1)
1640          {
1641              $forumin = " AND t.fid IN (".implode(',', $fidlist).")";
1642          }
1643      }
1644      $permsql = "";
1645      $onlyusfids = array();
1646  
1647      // Check group permissions if we can't view threads not started by us
1648      $group_permissions = forum_permissions();
1649      foreach($group_permissions as $fid => $forum_permissions)
1650      {
1651          if(isset($forum_permissions['canonlyviewownthreads']) && $forum_permissions['canonlyviewownthreads'] == 1)
1652          {
1653              $onlyusfids[] = $fid;
1654          }
1655      }
1656      if(!empty($onlyusfids))
1657      {
1658          $permsql .= "AND ((t.fid IN(".implode(',', $onlyusfids).") AND t.uid='{$mybb->user['uid']}') OR t.fid NOT IN(".implode(',', $onlyusfids)."))";
1659      }
1660  
1661      $unsearchforums = get_unsearchable_forums();
1662      if($unsearchforums)
1663      {
1664          $permsql .= " AND t.fid NOT IN ($unsearchforums)";
1665      }
1666      $inactiveforums = get_inactive_forums();
1667      if($inactiveforums)
1668      {
1669          $permsql .= " AND t.fid NOT IN ($inactiveforums)";
1670      }
1671  
1672      $visiblesql = $post_visiblesql = $plain_post_visiblesql = $unapproved_where_t = $unapproved_where_p = "";
1673      if(isset($search['visible']))
1674      {
1675          if($search['visible'] == 1)
1676          {
1677              $visiblesql = " AND t.visible = '1'";
1678  
1679              if($search['postthread'] == 1)
1680              {
1681                  $post_visiblesql = " AND p.visible = '1'";
1682                  $plain_post_visiblesql = " AND visible = '1'";
1683              }
1684          }
1685          elseif($search['visible'] == -1)
1686          {
1687              $visiblesql = " AND t.visible = '-1'";
1688  
1689              if($search['postthread'] == 1)
1690              {
1691                  $post_visiblesql = " AND p.visible = '-1'";
1692                  $plain_post_visiblesql = " AND visible = '-1'";
1693              }
1694          }
1695          else
1696          {
1697              $visiblesql = " AND t.visible != '1'";
1698  
1699              if($search['postthread'] == 1)
1700              {
1701                  $post_visiblesql = " AND p.visible != '1'";
1702                  $plain_post_visiblesql = " AND visible != '1'";
1703              }
1704          }
1705      }
1706  
1707      // Moderators can view unapproved threads and deleted threads from forums they moderate
1708      $unapproved_where_t = get_visible_where('t');
1709      $unapproved_where_p = get_visible_where('p');
1710  
1711      // Searching a specific thread?
1712      $tidsql = '';
1713      if(!empty($search['tid']))
1714      {
1715          $tidsql = " AND t.tid='".(int)$search['tid']."'";
1716      }
1717  
1718      $limitsql = '';
1719      if((int)$mybb->settings['searchhardlimit'] > 0)
1720      {
1721          $limitsql = "LIMIT ".(int)$mybb->settings['searchhardlimit'];
1722      }
1723  
1724      // Searching both posts and thread titles
1725      $threads = array();
1726      $posts = array();
1727      $firstposts = array();
1728      if($search['postthread'] == 1)
1729      {
1730          // No need to search subjects when looking for results within a specific thread
1731          if(empty($search['tid']))
1732          {
1733              $query = $db->query("
1734                  SELECT t.tid, t.firstpost
1735                  FROM ".TABLE_PREFIX."threads t
1736                  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}
1737                  {$limitsql}
1738              ");
1739              while($thread = $db->fetch_array($query))
1740              {
1741                  $threads[$thread['tid']] = $thread['tid'];
1742                  if($thread['firstpost'])
1743                  {
1744                      $posts[$thread['tid']] = $thread['firstpost'];
1745                  }
1746              }
1747          }
1748  
1749          $query = $db->query("
1750              SELECT p.pid, p.tid
1751              FROM ".TABLE_PREFIX."posts p
1752              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
1753              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}
1754              {$limitsql}
1755          ");
1756          while($post = $db->fetch_array($query))
1757          {
1758              $posts[$post['pid']] = $post['pid'];
1759              $threads[$post['tid']] = $post['tid'];
1760          }
1761          if(count($posts) < 1 && count($threads) < 1)
1762          {
1763              error($lang->error_nosearchresults);
1764          }
1765          $threads = implode(',', $threads);
1766          $posts = implode(',', $posts);
1767  
1768      }
1769      // Searching only thread titles
1770      else
1771      {
1772          $query = $db->query("
1773              SELECT t.tid, t.firstpost
1774              FROM ".TABLE_PREFIX."threads t
1775              WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} {$subject_lookin}
1776              {$limitsql}
1777          ");
1778          while($thread = $db->fetch_array($query))
1779          {
1780              $threads[$thread['tid']] = $thread['tid'];
1781              if($thread['firstpost'])
1782              {
1783                  $firstposts[$thread['tid']] = $thread['firstpost'];
1784              }
1785          }
1786          if(count($threads) < 1)
1787          {
1788              error($lang->error_nosearchresults);
1789          }
1790  
1791          $threads = implode(',', $threads);
1792          $firstposts = implode(',', $firstposts);
1793          if($firstposts)
1794          {
1795              $query = $db->simple_select("posts", "pid", "pid IN ($firstposts) {$plain_post_visiblesql} {$limitsql}");
1796              while($post = $db->fetch_array($query))
1797              {
1798                  $posts[$post['pid']] = $post['pid'];
1799              }
1800              $posts = implode(',', $posts);
1801          }
1802      }
1803      return array(
1804          "threads" => $threads,
1805          "posts" => $posts,
1806          "querycache" => ''
1807      );
1808  }


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