diff --git a/include/search_filters.inc.php b/include/search_filters.inc.php
new file mode 100644
index 000000000..b75cc98b4
--- /dev/null
+++ b/include/search_filters.inc.php
@@ -0,0 +1,699 @@
+ 'category_id',
+ 'visible_categories' => 'category_id',
+ 'visible_images' => 'id',
+ ),
+ "\n AND"
+ );
+
+ // we want filters to be filled with values related to current items ONLY IF we have some filters filled
+ if ($page['search_details']['has_filters_filled'])
+ {
+ $search_items = array(-1);
+ if (!empty($page['items']))
+ {
+ $search_items = $page['items'];
+ }
+
+ $search_items_clause = 'image_id IN ('.implode(',', $search_items).')';
+ }
+ else
+ {
+ $search_items_clause = '1=1';
+ }
+
+ if (isset($my_search['fields']['tags']))
+ {
+ $filter_tags = array();
+
+ // TODO calling get_available_tags(), with lots of photos/albums/tags may cost time,
+ // we should reuse the result if already executed (for building the menu for example)
+
+ $other_filters_items = get_items_for_filter('tags');
+ if (false === $other_filters_items)
+ {
+ $filter_tags = get_available_tags();
+ usort($filter_tags, 'tag_alpha_compare');
+ }
+ else
+ {
+ $filter_tags = get_common_tags($other_filters_items, 0);
+
+ // the user may have started a search on 2 or more tags that have no
+ // intersection. In this case, $search_items is empty and get_common_tags
+ // returns nothing. We should still display the list of selected tags. We
+ // have to "force" them in the list.
+ $missing_tag_ids = array_diff($my_search['fields']['tags']['words'], array_column($filter_tags, 'id'));
+
+ if (count($missing_tag_ids) > 0)
+ {
+ $filter_tags = array_merge(get_available_tags($missing_tag_ids), $filter_tags);
+ }
+ }
+
+ $template->assign('TAGS', $filter_tags);
+
+ $filter_tag_ids = count($filter_tags) > 0 ? array_column($filter_tags, 'id') : array();
+
+ // in case the search has forbidden tags for current user, we need to filter the search rule
+ $my_search['fields']['tags']['words'] = array_intersect($my_search['fields']['tags']['words'], $filter_tag_ids);
+ }
+
+ if (isset($my_search['fields']['author']))
+ {
+ $filter_clause = get_clause_for_filter('author');
+
+ $query = '
+SELECT
+ author,
+ COUNT(DISTINCT(id)) AS counter
+ FROM '.IMAGES_TABLE.' AS i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE '.$filter_clause.'
+ AND author IS NOT NULL
+ GROUP BY author
+;';
+
+ if (!preg_match('/^image_id IN/', $filter_clause))
+ {
+ // we use persistent_cache only for fetching lines filtered only by permissions
+ $cache_key = $persistent_cache->make_key('filter_author_rows'.$user['id'].$user['cache_update_time']);
+ if (!$persistent_cache->get($cache_key, $filter_rows))
+ {
+ $filter_rows = query2array($query);
+ $persistent_cache->set($cache_key, $filter_rows);
+ }
+ }
+ else
+ {
+ $filter_rows = query2array($query);
+ }
+
+ $author_names = array();
+ foreach ($filter_rows as $author)
+ {
+ $author_names[] = $author['author'];
+ }
+ $template->assign('AUTHORS', $filter_rows);
+
+ // in case the search has forbidden authors for current user, we need to filter the search rule
+ $my_search['fields']['author']['words'] = array_intersect($my_search['fields']['author']['words'], $author_names);
+ }
+
+ if (isset($my_search['fields']['date_posted']))
+ {
+ $filter_clause = get_clause_for_filter('date_posted');
+ $cache_key = $persistent_cache->make_key('filter_date_posted'.$user['id'].$user['cache_update_time']);
+ $set_persistent_cache = !preg_match('/^image_id IN/', $filter_clause) and !$persistent_cache->get($cache_key, $date_posted);
+
+ if (!isset($date_posted))
+ {
+ $query = '
+SELECT
+ SUBDATE(NOW(), INTERVAL 24 HOUR) AS 24h,
+ SUBDATE(NOW(), INTERVAL 7 DAY) AS 7d,
+ SUBDATE(NOW(), INTERVAL 30 DAY) AS 30d,
+ SUBDATE(NOW(), INTERVAL 3 MONTH) AS 3m,
+ SUBDATE(NOW(), INTERVAL 6 MONTH) AS 6m
+;';
+ $thresholds = query2array($query)[0];
+
+ $query = '
+SELECT
+ DISTINCT id,
+ date_available as date
+ FROM '.IMAGES_TABLE.' AS i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE '.$filter_clause.'
+;';
+
+ $list_of_dates = array();
+ $pre_counters = array();
+
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ foreach ($thresholds as $threshold => $date_limit)
+ {
+ if ($row['date'] > $date_limit)
+ {
+ @$pre_counters[$threshold]++;
+ }
+ }
+
+ list($date_without_time) = explode(' ', $row['date']);
+ list($y, $m) = explode('-', $date_without_time);
+
+ @$list_of_dates[$y]['months'][$y.'-'.$m]['days'][$date_without_time]['count']++;
+ @$list_of_dates[$y]['months'][$y.'-'.$m]['count']++;
+ @$list_of_dates[$y]['count']++;
+ }
+
+ $date_posted = array(
+ 'pre_counters' => $pre_counters,
+ 'list_of_dates' => $list_of_dates,
+ );
+
+ if ($set_persistent_cache)
+ {
+ // for this filter, we do not store in cache the $filter_rows : for a big gallery it may
+ // take more than 10MB. It is smarter to store in cache the result of the computation,
+ // which is just around 100 bytes.
+ $persistent_cache->set($cache_key, $date_posted);
+ }
+ }
+
+ $label_for_threshold = array(
+ '24h' => l10n('last 24 hours'),
+ '7d' => l10n('last 7 days'),
+ '30d' => l10n('last 30 days'),
+ '3m' => l10n('last 3 months'),
+ '6m' => l10n('last 6 months'),
+ );
+
+ $counters = array();
+ foreach (array_keys($label_for_threshold) as $threshold)
+ {
+ if (isset($date_posted['pre_counters'][$threshold]))
+ {
+ $counters[$threshold] = array(
+ 'label' => $label_for_threshold[$threshold],
+ 'counter' => $date_posted['pre_counters'][$threshold],
+ );
+ }
+ }
+
+ foreach (array_keys($date_posted['list_of_dates']) as $y)
+ {
+ $date_posted['list_of_dates'][$y]['label'] = l10n('year %d', $y);
+
+ foreach (array_keys($date_posted['list_of_dates'][$y]['months']) as $ym)
+ {
+ list(,$m) = explode('-', $ym);
+ $date_posted['list_of_dates'][$y]['months'][$ym]['label'] = $lang['month'][(int)$m].' '.$y;
+
+ foreach (array_keys($date_posted['list_of_dates'][$y]['months'][$ym]['days']) as $ymd)
+ {
+ list(,,$d) = explode('-', $ymd);
+ $date_posted['list_of_dates'][$y]['months'][$ym]['days'][$ymd]['label'] = format_date($ymd);
+ }
+ }
+ }
+
+ $template->assign('LIST_DATE_POSTED', $date_posted['list_of_dates']);
+ $template->assign('DATE_POSTED', $counters);
+ }
+
+ if (isset($my_search['fields']['added_by']))
+ {
+ $filter_clause = get_clause_for_filter('added_by');
+
+ $query = '
+SELECT
+ COUNT(DISTINCT(id)) AS counter,
+ added_by AS added_by_id
+ FROM '.IMAGES_TABLE.' AS i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE '.$filter_clause.'
+ GROUP BY added_by_id
+ ORDER BY counter DESC
+;';
+
+ if (!preg_match('/^image_id IN/', $filter_clause))
+ {
+ // we use persistent_cache only for fetching lines filtered only by permissions
+ $cache_key = $persistent_cache->make_key('filter_added_by_rows'.$user['id'].$user['cache_update_time']);
+ if (!$persistent_cache->get($cache_key, $filter_rows))
+ {
+ $filter_rows = query2array($query);
+ $persistent_cache->set($cache_key, $filter_rows);
+ }
+ }
+ else
+ {
+ $filter_rows = query2array($query);
+ }
+
+ $added_by = $filter_rows;
+ $user_ids = array();
+
+ if (count($added_by) > 0)
+ {
+ // now let's find the usernames of added_by users
+ foreach ($added_by as $i)
+ {
+ $user_ids[] = $i['added_by_id'];
+ }
+
+ $query = '
+SELECT
+ '.$conf['user_fields']['id'].' AS id,
+ '.$conf['user_fields']['username'].' AS username
+ FROM '.USERS_TABLE.'
+ WHERE '.$conf['user_fields']['id'].' IN ('.implode(',', $user_ids).')
+;';
+ $username_of = query2array($query, 'id', 'username');
+
+ foreach (array_keys($added_by) as $added_by_idx)
+ {
+ $added_by_id = $added_by[$added_by_idx]['added_by_id'];
+ $added_by[$added_by_idx]['added_by_name'] = $username_of[$added_by_id] ?? 'user #'.$added_by_id.' (deleted)';
+ }
+ }
+
+ $template->assign('ADDED_BY', $added_by);
+
+ // in case the search has forbidden added_by users for current user, we need to filter the search rule
+ $my_search['fields']['added_by'] = array_intersect($my_search['fields']['added_by'], $user_ids);
+ }
+
+ if (isset($my_search['fields']['cat']) and !empty($my_search['fields']['cat']['words']))
+ {
+ $fullname_of = array();
+
+ $query = '
+SELECT
+ id,
+ uppercats
+ FROM '.CATEGORIES_TABLE.'
+ INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON id = cat_id AND user_id = '.$user['id'].'
+ WHERE id IN ('.implode(',', $my_search['fields']['cat']['words']).')
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $cat_display_name = get_cat_display_name_cache(
+ $row['uppercats'],
+ 'admin.php?page=album-' // TODO not sure it's relevant to link to admin pages
+ );
+ $row['fullname'] = strip_tags($cat_display_name);
+
+ $fullname_of[$row['id']] = $row['fullname'];
+ }
+
+ $template->assign('fullname_of', json_encode($fullname_of));
+
+ // in case the search has forbidden albums for current user, we need to filter the search rule
+ $my_search['fields']['cat']['words'] = array_intersect($my_search['fields']['cat']['words'], array_keys($fullname_of));
+ }
+
+ if (isset($my_search['fields']['filetypes']))
+ {
+ $filter_clause = get_clause_for_filter('filetypes');
+
+ // get all file extensions for this user in the gallery, whatever the current filters
+ $cache_key = $persistent_cache->make_key('file_exts'.$user['id'].$user['cache_update_time']);
+ if (!$persistent_cache->get($cache_key, $all_exts))
+ {
+ $query = '
+SELECT
+ SUBSTRING_INDEX(path, ".", -1) AS ext,
+ COUNT(DISTINCT(id)) AS counter
+ FROM '.IMAGES_TABLE.' AS i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE 1=1'.$page['search_details']['forbidden'].'
+ GROUP BY ext
+ ORDER BY counter DESC
+;';
+ $all_exts = query2array($query, 'ext', 'counter');
+ $persistent_cache->set($cache_key, $all_exts);
+ }
+
+ if (preg_match('/^image_id IN/', $filter_clause))
+ {
+ $query = '
+SELECT
+ SUBSTRING_INDEX(path, ".", -1) AS ext,
+ COUNT(DISTINCT(id)) AS counter
+ FROM '.IMAGES_TABLE.' AS i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE '.$filter_clause.'
+ GROUP BY ext
+ ORDER BY counter DESC
+;';
+ $filtered_exts = query2array($query, 'ext', 'counter');
+
+ $exts = array();
+ foreach ($all_exts as $ext => $counter)
+ {
+ $exts[$ext] = $filtered_exts[$ext] ?? 0;
+ }
+
+ $template->assign('FILETYPES', $exts);
+ }
+ else
+ {
+ $template->assign('FILETYPES', $all_exts);
+ }
+ }
+
+ // For rating
+ if (isset($my_search['fields']['ratings']))
+ {
+ $filter_clause = get_clause_for_filter('ratings');
+
+ $cache_key = $persistent_cache->make_key('filter_ratings'.$user['id'].$user['cache_update_time']);
+
+ $set_persistent_cache = !preg_match('/^image_id IN/', $filter_clause) and !$persistent_cache->get($cache_key, $ratings);
+
+ if (!isset($ratings))
+ {
+ $query = '
+SELECT
+ DISTINCT id,
+ rating_score
+ FROM '.IMAGES_TABLE.' AS i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE '.$filter_clause;
+
+ $filter_rows = query2array($query);
+
+ $ratings = array_fill(0, 6, 0);
+
+ foreach ($filter_rows as $row)
+ {
+ $r = 5;
+
+ if (!isset($row['rating_score']))
+ {
+ $r = 0;
+ }
+ else
+ {
+ for ($i=1; $i<=4; $i++)
+ {
+ if ($row['rating_score'] < $i)
+ {
+ $r = $i;
+ break;
+ }
+ }
+ }
+
+ $ratings[$r]++;
+ }
+
+ if ($set_persistent_cache)
+ {
+ // for this filter, we do not store in cache the $filter_rows : for a big gallery it may
+ // take more than 10MB. It is smarter to store in cache the result of the computation,
+ // which is just around 100 bytes.
+ $persistent_cache->set($cache_key, $ratings);
+ }
+ }
+
+ $template->assign('RATING', $ratings);
+ }
+
+ // For filesize
+ if (isset($my_search['fields']['filesize_min']) && isset($my_search['fields']['filesize_max']))
+ {
+ $filter_clause = get_clause_for_filter('filesize');
+
+ $filesizes = array();
+ $filesize = array();
+
+ $query = '
+SELECT
+ DISTINCT id,
+ filesize
+ FROM '.IMAGES_TABLE.' AS i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE '.$filter_clause.'
+;';
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ @$filesizes[sprintf('%.1f', $row['filesize']/1024)]++;
+ }
+
+ if (empty($filesizes))
+ { // arbitrary values, only used when no photos on the gallery
+ $filesizes = array(0, 1, 2, 5, 8, 15);
+ }
+
+ $unique_filesizes = array_keys($filesizes);
+ sort($unique_filesizes, SORT_NUMERIC);
+
+ $filesize['list'] = implode(',', $unique_filesizes);
+
+ $filesize['bounds'] = array(
+ 'min' => $unique_filesizes[0],
+ 'max' => end($unique_filesizes),
+ );
+
+ // warning: we will (hopefully) have smarter values for filters. The min/max of the
+ // current search won't always be the first/last values found. It's going to be a
+ // problem with this way to select selected values
+ $filesize['selected'] = array(
+ 'min' => !empty($my_search['fields']['filesize_min']) ? sprintf('%.1f', $my_search['fields']['filesize_min']/1024) : $unique_filesizes[0],
+ 'max' => !empty($my_search['fields']['filesize_max']) ? sprintf('%.1f', $my_search['fields']['filesize_max']/1024) : end($unique_filesizes),
+ );
+
+ $template->assign('FILESIZE', $filesize );
+ }
+
+ if (isset($my_search['fields']['ratios']))
+ {
+ $filter_clause = get_clause_for_filter('ratios');
+
+ $cache_key = $persistent_cache->make_key('filter_ratios'.$user['id'].$user['cache_update_time']);
+
+ $set_persistent_cache = !preg_match('/^image_id IN/', $filter_clause) and !$persistent_cache->get($cache_key, $ratios);
+
+ if (!isset($ratios))
+ {
+ $query = '
+SELECT
+ DISTINCT id,
+ width,
+ height
+ FROM '.IMAGES_TABLE.' as i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE '.$filter_clause.'
+ AND width IS NOT NULL
+ AND height IS NOT NULL
+;';
+
+ $filter_rows = query2array($query);
+
+ $ratios = array(
+ 'Portrait' => 0,
+ 'square' => 0,
+ 'Landscape' => 0,
+ 'Panorama' => 0,
+ );
+
+ foreach ($filter_rows as $row)
+ {
+ $r = $row['width'] / $row['height'];
+ if ($r < 0.95)
+ {
+ $ratios['Portrait']++;
+ }
+ else if ($r >= 0.95 and $r <= 1.05)
+ {
+ $ratios['square']++;
+ }
+ else if ($r > 1.05 and $r < 2)
+ {
+ $ratios['Landscape']++;
+ }
+ else if ($r >= 2)
+ {
+ $ratios['Panorama']++;
+ }
+ }
+
+ if ($set_persistent_cache)
+ {
+ // for this filter, we do not store in cache the $filter_rows : for a big gallery it may
+ // take more than 10MB. It is smarter to store in cache the result of the computation,
+ // which is just around 100 bytes.
+ $persistent_cache->set($cache_key, $ratios);
+ }
+ }
+
+ $template->assign('RATIOS', $ratios);
+ }
+
+ if (isset($my_search['fields']['height_min']) and isset($my_search['fields']['height_max']))
+ {
+ $filter_clause = get_clause_for_filter('height');
+
+ $query = '
+SELECT
+ height
+ FROM '.IMAGES_TABLE.' as i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE '.$filter_clause.'
+ AND height IS NOT NULL
+ GROUP BY height
+ ORDER BY height ASC
+;';
+
+ if (!preg_match('/^image_id IN/', $filter_clause))
+ {
+ // we use persistent_cache only for fetching lines filtered only by permissions
+ $cache_key = $persistent_cache->make_key('filter_height_rows'.$user['id'].$user['cache_update_time']);
+ if (!$persistent_cache->get($cache_key, $filter_rows))
+ {
+ $filter_rows = query2array($query, null, 'height');
+ $persistent_cache->set($cache_key, $filter_rows);
+ }
+ }
+ else
+ {
+ $filter_rows = query2array($query, null, 'height');
+ }
+
+ $heights = $filter_rows;
+
+ $height = array(
+ 'list' => implode(',', $heights),
+ 'bounds' => array(
+ 'min' => $heights[0],
+ 'max' => end($heights),
+ ),
+ 'selected' => array(
+ 'min' => !empty($my_search['fields']['height_min']) ? $my_search['fields']['height_min'] : $heights[0],
+ 'max' => !empty($my_search['fields']['height_max']) ? $my_search['fields']['height_max'] : end($heights),
+ )
+ );
+
+ $template->assign('HEIGHT', $height);
+ }
+
+ if (isset($my_search['fields']['width_min']) and isset($my_search['fields']['width_max']))
+ {
+ $filter_clause = get_clause_for_filter('width');
+
+ $query = '
+SELECT
+ width
+ FROM '.IMAGES_TABLE.' as i
+ JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
+ WHERE '.$filter_clause.'
+ AND width IS NOT NULL
+ GROUP BY width
+ ORDER BY width ASC
+;';
+
+ if (!preg_match('/^image_id IN/', $filter_clause))
+ {
+ // we use persistent_cache only for fetching lines filtered only by permissions
+ $cache_key = $persistent_cache->make_key('filter_width_rows'.$user['id'].$user['cache_update_time']);
+ if (!$persistent_cache->get($cache_key, $filter_rows))
+ {
+ $filter_rows = query2array($query, null, 'width');
+ $persistent_cache->set($cache_key, $filter_rows);
+ }
+ }
+ else
+ {
+ $filter_rows = query2array($query, null, 'width');
+ }
+
+ $widths = $filter_rows;
+
+ $width = array(
+ 'list' => implode(',', $widths),
+ 'bounds' => array(
+ 'min' => $widths[0],
+ 'max' => end($widths),
+ ),
+ 'selected' => array(
+ 'min' => !empty($my_search['fields']['width_min']) ? $my_search['fields']['width_min'] : $widths[0],
+ 'max' => !empty($my_search['fields']['width_max']) ? $my_search['fields']['width_max'] : end($widths),
+ )
+ );
+
+ $template->assign('WIDTH', $width);
+ }
+
+ $template->assign(
+ array(
+ 'GP' => json_encode($my_search),
+ 'SEARCH_ID' => $page['search'],
+ )
+ );
+
+ if (0 == $page['start'] and !isset($page['chronology_field']) and isset($page['search_details']))
+ {
+ if (isset($page['search_details']['matching_cat_ids']))
+ {
+ $cat_ids = $page['search_details']['matching_cat_ids'];
+ if (count($cat_ids))
+ {
+ $query = '
+SELECT
+ c.*
+ FROM '.CATEGORIES_TABLE.' AS c
+ INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON c.id = cat_id and user_id = '.$user['id'].'
+ WHERE id IN ('.implode(',', $cat_ids).')
+;';
+ $cats = query2array($query);
+ usort($cats, 'name_compare');
+ $albums_found = array();
+ foreach ($cats as $cat)
+ {
+ $single_link = false;
+ $albums_found[] = get_cat_display_name_cache(
+ $cat['uppercats'],
+ '',
+ $single_link
+ );
+ }
+
+ if (count($albums_found) > 0)
+ {
+ $template->assign('ALBUMS_FOUND', $albums_found);
+ }
+ }
+ }
+ if (isset($page['search_details']['matching_tag_ids']))
+ {
+ $tag_ids = $page['search_details']['matching_tag_ids'];
+
+ if (count($tag_ids) > 0)
+ {
+ $tags = get_available_tags($tag_ids);
+ usort($tags, 'tag_alpha_compare');
+ $tags_found = array();
+ foreach ($tags as $tag)
+ {
+ $url = make_index_url(
+ array(
+ 'tags' => array($tag)
+ )
+ );
+ $tags_found[] = sprintf('%s', $url, $tag['name']);
+ }
+
+ if (count($tags_found) > 0)
+ {
+ $template->assign('TAGS_FOUND', $tags_found);
+ }
+ }
+ }
+ }
+}
diff --git a/index.php b/index.php
index 5529cf4ad..94ef67140 100644
--- a/index.php
+++ b/index.php
@@ -174,697 +174,7 @@ if ( empty($page['is_external']) )
}
}
- // we add isset($page['search_details']) in this condition because it only
- // applies to regular search, not the legacy qsearch. As Piwigo 14 will still
- // be able to show an old quicksearch result, we must check this condtion too.
- if ('search' == $page['section'] and isset($page['search_details']))
- {
- include_once(PHPWG_ROOT_PATH.'include/functions_search.inc.php');
-
- $my_search = get_search_array($page['search']);
-
- $page['search_details']['forbidden'] = get_sql_condition_FandF(
- array(
- 'forbidden_categories' => 'category_id',
- 'visible_categories' => 'category_id',
- 'visible_images' => 'id',
- ),
- "\n AND"
- );
-
- // we want filters to be filled with values related to current items ONLY IF we have some filters filled
- if ($page['search_details']['has_filters_filled'])
- {
- $search_items = array(-1);
- if (!empty($page['items']))
- {
- $search_items = $page['items'];
- }
-
- $search_items_clause = 'image_id IN ('.implode(',', $search_items).')';
- }
- else
- {
- $search_items_clause = '1=1';
- }
-
- if (isset($my_search['fields']['tags']))
- {
- $filter_tags = array();
-
- // TODO calling get_available_tags(), with lots of photos/albums/tags may cost time,
- // we should reuse the result if already executed (for building the menu for example)
-
- $other_filters_items = get_items_for_filter('tags');
- if (false === $other_filters_items)
- {
- $filter_tags = get_available_tags();
- usort($filter_tags, 'tag_alpha_compare');
- }
- else
- {
- $filter_tags = get_common_tags($other_filters_items, 0);
-
- // the user may have started a search on 2 or more tags that have no
- // intersection. In this case, $search_items is empty and get_common_tags
- // returns nothing. We should still display the list of selected tags. We
- // have to "force" them in the list.
- $missing_tag_ids = array_diff($my_search['fields']['tags']['words'], array_column($filter_tags, 'id'));
-
- if (count($missing_tag_ids) > 0)
- {
- $filter_tags = array_merge(get_available_tags($missing_tag_ids), $filter_tags);
- }
- }
-
- $template->assign('TAGS', $filter_tags);
-
- $filter_tag_ids = count($filter_tags) > 0 ? array_column($filter_tags, 'id') : array();
-
- // in case the search has forbidden tags for current user, we need to filter the search rule
- $my_search['fields']['tags']['words'] = array_intersect($my_search['fields']['tags']['words'], $filter_tag_ids);
- }
-
- if (isset($my_search['fields']['author']))
- {
- $filter_clause = get_clause_for_filter('author');
-
- $query = '
-SELECT
- author,
- COUNT(DISTINCT(id)) AS counter
- FROM '.IMAGES_TABLE.' AS i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE '.$filter_clause.'
- AND author IS NOT NULL
- GROUP BY author
-;';
-
- if (!preg_match('/^image_id IN/', $filter_clause))
- {
- // we use persistent_cache only for fetching lines filtered only by permissions
- $cache_key = $persistent_cache->make_key('filter_author_rows'.$user['id'].$user['cache_update_time']);
- if (!$persistent_cache->get($cache_key, $filter_rows))
- {
- $filter_rows = query2array($query);
- $persistent_cache->set($cache_key, $filter_rows);
- }
- }
- else
- {
- $filter_rows = query2array($query);
- }
-
- $author_names = array();
- foreach ($filter_rows as $author)
- {
- $author_names[] = $author['author'];
- }
- $template->assign('AUTHORS', $filter_rows);
-
- // in case the search has forbidden authors for current user, we need to filter the search rule
- $my_search['fields']['author']['words'] = array_intersect($my_search['fields']['author']['words'], $author_names);
- }
-
- if (isset($my_search['fields']['date_posted']))
- {
- $filter_clause = get_clause_for_filter('date_posted');
- $cache_key = $persistent_cache->make_key('filter_date_posted'.$user['id'].$user['cache_update_time']);
- $set_persistent_cache = !preg_match('/^image_id IN/', $filter_clause) and !$persistent_cache->get($cache_key, $date_posted);
-
- if (!isset($date_posted))
- {
- $query = '
-SELECT
- SUBDATE(NOW(), INTERVAL 24 HOUR) AS 24h,
- SUBDATE(NOW(), INTERVAL 7 DAY) AS 7d,
- SUBDATE(NOW(), INTERVAL 30 DAY) AS 30d,
- SUBDATE(NOW(), INTERVAL 3 MONTH) AS 3m,
- SUBDATE(NOW(), INTERVAL 6 MONTH) AS 6m
-;';
- $thresholds = query2array($query)[0];
-
- $query = '
-SELECT
- DISTINCT id,
- date_available as date
- FROM '.IMAGES_TABLE.' AS i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE '.$filter_clause.'
-;';
-
- $list_of_dates = array();
- $pre_counters = array();
-
- $result = pwg_query($query);
- while ($row = pwg_db_fetch_assoc($result))
- {
- foreach ($thresholds as $threshold => $date_limit)
- {
- if ($row['date'] > $date_limit)
- {
- @$pre_counters[$threshold]++;
- }
- }
-
- list($date_without_time) = explode(' ', $row['date']);
- list($y, $m) = explode('-', $date_without_time);
-
- @$list_of_dates[$y]['months'][$y.'-'.$m]['days'][$date_without_time]['count']++;
- @$list_of_dates[$y]['months'][$y.'-'.$m]['count']++;
- @$list_of_dates[$y]['count']++;
- }
-
- $date_posted = array(
- 'pre_counters' => $pre_counters,
- 'list_of_dates' => $list_of_dates,
- );
-
- if ($set_persistent_cache)
- {
- // for this filter, we do not store in cache the $filter_rows : for a big gallery it may
- // take more than 10MB. It is smarter to store in cache the result of the computation,
- // which is just around 100 bytes.
- $persistent_cache->set($cache_key, $date_posted);
- }
- }
-
- $label_for_threshold = array(
- '24h' => l10n('last 24 hours'),
- '7d' => l10n('last 7 days'),
- '30d' => l10n('last 30 days'),
- '3m' => l10n('last 3 months'),
- '6m' => l10n('last 6 months'),
- );
-
- $counters = array();
- foreach (array_keys($label_for_threshold) as $threshold)
- {
- if (isset($date_posted['pre_counters'][$threshold]))
- {
- $counters[$threshold] = array(
- 'label' => $label_for_threshold[$threshold],
- 'counter' => $date_posted['pre_counters'][$threshold],
- );
- }
- }
-
- foreach (array_keys($date_posted['list_of_dates']) as $y)
- {
- $date_posted['list_of_dates'][$y]['label'] = l10n('year %d', $y);
-
- foreach (array_keys($date_posted['list_of_dates'][$y]['months']) as $ym)
- {
- list(,$m) = explode('-', $ym);
- $date_posted['list_of_dates'][$y]['months'][$ym]['label'] = $lang['month'][(int)$m].' '.$y;
-
- foreach (array_keys($date_posted['list_of_dates'][$y]['months'][$ym]['days']) as $ymd)
- {
- list(,,$d) = explode('-', $ymd);
- $date_posted['list_of_dates'][$y]['months'][$ym]['days'][$ymd]['label'] = format_date($ymd);
- }
- }
- }
-
- $template->assign('LIST_DATE_POSTED', $date_posted['list_of_dates']);
- $template->assign('DATE_POSTED', $counters);
- }
-
- if (isset($my_search['fields']['added_by']))
- {
- $filter_clause = get_clause_for_filter('added_by');
-
- $query = '
-SELECT
- COUNT(DISTINCT(id)) AS counter,
- added_by AS added_by_id
- FROM '.IMAGES_TABLE.' AS i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE '.$filter_clause.'
- GROUP BY added_by_id
- ORDER BY counter DESC
-;';
-
- if (!preg_match('/^image_id IN/', $filter_clause))
- {
- // we use persistent_cache only for fetching lines filtered only by permissions
- $cache_key = $persistent_cache->make_key('filter_added_by_rows'.$user['id'].$user['cache_update_time']);
- if (!$persistent_cache->get($cache_key, $filter_rows))
- {
- $filter_rows = query2array($query);
- $persistent_cache->set($cache_key, $filter_rows);
- }
- }
- else
- {
- $filter_rows = query2array($query);
- }
-
- $added_by = $filter_rows;
- $user_ids = array();
-
- if (count($added_by) > 0)
- {
- // now let's find the usernames of added_by users
- foreach ($added_by as $i)
- {
- $user_ids[] = $i['added_by_id'];
- }
-
- $query = '
-SELECT
- '.$conf['user_fields']['id'].' AS id,
- '.$conf['user_fields']['username'].' AS username
- FROM '.USERS_TABLE.'
- WHERE '.$conf['user_fields']['id'].' IN ('.implode(',', $user_ids).')
-;';
- $username_of = query2array($query, 'id', 'username');
-
- foreach (array_keys($added_by) as $added_by_idx)
- {
- $added_by_id = $added_by[$added_by_idx]['added_by_id'];
- $added_by[$added_by_idx]['added_by_name'] = $username_of[$added_by_id] ?? 'user #'.$added_by_id.' (deleted)';
- }
- }
-
- $template->assign('ADDED_BY', $added_by);
-
- // in case the search has forbidden added_by users for current user, we need to filter the search rule
- $my_search['fields']['added_by'] = array_intersect($my_search['fields']['added_by'], $user_ids);
- }
-
- if (isset($my_search['fields']['cat']) and !empty($my_search['fields']['cat']['words']))
- {
- $fullname_of = array();
-
- $query = '
-SELECT
- id,
- uppercats
- FROM '.CATEGORIES_TABLE.'
- INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON id = cat_id AND user_id = '.$user['id'].'
- WHERE id IN ('.implode(',', $my_search['fields']['cat']['words']).')
-;';
- $result = pwg_query($query);
-
- while ($row = pwg_db_fetch_assoc($result))
- {
- $cat_display_name = get_cat_display_name_cache(
- $row['uppercats'],
- 'admin.php?page=album-' // TODO not sure it's relevant to link to admin pages
- );
- $row['fullname'] = strip_tags($cat_display_name);
-
- $fullname_of[$row['id']] = $row['fullname'];
- }
-
- $template->assign('fullname_of', json_encode($fullname_of));
-
- // in case the search has forbidden albums for current user, we need to filter the search rule
- $my_search['fields']['cat']['words'] = array_intersect($my_search['fields']['cat']['words'], array_keys($fullname_of));
- }
-
- if (isset($my_search['fields']['filetypes']))
- {
- $filter_clause = get_clause_for_filter('filetypes');
-
- // get all file extensions for this user in the gallery, whatever the current filters
- $cache_key = $persistent_cache->make_key('file_exts'.$user['id'].$user['cache_update_time']);
- if (!$persistent_cache->get($cache_key, $all_exts))
- {
- $query = '
-SELECT
- SUBSTRING_INDEX(path, ".", -1) AS ext,
- COUNT(DISTINCT(id)) AS counter
- FROM '.IMAGES_TABLE.' AS i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE 1=1'.$page['search_details']['forbidden'].'
- GROUP BY ext
- ORDER BY counter DESC
-;';
- $all_exts = query2array($query, 'ext', 'counter');
- $persistent_cache->set($cache_key, $all_exts);
- }
-
- if (preg_match('/^image_id IN/', $filter_clause))
- {
- $query = '
-SELECT
- SUBSTRING_INDEX(path, ".", -1) AS ext,
- COUNT(DISTINCT(id)) AS counter
- FROM '.IMAGES_TABLE.' AS i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE '.$filter_clause.'
- GROUP BY ext
- ORDER BY counter DESC
-;';
- $filtered_exts = query2array($query, 'ext', 'counter');
-
- $exts = array();
- foreach ($all_exts as $ext => $counter)
- {
- $exts[$ext] = $filtered_exts[$ext] ?? 0;
- }
-
- $template->assign('FILETYPES', $exts);
- }
- else
- {
- $template->assign('FILETYPES', $all_exts);
- }
- }
-
- // For rating
- if (isset($my_search['fields']['ratings']))
- {
- $filter_clause = get_clause_for_filter('ratings');
-
- $cache_key = $persistent_cache->make_key('filter_ratings'.$user['id'].$user['cache_update_time']);
-
- $set_persistent_cache = !preg_match('/^image_id IN/', $filter_clause) and !$persistent_cache->get($cache_key, $ratings);
-
- if (!isset($ratings))
- {
- $query = '
-SELECT
- DISTINCT id,
- rating_score
- FROM '.IMAGES_TABLE.' AS i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE '.$filter_clause;
-
- $filter_rows = query2array($query);
-
- $ratings = array_fill(0, 6, 0);
-
- foreach ($filter_rows as $row)
- {
- $r = 5;
-
- if (!isset($row['rating_score']))
- {
- $r = 0;
- }
- else
- {
- for ($i=1; $i<=4; $i++)
- {
- if ($row['rating_score'] < $i)
- {
- $r = $i;
- break;
- }
- }
- }
-
- $ratings[$r]++;
- }
-
- if ($set_persistent_cache)
- {
- // for this filter, we do not store in cache the $filter_rows : for a big gallery it may
- // take more than 10MB. It is smarter to store in cache the result of the computation,
- // which is just around 100 bytes.
- $persistent_cache->set($cache_key, $ratings);
- }
- }
-
- $template->assign('RATING', $ratings);
- }
-
- // For filesize
- if (isset($my_search['fields']['filesize_min']) && isset($my_search['fields']['filesize_max']))
- {
- $filter_clause = get_clause_for_filter('filesize');
-
- $filesizes = array();
- $filesize = array();
-
- $query = '
-SELECT
- DISTINCT id,
- filesize
- FROM '.IMAGES_TABLE.' AS i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE '.$filter_clause.'
-;';
- $result = pwg_query($query);
- while ($row = pwg_db_fetch_assoc($result))
- {
- @$filesizes[sprintf('%.1f', $row['filesize']/1024)]++;
- }
-
- if (empty($filesizes))
- { // arbitrary values, only used when no photos on the gallery
- $filesizes = array(0, 1, 2, 5, 8, 15);
- }
-
- $unique_filesizes = array_keys($filesizes);
- sort($unique_filesizes, SORT_NUMERIC);
-
- $filesize['list'] = implode(',', $unique_filesizes);
-
- $filesize['bounds'] = array(
- 'min' => $unique_filesizes[0],
- 'max' => end($unique_filesizes),
- );
-
- // warning: we will (hopefully) have smarter values for filters. The min/max of the
- // current search won't always be the first/last values found. It's going to be a
- // problem with this way to select selected values
- $filesize['selected'] = array(
- 'min' => !empty($my_search['fields']['filesize_min']) ? sprintf('%.1f', $my_search['fields']['filesize_min']/1024) : $unique_filesizes[0],
- 'max' => !empty($my_search['fields']['filesize_max']) ? sprintf('%.1f', $my_search['fields']['filesize_max']/1024) : end($unique_filesizes),
- );
-
- $template->assign('FILESIZE', $filesize );
- }
-
- if (isset($my_search['fields']['ratios']))
- {
- $filter_clause = get_clause_for_filter('ratios');
-
- $cache_key = $persistent_cache->make_key('filter_ratios'.$user['id'].$user['cache_update_time']);
-
- $set_persistent_cache = !preg_match('/^image_id IN/', $filter_clause) and !$persistent_cache->get($cache_key, $ratios);
-
- if (!isset($ratios))
- {
- $query = '
-SELECT
- DISTINCT id,
- width,
- height
- FROM '.IMAGES_TABLE.' as i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE '.$filter_clause.'
- AND width IS NOT NULL
- AND height IS NOT NULL
-;';
-
- $filter_rows = query2array($query);
-
- $ratios = array(
- 'Portrait' => 0,
- 'square' => 0,
- 'Landscape' => 0,
- 'Panorama' => 0,
- );
-
- foreach ($filter_rows as $row)
- {
- $r = $row['width'] / $row['height'];
- if ($r < 0.95)
- {
- $ratios['Portrait']++;
- }
- else if ($r >= 0.95 and $r <= 1.05)
- {
- $ratios['square']++;
- }
- else if ($r > 1.05 and $r < 2)
- {
- $ratios['Landscape']++;
- }
- else if ($r >= 2)
- {
- $ratios['Panorama']++;
- }
- }
-
- if ($set_persistent_cache)
- {
- // for this filter, we do not store in cache the $filter_rows : for a big gallery it may
- // take more than 10MB. It is smarter to store in cache the result of the computation,
- // which is just around 100 bytes.
- $persistent_cache->set($cache_key, $ratios);
- }
- }
-
- $template->assign('RATIOS', $ratios);
- }
-
- if (isset($my_search['fields']['height_min']) and isset($my_search['fields']['height_max']))
- {
- $filter_clause = get_clause_for_filter('height');
-
- $query = '
-SELECT
- height
- FROM '.IMAGES_TABLE.' as i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE '.$filter_clause.'
- AND height IS NOT NULL
- GROUP BY height
- ORDER BY height ASC
-;';
-
- if (!preg_match('/^image_id IN/', $filter_clause))
- {
- // we use persistent_cache only for fetching lines filtered only by permissions
- $cache_key = $persistent_cache->make_key('filter_height_rows'.$user['id'].$user['cache_update_time']);
- if (!$persistent_cache->get($cache_key, $filter_rows))
- {
- $filter_rows = query2array($query, null, 'height');
- $persistent_cache->set($cache_key, $filter_rows);
- }
- }
- else
- {
- $filter_rows = query2array($query, null, 'height');
- }
-
- $heights = $filter_rows;
-
- $height = array(
- 'list' => implode(',', $heights),
- 'bounds' => array(
- 'min' => $heights[0],
- 'max' => end($heights),
- ),
- 'selected' => array(
- 'min' => !empty($my_search['fields']['height_min']) ? $my_search['fields']['height_min'] : $heights[0],
- 'max' => !empty($my_search['fields']['height_max']) ? $my_search['fields']['height_max'] : end($heights),
- )
- );
-
- $template->assign('HEIGHT', $height);
- }
-
- if (isset($my_search['fields']['width_min']) and isset($my_search['fields']['width_max']))
- {
- $filter_clause = get_clause_for_filter('width');
-
- $query = '
-SELECT
- width
- FROM '.IMAGES_TABLE.' as i
- JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.image_id = i.id
- WHERE '.$filter_clause.'
- AND width IS NOT NULL
- GROUP BY width
- ORDER BY width ASC
-;';
-
- if (!preg_match('/^image_id IN/', $filter_clause))
- {
- // we use persistent_cache only for fetching lines filtered only by permissions
- $cache_key = $persistent_cache->make_key('filter_width_rows'.$user['id'].$user['cache_update_time']);
- if (!$persistent_cache->get($cache_key, $filter_rows))
- {
- $filter_rows = query2array($query, null, 'width');
- $persistent_cache->set($cache_key, $filter_rows);
- }
- }
- else
- {
- $filter_rows = query2array($query, null, 'width');
- }
-
- $widths = $filter_rows;
-
- $width = array(
- 'list' => implode(',', $widths),
- 'bounds' => array(
- 'min' => $widths[0],
- 'max' => end($widths),
- ),
- 'selected' => array(
- 'min' => !empty($my_search['fields']['width_min']) ? $my_search['fields']['width_min'] : $widths[0],
- 'max' => !empty($my_search['fields']['width_max']) ? $my_search['fields']['width_max'] : end($widths),
- )
- );
-
- $template->assign('WIDTH', $width);
- }
-
- $template->assign(
- array(
- 'GP' => json_encode($my_search),
- 'SEARCH_ID' => $page['search'],
- )
- );
-
- if (0 == $page['start'] and !isset($page['chronology_field']) and isset($page['search_details']))
- {
- if (isset($page['search_details']['matching_cat_ids']))
- {
- $cat_ids = $page['search_details']['matching_cat_ids'];
- if (count($cat_ids))
- {
- $query = '
-SELECT
- c.*
- FROM '.CATEGORIES_TABLE.' AS c
- INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON c.id = cat_id and user_id = '.$user['id'].'
- WHERE id IN ('.implode(',', $cat_ids).')
-;';
- $cats = query2array($query);
- usort($cats, 'name_compare');
- $albums_found = array();
- foreach ($cats as $cat)
- {
- $single_link = false;
- $albums_found[] = get_cat_display_name_cache(
- $cat['uppercats'],
- '',
- $single_link
- );
- }
-
- if (count($albums_found) > 0)
- {
- $template->assign('ALBUMS_FOUND', $albums_found);
- }
- }
- }
- if (isset($page['search_details']['matching_tag_ids']))
- {
- $tag_ids = $page['search_details']['matching_tag_ids'];
-
- if (count($tag_ids) > 0)
- {
- $tags = get_available_tags($tag_ids);
- usort($tags, 'tag_alpha_compare');
- $tags_found = array();
- foreach ($tags as $tag)
- {
- $url = make_index_url(
- array(
- 'tags' => array($tag)
- )
- );
- $tags_found[] = sprintf('%s', $url, $tag['name']);
- }
-
- if (count($tags_found) > 0)
- {
- $template->assign('TAGS_FOUND', $tags_found);
- }
- }
- }
- }
- }
+ include(PHPWG_ROOT_PATH.'include/search_filters.inc.php');
if ('categories' == $page['section'] and isset($page['category']) and !isset($page['combined_categories']))
{