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

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

allow to choose the sort order when using limit filter

File size: 15.3 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        switch ($filter['cond'])
280        {
281          // search images existing in all albums
282          case 'all':
283          {
284            $albums_arr = explode(',', $filter['value']);
285            foreach($albums_arr as $value)
286            {
287              $sub_query = '
288      SELECT image_id
289        FROM '.IMAGE_CATEGORY_TABLE.'
290        WHERE category_id = '.$value.'
291      ';
292              $where[] = 'i.id IN ('.$sub_query.')';
293            }
294
295            break;
296          }
297          // search images existing in one of these albums
298          case 'one':
299          {
300            $sub_query = '
301      SELECT image_id
302        FROM '.IMAGE_CATEGORY_TABLE.'
303        WHERE category_id IN('.$filter['value'].')
304      ';
305            $where[] = 'i.id IN ('.$sub_query.')';
306
307            break;
308          }
309          // exclude images existing in one of these albums
310          case 'none':
311          {
312            $sub_query = '
313      SELECT image_id
314        FROM '.IMAGE_CATEGORY_TABLE.'
315        WHERE category_id IN('.$filter['value'].')
316      ';
317            $where[] = 'i.id NOT IN ('.$sub_query.')';
318
319            break;
320          }
321          // exclude images existing on other albums, and search images existing in all albums
322          case 'only':
323          {
324            $sub_query = '
325      SELECT image_id
326        FROM '.IMAGE_CATEGORY_TABLE.'
327        WHERE category_id NOT IN('.$filter['value'].')
328      ';
329            $where[] = 'i.id NOT IN ('.$sub_query.')';
330
331            $albums_arr = explode(',', $filter['value']);
332            foreach($albums_arr as $value)
333            {
334              $sub_query = '
335      SELECT image_id
336        FROM '.IMAGE_CATEGORY_TABLE.'
337        WHERE category_id = '.$value.'
338      ';
339              $where[] = 'i.id IN ('.$sub_query.')';
340            }
341
342            break;
343          }
344        }
345
346        break;
347      }
348
349      // dimensions
350      case 'dimensions':
351      {
352        $filter['value'] = explode(',', $filter['value']);
353
354        switch ($filter['cond'])
355        {
356          case 'width':
357            $where[] = 'width >= '.$filter['value'][0].' AND width <= '.$filter['value'][1];
358            break;
359          case 'height':
360            $where[] = 'height >= '.$filter['value'][0].' AND height <= '.$filter['value'][1];
361            break;
362          case 'ratio':
363            $where[] = 'width/height >= '.$filter['value'][0].' AND width/height < '.($filter['value'][1]+0.01);
364            break;
365        }
366      }
367
368      // author
369      case 'author':
370      {
371        switch ($filter['cond'])
372        {
373          case 'is':
374            if ($filter['value'] != 'NULL') $filter['value'] = '"'.$filter['value'].'"';
375            $where[] = 'author = '.$filter['value'].'';
376            break;
377          case 'not_is':
378            if ($filter['value'] != 'NULL') $filter['value'] = '"'.$filter['value'].'"';
379            $where[] = 'author != '.$filter['value'].'';
380            break;
381          case 'in':
382            $filter['value'] = '"'.str_replace(',', '","', $filter['value']).'"';
383            $where[] = 'author IN('.$filter['value'].')';
384            break;
385          case 'not_in':
386            $filter['value'] = '"'.str_replace(',', '","', $filter['value']).'"';
387            $where[] = 'author NOT IN('.$filter['value'].')';
388            break;
389          case 'regex':
390            $where[] = 'author REGEXP "'.$filter['value'].'"';
391            break;
392        }
393
394        break;
395      }
396
397      // hit
398      case 'hit':
399      {
400        switch ($filter['cond'])
401        {
402          case 'less':
403            $where[] = 'hit < '.$filter['value'].'';
404            break;
405          case 'more':
406            $where[] = 'hit >= '.$filter['value'].'';
407            break;
408        }
409
410        break;
411      }
412
413      // rating_score
414      case 'rating_score':
415      {
416        switch ($filter['cond'])
417        {
418          case 'less':
419            $where[] = 'rating_score < '.$filter['value'].'';
420            break;
421          case 'more':
422            $where[] = 'rating_score >= '.$filter['value'].'';
423            break;
424        }
425
426        break;
427      }
428
429      // level
430      case 'level':
431      {
432        $where[] = 'level = '.$filter['value'].'';
433        break;
434      }
435
436      // limit
437      case 'limit':
438      {
439        $limit = '0, '.$filter['value'];
440        if (!empty($filter['cond'])) $order_by = $filter['cond'];
441        break;
442      }
443
444      // mode
445      case 'mode':
446      {
447        $mode = $filter['value'];
448        break;
449      }
450    }
451  }
452
453  /* bluid query */
454  $MainQuery = '
455SELECT i.id
456  FROM '.IMAGES_TABLE.' AS i';
457
458    if (count($join))
459    {
460      $MainQuery.= '
461    LEFT JOIN '.implode("\n    LEFT JOIN ", $join);
462    }
463    if (count($where))
464    {
465      $MainQuery.= '
466  WHERE
467    '.implode("\n    ".$mode." ", $where);
468    }
469
470  $MainQuery.= '
471  GROUP BY i.id
472  '.(isset($order_by) ? "ORDER BY ".$order_by : $conf['order_by']).'
473  '.(isset($limit) ? "LIMIT ".$limit : null).'
474;';
475
476  if (defined('SMART_DEBUG'))
477  {
478    file_put_contents(SMART_PATH.'dump_filters.txt', print_r($filters, true));
479    file_put_contents(SMART_PATH.'dump_query.sql', $MainQuery);
480  }
481
482  return query2array($MainQuery, null, 'id');
483}
484
485
486/**
487 * Check if the filter is proper
488 * @param array filter
489 * @return array or false
490 */
491function smart_check_filter($filter)
492{
493  global $page, $limit_is_set, $level_is_set;
494
495  $error = false;
496  if (!isset($limit_is_set)) $limit_is_set = false;
497  if (!isset($level_is_set)) $level_is_set = false;
498
499  switch ($filter['type'])
500  {
501    # tags
502    case 'tags':
503    {
504      if ($filter['value'] == null)
505      {
506        $page['errors'][] = l10n('No tag selected');
507      }
508      else
509      {
510        include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
511        $filter['value'] = implode(',', get_tag_ids($filter['value']));
512      }
513      break;
514    }
515    # date
516    case 'date':
517    {
518      if (!preg_match('#([0-9]{4})-([0-9]{2})-([0-9]{2})#', $filter['value']))
519      {
520        $page['errors'][] = l10n('Date string is malformed');
521      }
522      break;
523    }
524    # name
525    case 'name':
526    {
527      if (empty($filter['value']))
528      {
529        $page['errors'][] = l10n('Name is empty');
530      }
531      else if ($filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false)
532      {
533        $page['errors'][] = l10n('Regex is malformed');
534      }
535      break;
536    }
537    # album
538    case 'album':
539    {
540      if (@$filter['value'] == null)
541      {
542        $page['errors'][] = l10n('No album selected');
543      }
544      else
545      {
546        $filter['value'] = implode(',', $filter['value']);
547      }
548      break;
549    }
550    # dimensions
551    case 'dimensions':
552    {
553      if (empty($filter['value']['min']) or empty($filter['value']['max']))
554      {
555        $error = true;
556      }
557      else
558      {
559        $filter['value'] = $filter['value']['min'].','.$filter['value']['max'];
560      }
561      break;
562    }
563    # author
564    case 'author':
565    {
566      if (empty($filter['value']))
567      {
568        $page['errors'][] = l10n('Author is empty');
569      }
570      else if ($filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false)
571      {
572        $page['errors'][] = l10n('Regex is malformed');
573      }
574      else
575      {
576        $filter['value'] = preg_replace('#([ ]?),([ ]?)#', ',', $filter['value']);
577      }
578      break;
579    }
580    # hit
581    case 'hit':
582    {
583      if (!preg_match('#([0-9]+)#', $filter['value']))
584      {
585        $page['errors'][] = l10n('Hits must be an integer');
586      }
587      break;
588    }
589    # rating_score
590    case 'rating_score':
591    {
592      if (!preg_match('#([0-9]+)#', $filter['value']))
593      {
594        $page['errors'][] = l10n('Rating score must be an integer');
595      }
596      break;
597    }
598    # level
599    case 'level':
600    {
601      if ($level_is_set == true) // only one level is allowed, first is saved
602      {
603        $page['errors'][] = l10n('You can\'t use more than one level filter');
604      }
605      else
606      {
607        $filter['cond'] = 'level';
608        $level_is_set = true;
609      }
610      break;
611    }
612    # limit
613    case 'limit':
614    {
615      if ($limit_is_set == true) // only one limit is allowed, first is saved
616      {
617        $page['errors'][] = l10n('You can\'t use more than one limit filter');
618      }
619      else if (!preg_match('#([0-9]+)#', $filter['value']))
620      {
621        $page['errors'][] = l10n('Limit must be an integer');
622      }
623      else
624      {
625        $limit_is_set = true;
626      }
627      break;
628    }
629    # mode
630    case 'mode':
631    {
632      $filter['cond'] = 'mode';
633      break;
634    }
635
636    default:
637    {
638      $error = true;
639      break;
640    }
641  }
642
643
644  if (!$error && empty($page['errors']))
645  {
646    return $filter;
647  }
648  else
649  {
650    return false;
651  }
652}
Note: See TracBrowser for help on using the repository browser.