source: extensions/SmartAlbums/include/functions.inc.php @ 28063

Last change on this file since 28063 was 28063, checked in by mistic100, 10 years ago

add recursive option for album filter
fix choosen display

File size: 16.8 KB
Line 
1<?php
2defined('SMART_PATH') or die('Hacking attempt!');
3
4/*
5 * Associates images to the category according to the filters
6 * @param int category_id
7 * @return array
8 */
9function smart_make_associations($cat_id)
10{
11  $query = '
12DELETE FROM '.IMAGE_CATEGORY_TABLE.'
13  WHERE
14    category_id = '.$cat_id.'
15    AND smart = true
16;';
17  pwg_query($query);
18
19  $images = smart_get_pictures($cat_id);
20
21  if (count($images) != 0)
22  {
23    foreach ($images as $img)
24    {
25      $datas[] = array(
26        'image_id' => $img,
27        'category_id' => $cat_id,
28        'smart' => true,
29        );
30    }
31    mass_inserts(
32      IMAGE_CATEGORY_TABLE,
33      array_keys($datas[0]),
34      $datas,
35      array('ignore'=>true)
36      );
37  }
38
39  // representant, try to not overwrite if still in images list
40  $query = '
41SELECT representative_picture_id
42  FROM '.CATEGORIES_TABLE.'
43  WHERE id = '.$cat_id.'
44;';
45  list($rep_id) = pwg_db_fetch_row(pwg_query($query));
46
47  if (!in_array($rep_id, $images))
48  {
49    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
50    set_random_representant(array($cat_id));
51  }
52
53  $query = '
54UPDATE '.CATEGORY_FILTERS_TABLE.'
55  SET updated = NOW()
56  WHERE category_id = '.$cat_id.'
57;';
58  pwg_query($query);
59
60  return $images;
61}
62
63
64/*
65 * Make associations for all SmartAlbums
66 * Called with invalidate_user_cache
67 */
68function smart_make_all_associations()
69{
70  global $conf;
71
72  if (defined('SMART_NOT_UPDATE'))
73  {
74    return;
75  }
76
77  // get categories with smart filters
78  $query = '
79SELECT DISTINCT category_id
80  FROM '.CATEGORY_FILTERS_TABLE.'
81;';
82
83  // regenerate photo list
84  $smart_cats = query2array($query, null, 'category_id');
85  array_map('smart_make_associations', $smart_cats);
86}
87
88
89/*
90 * Generates the list of images, according to the filters of the category
91 * @param int category_id
92 * @param array filters, if null => catch from db
93 * @return array
94 */
95function smart_get_pictures($cat_id, $filters = null)
96{
97  global $conf;
98
99  /* get filters */
100  if (!isset($filters))
101  {
102    $query = '
103SELECT *
104  FROM '.CATEGORY_FILTERS_TABLE.'
105  WHERE category_id = '.$cat_id.'
106  ORDER BY type ASC, cond ASC
107;';
108    $result = pwg_query($query);
109
110    if (!pwg_db_num_rows($result))
111    {
112      return array();
113    }
114
115    $filters = array();
116    while ($row = pwg_db_fetch_assoc($result))
117    {
118      $filters[] = array(
119        'type' => $row['type'],
120        'cond' => $row['cond'],
121        'value' => $row['value'],
122        );
123    }
124  }
125  else if (!count($filters))
126  {
127    return array();
128  }
129
130  $mode = 'and';
131
132  /* build constrains */
133  ## generate 'join', 'where' arrays and 'limit' string to create the SQL query
134  ## inspired by PicsEngine 3 by Michael Villar
135  $i_tags = 1;
136  $join = array();
137  $where = array();
138
139  foreach ($filters as $filter)
140  {
141    switch ($filter['type'])
142    {
143      // tags
144      case 'tags':
145      {
146        switch ($filter['cond'])
147        {
148          // search images which have all tags
149          case 'all':
150          {
151            $tags_arr = explode(',', $filter['value']);
152            foreach ($tags_arr as $value)
153            {
154              $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
155              $where[] = 'it'.$i_tags.'.tag_id = '.$value;
156              $i_tags++;
157            }
158
159            break;
160          }
161          // search images which tags are in the list
162          case 'one':
163          {
164            $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
165            $where[] = 'it'.$i_tags.'.tag_id IN ('.$filter['value'].')';
166            $i_tags++;
167
168            break;
169          }
170          // exclude images which tags are in the list
171          case 'none':
172          {
173            $sub_query = '
174      SELECT it'.$i_tags.'.image_id
175        FROM '.IMAGE_TAG_TABLE.' AS it'.$i_tags.'
176        WHERE
177          it'.$i_tags.'.image_id = i.id AND
178          it'.$i_tags.'.tag_id IN ('.$filter['value'].')
179        GROUP BY it'.$i_tags.'.image_id
180      ';
181            $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
182            $where[] = 'NOT EXISTS ('.$sub_query.')';
183            $i_tags++;
184
185            break;
186          }
187          // exclude images which tags are not in the list and search images which have all tags
188          case 'only':
189          {
190            $sub_query = '
191      SELECT it'.$i_tags.'.image_id
192        FROM '.IMAGE_TAG_TABLE.' AS it'.$i_tags.'
193        WHERE
194          it'.$i_tags.'.image_id = i.id AND
195          it'.$i_tags.'.tag_id NOT IN ('.$filter['value'].')
196        GROUP BY it'.$i_tags.'.image_id
197      ';
198            $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
199            $where[] = 'NOT EXISTS ('.$sub_query.')';
200            $i_tags++;
201
202            $tags_arr = explode(',', $filter['value']);
203            foreach($tags_arr as $value)
204            {
205              $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
206              $where[] = 'it'.$i_tags.'.tag_id = '.$value;
207              $i_tags++;
208            }
209
210            break;
211          }
212        }
213
214        break;
215      }
216
217      // date
218      case 'date':
219      {
220        switch ($filter['cond'])
221        {
222          case 'the_post':
223            $where[] = 'date_available BETWEEN "'.$filter['value'].' 00:00:00" AND "'.$filter['value'].' 23:59:59"';
224            break;
225          case 'before_post':
226            $where[] = 'date_available < "'.$filter['value'].' 00:00:00"';
227            break;
228          case 'after_post':
229            $where[] = 'date_available > "'.$filter['value'].' 23:59:59"';
230            break;
231          case 'the_taken':
232            $where[] = 'date_creation BETWEEN "'.$filter['value'].' 00:00:00" AND "'.$filter['value'].' 23:59:59"';
233            break;
234          case 'before_taken':
235            $where[] = 'date_creation < "'.$filter['value'].' 00:00:00"';
236            break;
237          case 'after_taken':
238            $where[] = 'date_creation > "'.$filter['value'].' 23:59:59"';
239            break;
240        }
241
242        break;
243      }
244
245      // name
246      case 'name':
247      {
248        switch ($filter['cond'])
249        {
250          case 'contain':
251            $where[] = 'name LIKE "%'.$filter['value'].'%"';
252            break;
253          case 'begin':
254            $where[] = 'name LIKE "'.$filter['value'].'%"';
255            break;
256          case 'end':
257            $where[] = 'name LIKE "%'.$filter['value'].'"';
258            break;
259          case 'not_contain':
260            $where[] = 'name NOT LIKE "%'.$filter['value'].'%"';
261            break;
262          case 'not_begin':
263            $where[] = 'name NOT LIKE "'.$filter['value'].'%"';
264            break;
265          case 'not_end':
266            $where[] = 'name NOT LIKE "%'.$filter['value'].'"';
267            break;
268          case 'regex':
269            $where[] = 'name REGEXP "'.$filter['value'].'"';
270            break;
271        }
272
273        break;
274      }
275
276      // album
277      case 'album':
278      {
279        $filter['values'] = explode(',', $filter['value']);
280        $filter['recursive'] = array_shift($filter['values']) == "true";
281        $filter['value'] = implode(',', $filter['values']);
282
283        switch ($filter['cond'])
284        {
285          // search images existing in all albums
286          case 'all':
287          {
288            foreach ($filter['values'] as $value)
289            {
290              if ($filter['recursive'])
291              {
292                $value = get_subcat_ids_query(array($value));
293              }
294              $sub_query = '
295      SELECT image_id
296        FROM '.IMAGE_CATEGORY_TABLE.'
297        WHERE category_id IN('.$value.')
298      ';
299              $where[] = 'i.id IN ('.$sub_query.')';
300            }
301
302            break;
303          }
304          // search images existing in one of these albums
305          case 'one':
306          {
307            if ($filter['recursive'])
308            {
309              $value = get_subcat_ids_query($filter['values']);
310            }
311            else
312            {
313              $value = $filter['value'];
314            }
315            $sub_query = '
316      SELECT image_id
317        FROM '.IMAGE_CATEGORY_TABLE.'
318        WHERE category_id IN('.$value.')
319      ';
320            $where[] = 'i.id IN ('.$sub_query.')';
321
322            break;
323          }
324          // exclude images existing in one of these albums
325          case 'none':
326          {
327            if ($filter['recursive'])
328            {
329              $value = get_subcat_ids_query($filter['values']);
330            }
331            else
332            {
333              $value = $filter['value'];
334            }
335            $sub_query = '
336      SELECT image_id
337        FROM '.IMAGE_CATEGORY_TABLE.'
338        WHERE category_id IN('.$value.')
339      ';
340            $where[] = 'i.id NOT IN ('.$sub_query.')';
341
342            break;
343          }
344          // exclude images existing on other albums, and search images existing in all albums
345          case 'only':
346          {
347            if ($filter['recursive'])
348            {
349              $value = get_subcat_ids_query($filter['values']);
350            }
351            else
352            {
353              $value = $filter['value'];
354            }
355            $sub_query = '
356      SELECT image_id
357        FROM '.IMAGE_CATEGORY_TABLE.'
358        WHERE category_id NOT IN('.$value.')
359      ';
360            $where[] = 'i.id NOT IN ('.$sub_query.')';
361
362            foreach ($filter['values'] as $value)
363            {
364              if ($filter['recursive'])
365              {
366                $value = get_subcat_ids_query(array($value));
367              }
368              $sub_query = '
369      SELECT image_id
370        FROM '.IMAGE_CATEGORY_TABLE.'
371        WHERE category_id = '.$value.'
372      ';
373              $where[] = 'i.id IN ('.$sub_query.')';
374            }
375
376            break;
377          }
378        }
379
380        break;
381      }
382
383      // dimensions
384      case 'dimensions':
385      {
386        $filter['value'] = explode(',', $filter['value']);
387
388        switch ($filter['cond'])
389        {
390          case 'width':
391            $where[] = 'width >= '.$filter['value'][0].' AND width <= '.$filter['value'][1];
392            break;
393          case 'height':
394            $where[] = 'height >= '.$filter['value'][0].' AND height <= '.$filter['value'][1];
395            break;
396          case 'ratio':
397            $where[] = 'width/height >= '.$filter['value'][0].' AND width/height < '.($filter['value'][1]+0.01);
398            break;
399        }
400      }
401
402      // author
403      case 'author':
404      {
405        switch ($filter['cond'])
406        {
407          case 'is':
408            if ($filter['value'] != 'NULL') $filter['value'] = '"'.$filter['value'].'"';
409            $where[] = 'author = '.$filter['value'].'';
410            break;
411          case 'not_is':
412            if ($filter['value'] != 'NULL') $filter['value'] = '"'.$filter['value'].'"';
413            $where[] = 'author != '.$filter['value'].'';
414            break;
415          case 'in':
416            $filter['value'] = '"'.str_replace(',', '","', $filter['value']).'"';
417            $where[] = 'author IN('.$filter['value'].')';
418            break;
419          case 'not_in':
420            $filter['value'] = '"'.str_replace(',', '","', $filter['value']).'"';
421            $where[] = 'author NOT IN('.$filter['value'].')';
422            break;
423          case 'regex':
424            $where[] = 'author REGEXP "'.$filter['value'].'"';
425            break;
426        }
427
428        break;
429      }
430
431      // hit
432      case 'hit':
433      {
434        switch ($filter['cond'])
435        {
436          case 'less':
437            $where[] = 'hit < '.$filter['value'].'';
438            break;
439          case 'more':
440            $where[] = 'hit >= '.$filter['value'].'';
441            break;
442        }
443
444        break;
445      }
446
447      // rating_score
448      case 'rating_score':
449      {
450        switch ($filter['cond'])
451        {
452          case 'less':
453            $where[] = 'rating_score < '.$filter['value'].'';
454            break;
455          case 'more':
456            $where[] = 'rating_score >= '.$filter['value'].'';
457            break;
458        }
459
460        break;
461      }
462
463      // level
464      case 'level':
465      {
466        $where[] = 'level = '.$filter['value'].'';
467        break;
468      }
469
470      // limit
471      case 'limit':
472      {
473        $limit = '0, '.$filter['value'];
474        if (!empty($filter['cond'])) $order_by = $filter['cond'];
475        break;
476      }
477
478      // mode
479      case 'mode':
480      {
481        $mode = $filter['value'];
482        break;
483      }
484    }
485  }
486
487  /* bluid query */
488  $MainQuery = '
489SELECT i.id
490  FROM '.IMAGES_TABLE.' AS i';
491
492    if (count($join))
493    {
494      $MainQuery.= '
495    LEFT JOIN '.implode("\n    LEFT JOIN ", $join);
496    }
497    if (count($where))
498    {
499      $MainQuery.= '
500  WHERE
501    '.implode("\n    ".$mode." ", $where);
502    }
503
504  $MainQuery.= '
505  GROUP BY i.id
506  '.(isset($order_by) ? "ORDER BY ".$order_by : $conf['order_by']).'
507  '.(isset($limit) ? "LIMIT ".$limit : null).'
508;';
509
510  if (defined('SMART_DEBUG'))
511  {
512    file_put_contents(SMART_PATH.'dump_filters.txt', print_r($filters, true));
513    file_put_contents(SMART_PATH.'dump_query.sql', $MainQuery);
514  }
515
516  return query2array($MainQuery, null, 'id');
517}
518
519
520/**
521 * Check if the filter is proper
522 * @param array filter
523 * @return array or false
524 */
525function smart_check_filter($filter)
526{
527  global $page, $limit_is_set, $level_is_set;
528
529  $error = false;
530  if (!isset($limit_is_set)) $limit_is_set = false;
531  if (!isset($level_is_set)) $level_is_set = false;
532
533  switch ($filter['type'])
534  {
535    # tags
536    case 'tags':
537    {
538      if ($filter['value'] == null)
539      {
540        $page['errors'][] = l10n('No tag selected');
541      }
542      else
543      {
544        include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
545        $filter['value'] = implode(',', get_tag_ids($filter['value']));
546      }
547      break;
548    }
549    # date
550    case 'date':
551    {
552      if (!preg_match('#([0-9]{4})-([0-9]{2})-([0-9]{2})#', $filter['value']))
553      {
554        $page['errors'][] = l10n('Date string is malformed');
555      }
556      break;
557    }
558    # name
559    case 'name':
560    {
561      if (empty($filter['value']))
562      {
563        $page['errors'][] = l10n('Name is empty');
564      }
565      else if ($filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false)
566      {
567        $page['errors'][] = l10n('Regex is malformed');
568      }
569      break;
570    }
571    # album
572    case 'album':
573    {
574      if (@$filter['value'] == null)
575      {
576        $page['errors'][] = l10n('No album selected');
577      }
578      else
579      {
580        array_unshift($filter['value'], boolean_to_string(isset($filter['recursive'])));
581        $filter['value'] = implode(',', $filter['value']);
582      }
583      break;
584    }
585    # dimensions
586    case 'dimensions':
587    {
588      if (empty($filter['value']['min']) or empty($filter['value']['max']))
589      {
590        $error = true;
591      }
592      else
593      {
594        $filter['value'] = $filter['value']['min'].','.$filter['value']['max'];
595      }
596      break;
597    }
598    # author
599    case 'author':
600    {
601      if (empty($filter['value']))
602      {
603        $page['errors'][] = l10n('Author is empty');
604      }
605      else if ($filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false)
606      {
607        $page['errors'][] = l10n('Regex is malformed');
608      }
609      else
610      {
611        $filter['value'] = preg_replace('#([ ]?),([ ]?)#', ',', $filter['value']);
612      }
613      break;
614    }
615    # hit
616    case 'hit':
617    {
618      if (!preg_match('#([0-9]+)#', $filter['value']))
619      {
620        $page['errors'][] = l10n('Hits must be an integer');
621      }
622      break;
623    }
624    # rating_score
625    case 'rating_score':
626    {
627      if (!preg_match('#([0-9]+)#', $filter['value']))
628      {
629        $page['errors'][] = l10n('Rating score must be an integer');
630      }
631      break;
632    }
633    # level
634    case 'level':
635    {
636      if ($level_is_set == true) // only one level is allowed, first is saved
637      {
638        $page['errors'][] = l10n('You can\'t use more than one level filter');
639      }
640      else
641      {
642        $filter['cond'] = 'level';
643        $level_is_set = true;
644      }
645      break;
646    }
647    # limit
648    case 'limit':
649    {
650      if ($limit_is_set == true) // only one limit is allowed, first is saved
651      {
652        $page['errors'][] = l10n('You can\'t use more than one limit filter');
653      }
654      else if (!preg_match('#([0-9]+)#', $filter['value']))
655      {
656        $page['errors'][] = l10n('Limit must be an integer');
657      }
658      else
659      {
660        $limit_is_set = true;
661      }
662      break;
663    }
664    # mode
665    case 'mode':
666    {
667      $filter['cond'] = 'mode';
668      break;
669    }
670
671    default:
672    {
673      $error = true;
674      break;
675    }
676  }
677
678
679  if (!$error && empty($page['errors']))
680  {
681    return $filter;
682  }
683  else
684  {
685    return false;
686  }
687}
688
689/**
690 * Returns SQL query returning all subcategory identifiers of given category ids
691 *
692 * @param int[] $ids
693 * @return int[]
694 */
695function get_subcat_ids_query($ids)
696{
697  $query = '
698SELECT DISTINCT(id)
699  FROM '.CATEGORIES_TABLE.'
700  WHERE ';
701  foreach ($ids as $num => $category_id)
702  {
703    if ($num > 0)
704    {
705      $query.= '
706    OR ';
707    }
708    $query.= 'uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.$category_id.'(,|$)\'';
709  }
710  return $query;
711}
Note: See TracBrowser for help on using the repository browser.