/**
  * Standard aed_module table function.
  *
  * @param  array			Details to go to build_url for link to the next screen.
  * @return array			A pair: The choose table, Whether re-ordering is supported from this screen.
  */
 function nice_get_choose_table($url_map)
 {
     require_code('templates_results_table');
     $current_ordering = get_param('sort', 'title ASC', true);
     list($sortable, $sort_order) = array(substr($current_ordering, 0, strrpos($current_ordering, ' ')), substr($current_ordering, strrpos($current_ordering, ' ') + 1));
     $sortables = array('title' => do_lang_tempcode('TITLE'));
     if (db_has_subqueries($GLOBALS['SITE_DB']->connection_read)) {
         $sortables['(SELECT COUNT(*) FROM ' . get_table_prefix() . 'newsletter n JOIN ' . get_table_prefix() . 'newsletter_subscribe s ON n.id=s.newsletter_id WHERE code_confirm=0)'] = do_lang_tempcode('COUNT_MEMBERS');
     }
     if (strtoupper($sort_order) != 'ASC' && strtoupper($sort_order) != 'DESC' || !array_key_exists($sortable, $sortables)) {
         log_hack_attack_and_exit('ORDERBY_HACK');
     }
     global $NON_CANONICAL_PARAMS;
     $NON_CANONICAL_PARAMS[] = 'sort';
     $header_row = results_field_title(array(do_lang_tempcode('TITLE'), do_lang_tempcode('COUNT_MEMBERS'), do_lang_tempcode('ACTIONS')), $sortables, 'sort', $sortable . ' ' . $sort_order);
     $fields = new ocp_tempcode();
     require_code('form_templates');
     list($rows, $max_rows) = $this->get_entry_rows(false, $current_ordering);
     foreach ($rows as $row) {
         $edit_link = build_url($url_map + array('id' => $row['id']), '_SELF');
         $num_readers = $GLOBALS['SITE_DB']->query_value('newsletter n JOIN ' . get_table_prefix() . 'newsletter_subscribe s ON n.id=s.newsletter_id', 'COUNT(*)', array('code_confirm' => 0));
         $fields->attach(results_entry(array(get_translated_text($row['title']), integer_format($num_readers), protect_from_escaping(hyperlink($edit_link, do_lang_tempcode('EDIT'), false, true, '#' . strval($row['id'])))), true));
     }
     return array(results_table(do_lang($this->menu_label), get_param_integer('start', 0), 'start', either_param_integer('max', 20), 'max', $max_rows, $header_row, $fields, $sortables, $sortable, $sort_order), false);
 }
Beispiel #2
0
 /**
  * The UI to translate content.
  *
  * @return tempcode		The UI
  */
 function interface_content()
 {
     $title = get_page_title('TRANSLATE_CONTENT');
     if (!multi_lang()) {
         warn_exit(do_lang_tempcode('MULTILANG_OFF'));
     }
     $max = get_param_integer('max', 100);
     $lang = choose_language($title);
     if (is_object($lang)) {
         return $lang;
     }
     // Fiddle around in order to find what we haven't translated. Subqueries and self joins don't work well enough across different db's
     if (!db_has_subqueries($GLOBALS['SITE_DB']->connection_read)) {
         $_done_id_list = collapse_2d_complexity('id', 'text_original', $GLOBALS['SITE_DB']->query_select('translate', array('id', 'text_original'), array('language' => $lang, 'broken' => 0)));
         $done_id_list = '';
         foreach (array_keys($_done_id_list) as $done_id) {
             if ($done_id_list != '') {
                 $done_id_list .= ',';
             }
             $done_id_list .= strval($done_id);
         }
         $and_clause = $done_id_list == '' ? '' : 'AND id NOT IN (' . $done_id_list . ')';
         $query = 'FROM ' . get_table_prefix() . 'translate WHERE ' . db_string_not_equal_to('language', $lang) . ' ' . $and_clause . ' AND ' . db_string_not_equal_to('text_original', '') . ' ORDER BY importance_level';
         $to_translate = $GLOBALS['SITE_DB']->query('SELECT * ' . $query, $max);
     } else {
         $query = 'FROM ' . get_table_prefix() . 'translate a LEFT JOIN ' . get_table_prefix() . 'translate b ON a.id=b.id AND b.broken=0 AND ' . db_string_equal_to('b.language', $lang) . ' WHERE b.id IS NULL AND ' . db_string_not_equal_to('a.language', $lang) . ' AND ' . db_string_not_equal_to('a.text_original', '');
         $to_translate = $GLOBALS['SITE_DB']->query('SELECT a.* ' . $query . (can_arbitrary_groupby() ? ' GROUP BY a.id' : '') . ' ORDER BY a.importance_level', $max);
     }
     $total = $GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT COUNT(*) ' . $query);
     if (count($to_translate) == 0) {
         inform_exit(do_lang_tempcode('NOTHING_TO_TRANSLATE'));
     }
     require_all_lang($lang, true);
     require_all_open_lang_files($lang);
     // Make our translation page
     require_code('lang2');
     $lines = '';
     $intertrans = $this->get_intertran_conv($lang);
     $actions = make_string_tempcode(' ');
     $last_level = NULL;
     $too_many = count($to_translate) == $max;
     $ids_to_lookup = array();
     foreach ($to_translate as $it) {
         $ids_to_lookup[] = $it['id'];
     }
     $names = find_lang_content_names($ids_to_lookup);
     foreach ($to_translate as $i => $it) {
         if ($it['importance_level'] == 0) {
             continue;
         }
         // Corrupt data
         $id = $it['id'];
         $old = $it['text_original'];
         $current = $this->find_lang_matches($old, $lang);
         $priority = $last_level === $it['importance_level'] ? NULL : do_lang('PRIORITY_' . strval($it['importance_level']));
         $name = $names[$id];
         if (is_null($name)) {
             continue;
         }
         // Orphaned string
         if ($intertrans != '') {
             $actions = do_template('TRANSLATE_ACTION', array('_GUID' => 'f625cf15c9db5e5af30fc772a7f0d5ff', 'LANG_FROM' => $it['language'], 'LANG_TO' => $lang, 'NAME' => 'trans_' . strval($id), 'OLD' => $old));
         }
         $line = do_template('TRANSLATE_LINE_CONTENT', array('_GUID' => '87a0f5298ce9532839f3206cd0e06051', 'NAME' => $name, 'ID' => strval($id), 'OLD' => $old, 'CURRENT' => $current, 'ACTIONS' => $actions, 'PRIORITY' => $priority));
         $lines .= $line->evaluate();
         /*XHTMLXHTML*/
         $last_level = $it['importance_level'];
     }
     $url = build_url(array('page' => '_SELF', 'type' => '_content', 'lang' => $lang), '_SELF');
     require_code('lang2');
     return do_template('TRANSLATE_SCREEN_CONTENT_SCREEN', array('_GUID' => 'af732c5e595816db1c6f025c4b8fa6a2', 'MAX' => integer_format($max), 'TOTAL' => integer_format($total - $max), 'LANG_ORIGINAL_NAME' => get_site_default_lang(), 'LANG_NICE_ORIGINAL_NAME' => lookup_language_full_name(get_site_default_lang()), 'LANG_NICE_NAME' => lookup_language_full_name($lang), 'TOO_MANY' => $too_many, 'INTERTRANS' => $intertrans, 'LANG' => $lang, 'LINES' => $lines, 'TITLE' => $title, 'URL' => $url));
 }
Beispiel #3
0
 /**
  * Get a list of members who have enabled this notification (i.e. have chosen to or are defaulted to).
  * (No pagination supported, as assumed there are only a small set of members here.)
  *
  * @param  ID_TEXT		Notification code
  * @param  ?SHORT_TEXT	The category within the notification code (NULL: none)
  * @param  ?array			List of member IDs we are restricting to (NULL: no restriction). This effectively works as a intersection set operator against those who have enabled.
  * @param  integer		Start position (for pagination)
  * @param  integer		Maximum (for pagination)
  * @return array			A pair: Map of members to their notification setting, and whether there may be more
  */
 function _all_members_who_have_enabled($only_if_enabled_on__notification_code, $only_if_enabled_on__category, $to_member_ids, $start, $max)
 {
     global $NO_DB_SCOPE_CHECK;
     $bak = $NO_DB_SCOPE_CHECK;
     $NO_DB_SCOPE_CHECK = true;
     $initial_setting = $this->get_initial_setting($only_if_enabled_on__notification_code, $only_if_enabled_on__category);
     $has_by_default = $initial_setting != A_NA;
     $clause_1 = db_string_equal_to('l_notification_code', substr($only_if_enabled_on__notification_code, 0, 80));
     $clause_2 = is_null($only_if_enabled_on__category) ? db_string_equal_to('l_code_category', '') : '(' . db_string_equal_to('l_code_category', '') . ' OR ' . db_string_equal_to('l_code_category', $only_if_enabled_on__category) . ')';
     $clause_3 = '1=1';
     if (!is_null($to_member_ids)) {
         if (count($to_member_ids) == 0) {
             return array(array(), false);
         }
         $clause_3 = '(';
         foreach ($to_member_ids as $member_id) {
             if ($clause_3 != '(') {
                 $clause_3 .= ' OR ';
             }
             $clause_3 .= 'l_member_id=' . strval($member_id);
         }
         $clause_3 .= ')';
     }
     $db = substr($only_if_enabled_on__notification_code, 0, 4) == 'ocf_' ? $GLOBALS['FORUM_DB'] : $GLOBALS['SITE_DB'];
     $test = $GLOBALS['SITE_DB']->query_value_null_ok('notification_lockdown', 'l_setting', array('l_notification_code' => substr($only_if_enabled_on__notification_code, 0, 80)));
     if (!is_null($test) && get_forum_type() == 'ocf') {
         $query_stub = 'SELECT m.id AS l_member_id,' . strval($test) . ' AS l_setting FROM ' . $db->get_table_prefix() . 'f_members m WHERE ' . str_replace('l_member_id', 'id', $clause_3);
         $query_stem = '';
     } else {
         if ($has_by_default && get_forum_type() == 'ocf' && db_has_subqueries($db->connection_read)) {
             $query_stub = 'SELECT m.id AS l_member_id,l_setting FROM ' . $db->get_table_prefix() . 'f_members m LEFT JOIN ' . $db->get_table_prefix() . 'notifications_enabled l ON ' . $clause_1 . ' AND ' . $clause_2 . ' AND ' . $clause_3 . ' AND m.id=l.l_member_id WHERE ' . str_replace('l_member_id', 'm.id', $clause_3) . ' AND ';
             $query_stem = 'NOT EXISTS(SELECT * FROM ' . $db->get_table_prefix() . 'notifications_enabled l WHERE m.id=l.l_member_id AND ' . $clause_1 . ' AND ' . $clause_2 . ' AND ' . $clause_3 . ' AND l_setting=' . strval(A_NA) . ')';
         } else {
             $query_stub = 'SELECT l_member_id,l_setting FROM ' . $db->get_table_prefix() . 'notifications_enabled WHERE ';
             $query_stem = $clause_1 . ' AND ' . $clause_2 . ' AND ' . $clause_3 . ' AND l_setting<>' . strval(A_NA);
         }
     }
     $results = $db->query($query_stub . $query_stem, $max, $start);
     foreach ($results as $i => $r) {
         if (is_null($results[$i]['l_setting'])) {
             $results[$i]['l_setting'] = $initial_setting;
         }
     }
     $NO_DB_SCOPE_CHECK = $bak;
     $possibly_has_more = count($results) == $max;
     return array(collapse_2d_complexity('l_member_id', 'l_setting', $results), $possibly_has_more);
 }
Beispiel #4
0
/**
 * Get a nice formatted XHTML list of all the children beneath the specified CEDI page. This function is recursive.
 *
 * @param  ?AUTO_LINK	The CEDI page to select by default (NULL: none)
 * @param  ?AUTO_LINK	The CEDI page to look beneath (NULL: the root)
 * @param  string			Tree built up so far, in recursion (blank: starting recursion)
 * @param  boolean		Whether to include orphaned pages in the tree
 * @param  boolean		Whether to create a compound list (gets pairs: tempcode, and comma-separated list of children)
 * @param  boolean		Whether to use titles in IDs after a ! (used on tree edit page)
 * @return mixed			Tempcode for the list / pair of tempcode and compound
 */
function cedi_show_tree($select = NULL, $id = NULL, $tree = '', $include_orphans = true, $use_compound_list = false, $ins_format = false)
{
    if (is_null($id)) {
        $id = db_get_first_id();
    }
    if ($GLOBALS['SITE_DB']->query_value('seedy_pages', 'COUNT(*)') > 1000) {
        return new ocp_tempcode();
    }
    $cedi_seen = array(db_get_first_id());
    $title = get_translated_text($GLOBALS['SITE_DB']->query_value('seedy_pages', 'title', array('id' => $id)));
    $out = _cedi_show_tree($cedi_seen, $select, $id, $tree, $title, $use_compound_list, $ins_format);
    if ($include_orphans) {
        if (!db_has_subqueries($GLOBALS['SITE_DB']->connection_read)) {
            $cedi_seen = array();
            get_cedi_page_tree($cedi_seen, is_null($id) ? NULL : intval($id));
            // To build up $cedi_seen
            $where = '';
            foreach ($cedi_seen as $seen) {
                if ($where != '') {
                    $where .= ' AND ';
                }
                $where .= 'p.id<>' . strval((int) $seen);
            }
            $orphans = $GLOBALS['SITE_DB']->query('SELECT p.id,text_original,p.title FROM ' . get_table_prefix() . 'seedy_pages p LEFT JOIN ' . get_table_prefix() . 'translate t ON ' . db_string_equal_to('language', user_lang()) . ' AND t.id=p.title WHERE ' . $where . ' ORDER BY add_date DESC', 50);
        } else {
            $orphans = $GLOBALS['SITE_DB']->query('SELECT p.id,text_original,p.title FROM ' . get_table_prefix() . 'seedy_pages p LEFT JOIN ' . get_table_prefix() . 'translate t ON ' . db_string_equal_to('language', user_lang()) . ' AND t.id=p.title WHERE p.id<>' . strval(db_get_first_id()) . ' AND NOT EXISTS(SELECT * FROM ' . get_table_prefix() . 'seedy_children WHERE child_id=p.id) ORDER BY add_date DESC', 50);
            if (count($orphans) < 50) {
                global $M_SORT_KEY;
                $M_SORT_KEY = 'text_original';
                usort($orphans, 'multi_sort');
            }
        }
        foreach ($orphans as $orphan) {
            if (!has_category_access(get_member(), 'seedy_page', strval($orphan['id']))) {
                continue;
            }
            if ($GLOBALS['RECORD_LANG_STRINGS_CONTENT'] || is_null($orphan['text_original'])) {
                $orphan['text_original'] = get_translated_text($orphan['title']);
            }
            $title = $orphan['text_original'];
            //$out->attach(form_input_list_entry(strval($orphan['id']),($select==$orphan['id']),do_template('CEDI_LIST_TREE_LINE',array('_GUID'=>'e3eb3decfac32382cdcb5b745ef0ad7e','DEPTH'=>'?','TITLE'=>$title,'ID'=>$orphan['id']))));
            //			$out.='<option value="'.$orphan['id'].'"> ? '.$title.'</option>';
            $out->attach(form_input_list_entry($ins_format ? strval($orphan['id']) . '!' . $title : strval($orphan['id']), false, do_lang('CEDI_ORPHANED') . ' > ' . $title));
        }
    }
    return $out;
}
Beispiel #5
0
 /**
  * Standard aed_module table function.
  *
  * @param  array			Details to go to build_url for link to the next screen.
  * @return array			A pair: The choose table, Whether re-ordering is supported from this screen.
  */
 function nice_get_choose_table($url_map)
 {
     require_code('templates_results_table');
     $current_ordering = get_param('sort', 'id ASC', true);
     list($sortable, $sort_order) = array(substr($current_ordering, 0, strrpos($current_ordering, ' ')), substr($current_ordering, strrpos($current_ordering, ' ') + 1));
     $sortables = array('id' => do_lang_tempcode('CODENAME'), 't_is_textual' => do_lang_tempcode('BANNER_IS_TEXTUAL'), 't_image_width' => do_lang_tempcode('WIDTH'), 't_image_height' => do_lang_tempcode('HEIGHT'), 't_max_file_size' => do_lang_tempcode('_FILE_SIZE'), 't_comcode_inline' => do_lang_tempcode('COMCODE_INLINE'));
     if (db_has_subqueries($GLOBALS['SITE_DB']->connection_read)) {
         $sortables['(SELECT COUNT(*) FROM ' . get_table_prefix() . 'banners WHERE b_type=r.id)'] = do_lang_tempcode('COUNT_TOTAL');
     }
     if (strtoupper($sort_order) != 'ASC' && strtoupper($sort_order) != 'DESC' || !array_key_exists($sortable, $sortables)) {
         log_hack_attack_and_exit('ORDERBY_HACK');
     }
     global $NON_CANONICAL_PARAMS;
     $NON_CANONICAL_PARAMS[] = 'sort';
     $header_row = results_field_title(array(do_lang_tempcode('CODENAME'), do_lang_tempcode('BANNER_IS_TEXTUAL'), do_lang_tempcode('WIDTH'), do_lang_tempcode('HEIGHT'), do_lang_tempcode('_FILE_SIZE'), do_lang_tempcode('COMCODE_INLINE'), do_lang_tempcode('COUNT_TOTAL'), do_lang_tempcode('ACTIONS')), $sortables, 'sort', $sortable . ' ' . $sort_order);
     $fields = new ocp_tempcode();
     require_code('form_templates');
     list($rows, $max_rows) = $this->get_entry_rows(false, $current_ordering);
     foreach ($rows as $row) {
         $edit_link = build_url($url_map + array('id' => $row['id']), '_SELF');
         $total = integer_format($GLOBALS['SITE_DB']->query_value('banners', 'COUNT(*)', array('b_type' => $row['id'])));
         $fields->attach(results_entry(array($row['id'] == '' ? do_lang('GENERAL') : $row['id'], $row['t_is_textual'] == 1 ? do_lang_tempcode('YES') : do_lang_tempcode('NO'), integer_format($row['t_image_width']), integer_format($row['t_image_height']), clean_file_size($row['t_max_file_size'] * 1024), $row['t_comcode_inline'] == 1 ? do_lang_tempcode('YES') : do_lang_tempcode('NO'), $total, protect_from_escaping(hyperlink($edit_link, do_lang_tempcode('EDIT'), false, true, '#' . $row['id']))), true));
     }
     return array(results_table(do_lang($this->menu_label), get_param_integer('start', 0), 'start', get_param_integer('max', 20), 'max', $max_rows, $header_row, $fields, $sortables, $sortable, $sort_order), false);
 }
/**
 * Get an array of maps for the topic in the given forum.
 *
 * @param  object			Link to the real forum driver
 * @param  integer		The topic ID
 * @param  integer		The comment count will be returned here by reference
 * @param  ?integer		Maximum comments to returned (NULL: no limit)
 * @param  integer		Comment to start at
 * @param  boolean		Whether to mark the topic read
 * @param  boolean		Whether to show in reverse
 * @param  boolean		Whether to only load minimal details if it is a threaded topic
 * @param  ?array			List of post IDs to load (NULL: no filter)
 * @param  boolean		Whether to load spacer posts
 * @return mixed			The array of maps (Each map is: title, message, member, date) (-1 for no such forum, -2 for no such topic)
 */
function _helper_get_forum_topic_posts($this_ref, $topic_id, &$count, $max, $start, $mark_read = true, $reverse = false, $light_if_threaded = false, $post_ids = NULL, $load_spacer_posts_too = false)
{
    if (is_null($topic_id)) {
        $count = 0;
        return -2;
    }
    require_code('ocf_topics');
    $is_threaded = $this_ref->topic_is_threaded($topic_id);
    $extra_where = '';
    if (!is_null($post_ids)) {
        if (count($post_ids) == 0) {
            $count = 0;
            return array();
        }
        $extra_where = ' AND (';
        foreach ($post_ids as $i => $id) {
            if ($i != 0) {
                $extra_where .= ' OR ';
            }
            $extra_where .= 'p.id=' . strval($id);
        }
        $extra_where .= ')';
    }
    $where = '(' . ocf_get_topic_where($topic_id) . ')';
    if (!$load_spacer_posts_too) {
        $where .= not_like_spacer_posts('t.text_original');
    }
    $where .= $extra_where;
    if (!has_specific_permission(get_member(), 'see_unvalidated')) {
        $where .= ' AND (p_validated=1 OR ((p_poster<>' . strval($GLOBALS['FORUM_DRIVER']->get_guest_id()) . ' OR ' . db_string_equal_to('p_ip_address', get_ip_address()) . ') AND p_poster=' . strval((int) get_member()) . '))';
    }
    $index = strpos(get_db_type(), 'mysql') !== false && !is_null($GLOBALS['SITE_DB']->query_value_null_ok('db_meta_indices', 'i_name', array('i_table' => 'f_posts', 'i_name' => 'in_topic'))) ? 'USE INDEX (in_topic)' : '';
    $order = $reverse ? 'p_time DESC,p.id DESC' : 'p_time ASC,p.id ASC';
    if ($is_threaded && db_has_subqueries($this_ref->connection->connection_read)) {
        $order = ($reverse ? 'compound_rating ASC' : 'compound_rating DESC') . ',' . $order;
    }
    if ($light_if_threaded && $is_threaded) {
        $select = 'p.id,p.p_parent_id,p.p_intended_solely_for,p.p_poster';
    } else {
        $select = 'p.*,text_parsed,text_original';
        if (!db_has_subqueries($GLOBALS['FORUM_DB']->connection_read)) {
            $select .= ',h.h_post_id';
        }
    }
    if ($is_threaded && db_has_subqueries($this_ref->connection->connection_read)) {
        $select .= ',COALESCE((SELECT AVG(rating) FROM ' . $this_ref->connection->get_table_prefix() . 'rating WHERE ' . db_string_equal_to('rating_for_type', 'post') . ' AND rating_for_id=p.id),5) AS compound_rating';
    }
    if (!db_has_subqueries($GLOBALS['FORUM_DB']->connection_read)) {
        $rows = $this_ref->connection->query('SELECT ' . $select . ' FROM ' . $this_ref->connection->get_table_prefix() . 'f_posts p ' . $index . ' LEFT JOIN ' . $this_ref->connection->get_table_prefix() . 'translate t ON t.id=p.p_post LEFT JOIN ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_post_history h ON (h.h_post_id=p.id AND h.h_action_date_and_time=p.p_last_edit_time) WHERE ' . $where . ' ORDER BY ' . $order, $max, $start);
    } else {
        $rows = $this_ref->connection->query('SELECT ' . $select . ', (SELECT h_post_id FROM ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_post_history h WHERE (h.h_post_id=p.id) LIMIT 1) AS h_post_id FROM ' . $this_ref->connection->get_table_prefix() . 'f_posts p ' . $index . ' LEFT JOIN ' . $this_ref->connection->get_table_prefix() . 'translate t ON t.id=p.p_post WHERE ' . $where . ' ORDER BY ' . $order, $max, $start);
    }
    $count = $this_ref->connection->query_value_null_ok_full('SELECT COUNT(*) FROM ' . $this_ref->connection->get_table_prefix() . 'f_posts p ' . $index . ' LEFT JOIN ' . $this_ref->connection->get_table_prefix() . 'translate t ON t.id=p.p_post WHERE ' . $where);
    $out = array();
    foreach ($rows as $myrow) {
        if (is_null($myrow['p_intended_solely_for']) || $myrow['p_intended_solely_for'] == get_member() || $myrow['p_intended_solely_for'] == $this_ref->get_guest_id() && $this_ref->is_staff(get_member())) {
            $temp = $myrow;
            // Takes all OCF properties
            // Then sanitised for normal forum driver API too (involves repetition)
            $temp['parent_id'] = $myrow['p_parent_id'];
            if (!$light_if_threaded || !$is_threaded) {
                $temp['title'] = $myrow['p_title'];
                $message = new ocp_tempcode();
                if (get_page_name() == 'search' || is_null($myrow['text_parsed']) || $myrow['text_parsed'] == '' || $myrow['p_post'] == 0) {
                    $message = get_translated_tempcode($myrow['p_post'], $GLOBALS['FORUM_DB']);
                } else {
                    if (!$message->from_assembly($myrow['text_parsed'], true)) {
                        $message = get_translated_tempcode($myrow['p_post'], $GLOBALS['FORUM_DB']);
                    }
                }
                $temp['message'] = $message;
                $temp['message_comcode'] = get_translated_text($myrow['p_post'], $GLOBALS['FORUM_DB']);
                $temp['user'] = $myrow['p_poster'];
                if ($myrow['p_poster_name_if_guest'] != '') {
                    $temp['username'] = $myrow['p_poster_name_if_guest'];
                }
                $temp['date'] = $myrow['p_time'];
            }
            $out[] = $temp;
        }
    }
    if ($mark_read) {
        require_code('ocf_topics');
        ocf_ping_topic_read($topic_id);
    }
    return $out;
}
Beispiel #7
0
/**
 * Turn an ocFilter (a filter specifying which records to match) into an SQL query fragment.
 *
 * @param  string		The filter
 * @param  string		The database's ID field for the record-set we're matching
 * @param  ?string	The database's table that contains parent/child relationships in the record-set's category-set (the category-set is equal to the record-set if we're matching categories, but not if we're matching entries) (NULL: don't support subtree [*-style] searches)
 * @param  ?string	The database's field name for the category-set's parent-category-ID (NULL: don't support subtree [*-style] searches beyond the tree base)
 * @param  ?string	The database's field name for the record-set's container-category specifier (NULL: don't support subtree [*-style] searches)
 * @param  ?string	The database's field name for the category-set's category-ID (NULL: don't support subtree [*-style] searches beyond the tree base)
 * @param  boolean	Whether the record-set IDs are numeric
 * @param  boolean	Whether the category-set IDs are numeric
 * @param  ?object	Database connection to use (NULL: website)
 * @return string		SQL query fragment. Note that brackets will be put around this automatically if required, so there's no need to do this yourself.
 */
function ocfilter_to_sqlfragment($filter, $field_name, $parent_spec__table_name = NULL, $parent_spec__parent_name = NULL, $parent_field_name = NULL, $parent_spec__field_name = NULL, $numeric_record_set_ids = true, $numeric_category_set_ids = true, $db = NULL)
{
    if (is_null($db)) {
        $db = $GLOBALS['SITE_DB'];
    }
    if ($filter == '') {
        return '1=2';
    }
    if ($filter == '*') {
        return '1=1';
    }
    if ($parent_spec__table_name !== 'catalogue_categories') {
        if ($filter == strval(db_get_first_id()) . '*') {
            return '1=1';
        }
    }
    if (is_null($parent_spec__table_name)) {
        if (!is_null($parent_spec__parent_name) || !is_null($parent_field_name) || !is_null($parent_spec__field_name)) {
            fatal_exit(do_lang_tempcode('INTERNAL_ERROR'));
        }
    }
    $out_or = '';
    $out_and = '';
    $cached_mappings = mixed();
    $tokens = explode(',', $filter);
    $matches = array();
    foreach ($tokens as $token) {
        $token = trim($token);
        if ($token == '*') {
            if ($out_or != '') {
                $out_or .= ' OR ';
            }
            $out_or .= '1=1';
        } elseif (preg_match('#^\\!(.+)$#', $token, $matches) != 0) {
            if ($out_and != '') {
                $out_and .= ' AND ';
            }
            $out_and .= _ocfilter_neq($field_name, $matches[1], $numeric_record_set_ids);
        } elseif ($numeric_record_set_ids && preg_match('#^(\\d+)\\-(\\d+)$#', $token, $matches) != 0) {
            for ($i = intval($matches[1]); $i <= intval($matches[2]); $i++) {
                if ($out_or != '') {
                    $out_or .= ' OR ';
                }
                $out_or .= _ocfilter_eq($field_name, strval($i), $numeric_record_set_ids);
            }
        } elseif ($numeric_record_set_ids && preg_match('#^(\\d+)\\+$#', $token, $matches) != 0) {
            if ($out_or != '') {
                $out_or .= ' OR ';
            }
            $out_or .= $field_name . '>=' . strval(intval($matches[1]));
        } elseif (preg_match('#^(.+)\\*$#', $token, $matches) != 0 && $parent_spec__parent_name !== NULL) {
            if ($parent_spec__table_name == 'catalogue_categories' && db_has_subqueries($db->connection_read)) {
                /*static $counter=0;
                		$out_join.=' JOIN '.$db->get_table_prefix().'catalogue_cat_treecache t'.strval($counter).' ON t'.strval($counter).'.cc_id='.$parent_field_name.' AND t'.strval($counter).'.cc_ancestor_id='.strval(intval($matches[1]));
                		$counter++;*/
                // MySQL should be smart enough to not enumerate the 'IN' clause here, which would be bad - instead it can jump into the embedded WHERE clause on each test iteration
                $this_details = $db->query_select('catalogue_categories cc JOIN ' . $db->get_table_prefix() . 'catalogues c ON c.c_name=cc.c_name', array('cc_parent_id', 'cc.c_name', 'c_is_tree'), array('id' => intval($matches[1])), '', 1);
                if ($this_details[0]['c_is_tree'] == 0) {
                    $out_or .= _ocfilter_eq($parent_field_name, $matches[1], $numeric_category_set_ids);
                } elseif (is_null($this_details[0]['cc_parent_id'])) {
                    $out_or .= db_string_equal_to('c_name', $this_details[0]['c_name']);
                } else {
                    $out_or .= $parent_field_name . ' IN (SELECT cc_id FROM ' . $db->get_table_prefix() . 'catalogue_cat_treecache WHERE cc_ancestor_id=' . strval(intval($matches[1])) . ')';
                }
            } else {
                $subtree = _ocfilter_subtree_fetch($matches[1], $parent_spec__table_name, $parent_spec__parent_name, $parent_spec__field_name, $numeric_category_set_ids, $db, $cached_mappings);
                foreach ($subtree as $ii) {
                    if ($out_or != '') {
                        $out_or .= ' OR ';
                    }
                    $out_or .= _ocfilter_eq($parent_field_name, is_integer($ii) ? strval($ii) : $ii, $numeric_category_set_ids);
                }
            }
        } elseif (preg_match('#^(.+)\\~$#', $token, $matches) != 0 && $parent_spec__parent_name !== NULL) {
            $subtree = _ocfilter_subtree_fetch($matches[1], $parent_spec__table_name, $parent_spec__parent_name, $parent_spec__field_name, $numeric_category_set_ids, $db, $cached_mappings);
            foreach ($subtree as $ii) {
                if ($out_and != '') {
                    $out_and .= ' AND ';
                }
                $out_and .= _ocfilter_neq($parent_field_name, is_integer($ii) ? strval($ii) : $ii, $numeric_category_set_ids);
            }
        } else {
            if ($out_or != '') {
                $out_or .= ' OR ';
            }
            $out_or .= _ocfilter_eq($field_name, $token, $numeric_record_set_ids);
        }
    }
    if ($out_or == '') {
        return $out_and == '' ? '0=1' : $out_and;
    }
    if ($out_and == '') {
        return $out_or == '' ? '0=1' : '(' . $out_or . ')';
    }
    return '(' . $out_or . ') AND (' . $out_and . ')';
}
 /**
  * Standard modular run function for ajax-tree hooks. Generates XML for a tree list, which is interpreted by Javascript and expanded on-demand (via new calls).
  *
  * @param  ?ID_TEXT		The ID to do under (NULL: root)
  * @param  array			Options being passed through
  * @param  ?ID_TEXT		The ID to select by default (NULL: none)
  * @return string			XML in the special category,entry format
  */
 function run($id, $options, $default = NULL)
 {
     unset($options);
     require_code('cedi');
     require_lang('cedi');
     $cedi_seen = array();
     $tree = get_cedi_page_tree($cedi_seen, is_null($id) ? NULL : intval($id), NULL, NULL, true, false, is_null($id) ? 0 : 1);
     $stripped_id = $id;
     $out = '';
     if (!has_actual_page_access(NULL, 'cedi')) {
         $tree = array();
     }
     foreach ($tree as $t) {
         $_id = strval($t['id']);
         if ($stripped_id === $_id) {
             continue;
         }
         // Possible when we look under as a root
         $title = $t['title'];
         $has_children = $t['child_count'] != 0;
         $selectable = true;
         $tag = 'category';
         // category
         $out .= '<' . $tag . ' id="' . $_id . '" title="' . xmlentities($title) . '" has_children="' . ($has_children ? 'true' : 'false') . '" selectable="' . ($selectable ? 'true' : 'false') . '"></' . $tag . '>';
     }
     if (is_null($id)) {
         if (!db_has_subqueries($GLOBALS['SITE_DB']->connection_read)) {
             $where = '';
             $cedi_seen = array();
             get_cedi_page_tree($cedi_seen, is_null($id) ? NULL : intval($id));
             // To build up $cedi_seen
             foreach ($cedi_seen as $seen) {
                 if ($where != '') {
                     $where .= ' AND ';
                 }
                 $where .= 'p.id<>' . strval((int) $seen);
             }
             $orphans = $GLOBALS['SITE_DB']->query('SELECT p.id,text_original,p.title FROM ' . get_table_prefix() . 'seedy_pages p LEFT JOIN ' . get_table_prefix() . 'translate t ON ' . db_string_equal_to('language', user_lang()) . ' AND t.id=p.title WHERE ' . $where . ' ORDER BY add_date DESC', 50);
         } else {
             $orphans = $GLOBALS['SITE_DB']->query('SELECT p.id,text_original,p.title FROM ' . get_table_prefix() . 'seedy_pages p LEFT JOIN ' . get_table_prefix() . 'translate t ON ' . db_string_equal_to('language', user_lang()) . ' AND t.id=p.title WHERE NOT EXISTS(SELECT * FROM ' . get_table_prefix() . 'seedy_children WHERE child_id=p.id) ORDER BY add_date DESC', 50);
             if (count($orphans) < 50) {
                 global $M_SORT_KEY;
                 $M_SORT_KEY = 'text_original';
                 usort($orphans, 'multi_sort');
             }
         }
         foreach ($orphans as $orphan) {
             if (!has_category_access(get_member(), 'seedy_page', strval($orphan['id']))) {
                 continue;
             }
             if ($orphan['id'] == db_get_first_id()) {
                 continue;
             }
             if ($GLOBALS['RECORD_LANG_STRINGS_CONTENT'] || is_null($orphan['text_original'])) {
                 $orphan['text_original'] = get_translated_text($orphan['title']);
             }
             $_id = strval($orphan['id']);
             $title = $orphan['text_original'];
             $has_children = $GLOBALS['SITE_DB']->query_value('seedy_children', 'COUNT(*)', array('parent_id' => $orphan['id'])) != 0;
             $selectable = true;
             $tag = 'category';
             // category
             $out .= '<' . $tag . ' id="' . $_id . '" title="' . xmlentities($title) . '" has_children="' . ($has_children ? 'true' : 'false') . '" selectable="' . ($selectable ? 'true' : 'false') . '"></' . $tag . '>';
         }
     }
     $tag = 'result';
     // result
     return '<' . $tag . '>' . $out . '</' . $tag . '>';
 }
Beispiel #9
0
 /**
  * The UI to do a search.
  *
  * @return tempcode		The UI
  */
 function form()
 {
     global $NON_CANONICAL_PARAMS;
     $id = get_param('id', '');
     $title = get_page_title('SEARCH_TITLE');
     require_code('templates_internalise_screen');
     if ($id != '') {
         require_code('hooks/modules/search/' . filter_naughty_harsh($id), true);
         $object = object_factory('Hook_search_' . filter_naughty_harsh($id));
         $info = $object->info();
         if (!is_null($info)) {
             $title = get_page_title('_SEARCH_TITLE', true, array($info['lang']));
         }
         breadcrumb_set_parents(array(array('_SELF:_SELF', do_lang_tempcode('SEARCH_FOR'))));
         breadcrumb_set_self($info['lang']);
         $under = get_param('search_under', '!', true);
         if (!is_null($info) && method_exists($object, 'get_tree')) {
             $object->get_tree($under);
         }
         if (!is_null($info)) {
             $test_tpl = internalise_own_screen($title);
         } else {
             $test_tpl = NULL;
         }
     } else {
         $test_tpl = internalise_own_screen($title);
     }
     if (is_object($test_tpl)) {
         return $test_tpl;
     }
     require_javascript('javascript_ajax');
     require_javascript('javascript_ajax_people_lists');
     $content = get_param('content', NULL, true);
     $user_label = do_lang_tempcode('SEARCH_USER');
     $days_label = do_lang_tempcode('SUBMITTED_WITHIN');
     $extra_sort_fields = array();
     if ($id != '') {
         $url_map = array('page' => '_SELF', 'type' => 'results', 'id' => $id, 'specific' => 1);
         $catalogue_name = get_param('catalogue_name', '');
         if ($catalogue_name != '') {
             $url_map['catalogue_name'] = $catalogue_name;
         }
         $force_non_tabular = get_param_integer('force_non_tabular', 0);
         if ($force_non_tabular == 1) {
             $url_map['force_non_tabular'] = 1;
         }
         $url = build_url($url_map, '_SELF', NULL, false, true);
         require_code('hooks/modules/search/' . filter_naughty_harsh($id), true);
         $object = object_factory('Hook_search_' . filter_naughty_harsh($id));
         $info = $object->info();
         if (is_null($info)) {
             warn_exit(do_lang_tempcode('SEARCH_HOOK_NOT_AVAILABLE'));
         }
         if (array_key_exists('user_label', $info)) {
             $user_label = $info['user_label'];
         }
         if (array_key_exists('days_label', $info)) {
             $days_label = $info['days_label'];
         }
         $extra_sort_fields = array_key_exists('extra_sort_fields', $info) ? $info['extra_sort_fields'] : array();
         $under = NULL;
         if (method_exists($object, 'ajax_tree')) {
             require_javascript('javascript_tree_list');
             require_javascript('javascript_more');
             $ajax = true;
             $under = get_param('search_under', '', true);
             list($ajax_hook, $ajax_options) = $object->ajax_tree();
             require_code('hooks/systems/ajax_tree/' . $ajax_hook);
             $tree_hook_object = object_factory('Hook_' . $ajax_hook);
             $simple_content = $tree_hook_object->simple(NULL, $ajax_options, preg_replace('#,.*$#', '', $under));
             $nice_label = $under;
             if (!is_null($under)) {
                 $simple_content_evaluated = $simple_content->evaluate();
                 $matches = array();
                 if (preg_match('#<option [^>]*value="' . str_replace('#', '\\#', preg_quote($under)) . '(' . (strpos($under, ',') === false ? ',' : '') . '[^"]*)?"[^>]*>([^>]* &gt; )?([^>]*)</option>#', $simple_content_evaluated, $matches) != 0) {
                     if (strpos($under, ',') === false) {
                         $under = $under . $matches[1];
                     }
                     $nice_label = trim($matches[3]);
                 }
             }
             require_code('form_templates');
             $tree = do_template('FORM_SCREEN_INPUT_TREE_LIST', array('_GUID' => '25368e562be3b4b9c6163aa008b47c91', 'TABINDEX' => strval(get_form_field_tabindex()), 'NICE_LABEL' => is_null($nice_label) || $nice_label == '-1' ? '' : $nice_label, 'END_OF_FORM' => true, 'REQUIRED' => '', 'USE_SERVER_ID' => false, 'NAME' => 'search_under', 'DEFAULT' => $under, 'HOOK' => $ajax_hook, 'ROOT_ID' => '', 'OPTIONS' => serialize($ajax_options)));
         } else {
             $ajax = false;
             $tree = form_input_list_entry('!', false, do_lang_tempcode('NA_EM'));
             if (method_exists($object, 'get_tree')) {
                 $under = get_param('search_under', '!', true);
                 $tree->attach($object->get_tree($under));
             }
         }
         $options = new ocp_tempcode();
         if (array_key_exists('special_on', $info)) {
             foreach ($info['special_on'] as $name => $display) {
                 $options->attach(do_template('SEARCH_FOR_SEARCH_DOMAIN_OPTION', array('_GUID' => 'c1853f42d0a110026453f8b94c9f623c', 'CHECKED' => is_null($content) || get_param_integer('option_' . $id . '_' . $name, 0) == 1, 'NAME' => 'option_' . $id . '_' . $name, 'DISPLAY' => $display)));
             }
         }
         if (array_key_exists('special_off', $info)) {
             foreach ($info['special_off'] as $name => $display) {
                 $options->attach(do_template('SEARCH_FOR_SEARCH_DOMAIN_OPTION', array('_GUID' => '2223ada7636c85e6879feb9a6f6885d2', 'CHECKED' => get_param_integer('option_' . $id . '_' . $name, 0) == 1, 'NAME' => 'option_' . $id . '_' . $name, 'DISPLAY' => $display)));
             }
         }
         if (method_exists($object, 'get_fields')) {
             $fields = $object->get_fields();
             foreach ($fields as $field) {
                 $options->attach(do_template('SEARCH_FOR_SEARCH_DOMAIN_OPTION' . $field['TYPE'], array('_GUID' => 'a223ada7636c85e6879feb9a6f6885d2', 'NAME' => 'option_' . $field['NAME'], 'DISPLAY' => $field['DISPLAY'], 'SPECIAL' => $field['SPECIAL'], 'CHECKED' => array_key_exists('checked', $field) ? $field['CHECKED'] : false)));
             }
         }
         $specialisation = do_template('SEARCH_ADVANCED', array('_GUID' => 'fad0c147b8291ba972f105c65715f1ac', 'AJAX' => $ajax, 'OPTIONS' => $options, 'TREE' => $tree, 'UNDERNEATH' => !is_null($under)));
     } else {
         $map = array('page' => '_SELF', 'type' => 'results');
         $under = get_param('search_under', '-1', true);
         if ($under != '-1') {
             $map['search_under'] = $under;
         }
         $url = build_url($map, '_SELF', NULL, false, true);
         $search_domains = new ocp_tempcode();
         $_search_domains = array();
         $_hooks = find_all_hooks('modules', 'search');
         foreach (array_keys($_hooks) as $hook) {
             require_code('hooks/modules/search/' . filter_naughty_harsh($hook));
             $object = object_factory('Hook_search_' . filter_naughty_harsh($hook), true);
             if (is_null($object)) {
                 continue;
             }
             $info = $object->info();
             if (is_null($info)) {
                 continue;
             }
             $NON_CANONICAL_PARAMS[] = 'search_' . $hook;
             $is_default_or_advanced = $info['default'] && $id == '' || $hook == $id;
             $checked = get_param_integer('search_' . $hook, is_null($content) || get_param_integer('all_defaults', 0) == 1 ? $is_default_or_advanced ? 1 : 0 : 0) == 1;
             $options = array_key_exists('special_on', $info) || array_key_exists('special_off', $info) || array_key_exists('extra_sort_fields', $info) || method_exists($object, 'get_fields') || method_exists($object, 'get_tree') || method_exists($object, 'get_ajax_tree') ? build_url(array('page' => '_SELF', 'id' => $hook), '_SELF', NULL, false, true) : new ocp_tempcode();
             $_search_domains[] = array('_GUID' => '3d3099872184923aec0f49388f52c750', 'ADVANCED_ONLY' => array_key_exists('advanced_only', $info) && $info['advanced_only'], 'CHECKED' => $checked, 'OPTIONS' => $options, 'LANG' => $info['lang'], 'NAME' => $hook);
         }
         global $M_SORT_KEY;
         $M_SORT_KEY = 'LANG';
         usort($_search_domains, 'multi_sort');
         foreach ($_search_domains as $sd) {
             $search_domains->attach(do_template('SEARCH_FOR_SEARCH_DOMAIN', $sd));
         }
         $specialisation = do_template('SEARCH_DOMAINS', array('_GUID' => '1fd8718b540ec475988070ee7a444dc1', 'SEARCH_DOMAINS' => $search_domains));
     }
     $author = get_param('author', '');
     $author_id = $author != '' ? $GLOBALS['FORUM_DRIVER']->get_member_from_username($author) : NULL;
     $days = get_param_integer('days', 60);
     $sort = get_param('sort', 'relevance');
     $direction = get_param('direction', 'DESC');
     if (!in_array(strtoupper($direction), array('ASC', 'DESC'))) {
         log_hack_attack_and_exit('ORDERBY_HACK');
     }
     $NON_CANONICAL_PARAMS[] = 'sort';
     $NON_CANONICAL_PARAMS[] = 'direction';
     $only_titles = get_param_integer('only_titles', 0) == 1;
     $search_under = get_param('search_under', '!', true);
     if ($search_under == '') {
         $search_under = '!';
     }
     $boolean_operator = get_param('conjunctive_operator', 'OR');
     $NON_CANONICAL_PARAMS[] = 'search_under';
     $NON_CANONICAL_PARAMS[] = 'all_defaults';
     $NON_CANONICAL_PARAMS[] = 'days';
     $NON_CANONICAL_PARAMS[] = 'only_titles';
     $NON_CANONICAL_PARAMS[] = 'conjunctive_operator';
     $NON_CANONICAL_PARAMS[] = 'boolean_search';
     $NON_CANONICAL_PARAMS[] = 'only_search_meta';
     $NON_CANONICAL_PARAMS[] = 'content';
     $NON_CANONICAL_PARAMS[] = 'author';
     $test = db_has_full_text($GLOBALS['SITE_DB']->connection_read);
     $old_mysql = !$test;
     $can_order_by_rating = db_has_subqueries($GLOBALS['SITE_DB']->connection_read);
     // Perform search, if we did one
     $out = NULL;
     $results_browser = '';
     $num_results = 0;
     if (!is_null($content)) {
         list($out, $results_browser, $num_results) = $this->results($id, $author, $author_id, $days, $sort, $direction, $only_titles, $search_under);
         if (has_zone_access(get_member(), 'adminzone')) {
             $admin_search_url = build_url(array('page' => 'admin', 'type' => 'search', 'search_content' => $content), 'adminzone');
             attach_message(do_lang_tempcode('ALSO_ADMIN_ZONE_SEARCH', escape_html($admin_search_url->evaluate())), 'inform');
         }
     }
     return do_template('SEARCH_FORM_SCREEN', array('_GUID' => '8bb208185740183323a6fe6e89d55de5', 'SEARCH_TERM' => is_null($content) ? '' : $content, 'NUM_RESULTS' => integer_format($num_results), 'CAN_ORDER_BY_RATING' => $can_order_by_rating, 'EXTRA_SORT_FIELDS' => $extra_sort_fields, 'USER_LABEL' => $user_label, 'DAYS_LABEL' => $days_label, 'BOOLEAN_SEARCH' => $this->_is_boolean_search(), 'AND' => $boolean_operator == 'AND', 'ONLY_TITLES' => $only_titles, 'DAYS' => is_null($days) ? '' : strval($days), 'SORT' => $sort, 'DIRECTION' => $direction, 'CONTENT' => $content, 'RESULTS' => $out, 'RESULTS_BROWSER' => $results_browser, 'OLD_MYSQL' => $old_mysql, 'TITLE' => $title, 'AUTHOR' => $author, 'SPECIALISATION' => $specialisation, 'URL' => $url));
 }
Beispiel #10
0
 /**
  * Standard modular new-style deep page-link finder function (does not return the main entry-points).
  *
  * @param  string  	Callback function to send discovered page-links to.
  * @param  MEMBER		The member we are finding stuff for (we only find what the member can view).
  * @param  integer	Code for how deep we are tunnelling down, in terms of whether we are getting entries as well as categories.
  * @param  string		Stub used to create page-links. This is passed in because we don't want to assume a zone or page name within this function.
  * @param  ?string	Where we're looking under (NULL: root of tree). We typically will NOT show a root node as there's often already an entry-point representing it.
  * @param  integer	Our recursion depth (used to calculate importance of page-link, used for instance by Google sitemap). Deeper is typically less important.
  * @param  ?array		Non-standard for API [extra parameter tacked on] (NULL: yet unknown). Contents of database table for performance.
  * @param  ?array		Non-standard for API [extra parameter tacked on] (NULL: yet unknown). Contents of database table for performance.
  */
 function get_sitemap_pagelinks($callback, $member_id, $depth, $pagelink_stub, $parent_pagelink = NULL, $recurse_level = 0, $category_data = NULL, $entry_data = NULL)
 {
     $parent_pagelink_orig = $parent_pagelink;
     // This is where we start
     if (is_null($parent_pagelink)) {
         $parent_pagelink = $pagelink_stub . ':misc';
         // This is the entry-point we're under
         $parent_attributes = array('id' => NULL, 'c_name' => '');
     } else {
         list(, $parent_attributes, ) = page_link_decode($parent_pagelink);
     }
     // We read in all data for efficiency
     if (is_null($category_data)) {
         $query = 'SELECT c_name,d.id,t.text_original AS title,cc_add_date AS edit_date';
         $lots = $GLOBALS['SITE_DB']->query_value_null_ok('catalogue_categories', 'COUNT(*)') > 1000 && db_has_subqueries($GLOBALS['SITE_DB']->connection_read);
         if ($lots) {
             $query .= ',NULL AS parent_id';
         } else {
             $query .= ',cc_parent_id AS parent_id';
         }
         $query .= ' FROM ' . get_table_prefix() . 'catalogue_categories d LEFT JOIN ' . get_table_prefix() . 'translate t ON ' . db_string_equal_to('language', user_lang()) . ' AND t.id=d.cc_title';
         $query .= ' WHERE d.c_name NOT LIKE \'' . db_encode_like('\\_%') . '\'';
         if ($lots) {
             $query .= ' AND EXISTS (SELECT * FROM ' . get_table_prefix() . 'catalogue_entries e WHERE e.cc_id=d.id)';
         }
         $category_data = list_to_map('id', $GLOBALS['SITE_DB']->query($query));
     }
     $query = 'SELECT c.* FROM ' . get_table_prefix() . 'catalogues c';
     if (can_arbitrary_groupby()) {
         $query .= ' JOIN ' . get_table_prefix() . 'catalogue_entries e ON c.c_name=e.c_name';
     }
     $query .= ' WHERE c.c_name NOT LIKE \'' . db_encode_like('\\_%') . '\'';
     if (can_arbitrary_groupby()) {
         $query .= ' GROUP BY e.cc_id';
     }
     $catalogues = list_to_map('c_name', $GLOBALS['SITE_DB']->query($query));
     if (!is_null($parent_pagelink_orig)) {
         $parent_attributes['c_name'] = $category_data[intval($parent_attributes['id'])]['c_name'];
     }
     // Subcategories
     foreach ($category_data as $row) {
         if (!is_null($row['parent_id']) && strval($row['parent_id']) == $parent_attributes['id'] || is_null($parent_pagelink_orig) && is_null($row['parent_id'])) {
             $pagelink = $pagelink_stub . 'category:' . strval($row['id']);
             if (__CLASS__ != '') {
                 $this->get_sitemap_pagelinks($callback, $member_id, $depth, $pagelink_stub, $pagelink, $recurse_level + 1, $category_data, $entry_data);
                 // Recurse
             } else {
                 call_user_func_array(__FUNCTION__, array($callback, $member_id, $depth, $pagelink_stub, $pagelink, $recurse_level + 1, $category_data, $entry_data));
                 // Recurse
             }
             if (has_category_access($member_id, 'catalogues_catalogue', $row['c_name']) && (get_value('disable_cat_cat_perms') === '1' || has_category_access($member_id, 'catalogues_category', strval($row['id'])))) {
                 call_user_func_array($callback, array($pagelink, $parent_pagelink, NULL, $row['edit_date'], max(0.7 - $recurse_level * 0.1, 0.3), $row['title']));
                 // Callback
             } else {
                 call_user_func_array($callback, array($pagelink, $parent_pagelink, NULL, $row['edit_date'], max(0.7 - $recurse_level * 0.1, 0.3), do_lang('UNKNOWN'), false));
                 // Callback
             }
         }
     }
     // Entries
     if ($depth >= DEPTH__ENTRIES && has_category_access($member_id, 'catalogues_catalogue', $parent_attributes['c_name']) && (get_value('disable_cat_cat_perms') === '1' || has_category_access($member_id, 'catalogues_category', $parent_attributes['id']))) {
         require_code('catalogues');
         $start = 0;
         do {
             $entry_data = $GLOBALS['SITE_DB']->query_select('catalogue_entries d', array('c_name', 'id', 'cc_id AS category_id', 'ce_add_date AS add_date', 'ce_edit_date AS edit_date', 'd.*'), array('cc_id' => intval($parent_attributes['id'])), '', 500, $start);
             foreach ($entry_data as $row) {
                 $map = get_catalogue_entry_map($row, $catalogues[$row['c_name']], 'CATEGORY', 'DEFAULT', NULL, NULL, array(0));
                 $row['title'] = is_object($map['FIELD_0_PLAIN']) ? $map['FIELD_0_PLAIN']->evaluate() : $map['FIELD_0_PLAIN'];
                 $pagelink = $pagelink_stub . 'entry:' . strval($row['id']);
                 call_user_func_array($callback, array($pagelink, $parent_pagelink, $row['add_date'], $row['edit_date'], 0.2, $row['title']));
                 // Callback
             }
             $start += 500;
         } while (array_key_exists(0, $entry_data));
     }
 }
Beispiel #11
0
/**
 * Get some rows, queried from the database according to the search parameters.
 *
 * @param  ?ID_TEXT		The META type used by our content (NULL: Cannot support META search)
 * @param  ?ID_TEXT		The name of the field that retrieved META IDs will relate to (NULL: Cannot support META search)
 * @param  string			Search string
 * @param  boolean		Whether to do a boolean search.
 * @param  ID_TEXT		Boolean operator
 * @set OR AND
 * @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 to only search titles (as opposed to both titles and content)
 * @param  ID_TEXT		The table name
 * @param  array			The translateable fields to search over (or an ! which is skipped). The first of these must be the title field or an '!'; if it is '!' then the title field will be the first raw-field
 * @param  string			The WHERE clause
 * @param  string			The WHERE clause that applies specifically for content (this will be duplicated to check against multiple fields). ? refers to the yet-unknown field name
 * @param  ID_TEXT		What to order by
 * @param  string			What to select
 * @param  ?array			The non-translateable fields to search over (NULL: there are none)
 * @param  ?string		The permission module to check category access for (NULL: none)
 * @param  ?string		The field that specifies the permissions ID to check category access for (NULL: none)
 * @param  boolean		Whether the permissions field is a string
 * @return array			The rows found
 */
function get_search_rows($meta_type, $meta_id_field, $content, $boolean_search, $boolean_operator, $only_search_meta, $direction, $max, $start, $only_titles, $table, $fields, $where_clause, $content_where, $order, $select = '*', $raw_fields = NULL, $permissions_module = NULL, $permissions_field = NULL, $permissions_field_is_string = false)
{
    if (substr($where_clause, 0, 5) == ' AND ') {
        $where_clause = substr($where_clause, 5);
    }
    if (substr($where_clause, -5) == ' AND ') {
        $where_clause = substr($where_clause, 0, strlen($where_clause) - 5);
    }
    $where_alternative_matches = array();
    $had_limit_imposed = false;
    if (!is_null($permissions_module) && !$GLOBALS['FORUM_DRIVER']->is_super_admin(get_member())) {
        $g_or = _get_where_clause_groups(get_member());
        // this destroys mysqls query optimiser by forcing complexed OR's into the join, so we'll do this in PHP code
        //		$table.=' LEFT JOIN '.$GLOBALS['SITE_DB']->get_table_prefix().'group_category_access z ON ('.db_string_equal_to('z.module_the_name',$permissions_module).' AND z.category_name='.$permissions_field.(($g_or!='')?(' AND '.str_replace('group_id','z.group_id',$g_or)):'').')';
        //		$where_clause.=' AND ';
        //		$where_clause.='z.category_name IS NOT NULL';
        $cat_access = list_to_map('category_name', $GLOBALS['SITE_DB']->query('SELECT category_name FROM ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'group_category_access WHERE ' . db_string_equal_to('module_the_name', $permissions_module) . ($g_or != '' ? ' AND (' . $g_or . ')' : '')));
    }
    if ($only_titles && array_key_exists(0, $fields) && $fields[0] == '') {
        return array();
    }
    if (is_null($raw_fields)) {
        $raw_fields = array();
    }
    $db = substr($table, 0, 2) != 'f_' ? $GLOBALS['SITE_DB'] : $GLOBALS['FORUM_DB'];
    // This is so for example catalogue_entries.php can use brackets in it's table specifier whilst avoiding the table prefix after the first bracket. A bit weird, but that's our convention and it does save a small amount of typing
    $table_clause = $db->get_table_prefix() . ($table[0] == '(' ? substr($table, 1) : $table);
    if ($table[0] == '(') {
        $table_clause = '(' . $table_clause;
    }
    $t_rows = array();
    $t_count = 0;
    // Rating ordering, via special encoding
    if (substr($order, 0, 7) == '_rating') {
        list(, $rating_type, $meta_rating_id_field) = explode(':', $order);
        $select .= ',(SELECT AVG(rating) FROM ' . get_table_prefix() . 'rating WHERE ' . db_string_equal_to('rating_for_type', $rating_type) . ' AND rating_for_id=' . $meta_rating_id_field . ') AS compound_rating';
        $order = 'compound_rating';
    }
    $translate_join_type = get_value('alternate_search_join_type') === '1' ? 'LEFT JOIN' : 'JOIN';
    // Defined-keywords/tags search
    if (get_param_integer('keep_just_show_query', 0) == 0 && !is_null($meta_type) && $content != '') {
        $keywords_where = preg_replace('#\\?#', 'tm.text_original', build_content_where($content, $boolean_search, $boolean_operator, true));
        $keywords_where = str_replace(' AND (tm.text_original IS NOT NULL)', '', $keywords_where);
        // Not needed for translate joins, as these won't be NULL's. Fixes performance issue.
        if ($keywords_where != '') {
            if ($meta_id_field == 'the_zone:the_page') {
                $meta_join = 'm.meta_for_id=CONCAT(r.the_zone,\':\',r.the_page)';
            } else {
                $meta_join = 'm.meta_for_id=r.' . $meta_id_field;
            }
            $extra_join = '';
            foreach ($fields as $i => $field) {
                if ($field == '' || $field == '!' || strpos($select, 't1.text_original') === false) {
                    continue;
                }
                $extra_join .= ' ' . $translate_join_type . ' ' . $db->get_table_prefix() . 'translate t' . strval($i) . ' ON t' . strval($i) . '.id=' . $field . ' AND ' . db_string_equal_to('t' . strval($i) . '.language', user_lang());
            }
            if (!db_has_subqueries($db->connection_read) || true) {
                $_keywords_query = $table_clause . ' LEFT JOIN ' . $db->get_table_prefix() . 'seo_meta m ON (' . db_string_equal_to('m.meta_for_type', $meta_type) . ' AND ' . $meta_join . ') ' . $translate_join_type . ' ' . $db->get_table_prefix() . 'translate tm ON tm.id=m.meta_keywords AND ' . db_string_equal_to('tm.language', user_lang()) . $extra_join;
                $_keywords_query .= ' WHERE ' . $keywords_where;
                $_keywords_query .= $where_clause != '' ? ' AND ' . $where_clause : '';
            } else {
                $_keywords_query = $table_clause . ' LEFT JOIN ' . $db->get_table_prefix() . 'seo_meta m ON (' . db_string_equal_to('m.meta_for_type', $meta_type) . ' AND ' . $meta_join . ') ' . $translate_join_type . ' ' . $db->get_table_prefix() . 'translate tm ON tm.id=m.meta_keywords AND ' . db_string_equal_to('tm.language', user_lang()) . $extra_join;
                $_keywords_query .= ' WHERE ' . $keywords_where;
                $_keywords_query .= $where_clause != '' ? ' AND tm.id IN (SELECT m.id FROM ' . $table_clause . ' LEFT JOIN ' . $db->get_table_prefix() . 'seo_meta m ON (' . db_string_equal_to('m.meta_for_type', $meta_type) . ' AND ' . $meta_join . ') ' . $translate_join_type . ' ' . $db->get_table_prefix() . 'translate tm ON tm.id=m.meta_keywords AND ' . db_string_equal_to('tm.language', user_lang()) . ' WHERE ' . $where_clause . ' AND ' . $keywords_where . ')' : '';
            }
            $keywords_query = 'SELECT ' . $select . ' FROM ' . $_keywords_query;
            $_count_query_keywords_search = 'SELECT COUNT(*) FROM ' . $_keywords_query;
            $group_by_ok = can_arbitrary_groupby() && $meta_id_field === 'id';
            if (strpos($table, ' LEFT JOIN') === false) {
                $group_by_ok = false;
            }
            // Don't actually need to do a group by, as no duplication possible
            $keywords_query .= $group_by_ok ? ' GROUP BY r.id' : '';
            if ($order != '' && $order . ' ' . $direction != 'contextual_relevance DESC') {
                $keywords_query .= ' ORDER BY ' . $order;
                if ($direction == 'DESC') {
                    $keywords_query .= ' DESC';
                }
            }
            if ($group_by_ok) {
                $_count_query_keywords_search = str_replace('COUNT(*)', 'COUNT(DISTINCT r.id)', $_count_query_keywords_search);
            }
            $t_keyword_search_rows_count = $db->query_value_null_ok_full($_count_query_keywords_search);
            if ($t_keyword_search_rows_count > 500) {
                $t_keyword_search_rows = $db->query($keywords_query, $max + $start);
                $had_limit_imposed = true;
            } else {
                $t_keyword_search_rows = $db->query($keywords_query);
            }
            $t_count += $t_keyword_search_rows_count;
            $t_rows = array_merge($t_rows, $t_keyword_search_rows);
        } else {
            $_count_query_keywords_search = NULL;
        }
    } else {
        $_count_query_keywords_search = NULL;
    }
    $orig_table_clause = $table_clause;
    // Main content search
    if (!$only_search_meta) {
        if ($content_where != '' || preg_match('#t\\d+\\.text_original#', $where_clause) != 0 || preg_match('#t\\d+\\.text_original#', $select) != 0) {
            // Each of the fields represents an 'OR' match, so we put it together into a list ($where_alternative_matches) of specifiers for each. Hopefully we will 'UNION' them rather than 'OR' them as it is much more efficient in terms of table index usage
            $where_alternative_matches = array();
            foreach ($fields as $i => $field) {
                if (strpos($select, 't' . strval($i) . '.text_original') !== false || strpos($where_clause, 't' . strval($i) . '.text_original') !== false) {
                    $tc_add = ' ' . $translate_join_type . ' ' . $db->get_table_prefix() . 'translate t' . strval($i) . ' ON t' . strval($i) . '.id=' . $field . ' AND ' . db_string_equal_to('t' . strval($i) . '.language', user_lang());
                    $orig_table_clause .= $tc_add;
                }
            }
            foreach ($fields as $i => $field) {
                if ($field == '' || $field == '!') {
                    continue;
                }
                if ($field == $order) {
                    $order = 't' . $i . '.text_original';
                }
                // Ah, remap to the textual equivalent then
                $tc_add = ' ' . $translate_join_type . ' ' . $db->get_table_prefix() . 'translate t' . strval($i) . ' ON t' . strval($i) . '.id=' . $field . ' AND ' . db_string_equal_to('t' . strval($i) . '.language', user_lang());
                if (strpos($orig_table_clause, $tc_add) !== false) {
                    $tc_add = '';
                }
                if (!$only_titles || $i == 0) {
                    $where_clause_2 = preg_replace('#\\?#', 't' . strval($i) . '.text_original', $content_where);
                    $where_clause_2 = str_replace(' AND (t' . strval($i) . '.text_original IS NOT NULL)', '', $where_clause_2);
                    // Not needed for translate joins, as these won't be NULL's. Fixes performance issue.
                    $where_clause_3 = $where_clause;
                    if ($table == 'f_members' && substr($field, 0, 6) == 'field_' && db_has_subqueries($db->connection_read)) {
                        $where_clause_3 .= ($where_clause == '' ? '' : ' AND ') . 'NOT EXISTS (SELECT * FROM ' . $db->get_table_prefix() . 'f_cpf_perms cpfp WHERE cpfp.member_id=r.id AND cpfp.field_id=' . substr($field, 6) . ' AND cpfp.guest_view=0)';
                    }
                    if ($order == '' && db_has_expression_ordering($db->connection_read) && $content_where != '') {
                        $_select = preg_replace('#\\?#', 't' . strval($i) . '.text_original', $content_where) . ' AS contextual_relevance';
                        $_select = str_replace(' AND (t' . strval($i) . '.text_original IS NOT NULL)', '', $_select);
                        // Not needed for translate joins, as these won't be NULL's. Fixes performance issue.
                    } else {
                        $_select = '1';
                    }
                    $_table_clause = $orig_table_clause . $tc_add;
                    $where_alternative_matches[] = array($where_clause_2, $where_clause_3, $_select, $_table_clause, 't' . strval($i));
                } else {
                    $_table_clause = $orig_table_clause . $tc_add;
                    $where_alternative_matches[] = array('1=0', '', '1', $_table_clause, 't' . strval($i));
                }
            }
            if ($content_where != '') {
                foreach ($raw_fields as $i => $field) {
                    if ($only_titles && $i != 0) {
                        break;
                    }
                    $where_clause_2 = preg_replace('#\\?#', $field, $content_where);
                    $where_clause_3 = $where_clause;
                    if ($table == 'f_members' && substr($field, 0, 6) == 'field_' && db_has_subqueries($db->connection_read)) {
                        $where_clause_3 .= ($where_clause == '' ? '' : ' AND ') . 'NOT EXISTS (SELECT * FROM ' . $db->get_table_prefix() . 'f_cpf_perms cpfp WHERE cpfp.member_id=r.id AND cpfp.field_id=' . substr($field, 6) . ' AND cpfp.guest_view=0)';
                    }
                    if ($order == '' && db_has_expression_ordering($db->connection_read) && $content_where != '') {
                        $_select = preg_replace('#\\?#', $field, $content_where) . ' AS contextual_relevance';
                    } else {
                        $_select = '1';
                    }
                    $_table_clause = $orig_table_clause;
                    $where_alternative_matches[] = array($where_clause_2, $where_clause_3, $_select, $_table_clause, NULL);
                }
            }
        }
        if (count($where_alternative_matches) == 0) {
            $where_alternative_matches[] = array($where_clause, '', '', $table_clause, NULL);
        } else {
            if ($order == '' && db_has_expression_ordering($db->connection_read) && $content_where != '') {
                $order = 'contextual_relevance DESC';
            }
        }
        // Work out main query
        global $SITE_INFO;
        if (isset($SITE_INFO['mysql_old']) && $SITE_INFO['mysql_old'] == '1' || !isset($SITE_INFO['mysql_old']) && is_file(get_file_base() . '/mysql_old')) {
            $_query = '';
            foreach ($where_alternative_matches as $parts) {
                list($where_clause_2, $where_clause_3, $_select, , ) = $parts;
                $where_clause_3 = $where_clause_2 . ($where_clause_3 == '' ? '' : ($where_clause_2 == '' ? '' : ' AND ') . $where_clause_3);
                $select .= ($_select == '' ? '' : ',') . $_select;
                $_query .= $where_clause_3 != '' ? ($_query == '' ? ' WHERE ' : ' OR ') . $where_clause_3 : '';
            }
            $query = 'SELECT ' . $select . ' FROM ' . $table_clause . $_query;
        } else {
            $query = '';
            foreach ($where_alternative_matches as $parts) {
                list($where_clause_2, $where_clause_3, $_select, $_table_clause, $tid) = $parts;
                if ($query != '') {
                    $query .= ' LIMIT ' . strval($max);
                    $query .= ' UNION ';
                }
                if (!db_has_subqueries($db->connection_read) || is_null($tid) || $content_where == '' || true) {
                    $where_clause_3 = $where_clause_2 . ($where_clause_3 == '' ? '' : ($where_clause_2 == '' ? '' : ' AND ') . $where_clause_3);
                    $query .= 'SELECT ' . $select . ($_select == '' ? '' : ',') . $_select . ' FROM ' . $_table_clause . ($where_clause_3 == '' ? '' : ' WHERE ' . $where_clause_3);
                } else {
                    $query .= 'SELECT ' . $select . ($_select == '' ? '' : ',') . $_select . ' FROM ' . $_table_clause;
                    if ($where_clause_2 != '' || $where_clause_3 != '') {
                        $query .= ' WHERE ' . $where_clause_2;
                        $query .= $where_clause_3 != '' ? ($where_clause_2 == '' ? '' : ' AND ') . $tid . '.id IN (SELECT ' . $tid . '.id FROM ' . $_table_clause . ' WHERE ' . $where_clause_2 . ($where_clause_3 == '' ? '' : ($where_clause_2 == '' ? '' : ' AND ') . $where_clause_3) . ')' : '';
                    }
                }
            }
        }
        // Work out COUNT(*) query using one of a few possible methods. It's not efficient and stops us doing proper merge-sorting between content types (and possible not accurate - if we use an efficient but non-deduping COUNT strategy) if we have to use this, so we only do it if there are too many rows to fetch in one go.
        $_query = '';
        if (isset($SITE_INFO['mysql_old']) && $SITE_INFO['mysql_old'] == '1' || !isset($SITE_INFO['mysql_old']) && is_file(get_file_base() . '/mysql_old') || strpos(get_db_type(), 'mysql') === false) {
            foreach ($where_alternative_matches as $parts) {
                list($where_clause_2, $where_clause_3, , $_table_clause, $tid) = $parts;
                if (!db_has_subqueries($db->connection_read) || is_null($tid) || $content_where == '' || true) {
                    $where_clause_3 = $where_clause_2 . ($where_clause_3 == '' ? '' : ($where_clause_2 == '' ? '' : ' AND ') . $where_clause_3);
                    $_query .= $where_clause_3 != '' ? ($_query == '' ? ' WHERE ' : ' OR ') . $where_clause_3 : '';
                } else {
                    if ($where_clause_2 != '' || $where_clause_3 != '') {
                        $_query .= ($_query == '' ? ' WHERE ' : ' OR ') . $where_clause_2;
                        $_query .= $where_clause_3 != '' ? ($where_clause_2 == '' ? '' : ' AND ') . $tid . '.id IN (SELECT ' . $tid . '.id FROM ' . $_table_clause . ' WHERE ' . $where_clause_2 . ($where_clause_3 == '' ? '' : ($where_clause_2 == '' ? '' : ' AND ') . $where_clause_3) . ')' : '';
                    }
                }
            }
            $_count_query_main_search = 'SELECT COUNT(*) FROM ' . $table_clause . $_query;
        } else {
            foreach ($where_alternative_matches as $parts) {
                list($where_clause_2, $where_clause_3, $_select, $_table_clause, $tid) = $parts;
                if ($_query != '') {
                    $_query .= '+';
                }
                if (!db_has_subqueries($db->connection_read) || is_null($tid) || $content_where == '' || true) {
                    $where_clause_3 = $where_clause_2 . ($where_clause_3 == '' ? '' : ($where_clause_2 == '' ? '' : ' AND ') . $where_clause_3);
                    $_query .= '(SELECT COUNT(*) FROM ' . $_table_clause . ($where_clause_3 == '' ? '' : ' WHERE ' . $where_clause_3) . ')';
                } else {
                    $_query .= '(SELECT COUNT(*) FROM ' . $_table_clause;
                    if ($where_clause_2 != '' || $where_clause_3 != '') {
                        $_query .= ' WHERE ' . $where_clause_2;
                        $_query .= $where_clause_3 != '' ? ($where_clause_2 == '' ? '' : ' AND ') . $tid . '.id IN (SELECT ' . $tid . '.id FROM ' . $_table_clause . ' WHERE ' . $where_clause_2 . ($where_clause_3 == '' ? '' : ($where_clause_2 == '' ? '' : ' AND ') . $where_clause_3) . ')' : '';
                    }
                    $_query .= ')';
                }
            }
            $_count_query_main_search = 'SELECT (' . $_query . ')';
        }
        $group_by_ok = can_arbitrary_groupby() && $meta_id_field === 'id';
        if (strpos($table, ' LEFT JOIN') === false) {
            $group_by_ok = false;
        }
        // Don't actually need to do a group by, as no duplication possible. We want to avoid GROUP BY as it forces MySQL to create a temporary table, slowing things down a lot.
        $query .= $group_by_ok ? ' GROUP BY r.id' : '';
        if ($order != '' && $order . ' ' . $direction != 'contextual_relevance DESC') {
            $query .= ' ORDER BY ' . $order;
            if ($direction == 'DESC' && substr($order, -4) != ' ASC' && substr($order, -5) != ' DESC') {
                $query .= ' DESC';
            }
        }
        if (get_param_integer('keep_show_query', 0) == 1) {
            attach_message($query, 'inform');
        }
        if (get_param_integer('keep_just_show_query', 0) == 1) {
            @ini_set('ocproducts.xss_detect', '0');
            header('Content-type: text/plain; charset=' . get_charset());
            exit($query);
        }
        if ($group_by_ok) {
            $_count_query_main_search = str_replace('COUNT(*)', 'COUNT(DISTINCT r.id)', $_count_query_main_search);
        }
        $t_main_search_rows_count = $db->query_value_null_ok_full($_count_query_main_search);
        if ($t_main_search_rows_count > 500) {
            $t_main_search_rows = $db->query($query, $max + $start, NULL, false, true);
            $had_limit_imposed = true;
        } else {
            $t_main_search_rows = $db->query($query, NULL, NULL, false, true);
        }
        if ($t_main_search_rows === NULL) {
            $t_main_search_rows = array();
        }
        // In case of a failed search query
        $t_count += $t_main_search_rows_count;
        $t_rows = array_merge($t_rows, $t_main_search_rows);
    } else {
        $t_main_search_rows = array();
    }
    // Clean results and return
    // NB: We don't use the count_query's any more (except when using huge data sets, see above), because you can't actually just add them because they overlap. So instead we fetch all results and throw some away.
    $t_rows = array_merge($t_rows, $t_main_search_rows);
    if (count($t_rows) > 0) {
        $t_rows_new = array();
        if (array_key_exists('id', $t_rows[0]) || array_key_exists('_primary_id', $t_rows[0])) {
            $done = array();
            foreach ($t_rows as $t_row) {
                if (array_key_exists('id', $t_row)) {
                    if (array_key_exists($t_row['id'], $done)) {
                        continue;
                    }
                    $done[$t_row['id']] = 1;
                } elseif (array_key_exists('_primary_id', $t_row)) {
                    if (array_key_exists($t_row['_primary_id'], $done)) {
                        continue;
                    }
                    $done[$t_row['_primary_id']] = 1;
                }
                $t_rows_new[] = $t_row;
            }
        } else {
            foreach ($t_rows as $t_row) {
                unset($t_row['contextual_relevance']);
                foreach ($t_rows_new as $_t_row) {
                    if ($_t_row == $t_row || array_key_exists('id', $t_row) && array_key_exists('id', $_t_row) && !array_key_exists('_primary_id', $t_row) && !array_key_exists('_primary_id', $_t_row) && $t_row['id'] == $_t_row['id'] || array_key_exists('_primary_id', $t_row) && array_key_exists('_primary_id', $_t_row) && $t_row['_primary_id'] == $_t_row['_primary_id']) {
                        continue 2;
                    }
                }
                $t_rows_new[] = $t_row;
            }
        }
        $t_rows = $t_rows_new;
    }
    if (get_param_integer('keep_show_query', 0) == 1) {
        if (array_key_exists(0, $t_rows) && array_key_exists('id', $t_rows[0])) {
            $results = var_export(array_unique(collapse_1d_complexity('id', $t_rows)), true);
        } else {
            $results = var_export($t_rows, true);
        }
        attach_message(do_lang('_RESULTS') . ': ' . $results, 'inform');
    }
    if (isset($cat_access)) {
        $before = count($t_rows);
        foreach ($t_rows as $i => $row) {
            if (!array_key_exists(@strval($row[$permissions_field]), $cat_access)) {
                unset($t_rows[$i]);
            }
        }
    }
    $final_result_rows = $t_rows;
    if (!$had_limit_imposed) {
        // More accurate, as filtered for dupes
        $t_count = count($t_rows);
    }
    $GLOBALS['TOTAL_RESULTS'] += $t_count;
    array_splice($final_result_rows, $max * 2 + $start);
    // We return more than max in case our search hook does some extra in-code filtering (Catalogues, Comcode pages). It shouldn't really but sometimes it has to, and it certainly shouldn't filter more than 50%. Also so our overall ordering can be better.
    return $final_result_rows;
}