[ Index ]

PHP Cross Reference of MyBB

title

Body

[close]

/inc/ -> functions_search.php (source)

   1  <?php
   2  /**
   3   * MyBB 1.6
   4   * Copyright 2010 MyBB Group, All Rights Reserved
   5   *
   6   * Website: http://mybb.com
   7   * License: http://mybb.com/about/license
   8   *
   9   * $Id$
  10   */
  11  
  12  /**
  13   * Build a select box list of forums the current user has permission to search
  14   *
  15   * @param int The parent forum ID to start at
  16   * @param int The selected forum ID
  17   * @param int Add select boxes at this call or not
  18   * @param int The current depth
  19   * @return string The forum select boxes
  20   */
  21  function make_searchable_forums($pid="0", $selitem='', $addselect="1", $depth='')
  22  {
  23      global $db, $pforumcache, $permissioncache, $mybb, $selecteddone, $forumlist, $forumlistbits, $theme, $templates, $lang, $forumpass;
  24      $pid = intval($pid);
  25  
  26      if(!is_array($pforumcache))
  27      {
  28          // Get Forums
  29          $query = $db->simple_select("forums", "pid,disporder,fid,password,name", "linkto='' AND active!=0", array('order_by' => "pid, disporder"));
  30          while($forum = $db->fetch_array($query))
  31          {
  32              $pforumcache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum;
  33          }
  34      }
  35      if(!is_array($permissioncache))
  36      {
  37          $permissioncache = forum_permissions();
  38      }
  39      if(is_array($pforumcache[$pid]))
  40      {
  41          foreach($pforumcache[$pid] as $key => $main)
  42          {
  43              foreach($main as $key => $forum)
  44              {
  45                  $perms = $permissioncache[$forum['fid']];
  46                  if(($perms['canview'] == 1 || $mybb->settings['hideprivateforums'] == 0) && $perms['cansearch'] != 0)
  47                  {
  48                      if($selitem == $forum['fid'])
  49                      {
  50                          $optionselected = "selected";
  51                          $selecteddone = "1";
  52                      }
  53                      else
  54                      {
  55                          $optionselected = '';
  56                          $selecteddone = "0";
  57                      }
  58                      if($forum['password'] != '')
  59                      {
  60                          if($mybb->cookies['forumpass'][$forum['fid']] == md5($mybb->user['uid'].$forum['password']))
  61                          {
  62                              $pwverified = 1;
  63                          }
  64                          else
  65                          {
  66                              $pwverified = 0;
  67                          }
  68                      }
  69                      if(empty($forum['password']) || $pwverified == 1)
  70                      {
  71                          $forumlistbits .= "<option value=\"{$forum['fid']}\">$depth {$forum['name']}</option>\n";
  72                      }
  73                      if($pforumcache[$forum['fid']])
  74                      {
  75                          $newdepth = $depth."&nbsp;&nbsp;&nbsp;&nbsp;";
  76                          $forumlistbits .= make_searchable_forums($forum['fid'], $selitem, 0, $newdepth);
  77                      }
  78                  }
  79              }
  80          }
  81      }
  82      if($addselect)
  83      {
  84          $forumlist = "<select name=\"forums[]\" size=\"20\" multiple=\"multiple\">\n<option value=\"all\" selected=\"selected\">$lang->search_all_forums</option>\n<option value=\"all\">----------------------</option>\n$forumlistbits\n</select>";
  85      }
  86      return $forumlist;
  87  }
  88  
  89  /**
  90   * Build a comma separated list of the forums this user cannot search
  91   *
  92   * @param int The parent ID to build from
  93   * @param int First rotation or not (leave at default)
  94   * @return return a CSV list of forums the user cannot search
  95   */
  96  function get_unsearchable_forums($pid="0", $first=1)
  97  {
  98      global $db, $forum_cache, $permissioncache, $mybb, $unsearchableforums, $unsearchable, $templates, $forumpass;
  99  
 100      $pid = intval($pid);
 101  
 102      if(!is_array($forum_cache))
 103      {
 104          // Get Forums
 105          $query = $db->simple_select("forums", "fid,parentlist,password,active", '', array('order_by' => 'pid, disporder'));
 106          while($forum = $db->fetch_array($query))
 107          {
 108              $forum_cache[$forum['fid']] = $forum;
 109          }
 110      }
 111      if(!is_array($permissioncache))
 112      {
 113          $permissioncache = forum_permissions();
 114      }
 115      foreach($forum_cache as $fid => $forum)
 116      {
 117          if($permissioncache[$forum['fid']])
 118          {
 119              $perms = $permissioncache[$forum['fid']];
 120          }
 121          else
 122          {
 123              $perms = $mybb->usergroup;
 124          }
 125  
 126          $pwverified = 1;
 127          if($forum['password'] != '')
 128          {
 129              if($mybb->cookies['forumpass'][$forum['fid']] != md5($mybb->user['uid'].$forum['password']))
 130              {
 131                  $pwverified = 0;
 132              }
 133          }
 134  
 135          $parents = explode(",", $forum['parentlist']);
 136          if(is_array($parents))
 137          {
 138              foreach($parents as $parent)
 139              {
 140                  if($forum_cache[$parent]['active'] == 0)
 141                  {
 142                      $forum['active'] = 0;
 143                  }
 144              }
 145          }
 146  
 147          if($perms['canview'] != 1 || $perms['cansearch'] != 1 || $pwverified == 0 || $forum['active'] == 0)
 148          {
 149              if($unsearchableforums)
 150              {
 151                  $unsearchableforums .= ",";
 152              }
 153              $unsearchableforums .= "'{$forum['fid']}'";
 154          }
 155      }
 156      $unsearchable = $unsearchableforums;
 157  
 158      // Get our unsearchable password protected forums
 159      $pass_protected_forums = get_password_protected_forums();
 160  
 161      if($unsearchable && $pass_protected_forums)
 162      {
 163          $unsearchable .= ",";
 164      }
 165  
 166      if($pass_protected_forums)
 167      {
 168          $unsearchable .= implode(",", $pass_protected_forums);
 169      }
 170  
 171      return $unsearchable;
 172  }
 173  
 174  /**
 175   * Build a array list of the forums this user cannot search due to password protection
 176   *
 177   * @param int the fids to check (leave null to check all forums)
 178   * @return return a array list of password protected forums the user cannot search
 179   */
 180  function get_password_protected_forums($fids=array())
 181  {
 182      global $forum_cache, $mybb;
 183  
 184      if(!is_array($fids))
 185      {
 186          return false;
 187      }
 188  
 189      if(!is_array($forum_cache))
 190      {
 191          $forum_cache = cache_forums();
 192          if(!$forum_cache)
 193          {
 194              return false;
 195          }
 196      }
 197  
 198      if(empty($fids))
 199      {
 200          $fids = array_keys($forum_cache);
 201      }
 202  
 203      $pass_fids = array();
 204      foreach($fids as $fid)
 205      {
 206          if(empty($forum_cache[$fid]['password']))
 207          {
 208              continue;
 209          }
 210  
 211          if(md5($mybb->user['uid'].$forum_cache[$fid]['password']) != $mybb->cookies['forumpass'][$fid])
 212          {
 213              $pass_fids[] = $fid;
 214              $child_list = get_child_list($fid);
 215          }
 216  
 217          if(is_array($child_list))
 218          {
 219              $pass_fids = array_merge($pass_fids, $child_list);
 220          }
 221      }
 222      return array_unique($pass_fids);
 223  }
 224  
 225  /**
 226   * Clean search keywords and make them safe for querying
 227   *
 228   * @param string The keywords to be cleaned
 229   * @return string The cleaned keywords
 230   */
 231  function clean_keywords($keywords)
 232  {
 233      $keywords = my_strtolower($keywords);
 234      $keywords = str_replace("%", "\\%", $keywords);
 235      $keywords = preg_replace("#\*{2,}#s", "*", $keywords);
 236      $keywords = str_replace("*", "%", $keywords);
 237      $keywords = preg_replace("#([\[\]\|\.\,:'])#s", " ", $keywords);
 238      $keywords = preg_replace("#\s+#s", " ", $keywords);
 239  
 240      // Search for "and" or "or" and remove if it's at the beginning
 241      $keywords = trim($keywords);
 242      if(my_strpos($keywords, "or") === 0)
 243      {
 244          $keywords = substr_replace($keywords, "", 0, 2);
 245      }
 246  
 247      if(my_strpos($keywords, "and") === 0)
 248      {
 249          $keywords = substr_replace($keywords, "", 0, 3);
 250      }
 251  
 252      return $keywords;
 253  }
 254  
 255  /**
 256   * Clean search keywords for fulltext searching, making them safe for querying
 257   *
 258   * @param string The keywords to be cleaned
 259   * @return string The cleaned keywords
 260   */
 261  function clean_keywords_ft($keywords)
 262  {
 263      if(!$keywords)
 264      {
 265          return false;
 266      }
 267      $keywords = my_strtolower($keywords);
 268      $keywords = str_replace("%", "\\%", $keywords);
 269      $keywords = preg_replace("#\*{2,}#s", "*", $keywords);
 270      $keywords = preg_replace("#([\[\]\|\.\,:])#s", " ", $keywords);
 271      $keywords = preg_replace("#\s+#s", " ", $keywords);
 272  
 273      $words = array();
 274  
 275      if(my_strpos($keywords, "\"") !== false)
 276      {
 277          $inquote = false;
 278          $keywords = explode("\"", $keywords);
 279          foreach($keywords as $phrase)
 280          {
 281              if($phrase != '')
 282              {
 283                  if($inquote)
 284                  {
 285                      $words[] = "\"".trim($phrase)."\"";
 286                  }
 287                  else
 288                  {
 289                      $split_words = preg_split("#\s{1,}#", $phrase, -1);
 290                      if(!is_array($split_words))
 291                      {
 292                          continue;
 293                      }
 294                      foreach($split_words as $word)
 295                      {
 296                          if(!$word)
 297                          {
 298                              continue;
 299                          }
 300                          $words[] = trim($word);
 301                      }
 302                  }
 303              }
 304              $inquote = !$inquote;
 305          }
 306      }
 307      else
 308      {
 309          $split_words = preg_split("#\s{1,}#", $keywords, -1);
 310          if(!is_array($split_words))
 311          {
 312              continue;
 313          }
 314          foreach($split_words as $word)
 315          {
 316              if(!$word)
 317              {
 318                  continue;
 319              }
 320              $words[] = trim($word);
 321          }
 322  
 323      }
 324      $keywords = '';
 325      foreach($words as $word)
 326      {
 327          if($word == "or")
 328          {
 329              $boolean = '';
 330          }
 331          elseif($word == "and")
 332          {
 333              $boolean = "+";
 334          }
 335          elseif($word == "not")
 336          {
 337              $boolean = "-";
 338          }
 339          else
 340          {
 341              $keywords .= " ".$boolean.$word;
 342              $boolean = '';
 343          }
 344      }
 345      $keywords = "+".trim($keywords);
 346      return $keywords;
 347  }
 348  
 349  /* Database engine specific search functions */
 350  
 351  /**
 352   * Perform a thread and post search under MySQL or MySQLi
 353   *
 354   * @param array Array of search data
 355   * @return array Array of search data with results mixed in
 356   */
 357  function privatemessage_perform_search_mysql($search)
 358  {
 359      global $mybb, $db, $lang;
 360  
 361      $keywords = clean_keywords($search['keywords']);
 362      if(!$keywords && !$search['sender'])
 363      {
 364          error($lang->error_nosearchterms);
 365      }
 366  
 367      if($mybb->settings['minsearchword'] < 1)
 368      {
 369          $mybb->settings['minsearchword'] = 3;
 370      }
 371  
 372      $subject_lookin = "";
 373      $message_lookin = "";
 374      $searchsql = "uid='{$mybb->user['uid']}'";
 375  
 376      if($keywords)
 377      {
 378          // Complex search
 379          $keywords = " {$keywords} ";
 380          if(preg_match("# and|or #", $keywords))
 381          {
 382              $string = "AND";
 383              if($search['subject'] == 1)
 384              {
 385                  $string = "OR";
 386                  $subject_lookin = " AND (";
 387              }
 388  
 389              if($search['message'] == 1)
 390              {
 391                  $message_lookin = " {$string} (";
 392              }
 393  
 394              // Expand the string by double quotes
 395              $keywords_exp = explode("\"", $keywords);
 396              $inquote = false;
 397  
 398              foreach($keywords_exp as $phrase)
 399              {
 400                  // If we're not in a double quoted section
 401                  if(!$inquote)
 402                  {
 403                      // Expand out based on search operators (and, or)
 404                      $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
 405                      $count_matches = count($matches);
 406  
 407                      for($i=0; $i < $count_matches; ++$i)
 408                      {
 409                          $word = trim($matches[$i]);
 410                          if(empty($word))
 411                          {
 412                              continue;
 413                          }
 414                          // If this word is a search operator set the boolean
 415                          if($i % 2 && ($word == "and" || $word == "or"))
 416                          {
 417                              if($i <= 1)
 418                              {
 419                                  if($search['subject'] && $search['message'] && $subject_lookin == " AND (")
 420                                  {
 421                                      // We're looking for anything, check for a subject lookin
 422                                      continue;
 423                                  }
 424                                  elseif($search['subject'] && !$search['message'] && $subject_lookin == " AND (")
 425                                  {
 426                                      // Just in a subject?
 427                                      continue;
 428                                  }
 429                                  elseif(!$search['subject'] && $search['message'] && $message_lookin == " {$string} (")
 430                                  {
 431                                      // Just in a message?
 432                                      continue;
 433                                  }
 434                              }
 435  
 436                              $boolean = $word;
 437                          }
 438                          // Otherwise check the length of the word as it is a normal search term
 439                          else
 440                          {
 441                              $word = trim($word);
 442                              // Word is too short - show error message
 443                              if(my_strlen($word) < $mybb->settings['minsearchword'])
 444                              {
 445                                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 446                                  error($lang->error_minsearchlength);
 447                              }
 448                              // Add terms to search query
 449                              if($search['subject'] == 1)
 450                              {
 451                                  $subject_lookin .= " $boolean LOWER(subject) LIKE '%{$word}%'";
 452                              }
 453                              if($search['message'] == 1)
 454                              {
 455                                  $message_lookin .= " $boolean LOWER(message) LIKE '%{$word}%'";
 456                              }
 457                          }
 458                      }
 459                  }
 460                  // In the middle of a quote (phrase)
 461                  else
 462                  {
 463                      $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
 464                      if(my_strlen($phrase) < $mybb->settings['minsearchword'])
 465                      {
 466                          $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 467                          error($lang->error_minsearchlength);
 468                      }
 469                      // Add phrase to search query
 470                      $subject_lookin .= " $boolean LOWER(subject) LIKE '%{$phrase}%'";
 471                      if($search['message'] == 1)
 472                      {
 473                          $message_lookin .= " $boolean LOWER(message) LIKE '%{$phrase}%'";
 474                      }
 475                  }
 476  
 477                  // Check to see if we have any search terms and not a malformed SQL string
 478                  $error = false;
 479                  if($search['subject'] && $search['message'] && $subject_lookin == " AND (")
 480                  {
 481                      // We're looking for anything, check for a subject lookin
 482                      $error = true;
 483                  }
 484                  elseif($search['subject'] && !$search['message'] && $subject_lookin == " AND (")
 485                  {
 486                      // Just in a subject?
 487                      $error = true;
 488                  }
 489                  elseif(!$search['subject'] && $search['message'] && $message_lookin == " {$string} (")
 490                  {
 491                      // Just in a message?
 492                      $error = true;
 493                  }
 494  
 495                  if($error == true)
 496                  {
 497                      // There are no search keywords to look for
 498                      $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 499                      error($lang->error_minsearchlength);
 500                  }
 501  
 502                  $inquote = !$inquote;
 503              }
 504  
 505              if($search['subject'] == 1)
 506              {
 507                  $subject_lookin .= ")";
 508              }
 509  
 510              if($search['message'] == 1)
 511              {
 512                  $message_lookin .= ")";
 513              }
 514  
 515              $searchsql .= "{$subject_lookin} {$message_lookin}";
 516          }
 517          else
 518          {
 519              $keywords = str_replace("\"", '', trim($keywords));
 520              if(my_strlen($keywords) < $mybb->settings['minsearchword'])
 521              {
 522                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 523                  error($lang->error_minsearchlength);
 524              }
 525  
 526              // If we're looking in both, then find matches in either the subject or the message
 527              if($search['subject'] == 1 && $search['message'] == 1)
 528              {
 529                  $searchsql .= " AND (LOWER(subject) LIKE '%{$keywords}%' OR LOWER(message) LIKE '%{$keywords}%')";
 530              }
 531              else
 532              {
 533                  if($search['subject'] == 1)
 534                  {
 535                      $searchsql .= " AND LOWER(subject) LIKE '%{$keywords}%'";
 536                  }
 537  
 538                  if($search['message'] == 1)
 539                  {
 540                      $searchsql .= " AND LOWER(message) LIKE '%{$keywords}%'";
 541                  }
 542              }
 543          }
 544      }
 545  
 546      if($search['sender'])
 547      {
 548          $userids = array();
 549          $search['sender'] = my_strtolower($search['sender']);
 550  
 551          $query = $db->simple_select("users", "uid", "LOWER(username) LIKE '%".$db->escape_string_like($db->escape_string($search['sender']))."%'");
 552          while($user = $db->fetch_array($query))
 553          {
 554              $userids[] = $user['uid'];
 555          }
 556  
 557          if(count($userids) < 1)
 558          {
 559              error($lang->error_nosearchresults);
 560          }
 561          else
 562          {
 563              $userids = implode(',', $userids);
 564              $searchsql .= " AND fromid IN (".$userids.")";
 565          }
 566      }
 567  
 568      if(!is_array($search['folder']))
 569      {
 570          $search['folder'] = array($search['folder']);
 571      }
 572  
 573      if(!empty($search['folder']))
 574      {
 575          $folderids = array();
 576  
 577          $search['folder'] = array_map("intval", $search['folder']);
 578  
 579          $folderids = implode(',', $search['folder']);
 580  
 581          if($folderids)
 582          {
 583              $searchsql .= " AND folder IN (".$folderids.")";
 584          }
 585      }
 586  
 587      if($search['status'])
 588      {
 589          $searchsql .= " AND (";
 590          if($search['status']['new'])
 591          {
 592              $statussql[] = " status='0' ";
 593          }
 594          if($search['status']['replied'])
 595          {
 596              $statussql[] = " status='3' ";
 597          }
 598          if($search['status']['forwarded'])
 599          {
 600              $statussql[] = " status='4' ";
 601          }
 602          if($search['status']['read'])
 603          {
 604              $statussql[] = " (status != '0' AND readtime > '0') ";
 605          }
 606          // Sent Folder
 607          if(in_array(2, $search['folder']))
 608          {
 609              $statussql[] = " status='1' ";
 610          }
 611          $statussql = implode("OR", $statussql);
 612          $searchsql .= $statussql.")";
 613      }
 614  
 615      // Run the search
 616      $pms = array();
 617      $query = $db->simple_select("privatemessages", "pmid", $searchsql);
 618      while($pm = $db->fetch_array($query))
 619      {
 620          $pms[$pm['pmid']] = $pm['pmid'];
 621      }
 622  
 623      if(count($pms) < 1)
 624      {
 625          error($lang->error_nosearchresults);
 626      }
 627      $pms = implode(',', $pms);
 628  
 629      return array(
 630          "querycache" => $pms
 631      );
 632  }
 633  
 634  /**
 635   * Perform a thread and post search under MySQL or MySQLi
 636   *
 637   * @param array Array of search data
 638   * @return array Array of search data with results mixed in
 639   */
 640  function perform_search_mysql($search)
 641  {
 642      global $mybb, $db, $lang, $cache;
 643  
 644      $keywords = clean_keywords($search['keywords']);
 645      if(!$keywords && !$search['author'])
 646      {
 647          error($lang->error_nosearchterms);
 648      }
 649  
 650      if($mybb->settings['minsearchword'] < 1)
 651      {
 652          $mybb->settings['minsearchword'] = 3;
 653      }
 654  
 655      if($keywords)
 656      {
 657          // Complex search
 658          $keywords = " {$keywords} ";
 659          if(preg_match("# and|or #", $keywords))
 660          {
 661              $subject_lookin = " AND (";
 662              $message_lookin = " AND (";
 663  
 664              // Expand the string by double quotes
 665              $keywords_exp = explode("\"", $keywords);
 666              $inquote = false;
 667  
 668              foreach($keywords_exp as $phrase)
 669              {
 670                  // If we're not in a double quoted section
 671                  if(!$inquote)
 672                  {
 673                      // Expand out based on search operators (and, or)
 674                      $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
 675                      $count_matches = count($matches);
 676  
 677                      for($i=0; $i < $count_matches; ++$i)
 678                      {
 679                          $word = trim($matches[$i]);
 680                          if(empty($word))
 681                          {
 682                              continue;
 683                          }
 684                          // If this word is a search operator set the boolean
 685                          if($i % 2 && ($word == "and" || $word == "or"))
 686                          {
 687                              if($i <= 1 && $subject_lookin == " AND (")
 688                              {
 689                                  continue;
 690                              }
 691  
 692                              $boolean = $word;
 693                          }
 694                          // Otherwise check the length of the word as it is a normal search term
 695                          else
 696                          {
 697                              $word = trim($word);
 698                              // Word is too short - show error message
 699                              if(my_strlen($word) < $mybb->settings['minsearchword'])
 700                              {
 701                                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 702                                  error($lang->error_minsearchlength);
 703                              }
 704                              // Add terms to search query
 705                              $subject_lookin .= " $boolean LOWER(t.subject) LIKE '%{$word}%'";
 706                              if($search['postthread'] == 1)
 707                              {
 708                                  $message_lookin .= " $boolean LOWER(p.message) LIKE '%{$word}%'";
 709                              }
 710                          }
 711                      }
 712                  }
 713                  // In the middle of a quote (phrase)
 714                  else
 715                  {
 716                      $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
 717                      if(my_strlen($phrase) < $mybb->settings['minsearchword'])
 718                      {
 719                          $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 720                          error($lang->error_minsearchlength);
 721                      }
 722                      // Add phrase to search query
 723                      $subject_lookin .= " $boolean LOWER(t.subject) LIKE '%{$phrase}%'";
 724                      if($search['postthread'] == 1)
 725                      {
 726                          $message_lookin .= " $boolean LOWER(p.message) LIKE '%{$phrase}%'";
 727                      }
 728                  }
 729  
 730                  if($subject_lookin == " AND (")
 731                  {
 732                      // There are no search keywords to look for
 733                      $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 734                      error($lang->error_minsearchlength);
 735                  }
 736  
 737                  $inquote = !$inquote;
 738              }
 739              $subject_lookin .= ")";
 740              $message_lookin .= ")";
 741          }
 742          else
 743          {
 744              $keywords = str_replace("\"", '', trim($keywords));
 745              if(my_strlen($keywords) < $mybb->settings['minsearchword'])
 746              {
 747                  $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
 748                  error($lang->error_minsearchlength);
 749              }
 750              $subject_lookin = " AND LOWER(t.subject) LIKE '%{$keywords}%'";
 751              if($search['postthread'] == 1)
 752              {
 753                  $message_lookin = " AND LOWER(p.message) LIKE '%{$keywords}%'";
 754              }
 755          }
 756      }
 757      $post_usersql = '';
 758      $thread_usersql = '';
 759      if($search['author'])
 760      {
 761          $userids = array();
 762          if($search['matchusername'])
 763          {
 764              $query = $db->simple_select("users", "uid", "username='".$db->escape_string($search['author'])."'");
 765          }
 766          else
 767          {
 768              $search['author'] = my_strtolower($search['author']);
 769              $query = $db->simple_select("users", "uid", "LOWER(username) LIKE '%".$db->escape_string_like($db->escape_string($search['author']))."%'");
 770          }
 771          while($user = $db->fetch_array($query))
 772          {
 773              $userids[] = $user['uid'];
 774          }
 775          if(count($userids) < 1)
 776          {
 777              error($lang->error_nosearchresults);
 778          }
 779          else
 780          {
 781              $userids = implode(',', $userids);
 782              $post_usersql = " AND p.uid IN (".$userids.")";
 783              $thread_usersql = " AND t.uid IN (".$userids.")";
 784          }
 785      }
 786      $datecut = '';
 787      if($search['postdate'])
 788      {
 789          if($search['pddir'] == 0)
 790          {
 791              $datecut = "<=";
 792          }
 793          else
 794          {
 795              $datecut = ">=";
 796          }
 797          $now = TIME_NOW;
 798          $datelimit = $now-(86400 * $search['postdate']);
 799          $datecut .= "'$datelimit'";
 800          $post_datecut = " AND p.dateline $datecut";
 801          $thread_datecut = " AND t.dateline $datecut";
 802      }
 803  
 804      $thread_replycut = '';
 805      if($search['numreplies'] != '' && $search['findthreadst'])
 806      {
 807          if(intval($search['findthreadst']) == 1)
 808          {
 809              $thread_replycut = " AND t.replies >= '".intval($search['numreplies'])."'";
 810          }
 811          else
 812          {
 813              $thread_replycut = " AND t.replies <= '".intval($search['numreplies'])."'";
 814          }
 815      }
 816  
 817      $thread_prefixcut = '';
 818      if($search['threadprefix'] && $search['threadprefix'] != 'any')
 819      {
 820          $thread_prefixcut = " AND t.prefix='".intval($search['threadprefix'])."'";
 821      }
 822  
 823      $forumin = '';
 824      $fidlist = array();
 825      $searchin = array();
 826      if($search['forums'][0] != "all")
 827      {
 828          if(!is_array($search['forums']))
 829          {
 830              $search['forums'] = array(intval($search['forums']));
 831          }
 832          // Generate a comma separated list of all groups the user belongs to
 833          $user_groups = $mybb->user['usergroup'];
 834          if($mybb->user['additionalgroups'])
 835          {
 836              $user_groups .= ",".$mybb->user['additionalgroups'];
 837  
 838              // Setup some quick permissions for us
 839              $fcache = $cache->read("forumpermissions");
 840              $add_groups = explode(",", $mybb->user['additionalgroups']);
 841          }
 842          foreach($search['forums'] as $forum)
 843          {
 844              $forum = intval($forum);
 845              if(!$searchin[$forum])
 846              {
 847                  if(is_array($add_groups))
 848                  {
 849                      $can_search = 0;
 850                      foreach($add_groups as $add_group)
 851                      {
 852                          // Check to make sure that we have sufficient permissions to search this forum
 853                          if(!is_array($fcache[$forum][$add_group]) || $fcache[$forum][$add_group]['cansearch'] == 1 || $mybb->usergroup['cansearch'] == 1)
 854                          {
 855                              $can_search = 1;
 856                          }
 857                      }
 858  
 859                      if($can_search == 0)
 860                      {
 861                          // We can't search this forum...
 862                          continue;
 863                      }
 864                  }
 865  
 866                   switch($db->type)
 867                   {
 868                       case "pgsql":
 869                          $query = $db->simple_select("forums", "DISTINCT fid", "(','||parentlist||',' LIKE ',%{$forum}%,') = true AND active != 0");
 870                           break;
 871                       case "sqlite":
 872                          $query = $db->simple_select("forums", "DISTINCT fid", "(','||parentlist||',' LIKE ',%{$forum}%,') > 0 AND active != 0");
 873                           break;
 874                       default:
 875                          $query = $db->simple_select("forums", "DISTINCT fid", "INSTR(CONCAT(',',parentlist,','),',{$forum},') > 0 AND active != 0");
 876                   }
 877  
 878                  while($sforum = $db->fetch_array($query))
 879                  {
 880                      $fidlist[] = $sforum['fid'];
 881                  }
 882              }
 883          }
 884          if(count($fidlist) == 1)
 885          {
 886              $forumin .= " AND t.fid='$forum' ";
 887              $searchin[$fid] = 1;
 888          }
 889          else
 890          {
 891              if(count($fidlist) > 1)
 892              {
 893                  $forumin = " AND t.fid IN (".implode(',', $fidlist).")";
 894              }
 895          }
 896      }
 897  
 898      $permsql = "";
 899      $onlyusfids = array();
 900  
 901      // Check group permissions if we can't view threads not started by us
 902      if($group_permissions = forum_permissions())
 903      {
 904          foreach($group_permissions as $fid => $forum_permissions)
 905          {
 906              if($forum_permissions['canonlyviewownthreads'] == 1)
 907              {
 908                  $onlyusfids[] = $fid;
 909              }
 910          }
 911      }
 912      if(!empty($onlyusfids))
 913      {
 914          $permsql .= "AND ((t.fid IN(".implode(',', $onlyusfids).") AND t.uid='{$mybb->user['uid']}') OR t.fid NOT IN(".implode(',', $onlyusfids)."))";
 915      }
 916  
 917      $unsearchforums = get_unsearchable_forums();
 918      if($unsearchforums)
 919      {
 920          $permsql .= " AND t.fid NOT IN ($unsearchforums)";
 921      }
 922      $inactiveforums = get_inactive_forums();
 923      if($inactiveforums)
 924      {
 925          $permsql .= " AND t.fid NOT IN ($inactiveforums)";
 926      }
 927  
 928      $visiblesql = $post_visiblesql = $plain_post_visiblesql = "";
 929      if(isset($search['visible']))
 930      {
 931          if($search['visible'] == 1)
 932          {
 933              $visiblesql = " AND t.visible = '1'";
 934  
 935              if($search['postthread'] == 1)
 936              {
 937                  $post_visiblesql = " AND p.visible = '1'";
 938                  $plain_post_visiblesql = " AND visible = '1'";
 939              }
 940          }
 941          else
 942          {
 943              $visiblesql = " AND t.visible != '1'";
 944  
 945              if($search['postthread'] == 1)
 946              {
 947                  $post_visiblesql = " AND p.visible != '1'";
 948                  $plain_post_visiblesql = " AND visible != '1'";
 949              }
 950          }
 951      }
 952  
 953      // Searching a specific thread?
 954      if($search['tid'])
 955      {
 956          $tidsql = " AND t.tid='".intval($search['tid'])."'";
 957      }
 958  
 959      $limitsql = '';
 960      if(intval($mybb->settings['searchhardlimit']) > 0)
 961      {
 962          $limitsql = "LIMIT ".intval($mybb->settings['searchhardlimit']);
 963      }
 964  
 965      // Searching both posts and thread titles
 966      $threads = array();
 967      $posts = array();
 968      $firstposts = array();
 969      if($search['postthread'] == 1)
 970      {
 971          // No need to search subjects when looking for results within a specific thread
 972          if(!$search['tid'])
 973          {
 974              $query = $db->query("
 975                  SELECT t.tid, t.firstpost
 976                  FROM ".TABLE_PREFIX."threads t
 977                  WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} AND t.closed NOT LIKE 'moved|%' {$subject_lookin}
 978                  {$limitsql}
 979              ");
 980              while($thread = $db->fetch_array($query))
 981              {
 982                  $threads[$thread['tid']] = $thread['tid'];
 983                  if($thread['firstpost'])
 984                  {
 985                      $posts[$thread['tid']] = $thread['firstpost'];
 986                  }
 987              }
 988          }
 989  
 990          $query = $db->query("
 991              SELECT p.pid, p.tid
 992              FROM ".TABLE_PREFIX."posts p
 993              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
 994              WHERE 1=1 {$post_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$post_usersql} {$permsql} {$tidsql} {$visiblesql} {$post_visiblesql} AND t.closed NOT LIKE 'moved|%' {$message_lookin}
 995              {$limitsql}
 996          ");
 997          while($post = $db->fetch_array($query))
 998          {
 999              $posts[$post['pid']] = $post['pid'];
1000              $threads[$post['tid']] = $post['tid'];
1001          }
1002  
1003          if(count($posts) < 1 && count($threads) < 1)
1004          {
1005              error($lang->error_nosearchresults);
1006          }
1007          $threads = implode(',', $threads);
1008          $posts = implode(',', $posts);
1009  
1010      }
1011      // Searching only thread titles
1012      else
1013      {
1014          $query = $db->query("
1015              SELECT t.tid, t.firstpost
1016              FROM ".TABLE_PREFIX."threads t
1017              WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} {$subject_lookin}
1018              {$limitsql}
1019          ");
1020          while($thread = $db->fetch_array($query))
1021          {
1022              $threads[$thread['tid']] = $thread['tid'];
1023              if($thread['firstpost'])
1024              {
1025                  $firstposts[$thread['tid']] = $thread['firstpost'];
1026              }
1027          }
1028          if(count($threads) < 1)
1029          {
1030              error($lang->error_nosearchresults);
1031          }
1032  
1033          $threads = implode(',', $threads);
1034          $firstposts = implode(',', $firstposts);
1035          if($firstposts)
1036          {
1037              $query = $db->simple_select("posts", "pid", "pid IN ($firstposts) {$plain_post_visiblesql} {$limitsql}");
1038              while($post = $db->fetch_array($query))
1039              {
1040                  $posts[$post['pid']] = $post['pid'];
1041              }
1042              $posts = implode(',', $posts);
1043          }
1044      }
1045      return array(
1046          "threads" => $threads,
1047          "posts" => $posts,
1048          "querycache" => ''
1049      );
1050  }
1051  
1052  /**
1053   * Perform a thread and post search under MySQL or MySQLi using boolean fulltext capabilities
1054   *
1055   * @param array Array of search data
1056   * @return array Array of search data with results mixed in
1057   */
1058  function perform_search_mysql_ft($search)
1059  {
1060      global $mybb, $db, $lang;
1061  
1062      $keywords = clean_keywords_ft($search['keywords']);
1063      if(!$keywords && !$search['author'])
1064      {
1065          error($lang->error_nosearchterms);
1066      }
1067  
1068      // Attempt to determine minimum word length from MySQL for fulltext searches
1069      $query = $db->query("SHOW VARIABLES LIKE 'ft_min_word_len';");
1070      $min_length = $db->fetch_field($query, 'Value');
1071      if(is_numeric($min_length))
1072      {
1073          $mybb->settings['minsearchword'] = $min_length;
1074      }
1075      // Otherwise, could not fetch - default back to MySQL fulltext default setting
1076      else
1077      {
1078          $mybb->settings['minsearchword'] = 4;
1079      }
1080  
1081      if($keywords)
1082      {
1083          $keywords_exp = explode("\"", $keywords);
1084          $inquote = false;
1085          foreach($keywords_exp as $phrase)
1086          {
1087              if(!$inquote)
1088              {
1089                  $split_words = preg_split("#\s{1,}#", $phrase, -1);
1090                  foreach($split_words as $word)
1091                  {
1092                      $word = str_replace(array("+", "-", "*"), '', $word);
1093                      if(!$word)
1094                      {
1095                          continue;
1096                      }
1097                      if(my_strlen($word) < $mybb->settings['minsearchword'])
1098                      {
1099                          $all_too_short = true;
1100                      }
1101                      else
1102                      {
1103                          $all_too_short = false;
1104                          break;
1105                      }
1106                  }
1107              }
1108              else
1109              {
1110                  $phrase = str_replace(array("+", "-", "*"), '', $phrase);
1111                  if(my_strlen($phrase) < $mybb->settings['minsearchword'])
1112                  {
1113                      $all_too_short = true;
1114                  }
1115                  else
1116                  {
1117                      $all_too_short = false;
1118                      break;
1119                  }
1120              }
1121              $inquote = !$inquote;
1122          }
1123          // Show the minimum search term error only if all search terms are too short
1124          if($all_too_short == true)
1125          {
1126              $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
1127              error($lang->error_minsearchlength);
1128          }
1129          $message_lookin = "AND MATCH(message) AGAINST('".$db->escape_string($keywords)."' IN BOOLEAN MODE)";
1130          $subject_lookin = "AND MATCH(subject) AGAINST('".$db->escape_string($keywords)."' IN BOOLEAN MODE)";
1131      }
1132      $post_usersql = '';
1133      $thread_usersql = '';
1134      if($search['author'])
1135      {
1136          $userids = array();
1137          if($search['matchusername'])
1138          {
1139              $query = $db->simple_select("users", "uid", "username='".$db->escape_string($search['author'])."'");
1140          }
1141          else
1142          {
1143              $search['author'] = my_strtolower($search['author']);
1144              $query = $db->simple_select("users", "uid", "LOWER(username) LIKE '%".$db->escape_string_like($db->escape_string($search['author']))."%'");
1145          }
1146  
1147          while($user = $db->fetch_array($query))
1148          {
1149              $userids[] = $user['uid'];
1150          }
1151  
1152          if(count($userids) < 1)
1153          {
1154              error($lang->error_nosearchresults);
1155          }
1156          else
1157          {
1158              $userids = implode(',', $userids);
1159              $post_usersql = " AND p.uid IN (".$userids.")";
1160              $thread_usersql = " AND t.uid IN (".$userids.")";
1161          }
1162      }
1163      $datecut = '';
1164      if($search['postdate'])
1165      {
1166          if($search['pddir'] == 0)
1167          {
1168              $datecut = "<=";
1169          }
1170          else
1171          {
1172              $datecut = ">=";
1173          }
1174          $now = TIME_NOW;
1175          $datelimit = $now-(86400 * $search['postdate']);
1176          $datecut .= "'$datelimit'";
1177          $post_datecut = " AND p.dateline $datecut";
1178          $thread_datecut = " AND t.dateline $datecut";
1179      }
1180  
1181      $thread_replycut = '';
1182      if($search['numreplies'] != '' && $search['findthreadst'])
1183      {
1184          if(intval($search['findthreadst']) == 1)
1185          {
1186              $thread_replycut = " AND t.replies >= '".intval($search['numreplies'])."'";
1187          }
1188          else
1189          {
1190              $thread_replycut = " AND t.replies <= '".intval($search['numreplies'])."'";
1191          }
1192      }
1193  
1194      $thread_prefixcut = '';
1195      if($search['threadprefix'] && $search['threadprefix'] != 'any')
1196      {
1197          $thread_prefixcut = " AND t.prefix='".intval($search['threadprefix'])."'";
1198      }
1199  
1200      $forumin = '';
1201      $fidlist = array();
1202      $searchin = array();
1203      if($search['forums'][0] != "all")
1204      {
1205          if(!is_array($search['forums']))
1206          {
1207              $search['forums'] = array(intval($search['forums']));
1208          }
1209          // Generate a comma separated list of all groups the user belongs to
1210          $user_groups = $mybb->user['usergroup'];
1211          if($mybb->user['additionalgroups'])
1212          {
1213              $user_groups .= ",".$mybb->user['additionalgroups'];
1214          }
1215          foreach($search['forums'] as $forum)
1216          {
1217              $forum = intval($forum);
1218              if(!$searchin[$forum])
1219              {
1220                  switch($db->type)
1221                  {
1222                      case "pgsql":
1223                      case "sqlite":
1224                          $query = $db->query("
1225                              SELECT f.fid
1226                              FROM ".TABLE_PREFIX."forums f
1227                              LEFT JOIN ".TABLE_PREFIX."forumpermissions p ON (f.fid=p.fid AND p.gid IN (".$user_groups."))
1228                              WHERE INSTR(','||parentlist||',',',$forum,') > 0 AND active!=0 AND (ISNULL(p.fid) OR p.cansearch=1)
1229                          ");
1230                          break;
1231                      default:
1232                          $query = $db->query("
1233                              SELECT f.fid
1234                              FROM ".TABLE_PREFIX."forums f
1235                              LEFT JOIN ".TABLE_PREFIX."forumpermissions p ON (f.fid=p.fid AND p.gid IN (".$user_groups."))
1236                              WHERE INSTR(CONCAT(',',parentlist,','),',$forum,') > 0 AND active!=0 AND (ISNULL(p.fid) OR p.cansearch=1)
1237                          ");
1238                  }
1239                  while($sforum = $db->fetch_array($query))
1240                  {
1241                      $fidlist[] = $sforum['fid'];
1242                  }
1243              }
1244          }
1245          if(count($fidlist) == 1)
1246          {
1247              $forumin .= " AND t.fid='$forum' ";
1248              $searchin[$fid] = 1;
1249          }
1250          else
1251          {
1252  
1253              if(count($fidlist) > 1)
1254              {
1255                  $forumin = " AND t.fid IN (".implode(',', $fidlist).")";
1256              }
1257          }
1258      }
1259      $permsql = "";
1260      $onlyusfids = array();
1261  
1262      // Check group permissions if we can't view threads not started by us
1263      $group_permissions = forum_permissions();
1264      foreach($group_permissions as $fid => $forum_permissions)
1265      {
1266          if($forum_permissions['canonlyviewownthreads'] == 1)
1267          {
1268              $onlyusfids[] = $fid;
1269          }
1270      }
1271      if(!empty($onlyusfids))
1272      {
1273          $permsql .= "AND ((t.fid IN(".implode(',', $onlyusfids).") AND t.uid='{$mybb->user['uid']}') OR t.fid NOT IN(".implode(',', $onlyusfids)."))";
1274      }
1275  
1276      $unsearchforums = get_unsearchable_forums();
1277      if($unsearchforums)
1278      {
1279          $permsql .= " AND t.fid NOT IN ($unsearchforums)";
1280      }
1281      $inactiveforums = get_inactive_forums();
1282      if($inactiveforums)
1283      {
1284          $permsql .= " AND t.fid NOT IN ($inactiveforums)";
1285      }
1286  
1287      $visiblesql = $post_visiblesql = $plain_post_visiblesql = "";
1288      if(isset($search['visible']))
1289      {
1290          if($search['visible'] == 1)
1291          {
1292              $visiblesql = " AND t.visible = '1'";
1293  
1294              if($search['postthread'] == 1)
1295              {
1296                  $post_visiblesql = " AND p.visible = '1'";
1297                  $plain_post_visiblesql = " AND visible = '1'";
1298              }
1299          }
1300          else
1301          {
1302              $visiblesql = " AND t.visible != '1'";
1303  
1304              if($search['postthread'] == 1)
1305              {
1306                  $post_visiblesql = " AND p.visible != '1'";
1307                  $plain_post_visiblesql = " AND visible != '1'";
1308              }
1309          }
1310      }
1311  
1312      // Searching a specific thread?
1313      if($search['tid'])
1314      {
1315          $tidsql = " AND t.tid='".intval($search['tid'])."'";
1316      }
1317  
1318      $limitsql = '';
1319      if(intval($mybb->settings['searchhardlimit']) > 0)
1320      {
1321          $limitsql = "LIMIT ".intval($mybb->settings['searchhardlimit']);
1322      }
1323  
1324      // Searching both posts and thread titles
1325      $threads = array();
1326      $posts = array();
1327      $firstposts = array();
1328      if($search['postthread'] == 1)
1329      {
1330          // No need to search subjects when looking for results within a specific thread
1331          if(!$search['tid'])
1332          {
1333              $query = $db->query("
1334                  SELECT t.tid, t.firstpost
1335                  FROM ".TABLE_PREFIX."threads t
1336                  WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} AND t.closed NOT LIKE 'moved|%' {$subject_lookin}
1337                  {$limitsql}
1338              ");
1339              while($thread = $db->fetch_array($query))
1340              {
1341                  $threads[$thread['tid']] = $thread['tid'];
1342                  if($thread['firstpost'])
1343                  {
1344                      $posts[$thread['tid']] = $thread['firstpost'];
1345                  }
1346              }
1347          }
1348  
1349          $query = $db->query("
1350              SELECT p.pid, p.tid
1351              FROM ".TABLE_PREFIX."posts p
1352              LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
1353              WHERE 1=1 {$post_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$post_usersql} {$permsql} {$tidsql} {$post_visiblesql} {$visiblesql} AND t.closed NOT LIKE 'moved|%' {$message_lookin}
1354              {$limitsql}
1355          ");
1356          while($post = $db->fetch_array($query))
1357          {
1358              $posts[$post['pid']] = $post['pid'];
1359              $threads[$post['tid']] = $post['tid'];
1360          }
1361          if(count($posts) < 1 && count($threads) < 1)
1362          {
1363              error($lang->error_nosearchresults);
1364          }
1365          $threads = implode(',', $threads);
1366          $posts = implode(',', $posts);
1367  
1368      }
1369      // Searching only thread titles
1370      else
1371      {
1372          $query = $db->query("
1373              SELECT t.tid, t.firstpost
1374              FROM ".TABLE_PREFIX."threads t
1375              WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} {$subject_lookin}
1376              {$limitsql}
1377          ");
1378          while($thread = $db->fetch_array($query))
1379          {
1380              $threads[$thread['tid']] = $thread['tid'];
1381              if($thread['firstpost'])
1382              {
1383                  $firstposts[$thread['tid']] = $thread['firstpost'];
1384              }
1385          }
1386          if(count($threads) < 1)
1387          {
1388              error($lang->error_nosearchresults);
1389          }
1390  
1391          $threads = implode(',', $threads);
1392          $firstposts = implode(',', $firstposts);
1393          if($firstposts)
1394          {
1395              $query = $db->simple_select("posts", "pid", "pid IN ($firstposts) {$plain_post_visiblesql} {$limitsql}");
1396              while($post = $db->fetch_array($query))
1397              {
1398                  $posts[$post['pid']] = $post['pid'];
1399              }
1400              $posts = implode(',', $posts);
1401          }
1402      }
1403      return array(
1404          "threads" => $threads,
1405          "posts" => $posts,
1406          "querycache" => ''
1407      );
1408  }
1409  ?>


Generated: Tue Oct 8 19:19:50 2013 Cross-referenced by PHPXref 0.7.1