[ Index ]

PHP Cross Reference of MyBB 1.8.27

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


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