[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-forums/bbpress/bb-includes/ -> class.bb-query.php (source)

   1  <?php
   2  
   3  class BB_Query {
   4      var $type;
   5      var $query;
   6      var $query_id;
   7  
   8      var $query_vars = array();
   9      var $not_set = array();
  10      var $request;
  11      var $match_query = false;
  12  
  13      var $results;
  14      var $errors;
  15      var $count = 0;
  16      var $found_rows = false;
  17  
  18      // Can optionally pass unique id string to help out filters
  19  	function __construct( $type = 'topic', $query = '', $id = '' ) {
  20          $this->init( $type, $query, $id );
  21  
  22          if ( !empty($this->query) )
  23              $this->query();
  24      }
  25  
  26  	function BB_Query( $type = 'topic', $query = '', $id = '' ) {
  27          $this->__construct( $type, $query, $id );
  28      }
  29  
  30  	function init( $type = null, $query = null, $id = null ) {
  31          if ( !is_null($type) || !isset($this->type) )
  32              $this->type = is_null($type) ? 'topic' : $type;
  33          if ( !is_null($query) || !isset($this->query) )
  34              $this->query = $query;
  35          if ( !is_null($id) || !isset($this->query_id) )
  36              $this->query_id = $id;
  37  
  38          $this->query_vars = array();
  39          $this->not_set = array();
  40          unset($this->request);
  41          $this->match_query = false;
  42  
  43          unset($this->results, $this->errors);
  44          $this->count = 0;
  45          $this->found_rows = false;
  46      }
  47  
  48      function &query() {
  49          global $bbdb;
  50  
  51          if ( $args = func_get_args() )
  52              call_user_func_array( array(&$this, 'init'), $args );
  53  
  54          if ( !$this->generate_query() )
  55              return;
  56  
  57          do_action_ref_array( 'bb_query', array(&$this) );
  58  
  59          $key = md5( $this->request );
  60          if ( false === $cached_ids = wp_cache_get( $key, 'bb_query' ) ) {
  61              if ( 'post' == $this->type ) {
  62                  $this->results = bb_cache_posts( $this->request, $this->query_vars['post_id_only'] ); // This always appends meta
  63                  $_the_id = 'post_id';
  64                  $this->query_vars['append_meta'] = false;
  65              } else {
  66                  $this->results = $bbdb->get_results( $this->request );
  67                  $_the_id = 'topic_id';
  68              }
  69              $cached_ids = array();
  70              if ( is_array($this->results) )
  71                  foreach ( $this->results as $object )
  72                      $cached_ids[] = $object->$_the_id;
  73              wp_cache_set( $key, $cached_ids, 'bb_query' );
  74          } else {
  75              if ( 'post' == $this->type ) {
  76                  $_query_ids = array();
  77                  $_cached_posts = array();
  78                  foreach ( $cached_ids as $_cached_id ) {
  79                      if ( false !== $_post = wp_cache_get( $_cached_id, 'bb_post' ) ) {
  80                          $_cached_posts[$_post->post_id] = $_post;
  81                      } else {
  82                          $_query_ids[] = $_cached_id;
  83                      }
  84                  }
  85                  if ( count( $_query_ids ) ) {
  86                      $_query_ids = join( ',', array_map( 'intval', $_query_ids ) );
  87                      $results = $bbdb->get_results( "SELECT * FROM $bbdb->posts WHERE post_id IN($_query_ids)" );
  88                      $results = array_merge( $results, $_cached_posts );
  89                  } else {
  90                      $results = $_cached_posts;
  91                  }
  92                  $_the_id = 'post_id';
  93              } else {
  94                  $_query_ids = array();
  95                  $_cached_topics = array();
  96                  foreach ( $cached_ids as $_cached_id ) {
  97                      if ( false !== $_topic = wp_cache_get( $_cached_id, 'bb_topic' ) ) {
  98                          $_cached_topics[$_topic->topic_id] = $_topic;
  99                      } else {
 100                          $_query_ids[] = $_cached_id;
 101                      }
 102                  }
 103                  if ( count( $_query_ids ) ) {
 104                      $_query_ids = join( ',', array_map( 'intval', $_query_ids ) );
 105                      $results = $bbdb->get_results( "SELECT * FROM $bbdb->topics WHERE topic_id IN($_query_ids)" );
 106                      $results = array_merge( $results, $_cached_topics );
 107                  } else {
 108                      $results = $_cached_topics;
 109                  }
 110                  $_the_id = 'topic_id';
 111              }
 112  
 113              $this->results = array();
 114              $trans = array();
 115  
 116              foreach ( $results as $object )
 117                  $trans[$object->$_the_id] = $object;
 118              foreach ( $cached_ids as $cached_id )
 119                  $this->results[] = $trans[$cached_id];
 120          }
 121  
 122          $this->count = count( $this->results );
 123  
 124          if ( false === $this->found_rows && $this->query_vars['count'] ) // handles FOUND_ROWS() or COUNT(*)
 125              $this->found_rows = bb_count_last_query( $this->request );
 126          if ( 'post' == $this->type ) {
 127              if ( $this->query_vars['append_meta'] )
 128                  $this->results = bb_append_meta( $this->results, 'post' );
 129              if ( $this->query_vars['cache_users'] )
 130                  bb_post_author_cache( $this->results );
 131              if ( $this->query_vars['cache_topics'] )
 132                  bb_cache_post_topics( $this->results );
 133          } else {
 134              if ( $this->query_vars['append_meta'] )
 135                  $this->results = bb_append_meta( $this->results, 'topic' );
 136          }
 137  
 138          return $this->results;
 139      }
 140  
 141  	function generate_query() {
 142          if ( $args = func_get_args() )
 143              call_user_func_array( array(&$this, 'init'), $args );
 144  
 145          $this->parse_query();
 146  
 147          // Allow filter to abort query
 148          if ( false === $this->query_vars )
 149              return false;
 150  
 151          if ( 'post' == $this->type )
 152              $this->generate_post_sql();
 153          else
 154              $this->generate_topic_sql();
 155  
 156          return $this->request;
 157      }
 158  
 159      // $defaults = vars to use if not set in GET, POST or allowed
 160      // $allowed = array( key_name => value, key_name, key_name, key_name => value );
 161      //     key_name => value pairs override anything from defaults, GET, POST
 162      //    Lone key_names are a whitelist.  Only those can be set by defaults, GET, POST
 163      //    If there are no lone key_names, allow everything but still override with key_name => value pairs
 164      //    Ex: $allowed = array( 'topic_status' => 0, 'post_status' => 0, 'topic_author', 'started' );
 165      //        Will only take topic_author and started values from defaults, GET, POST and will query with topic_status = 0 and post_status = 0
 166      function &query_from_env( $type = 'topic', $defaults = null, $allowed = null, $id = '' ) {
 167          $this->init_from_env( $type, $defaults, $allowed, $id );
 168          return $this->query();
 169      }
 170  
 171  	function init_from_env( $type = 'topic', $defaults = null, $allowed = null, $id = '' ) {
 172          $vars = $this->fill_query_vars( array() );
 173  
 174          $defaults  = wp_parse_args($defaults);
 175          $get_vars  = stripslashes_deep( $_GET );
 176          $post_vars = stripslashes_deep( $_POST );
 177          $allowed   = wp_parse_args($allowed);
 178  
 179          $_allowed = array();
 180          foreach ( array_keys($allowed) as $k ) {
 181              if ( is_numeric($k) ) {
 182                  $_allowed[] = $allowed[$k];
 183                  unset($allowed[$k]);
 184              } elseif ( !isset($$k) ) {
 185                  $$k = $allowed[$k];
 186              }
 187          }
 188  
 189          extract($post_vars, EXTR_SKIP);
 190          extract($get_vars, EXTR_SKIP);
 191          extract($defaults, EXTR_SKIP);
 192  
 193          $vars = $_allowed ? compact($_allowed, array_keys($allowed)) : compact(array_keys($vars));
 194  
 195          $this->init( $type, $vars, $id );
 196      }
 197  
 198  	function fill_query_vars( $array ) {
 199          // Should use 0, '' for empty values
 200          // Function should return false iff not set
 201  
 202          // parameters commented out are handled farther down
 203  
 204          $ints = array(
 205  //            'page',         // Defaults to global or number in URI
 206  //            'per_page',     // Defaults to page_topics
 207              'tag_id',     // one tag ID
 208              'favorites', // one user ID,
 209              'offset',     // first item to query
 210              'number'     // number of items to retrieve
 211          );
 212  
 213          $parse_ints = array(
 214              // Both
 215              'post_id',
 216              'topic_id',
 217              'forum_id',
 218  
 219              // Topics
 220              'topic_author_id',
 221              'post_count',
 222              'tag_count',
 223  
 224              // Posts
 225              'post_author_id',
 226              'position'
 227          );
 228  
 229          $dates = array(
 230              'started',    // topic
 231              'updated',    // topic
 232              'posted'    // post
 233          );
 234  
 235          $others = array(
 236              // Both
 237              'topic',    // one topic name
 238              'forum',    // one forum name
 239              'tag',        // one tag name
 240  
 241              // Topics
 242              'topic_author',    // one username
 243              'topic_status',    // *normal, deleted, all, parse_int ( and - )
 244              'open',            // *all, yes = open, no = closed, parse_int ( and - )
 245              'sticky',        // *all, no = normal, forum, super = front, parse_int ( and - )
 246              'meta_key',        // one meta_key ( and - )
 247              'meta_value',    // range
 248              'topic_title',    // LIKE search.  Understands "doublequoted strings"
 249              'search',        // generic search: topic_title OR post_text
 250                              // Can ONLY be used in a topic query
 251                              // Returns additional search_score and (concatenated) post_text columns
 252  
 253              // Posts
 254              'post_author',    // one username
 255              'post_status',    // *noraml, deleted, all, parse_int ( and - )
 256              'post_text',    // FULLTEXT search
 257                              // Returns additional search_score column (and (concatenated) post_text column if topic query)
 258              'poster_ip',    // one IPv4 address
 259  
 260              // SQL
 261              'index_hint',    // A full index hint using valid index hint syntax, can be multiple hints an array
 262              'order_by',        // fieldname
 263              'order',        // *DESC, ASC
 264              'count',        // *false = none, true = COUNT(*), found_rows = FOUND_ROWS()
 265              '_join_type',    // not implemented: For benchmarking only.  Will disappear. join (1 query), in (2 queries)
 266  
 267              // Utility
 268  //            'append_meta',    // *true, false: topics only
 269  //            'cache_users',    // *true, false
 270  //            'cache_topics,    // *true, false: posts only
 271  //            'post_id_only', // true, *false: this query is only returning post IDs
 272              'cache_posts'     // not implemented: none, first, last
 273          );
 274  
 275          foreach ( $ints as $key )
 276              if ( ( false === $array[$key] = isset($array[$key]) ? (int) $array[$key] : false ) && isset($this) )
 277                  $this->not_set[] = $key;
 278  
 279          foreach ( $parse_ints as $key )
 280              if ( ( false === $array[$key] = isset($array[$key]) ? preg_replace( '/[^<=>0-9,-]/', '', $array[$key] ) : false ) && isset($this) )
 281                  $this->not_set[] = $key;
 282  
 283          foreach ( $dates as $key )
 284              if ( ( false === $array[$key] = isset($array[$key]) ? preg_replace( '/[^<>0-9-]/', '', $array[$key] ) : false ) && isset($this) )
 285                  $this->not_set[] = $key;
 286  
 287          foreach ( $others as $key ) {
 288              if ( !isset($array[$key]) )
 289                  $array[$key] = false;
 290              if ( isset($this) && false === $array[$key] )
 291                  $this->not_set[] = $key;
 292          }
 293  
 294          // Both
 295          if ( isset($array['page']) )
 296              $array['page'] = (int) $array['page'];
 297          elseif ( isset($GLOBALS['page']) )
 298              $array['page'] = (int) $GLOBALS['page'];
 299          else
 300              $array['page'] = bb_get_uri_page();
 301  
 302          if ( $array['page'] < 1 )
 303              $array['page'] = 1;
 304  
 305          $array['per_page'] = isset($array['per_page']) ? (int) $array['per_page'] : 0;
 306          if ( $array['per_page'] < -1 )
 307              $array['per_page'] = 1;
 308  
 309          // Posts
 310          if ( ( !$array['poster_ip'] = isset($array['poster_ip']) ? preg_replace("@[^0-9a-f:.]@i", '', $array['poster_ip']) : false ) && isset($this) ) {
 311              $this->not_set[] = 'poster_ip';
 312              $array['poster_ip'] = false;
 313          }
 314  
 315          // Utility
 316          $array['append_meta']  = isset($array['append_meta'])  ? (int) (bool) $array['append_meta']  : 1;
 317          $array['cache_users']  = isset($array['cache_users'])  ? (int) (bool) $array['cache_users']  : 1;
 318          $array['cache_topics'] = isset($array['cache_topics']) ? (int) (bool) $array['cache_topics'] : 1;
 319          $array['post_id_only'] = isset($array['post_id_only']) ? (int) (bool) $array['post_id_only'] : 1;
 320  
 321          // Only one FULLTEXT search per query please
 322          if ( $array['search'] )
 323              $array['post_text'] = false;
 324  
 325          return $array;
 326      }
 327  
 328      // Parse a query string and set query flag booleans.
 329  	function parse_query() {
 330          if ( $args = func_get_args() )
 331              call_user_func_array( array(&$this, 'init'), $args );
 332  
 333          if ( is_array($this->query) )
 334              $this->query_vars = $this->query;
 335          else
 336              wp_parse_str($this->query, $this->query_vars);
 337  
 338          do_action_ref_array('bb_parse_query', array(&$this));
 339  
 340          if ( false === $this->query_vars )
 341              return;
 342  
 343          $this->query_vars = $this->fill_query_vars($this->query_vars);
 344      }
 345  
 346  	function get($query_var) {
 347          return isset($this->query_vars[$query_var]) ? $this->query_vars[$query_var] : null;
 348      }
 349  
 350  	function set($query_var, $value) {
 351          $this->query_vars[$query_var] = $value;
 352      }
 353  
 354  	function generate_topic_sql( $_part_of_post_query = false ) {
 355          global $bbdb;
 356  
 357          $q =& $this->query_vars;
 358          $distinct = '';
 359          $sql_calc_found_rows = 'found_rows' === $q['count'] ? 'SQL_CALC_FOUND_ROWS' : ''; // unfiltered
 360          $fields = 't.*';
 361          $index_hint = '';
 362          $join = '';
 363          $where = '';
 364          $group_by = '';
 365          $having = '';
 366          $order_by = '';
 367  
 368          $post_where = '';
 369          $post_queries = array('post_author_id', 'post_author', 'posted', 'post_status', 'position', 'post_text', 'poster_ip');
 370  
 371          if ( !$_part_of_post_query && ( $q['search'] || array_diff($post_queries, $this->not_set) ) ) :
 372              $join .= " JOIN $bbdb->posts as p ON ( t.topic_id = p.topic_id )";
 373              $post_where = $this->generate_post_sql( true );
 374              if ( $q['search'] ) {
 375                  $post_where .= ' AND ( ';
 376                  $post_where .= $this->generate_topic_title_sql( $q['search'] );
 377                  $post_where .= ' OR ';
 378                  $post_where .= $this->generate_post_text_sql( $q['search'] );
 379                  $post_where .= ' )';
 380              }
 381  
 382              $group_by = 't.topic_id';
 383  
 384              $fields .= ", MIN(p.post_id) as post_id";
 385  
 386              if ( $bbdb->has_cap( 'GROUP_CONCAT', $bbdb->posts ) )
 387                  $fields .= ", GROUP_CONCAT(p.post_text SEPARATOR ' ') AS post_text";
 388              else
 389                  $fields .= ", p.post_text";
 390  
 391              if ( $this->match_query ) {
 392                  $fields .= ", AVG($this->match_query) AS search_score";
 393                  if ( !$q['order_by'] )
 394                      $q['order_by'] = 'search_score';
 395              } elseif ( $q['search'] || $q['post_text'] ) {
 396                  $fields .= ", 0 AS search_score";
 397              }
 398          endif;
 399  
 400          if ( !$_part_of_post_query ) :
 401              if ( $q['post_id'] ) :
 402                  $post_topics = $post_topics_no = array();
 403                  $op = substr($q['post_id'], 0, 1);
 404                  if ( in_array($op, array('>','<')) ) :
 405                      $post_topics = $bbdb->get_col( "SELECT DISTINCT topic_id FROM $bbdb->posts WHERE post_id $op '" . (int) substr($q['post_id'], 1) . "'" );
 406                  else :
 407                      $posts = explode(',', $q['post_id']);
 408                      $get_posts = array();
 409                      foreach ( $posts as $post_id ) {
 410                          $post_id = (int) $post_id;
 411                          $_post_id = abs($post_id);
 412                          $get_posts[] = $_post_id;
 413                      }
 414                      bb_cache_posts( $get_posts );
 415  
 416                      foreach ( $posts as $post_id ) :
 417                          $post = bb_get_post( abs($post_id) );
 418                          if ( $post_id < 0 )
 419                              $post_topics_no[] = $post->topic_id;
 420                          else
 421                              $post_topics[] = $post->topic_id;
 422                      endforeach;
 423                  endif;
 424                  if ( $post_topics )
 425                      $where .= " AND t.topic_id IN (" . join(',', $post_topics) . ")";
 426                  if ( $post_topics_no )
 427                      $where .= " AND t.topic_id NOT IN (" . join(',', $post_topics_no) . ")";
 428              endif;
 429  
 430              if ( $q['topic_id'] ) :
 431                  $where .= $this->parse_value( 't.topic_id', $q['topic_id'] );
 432              elseif ( $q['topic'] ) :
 433                  $q['topic'] = bb_slug_sanitize( $q['topic'] );
 434                  $where .= " AND t.topic_slug = '$q[topic]'";
 435              endif;
 436  
 437              if ( $q['forum_id'] ) :
 438                  $where .= $this->parse_value( 't.forum_id', $q['forum_id'] );
 439              elseif ( $q['forum'] ) :
 440                  if ( !$q['forum_id'] = bb_get_id_from_slug( 'forum', $q['forum'] ) )
 441                      $this->error( 'query_var:forum', 'No forum by that name' );
 442                  $where .= " AND t.forum_id = $q[forum_id]";
 443              endif;
 444  
 445              if ( $q['tag'] && !is_int($q['tag_id']) )
 446                  $q['tag_id'] = (int) bb_get_tag_id( $q['tag'] );
 447  
 448              if ( is_numeric($q['tag_id']) ) :
 449                  $join .= " JOIN `$bbdb->term_relationships` AS tr ON ( t.`topic_id` = tr.`object_id` AND tr.`term_taxonomy_id` = $q[tag_id] )";
 450              endif;
 451  
 452              if ( is_numeric($q['favorites']) && $f_user = bb_get_user( $q['favorites'] ) )
 453                  $where .= $this->parse_value( 't.topic_id', $f_user->favorites );
 454          endif; // !_part_of_post_query
 455  
 456          if ( $q['topic_title'] )
 457              $where .= ' AND ' . $this->generate_topic_title_sql( $q['topic_title'] );
 458  
 459          if ( $q['started'] )
 460              $where .= $this->date( 't.topic_start_time', $q['started'] );
 461  
 462          if ( $q['updated'] )
 463              $where .= $this->date( 't.topic_time', $q['updated'] );
 464  
 465          if ( $q['topic_author_id'] ) :
 466              $where .= $this->parse_value( 't.topic_poster', $q['topic_author_id'] );
 467          elseif ( $q['topic_author'] ) :
 468              $user = bb_get_user( $q['topic_author'], array( 'by' => 'login' ) );
 469              if ( !$q['topic_author_id'] = (int) $user->ID )
 470                  $this->error( 'query_var:user', 'No user by that name' );
 471              $where .= " AND t.topic_poster = $q[topic_author_id]";
 472          endif;
 473  
 474          if ( !$q['topic_status'] ) :
 475              $where .= " AND t.topic_status = '0'";
 476          elseif ( false === strpos($q['topic_status'], 'all') ) :
 477              $stati = array( 'normal' => 0, 'deleted' => 1 );
 478              $q['topic_status'] = str_replace(array_keys($stati), array_values($stati), $q['topic_status']);
 479              $where .= $this->parse_value( 't.topic_status', $q['topic_status'] );
 480          endif;
 481  
 482          if ( false !== $q['open'] && false === strpos($q['open'], 'all') ) :
 483              $stati = array( 'no' => 0, 'closed' => 0, 'yes' => 1, 'open' => 1 );
 484              $q['open'] = str_replace(array_keys($stati), array_values($stati), $q['open']);
 485              $where .= $this->parse_value( 't.topic_open', $q['open'] );
 486          endif;
 487  
 488          if ( false !== $q['sticky'] && false === strpos($q['sticky'], 'all') ) :
 489              $stickies = array( 'no' => 0, 'normal' => 0, 'forum' => 1, 'super' => 2, 'front' => 2, 'sticky' => '-0' );
 490              $q['sticky'] = str_replace(array_keys($stickies), array_values($stickies), $q['sticky']);
 491              $where .= $this->parse_value( 't.topic_sticky', $q['sticky'] );
 492          endif;
 493  
 494          if ( false !== $q['post_count'] )
 495              $where .= $this->parse_value( 't.topic_posts', $q['post_count'] );
 496  
 497          if ( false !== $q['tag_count'] )
 498              $where .= $this->parse_value( 't.tag_count', $q['tag_count'] );
 499  
 500          if ( $q['meta_key'] && $q['meta_key'] = preg_replace('|[^a-z0-9_-]|i', '', $q['meta_key']) ) :
 501              if ( '-' == substr($q['meta_key'], 0, 1) ) :
 502                  $join  .= " LEFT JOIN $bbdb->meta AS tm ON ( tm.object_type = 'bb_topic' AND t.topic_id = tm.object_id AND tm.meta_key = '" . substr( $q['meta_key'], 1 ) . "' )";
 503                  $where .= " AND tm.meta_key IS NULL";
 504              else :
 505                  $join  .= " JOIN $bbdb->meta AS tm ON ( tm.object_type = 'bb_topic' AND t.topic_id = tm.object_id AND tm.meta_key = '$q[meta_key]' )";
 506  
 507                  if ( $q['meta_value'] ) :
 508                      $q['meta_value'] = maybe_serialize( $q['meta_value'] );
 509                      if ( strpos( $q['meta_value'], 'NULL' ) !== false )
 510                          $join = ' LEFT' . $join;
 511                      $where .= $this->parse_value( 'tm.meta_value', $q['meta_value'] );
 512                  endif;
 513              endif;
 514          endif;
 515  
 516          // Just getting topic part for inclusion in post query
 517          if ( $_part_of_post_query )
 518              return $where;
 519  
 520          $where .= $post_where;
 521  
 522          if ( $where ) // Get rid of initial " AND " (this is pre-filters)
 523              $where = substr($where, 5);
 524  
 525          if ( $q['index_hint'] )
 526              $index_hint = $q['index_hint'];
 527  
 528          if ( $q['order_by'] )
 529              $order_by = $q['order_by'];
 530          else
 531              $order_by = 't.topic_time';
 532  
 533          $bits = compact( array('distinct', 'sql_calc_found_rows', 'fields', 'index_hint', 'join', 'where', 'group_by', 'having', 'order_by') );
 534          $this->request = $this->_filter_sql( $bits, "$bbdb->topics AS t" );
 535          return $this->request;
 536      }
 537  
 538  	function generate_post_sql( $_part_of_topic_query = false ) {
 539          global $bbdb;
 540  
 541          $q =& $this->query_vars;
 542          $distinct = '';
 543          $sql_calc_found_rows = 'found_rows' === $q['count'] ? 'SQL_CALC_FOUND_ROWS' : ''; // unfiltered
 544          $fields = 'p.*';
 545          $index_hint = '';
 546          $join = '';
 547          $where = '';
 548          $group_by = '';
 549          $having = '';
 550          $order_by = '';
 551  
 552          $topic_where = '';
 553          $topic_queries = array( 'topic_author_id', 'topic_author', 'topic_status', 'post_count', 'tag_count', 'started', 'updated', 'open', 'sticky', 'meta_key', 'meta_value', 'topic_title' );
 554          if ( !$_part_of_topic_query && array_diff($topic_queries, $this->not_set) ) :
 555              $join .= " JOIN $bbdb->topics as t ON ( t.topic_id = p.topic_id )";
 556              $topic_where = $this->generate_topic_sql( true );
 557          endif;
 558          
 559          if ( !$_part_of_topic_query ) :
 560              if ( $q['post_id'] )
 561                  $where .= $this->parse_value( 'p.post_id', $q['post_id'] );
 562  
 563              if ( $q['topic_id'] ) :
 564                  $where .= $this->parse_value( 'p.topic_id', $q['topic_id'] );
 565              elseif ( $q['topic'] ) :
 566                  if ( !$q['topic_id'] = bb_get_id_from_slug( 'topic', $q['topic'] ) )
 567                      $this->error( 'query_var:topic', 'No topic by that name' );
 568                  $where .= " AND p.topic_id = " . $q['topic_id'];
 569              endif;
 570  
 571              if ( $q['forum_id'] ) :
 572                  $where .= $this->parse_value( 'p.forum_id', $q['forum_id'] );
 573              elseif ( $q['forum'] ) :
 574                  if ( !$q['forum_id'] = bb_get_id_from_slug( 'forum', $q['forum'] ) )
 575                      $this->error( 'query_var:forum', 'No forum by that name' );
 576                  $where .= " AND p.forum_id = " . $q['forum_id'];
 577              endif;
 578  
 579              if ( $q['tag'] && !is_int($q['tag_id']) )
 580                  $q['tag_id'] = (int) bb_get_tag_id( $q['tag'] );
 581  
 582              if ( is_numeric($q['tag_id']) ) :
 583                  $join .= " JOIN `$bbdb->term_relationships` AS tr ON ( p.`topic_id` = tr.`object_id` AND tr.`term_taxonomy_id` = $q[tag_id] )";
 584              endif;
 585  
 586              if ( is_numeric($q['favorites']) && $f_user = bb_get_user( $q['favorites'] ) )
 587                  $where .= $this->parse_value( 'p.topic_id', $f_user->favorites );
 588          endif; // !_part_of_topic_query
 589  
 590          if ( $q['post_text'] ) :
 591              $where  .= ' AND ' . $this->generate_post_text_sql( $q['post_text'] );
 592              if ( $this->match_query ) {
 593                  $fields .= ", $this->match_query AS search_score";
 594                  if ( !$q['order_by'] )
 595                      $q['order_by'] = 'search_score';
 596              } else {
 597                  $fields .= ', 0 AS search_score';
 598              }
 599          endif;
 600  
 601          if ( $q['posted'] )
 602              $where .= $this->date( 'p.post_time', $q['posted'] );
 603  
 604          if ( $q['post_author_id'] ) :
 605              $where .= $this->parse_value( 'p.poster_id', $q['post_author_id'] );
 606          elseif ( $q['post_author'] ) :
 607              $user = bb_get_user( $q['post_author'], array( 'by' => 'login' ) );
 608              if ( !$q['post_author_id'] = (int) $user->ID )
 609                  $this->error( 'query_var:user', 'No user by that name' );
 610              $where .= " AND p.poster_id = $q[post_author_id]";
 611          endif;
 612  
 613          if ( !$q['post_status'] ) :
 614              $where .= " AND p.post_status = '0'";
 615          elseif ( false === strpos($q['post_status'], 'all') ) :
 616              $stati = array( 'normal' => 0, 'deleted' => 1 );
 617              $q['post_status'] = str_replace(array_keys($stati), array_values($stati), $q['post_status']);
 618              $where .= $this->parse_value( 'p.post_status', $q['post_status'] );
 619          endif;
 620  
 621          if ( false !== $q['position'] )
 622              $where .= $this->parse_value( 'p.post_position', $q['position'] );
 623  
 624          if ( false !== $q['poster_ip'] )
 625              $where .= " AND poster_ip = '" . $q['poster_ip'] . "'";
 626  
 627          // Just getting post part for inclusion in topic query
 628          if ( $_part_of_topic_query )
 629              return $where;
 630  
 631          $where .= $topic_where;
 632  
 633          if ( $where ) // Get rid of initial " AND " (this is pre-filters)
 634              $where = substr($where, 5);
 635  
 636          if ( $q['index_hint'] )
 637              $index_hint = $q['index_hint'];
 638  
 639          if ( $q['order_by'] )
 640              $order_by = $q['order_by'];
 641          else
 642              $order_by = 'p.post_time';
 643  
 644          $bits = compact( array('distinct', 'sql_calc_found_rows', 'fields', 'index_hint', 'join', 'where', 'group_by', 'having', 'order_by') );
 645          $this->request = $this->_filter_sql( $bits, "$bbdb->posts AS p" );
 646  
 647          return $this->request;
 648      }
 649  
 650  	function generate_topic_title_sql( $string ) {
 651          global $bbdb;
 652          $string = trim($string);
 653  
 654          if ( !preg_match_all('/".*?("|$)|((?<=[\s",+])|^)[^\s",+]+/', $string, $matches) ) {
 655              $string = $bbdb->escape($string);
 656              return "(t.topic_title LIKE '%$string%')";
 657          }
 658  
 659          $where = '';
 660  
 661          foreach ( $matches[0] as $match ) {
 662              $term = trim($match, "\"\n\r ");
 663              $term = $bbdb->escape($term);
 664              $where .= " AND t.topic_title LIKE '%$term%'";
 665          }
 666  
 667          if ( count($matches[0]) > 1 && $string != $matches[0][0] ) {
 668              $string = $bbdb->escape($string);
 669              $where .= " OR t.topic_title LIKE '%$string%'";
 670          }
 671  
 672          return '(' . substr($where, 5) . ')';
 673      }
 674  
 675  	function generate_post_text_sql( $string ) {
 676          global $bbdb;
 677          $string = trim($string);
 678          $_string = $bbdb->escape( $string );
 679          if ( strlen($string) < 5 )
 680              return "p.post_text LIKE '%$_string%'";
 681  
 682          return $this->match_query = "MATCH(p.post_text) AGAINST('$_string')";
 683      }
 684  
 685  	function _filter_sql( $bits, $from ) {
 686          global $bbdb;
 687  
 688          $q =& $this->query_vars;
 689  
 690          // MySQL 5.1 allows multiple index hints per query - earlier versions only get the first hint
 691          if ( $bits['index_hint'] ) {
 692              if ( !is_array( $bits['index_hint'] ) ) {
 693                  $bits['index_hint'] = array( (string) $bits['index_hint'] );
 694              }
 695              if ( $bbdb->has_cap( 'index_hint_for_any' ) ) {
 696                  // 5.1 <= MySQL
 697                  $_regex = '/\s*(USE|IGNORE|FORCE)\s+(INDEX|KEY)\s+(FOR\s+(JOIN|ORDER\s+BY|GROUP\s+BY)\s+)?\(\s*`?[a-z0-9_]+`?(\s*,\s*`?[a-z0-9_]+`?)*\s*\)\s*/i';
 698              } elseif ( $bbdb->has_cap( 'index_hint_for_join' ) ) {
 699                  // 5.0 <= MySQL < 5.1
 700                  $_regex = '/\s*(USE|IGNORE|FORCE)\s+(INDEX|KEY)\s+(FOR\s+JOIN\s+)?\(\s*`?[a-z0-9_]+`?(\s*,\s*`?[a-z0-9_]+`?)*\s*\)\s*/i';
 701              } else {
 702                  // MySQL < 5.0
 703                  $_regex = '/\s*(USE|IGNORE|FORCE)\s+(INDEX|KEY)\s+\(\s*`?[a-z0-9_]+`?(\s*,\s*`?[a-z0-9_]+`?)*\s*\)\s*/i';
 704              }
 705              $_index_hint = array();
 706              foreach ( $bits['index_hint'] as $_hint ) {
 707                  if ( preg_match( $_regex, $_hint ) ) {
 708                      $_index_hint[] = trim( $_hint );
 709                  }
 710              }
 711              unset( $_regex, $_hint );
 712              if ( $bbdb->has_cap( 'index_hint_lists' ) ) {
 713                  // 5.1 <= MySQL
 714                  $bits['index_hint'] = join( ' ', $_index_hint );
 715              } else {
 716                  // MySQL < 5.1
 717                  $bits['index_hint'] = isset( $_index_hint[0] ) ? $_index_hint[0] : '';
 718              }
 719              unset( $_index_hint );
 720          }
 721  
 722          $q['order'] = strtoupper($q['order']);
 723          if ( $q['order'] && in_array($q['order'], array('ASC', 'DESC')) )
 724              $bits['order_by'] .= " $q[order]";
 725          else
 726              $bits['order_by'] .= " DESC";
 727  
 728          $bits['limit'] = '';
 729  
 730          // When offset and number are provided, skip per_page and limit checks
 731          if ( !empty( $q['offset'] ) && !empty( $q['number'] ) ) {
 732              $bits['limit'] .= $q['offset'] . ", " . $q['number'];
 733  
 734          // Else proceed as normal
 735          } else {
 736              if ( !$q['per_page'] ) {
 737                  $q['per_page'] = (int) bb_get_option( 'page_topics' );
 738              }
 739      
 740              if ( $q['per_page'] > 0 ) {
 741                  if ( $q['page'] > 1 ) {
 742                      $bits['limit'] .= $q['per_page'] * ( $q['page'] - 1 ) . ", ";
 743                  }
 744                  $bits['limit'] .= $q['per_page'];
 745              }
 746          }
 747  
 748          $name = "get_{$this->type}s_";
 749  
 750          // Unfiltered
 751          $sql_calc_found_rows = $bits['sql_calc_found_rows'];
 752          unset($bits['sql_calc_found_rows']);
 753  
 754          foreach ( $bits as $bit => $value ) {
 755              if ( $this->query_id )
 756                  $value = apply_filters( "{$this->query_id}_$bit", $value );
 757              $$bit = apply_filters( "$name$bit", $value );
 758          }
 759  
 760          if ( $where )
 761              $where = "WHERE $where";
 762          if ( $group_by )
 763              $group_by = "GROUP BY $group_by";
 764          if ( $having )
 765              $having = "HAVING $having";
 766          if ( $order_by )
 767              $order_by = "ORDER BY $order_by";
 768          if ( $limit )
 769              $limit = "LIMIT $limit";
 770  
 771          return "SELECT $distinct $sql_calc_found_rows $fields FROM $from $index_hint $join $where $group_by $having $order_by $limit";
 772      }
 773  
 774  	function parse_value( $field, $value = '' ) {
 775          if ( !$value && !is_numeric($value) )
 776              return '';
 777  
 778          global $bbdb;
 779  
 780          $op = substr($value, 0, 1);
 781  
 782          // #, =whatever, <#, >#.  Cannot do < and > at same time
 783          if ( in_array($op, array('<', '=', '>')) ) :
 784              $value = substr($value, 1);
 785              $value = is_numeric($value) ? (float) $value : $bbdb->escape( $value );
 786              return " AND $field $op '$value'";
 787          elseif ( false === strpos($value, ',') && 'NULL' !== $value && '-NULL' !== $value ) :
 788              $value = is_numeric($value) ? (float) $value : $bbdb->escape( $value );
 789              return '-' == $op ? " AND $field != '" . substr($value, 1) . "'" : " AND $field = '$value'";
 790          endif;
 791  
 792          $y = $n = array();
 793          foreach ( explode(',', $value) as $v ) {
 794              $v = is_numeric($v) ? (int) $v : $bbdb->escape( $v );
 795              if ( '-' == substr($v, 0, 1) )
 796                  if ( $v === '-NULL' )
 797                      $not_null_flag = true;
 798                  else
 799                      $n[] = substr($v, 1);
 800              else
 801                  if ( $v === 'NULL' )
 802                      $null_flag = true;
 803                  else
 804                      $y[] = $v;
 805          }
 806  
 807          $r = '';
 808          if ( $y ) {
 809              $r .= " AND ";
 810              if ( $null_flag )
 811                  $r .= "(";
 812              $r .= "$field IN ('" . join("','", $y) . "')";
 813              if ( $null_flag )
 814                  $r .= " OR $field IS NULL)";
 815          } elseif ( $null_flag ) {
 816              $r .= " AND $field IS NULL";
 817          }
 818          
 819          if ( $n ) {
 820              $r .= " AND ";
 821              if ( $not_null_flag )
 822                  $r .= "(";
 823              $r .= "$field NOT IN ('" . join("','", $n) . "')";
 824              if ( $not_null_flag )
 825                  $r .= " AND $field IS NOT NULL)";
 826          } elseif ( $not_null_flag ) {
 827              $r .= " AND $field IS NOT NULL";
 828          }
 829  
 830          return $r;
 831      }
 832  
 833  	function date( $field, $date ) {
 834          if ( !$date && !is_int($date) )
 835              return '';
 836  
 837          if ( $is_range = false !== strpos( $date, '--' ) )
 838              $dates = explode( '--', $date, 2 );
 839          else
 840              $dates = array( $date );
 841  
 842          $op = false;
 843          $r = '';
 844          foreach ( $dates as $date ) {
 845              if ( $is_range ) {
 846                  $op = $op ? '<' : '>';
 847                  $date = (int) substr($date, 0, 14);
 848              } else {
 849                  $op = substr($date, 0, 1);
 850                  if ( !in_array($op, array('>', '<')) )
 851                      break;
 852                  $date = (int) substr($date, 1, 14);
 853              }
 854              if ( strlen($date) < 14 )
 855                  $date .= str_repeat('0', 14 - strlen($date));
 856              $r .= " AND $field $op $date";
 857          }
 858          if ( $r )
 859              return $r;
 860  
 861          $date = (int) $date;
 862          $r = " AND YEAR($field) = " . substr($date, 0, 4);
 863          if ( strlen($date) > 5 )
 864              $r .= " AND MONTH($field) = " . substr($date, 4, 2);
 865          if ( strlen($date) > 7 )
 866              $r .= " AND DAYOFMONTH($field) = " . substr($date, 6, 2);
 867          if ( strlen($date) > 9 )
 868              $r .= " AND HOUR($field) = " . substr($date, 8, 2);
 869          if ( strlen($date) > 11 )
 870              $r .= " AND MINUTE($field) = " . substr($date, 10, 2);
 871          if ( strlen($date) > 13 )
 872              $r .= " AND SECOND($field) = " . substr($date, 12, 2);
 873          return $r;
 874      }
 875  
 876  	function error( $code, $message ) {
 877          if ( is_wp_error($this->errors) )
 878              $this->errors->add( $code, $message );
 879          else
 880              $this->errors = new WP_Error( $code, $message );
 881      }
 882  }
 883  
 884  class BB_Query_Form extends BB_Query {
 885      var $defaults;
 886      var $allowed;
 887  
 888      // Can optionally pass unique id string to help out filters
 889  	function __construct( $type = 'topic', $defaults = '', $allowed = '', $id = '' ) {
 890          $this->defaults = wp_parse_args( $defaults );
 891          $this->allowed  = wp_parse_args( $allowed );
 892          if ( !empty($defaults) || !empty($allowed) )
 893              $this->query_from_env($type, $defaults, $allowed, $id);
 894      }
 895  
 896  	function BB_Query_Form( $type = 'topic', $defaults = '', $allowed = '', $id = '' ) {
 897          $this->__construct( $type, $defaults, $allowed, $id );
 898      }
 899  
 900  	function form( $args = null ) {
 901          $_post = 'post' == $this->type;
 902  
 903          $defaults = array(
 904              'search' => true,
 905              'forum'  => true,
 906              'tag'    => false,
 907              'open'   => false,
 908              'topic_author' => false,
 909              'post_author'  => false,
 910              'topic_status' => false,
 911              'post_status'  => false,
 912              'topic_title'  => false,
 913              'poster_ip'  => false,
 914  
 915              'method' => 'get',
 916              'submit' => __('Search &#187;'),
 917              'action' => ''
 918          );
 919          $defaults['id'] = $_post ? 'post-search-form' : 'topic-search-form';
 920  
 921          $args = wp_parse_args( $args, $defaults );
 922          extract( $args, EXTR_SKIP );
 923  
 924          $id = esc_attr( $id );
 925          $method = 'get' == strtolower($method) ? 'get' : 'post';
 926          $submit = esc_attr( $submit );
 927          if ( !$action = esc_url( $action ) )
 928              $action = '';
 929  
 930          if ( $this->query_vars )
 931              $query_vars =& $this->query_vars;
 932          else
 933              $query_vars = $this->fill_query_vars( $this->defaults );
 934  
 935          extract($query_vars, EXTR_PREFIX_ALL, 'q');
 936  
 937          $r  = "<form action='$action' method='$method' id='$id' class='search-form'>\n";
 938  
 939          $r .= "\t<fieldset>\n";
 940  
 941          if ( $search ) {
 942              if ( $_post ) {
 943                  $s_value = esc_attr( $q_post_text );
 944                  $s_name = 'post_text';
 945                  $s_id = 'post-text';
 946              } else {
 947                  $s_value = esc_attr( $q_search );
 948                  $s_name = $s_id = 'search';
 949              }
 950              $r .= "\t<div><label for=\"$s_id\">" . __('Search term') . "</label>\n";
 951              $r .= "\t\t<div><input name='$s_name' id='$s_id' type='text' class='text-input' value='$s_value' /></div>\n";
 952              $r .= "\t</div>\n\n";
 953          }
 954  
 955          if ( $forum ) {
 956              $r .= "\t<div><label for=\"forum-id\">" . __('Forum')  . "</label>\n";
 957              $r .= "\t\t<div>" . bb_get_forum_dropdown( array( 'selected' => $q_forum_id, 'none' => __('Any') ) ) . "</div>\n";
 958              $r .= "\t</div>\n\n";
 959          }
 960  
 961          if ( $tag ) {
 962              $q_tag = esc_attr( $q_tag );
 963              $r .= "\t<div><label for=\"topic-tag\">" .  __('Tag') . "</label>\n";
 964              $r .= "\t\t<div><input name='tag' id='topic-tag' type='text' class='text-input' value='$q_tag' /></div>\n";
 965              $r .= "\t</div>\n\n";
 966          }
 967  
 968          if ( $topic_author ) {
 969              $q_topic_author = esc_attr( $q_topic_author );
 970              $r .= "\t<div><label for=\"topic-author\">" . __('Topic author') . "</label>\n";
 971              $r .= "\t\t<div><input name='topic_author' id='topic-author' type='text' class='text-input' value='$q_topic_author' /></div>\n";
 972              $r .= "\t</div>\n\n";
 973          }
 974  
 975          if ( $post_author ) {
 976              $q_post_author = esc_attr( $q_post_author );
 977              $r .= "\t<div><label for=\"post-author\">" . __('Post author') . "</label>\n";
 978              $r .= "\t\t<div><input name='post_author' id='post-author' type='text' class='text-input' value='$q_post_author' /></div>\n";
 979              $r .= "\t</div>\n\n";
 980          }
 981  
 982          $stati = apply_filters( 'bb_query_form_post_status', array( 'all' => _x( 'All', 'post status' ), '0' => __('Normal'), '1' => __('Deleted') ), $this->type );
 983  
 984          if ( $topic_status ) {
 985              $r .= "\t<div><label for=\"topic-status\">" . __('Topic status') . "</label>\n";
 986              $r .= "\t\t<div><select name='topic_status' id='topic-status'>\n";
 987              foreach ( $stati as $status => $label ) {
 988                  $selected = (string) $status == (string) $q_topic_status ? " selected='selected'" : '';
 989                  $r .= "\t\t\t<option value='$status'$selected>$label</option>\n";
 990              }
 991              $r .= "\t\t</select></div>\n";
 992              $r .= "\t</div>\n\n";
 993          }
 994  
 995          if ( $post_status ) {
 996              $r .= "\t<div><label for=\"post-status\">" . __('Post status') . "</label>\n";
 997              $r .= "\t\t<div><select name='post_status' id='post-status'>\n";
 998              foreach ( $stati as $status => $label ) {
 999                  $selected = (string) $status == (string) $q_post_status ? " selected='selected'" : '';
1000                  $r .= "\t\t\t<option value='$status'$selected>$label</option>\n";
1001              }
1002              $r .= "\t\t</select></div>\n";
1003              $r .= "\t</div>\n\n";
1004          }
1005  
1006          if ( $poster_ip ) {
1007              $r .= "\t<div><label for=\"poster-ip\">" . __('Poster IP address') . "</label>\n";
1008              $r .= "\t\t<div><input name='poster_ip' id='poster-ip' type='text' class='text-input' value='$q_poster_ip' /></div>\n";
1009              $r .= "\t</div>\n\n";
1010          }
1011  
1012          if ( $open ) {
1013              $r .= "\t<div><label for=\"topic-open\">" . __('Open?') . "</label>\n";
1014              $r .= "\t\t<div><select name='open' id='topic-open'>\n";
1015              foreach ( array( 'all' => _x( 'All', 'posting status' ), '1' => _x( 'Open', 'posting status' ), '0' => __('Closed') ) as $status => $label ) {
1016                  $label = esc_html( $label );
1017                  $selected = (string) $status == (string) $q_open ? " selected='selected'" : '';
1018                  $r .= "\t\t\t<option value='$status'$selected>$label</option>\n";
1019              }
1020              $r .= "\t\t</select></div>\n";
1021              $r .= "\t</div>\n\n";
1022          }
1023  
1024          if ( $topic_title ) {
1025              $q_topic_title = esc_attr( $q_topic_title );
1026              $r .= "\t<div><label for=\"topic-title\">" . __('Title') . "</label>\n";
1027              $r .= "\t\t<div><input name='topic_title' id='topic-title' type='text' class='text-input' value='$q_topic_title' /></div>\n";
1028              $r .= "\t</div>\n\n";
1029          }
1030  
1031          $r .= apply_filters( 'bb_query_form_inputs', '', $args, $query_vars );
1032  
1033          $r .= "\t<div class=\"submit\"><label for=\"$id-submit\">" . __('Search') . "</label>\n";
1034          $r .= "\t\t<div><input type='submit' class='button submit-input' value='$submit' id='$id-submit' /></div>\n";
1035          $r .= "\t</div>\n";
1036  
1037          $r .= "\t</fieldset>\n\n";
1038  
1039          do_action( 'bb_query_form', $args, $query_vars );
1040  
1041          $r .= "</form>\n\n";
1042  
1043          echo $r;
1044      }
1045  }


Generated: Thu Dec 7 01:01:35 2017 Cross-referenced by PHPXref 0.7.1