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