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'])) {