source: trunk/admin/include/functions.php @ 13052

Last change on this file since 13052 was 13052, checked in by rvelices, 12 years ago

upgrade jquery to 1.7.1
mouseout on index drop down bozes
improved multisize center of interest

  • Property svn:eol-style set to LF
File size: 52.7 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2012 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
24include(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
25
26// The function delete_site deletes a site and call the function
27// delete_categories for each primary category of the site
28function delete_site( $id )
29{
30  // destruction of the categories of the site
31  $query = '
32SELECT id
33  FROM '.CATEGORIES_TABLE.'
34  WHERE site_id = '.$id.'
35;';
36  $result = pwg_query($query);
37  $category_ids = array();
38  while ($row = pwg_db_fetch_assoc($result))
39  {
40    array_push($category_ids, $row['id']);
41  }
42  delete_categories($category_ids);
43
44  // destruction of the site
45  $query = '
46DELETE FROM '.SITES_TABLE.'
47  WHERE id = '.$id.'
48;';
49  pwg_query($query);
50}
51
52
53// The function delete_categories deletes the categories identified by the
54// (numeric) key of the array $ids. It also deletes (in the database) :
55//    - all the elements physically linked to the category (delete_elements, see further)
56//    - all the links between elements and this category
57//    - all the restrictions linked to the category
58// The function works recursively.
59//
60// the $photo_deletion_mode is for photos virtually linked to the categorty
61//   * no_delete : delete no photo, may create orphans
62//   * delete_orphans : delete photos that are no longer linked to any category
63//   * force_delete : delete photos even if they are linked to another category
64function delete_categories($ids, $photo_deletion_mode='no_delete')
65{
66  if (count($ids) == 0)
67  {
68    return;
69  }
70
71  // add sub-category ids to the given ids : if a category is deleted, all
72  // sub-categories must be so
73  $ids = get_subcat_ids($ids);
74
75  // destruction of all photos physically linked to the category
76  $query = '
77SELECT id
78  FROM '.IMAGES_TABLE.'
79  WHERE storage_category_id IN (
80'.wordwrap(implode(', ', $ids), 80, "\n").')
81;';
82  $result = pwg_query($query);
83  $element_ids = array();
84  while ($row = pwg_db_fetch_assoc($result))
85  {
86    array_push($element_ids, $row['id']);
87  }
88  delete_elements($element_ids);
89
90  // now, should we delete photos that are virtually linked to the category?
91  if ('delete_orphans' == $photo_deletion_mode or 'force_delete' == $photo_deletion_mode)
92  {
93    $query = '
94SELECT
95    DISTINCT(image_id)
96  FROM '.IMAGE_CATEGORY_TABLE.'
97  WHERE category_id IN ('.implode(',', $ids).')
98;';
99    $image_ids_linked = array_from_query($query, 'image_id');
100
101    if (count($image_ids_linked) > 0)
102    {
103      if ('delete_orphans' == $photo_deletion_mode)
104      {
105        $query = '
106SELECT
107    DISTINCT(image_id)
108  FROM '.IMAGE_CATEGORY_TABLE.'
109  WHERE image_id IN ('.implode(',', $image_ids_linked).')
110    AND category_id NOT IN ('.implode(',', $ids).')
111;';
112        $image_ids_not_orphans = array_from_query($query, 'image_id');
113        $image_ids_to_delete = array_diff($image_ids_linked, $image_ids_not_orphans);
114      }
115
116      if ('force_delete' == $photo_deletion_mode)
117      {
118        $image_ids_to_delete = $image_ids_linked;
119      }
120
121      delete_elements($image_ids_to_delete, true);
122    }
123  }
124
125  // destruction of the links between images and this category
126  $query = '
127DELETE FROM '.IMAGE_CATEGORY_TABLE.'
128  WHERE category_id IN (
129'.wordwrap(implode(', ', $ids), 80, "\n").')
130;';
131  pwg_query($query);
132
133  // destruction of the access linked to the category
134  $query = '
135DELETE FROM '.USER_ACCESS_TABLE.'
136  WHERE cat_id IN (
137'.wordwrap(implode(', ', $ids), 80, "\n").')
138;';
139  pwg_query($query);
140
141  $query = '
142DELETE FROM '.GROUP_ACCESS_TABLE.'
143  WHERE cat_id IN (
144'.wordwrap(implode(', ', $ids), 80, "\n").')
145;';
146  pwg_query($query);
147
148  // destruction of the category
149  $query = '
150DELETE FROM '.CATEGORIES_TABLE.'
151  WHERE id IN (
152'.wordwrap(implode(', ', $ids), 80, "\n").')
153;';
154  pwg_query($query);
155
156  $query='
157DELETE FROM '.OLD_PERMALINKS_TABLE.'
158  WHERE cat_id IN ('.implode(',',$ids).')';
159  pwg_query($query);
160
161  $query='
162DELETE FROM '.USER_CACHE_CATEGORIES_TABLE.'
163  WHERE cat_id IN ('.implode(',',$ids).')';
164  pwg_query($query);
165
166  trigger_action('delete_categories', $ids);
167}
168
169// Deletes all files (on disk) related to given image ids
170// @return image ids where files are deleted successfully
171function delete_element_files($ids)
172{
173  if (count($ids) == 0)
174  {
175    return 0;
176  }
177
178  $new_ids = array();
179
180  $query = '
181SELECT
182    id,
183    path,
184    representative_ext
185  FROM '.IMAGES_TABLE.'
186  WHERE id IN ('.implode(',', $ids).')
187;';
188  $result = pwg_query($query);
189  while ($row = pwg_db_fetch_assoc($result))
190  {
191    if (url_is_remote($row['path']))
192    {
193      continue;
194    }
195
196    $files = array();
197    $files[] = get_element_path($row);
198
199    if (!empty($row['representative_ext']))
200    {
201      $files[] = original_to_representative( $files[0], $row['representative_ext']);
202    }
203
204    $ok = true;
205    if (!isset($conf['never_delete_originals']))
206    {
207      foreach ($files as $path)
208      {
209        if (is_file($path) and !unlink($path))
210        {
211          $ok = false;
212          trigger_error('"'.$path.'" cannot be removed', E_USER_WARNING);
213          break;
214        }
215      }
216    }
217
218    if ($ok)
219    {
220      delete_element_derivatives($row);
221      $new_ids[] += $row['id'];
222    }
223    else
224    {
225      break;
226    }
227  }
228  return $new_ids;
229}
230
231// The function delete_elements deletes the elements identified by the
232// (numeric) values of the array $ids. It also deletes (in the database) :
233//    - all the comments related to elements
234//    - all the links between categories and elements
235//    - all the favorites associated to elements
236// @return number of deleted elements
237function delete_elements($ids, $physical_deletion=false)
238{
239  if (count($ids) == 0)
240  {
241    return 0;
242  }
243  trigger_action('begin_delete_elements', $ids);
244
245  if ($physical_deletion)
246  {
247    $ids = delete_element_files($ids);
248    if (count($ids)==0)
249    {
250      return 0;
251    }
252  }
253
254  // destruction of the comments on the image
255  $query = '
256DELETE FROM '.COMMENTS_TABLE.'
257  WHERE image_id IN (
258'.wordwrap(implode(', ', $ids), 80, "\n").')
259;';
260  pwg_query($query);
261
262  // destruction of the links between images and this category
263  $query = '
264DELETE FROM '.IMAGE_CATEGORY_TABLE.'
265  WHERE image_id IN (
266'.wordwrap(implode(', ', $ids), 80, "\n").')
267;';
268  pwg_query($query);
269
270  // destruction of the links between images and tags
271  $query = '
272DELETE FROM '.IMAGE_TAG_TABLE.'
273  WHERE image_id IN (
274'.wordwrap(implode(', ', $ids), 80, "\n").')
275;';
276  pwg_query($query);
277
278  // destruction of the favorites associated with the picture
279  $query = '
280DELETE FROM '.FAVORITES_TABLE.'
281  WHERE image_id IN (
282'.wordwrap(implode(', ', $ids), 80, "\n").')
283;';
284  pwg_query($query);
285
286  // destruction of the rates associated to this element
287  $query = '
288DELETE FROM '.RATE_TABLE.'
289  WHERE element_id IN (
290'.wordwrap(implode(', ', $ids), 80, "\n").')
291;';
292  pwg_query($query);
293
294  // destruction of the rates associated to this element
295  $query = '
296DELETE FROM '.CADDIE_TABLE.'
297  WHERE element_id IN (
298'.wordwrap(implode(', ', $ids), 80, "\n").')
299;';
300  pwg_query($query);
301
302  // destruction of the image
303  $query = '
304DELETE FROM '.IMAGES_TABLE.'
305  WHERE id IN (
306'.wordwrap(implode(', ', $ids), 80, "\n").')
307;';
308  pwg_query($query);
309
310  // are the photo used as category representant?
311  $query = '
312SELECT
313    id
314  FROM '.CATEGORIES_TABLE.'
315  WHERE representative_picture_id IN (
316'.wordwrap(implode(', ', $ids), 80, "\n").')
317;';
318  $category_ids = array_from_query($query, 'id');
319  if (count($category_ids) > 0)
320  {
321    update_category($category_ids);
322  }
323
324  trigger_action('delete_elements', $ids);
325  return count($ids);
326}
327
328// The delete_user function delete a user identified by the $user_id
329// It also deletes :
330//     - all the access linked to this user
331//     - all the links to any group
332//     - all the favorites linked to this user
333//     - calculated permissions linked to the user
334//     - all datas about notifications for the user
335function delete_user($user_id)
336{
337  global $conf;
338  $tables = array(
339    // destruction of the access linked to the user
340    USER_ACCESS_TABLE,
341    // destruction of data notification by mail for this user
342    USER_MAIL_NOTIFICATION_TABLE,
343    // destruction of data RSS notification for this user
344    USER_FEED_TABLE,
345    // deletion of calculated permissions linked to the user
346    USER_CACHE_TABLE,
347    // deletion of computed cache data linked to the user
348    USER_CACHE_CATEGORIES_TABLE,
349    // destruction of the group links for this user
350    USER_GROUP_TABLE,
351    // destruction of the favorites associated with the user
352    FAVORITES_TABLE,
353    // destruction of the caddie associated with the user
354    CADDIE_TABLE,
355    // deletion of piwigo specific informations
356    USER_INFOS_TABLE,
357    );
358
359  foreach ($tables as $table)
360  {
361    $query = '
362DELETE FROM '.$table.'
363  WHERE user_id = '.$user_id.'
364;';
365    pwg_query($query);
366  }
367
368  // destruction of the user
369  $query = '
370DELETE FROM '.SESSIONS_TABLE.'
371  WHERE data LIKE \'pwg_uid|i:'.(int)$user_id.';%\'
372;';
373  pwg_query($query);
374
375  // destruction of the user
376  $query = '
377DELETE FROM '.USERS_TABLE.'
378  WHERE '.$conf['user_fields']['id'].' = '.$user_id.'
379;';
380  pwg_query($query);
381
382  trigger_action('delete_user', $user_id);
383}
384
385/**
386 * Deletes all tags linked to no photo
387 */
388function delete_orphan_tags()
389{
390  $orphan_tags = get_orphan_tags();
391
392  if (count($orphan_tags) > 0)
393  {
394    $orphan_tag_ids = array();
395    foreach ($orphan_tags as $tag)
396    {
397      array_push($orphan_tag_ids, $tag['id']);
398    }
399
400    $query = '
401DELETE
402  FROM '.TAGS_TABLE.'
403  WHERE id IN ('.implode(',', $orphan_tag_ids).')
404;';
405    pwg_query($query);
406  }
407}
408
409/**
410 * Get all tags (id + name) linked to no photo
411 */
412function get_orphan_tags()
413{
414  $orphan_tags = array();
415
416  $query = '
417SELECT
418    id,
419    name
420  FROM '.TAGS_TABLE.'
421    LEFT JOIN '.IMAGE_TAG_TABLE.' ON id = tag_id
422  WHERE tag_id IS NULL
423;';
424  $result = pwg_query($query);
425  while ($row = pwg_db_fetch_assoc($result))
426  {
427    array_push($orphan_tags, $row);
428  }
429
430  return $orphan_tags;
431}
432
433/**
434 * Verifies that the representative picture really exists in the db and
435 * picks up a random represantive if possible and based on config.
436 *
437 * @param mixed category id
438 * @returns void
439 */
440function update_category($ids = 'all')
441{
442  global $conf;
443
444  if ($ids=='all')
445  {
446    $where_cats = '1=1';
447  }
448  elseif ( !is_array($ids) )
449  {
450    $where_cats = '%s='.$ids;
451  }
452  else
453  {
454    if (count($ids) == 0)
455    {
456      return false;
457    }
458    $where_cats = '%s IN('.wordwrap(implode(', ', $ids), 120, "\n").')';
459  }
460
461  // find all categories where the setted representative is not possible :
462  // the picture does not exist
463  $query = '
464SELECT DISTINCT c.id
465  FROM '.CATEGORIES_TABLE.' AS c LEFT JOIN '.IMAGES_TABLE.' AS i
466    ON c.representative_picture_id = i.id
467  WHERE representative_picture_id IS NOT NULL
468    AND '.sprintf($where_cats, 'c.id').'
469    AND i.id IS NULL
470;';
471  $wrong_representant = array_from_query($query, 'id');
472
473  if (count($wrong_representant) > 0)
474  {
475    $query = '
476UPDATE '.CATEGORIES_TABLE.'
477  SET representative_picture_id = NULL
478  WHERE id IN ('.wordwrap(implode(', ', $wrong_representant), 120, "\n").')
479;';
480    pwg_query($query);
481  }
482
483  if (!$conf['allow_random_representative'])
484  {
485    // If the random representant is not allowed, we need to find
486    // categories with elements and with no representant. Those categories
487    // must be added to the list of categories to set to a random
488    // representant.
489    $query = '
490SELECT DISTINCT id
491  FROM '.CATEGORIES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.'
492    ON id = category_id
493  WHERE representative_picture_id IS NULL
494    AND '.sprintf($where_cats, 'category_id').'
495;';
496    $to_rand = array_from_query($query, 'id');
497    if (count($to_rand) > 0)
498    {
499      set_random_representant($to_rand);
500    }
501  }
502}
503
504/**
505 * returns an array containing sub-directories which can be a category,
506 * recursive by default
507 *
508 * directories nammed "thumbnail", "pwg_high" or "pwg_representative" are
509 * omitted
510 *
511 * @param string $basedir
512 * @return array
513 */
514function get_fs_directories($path, $recursive = true)
515{
516  $dirs = array();
517
518  if (is_dir($path))
519  {
520    if ($contents = opendir($path))
521    {
522      while (($node = readdir($contents)) !== false)
523      {
524        if ($node != '.'
525            and $node != '..'
526            and $node != '.svn'
527            and $node != 'thumbnail'
528            and $node != 'pwg_high'
529            and $node != 'pwg_representative'
530            and is_dir($path.'/'.$node))
531        {
532          array_push($dirs, $path.'/'.$node);
533          if ($recursive)
534          {
535            $dirs = array_merge($dirs, get_fs_directories($path.'/'.$node));
536          }
537        }
538      }
539      closedir($contents);
540    }
541  }
542
543  return $dirs;
544}
545
546/**
547 * order categories (update categories.rank and global_rank database fields)
548 * so that rank field are consecutive integers starting at 1 for each child
549 * @return void
550 */
551function update_global_rank()
552{
553  $query = '
554SELECT id, id_uppercat, uppercats, rank, global_rank
555  FROM '.CATEGORIES_TABLE.'
556  ORDER BY id_uppercat,rank,name';
557
558  $cat_map = array();
559
560  $current_rank = 0;
561  $current_uppercat = '';
562
563  $result = pwg_query($query);
564  while ($row = pwg_db_fetch_assoc($result))
565  {
566    if ($row['id_uppercat'] != $current_uppercat)
567    {
568      $current_rank = 0;
569      $current_uppercat = $row['id_uppercat'];
570    }
571    ++$current_rank;
572    $cat =
573      array(
574        'rank' =>        $current_rank,
575        'rank_changed' =>$current_rank!=$row['rank'],
576        'global_rank' => $row['global_rank'],
577        'uppercats' =>   $row['uppercats'],
578        );
579    $cat_map[ $row['id'] ] = $cat;
580  }
581
582  $datas = array();
583
584  foreach( $cat_map as $id=>$cat )
585  {
586    $new_global_rank = preg_replace(
587          '/(\d+)/e',
588          "\$cat_map['$1']['rank']",
589          str_replace(',', '.', $cat['uppercats'] )
590          );
591    if ( $cat['rank_changed']
592      or $new_global_rank!=$cat['global_rank']
593      )
594    {
595      $datas[] = array(
596          'id' => $id,
597          'rank' => $cat['rank'],
598          'global_rank' => $new_global_rank,
599        );
600    }
601  }
602
603  mass_updates(
604    CATEGORIES_TABLE,
605    array(
606      'primary' => array('id'),
607      'update'  => array('rank', 'global_rank')
608      ),
609    $datas
610    );
611  return count($datas);
612}
613
614/**
615 * change the visible property on a set of categories
616 *
617 * @param array categories
618 * @param string value
619 * @return void
620 */
621function set_cat_visible($categories, $value)
622{
623  if (!in_array($value, array('true', 'false')))
624  {
625    trigger_error("set_cat_visible invalid param $value", E_USER_WARNING);
626    return false;
627  }
628
629  // unlocking a category => all its parent categories become unlocked
630  if ($value == 'true')
631  {
632    $uppercats = get_uppercat_ids($categories);
633    $query = '
634UPDATE '.CATEGORIES_TABLE.'
635  SET visible = \'true\'
636  WHERE id IN ('.implode(',', $uppercats).')';
637    pwg_query($query);
638  }
639  // locking a category   => all its child categories become locked
640  if ($value == 'false')
641  {
642    $subcats = get_subcat_ids($categories);
643    $query = '
644UPDATE '.CATEGORIES_TABLE.'
645  SET visible = \'false\'
646  WHERE id IN ('.implode(',', $subcats).')';
647    pwg_query($query);
648  }
649}
650
651/**
652 * change the status property on a set of categories : private or public
653 *
654 * @param array categories
655 * @param string value
656 * @return void
657 */
658function set_cat_status($categories, $value)
659{
660  if (!in_array($value, array('public', 'private')))
661  {
662    trigger_error("set_cat_status invalid param $value", E_USER_WARNING);
663    return false;
664  }
665
666  // make public a category => all its parent categories become public
667  if ($value == 'public')
668  {
669    $uppercats = get_uppercat_ids($categories);
670    $query = '
671UPDATE '.CATEGORIES_TABLE.'
672  SET status = \'public\'
673  WHERE id IN ('.implode(',', $uppercats).')
674;';
675    pwg_query($query);
676  }
677  // make a category private => all its child categories become private
678  if ($value == 'private')
679  {
680    $subcats = get_subcat_ids($categories);
681    $query = '
682UPDATE '.CATEGORIES_TABLE.'
683  SET status = \'private\'
684  WHERE id IN ('.implode(',', $subcats).')';
685    pwg_query($query);
686  }
687}
688
689/**
690 * returns all uppercats category ids of the given category ids
691 *
692 * @param array cat_ids
693 * @return array
694 */
695function get_uppercat_ids($cat_ids)
696{
697  if (!is_array($cat_ids) or count($cat_ids) < 1)
698  {
699    return array();
700  }
701
702  $uppercats = array();
703
704  $query = '
705SELECT uppercats
706  FROM '.CATEGORIES_TABLE.'
707  WHERE id IN ('.implode(',', $cat_ids).')
708;';
709  $result = pwg_query($query);
710  while ($row = pwg_db_fetch_assoc($result))
711  {
712    $uppercats = array_merge($uppercats,
713                             explode(',', $row['uppercats']));
714  }
715  $uppercats = array_unique($uppercats);
716
717  return $uppercats;
718}
719
720/**
721 * set a new random representant to the categories
722 *
723 * @param array categories
724 */
725function set_random_representant($categories)
726{
727  $datas = array();
728  foreach ($categories as $category_id)
729  {
730    $query = '
731SELECT image_id
732  FROM '.IMAGE_CATEGORY_TABLE.'
733  WHERE category_id = '.$category_id.'
734  ORDER BY '.DB_RANDOM_FUNCTION.'()
735  LIMIT 1
736;';
737    list($representative) = pwg_db_fetch_row(pwg_query($query));
738
739    array_push(
740      $datas,
741      array(
742        'id' => $category_id,
743        'representative_picture_id' => $representative,
744        )
745      );
746  }
747
748  mass_updates(
749    CATEGORIES_TABLE,
750    array(
751      'primary' => array('id'),
752      'update' => array('representative_picture_id')
753      ),
754    $datas
755    );
756}
757
758/**
759 * returns the fulldir for each given category id
760 *
761 * @param array cat_ids
762 * @return array
763 */
764function get_fulldirs($cat_ids)
765{
766  if (count($cat_ids) == 0)
767  {
768    return array();
769  }
770
771  // caching directories of existing categories
772  $query = '
773SELECT id, dir
774  FROM '.CATEGORIES_TABLE.'
775  WHERE dir IS NOT NULL
776;';
777  $cat_dirs = simple_hash_from_query($query, 'id', 'dir');
778
779  // caching galleries_url
780  $query = '
781SELECT id, galleries_url
782  FROM '.SITES_TABLE.'
783;';
784  $galleries_url = simple_hash_from_query($query, 'id', 'galleries_url');
785
786  // categories : id, site_id, uppercats
787  $categories = array();
788
789  $query = '
790SELECT id, uppercats, site_id
791  FROM '.CATEGORIES_TABLE.'
792  WHERE dir IS NOT NULL
793    AND id IN (
794'.wordwrap(implode(', ', $cat_ids), 80, "\n").')
795;';
796  $result = pwg_query($query);
797  while ($row = pwg_db_fetch_assoc($result))
798  {
799    array_push($categories, $row);
800  }
801
802  // filling $cat_fulldirs
803  $cat_fulldirs = array();
804  foreach ($categories as $category)
805  {
806    $uppercats = str_replace(',', '/', $category['uppercats']);
807    $cat_fulldirs[$category['id']] = $galleries_url[$category['site_id']];
808    $cat_fulldirs[$category['id']].= preg_replace('/(\d+)/e',
809                                                  "\$cat_dirs['$1']",
810                                                  $uppercats);
811  }
812
813  return $cat_fulldirs;
814}
815
816/**
817 * returns an array with all file system files according to
818 * $conf['file_ext']
819 *
820 * @param string $path
821 * @param bool recursive
822 * @return array
823 */
824function get_fs($path, $recursive = true)
825{
826  global $conf;
827
828  // because isset is faster than in_array...
829  if (!isset($conf['flip_picture_ext']))
830  {
831    $conf['flip_picture_ext'] = array_flip($conf['picture_ext']);
832  }
833  if (!isset($conf['flip_file_ext']))
834  {
835    $conf['flip_file_ext'] = array_flip($conf['file_ext']);
836  }
837
838  $fs['elements'] = array();
839  $fs['thumbnails'] = array();
840  $fs['representatives'] = array();
841  $subdirs = array();
842
843  if (is_dir($path))
844  {
845    if ($contents = opendir($path))
846    {
847      while (($node = readdir($contents)) !== false)
848      {
849        if ($node == '.' or $node == '..') continue;
850
851        if (is_file($path.'/'.$node))
852        {
853          $extension = get_extension($node);
854
855//          if (in_array($extension, $conf['picture_ext']))
856          if (isset($conf['flip_picture_ext'][$extension]))
857          {
858            if (basename($path) == 'thumbnail')
859            {
860              array_push($fs['thumbnails'], $path.'/'.$node);
861            }
862            else if (basename($path) == 'pwg_representative')
863            {
864              array_push($fs['representatives'], $path.'/'.$node);
865            }
866            else
867            {
868              array_push($fs['elements'], $path.'/'.$node);
869            }
870          }
871//          else if (in_array($extension, $conf['file_ext']))
872          else if (isset($conf['flip_file_ext'][$extension]))
873          {
874            array_push($fs['elements'], $path.'/'.$node);
875          }
876        }
877        else if (is_dir($path.'/'.$node) and $node != 'pwg_high' and $recursive)
878        {
879          array_push($subdirs, $node);
880        }
881      }
882    }
883    closedir($contents);
884
885    foreach ($subdirs as $subdir)
886    {
887      $tmp_fs = get_fs($path.'/'.$subdir);
888
889      $fs['elements']        = array_merge($fs['elements'],
890                                           $tmp_fs['elements']);
891
892      $fs['thumbnails']      = array_merge($fs['thumbnails'],
893                                           $tmp_fs['thumbnails']);
894
895      $fs['representatives'] = array_merge($fs['representatives'],
896                                           $tmp_fs['representatives']);
897    }
898  }
899  return $fs;
900}
901
902/**
903 * synchronize base users list and related users list
904 *
905 * compares and synchronizes base users table (USERS_TABLE) with its child
906 * tables (USER_INFOS_TABLE, USER_ACCESS, USER_CACHE, USER_GROUP) : each
907 * base user must be present in child tables, users in child tables not
908 * present in base table must be deleted.
909 *
910 * @return void
911 */
912function sync_users()
913{
914  global $conf;
915
916  $query = '
917SELECT '.$conf['user_fields']['id'].' AS id
918  FROM '.USERS_TABLE.'
919;';
920  $base_users = array_from_query($query, 'id');
921
922  $query = '
923SELECT user_id
924  FROM '.USER_INFOS_TABLE.'
925;';
926  $infos_users = array_from_query($query, 'user_id');
927
928  // users present in $base_users and not in $infos_users must be added
929  $to_create = array_diff($base_users, $infos_users);
930
931  if (count($to_create) > 0)
932  {
933    create_user_infos($to_create);
934  }
935
936  // users present in user related tables must be present in the base user
937  // table
938  $tables = array(
939    USER_MAIL_NOTIFICATION_TABLE,
940    USER_FEED_TABLE,
941    USER_INFOS_TABLE,
942    USER_ACCESS_TABLE,
943    USER_CACHE_TABLE,
944    USER_CACHE_CATEGORIES_TABLE,
945    USER_GROUP_TABLE
946    );
947
948  foreach ($tables as $table)
949  {
950    $query = '
951SELECT DISTINCT user_id
952  FROM '.$table.'
953;';
954    $to_delete = array_diff(
955      array_from_query($query, 'user_id'),
956      $base_users
957      );
958
959    if (count($to_delete) > 0)
960    {
961      $query = '
962DELETE
963  FROM '.$table.'
964  WHERE user_id in ('.implode(',', $to_delete).')
965;';
966      pwg_query($query);
967    }
968  }
969}
970
971/**
972 * updates categories.uppercats field based on categories.id +
973 * categories.id_uppercat
974 *
975 * @return void
976 */
977function update_uppercats()
978{
979  $query = '
980SELECT id, id_uppercat, uppercats
981  FROM '.CATEGORIES_TABLE.'
982;';
983  $cat_map = hash_from_query($query, 'id');
984
985  $datas = array();
986  foreach ($cat_map as $id => $cat)
987  {
988    $upper_list = array();
989
990    $uppercat = $id;
991    while ($uppercat)
992    {
993      array_push($upper_list, $uppercat);
994      $uppercat = $cat_map[$uppercat]['id_uppercat'];
995    }
996
997    $new_uppercats = implode(',', array_reverse($upper_list));
998    if ($new_uppercats != $cat['uppercats'])
999    {
1000      array_push(
1001        $datas,
1002        array(
1003          'id' => $id,
1004          'uppercats' => $new_uppercats
1005          )
1006        );
1007    }
1008  }
1009  $fields = array('primary' => array('id'), 'update' => array('uppercats'));
1010  mass_updates(CATEGORIES_TABLE, $fields, $datas);
1011}
1012
1013/**
1014 * update images.path field
1015 *
1016 * @return void
1017 */
1018function update_path()
1019{
1020  $query = '
1021SELECT DISTINCT(storage_category_id)
1022  FROM '.IMAGES_TABLE.'
1023  WHERE storage_category_id IS NOT NULL
1024;';
1025  $cat_ids = array_from_query($query, 'storage_category_id');
1026  $fulldirs = get_fulldirs($cat_ids);
1027
1028  foreach ($cat_ids as $cat_id)
1029  {
1030    $query = '
1031UPDATE '.IMAGES_TABLE.'
1032  SET path = '.pwg_db_concat(array("'".$fulldirs[$cat_id]."/'",'file')).'
1033  WHERE storage_category_id = '.$cat_id.'
1034;';
1035    pwg_query($query);
1036  }
1037}
1038
1039/**
1040 * change the parent category of the given categories. The categories are
1041 * supposed virtual.
1042 *
1043 * @param array category identifiers
1044 * @param int parent category identifier
1045 * @return void
1046 */
1047function move_categories($category_ids, $new_parent = -1)
1048{
1049  global $page;
1050
1051  if (count($category_ids) == 0)
1052  {
1053    return;
1054  }
1055
1056  $new_parent = $new_parent < 1 ? 'NULL' : $new_parent;
1057
1058  $categories = array();
1059
1060  $query = '
1061SELECT id, id_uppercat, status, uppercats
1062  FROM '.CATEGORIES_TABLE.'
1063  WHERE id IN ('.implode(',', $category_ids).')
1064;';
1065  $result = pwg_query($query);
1066  while ($row = pwg_db_fetch_assoc($result))
1067  {
1068    $categories[$row['id']] =
1069      array(
1070        'parent' => empty($row['id_uppercat']) ? 'NULL' : $row['id_uppercat'],
1071        'status' => $row['status'],
1072        'uppercats' => $row['uppercats']
1073        );
1074  }
1075
1076  // is the movement possible? The movement is impossible if you try to move
1077  // a category in a sub-category or itself
1078  if ('NULL' != $new_parent)
1079  {
1080    $query = '
1081SELECT uppercats
1082  FROM '.CATEGORIES_TABLE.'
1083  WHERE id = '.$new_parent.'
1084;';
1085    list($new_parent_uppercats) = pwg_db_fetch_row(pwg_query($query));
1086
1087    foreach ($categories as $category)
1088    {
1089      // technically, you can't move a category with uppercats 12,125,13,14
1090      // into a new parent category with uppercats 12,125,13,14,24
1091      if (preg_match('/^'.$category['uppercats'].'(,|$)/', $new_parent_uppercats))
1092      {
1093        array_push(
1094          $page['errors'],
1095          l10n('You cannot move an album in its own sub album')
1096          );
1097        return;
1098      }
1099    }
1100  }
1101
1102  $tables =
1103    array(
1104      USER_ACCESS_TABLE => 'user_id',
1105      GROUP_ACCESS_TABLE => 'group_id'
1106      );
1107
1108  $query = '
1109UPDATE '.CATEGORIES_TABLE.'
1110  SET id_uppercat = '.$new_parent.'
1111  WHERE id IN ('.implode(',', $category_ids).')
1112;';
1113  pwg_query($query);
1114
1115  update_uppercats();
1116  update_global_rank();
1117
1118  // status and related permissions management
1119  if ('NULL' == $new_parent)
1120  {
1121    $parent_status = 'public';
1122  }
1123  else
1124  {
1125    $query = '
1126SELECT status
1127  FROM '.CATEGORIES_TABLE.'
1128  WHERE id = '.$new_parent.'
1129;';
1130    list($parent_status) = pwg_db_fetch_row(pwg_query($query));
1131  }
1132
1133  if ('private' == $parent_status)
1134  {
1135    foreach ($categories as $cat_id => $category)
1136    {
1137      switch ($category['status'])
1138      {
1139        case 'public' :
1140        {
1141          set_cat_status(array($cat_id), 'private');
1142          break;
1143        }
1144        case 'private' :
1145        {
1146          $subcats = get_subcat_ids(array($cat_id));
1147
1148          foreach ($tables as $table => $field)
1149          {
1150            $query = '
1151SELECT '.$field.'
1152  FROM '.$table.'
1153  WHERE cat_id = '.$cat_id.'
1154;';
1155            $category_access = array_from_query($query, $field);
1156
1157            $query = '
1158SELECT '.$field.'
1159  FROM '.$table.'
1160  WHERE cat_id = '.$new_parent.'
1161;';
1162            $parent_access = array_from_query($query, $field);
1163
1164            $to_delete = array_diff($parent_access, $category_access);
1165
1166            if (count($to_delete) > 0)
1167            {
1168              $query = '
1169DELETE FROM '.$table.'
1170  WHERE '.$field.' IN ('.implode(',', $to_delete).')
1171    AND cat_id IN ('.implode(',', $subcats).')
1172;';
1173              pwg_query($query);
1174            }
1175          }
1176          break;
1177        }
1178      }
1179    }
1180  }
1181
1182  array_push(
1183    $page['infos'],
1184    l10n_dec(
1185      '%d album moved', '%d albums moved',
1186      count($categories)
1187      )
1188    );
1189}
1190
1191/**
1192 * create a virtual category
1193 *
1194 * @param string category name
1195 * @param int parent category id
1196 * @return array with ('info' and 'id') or ('error') key
1197 */
1198function create_virtual_category($category_name, $parent_id=null)
1199{
1200  global $conf, $user;
1201
1202  // is the given category name only containing blank spaces ?
1203  if (preg_match('/^\s*$/', $category_name))
1204  {
1205    return array('error' => l10n('The name of an album must not be empty'));
1206  }
1207
1208  $parent_id = !empty($parent_id) ? $parent_id : 'NULL';
1209
1210  $insert = array(
1211    'name' => $category_name,
1212    'rank' => 0,
1213    'commentable' => boolean_to_string($conf['newcat_default_commentable']),
1214    );
1215
1216  if ($parent_id != 'NULL')
1217  {
1218    $query = '
1219SELECT id, uppercats, global_rank, visible, status
1220  FROM '.CATEGORIES_TABLE.'
1221  WHERE id = '.$parent_id.'
1222;';
1223    $parent = pwg_db_fetch_assoc(pwg_query($query));
1224
1225    $insert['id_uppercat'] = $parent['id'];
1226    $insert['global_rank'] = $parent['global_rank'].'.'.$insert['rank'];
1227
1228    // at creation, must a category be visible or not ? Warning : if the
1229    // parent category is invisible, the category is automatically create
1230    // invisible. (invisible = locked)
1231    if ('false' == $parent['visible'])
1232    {
1233      $insert['visible'] = 'false';
1234    }
1235    else
1236    {
1237      $insert['visible'] = boolean_to_string($conf['newcat_default_visible']);
1238    }
1239
1240    // at creation, must a category be public or private ? Warning : if the
1241    // parent category is private, the category is automatically create
1242    // private.
1243    if ('private' == $parent['status'])
1244    {
1245      $insert['status'] = 'private';
1246    }
1247    else
1248    {
1249      $insert['status'] = $conf['newcat_default_status'];
1250    }
1251  }
1252  else
1253  {
1254    $insert['visible'] = boolean_to_string($conf['newcat_default_visible']);
1255    $insert['status'] = $conf['newcat_default_status'];
1256    $insert['global_rank'] = $insert['rank'];
1257  }
1258
1259  // we have then to add the virtual category
1260  mass_inserts(
1261    CATEGORIES_TABLE,
1262    array(
1263      'site_id', 'name', 'id_uppercat', 'rank', 'commentable',
1264      'visible', 'status', 'global_rank',
1265      ),
1266    array($insert)
1267    );
1268
1269  $inserted_id = pwg_db_insert_id(CATEGORIES_TABLE);
1270
1271  $query = '
1272UPDATE
1273  '.CATEGORIES_TABLE.'
1274  SET uppercats = \''.
1275    (isset($parent) ? $parent{'uppercats'}.',' : '').
1276    $inserted_id.
1277    '\'
1278  WHERE id = '.$inserted_id.'
1279;';
1280  pwg_query($query);
1281
1282  update_global_rank();
1283
1284  if ('private' == $insert['status'])
1285  {
1286    add_permission_on_category($inserted_id, array_unique(array_merge(get_admins(), array($user['id']))));
1287  }
1288
1289  return array(
1290    'info' => l10n('Virtual album added'),
1291    'id'   => $inserted_id,
1292    );
1293}
1294
1295/**
1296 * Set tags to an image. Warning: given tags are all tags associated to the
1297 * image, not additionnal tags.
1298 *
1299 * @param array tag ids
1300 * @param int image id
1301 * @return void
1302 */
1303function set_tags($tags, $image_id)
1304{
1305  $query = '
1306DELETE
1307  FROM '.IMAGE_TAG_TABLE.'
1308  WHERE image_id = '.$image_id.'
1309;';
1310  pwg_query($query);
1311
1312  if (count($tags) > 0)
1313  {
1314    $inserts = array();
1315    foreach ($tags as $tag_id)
1316    {
1317      array_push(
1318        $inserts,
1319        array(
1320          'tag_id' => $tag_id,
1321          'image_id' => $image_id
1322          )
1323        );
1324    }
1325    mass_inserts(
1326      IMAGE_TAG_TABLE,
1327      array_keys($inserts[0]),
1328      $inserts
1329      );
1330  }
1331}
1332
1333/**
1334 * Add new tags to a set of images.
1335 *
1336 * @param array tag ids
1337 * @param array image ids
1338 * @return void
1339 */
1340function add_tags($tags, $images)
1341{
1342  if (count($tags) == 0 or count($images) == 0)
1343  {
1344    return;
1345  }
1346
1347  // we can't insert twice the same {image_id,tag_id} so we must first
1348  // delete lines we'll insert later
1349  $query = '
1350DELETE
1351  FROM '.IMAGE_TAG_TABLE.'
1352  WHERE image_id IN ('.implode(',', $images).')
1353    AND tag_id IN ('.implode(',', $tags).')
1354;';
1355  pwg_query($query);
1356
1357  $inserts = array();
1358  foreach ($images as $image_id)
1359  {
1360    foreach ($tags as $tag_id)
1361    {
1362      array_push(
1363        $inserts,
1364        array(
1365          'image_id' => $image_id,
1366          'tag_id' => $tag_id,
1367          )
1368        );
1369    }
1370  }
1371  mass_inserts(
1372    IMAGE_TAG_TABLE,
1373    array_keys($inserts[0]),
1374    $inserts
1375    );
1376}
1377
1378/**
1379 *
1380 */
1381function delete_tags($tag_ids)
1382{
1383  if (is_numeric($tag_ids))
1384  {
1385    $tag_ids = array($tag_ids);
1386  }
1387
1388  if (!is_array($tag_ids))
1389  {
1390    return false;
1391  }
1392
1393  $query = '
1394DELETE
1395  FROM '.IMAGE_TAG_TABLE.'
1396  WHERE tag_id IN ('.implode(',', $tag_ids).')
1397;';
1398  pwg_query($query);
1399
1400  $query = '
1401DELETE
1402  FROM '.TAGS_TABLE.'
1403  WHERE id IN ('.implode(',', $tag_ids).')
1404;';
1405  pwg_query($query);
1406}
1407
1408function tag_id_from_tag_name($tag_name)
1409{
1410  global $page;
1411
1412  $tag_name = trim($tag_name);
1413  if (isset($page['tag_id_from_tag_name_cache'][$tag_name]))
1414  {
1415    return $page['tag_id_from_tag_name_cache'][$tag_name];
1416  }
1417
1418  // does the tag already exists?
1419  $query = '
1420SELECT id
1421  FROM '.TAGS_TABLE.'
1422  WHERE name = \''.$tag_name.'\'
1423;';
1424  $existing_tags = array_from_query($query, 'id');
1425
1426  if (count($existing_tags) == 0)
1427  {
1428    mass_inserts(
1429      TAGS_TABLE,
1430      array('name', 'url_name'),
1431      array(
1432        array(
1433          'name' => $tag_name,
1434          'url_name' => trigger_event('render_tag_url', $tag_name),
1435          )
1436        )
1437      );
1438
1439    $page['tag_id_from_tag_name_cache'][$tag_name] = pwg_db_insert_id(TAGS_TABLE);
1440  }
1441  else
1442  {
1443    $page['tag_id_from_tag_name_cache'][$tag_name] = $existing_tags[0];
1444  }
1445
1446  return $page['tag_id_from_tag_name_cache'][$tag_name];
1447}
1448
1449function set_tags_of($tags_of)
1450{
1451  if (count($tags_of) > 0)
1452  {
1453    $query = '
1454DELETE
1455  FROM '.IMAGE_TAG_TABLE.'
1456  WHERE image_id IN ('.implode(',', array_keys($tags_of)).')
1457;';
1458    pwg_query($query);
1459
1460    $inserts = array();
1461
1462    foreach ($tags_of as $image_id => $tag_ids)
1463    {
1464      foreach ($tag_ids as $tag_id)
1465      {
1466        array_push(
1467          $inserts,
1468          array(
1469            'image_id' => $image_id,
1470            'tag_id' => $tag_id,
1471            )
1472          );
1473      }
1474    }
1475
1476    mass_inserts(
1477      IMAGE_TAG_TABLE,
1478      array_keys($inserts[0]),
1479      $inserts
1480      );
1481  }
1482}
1483
1484/**
1485 * Associate a list of images to a list of categories.
1486 *
1487 * The function will not duplicate links
1488 *
1489 * @param array images
1490 * @param array categories
1491 * @return void
1492 */
1493function associate_images_to_categories($images, $categories)
1494{
1495  if (count($images) == 0
1496      or count($categories) == 0)
1497  {
1498    return false;
1499  }
1500
1501  $query = '
1502DELETE
1503  FROM '.IMAGE_CATEGORY_TABLE.'
1504  WHERE image_id IN ('.implode(',', $images).')
1505    AND category_id IN ('.implode(',', $categories).')
1506;';
1507  pwg_query($query);
1508
1509  $inserts = array();
1510  foreach ($categories as $category_id)
1511  {
1512    foreach ($images as $image_id)
1513    {
1514      array_push(
1515        $inserts,
1516        array(
1517          'image_id' => $image_id,
1518          'category_id' => $category_id,
1519          )
1520        );
1521    }
1522  }
1523
1524  mass_inserts(
1525    IMAGE_CATEGORY_TABLE,
1526    array_keys($inserts[0]),
1527    $inserts
1528    );
1529
1530  update_category($categories);
1531}
1532
1533/**
1534 * Associate images associated to a list of source categories to a list of
1535 * destination categories.
1536 *
1537 * @param array sources
1538 * @param array destinations
1539 * @return void
1540 */
1541function associate_categories_to_categories($sources, $destinations)
1542{
1543  if (count($sources) == 0)
1544  {
1545    return false;
1546  }
1547
1548  $query = '
1549SELECT image_id
1550  FROM '.IMAGE_CATEGORY_TABLE.'
1551  WHERE category_id IN ('.implode(',', $sources).')
1552;';
1553  $images = array_from_query($query, 'image_id');
1554
1555  associate_images_to_categories($images, $destinations);
1556}
1557
1558/**
1559 * Refer main Piwigo URLs (currently PHPWG_DOMAIN domain)
1560 *
1561 * @param void
1562 * @return array like $conf['links']
1563 */
1564function pwg_URL()
1565{
1566  $urls = array(
1567    'HOME'       => PHPWG_URL,
1568    'WIKI'       => PHPWG_URL.'/doc',
1569    'DEMO'       => PHPWG_URL.'/demo',
1570    'FORUM'      => PHPWG_URL.'/forum',
1571    'BUGS'       => PHPWG_URL.'/bugs',
1572    'EXTENSIONS' => PHPWG_URL.'/ext',
1573    );
1574  return $urls;
1575}
1576
1577/**
1578 * Invalidates cahed data (permissions and category counts) for all users.
1579 */
1580function invalidate_user_cache($full = true)
1581{
1582  if ($full)
1583  {
1584    $query = '
1585TRUNCATE TABLE '.USER_CACHE_CATEGORIES_TABLE.';';
1586    pwg_query($query);
1587    $query = '
1588TRUNCATE TABLE '.USER_CACHE_TABLE.';';
1589    pwg_query($query);
1590  }
1591  else
1592  {
1593    $query = '
1594UPDATE '.USER_CACHE_TABLE.'
1595  SET need_update = \'true\';';
1596    pwg_query($query);
1597  }
1598  trigger_action('invalidate_user_cache', $full);
1599}
1600
1601/**
1602 * adds the caracter set to a create table sql query.
1603 * all CREATE TABLE queries must call this function
1604 * @param string query - the sql query
1605 */
1606function create_table_add_character_set($query)
1607{
1608  defined('DB_CHARSET') or fatal_error('create_table_add_character_set DB_CHARSET undefined');
1609  if ('DB_CHARSET'!='')
1610  {
1611    if ( version_compare(mysql_get_server_info(), '4.1.0', '<') )
1612    {
1613      return $query;
1614    }
1615    $charset_collate = " DEFAULT CHARACTER SET ".DB_CHARSET;
1616    if (DB_COLLATE!='')
1617    {
1618      $charset_collate .= " COLLATE ".DB_COLLATE;
1619    }
1620    if ( is_array($query) )
1621    {
1622      foreach( $query as $id=>$q)
1623      {
1624        $q=trim($q);
1625        $q=trim($q, ';');
1626        if (preg_match('/^CREATE\s+TABLE/i',$q))
1627        {
1628          $q.=$charset_collate;
1629        }
1630        $q .= ';';
1631        $query[$id] = $q;
1632      }
1633    }
1634    else
1635    {
1636      $query=trim($query);
1637      $query=trim($query, ';');
1638      if (preg_match('/^CREATE\s+TABLE/i',$query))
1639      {
1640        $query.=$charset_collate;
1641      }
1642      $query .= ';';
1643    }
1644  }
1645  return $query;
1646}
1647
1648/**
1649 * Returns array use on template with html_options method
1650 * @param Min and Max access to use
1651 * @return array of user access level
1652 */
1653function get_user_access_level_html_options($MinLevelAccess = ACCESS_FREE, $MaxLevelAccess = ACCESS_CLOSED)
1654{
1655  $tpl_options = array();
1656  for ($level = $MinLevelAccess; $level <= $MaxLevelAccess; $level++)
1657  {
1658    $tpl_options[$level] = l10n(sprintf('ACCESS_%d', $level));
1659  }
1660  return $tpl_options;
1661}
1662
1663/**
1664 * returns a list of templates currently available in template-extension
1665 * Each .tpl file is extracted from template-extension.
1666 * @return array
1667 */
1668function get_extents($start='')
1669{
1670  if ($start == '') { $start = './template-extension'; }
1671  $dir = opendir($start);
1672  $extents = array();
1673
1674  while (($file = readdir($dir)) !== false)
1675  {
1676    if ( $file == '.' or $file == '..' or $file == '.svn') continue;
1677    $path = $start . '/' . $file;
1678    if (is_dir($path))
1679    {
1680      $extents = array_merge($extents, get_extents($path));
1681    }
1682    elseif ( !is_link($path) and file_exists($path)
1683            and get_extension($path) == 'tpl' )
1684    {
1685      $extents[] = substr($path, 21);
1686    }
1687  }
1688  return $extents;
1689}
1690
1691function create_tag($tag_name)
1692{
1693  // does the tag already exists?
1694  $query = '
1695SELECT id
1696  FROM '.TAGS_TABLE.'
1697  WHERE name = \''.$tag_name.'\'
1698;';
1699  $existing_tags = array_from_query($query, 'id');
1700
1701  if (count($existing_tags) == 0)
1702  {
1703    mass_inserts(
1704      TAGS_TABLE,
1705      array('name', 'url_name'),
1706      array(
1707        array(
1708          'name' => $tag_name,
1709          'url_name' => trigger_event('render_tag_url', $tag_name),
1710          )
1711        )
1712      );
1713
1714    $inserted_id = pwg_db_insert_id(TAGS_TABLE);
1715
1716    return array(
1717      'info' => sprintf(
1718        l10n('Tag "%s" was added'),
1719        stripslashes($tag_name)
1720        ),
1721      'id' => $inserted_id,
1722      );
1723  }
1724  else
1725  {
1726    return array(
1727      'error' => sprintf(
1728        l10n('Tag "%s" already exists'),
1729        stripslashes($tag_name)
1730        )
1731      );
1732  }
1733}
1734
1735/**
1736 * Is the category accessible to the (Admin) user ?
1737 *
1738 * Note : if the user is not authorized to see this category, category jump
1739 * will be replaced by admin cat_modify page
1740 *
1741 * @param int category id to verify
1742 * @return bool
1743 */
1744function cat_admin_access($category_id)
1745{
1746  global $user;
1747
1748  // $filter['visible_categories'] and $filter['visible_images']
1749  // are not used because it's not necessary (filter <> restriction)
1750  if (in_array($category_id, explode(',', $user['forbidden_categories'])))
1751  {
1752    return false;
1753  }
1754  return true;
1755}
1756
1757/**
1758 * Retrieve data from external URL
1759 *
1760 * @param string $src: URL
1761 * @param global $dest: can be a file ressource or string
1762 * @return bool
1763 */
1764function fetchRemote($src, &$dest, $get_data=array(), $post_data=array(), $user_agent='Piwigo', $step=0)
1765{
1766  // Try to retrieve data from local file?
1767  if (!url_is_remote($src))
1768  {
1769    $content = @file_get_contents($src);
1770    if ($content !== false)
1771    {
1772      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1773      return true;
1774    }
1775    else
1776    {
1777      return false;
1778    }
1779  }
1780
1781  // After 3 redirections, return false
1782  if ($step > 3) return false;
1783
1784  // Initialization
1785  $method  = empty($post_data) ? 'GET' : 'POST';
1786  $request = empty($post_data) ? '' : http_build_query($post_data, '', '&');
1787  if (!empty($get_data))
1788  {
1789    $src .= strpos($src, '?') === false ? '?' : '&';
1790    $src .= http_build_query($get_data, '', '&');
1791  }
1792
1793  // Initialize $dest
1794  is_resource($dest) or $dest = '';
1795
1796  // Try curl to read remote file
1797  if (function_exists('curl_init'))
1798  {
1799    $ch = @curl_init();
1800    @curl_setopt($ch, CURLOPT_URL, $src);
1801    @curl_setopt($ch, CURLOPT_HEADER, 1);
1802    @curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
1803    @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1804    if ($method == 'POST')
1805    {
1806      @curl_setopt($ch, CURLOPT_POST, 1);
1807      @curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
1808    }
1809    $content = @curl_exec($ch);
1810    $header_length = @curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1811    $status = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
1812    @curl_close($ch);
1813    if ($content !== false and $status >= 200 and $status < 400)
1814    {
1815      if (preg_match('/Location:\s+?(.+)/', substr($content, 0, $header_length), $m))
1816      {
1817        return fetchRemote($m[1], $dest, array(), array(), $user_agent, $step+1);
1818      }
1819      $content = substr($content, $header_length);
1820      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1821      return true;
1822    }
1823  }
1824
1825  // Try file_get_contents to read remote file
1826  if (ini_get('allow_url_fopen'))
1827  {
1828    $opts = array(
1829      'http' => array(
1830        'method' => $method,
1831        'user_agent' => $user_agent,
1832      )
1833    );
1834    if ($method == 'POST')
1835    {
1836      $opts['http']['content'] = $request;
1837    }
1838    $context = @stream_context_create($opts);
1839    $content = @file_get_contents($src, false, $context);
1840    if ($content !== false)
1841    {
1842      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1843      return true;
1844    }
1845  }
1846
1847  // Try fsockopen to read remote file
1848  $src = parse_url($src);
1849  $host = $src['host'];
1850  $path = isset($src['path']) ? $src['path'] : '/';
1851  $path .= isset($src['query']) ? '?'.$src['query'] : '';
1852
1853  if (($s = @fsockopen($host,80,$errno,$errstr,5)) === false)
1854  {
1855    return false;
1856  }
1857
1858  $http_request  = $method." ".$path." HTTP/1.0\r\n";
1859  $http_request .= "Host: ".$host."\r\n";
1860  if ($method == 'POST')
1861  {
1862    $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
1863    $http_request .= "Content-Length: ".strlen($request)."\r\n";
1864  }
1865  $http_request .= "User-Agent: ".$user_agent."\r\n";
1866  $http_request .= "Accept: */*\r\n";
1867  $http_request .= "\r\n";
1868  $http_request .= $request;
1869
1870  fwrite($s, $http_request);
1871
1872  $i = 0;
1873  $in_content = false;
1874  while (!feof($s))
1875  {
1876    $line = fgets($s);
1877
1878    if (rtrim($line,"\r\n") == '' && !$in_content)
1879    {
1880      $in_content = true;
1881      $i++;
1882      continue;
1883    }
1884    if ($i == 0)
1885    {
1886      if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/',rtrim($line,"\r\n"), $m))
1887      {
1888        fclose($s);
1889        return false;
1890      }
1891      $status = (integer) $m[2];
1892      if ($status < 200 || $status >= 400)
1893      {
1894        fclose($s);
1895        return false;
1896      }
1897    }
1898    if (!$in_content)
1899    {
1900      if (preg_match('/Location:\s+?(.+)$/',rtrim($line,"\r\n"),$m))
1901      {
1902        fclose($s);
1903        return fetchRemote(trim($m[1]),$dest,array(),array(),$user_agent,$step+1);
1904      }
1905      $i++;
1906      continue;
1907    }
1908    is_resource($dest) ? @fwrite($dest, $line) : $dest .= $line;
1909    $i++;
1910  }
1911  fclose($s);
1912  return true;
1913}
1914
1915
1916/**
1917 * returns the groupname corresponding to the given group identifier if
1918 * exists
1919 *
1920 * @param int group_id
1921 * @return mixed
1922 */
1923function get_groupname($group_id)
1924{
1925  $query = '
1926SELECT name
1927  FROM '.GROUPS_TABLE.'
1928  WHERE id = '.intval($group_id).'
1929;';
1930  $result = pwg_query($query);
1931  if (pwg_db_num_rows($result) > 0)
1932  {
1933    list($groupname) = pwg_db_fetch_row($result);
1934  }
1935  else
1936  {
1937    return false;
1938  }
1939
1940  return $groupname;
1941}
1942
1943/**
1944 * returns the username corresponding to the given user identifier if exists
1945 *
1946 * @param int user_id
1947 * @return mixed
1948 */
1949function get_username($user_id)
1950{
1951  global $conf;
1952
1953  $query = '
1954SELECT '.$conf['user_fields']['username'].'
1955  FROM '.USERS_TABLE.'
1956  WHERE '.$conf['user_fields']['id'].' = '.intval($user_id).'
1957;';
1958  $result = pwg_query($query);
1959  if (pwg_db_num_rows($result) > 0)
1960  {
1961    list($username) = pwg_db_fetch_row($result);
1962  }
1963  else
1964  {
1965    return false;
1966  }
1967
1968  return stripslashes($username);
1969}
1970
1971function get_newsletter_subscribe_base_url($language) {
1972  return PHPWG_URL.'/announcement/subscribe/';
1973}
1974
1975/**
1976 * Accordion menus need to know which section to open by default when
1977 * loading the page
1978 */
1979function get_active_menu($menu_page)
1980{
1981  global $page;
1982
1983  if (isset($page['active_menu']))
1984  {
1985    return $page['active_menu'];
1986  }
1987
1988  switch ($menu_page)
1989  {
1990    case 'photos_add':
1991    case 'rating':
1992    case 'tags':
1993    case 'picture_modify':
1994    case 'batch_manager':
1995      return 0;
1996
1997    case 'album':
1998    case 'cat_list':
1999    case 'cat_move':
2000    case 'cat_options':
2001    case 'permalinks':
2002      return 1;
2003
2004    case 'user_list':
2005    case 'user_perm':
2006    case 'group_list':
2007    case 'group_perm':
2008    case 'notification_by_mail':
2009      return 2;
2010
2011    case 'plugins':
2012    case 'plugin':
2013      return 3;
2014
2015    case 'site_manager':
2016    case 'site_update':
2017    case 'stats':
2018    case 'history':
2019    case 'maintenance':
2020    case 'comments':
2021    case 'updates':
2022      return 4;
2023
2024    case 'configuration':
2025    case 'derivatives':
2026    case 'extend_for_templates':
2027    case 'menubar':
2028    case 'themes':
2029    case 'theme':
2030    case 'languages':
2031      return 5;
2032  }
2033  return 0;
2034}
2035
2036function get_taglist($query, $only_user_language=true)
2037{
2038  $result = pwg_query($query);
2039
2040  $taglist = array();
2041  while ($row = pwg_db_fetch_assoc($result))
2042  {
2043    if (!$only_user_language and preg_match_all('#\[lang=(.*?)\](.*?)\[/lang\]#is', $row['name'], $matches))
2044    {
2045      foreach ($matches[2] as $tag_name)
2046      {
2047        array_push(
2048          $taglist,
2049          array(
2050            'name' => trigger_event('render_tag_name', $tag_name),
2051            'id' => '~~'.$row['id'].'~~',
2052            )
2053          );
2054      }
2055
2056      $row['name'] = preg_replace('#\[lang=(.*?)\](.*?)\[/lang\]#is', null, $row['name']);
2057    }
2058
2059    if (strlen($row['name']) > 0)
2060    {
2061      array_push(
2062        $taglist,
2063        array(
2064          'name' => trigger_event('render_tag_name', $row['name']),
2065          'id' => '~~'.$row['id'].'~~',
2066          )
2067        );
2068    }
2069  }
2070
2071  $cmp = create_function('$a,$b', 'return strcasecmp($a["name"], $b["name"]);');
2072  usort($taglist, $cmp);
2073
2074  return $taglist;
2075}
2076
2077function get_tag_ids($raw_tags, $allow_create=true)
2078{
2079  // In $raw_tags we receive something like array('~~6~~', '~~59~~', 'New
2080  // tag', 'Another new tag') The ~~34~~ means that it is an existing
2081  // tag. I've added the surrounding ~~ to permit creation of tags like "10"
2082  // or "1234" (numeric characters only)
2083
2084  $tag_ids = array();
2085  $raw_tags = explode(',',$raw_tags);
2086
2087  foreach ($raw_tags as $raw_tag)
2088  {
2089    if (preg_match('/^~~(\d+)~~$/', $raw_tag, $matches))
2090    {
2091      array_push($tag_ids, $matches[1]);
2092    }
2093    elseif ($allow_create)
2094    {
2095      // we have to create a new tag
2096      $tag_ids[] = tag_id_from_tag_name($raw_tag);
2097    }
2098  }
2099
2100  return $tag_ids;
2101}
2102
2103/** returns the argument_ids array with new sequenced keys based on related
2104 * names. Sequence is not case sensitive.
2105 * Warning: By definition, this function breaks original keys
2106 */
2107function order_by_name($element_ids,$name)
2108{
2109  $ordered_element_ids = array();
2110  foreach ($element_ids as $k_id => $element_id)
2111  {
2112    $key = strtolower($name[$element_id]) .'-'. $name[$element_id] .'-'. $k_id;
2113    $ordered_element_ids[$key] = $element_id;
2114  }
2115  ksort($ordered_element_ids);
2116  return $ordered_element_ids;
2117}
2118
2119function add_permission_on_category($category_ids, $user_ids)
2120{
2121  // array-ify categories and users
2122  if (!is_array($category_ids))
2123  {
2124    $category_ids = array($category_ids);
2125  }
2126
2127  if (!is_array($user_ids))
2128  {
2129    $user_ids = array($user_ids);
2130  }
2131
2132  // check for emptiness
2133  if (count($category_ids) == 0 or count($user_ids) == 0)
2134  {
2135    return;
2136  }
2137
2138  // make sure categories are private and select uppercats or subcats
2139  $cat_ids = (isset($_POST['apply_on_sub'])) ? implode(',', get_subcat_ids($category_ids)).",".implode(',', get_uppercat_ids($category_ids)) : implode(',', get_uppercat_ids($category_ids));
2140  $query = '
2141SELECT
2142    id
2143  FROM '.CATEGORIES_TABLE.'
2144  WHERE id IN ('.$cat_ids.')
2145    AND status = \'private\'
2146;';
2147  $private_cats = array_from_query($query, 'id');
2148
2149  if (count($private_cats) == 0)
2150  {
2151    return;
2152  }
2153
2154  // We must not reinsert already existing lines in user_access table
2155  $granteds = array();
2156  foreach ($private_cats as $cat_id)
2157  {
2158    $granteds[$cat_id] = array();
2159  }
2160
2161  $query = '
2162SELECT
2163    user_id,
2164    cat_id
2165  FROM '.USER_ACCESS_TABLE.'
2166  WHERE cat_id IN ('.implode(',', $private_cats).')
2167    AND user_id IN ('.implode(',', $user_ids).')
2168;';
2169  $result = pwg_query($query);
2170  while ($row = pwg_db_fetch_assoc($result))
2171  {
2172    array_push($granteds[$row['cat_id']], $row['user_id']);
2173  }
2174
2175  $inserts = array();
2176
2177  foreach ($private_cats as $cat_id)
2178  {
2179    $grant_to_users = array_diff($user_ids, $granteds[$cat_id]);
2180
2181    foreach ($grant_to_users as $user_id)
2182    {
2183      array_push(
2184        $inserts,
2185        array(
2186          'user_id' => $user_id,
2187          'cat_id' => $cat_id
2188          )
2189        );
2190    }
2191  }
2192
2193  if (count($inserts) > 0)
2194  {
2195    mass_inserts(USER_ACCESS_TABLE, array_keys($inserts[0]), $inserts);
2196  }
2197}
2198
2199
2200function get_admins($include_webmaster=true)
2201{
2202  $status_list = array('admin');
2203
2204  if ($include_webmaster)
2205  {
2206    $status_list[] = 'webmaster';
2207  }
2208
2209  $query = '
2210SELECT
2211    user_id
2212  FROM '.USER_INFOS_TABLE.'
2213  WHERE status in (\''.implode("','", $status_list).'\')
2214;';
2215
2216  return array_from_query($query, 'user_id');
2217}
2218
2219/** delete all derivative files for one or several types */
2220function clear_derivative_cache($types='all')
2221{
2222  $pattern='#.*-';
2223  if ($types == 'all')
2224  {
2225    $types = ImageStdParams::get_all_types();
2226    $types[] = IMG_CUSTOM;
2227  }
2228  elseif (!is_array($types))
2229  {
2230    $types = array($types);
2231  }
2232
2233  if (count($types)>1)
2234  {
2235    $type_urls = array();
2236    foreach($types as $dtype)
2237    {
2238      $type_urls[] = derivative_to_url($dtype);
2239    }
2240    $pattern .= '(' . implode('|',$type_urls) . ')';
2241  }
2242  else
2243  {
2244    $pattern .= derivative_to_url($types[0]);
2245  }
2246
2247  $pattern.='(_[a-zA-Z0-9]+)*\.[a-zA-Z0-9]{3,4}$#';
2248  if ($contents = opendir(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR))
2249  {
2250    while (($node = readdir($contents)) !== false)
2251    {
2252      if ($node != '.'
2253          and $node != '..'
2254          and is_dir(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR.$node))
2255      {
2256        clear_derivative_cache_rec(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR.$node, $pattern);
2257      }
2258    }
2259    closedir($contents);
2260  }
2261}
2262
2263function clear_derivative_cache_rec($path, $pattern)
2264{
2265  $rmdir = true;
2266  $rm_index = false;
2267
2268  if ($contents = opendir($path))
2269  {
2270    while (($node = readdir($contents)) !== false)
2271    {
2272      if ($node == '.' or $node == '..')
2273        continue;
2274      if (is_dir($path.'/'.$node))
2275      {
2276        $rmdir &= clear_derivative_cache_rec($path.'/'.$node, $pattern);
2277      }
2278      else
2279      {
2280        if (preg_match($pattern, $node))
2281        {
2282          unlink($path.'/'.$node);
2283        }
2284        elseif ($node=='index.htm')
2285        {
2286          $rm_index = true;
2287        }
2288        else
2289        {
2290          $rmdir = false;
2291        }
2292      }
2293    }
2294    closedir($contents);
2295
2296    if ($rmdir)
2297    {
2298      if ($rm_index)
2299      {
2300        unlink($path.'/index.htm');
2301      }
2302      clearstatcache();
2303      @rmdir($path);
2304    }
2305    return $rmdir;
2306  }
2307}
2308
2309function delete_element_derivatives($infos, $type='all')
2310{
2311  $path = $infos['path'];
2312  if (!empty($infos['representative_ext']))
2313  {
2314    $path = original_to_representative( $path, $infos['representative_ext']);
2315  }
2316  if (substr_compare($path, '../', 0, 3)==0)
2317  {
2318    $path = substr($path, 3);
2319  }
2320  $dot = strrpos($path, '.');
2321  if ($type=='all')
2322  {
2323    $pattern = '-*';
2324  }
2325  else
2326  {
2327    $pattern = '-'.derivative_to_url($type).'*';
2328  }
2329  $path = substr_replace($path, $pattern, $dot, 0);
2330  foreach( glob(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR.$path) as $file)
2331  {
2332    @unlink($file);
2333  }
2334}
2335?>
Note: See TracBrowser for help on using the repository browser.