source: branches/2.1/admin/include/functions.php @ 8023

Last change on this file since 8023 was 8023, checked in by patdenice, 14 years ago

merge r8022 from trunk to branch 2.1
Feature 2048: send piwigo version

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