source: branches/2.3/admin/batch_manager_global.php @ 12747

Last change on this file since 12747 was 12747, checked in by plg, 9 years ago

bug 2534 fixed: clean (as clean as possible with MySQL+MyISAM) handle of
concurrency on user cache refresh. No more error when regenerating several
thumbnails at once.

File size: 21.1 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24/**
25 * Management of elements set. Elements can belong to a category or to the
26 * user caddie.
27 *
28 */
29
30if (!defined('PHPWG_ROOT_PATH'))
31{
32  die('Hacking attempt!');
33}
34
35include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
36include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
37
38$upload_form_config = get_upload_form_config();
39foreach ($upload_form_config as $param_shortname => $param)
40{
41  $param_name = 'upload_form_'.$param_shortname;
42  $form_values[$param_shortname] = $conf[$param_name];
43}
44
45// +-----------------------------------------------------------------------+
46// | Check Access and exit when user status is not ok                      |
47// +-----------------------------------------------------------------------+
48
49check_status(ACCESS_ADMINISTRATOR);
50
51trigger_action('loc_begin_element_set_global');
52
53check_input_parameter('del_tags', $_POST, true, PATTERN_ID);
54check_input_parameter('associate', $_POST, false, PATTERN_ID);
55check_input_parameter('dissociate', $_POST, false, PATTERN_ID);
56
57// +-----------------------------------------------------------------------+
58// |                            current selection                          |
59// +-----------------------------------------------------------------------+
60
61$collection = array();
62if (isset($_POST['setSelected']))
63{
64  $collection = $page['cat_elements_id'];
65}
66else if (isset($_POST['selection']))
67{
68  $collection = $_POST['selection'];
69}
70
71// +-----------------------------------------------------------------------+
72// |                       global mode form submission                     |
73// +-----------------------------------------------------------------------+
74
75// $page['prefilter'] is a shortcut to test if the current filter contains a
76// given prefilter. The idea is to make conditions simpler to write in the
77// code.
78$page['prefilter'] = 'none';
79if (isset($_SESSION['bulk_manager_filter']['prefilter']))
80{
81  $page['prefilter'] = $_SESSION['bulk_manager_filter']['prefilter'];
82}
83
84// $page['category'] is a shortcut to test if the current filter contains a
85// given category. The idea is the same as for prefilter
86$page['category'] = -1;
87if (isset($_SESSION['bulk_manager_filter']['category']))
88{
89  $page['category'] = $_SESSION['bulk_manager_filter']['category'];
90}
91
92$redirect_url = get_root_url().'admin.php?page='.$_GET['page'];
93
94if (isset($_POST['submit']))
95{
96  // if the user tries to apply an action, it means that there is at least 1
97  // photo in the selection
98  if (count($collection) == 0)
99  {
100    array_push($page['errors'], l10n('Select at least one photo'));
101  }
102
103  $action = $_POST['selectAction'];
104 
105  if ('remove_from_caddie' == $action)
106  {
107    $query = '
108DELETE
109  FROM '.CADDIE_TABLE.'
110  WHERE element_id IN ('.implode(',', $collection).')
111    AND user_id = '.$user['id'].'
112;';
113    pwg_query($query);
114
115    if ('caddie' == $page['prefilter'])
116    {
117      redirect($redirect_url);
118    }
119   
120    // if we are here in the code, it means that the user is currently
121    // displaying the caddie content, so we have to remove the current
122    // selection from the current set
123    $page['cat_elements_id'] = array_diff($page['cat_elements_id'], $collection);
124  }
125
126  if ('add_tags' == $action)
127  {
128    if (empty($_POST['add_tags']))
129    {
130      array_push($page['errors'], l10n('Select at least one tag'));
131    }
132    else
133    {
134      $tag_ids = get_tag_ids($_POST['add_tags']);
135      add_tags($tag_ids, $collection);
136
137      if ('with no tag' == $page['prefilter'])
138      {
139        redirect(get_root_url().'admin.php?page='.$_GET['page']);
140      }
141    }
142  }
143
144  if ('del_tags' == $action)
145  {
146    if (count($_POST['del_tags']) == 0)
147    {
148      array_push($page['errors'], l10n('Select at least one tag'));
149    }
150   
151    $query = '
152DELETE
153  FROM '.IMAGE_TAG_TABLE.'
154  WHERE image_id IN ('.implode(',', $collection).')
155    AND tag_id IN ('.implode(',', $_POST['del_tags']).')
156;';
157    pwg_query($query);
158  }
159
160  if ('associate' == $action)
161  {
162    associate_images_to_categories(
163      $collection,
164      array($_POST['associate'])
165      );
166
167    $_SESSION['page_infos'] = array(
168      l10n('Information data registered in database')
169      );
170   
171    // let's refresh the page because we the current set might be modified
172    if ('with no album' == $page['prefilter'])
173    {
174      redirect($redirect_url);
175    }
176
177    if ('with no virtual album' == $page['prefilter'])
178    {
179      $category_info = get_cat_info($_POST['associate']);
180      if (empty($category_info['dir']))
181      {
182        redirect($redirect_url);
183      }
184    }
185  }
186
187  if ('dissociate' == $action)
188  {
189    // physical links must not be broken, so we must first retrieve image_id
190    // which create virtual links with the category to "dissociate from".
191    $query = '
192SELECT id
193  FROM '.IMAGE_CATEGORY_TABLE.'
194    INNER JOIN '.IMAGES_TABLE.' ON image_id = id
195  WHERE category_id = '.$_POST['dissociate'].'
196    AND id IN ('.implode(',', $collection).')
197    AND (
198      category_id != storage_category_id
199      OR storage_category_id IS NULL
200    )
201;';
202    $dissociables = array_from_query($query, 'id');
203
204    if (!empty($dissociables))
205    {
206      $query = '
207DELETE
208  FROM '.IMAGE_CATEGORY_TABLE.'
209  WHERE category_id = '.$_POST['dissociate'].'
210    AND image_id IN ('.implode(',', $dissociables).')
211';
212      pwg_query($query);
213
214      update_category($_POST['dissociate']);
215     
216      $_SESSION['page_infos'] = array(
217        l10n('Information data registered in database')
218        );
219     
220      // let's refresh the page because we the current set might be modified
221      redirect($redirect_url);
222    }
223  }
224
225  // author
226  if ('author' == $action)
227  {
228    if (isset($_POST['remove_author']))
229    {
230      $_POST['author'] = null;
231    }
232   
233    $datas = array();
234    foreach ($collection as $image_id)
235    {
236      array_push(
237        $datas,
238        array(
239          'id' => $image_id,
240          'author' => $_POST['author']
241          )
242        );
243    }
244
245    mass_updates(
246      IMAGES_TABLE,
247      array('primary' => array('id'), 'update' => array('author')),
248      $datas
249      );
250  }
251
252  // title
253  if ('title' == $action)
254  {
255    if (isset($_POST['remove_title']))
256    {
257      $_POST['title'] = null;
258    }
259   
260    $datas = array();
261    foreach ($collection as $image_id)
262    {
263      array_push(
264        $datas,
265        array(
266          'id' => $image_id,
267          'name' => $_POST['title']
268          )
269        );
270    }
271
272    mass_updates(
273      IMAGES_TABLE,
274      array('primary' => array('id'), 'update' => array('name')),
275      $datas
276      );
277  }
278 
279  // date_creation
280  if ('date_creation' == $action)
281  {
282    $date_creation = sprintf(
283      '%u-%u-%u',
284      $_POST['date_creation_year'],
285      $_POST['date_creation_month'],
286      $_POST['date_creation_day']
287      );
288
289    if (isset($_POST['remove_date_creation']))
290    {
291      $date_creation = null;
292    }
293
294    $datas = array();
295    foreach ($collection as $image_id)
296    {
297      array_push(
298        $datas,
299        array(
300          'id' => $image_id,
301          'date_creation' => $date_creation
302          )
303        );
304    }
305
306    mass_updates(
307      IMAGES_TABLE,
308      array('primary' => array('id'), 'update' => array('date_creation')),
309      $datas
310      );
311  }
312 
313  // privacy_level
314  if ('level' == $action)
315  {
316    $datas = array();
317    foreach ($collection as $image_id)
318    {
319      array_push(
320        $datas,
321        array(
322          'id' => $image_id,
323          'level' => $_POST['level']
324          )
325        );
326    }
327
328    mass_updates(
329      IMAGES_TABLE,
330      array('primary' => array('id'), 'update' => array('level')),
331      $datas
332      );
333
334    if (isset($_SESSION['bulk_manager_filter']['level']))
335    {
336      if ($_POST['level'] < $_SESSION['bulk_manager_filter']['level'])
337      {
338        redirect($redirect_url);
339      }
340    }
341  }
342 
343  // add_to_caddie
344  if ('add_to_caddie' == $action)
345  {
346    fill_caddie($collection);
347  }
348 
349  // delete
350  if ('delete' == $action)
351  {
352    if (isset($_POST['confirm_deletion']) and 1 == $_POST['confirm_deletion'])
353    {
354      $deleted_count = delete_elements($collection, true);
355      if ($deleted_count > 0)
356      {
357        $_SESSION['page_infos'] = array(
358          sprintf(
359            l10n_dec(
360              '%d photo was deleted',
361              '%d photos were deleted',
362              $deleted_count
363              ),
364            $deleted_count
365            )
366          );
367
368        $redirect_url = get_root_url().'admin.php?page='.$_GET['page'];
369        redirect($redirect_url);
370      }
371      else
372      {
373        array_push($page['errors'], l10n('No photo can be deleted'));
374      }
375    }
376    else
377    {
378      array_push($page['errors'], l10n('You need to confirm deletion'));
379    }
380  }
381
382  // synchronize metadata
383  if ('metadata' == $action)
384  {
385    $query = '
386SELECT id, path
387  FROM '.IMAGES_TABLE.'
388  WHERE id IN ('.implode(',', $collection).')
389;';
390    $id_to_path = array();
391    $result = pwg_query($query);
392    while ($row = pwg_db_fetch_assoc($result))
393    {
394      $id_to_path[$row['id']] = $row['path'];
395    }
396   
397    update_metadata($id_to_path);
398
399    array_push(
400      $page['infos'],
401      l10n('Metadata synchronized from file')
402      );
403  }
404
405  if ('regenerateThumbnails' == $action)
406  {
407    if ($_POST['regenerateSuccess'] != '0')
408      array_push($page['infos'], sprintf(l10n('%s thumbnails have been regenerated'), $_POST['regenerateSuccess']));
409
410    if ($_POST['regenerateError'] != '0')
411      array_push($page['warnings'], sprintf(l10n('%s thumbnails can not be regenerated'), $_POST['regenerateError']));
412
413    $update_fields = array('thumb_maxwidth', 'thumb_maxheight', 'thumb_quality', 'thumb_crop', 'thumb_follow_orientation');
414  }
415
416  if ('regenerateWebsize' == $action)
417  {
418    if ($_POST['regenerateSuccess'] != '0')
419      array_push($page['infos'], sprintf(l10n('%s photos have been regenerated'), $_POST['regenerateSuccess']));
420
421    if ($_POST['regenerateError'] != '0')
422      array_push($page['warnings'], sprintf(l10n('%s photos can not be regenerated'), $_POST['regenerateError']));
423
424    $update_fields = array('websize_maxwidth', 'websize_maxheight', 'websize_quality');
425  }
426
427  if (!empty($update_fields))
428  {
429    // Update upload configuration
430    $updates = array();
431    foreach ($update_fields as $field)
432    {
433      $value = !empty($_POST[$field]) ? $_POST[$field] : null;
434      $form_values[$field] = $value;
435      $updates[$field] = $value;
436    }
437    save_upload_form_config($updates);
438    $template->delete_compiled_templates();
439  }
440
441  trigger_action('element_set_global_action', $action, $collection);
442}
443
444// +-----------------------------------------------------------------------+
445// |                             template init                             |
446// +-----------------------------------------------------------------------+
447$template->set_filenames(array('batch_manager_global' => 'batch_manager_global.tpl'));
448
449$base_url = get_root_url().'admin.php';
450
451$prefilters = array();
452
453array_push($prefilters,
454  array('ID' => 'caddie', 'NAME' => l10n('caddie')),
455  array('ID' => 'last import', 'NAME' => l10n('last import')),
456  array('ID' => 'with no album', 'NAME' => l10n('with no album')),
457  array('ID' => 'with no tag', 'NAME' => l10n('with no tag')),
458  array('ID' => 'duplicates', 'NAME' => l10n('duplicates')),
459  array('ID' => 'all photos', 'NAME' => l10n('All'))
460);
461
462if ($conf['enable_synchronization'])
463{
464  array_push($prefilters,
465    array('ID' => 'with no virtual album', 'NAME' => l10n('with no virtual album'))
466  );
467}
468
469$prefilters = trigger_event('get_batch_manager_prefilters', $prefilters);
470usort($prefilters, 'UC_name_compare');
471
472$template->assign(
473  array(
474    'prefilters' => $prefilters,
475    'filter' => $_SESSION['bulk_manager_filter'],
476    'selection' => $collection,
477    'all_elements' => $page['cat_elements_id'],
478    'upload_form_settings' => $form_values,
479    'U_DISPLAY'=>$base_url.get_query_string_diff(array('display')),
480    'F_ACTION'=>$base_url.get_query_string_diff(array('cat')),
481   )
482 );
483
484// +-----------------------------------------------------------------------+
485// |                            caddie options                             |
486// +-----------------------------------------------------------------------+
487
488$in_caddie = false;
489if (isset($_SESSION['bulk_manager_filter']['prefilter'])
490    and 'caddie' == $_SESSION['bulk_manager_filter']['prefilter'])
491{
492  $in_caddie = true;
493}
494$template->assign('IN_CADDIE', $in_caddie);
495
496// +-----------------------------------------------------------------------+
497// |                            deletion form                              |
498// +-----------------------------------------------------------------------+
499
500// we can only remove photos that have no storage_category_id, in other
501// word, it currently (Butterfly) means that the photo was added with
502// pLoader
503if (count($page['cat_elements_id']) > 0)
504{
505  $query = '
506SELECT
507    id
508  FROM '.IMAGES_TABLE.'
509  WHERE id IN ('.implode(',', $page['cat_elements_id']).')
510    AND file NOT LIKE \'http%\'
511  LIMIT 1
512;';
513  ;
514
515  if ( pwg_db_fetch_row(pwg_query($query)) )
516  {
517    $template->assign('show_delete_form', true);
518  }
519}
520
521// +-----------------------------------------------------------------------+
522// |                           global mode form                            |
523// +-----------------------------------------------------------------------+
524
525// privacy level
526$template->assign(
527    array(
528      'filter_level_options'=> get_privacy_level_options(),
529      'filter_level_options_selected' => isset($_SESSION['bulk_manager_filter']['level'])
530        ? $_SESSION['bulk_manager_filter']['level']
531        : 0,
532    )
533  );
534
535if (!empty($_SESSION['bulk_manager_filter']['tags']))
536{
537  $query = '
538SELECT
539    id,
540    name
541  FROM '.TAGS_TABLE.'
542  WHERE id IN ('.implode(',', $_SESSION['bulk_manager_filter']['tags']).')
543;';
544  $template->assign('filter_tags', get_taglist($query));
545}
546
547// Virtualy associate a picture to a category
548$query = '
549SELECT id,name,uppercats,global_rank
550  FROM '.CATEGORIES_TABLE.'
551;';
552display_select_cat_wrapper($query, array(), 'associate_options', true);
553
554// in the filter box, which category to select by default
555$selected_category = array();
556
557if (isset($_SESSION['bulk_manager_filter']['category']))
558{
559  $selected_category = array($_SESSION['bulk_manager_filter']['category']);
560}
561else
562{
563  // we need to know the category in which the last photo was added
564  $selected_category = array();
565
566  $query = '
567SELECT
568    category_id,
569    id_uppercat
570  FROM '.IMAGES_TABLE.' AS i
571    JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON image_id = i.id
572    JOIN '.CATEGORIES_TABLE.' AS c ON category_id = c.id
573  ORDER BY i.id DESC
574  LIMIT 1
575;';
576  $result = pwg_query($query);
577  if (pwg_db_num_rows($result) > 0)
578  {
579    $row = pwg_db_fetch_assoc($result);
580 
581    $selected_category = array($row['category_id']);
582  }
583}
584
585$query = '
586SELECT id,name,uppercats,global_rank
587  FROM '.CATEGORIES_TABLE.'
588;';
589display_select_cat_wrapper($query, $selected_category, 'filter_category_options', true);
590
591// Dissociate from a category : categories listed for dissociation can only
592// represent virtual links. We can't create orphans. Links to physical
593// categories can't be broken.
594if (count($page['cat_elements_id']) > 0)
595{
596  $query = '
597SELECT
598    DISTINCT(category_id) AS id,
599    c.name,
600    c.uppercats,
601    c.global_rank
602  FROM '.IMAGE_CATEGORY_TABLE.' AS ic
603    JOIN '.CATEGORIES_TABLE.' AS c ON c.id = ic.category_id
604    JOIN '.IMAGES_TABLE.' AS i ON i.id = ic.image_id
605  WHERE ic.image_id IN ('.implode(',', $page['cat_elements_id']).')
606    AND (
607      ic.category_id != i.storage_category_id
608      OR i.storage_category_id IS NULL
609    )
610;';
611  display_select_cat_wrapper($query, array(), 'dissociate_options', true);
612}
613
614if (count($page['cat_elements_id']) > 0)
615{
616  // remove tags
617  $tags = get_common_tags($page['cat_elements_id'], -1);
618
619  $template->assign(
620    array(
621      'DEL_TAG_SELECTION' => get_html_tag_selection($tags, 'del_tags'),
622      )
623    );
624}
625
626// creation date
627$day =
628empty($_POST['date_creation_day']) ? date('j') : $_POST['date_creation_day'];
629
630$month =
631empty($_POST['date_creation_month']) ? date('n') : $_POST['date_creation_month'];
632
633$year =
634empty($_POST['date_creation_year']) ? date('Y') : $_POST['date_creation_year'];
635
636$month_list = $lang['month'];
637$month_list[0]='------------';
638ksort($month_list);
639$template->assign( array(
640      'month_list'         => $month_list,
641      'DATE_CREATION_DAY'  => (int)$day,
642      'DATE_CREATION_MONTH'=> (int)$month,
643      'DATE_CREATION_YEAR' => (int)$year,
644    )
645  );
646
647// image level options
648$template->assign(
649    array(
650      'level_options'=> get_privacy_level_options(),
651      'level_options_selected' => 0,
652    )
653  );
654
655// metadata
656include_once( PHPWG_ROOT_PATH.'admin/site_reader_local.php');
657$site_reader = new LocalSiteReader('./');
658$used_metadata = implode( ', ', $site_reader->get_metadata_attributes());
659
660$template->assign(
661    array(
662      'used_metadata' => $used_metadata,
663    )
664  );
665
666// +-----------------------------------------------------------------------+
667// |                        global mode thumbnails                         |
668// +-----------------------------------------------------------------------+
669
670// how many items to display on this page
671if (!empty($_GET['display']))
672{
673  if ('all' == $_GET['display'])
674  {
675    $page['nb_images'] = count($page['cat_elements_id']);
676  }
677  else
678  {
679    $page['nb_images'] = intval($_GET['display']);
680  }
681}
682else
683{
684  $page['nb_images'] = 20;
685}
686
687$nb_thumbs_page = 0;
688
689if (count($page['cat_elements_id']) > 0)
690{
691  $nav_bar = create_navigation_bar(
692    $base_url.get_query_string_diff(array('start')),
693    count($page['cat_elements_id']),
694    $page['start'],
695    $page['nb_images']
696    );
697  $template->assign('navbar', $nav_bar);
698
699  $is_category = false;
700  if (isset($_SESSION['bulk_manager_filter']['category'])
701      and !isset($_SESSION['bulk_manager_filter']['category_recursive']))
702  {
703    $is_category = true;
704  }
705
706  if (isset($_SESSION['bulk_manager_filter']['prefilter'])
707      and 'duplicates' == $_SESSION['bulk_manager_filter']['prefilter'])
708  {
709    $conf['order_by'] = ' ORDER BY file, id';
710  }
711
712
713  $query = '
714SELECT id,path,tn_ext,file,filesize,level,name
715  FROM '.IMAGES_TABLE;
716 
717  if ($is_category)
718  {
719    $category_info = get_cat_info($_SESSION['bulk_manager_filter']['category']);
720   
721    $conf['order_by'] = $conf['order_by_inside_category'];
722    if (!empty($category_info['image_order']))
723    {
724      $conf['order_by'] = ' ORDER BY '.$category_info['image_order'];
725    }
726
727    $query.= '
728    JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id';
729  }
730
731  $query.= '
732  WHERE id IN ('.implode(',', $page['cat_elements_id']).')';
733
734  if ($is_category)
735  {
736    $query.= '
737    AND category_id = '.$_SESSION['bulk_manager_filter']['category'];
738  }
739
740  $query.= '
741  '.$conf['order_by'].'
742  LIMIT '.$page['nb_images'].' OFFSET '.$page['start'].'
743;';
744  $result = pwg_query($query);
745
746  // template thumbnail initialization
747  while ($row = pwg_db_fetch_assoc($result))
748  {
749    $nb_thumbs_page++;
750    $src = get_thumbnail_url($row);
751
752    $title = $row['name'];
753    if (empty($title))
754    {     
755      $title = get_name_from_file($row['file']);
756    }
757
758    $template->append(
759      'thumbnails',
760      array(
761        'ID' => $row['id'],
762        'TN_SRC' => $src,
763        'FILE' => $row['file'],
764        'TITLE' => $title,
765        'LEVEL' => $row['level']
766        )
767      );
768  }
769}
770
771$template->assign(
772  array(
773    'nb_thumbs_page' => $nb_thumbs_page,
774    'nb_thumbs_set' => count($page['cat_elements_id']),
775    )
776  );
777
778function regenerateThumbnails_prefilter($content, $smarty)
779{
780  return str_replace('{$thumbnail.TN_SRC}', '{$thumbnail.TN_SRC}?rand='.md5(uniqid(rand(), true)), $content);
781}
782$template->set_prefilter('batch_manager_global', 'regenerateThumbnails_prefilter');
783
784trigger_action('loc_end_element_set_global');
785
786//----------------------------------------------------------- sending html code
787$template->assign_var_from_handle('ADMIN_CONTENT', 'batch_manager_global');
788?>
Note: See TracBrowser for help on using the repository browser.