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

Last change on this file since 11728 was 11728, checked in by plg, 13 years ago

merge r11727 from branch 2.2 to trunk

feature 2245: when a new private album is added, the creator and admins
automatically get permission on it.

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