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

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

feature 2548 multisize - added a page to build missing derivatives

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