/** * Standard modular run function for search results. * * @param string Search string * @param boolean Whether to only do a META (tags) search * @param ID_TEXT Order direction * @param integer Start position in total results * @param integer Maximum results to return in total * @param boolean Whether only to search titles (as opposed to both titles and content) * @param string Where clause that selects the content according to the main search string (SQL query fragment) (blank: full-text search) * @param SHORT_TEXT Username/Author to match for * @param ?MEMBER Member-ID to match for (NULL: unknown) * @param TIME Cutoff date * @param string The sort type (gets remapped to a field in this function) * @set title add_date * @param integer Limit to this number of results * @param string What kind of boolean search to do * @set or and * @param string Where constraints known by the main search code (SQL query fragment) * @param string Comma-separated list of categories to search under * @param boolean Whether it is a boolean search * @return array List of maps (template, orderer) */ function run($content, $only_search_meta, $direction, $max, $start, $only_titles, $content_where, $author, $author_id, $cutoff, $sort, $limit_to, $boolean_operator, $where_clause, $search_under, $boolean_search) { unset($limit_to); if (!module_installed('catalogues')) { return array(); } $remapped_orderer = ''; switch ($sort) { case 'rating': $remapped_orderer = '_rating:catalogues:id'; break; case 'title': $remapped_orderer = 'b_cv_value'; break; case 'add_date': $remapped_orderer = 'ce_add_date'; break; case 'relevance': break; default: $remapped_orderer = preg_replace('#[^\\w]#', '', $sort); break; } require_code('catalogues'); require_lang('catalogues'); // Calculate our where clause (search) $sq = build_search_submitter_clauses('ce_submitter', $author_id, $author); if (is_null($sq)) { return array(); } else { $where_clause .= $sq; } if (!is_null($cutoff)) { $where_clause .= ' AND '; $where_clause .= 'r.ce_add_date>' . strval($cutoff); } if (!$GLOBALS['FORUM_DRIVER']->is_super_admin(get_member())) { $where_clause .= ' AND '; $where_clause .= 'z.category_name IS NOT NULL'; $where_clause .= ' AND '; $where_clause .= 'p.category_name IS NOT NULL'; } if (!has_specific_permission(get_member(), 'see_unvalidated')) { $where_clause .= ' AND '; $where_clause .= 'ce_validated=1'; } $g_or = _get_where_clause_groups(get_member()); // Calculate and perform query $catalogue_name = get_param('catalogue_name', ''); $ranges = array(); if ($catalogue_name != '') { $extra_select = ''; $rows = $GLOBALS['SITE_DB']->query_select('catalogue_fields', array('id', 'cf_name', 'cf_type', 'cf_default'), array('c_name' => $catalogue_name, 'cf_searchable' => 1), 'ORDER BY cf_order'); $table = 'catalogue_entries r'; $trans_fields = array('!'); $nontrans_fields = array(); $title_field = mixed(); require_code('fields'); foreach ($rows as $i => $row) { $ob = get_fields_hook($row['cf_type']); $temp = $ob->inputted_to_sql_for_search($row, $i); if (is_null($temp)) { list(, , $row_type) = $ob->get_field_value_row_bits($row); switch ($row_type) { case 'long_trans': $trans_fields[] = 'f' . strval($i) . '.cv_value'; $table .= ' JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'catalogue_efv_long_trans f' . strval($i) . ' ON (f' . strval($i) . '.ce_id=r.id AND f' . strval($i) . '.cf_id=' . strval($row['id']) . ')'; $search_field = 't' . strval(count($trans_fields) - 1) . '.text_original'; //$extra_select.=',t'.strval(count($trans_fields)-1).'.text_original AS f'.strval($i).'_actual_value'; break; case 'short_trans': $trans_fields[] = 'f' . strval($i) . '.cv_value'; $table .= ' JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'catalogue_efv_short_trans f' . strval($i) . ' ON (f' . strval($i) . '.ce_id=r.id AND f' . strval($i) . '.cf_id=' . strval($row['id']) . ')'; $search_field = 't' . strval(count($trans_fields) - 1) . '.text_original'; //$extra_select.=',t'.strval(count($trans_fields)-1).'.text_original AS f'.strval($i).'_actual_value'; break; case 'long': $nontrans_fields[] = 'f' . strval($i) . '.cv_value'; $table .= ' JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'catalogue_efv_long f' . strval($i) . ' ON (f' . strval($i) . '.ce_id=r.id AND f' . strval($i) . '.cf_id=' . strval($row['id']) . ')'; $search_field = 'f' . strval($i) . '.cv_value'; //$extra_select.=',f'.strval($i).'.cv_value AS f'.strval($i).'_actual_value'; break; case 'short': $nontrans_fields[] = 'f' . strval($i) . '.cv_value'; $table .= ' JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'catalogue_efv_short f' . strval($i) . ' ON (f' . strval($i) . '.ce_id=r.id AND f' . strval($i) . '.cf_id=' . strval($row['id']) . ')'; $search_field = 'f' . strval($i) . '.cv_value'; //$extra_select.=',f'.strval($i).'.cv_value AS f'.strval($i).'_actual_value'; break; case 'float': //$nontrans_fields[]='f'.strval($i).'.cv_value'; $table .= ' JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'catalogue_efv_float f' . strval($i) . ' ON (f' . strval($i) . '.ce_id=r.id AND f' . strval($i) . '.cf_id=' . strval($row['id']) . ')'; $search_field = 'f' . strval($i) . '.cv_value'; //$extra_select.=',f'.strval($i).'.cv_value AS f'.strval($i).'_actual_value'; break; case 'integer': //$nontrans_fields[]='f'.strval($i).'.cv_value'; $table .= ' JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'catalogue_efv_integer f' . strval($i) . ' ON (f' . strval($i) . '.ce_id=r.id AND f' . strval($i) . '.cf_id=' . strval($row['id']) . ')'; $search_field = 'f' . strval($i) . '.cv_value'; //$extra_select.=',f'.strval($i).'.cv_value AS f'.strval($i).'_actual_value'; break; } $param = get_param('option_' . strval($row['id']), ''); if ($param != '') { $where_clause .= ' AND '; if (substr($param, 0, 1) == '=') { $where_clause .= db_string_equal_to($search_field, substr($param, 1)); } elseif ($row_type == 'integer' || $row_type == 'float') { if (is_numeric($param)) { $where_clause .= $search_field . '=' . $param; } else { $where_clause .= db_string_equal_to($search_field, $param); } } else { if (db_has_full_text($GLOBALS['SITE_DB']->connection_read) && method_exists($GLOBALS['SITE_DB']->static_ob, 'db_has_full_text_boolean') && $GLOBALS['SITE_DB']->static_ob->db_has_full_text_boolean() && !is_under_radar($param)) { $temp = db_full_text_assemble($param, true); } else { $temp = db_like_assemble($param); } $where_clause .= preg_replace('#\\?#', $search_field, $temp); } } else { $param = get_param('option_' . strval($row['id']) . '_ranged', ''); if ($param != '') { $ranges[$row['id']] = $param; } } } else { $table .= $temp[2]; $search_field = $temp[3]; if ($temp[4] != '') { $where_clause .= ' AND '; $where_clause .= $temp[4]; } else { $trans_fields = array_merge($trans_fields, $temp[0]); $non_trans_fields = array_merge($nontrans_fields, $temp[1]); } } if ($i == 0) { $title_field = $search_field; } } $where_clause .= ' AND '; $where_clause .= db_string_equal_to('r.c_name', $catalogue_name); if (is_null($title_field)) { return array(); } // No fields in catalogue -- very odd if ($g_or == '') { $rows = get_search_rows('catalogue_entry', 'id', $content, $boolean_search, $boolean_operator, $only_search_meta, $direction, $max, $start, $only_titles, $table, $trans_fields, $where_clause, $content_where, str_replace('b_cv_value', $title_field, $remapped_orderer), 'r.*,r.id AS id,r.cc_id AS r_cc_id,' . $title_field . ' AS b_cv_value' . $extra_select, $nontrans_fields); } else { $rows = get_search_rows('catalogue_entry', 'id', $content, $boolean_search, $boolean_operator, $only_search_meta, $direction, $max, $start, $only_titles, $table . ' LEFT JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'group_category_access z ON (' . db_string_equal_to('z.module_the_name', 'catalogues_category') . ' AND z.category_name=r.cc_id AND ' . str_replace('group_id', 'z.group_id', $g_or) . ') LEFT JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'group_category_access p ON (' . db_string_equal_to('p.module_the_name', 'catalogues_catalogue') . ' AND p.category_name=r.c_name AND ' . str_replace('group_id', 'p.group_id', $g_or) . ')', $trans_fields, $where_clause, $content_where, str_replace('b_cv_value', $title_field, $remapped_orderer), 'r.*,r.id AS id,r.cc_id AS r_cc_id,' . $title_field . ' AS b_cv_value' . $extra_select, $nontrans_fields); } } else { if ($GLOBALS['SITE_DB']->query_value('translate', 'COUNT(*)') > 10000) { $trans_fields = array(); $join = ' JOIN ' . get_table_prefix() . 'catalogue_efv_short c ON (r.id=c.ce_id AND f.id=c.cf_id)'; $_remapped_orderer = str_replace('b_cv_value', 'c.cv_value', $remapped_orderer); $extra_select = ''; $non_trans_fields = array('c.cv_value'); } else { $join = ' LEFT JOIN ' . get_table_prefix() . 'catalogue_efv_short_trans a ON (r.id=a.ce_id AND f.id=a.cf_id) LEFT JOIN ' . get_table_prefix() . 'catalogue_efv_long_trans b ON (r.id=b.ce_id AND f.id=b.cf_id) LEFT JOIN ' . get_table_prefix() . 'catalogue_efv_long d ON (r.id=d.ce_id AND f.id=d.cf_id) LEFT JOIN ' . get_table_prefix() . 'catalogue_efv_short c ON (r.id=c.ce_id AND f.id=c.cf_id)'; //' LEFT JOIN '.get_table_prefix().'catalogue_efv_float g ON (r.id=g.ce_id AND f.id=g.cf_id) LEFT JOIN '.get_table_prefix().'catalogue_efv_integer h ON (r.id=h.ce_id AND f.id=h.cf_id)'; $trans_fields = array('a.cv_value', 'b.cv_value'); $_remapped_orderer = str_replace('b_cv_value', 'b.cv_value', $remapped_orderer); $extra_select = ',b.cv_value AS b_cv_value'; $non_trans_fields = array('c.cv_value', 'd.cv_value'); } $where_clause .= ' AND '; $where_clause .= 'r.c_name NOT LIKE \'\\_%\''; // Don't want results drawn from the hidden custom-field catalogues if ($g_or == '') { $rows = get_search_rows('catalogue_entry', 'id', $content, $boolean_search, $boolean_operator, $only_search_meta, $direction, $max, $start, $only_titles, 'catalogue_fields f LEFT JOIN ' . get_table_prefix() . 'catalogue_entries r ON (r.c_name=f.c_name)' . $join, $trans_fields, $where_clause, $content_where, $_remapped_orderer, 'r.*,r.id AS id,r.cc_id AS r_cc_id' . $extra_select, $non_trans_fields); } else { $rows = get_search_rows('catalogue_entry', 'id', $content, $boolean_search, $boolean_operator, $only_search_meta, $direction, $max, $start, $only_titles, 'catalogue_fields f LEFT JOIN ' . get_table_prefix() . 'catalogue_entries r ON (r.c_name=f.c_name)' . $join . ' LEFT JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'group_category_access z ON (' . db_string_equal_to('z.module_the_name', 'catalogues_category') . ' AND z.category_name=r.cc_id AND ' . str_replace('group_id', 'z.group_id', $g_or) . ') LEFT JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'group_category_access p ON (' . db_string_equal_to('p.module_the_name', 'catalogues_catalogue') . ' AND p.category_name=r.c_name AND ' . str_replace('group_id', 'p.group_id', $g_or) . ')', $trans_fields, $where_clause, $content_where, $_remapped_orderer, 'r.*,r.id AS id,r.cc_id AS r_cc_id' . $extra_select, $non_trans_fields); } } $out = array(); if (count($rows) == 0) { return array(); } global $SEARCH_CATALOGUE_ENTRIES_CATALOGUES; $query = 'SELECT c.* FROM ' . get_table_prefix() . 'catalogues c'; if (can_arbitrary_groupby()) { $query .= ' JOIN ' . get_table_prefix() . 'catalogue_entries e ON e.c_name=c.c_name GROUP BY c.c_name'; } $_catalogues = $GLOBALS['SITE_DB']->query($query); foreach ($_catalogues as $catalogue) { $SEARCH_CATALOGUE_ENTRIES_CATALOGUES[$catalogue['c_name']] = $catalogue; } if (count($ranges) != 0) { foreach ($rows as $i => $row) { $out[$i]['data'] = $row; unset($rows[$i]); $catalogue_name = $row['c_name']; $tpl_set = $catalogue_name; $display = get_catalogue_entry_map($row, $SEARCH_CATALOGUE_ENTRIES_CATALOGUES[$catalogue_name], 'PAGE', $tpl_set, -1); foreach ($ranges as $range_id => $range_key) { $bits = explode('-', $display['_FIELD_' . strval($range_id)]); if (count($bits) == 2) { if (intval($bits[0]) >= intval($range_key) || intval($bits[1]) <= intval($range_key)) { $out[$i]['restricted'] = true; continue 2; } } } //$out[$i]['template']=do_template('CATALOGUE_'.$tpl_set.'_ENTRY_EMBED',$display,NULL,false,'CATALOGUE_DEFAULT_ENTRY_EMBED');//put_in_table(hyperlink($url,do_lang('_HERE')),'internal','middle','WIDE',1,do_lang('CATALOGUE_ENTRY').' ('.do_lang('IN',get_translated_text($catalogue['c_title'])).')'); if ($remapped_orderer != '' && array_key_exists($remapped_orderer, $row)) { $out[$i]['orderer'] = $row[$remapped_orderer]; } elseif (substr($remapped_orderer, 0, 7) == '_rating') { $out[$i]['orderer'] = $row['compound_rating']; } } } else { foreach ($rows as $i => $row) { $out[$i]['data'] = $row; unset($rows[$i]); if ($remapped_orderer != '' && array_key_exists($remapped_orderer, $row)) { $out[$i]['orderer'] = $row[$remapped_orderer]; } elseif (substr($remapped_orderer, 0, 7) == '_rating') { $out[$i]['orderer'] = $row['compound_rating']; } } } return $out; }
/** * Standard modular run function for search results. * * @param string Search string * @param boolean Whether to only do a META (tags) search * @param ID_TEXT Order direction * @param integer Start position in total results * @param integer Maximum results to return in total * @param boolean Whether only to search titles (as opposed to both titles and content) * @param string Where clause that selects the content according to the main search string (SQL query fragment) (blank: full-text search) * @param SHORT_TEXT Username/Author to match for * @param ?MEMBER Member-ID to match for (NULL: unknown) * @param TIME Cutoff date * @param string The sort type (gets remapped to a field in this function) * @set title add_date * @param integer Limit to this number of results * @param string What kind of boolean search to do * @set or and * @param string Where constraints known by the main search code (SQL query fragment) * @param string Comma-separated list of categories to search under * @param boolean Whether it is a boolean search * @return array List of maps (template, orderer) */ function run($content, $only_search_meta, $direction, $max, $start, $only_titles, $content_where, $author, $author_id, $cutoff, $sort, $limit_to, $boolean_operator, $where_clause, $search_under, $boolean_search) { unset($limit_to); if (get_forum_type() != 'ocf') { return array(); } require_code('ocf_members'); $remapped_orderer = ''; switch ($sort) { case 'title': $remapped_orderer = 'm_username'; break; case 'add_date': $remapped_orderer = 'm_join_time'; break; case 'relevance': case 'rating': break; default: $remapped_orderer = preg_replace('#[^\\w]#', '', $sort); break; } require_lang('ocf'); // Calculate our where clause (search) if ($author != '') { $where_clause .= ' AND '; $where_clause .= db_string_equal_to('m_username', $author); } if (!is_null($cutoff)) { $where_clause .= ' AND '; $where_clause .= 'm_join_time>' . strval($cutoff); } $raw_fields = array('m_username'); $trans_fields = array(); $rows = ocf_get_all_custom_fields_match(NULL, 1, 1); $table = ''; require_code('fields'); $non_trans_fields = 0; foreach ($rows as $i => $row) { $ob = get_fields_hook($row['cf_type']); list(, , $storage_type) = $ob->get_field_value_row_bits($row); if (strpos($storage_type, '_trans') === false) { $non_trans_fields++; } } $index_issue = $non_trans_fields > 16; foreach ($rows as $i => $row) { $ob = get_fields_hook($row['cf_type']); list(, , $storage_type) = $ob->get_field_value_row_bits($row); $param = get_param('option_' . strval($row['id']), ''); if ($param != '') { $where_clause .= ' AND '; if (db_has_full_text($GLOBALS['SITE_DB']->connection_read) && method_exists($GLOBALS['SITE_DB']->static_ob, 'db_has_full_text_boolean') && $GLOBALS['SITE_DB']->static_ob->db_has_full_text_boolean() && !is_under_radar($param)) { $temp = db_full_text_assemble('"' . $param . '"', true); } else { $temp = db_like_assemble($param); } if ($row['cf_type'] == 'short_trans' || $row['cf_type'] == 'long_trans') { $where_clause .= preg_replace('#\\?#', 't' . strval(count($trans_fields) + 1) . '.text_original', $temp); } else { $where_clause .= preg_replace('#\\?#', 'field_' . strval($row['id']), $temp); } } if (strpos($storage_type, '_trans') === false) { $raw_fields[] = 'field_' . strval($row['id']); } else { $trans_fields[] = 'field_' . strval($row['id']); } } $age_range = get_param('option__age_range', get_param('option__age_range_from', '') . '-' . get_param('option__age_range_to', '')); if ($age_range != '' && $age_range != '-') { $bits = explode('-', $age_range); if (count($bits) == 2) { $lower = strval(intval(date('Y', utctime_to_usertime())) - intval($bits[0])); $upper = strval(intval(date('Y', utctime_to_usertime())) - intval($bits[1])); $where_clause .= ' AND '; $where_clause .= '(m_dob_year<' . $lower . ' OR m_dob_year=' . $lower . ' AND (m_dob_month<' . date('m') . ' OR m_dob_month=' . date('m') . ' AND m_dob_day<=' . date('d') . '))'; $where_clause .= ' AND '; $where_clause .= '(m_dob_year>' . $upper . ' OR m_dob_year=' . $upper . ' AND (m_dob_month>' . date('m') . ' OR m_dob_month=' . date('m') . ' AND m_dob_day>=' . date('d') . '))'; } if (either_param_integer('option__photo_thumb_url', 0) == 1) { $where_clause .= ' AND '; $where_clause .= db_string_not_equal_to('m_photo_thumb_url', ''); } } $user_group = get_param('option__user_group', ''); if ($user_group != '') { $bits = explode(',', $user_group); $where_clause .= ' AND '; $group_where_clause = ''; foreach ($bits as $i => $bit) { $group = intval($bit); $table .= ' LEFT JOIN ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_group_members g' . strval($i) . ' ON (g' . strval($i) . '.gm_group_id=' . strval($group) . ' AND g' . strval($i) . '.gm_member_id=r.id)'; if ($group_where_clause != '') { $group_where_clause .= ' OR '; } $group_where_clause .= 'g' . strval($i) . '.gm_validated=1 OR m_primary_group=' . strval($group); } $where_clause .= '(' . $group_where_clause . ')'; } if (!has_specific_permission(get_member(), 'see_unvalidated')) { $where_clause .= ' AND '; $where_clause .= 'm_validated=1'; } // Calculate and perform query $rows = get_search_rows(NULL, NULL, $content, $boolean_search, $boolean_operator, $only_search_meta, $direction, $max, $start, $only_titles, 'f_members r JOIN ' . get_table_prefix() . 'f_member_custom_fields a ON r.id=a.mf_member_id' . $table, array('!', 'm_signature') + $trans_fields, $where_clause, $content_where, $remapped_orderer, 'r.*,a.*,r.id AS id', $raw_fields); $out = array(); foreach ($rows as $i => $row) { /*if ($user_group!='') { $bits=explode(',',$user_group); $ok=false; $groups=$GLOBALS['FORUM_DRIVER']->get_members_groups($row['id']); foreach ($bits as $bit) { if (in_array($user_group,$groups)) $ok=true; } if (!$ok) continue; }*/ if (!is_guest($row['id'])) { $out[$i]['data'] = $row; if ($remapped_orderer != '' && array_key_exists($remapped_orderer, $row)) { $out[$i]['orderer'] = $row[$remapped_orderer]; } elseif (substr($remapped_orderer, 0, 7) == '_rating') { $out[$i]['orderer'] = $row['compound_rating']; } } else { $out[$i]['data'] = NULL; } unset($rows[$i]); } return $out; }
/** * Build a fulltext query WHERE clause from given content. * * @param string The search content * @param boolean Whether it's a boolean search * @param string Boolean operation to use * @set AND OR * @param boolean Whether we can assume we require full coverage * @return string WHERE clause */ function build_content_where($content, $boolean_search, &$boolean_operator, $full_coverage = false) { $content = str_replace('?', '', $content); list($body_words, $include_words, $disclude_words) = _boolean_search_prepare($content); $under_radar = false; if (is_under_radar($content) && $content != '') { $under_radar = true; } if ($under_radar || $boolean_search || !db_has_full_text($GLOBALS['SITE_DB']->connection_read)) { if (!in_array(strtoupper($boolean_operator), array('AND', 'OR'))) { log_hack_attack_and_exit('ORDERBY_HACK'); } if ($content == '') { $content_where = ''; } else { if (db_has_full_text($GLOBALS['SITE_DB']->connection_read) && method_exists($GLOBALS['SITE_DB']->static_ob, 'db_has_full_text_boolean') && $GLOBALS['SITE_DB']->static_ob->db_has_full_text_boolean() && !$under_radar) { $content_where = db_full_text_assemble($content, true); } else { $content_where = db_like_assemble($content, $boolean_operator, $full_coverage); if ($content_where == '') { $content_where = '1=1'; } } } } else { if ($content == '') { $content_where = ''; } else { $content_where = db_full_text_assemble($content, false); } $boolean_operator = 'OR'; } return $content_where; }