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

Last change on this file since 10594 was 10594, checked in by patdenice, 13 years ago

Change tabsheet place for plugins, themes and languages.
Plugins, themes and languages use same update page.

  • Property svn:eol-style set to LF
File size: 49.3 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;
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  return array(
1365    'info' => l10n('Virtual album added'),
1366    'id'   => $inserted_id,
1367    );
1368}
1369
1370/**
1371 * Set tags to an image. Warning: given tags are all tags associated to the
1372 * image, not additionnal tags.
1373 *
1374 * @param array tag ids
1375 * @param int image id
1376 * @return void
1377 */
1378function set_tags($tags, $image_id)
1379{
1380  $query = '
1381DELETE
1382  FROM '.IMAGE_TAG_TABLE.'
1383  WHERE image_id = '.$image_id.'
1384;';
1385  pwg_query($query);
1386
1387  if (count($tags) > 0)
1388  {
1389    $inserts = array();
1390    foreach ($tags as $tag_id)
1391    {
1392      array_push(
1393        $inserts,
1394        array(
1395          'tag_id' => $tag_id,
1396          'image_id' => $image_id
1397          )
1398        );
1399    }
1400    mass_inserts(
1401      IMAGE_TAG_TABLE,
1402      array_keys($inserts[0]),
1403      $inserts
1404      );
1405  }
1406}
1407
1408/**
1409 * Add new tags to a set of images.
1410 *
1411 * @param array tag ids
1412 * @param array image ids
1413 * @return void
1414 */
1415function add_tags($tags, $images)
1416{
1417  if (count($tags) == 0 or count($images) == 0)
1418  {
1419    return;
1420  }
1421
1422  // we can't insert twice the same {image_id,tag_id} so we must first
1423  // delete lines we'll insert later
1424  $query = '
1425DELETE
1426  FROM '.IMAGE_TAG_TABLE.'
1427  WHERE image_id IN ('.implode(',', $images).')
1428    AND tag_id IN ('.implode(',', $tags).')
1429;';
1430  pwg_query($query);
1431
1432  $inserts = array();
1433  foreach ($images as $image_id)
1434  {
1435    foreach ($tags as $tag_id)
1436    {
1437      array_push(
1438        $inserts,
1439        array(
1440          'image_id' => $image_id,
1441          'tag_id' => $tag_id,
1442          )
1443        );
1444    }
1445  }
1446  mass_inserts(
1447    IMAGE_TAG_TABLE,
1448    array_keys($inserts[0]),
1449    $inserts
1450    );
1451}
1452
1453function tag_id_from_tag_name($tag_name)
1454{
1455  global $page;
1456
1457  $tag_name = trim($tag_name);
1458  if (isset($page['tag_id_from_tag_name_cache'][$tag_name]))
1459  {
1460    return $page['tag_id_from_tag_name_cache'][$tag_name];
1461  }
1462
1463  // does the tag already exists?
1464  $query = '
1465SELECT id
1466  FROM '.TAGS_TABLE.'
1467  WHERE name = \''.$tag_name.'\'
1468;';
1469  $existing_tags = array_from_query($query, 'id');
1470
1471  if (count($existing_tags) == 0)
1472  {
1473    mass_inserts(
1474      TAGS_TABLE,
1475      array('name', 'url_name'),
1476      array(
1477        array(
1478          'name' => $tag_name,
1479          'url_name' => str2url($tag_name),
1480          )
1481        )
1482      );
1483
1484    $page['tag_id_from_tag_name_cache'][$tag_name] = pwg_db_insert_id(TAGS_TABLE);
1485  }
1486  else
1487  {
1488    $page['tag_id_from_tag_name_cache'][$tag_name] = $existing_tags[0];
1489  }
1490
1491  return $page['tag_id_from_tag_name_cache'][$tag_name];
1492}
1493
1494function set_tags_of($tags_of)
1495{
1496  if (count($tags_of) > 0)
1497  {
1498    $query = '
1499DELETE
1500  FROM '.IMAGE_TAG_TABLE.'
1501  WHERE image_id IN ('.implode(',', array_keys($tags_of)).')
1502;';
1503    pwg_query($query);
1504
1505    $inserts = array();
1506
1507    foreach ($tags_of as $image_id => $tag_ids)
1508    {
1509      foreach ($tag_ids as $tag_id)
1510      {
1511        array_push(
1512          $inserts,
1513          array(
1514            'image_id' => $image_id,
1515            'tag_id' => $tag_id,
1516            )
1517          );
1518      }
1519    }
1520
1521    mass_inserts(
1522      IMAGE_TAG_TABLE,
1523      array_keys($inserts[0]),
1524      $inserts
1525      );
1526  }
1527}
1528
1529/**
1530 * Associate a list of images to a list of categories.
1531 *
1532 * The function will not duplicate links
1533 *
1534 * @param array images
1535 * @param array categories
1536 * @return void
1537 */
1538function associate_images_to_categories($images, $categories)
1539{
1540  if (count($images) == 0
1541      or count($categories) == 0)
1542  {
1543    return false;
1544  }
1545
1546  $query = '
1547DELETE
1548  FROM '.IMAGE_CATEGORY_TABLE.'
1549  WHERE image_id IN ('.implode(',', $images).')
1550    AND category_id IN ('.implode(',', $categories).')
1551;';
1552  pwg_query($query);
1553
1554  $inserts = array();
1555  foreach ($categories as $category_id)
1556  {
1557    foreach ($images as $image_id)
1558    {
1559      array_push(
1560        $inserts,
1561        array(
1562          'image_id' => $image_id,
1563          'category_id' => $category_id,
1564          )
1565        );
1566    }
1567  }
1568
1569  mass_inserts(
1570    IMAGE_CATEGORY_TABLE,
1571    array_keys($inserts[0]),
1572    $inserts
1573    );
1574
1575  update_category($categories);
1576}
1577
1578/**
1579 * Associate images associated to a list of source categories to a list of
1580 * destination categories.
1581 *
1582 * @param array sources
1583 * @param array destinations
1584 * @return void
1585 */
1586function associate_categories_to_categories($sources, $destinations)
1587{
1588  if (count($sources) == 0)
1589  {
1590    return false;
1591  }
1592
1593  $query = '
1594SELECT image_id
1595  FROM '.IMAGE_CATEGORY_TABLE.'
1596  WHERE category_id IN ('.implode(',', $sources).')
1597;';
1598  $images = array_from_query($query, 'image_id');
1599
1600  associate_images_to_categories($images, $destinations);
1601}
1602
1603/**
1604 * Refer main Piwigo URLs (currently PHPWG_DOMAIN domain)
1605 *
1606 * @param void
1607 * @return array like $conf['links']
1608 */
1609function pwg_URL()
1610{
1611  $urls = array(
1612    'HOME'       => 'http://'.PHPWG_DOMAIN,
1613    'WIKI'       => 'http://'.PHPWG_DOMAIN.'/doc',
1614    'DEMO'       => 'http://'.PHPWG_DOMAIN.'/demo',
1615    'FORUM'      => 'http://'.PHPWG_DOMAIN.'/forum',
1616    'BUGS'       => 'http://'.PHPWG_DOMAIN.'/bugs',
1617    'EXTENSIONS' => 'http://'.PHPWG_DOMAIN.'/ext',
1618    );
1619  return $urls;
1620}
1621
1622/**
1623 * Invalidates cahed data (permissions and category counts) for all users.
1624 */
1625function invalidate_user_cache($full = true)
1626{
1627  if ($full)
1628  {
1629    $query = '
1630TRUNCATE TABLE '.USER_CACHE_CATEGORIES_TABLE.';';
1631    pwg_query($query);
1632    $query = '
1633TRUNCATE TABLE '.USER_CACHE_TABLE.';';
1634    pwg_query($query);
1635  }
1636  else
1637  {
1638    $query = '
1639UPDATE '.USER_CACHE_TABLE.'
1640  SET need_update = \'true\';';
1641    pwg_query($query);
1642  }
1643  trigger_action('invalidate_user_cache', $full);
1644}
1645
1646/**
1647 * adds the caracter set to a create table sql query.
1648 * all CREATE TABLE queries must call this function
1649 * @param string query - the sql query
1650 */
1651function create_table_add_character_set($query)
1652{
1653  defined('DB_CHARSET') or fatal_error('create_table_add_character_set DB_CHARSET undefined');
1654  if ('DB_CHARSET'!='')
1655  {
1656    if ( version_compare(mysql_get_server_info(), '4.1.0', '<') )
1657    {
1658      return $query;
1659    }
1660    $charset_collate = " DEFAULT CHARACTER SET ".DB_CHARSET;
1661    if (DB_COLLATE!='')
1662    {
1663      $charset_collate .= " COLLATE ".DB_COLLATE;
1664    }
1665    if ( is_array($query) )
1666    {
1667      foreach( $query as $id=>$q)
1668      {
1669        $q=trim($q);
1670        $q=trim($q, ';');
1671        if (preg_match('/^CREATE\s+TABLE/i',$q))
1672        {
1673          $q.=$charset_collate;
1674        }
1675        $q .= ';';
1676        $query[$id] = $q;
1677      }
1678    }
1679    else
1680    {
1681      $query=trim($query);
1682      $query=trim($query, ';');
1683      if (preg_match('/^CREATE\s+TABLE/i',$query))
1684      {
1685        $query.=$charset_collate;
1686      }
1687      $query .= ';';
1688    }
1689  }
1690  return $query;
1691}
1692
1693/**
1694 * Returns array use on template with html_options method
1695 * @param Min and Max access to use
1696 * @return array of user access level
1697 */
1698function get_user_access_level_html_options($MinLevelAccess = ACCESS_FREE, $MaxLevelAccess = ACCESS_CLOSED)
1699{
1700  $tpl_options = array();
1701  for ($level = $MinLevelAccess; $level <= $MaxLevelAccess; $level++)
1702  {
1703    $tpl_options[$level] = l10n(sprintf('ACCESS_%d', $level));
1704  }
1705  return $tpl_options;
1706}
1707
1708/**
1709 * returns a list of templates currently available in template-extension
1710 * Each .tpl file is extracted from template-extension.
1711 * @return array
1712 */
1713function get_extents($start='')
1714{
1715  if ($start == '') { $start = './template-extension'; }
1716  $dir = opendir($start);
1717  $extents = array();
1718
1719  while (($file = readdir($dir)) !== false)
1720  {
1721    if ( $file == '.' or $file == '..' or $file == '.svn') continue;
1722    $path = $start . '/' . $file;
1723    if (is_dir($path))
1724    {
1725      $extents = array_merge($extents, get_extents($path));
1726    }
1727    elseif ( !is_link($path) and file_exists($path)
1728            and get_extension($path) == 'tpl' )
1729    {
1730      $extents[] = substr($path, 21);
1731    }
1732  }
1733  return $extents;
1734}
1735
1736function create_tag($tag_name)
1737{
1738  // does the tag already exists?
1739  $query = '
1740SELECT id
1741  FROM '.TAGS_TABLE.'
1742  WHERE name = \''.$tag_name.'\'
1743;';
1744  $existing_tags = array_from_query($query, 'id');
1745
1746  if (count($existing_tags) == 0)
1747  {
1748    mass_inserts(
1749      TAGS_TABLE,
1750      array('name', 'url_name'),
1751      array(
1752        array(
1753          'name' => $tag_name,
1754          'url_name' => str2url($tag_name),
1755          )
1756        )
1757      );
1758
1759    $inserted_id = pwg_db_insert_id(TAGS_TABLE);
1760
1761    return array(
1762      'info' => sprintf(
1763        l10n('Tag "%s" was added'),
1764        stripslashes($tag_name)
1765        ),
1766      'id' => $inserted_id,
1767      );
1768  }
1769  else
1770  {
1771    return array(
1772      'error' => sprintf(
1773        l10n('Tag "%s" already exists'),
1774        stripslashes($tag_name)
1775        )
1776      );
1777  }
1778}
1779
1780/**
1781 * Is the category accessible to the (Admin) user ?
1782 *
1783 * Note : if the user is not authorized to see this category, category jump
1784 * will be replaced by admin cat_modify page
1785 *
1786 * @param int category id to verify
1787 * @return bool
1788 */
1789function cat_admin_access($category_id)
1790{
1791  global $user;
1792
1793  // $filter['visible_categories'] and $filter['visible_images']
1794  // are not used because it's not necessary (filter <> restriction)
1795  if (in_array($category_id, explode(',', $user['forbidden_categories'])))
1796  {
1797    return false;
1798  }
1799  return true;
1800}
1801
1802/**
1803 * Retrieve data from external URL
1804 *
1805 * @param string $src: URL
1806 * @param global $dest: can be a file ressource or string
1807 * @return bool
1808 */
1809function fetchRemote($src, &$dest, $get_data=array(), $post_data=array(), $user_agent='Piwigo', $step=0)
1810{
1811  // Try to retrieve data from local file?
1812  if (!url_is_remote($src))
1813  {
1814    $content = @file_get_contents($src);
1815    if ($content !== false)
1816    {
1817      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1818      return true;
1819    }
1820    else
1821    {
1822      return false;
1823    }
1824  }
1825
1826  // After 3 redirections, return false
1827  if ($step > 3) return false;
1828
1829  // Initialization
1830  $method  = empty($post_data) ? 'GET' : 'POST';
1831  $request = empty($post_data) ? '' : http_build_query($post_data, '', '&');
1832  if (!empty($get_data))
1833  {
1834    $src .= strpos($src, '?') === false ? '?' : '&';
1835    $src .= http_build_query($get_data, '', '&');
1836  }
1837
1838  // Initialize $dest
1839  is_resource($dest) or $dest = '';
1840
1841  // Try curl to read remote file
1842  if (function_exists('curl_init'))
1843  {
1844    $ch = @curl_init();
1845    @curl_setopt($ch, CURLOPT_URL, $src);
1846    @curl_setopt($ch, CURLOPT_HEADER, 1);
1847    @curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
1848    @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1849    if ($method == 'POST')
1850    {
1851      @curl_setopt($ch, CURLOPT_POST, 1);
1852      @curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
1853    }
1854    $content = @curl_exec($ch);
1855    $header_length = @curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1856    $status = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
1857    @curl_close($ch);
1858    if ($content !== false and $status >= 200 and $status < 400)
1859    {
1860      if (preg_match('/Location:\s+?(.+)/', substr($content, 0, $header_length), $m))
1861      {
1862        return fetchRemote($m[1], $dest, array(), array(), $user_agent, $step+1);
1863      }
1864      $content = substr($content, $header_length);
1865      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1866      return true;
1867    }
1868  }
1869
1870  // Try file_get_contents to read remote file
1871  if (ini_get('allow_url_fopen'))
1872  {
1873    $opts = array(
1874      'http' => array(
1875        'method' => $method,
1876        'user_agent' => $user_agent,
1877      )
1878    );
1879    if ($method == 'POST')
1880    {
1881      $opts['http']['content'] = $request;
1882    }
1883    $context = @stream_context_create($opts);
1884    $content = @file_get_contents($src, false, $context);
1885    if ($content !== false)
1886    {
1887      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1888      return true;
1889    }
1890  }
1891
1892  // Try fsockopen to read remote file
1893  $src = parse_url($src);
1894  $host = $src['host'];
1895  $path = isset($src['path']) ? $src['path'] : '/';
1896  $path .= isset($src['query']) ? '?'.$src['query'] : '';
1897
1898  if (($s = @fsockopen($host,80,$errno,$errstr,5)) === false)
1899  {
1900    return false;
1901  }
1902
1903  $http_request  = $method." ".$path." HTTP/1.0\r\n";
1904  $http_request .= "Host: ".$host."\r\n";
1905  if ($method == 'POST')
1906  {
1907    $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
1908    $http_request .= "Content-Length: ".strlen($request)."\r\n";
1909  }
1910  $http_request .= "User-Agent: ".$user_agent."\r\n";
1911  $http_request .= "Accept: */*\r\n";
1912  $http_request .= "\r\n";
1913  $http_request .= $request;
1914
1915  fwrite($s, $http_request);
1916
1917  $i = 0;
1918  $in_content = false;
1919  while (!feof($s))
1920  {
1921    $line = fgets($s);
1922
1923    if (rtrim($line,"\r\n") == '' && !$in_content)
1924    {
1925      $in_content = true;
1926      $i++;
1927      continue;
1928    }
1929    if ($i == 0)
1930    {
1931      if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/',rtrim($line,"\r\n"), $m))
1932      {
1933        fclose($s);
1934        return false;
1935      }
1936      $status = (integer) $m[2];
1937      if ($status < 200 || $status >= 400)
1938      {
1939        fclose($s);
1940        return false;
1941      }
1942    }
1943    if (!$in_content)
1944    {
1945      if (preg_match('/Location:\s+?(.+)$/',rtrim($line,"\r\n"),$m))
1946      {
1947        fclose($s);
1948        return fetchRemote(trim($m[1]),$dest,array(),array(),$user_agent,$step+1);
1949      }
1950      $i++;
1951      continue;
1952    }
1953    is_resource($dest) ? @fwrite($dest, $line) : $dest .= $line;
1954    $i++;
1955  }
1956  fclose($s);
1957  return true;
1958}
1959
1960
1961/**
1962 * returns the groupname corresponding to the given group identifier if
1963 * exists
1964 *
1965 * @param int group_id
1966 * @return mixed
1967 */
1968function get_groupname($group_id)
1969{
1970  $query = '
1971SELECT name
1972  FROM '.GROUPS_TABLE.'
1973  WHERE id = '.intval($group_id).'
1974;';
1975  $result = pwg_query($query);
1976  if (pwg_db_num_rows($result) > 0)
1977  {
1978    list($groupname) = pwg_db_fetch_row($result);
1979  }
1980  else
1981  {
1982    return false;
1983  }
1984
1985  return $groupname;
1986}
1987
1988/**
1989 * returns the username corresponding to the given user identifier if exists
1990 *
1991 * @param int user_id
1992 * @return mixed
1993 */
1994function get_username($user_id)
1995{
1996  global $conf;
1997
1998  $query = '
1999SELECT '.$conf['user_fields']['username'].'
2000  FROM '.USERS_TABLE.'
2001  WHERE '.$conf['user_fields']['id'].' = '.intval($user_id).'
2002;';
2003  $result = pwg_query($query);
2004  if (pwg_db_num_rows($result) > 0)
2005  {
2006    list($username) = pwg_db_fetch_row($result);
2007  }
2008  else
2009  {
2010    return false;
2011  }
2012
2013  return stripslashes($username);
2014}
2015
2016function get_newsletter_subscribe_base_url($language) {
2017  $subscribe_domain = 'piwigo.org';
2018
2019  $domain_of = array(
2020    'fr_FR' => 'fr.piwigo.org',
2021    'it_IT' => 'it.piwigo.org',
2022    'de_DE' => 'de.piwigo.org',
2023    'es_ES' => 'es.piwigo.org',
2024    'zh_CN' => 'cn.piwigo.org',
2025    'pl_PL' => 'pl.piwigo.org',
2026    'hu_HU' => 'hu.piwigo.org',
2027    'ru_RU' => 'ru.piwigo.org',
2028        'nl_NL' => 'nl.piwigo.org',
2029    );
2030
2031  if (isset($domain_of[$language])) {
2032    $subscribe_domain = $domain_of[$language];
2033  }
2034
2035  return 'http://'.$subscribe_domain.'/announcement/subscribe/';
2036}
2037
2038/**
2039 * Accordion menus need to know which section to open by default when
2040 * loading the page
2041 */
2042function get_active_menu($menu_page)
2043{
2044  global $page;
2045
2046  if (isset($page['active_menu']))
2047  {
2048    return $page['active_menu'];
2049  }
2050
2051  switch ($menu_page)
2052  {
2053    case 'photos_add':
2054    case 'rating':
2055    case 'tags':
2056    case 'picture_modify':
2057    case 'batch_manager':
2058      return 0;
2059
2060    case 'cat_list':
2061    case 'cat_modify':
2062    case 'cat_move':
2063    case 'cat_options':
2064    case 'cat_perm':
2065    case 'permalinks':
2066      return 1;
2067
2068    case 'user_list':
2069    case 'user_perm':
2070    case 'group_list':
2071    case 'group_perm':
2072    case 'notification_by_mail':
2073      return 2;
2074
2075    case 'plugins':
2076    case 'plugin':
2077      return 3;
2078
2079    case 'site_manager':
2080    case 'site_update':
2081    case 'stats':
2082    case 'history':
2083    case 'maintenance':
2084    case 'thumbnail':
2085    case 'comments':
2086    case 'updates':
2087      return 4;
2088
2089    case 'configuration':
2090    case 'extend_for_templates':
2091    case 'menubar':
2092    case 'themes':
2093    case 'theme':
2094    case 'languages':
2095      return 5;
2096  }
2097  return 0;
2098}
2099
2100function get_fckb_taglist($query)
2101{
2102  $result = pwg_query($query);
2103  $taglist = array();
2104  while ($row = pwg_db_fetch_assoc($result))
2105  {
2106    array_push(
2107      $taglist,
2108      array(
2109        'key' => $row['tag_name'],
2110        'value' => '~~'.$row['tag_id'].'~~',
2111        )
2112      );
2113  }
2114
2115  return $taglist;
2116}
2117
2118function get_fckb_tag_ids($raw_tags)
2119{
2120  // In $raw_tags we receive something like array('~~6~~', '~~59~~', 'New
2121  // tag', 'Another new tag') The ~~34~~ means that it is an existing
2122  // tag. I've added the surrounding ~~ to permit creation of tags like "10"
2123  // or "1234" (numeric characters only)
2124
2125  $tag_ids = array();
2126
2127  foreach ($raw_tags as $raw_tag)
2128  {
2129    if (preg_match('/^~~(\d+)~~$/', $raw_tag, $matches))
2130    {
2131      array_push($tag_ids, $matches[1]);
2132    }
2133    else
2134    {
2135      // we have to create a new tag
2136      array_push(
2137        $tag_ids,
2138        tag_id_from_tag_name($raw_tag)
2139        );
2140    }
2141  }
2142
2143  return $tag_ids;
2144}
2145
2146/** returns the argument_ids array with new sequenced keys based on related
2147 * names. Sequence is not case sensitive.
2148 * Warning: By definition, this function breaks original keys
2149 */
2150function order_by_name($element_ids,$name)
2151{
2152  $ordered_element_ids = array();
2153  foreach ($element_ids as $k_id => $element_id)
2154  {
2155    $key = strtolower($name[$element_id]) .'-'. $name[$element_id] .'-'. $k_id;
2156    $ordered_element_ids[$key] = $element_id;
2157  }
2158  ksort($ordered_element_ids);
2159  return $ordered_element_ids;
2160}
2161
2162?>
Note: See TracBrowser for help on using the repository browser.