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

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

update for Piwigo 2.6

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        break;
441      }
442
443      // mode
444      case 'mode':
445      {
446        $mode = $filter['value'];
447        break;
448      }
449    }
450  }
451
452  /* bluid query */
453  $MainQuery = '
454SELECT i.id
455  FROM '.IMAGES_TABLE.' AS i';
456
457    if (count($join))
458    {
459      $MainQuery.= '
460    LEFT JOIN '.implode("\n    LEFT JOIN ", $join);
461    }
462    if (count($where))
463    {
464      $MainQuery.= '
465  WHERE
466    '.implode("\n    ".$mode." ", $where);
467    }
468
469  $MainQuery.= '
470  GROUP BY i.id
471  '.$conf['order_by'].'
472  '.(isset($limit) ? "LIMIT ".$limit : null).'
473;';
474
475  if (defined('SMART_DEBUG'))
476  {
477    file_put_contents(SMART_PATH.'dump_filters.txt', print_r($filters, true));
478    file_put_contents(SMART_PATH.'dump_query.sql', $MainQuery);
479  }
480
481  return query2array($MainQuery, null, 'id');
482}
483
484
485/**
486 * Check if the filter is proper
487 * @param array filter
488 * @return array or false
489 */
490function smart_check_filter($filter)
491{
492  global $page, $limit_is_set, $level_is_set;
493
494  $error = false;
495  if (!isset($limit_is_set)) $limit_is_set = false;
496  if (!isset($level_is_set)) $level_is_set = false;
497
498  switch ($filter['type'])
499  {
500    # tags
501    case 'tags':
502    {
503      if ($filter['value'] == null)
504      {
505        $page['errors'][] = l10n('No tag selected');
506      }
507      else
508      {
509        include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
510        $filter['value'] = implode(',', get_tag_ids($filter['value']));
511      }
512      break;
513    }
514    # date
515    case 'date':
516    {
517      if (!preg_match('#([0-9]{4})-([0-9]{2})-([0-9]{2})#', $filter['value']))
518      {
519        $page['errors'][] = l10n('Date string is malformed');
520      }
521      break;
522    }
523    # name
524    case 'name':
525    {
526      if (empty($filter['value']))
527      {
528        $page['errors'][] = l10n('Name is empty');
529      }
530      else if ($filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false)
531      {
532        $page['errors'][] = l10n('Regex is malformed');
533      }
534      break;
535    }
536    # album
537    case 'album':
538    {
539      if (@$filter['value'] == null)
540      {
541        $page['errors'][] = l10n('No album selected');
542      }
543      else
544      {
545        $filter['value'] = implode(',', $filter['value']);
546      }
547      break;
548    }
549    # dimensions
550    case 'dimensions':
551    {
552      if (empty($filter['value']['min']) or empty($filter['value']['max']))
553      {
554        $error = true;
555      }
556      else
557      {
558        $filter['value'] = $filter['value']['min'].','.$filter['value']['max'];
559      }
560      break;
561    }
562    # author
563    case 'author':
564    {
565      if (empty($filter['value']))
566      {
567        $page['errors'][] = l10n('Author is empty');
568      }
569      else if ($filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false)
570      {
571        $page['errors'][] = l10n('Regex is malformed');
572      }
573      else
574      {
575        $filter['value'] = preg_replace('#([ ]?),([ ]?)#', ',', $filter['value']);
576      }
577      break;
578    }
579    # hit
580    case 'hit':
581    {
582      if (!preg_match('#([0-9]+)#', $filter['value']))
583      {
584        $page['errors'][] = l10n('Hits must be an integer');
585      }
586      break;
587    }
588    # rating_score
589    case 'rating_score':
590    {
591      if (!preg_match('#([0-9]+)#', $filter['value']))
592      {
593        $page['errors'][] = l10n('Rating score must be an integer');
594      }
595      break;
596    }
597    # level
598    case 'level':
599    {
600      if ($level_is_set == true) // only one level is allowed, first is saved
601      {
602        $page['errors'][] = l10n('You can\'t use more than one level filter');
603      }
604      else
605      {
606        $filter['cond'] = 'level';
607        $level_is_set = true;
608      }
609      break;
610    }
611    # limit
612    case 'limit':
613    {
614      if ($limit_is_set == true) // only one limit is allowed, first is saved
615      {
616        $page['errors'][] = l10n('You can\'t use more than one limit filter');
617      }
618      else if (!preg_match('#([0-9]+)#', $filter['value']))
619      {
620        $page['errors'][] = l10n('Limit must be an integer');
621      }
622      else
623      {
624        $filter['cond'] = 'limit';
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.