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

Last change on this file since 4892 was 4892, checked in by nikrou, 14 years ago

Feature 1255 :
update pwg_db_insert_id() function.
PosgreSQL needs table name to retrieve last insert auto increment id.

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