source: branches/2.0/admin/include/functions.php @ 4730

Last change on this file since 4730 was 4730, checked in by plg, 14 years ago

bug 1396: when a photo was deleted, the code to avoid orphans as category
representative was 1) wrong (because a photo doesn't have to belong to a
category to represent it) 2) at the wrong place.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 49.3 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// 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 = mysql_fetch_array($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 = mysql_fetch_array($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 = mysql_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 * inserts multiple lines in a table
426 *
427 * @param string table_name
428 * @param array dbfields
429 * @param array inserts
430 * @return void
431 */
432function mass_inserts($table_name, $dbfields, $datas)
433{
434  if (count($datas) != 0)
435  {
436    $first = true;
437
438    $query = 'SHOW VARIABLES LIKE \'max_allowed_packet\'';
439    list(, $packet_size) = mysql_fetch_row(pwg_query($query));
440    $packet_size = $packet_size - 2000; // The last list of values MUST not exceed 2000 character*/
441    $query = '';
442
443    foreach ($datas as $insert)
444    {
445      if (strlen($query) >= $packet_size)
446      {
447        pwg_query($query);
448        $first = true;
449      }
450
451      if ($first)
452      {
453        $query = '
454INSERT INTO '.$table_name.'
455  ('.implode(',', $dbfields).')
456  VALUES';
457        $first = false;
458      }
459      else
460      {
461        $query .= '
462  , ';
463      }
464
465      $query .= '(';
466      foreach ($dbfields as $field_id => $dbfield)
467      {
468        if ($field_id > 0)
469        {
470          $query .= ',';
471        }
472
473        if (!isset($insert[$dbfield]) or $insert[$dbfield] === '')
474        {
475          $query .= 'NULL';
476        }
477        else
478        {
479          $query .= "'".$insert[$dbfield]."'";
480        }
481      }
482      $query .= ')';
483    }
484    pwg_query($query);
485  }
486}
487
488define('MASS_UPDATES_SKIP_EMPTY', 1);
489/**
490 * updates multiple lines in a table
491 *
492 * @param string table_name
493 * @param array dbfields
494 * @param array datas
495 * @param int flags - if MASS_UPDATES_SKIP_EMPTY - empty values do not overwrite existing ones
496 * @return void
497 */
498function mass_updates($tablename, $dbfields, $datas, $flags=0)
499{
500  if (count($datas) == 0)
501    return;
502  // depending on the MySQL version, we use the multi table update or N update queries
503  if (count($datas) < 10 or version_compare(mysql_get_server_info(), '4.0.4') < 0)
504  { // MySQL is prior to version 4.0.4, multi table update feature is not available
505    foreach ($datas as $data)
506    {
507      $query = '
508UPDATE '.$tablename.'
509  SET ';
510      $is_first = true;
511      foreach ($dbfields['update'] as $key)
512      {
513        $separator = $is_first ? '' : ",\n    ";
514
515        if (isset($data[$key]) and $data[$key] != '')
516        {
517          $query.= $separator.$key.' = \''.$data[$key].'\'';
518        }
519        else
520        {
521          if ($flags & MASS_UPDATES_SKIP_EMPTY )
522            continue; // next field
523          $query.= "$separator$key = NULL";
524        }
525        $is_first = false;
526      }
527      if (!$is_first)
528      {// only if one field at least updated
529        $query.= '
530  WHERE ';
531        $is_first = true;
532        foreach ($dbfields['primary'] as $key)
533        {
534          if (!$is_first)
535          {
536            $query.= ' AND ';
537          }
538          if ( isset($data[$key]) )
539          {
540            $query.= $key.' = \''.$data[$key].'\'';
541          }
542          else
543          {
544            $query.= $key.' IS NULL';
545          }
546          $is_first = false;
547        }
548        pwg_query($query);
549      }
550    } // foreach update
551  } // if mysql_ver or count<X
552  else
553  {
554    // creation of the temporary table
555    $query = '
556SHOW FULL COLUMNS FROM '.$tablename;
557    $result = pwg_query($query);
558    $columns = array();
559    $all_fields = array_merge($dbfields['primary'], $dbfields['update']);
560    while ($row = mysql_fetch_array($result))
561    {
562      if (in_array($row['Field'], $all_fields))
563      {
564        $column = $row['Field'];
565        $column.= ' '.$row['Type'];
566
567        $nullable = true;
568        if (!isset($row['Null']) or $row['Null'] == '' or $row['Null']=='NO')
569        {
570          $column.= ' NOT NULL';
571          $nullable = false;
572        }
573        if (isset($row['Default']))
574        {
575          $column.= " default '".$row['Default']."'";
576        }
577        elseif ($nullable)
578        {
579          $column.= " default NULL";
580        }
581        if (isset($row['Collation']) and $row['Collation'] != 'NULL')
582        {
583          $column.= " collate '".$row['Collation']."'";
584        }
585        array_push($columns, $column);
586      }
587    }
588
589    $temporary_tablename = $tablename.'_'.micro_seconds();
590
591    $query = '
592CREATE TABLE '.$temporary_tablename.'
593(
594  '.implode(",\n  ", $columns).',
595  UNIQUE KEY the_key ('.implode(',', $dbfields['primary']).')
596)';
597
598    pwg_query($query);
599    mass_inserts($temporary_tablename, $all_fields, $datas);
600    if ( $flags & MASS_UPDATES_SKIP_EMPTY )
601      $func_set = create_function('$s', 'return "t1.$s = IFNULL(t2.$s, t1.$s)";');
602    else
603      $func_set = create_function('$s', 'return "t1.$s = t2.$s";');
604
605    // update of images table by joining with temporary table
606    $query = '
607UPDATE '.$tablename.' AS t1, '.$temporary_tablename.' AS t2
608  SET '.
609      implode(
610        "\n    , ",
611        array_map($func_set,$dbfields['update'])
612        ).'
613  WHERE '.
614      implode(
615        "\n    AND ",
616        array_map(
617          create_function('$s', 'return "t1.$s = t2.$s";'),
618          $dbfields['primary']
619          )
620        );
621    pwg_query($query);
622    $query = '
623DROP TABLE '.$temporary_tablename;
624    pwg_query($query);
625  }
626}
627
628/**
629 * order categories (update categories.rank and global_rank database fields)
630 * so that rank field are consecutive integers starting at 1 for each child
631 * @return void
632 */
633function update_global_rank()
634{
635  $query = '
636SELECT id, if(id_uppercat is null,\'\',id_uppercat) AS id_uppercat, uppercats, rank, global_rank
637  FROM '.CATEGORIES_TABLE.'
638  ORDER BY id_uppercat,rank,name';
639
640  $cat_map = array();
641
642  $current_rank = 0;
643  $current_uppercat = '';
644
645  $result = pwg_query($query);
646  while ($row = mysql_fetch_array($result))
647  {
648    if ($row['id_uppercat'] != $current_uppercat)
649    {
650      $current_rank = 0;
651      $current_uppercat = $row['id_uppercat'];
652    }
653    ++$current_rank;
654    $cat =
655      array(
656        'rank' =>        $current_rank,
657        'rank_changed' =>$current_rank!=$row['rank'],
658        'global_rank' => $row['global_rank'],
659        'uppercats' =>   $row['uppercats'],
660        );
661    $cat_map[ $row['id'] ] = $cat;
662  }
663
664  $datas = array();
665
666  foreach( $cat_map as $id=>$cat )
667  {
668    $new_global_rank = preg_replace(
669          '/(\d+)/e',
670          "\$cat_map['$1']['rank']",
671          str_replace(',', '.', $cat['uppercats'] )
672          );
673    if ( $cat['rank_changed']
674      or $new_global_rank!=$cat['global_rank']
675      )
676    {
677      $datas[] = array(
678          'id' => $id,
679          'rank' => $cat['rank'],
680          'global_rank' => $new_global_rank,
681        );
682    }
683  }
684
685  mass_updates(
686    CATEGORIES_TABLE,
687    array(
688      'primary' => array('id'),
689      'update'  => array('rank', 'global_rank')
690      ),
691    $datas
692    );
693  return count($datas);
694}
695
696/**
697 * change the visible property on a set of categories
698 *
699 * @param array categories
700 * @param string value
701 * @return void
702 */
703function set_cat_visible($categories, $value)
704{
705  if (!in_array($value, array('true', 'false')))
706  {
707    trigger_error("set_cat_visible invalid param $value", E_USER_WARNING);
708    return false;
709  }
710
711  // unlocking a category => all its parent categories become unlocked
712  if ($value == 'true')
713  {
714    $uppercats = get_uppercat_ids($categories);
715    $query = '
716UPDATE '.CATEGORIES_TABLE.'
717  SET visible = \'true\'
718  WHERE id IN ('.implode(',', $uppercats).')';
719    pwg_query($query);
720  }
721  // locking a category   => all its child categories become locked
722  if ($value == 'false')
723  {
724    $subcats = get_subcat_ids($categories);
725    $query = '
726UPDATE '.CATEGORIES_TABLE.'
727  SET visible = \'false\'
728  WHERE id IN ('.implode(',', $subcats).')';
729    pwg_query($query);
730  }
731}
732
733/**
734 * change the status property on a set of categories : private or public
735 *
736 * @param array categories
737 * @param string value
738 * @return void
739 */
740function set_cat_status($categories, $value)
741{
742  if (!in_array($value, array('public', 'private')))
743  {
744    trigger_error("set_cat_status invalid param $value", E_USER_WARNING);
745    return false;
746  }
747
748  // make public a category => all its parent categories become public
749  if ($value == 'public')
750  {
751    $uppercats = get_uppercat_ids($categories);
752    $query = '
753UPDATE '.CATEGORIES_TABLE.'
754  SET status = \'public\'
755  WHERE id IN ('.implode(',', $uppercats).')
756;';
757    pwg_query($query);
758  }
759  // make a category private => all its child categories become private
760  if ($value == 'private')
761  {
762    $subcats = get_subcat_ids($categories);
763    $query = '
764UPDATE '.CATEGORIES_TABLE.'
765  SET status = \'private\'
766  WHERE id IN ('.implode(',', $subcats).')';
767    pwg_query($query);
768  }
769}
770
771/**
772 * returns all uppercats category ids of the given category ids
773 *
774 * @param array cat_ids
775 * @return array
776 */
777function get_uppercat_ids($cat_ids)
778{
779  if (!is_array($cat_ids) or count($cat_ids) < 1)
780  {
781    return array();
782  }
783
784  $uppercats = array();
785
786  $query = '
787SELECT uppercats
788  FROM '.CATEGORIES_TABLE.'
789  WHERE id IN ('.implode(',', $cat_ids).')
790;';
791  $result = pwg_query($query);
792  while ($row = mysql_fetch_array($result))
793  {
794    $uppercats = array_merge($uppercats,
795                             explode(',', $row['uppercats']));
796  }
797  $uppercats = array_unique($uppercats);
798
799  return $uppercats;
800}
801
802/**
803 * set a new random representant to the categories
804 *
805 * @param array categories
806 */
807function set_random_representant($categories)
808{
809  $datas = array();
810  foreach ($categories as $category_id)
811  {
812    $query = '
813SELECT image_id
814  FROM '.IMAGE_CATEGORY_TABLE.'
815  WHERE category_id = '.$category_id.'
816  ORDER BY RAND()
817  LIMIT 0,1
818;';
819    list($representative) = mysql_fetch_array(pwg_query($query));
820
821    array_push(
822      $datas,
823      array(
824        'id' => $category_id,
825        'representative_picture_id' => $representative,
826        )
827      );
828  }
829
830  mass_updates(
831    CATEGORIES_TABLE,
832    array(
833      'primary' => array('id'),
834      'update' => array('representative_picture_id')
835      ),
836    $datas
837    );
838}
839
840/**
841 * returns the fulldir for each given category id
842 *
843 * @param array cat_ids
844 * @return array
845 */
846function get_fulldirs($cat_ids)
847{
848  if (count($cat_ids) == 0)
849  {
850    return array();
851  }
852
853  // caching directories of existing categories
854  $query = '
855SELECT id, dir
856  FROM '.CATEGORIES_TABLE.'
857  WHERE dir IS NOT NULL
858;';
859  $cat_dirs = simple_hash_from_query($query, 'id', 'dir');
860
861  // caching galleries_url
862  $query = '
863SELECT id, galleries_url
864  FROM '.SITES_TABLE.'
865;';
866  $galleries_url = simple_hash_from_query($query, 'id', 'galleries_url');
867
868  // categories : id, site_id, uppercats
869  $categories = array();
870
871  $query = '
872SELECT id, uppercats, site_id
873  FROM '.CATEGORIES_TABLE.'
874  WHERE dir IS NOT NULL
875    AND id IN (
876'.wordwrap(implode(', ', $cat_ids), 80, "\n").')
877;';
878  $result = pwg_query($query);
879  while ($row = mysql_fetch_array($result))
880  {
881    array_push($categories, $row);
882  }
883
884  // filling $cat_fulldirs
885  $cat_fulldirs = array();
886  foreach ($categories as $category)
887  {
888    $uppercats = str_replace(',', '/', $category['uppercats']);
889    $cat_fulldirs[$category['id']] = $galleries_url[$category['site_id']];
890    $cat_fulldirs[$category['id']].= preg_replace('/(\d+)/e',
891                                                  "\$cat_dirs['$1']",
892                                                  $uppercats);
893  }
894
895  return $cat_fulldirs;
896}
897
898/**
899 * returns an array with all file system files according to
900 * $conf['file_ext']
901 *
902 * @param string $path
903 * @param bool recursive
904 * @return array
905 */
906function get_fs($path, $recursive = true)
907{
908  global $conf;
909
910  // because isset is faster than in_array...
911  if (!isset($conf['flip_picture_ext']))
912  {
913    $conf['flip_picture_ext'] = array_flip($conf['picture_ext']);
914  }
915  if (!isset($conf['flip_file_ext']))
916  {
917    $conf['flip_file_ext'] = array_flip($conf['file_ext']);
918  }
919
920  $fs['elements'] = array();
921  $fs['thumbnails'] = array();
922  $fs['representatives'] = array();
923  $subdirs = array();
924
925  if (is_dir($path))
926  {
927    if ($contents = opendir($path))
928    {
929      while (($node = readdir($contents)) !== false)
930      {
931        if (is_file($path.'/'.$node))
932        {
933          $extension = get_extension($node);
934
935//          if (in_array($extension, $conf['picture_ext']))
936          if (isset($conf['flip_picture_ext'][$extension]))
937          {
938            if (basename($path) == 'thumbnail')
939            {
940              array_push($fs['thumbnails'], $path.'/'.$node);
941            }
942            else if (basename($path) == 'pwg_representative')
943            {
944              array_push($fs['representatives'], $path.'/'.$node);
945            }
946            else
947            {
948              array_push($fs['elements'], $path.'/'.$node);
949            }
950          }
951//          else if (in_array($extension, $conf['file_ext']))
952          else if (isset($conf['flip_file_ext'][$extension]))
953          {
954            array_push($fs['elements'], $path.'/'.$node);
955          }
956        }
957        else if (is_dir($path.'/'.$node)
958                 and $node != '.'
959                 and $node != '..'
960                 and $node != 'pwg_high'
961                 and $recursive)
962        {
963          array_push($subdirs, $node);
964        }
965      }
966    }
967    closedir($contents);
968
969    foreach ($subdirs as $subdir)
970    {
971      $tmp_fs = get_fs($path.'/'.$subdir);
972
973      $fs['elements']        = array_merge($fs['elements'],
974                                           $tmp_fs['elements']);
975
976      $fs['thumbnails']      = array_merge($fs['thumbnails'],
977                                           $tmp_fs['thumbnails']);
978
979      $fs['representatives'] = array_merge($fs['representatives'],
980                                           $tmp_fs['representatives']);
981    }
982  }
983  return $fs;
984}
985
986/**
987 * stupidly returns the current microsecond since Unix epoch
988 */
989function micro_seconds()
990{
991  $t1 = explode(' ', microtime());
992  $t2 = explode('.', $t1[0]);
993  $t2 = $t1[1].substr($t2[1], 0, 6);
994  return $t2;
995}
996
997/**
998 * synchronize base users list and related users list
999 *
1000 * compares and synchronizes base users table (USERS_TABLE) with its child
1001 * tables (USER_INFOS_TABLE, USER_ACCESS, USER_CACHE, USER_GROUP) : each
1002 * base user must be present in child tables, users in child tables not
1003 * present in base table must be deleted.
1004 *
1005 * @return void
1006 */
1007function sync_users()
1008{
1009  global $conf;
1010
1011  $query = '
1012SELECT '.$conf['user_fields']['id'].' AS id
1013  FROM '.USERS_TABLE.'
1014;';
1015  $base_users = array_from_query($query, 'id');
1016
1017  $query = '
1018SELECT user_id
1019  FROM '.USER_INFOS_TABLE.'
1020;';
1021  $infos_users = array_from_query($query, 'user_id');
1022
1023  // users present in $base_users and not in $infos_users must be added
1024  $to_create = array_diff($base_users, $infos_users);
1025
1026  if (count($to_create) > 0)
1027  {
1028    create_user_infos($to_create);
1029  }
1030
1031  // users present in user related tables must be present in the base user
1032  // table
1033  $tables = array(
1034    USER_MAIL_NOTIFICATION_TABLE,
1035    USER_FEED_TABLE,
1036    USER_INFOS_TABLE,
1037    USER_ACCESS_TABLE,
1038    USER_CACHE_TABLE,
1039    USER_CACHE_CATEGORIES_TABLE,
1040    USER_GROUP_TABLE
1041    );
1042
1043  foreach ($tables as $table)
1044  {
1045    $query = '
1046SELECT DISTINCT user_id
1047  FROM '.$table.'
1048;';
1049    $to_delete = array_diff(
1050      array_from_query($query, 'user_id'),
1051      $base_users
1052      );
1053
1054    if (count($to_delete) > 0)
1055    {
1056      $query = '
1057DELETE
1058  FROM '.$table.'
1059  WHERE user_id in ('.implode(',', $to_delete).')
1060;';
1061      pwg_query($query);
1062    }
1063  }
1064}
1065
1066/**
1067 * updates categories.uppercats field based on categories.id +
1068 * categories.id_uppercat
1069 *
1070 * @return void
1071 */
1072function update_uppercats()
1073{
1074  $query = '
1075SELECT id, id_uppercat, uppercats
1076  FROM '.CATEGORIES_TABLE.'
1077;';
1078  $cat_map = hash_from_query($query, 'id');
1079
1080  $datas = array();
1081  foreach ($cat_map as $id => $cat)
1082  {
1083    $upper_list = array();
1084
1085    $uppercat = $id;
1086    while ($uppercat)
1087    {
1088      array_push($upper_list, $uppercat);
1089      $uppercat = $cat_map[$uppercat]['id_uppercat'];
1090    }
1091
1092    $new_uppercats = implode(',', array_reverse($upper_list));
1093    if ($new_uppercats != $cat['uppercats'])
1094    {
1095      array_push(
1096        $datas,
1097        array(
1098          'id' => $id,
1099          'uppercats' => $new_uppercats
1100          )
1101        );
1102    }
1103  }
1104  $fields = array('primary' => array('id'), 'update' => array('uppercats'));
1105  mass_updates(CATEGORIES_TABLE, $fields, $datas);
1106}
1107
1108/**
1109 * update images.path field
1110 *
1111 * @return void
1112 */
1113function update_path()
1114{
1115  $query = '
1116SELECT DISTINCT(storage_category_id)
1117  FROM '.IMAGES_TABLE.'
1118  WHERE storage_category_id IS NOT NULL
1119;';
1120  $cat_ids = array_from_query($query, 'storage_category_id');
1121  $fulldirs = get_fulldirs($cat_ids);
1122
1123  foreach ($cat_ids as $cat_id)
1124  {
1125    $query = '
1126UPDATE '.IMAGES_TABLE.'
1127  SET path = CONCAT(\''.$fulldirs[$cat_id].'\',\'/\',file)
1128  WHERE storage_category_id = '.$cat_id.'
1129;';
1130    pwg_query($query);
1131  }
1132}
1133
1134/**
1135 * update images.average_rate field
1136 * param int $element_id optional, otherwise applies to all
1137 * @return void
1138 */
1139function update_average_rate( $element_id=-1 )
1140{
1141  $query = '
1142SELECT element_id,
1143       ROUND(AVG(rate),2) AS average_rate
1144  FROM '.RATE_TABLE;
1145  if ( $element_id != -1 )
1146  {
1147    $query .= ' WHERE element_id=' . $element_id;
1148  }
1149  $query .= ' GROUP BY element_id;';
1150
1151  $result = pwg_query($query);
1152
1153  $datas = array();
1154
1155  while ($row = mysql_fetch_array($result))
1156  {
1157    array_push(
1158      $datas,
1159      array(
1160        'id' => $row['element_id'],
1161        'average_rate' => $row['average_rate']
1162        )
1163      );
1164  }
1165
1166  mass_updates(
1167    IMAGES_TABLE,
1168    array(
1169      'primary' => array('id'),
1170      'update' => array('average_rate')
1171      ),
1172    $datas
1173    );
1174
1175  $query='
1176SELECT id FROM '.IMAGES_TABLE .'
1177  LEFT JOIN '.RATE_TABLE.' ON id=element_id
1178  WHERE element_id IS NULL AND average_rate IS NOT NULL';
1179  if ( $element_id != -1 )
1180  {
1181    $query .= ' AND id=' . $element_id;
1182  }
1183  $to_update = array_from_query( $query, 'id');
1184
1185  if ( !empty($to_update) )
1186  {
1187    $query='
1188UPDATE '.IMAGES_TABLE .'
1189  SET average_rate=NULL
1190  WHERE id IN (' . implode(',',$to_update) . ')';
1191    pwg_query($query);
1192  }
1193}
1194
1195/**
1196 * change the parent category of the given categories. The categories are
1197 * supposed virtual.
1198 *
1199 * @param array category identifiers
1200 * @param int parent category identifier
1201 * @return void
1202 */
1203function move_categories($category_ids, $new_parent = -1)
1204{
1205  global $page;
1206
1207  if (count($category_ids) == 0)
1208  {
1209    return;
1210  }
1211
1212  $new_parent = $new_parent < 1 ? 'NULL' : $new_parent;
1213
1214  $categories = array();
1215
1216  $query = '
1217SELECT id, id_uppercat, status, uppercats
1218  FROM '.CATEGORIES_TABLE.'
1219  WHERE id IN ('.implode(',', $category_ids).')
1220;';
1221  $result = pwg_query($query);
1222  while ($row = mysql_fetch_array($result))
1223  {
1224    $categories[$row['id']] =
1225      array(
1226        'parent' => empty($row['id_uppercat']) ? 'NULL' : $row['id_uppercat'],
1227        'status' => $row['status'],
1228        'uppercats' => $row['uppercats']
1229        );
1230  }
1231
1232  // is the movement possible? The movement is impossible if you try to move
1233  // a category in a sub-category or itself
1234  if ('NULL' != $new_parent)
1235  {
1236    $query = '
1237SELECT uppercats
1238  FROM '.CATEGORIES_TABLE.'
1239  WHERE id = '.$new_parent.'
1240;';
1241    list($new_parent_uppercats) = mysql_fetch_row(pwg_query($query));
1242
1243    foreach ($categories as $category)
1244    {
1245      // technically, you can't move a category with uppercats 12,125,13,14
1246      // into a new parent category with uppercats 12,125,13,14,24
1247      if (preg_match('/^'.$category['uppercats'].',/', $new_parent_uppercats))
1248      {
1249        array_push(
1250          $page['errors'],
1251          l10n('You cannot move a category in its own sub category')
1252          );
1253        return;
1254      }
1255    }
1256  }
1257
1258  $tables =
1259    array(
1260      USER_ACCESS_TABLE => 'user_id',
1261      GROUP_ACCESS_TABLE => 'group_id'
1262      );
1263
1264  $query = '
1265UPDATE '.CATEGORIES_TABLE.'
1266  SET id_uppercat = '.$new_parent.'
1267  WHERE id IN ('.implode(',', $category_ids).')
1268;';
1269  pwg_query($query);
1270
1271  update_uppercats();
1272  update_global_rank();
1273
1274  // status and related permissions management
1275  if ('NULL' == $new_parent)
1276  {
1277    $parent_status = 'public';
1278  }
1279  else
1280  {
1281    $query = '
1282SELECT status
1283  FROM '.CATEGORIES_TABLE.'
1284  WHERE id = '.$new_parent.'
1285;';
1286    list($parent_status) = mysql_fetch_row(pwg_query($query));
1287  }
1288
1289  if ('private' == $parent_status)
1290  {
1291    foreach ($categories as $cat_id => $category)
1292    {
1293      switch ($category['status'])
1294      {
1295        case 'public' :
1296        {
1297          set_cat_status(array($cat_id), 'private');
1298          break;
1299        }
1300        case 'private' :
1301        {
1302          $subcats = get_subcat_ids(array($cat_id));
1303
1304          foreach ($tables as $table => $field)
1305          {
1306            $query = '
1307SELECT '.$field.'
1308  FROM '.$table.'
1309  WHERE cat_id = '.$cat_id.'
1310;';
1311            $category_access = array_from_query($query, $field);
1312
1313            $query = '
1314SELECT '.$field.'
1315  FROM '.$table.'
1316  WHERE cat_id = '.$new_parent.'
1317;';
1318            $parent_access = array_from_query($query, $field);
1319
1320            $to_delete = array_diff($parent_access, $category_access);
1321
1322            if (count($to_delete) > 0)
1323            {
1324              $query = '
1325DELETE FROM '.$table.'
1326  WHERE '.$field.' IN ('.implode(',', $to_delete).')
1327    AND cat_id IN ('.implode(',', $subcats).')
1328;';
1329              pwg_query($query);
1330            }
1331          }
1332          break;
1333        }
1334      }
1335    }
1336  }
1337
1338  array_push(
1339    $page['infos'],
1340    l10n_dec(
1341      '%d category moved', '%d categories moved',
1342      count($categories)
1343      )
1344    );
1345}
1346
1347/**
1348 * create a virtual category
1349 *
1350 * @param string category name
1351 * @param int parent category id
1352 * @return array with ('info' and 'id') or ('error') key
1353 */
1354function create_virtual_category($category_name, $parent_id=null)
1355{
1356  global $conf;
1357
1358  // is the given category name only containing blank spaces ?
1359  if (preg_match('/^\s*$/', $category_name))
1360  {
1361    return array('error' => l10n('cat_error_name'));
1362  }
1363
1364  $parent_id = !empty($parent_id) ? $parent_id : 'NULL';
1365
1366  $query = '
1367SELECT MAX(rank)
1368  FROM '.CATEGORIES_TABLE.'
1369  WHERE id_uppercat '.(is_numeric($parent_id) ? '= '.$parent_id : 'IS NULL').'
1370;';
1371  list($current_rank) = mysql_fetch_array(pwg_query($query));
1372
1373  $insert = array(
1374    'name' => $category_name,
1375    'rank' => ++$current_rank,
1376    'commentable' => boolean_to_string($conf['newcat_default_commentable']),
1377    'uploadable' => 'false',
1378    );
1379
1380  if ($parent_id != 'NULL')
1381  {
1382    $query = '
1383SELECT id, uppercats, global_rank, visible, status
1384  FROM '.CATEGORIES_TABLE.'
1385  WHERE id = '.$parent_id.'
1386;';
1387    $parent = mysql_fetch_array(pwg_query($query));
1388
1389    $insert{'id_uppercat'} = $parent{'id'};
1390    $insert{'global_rank'} = $parent{'global_rank'}.'.'.$insert{'rank'};
1391
1392    // at creation, must a category be visible or not ? Warning : if the
1393    // parent category is invisible, the category is automatically create
1394    // invisible. (invisible = locked)
1395    if ('false' == $parent['visible'])
1396    {
1397      $insert{'visible'} = 'false';
1398    }
1399    else
1400    {
1401      $insert{'visible'} = boolean_to_string($conf['newcat_default_visible']);
1402    }
1403
1404    // at creation, must a category be public or private ? Warning : if the
1405    // parent category is private, the category is automatically create
1406    // private.
1407    if ('private' == $parent['status'])
1408    {
1409      $insert{'status'} = 'private';
1410    }
1411    else
1412    {
1413      $insert{'status'} = $conf['newcat_default_status'];
1414    }
1415  }
1416  else
1417  {
1418    $insert{'visible'} = boolean_to_string($conf['newcat_default_visible']);
1419    $insert{'status'} = $conf['newcat_default_status'];
1420    $insert{'global_rank'} = $insert{'rank'};
1421  }
1422
1423  // we have then to add the virtual category
1424  mass_inserts(
1425    CATEGORIES_TABLE,
1426    array(
1427      'site_id', 'name', 'id_uppercat', 'rank', 'commentable',
1428      'uploadable', 'visible', 'status', 'global_rank',
1429      ),
1430    array($insert)
1431    );
1432
1433  $inserted_id = mysql_insert_id();
1434
1435  $query = '
1436UPDATE
1437  '.CATEGORIES_TABLE.'
1438  SET uppercats = \''.
1439    (isset($parent) ? $parent{'uppercats'}.',' : '').
1440    $inserted_id.
1441    '\'
1442  WHERE id = '.$inserted_id.'
1443;';
1444  pwg_query($query);
1445
1446  return array(
1447    'info' => l10n('cat_virtual_added'),
1448    'id'   => $inserted_id,
1449    );
1450}
1451
1452/**
1453 * Set tags to an image. Warning: given tags are all tags associated to the
1454 * image, not additionnal tags.
1455 *
1456 * @param array tag ids
1457 * @param int image id
1458 * @return void
1459 */
1460function set_tags($tags, $image_id)
1461{
1462  $query = '
1463DELETE
1464  FROM '.IMAGE_TAG_TABLE.'
1465  WHERE image_id = '.$image_id.'
1466;';
1467  pwg_query($query);
1468
1469  if (count($tags) > 0)
1470  {
1471    $inserts = array();
1472    foreach ($tags as $tag_id)
1473    {
1474      array_push(
1475        $inserts,
1476        array(
1477          'tag_id' => $tag_id,
1478          'image_id' => $image_id
1479          )
1480        );
1481    }
1482    mass_inserts(
1483      IMAGE_TAG_TABLE,
1484      array_keys($inserts[0]),
1485      $inserts
1486      );
1487  }
1488}
1489
1490/**
1491 * Add new tags to a set of images.
1492 *
1493 * @param array tag ids
1494 * @param array image ids
1495 * @return void
1496 */
1497function add_tags($tags, $images)
1498{
1499  if (count($tags) == 0 or count($tags) == 0)
1500  {
1501    return;
1502  }
1503
1504  // we can't insert twice the same {image_id,tag_id} so we must first
1505  // delete lines we'll insert later
1506  $query = '
1507DELETE
1508  FROM '.IMAGE_TAG_TABLE.'
1509  WHERE image_id IN ('.implode(',', $images).')
1510    AND tag_id IN ('.implode(',', $tags).')
1511;';
1512  pwg_query($query);
1513
1514  $inserts = array();
1515  foreach ($images as $image_id)
1516  {
1517    foreach ($tags as $tag_id)
1518    {
1519      array_push(
1520        $inserts,
1521        array(
1522          'image_id' => $image_id,
1523          'tag_id' => $tag_id,
1524          )
1525        );
1526    }
1527  }
1528  mass_inserts(
1529    IMAGE_TAG_TABLE,
1530    array_keys($inserts[0]),
1531    $inserts
1532    );
1533}
1534
1535function tag_id_from_tag_name($tag_name)
1536{
1537  global $page;
1538
1539  $tag_name = trim($tag_name);
1540  if (isset($page['tag_id_from_tag_name_cache'][$tag_name]))
1541  {
1542    return $page['tag_id_from_tag_name_cache'][$tag_name];
1543  }
1544
1545  // does the tag already exists?
1546  $query = '
1547SELECT id
1548  FROM '.TAGS_TABLE.'
1549  WHERE name = \''.$tag_name.'\'
1550;';
1551  $existing_tags = array_from_query($query, 'id');
1552
1553  if (count($existing_tags) == 0)
1554  {
1555    mass_inserts(
1556      TAGS_TABLE,
1557      array('name', 'url_name'),
1558      array(
1559        array(
1560          'name' => $tag_name,
1561          'url_name' => str2url($tag_name),
1562          )
1563        )
1564      );
1565
1566    $page['tag_id_from_tag_name_cache'][$tag_name] = mysql_insert_id();
1567  }
1568  else
1569  {
1570    $page['tag_id_from_tag_name_cache'][$tag_name] = $existing_tags[0];
1571  }
1572
1573  return $page['tag_id_from_tag_name_cache'][$tag_name];
1574}
1575
1576function set_tags_of($tags_of)
1577{
1578  if (count($tags_of) > 0)
1579  {
1580    $query = '
1581DELETE
1582  FROM '.IMAGE_TAG_TABLE.'
1583  WHERE image_id IN ('.implode(',', array_keys($tags_of)).')
1584;';
1585    pwg_query($query);
1586
1587    $inserts = array();
1588
1589    foreach ($tags_of as $image_id => $tag_ids)
1590    {
1591      foreach ($tag_ids as $tag_id)
1592      {
1593        array_push(
1594          $inserts,
1595          array(
1596            'image_id' => $image_id,
1597            'tag_id' => $tag_id,
1598            )
1599          );
1600      }
1601    }
1602
1603    mass_inserts(
1604      IMAGE_TAG_TABLE,
1605      array_keys($inserts[0]),
1606      $inserts
1607      );
1608  }
1609}
1610
1611/**
1612 * Do maintenance on all PWG tables
1613 *
1614 * @return none
1615 */
1616function do_maintenance_all_tables()
1617{
1618  global $prefixeTable, $page;
1619
1620  $all_tables = array();
1621
1622  // List all tables
1623  $query = 'SHOW TABLES LIKE \''.$prefixeTable.'%\'';
1624  $result = pwg_query($query);
1625  while ($row = mysql_fetch_array($result))
1626  {
1627    array_push($all_tables, $row[0]);
1628  }
1629
1630  // Repair all tables
1631  $query = 'REPAIR TABLE '.implode(', ', $all_tables);
1632  $mysql_rc = pwg_query($query);
1633
1634  // Re-Order all tables
1635  foreach ($all_tables as $table_name)
1636  {
1637    $all_primary_key = array();
1638
1639    $query = 'DESC '.$table_name.';';
1640    $result = pwg_query($query);
1641    while ($row = mysql_fetch_array($result))
1642    {
1643      if ($row['Key'] == 'PRI')
1644      {
1645        array_push($all_primary_key, $row['Field']);
1646      }
1647    }
1648
1649    if (count($all_primary_key) != 0)
1650    {
1651      $query = 'ALTER TABLE '.$table_name.' ORDER BY '.implode(', ', $all_primary_key).';';
1652      $mysql_rc = $mysql_rc && pwg_query($query);
1653    }
1654  }
1655
1656  // Optimize all tables
1657  $query = 'OPTIMIZE TABLE '.implode(', ', $all_tables);
1658  $mysql_rc = $mysql_rc && pwg_query($query);
1659  if ($mysql_rc)
1660  {
1661    array_push(
1662          $page['infos'],
1663          l10n('Optimizations completed')
1664          );
1665  }
1666  else
1667  {
1668    array_push(
1669          $page['errors'],
1670          l10n('Optimizations errors')
1671          );
1672  }
1673}
1674
1675/**
1676 * Associate a list of images to a list of categories.
1677 *
1678 * The function will not duplicate links
1679 *
1680 * @param array images
1681 * @param array categories
1682 * @return void
1683 */
1684function associate_images_to_categories($images, $categories)
1685{
1686  if (count($images) == 0
1687      or count($categories) == 0)
1688  {
1689    return false;
1690  }
1691
1692  $query = '
1693DELETE
1694  FROM '.IMAGE_CATEGORY_TABLE.'
1695  WHERE image_id IN ('.implode(',', $images).')
1696    AND category_id IN ('.implode(',', $categories).')
1697;';
1698  pwg_query($query);
1699
1700  $inserts = array();
1701  foreach ($categories as $category_id)
1702  {
1703    foreach ($images as $image_id)
1704    {
1705      array_push(
1706        $inserts,
1707        array(
1708          'image_id' => $image_id,
1709          'category_id' => $category_id,
1710          )
1711        );
1712    }
1713  }
1714
1715  mass_inserts(
1716    IMAGE_CATEGORY_TABLE,
1717    array_keys($inserts[0]),
1718    $inserts
1719    );
1720
1721  update_category($categories);
1722}
1723
1724/**
1725 * Associate images associated to a list of source categories to a list of
1726 * destination categories.
1727 *
1728 * @param array sources
1729 * @param array destinations
1730 * @return void
1731 */
1732function associate_categories_to_categories($sources, $destinations)
1733{
1734  if (count($sources) == 0)
1735  {
1736    return false;
1737  }
1738
1739  $query = '
1740SELECT image_id
1741  FROM '.IMAGE_CATEGORY_TABLE.'
1742  WHERE category_id IN ('.implode(',', $sources).')
1743;';
1744  $images = array_from_query($query, 'image_id');
1745
1746  associate_images_to_categories($images, $destinations);
1747}
1748
1749/**
1750 * Refer main Piwigo URLs (currently PHPWG_DOMAIN domain)
1751 *
1752 * @param void
1753 * @return array like $conf['links']
1754 */
1755function pwg_URL()
1756{
1757  $urls = array(
1758    'HOME'       => 'http://'.PHPWG_DOMAIN,
1759    'WIKI'       => 'http://'.PHPWG_DOMAIN.'/doc',
1760    'DEMO'       => 'http://'.PHPWG_DOMAIN.'/demo',
1761    'FORUM'      => 'http://'.PHPWG_DOMAIN.'/forum',
1762    'BUGS'       => 'http://'.PHPWG_DOMAIN.'/bugs',
1763    'EXTENSIONS' => 'http://'.PHPWG_DOMAIN.'/ext',
1764    );
1765  return $urls;
1766}
1767
1768/**
1769 * Invalidates cahed data (permissions and category counts) for all users.
1770 */
1771function invalidate_user_cache($full = true)
1772{
1773  if ($full)
1774  {
1775    $query = '
1776TRUNCATE TABLE '.USER_CACHE_CATEGORIES_TABLE.';';
1777    pwg_query($query);
1778    $query = '
1779TRUNCATE TABLE '.USER_CACHE_TABLE.';';
1780    pwg_query($query);
1781  }
1782  else
1783  {
1784    $query = '
1785UPDATE '.USER_CACHE_TABLE.'
1786  SET need_update = \'true\';';
1787    pwg_query($query);
1788  }
1789  trigger_action('invalidate_user_cache', $full);
1790}
1791
1792/**
1793 * adds the caracter set to a create table sql query.
1794 * all CREATE TABLE queries must call this function
1795 * @param string query - the sql query
1796 */
1797function create_table_add_character_set($query)
1798{
1799  defined('DB_CHARSET') or fatal_error('create_table_add_character_set DB_CHARSET undefined');
1800  if ('DB_CHARSET'!='')
1801  {
1802    if ( version_compare(mysql_get_server_info(), '4.1.0', '<') )
1803    {
1804      return $query;
1805    }
1806    $charset_collate = " DEFAULT CHARACTER SET ".DB_CHARSET;
1807    if (DB_COLLATE!='')
1808    {
1809      $charset_collate .= " COLLATE ".DB_COLLATE;
1810    }
1811    if ( is_array($query) )
1812    {
1813      foreach( $query as $id=>$q)
1814      {
1815        $q=trim($q);
1816        $q=trim($q, ';');
1817        if (preg_match('/^CREATE\s+TABLE/i',$q))
1818        {
1819          $q.=$charset_collate;
1820        }
1821        $q .= ';';
1822        $query[$id] = $q;
1823      }
1824    }
1825    else
1826    {
1827      $query=trim($query);
1828      $query=trim($query, ';');
1829      if (preg_match('/^CREATE\s+TABLE/i',$query))
1830      {
1831        $query.=$charset_collate;
1832      }
1833      $query .= ';';
1834    }
1835  }
1836  return $query;
1837}
1838
1839/**
1840 * Returns array use on template with html_options method
1841 * @param Min and Max access to use
1842 * @return array of user access level
1843 */
1844function get_user_access_level_html_options($MinLevelAccess = ACCESS_FREE, $MaxLevelAccess = ACCESS_CLOSED)
1845{
1846  $tpl_options = array();
1847  for ($level = $MinLevelAccess; $level <= $MaxLevelAccess; $level++)
1848  {
1849    $tpl_options[$level] = l10n(sprintf('ACCESS_%d', $level));
1850  }
1851  return $tpl_options;
1852}
1853
1854/**
1855 * returns a list of templates currently available in template-extension
1856 * Each .tpl file is extracted from template-extension.
1857 * @return array
1858 */
1859function get_extents($start='')
1860{
1861  if ($start == '') { $start = './template-extension'; }
1862  $dir = opendir($start);
1863  $extents = array();
1864
1865  while (($file = readdir($dir)) !== false)
1866  {
1867    if ( $file == '.' or $file == '..' or $file == '.svn') continue;
1868    $path = $start . '/' . $file;
1869    if (is_dir($path))
1870    {
1871      $extents = array_merge($extents, get_extents($path));
1872    }
1873    elseif ( !is_link($path) and file_exists($path)
1874            and get_extension($path) == 'tpl' )
1875    {
1876      $extents[] = substr($path, 21);
1877    }
1878  }
1879  return $extents;
1880}
1881
1882function create_tag($tag_name)
1883{
1884  // does the tag already exists?
1885  $query = '
1886SELECT id
1887  FROM '.TAGS_TABLE.'
1888  WHERE name = \''.$tag_name.'\'
1889;';
1890  $existing_tags = array_from_query($query, 'id');
1891
1892  if (count($existing_tags) == 0)
1893  {
1894    mass_inserts(
1895      TAGS_TABLE,
1896      array('name', 'url_name'),
1897      array(
1898        array(
1899          'name' => $tag_name,
1900          'url_name' => str2url($tag_name),
1901          )
1902        )
1903      );
1904
1905    $inserted_id = mysql_insert_id();
1906
1907    return array(
1908      'info' => sprintf(
1909        l10n('Tag "%s" was added'),
1910        stripslashes($tag_name)
1911        ),
1912      'id' => $inserted_id,
1913      );
1914  }
1915  else
1916  {
1917    return array(
1918      'error' => sprintf(
1919        l10n('Tag "%s" already exists'),
1920        stripslashes($tag_name)
1921        )
1922      );
1923  }
1924}
1925
1926/**
1927 * Is the category accessible to the (Admin) user ?
1928 *
1929 * Note : if the user is not authorized to see this category, category jump
1930 * will be replaced by admin cat_modify page
1931 *
1932 * @param int category id to verify
1933 * @return bool
1934 */
1935function cat_admin_access($category_id)
1936{
1937  global $user;
1938
1939  // $filter['visible_categories'] and $filter['visible_images']
1940  // are not used because it's not necessary (filter <> restriction)
1941  if (in_array($category_id, explode(',', $user['forbidden_categories'])))
1942  {
1943    return false;
1944  }
1945  return true;
1946}
1947
1948/**
1949 * Retrieve data from external URL
1950 *
1951 * @param string $src: URL
1952 * @param global $dest: can be a file ressource or string
1953 * @return bool
1954 */
1955function fetchRemote($src, &$dest, $user_agent='Piwigo', $step=0)
1956{
1957  // Try to retrieve data from local file?
1958  if (!url_is_remote($src))
1959  {
1960    $content = @file_get_contents($src);
1961    if ($content !== false)
1962    {
1963      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1964      return true;
1965    }
1966    else
1967    {
1968      return false;
1969    }
1970  }
1971
1972  // After 3 redirections, return false
1973  if ($step > 3) return false;
1974
1975  // Initialize $dest
1976  is_resource($dest) or $dest = '';
1977
1978  // Try curl to read remote file
1979  if (function_exists('curl_init'))
1980  {
1981    $ch = @curl_init();
1982    @curl_setopt($ch, CURLOPT_URL, $src);
1983    @curl_setopt($ch, CURLOPT_HEADER, 1);
1984    @curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
1985    @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1986    $content = @curl_exec($ch);
1987    $header_length = @curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1988    $status = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
1989    @curl_close($ch);
1990    if ($content !== false and $status >= 200 and $status < 400)
1991    {
1992      if (preg_match('/Location:\s+?(.+)/', substr($content, 0, $header_length), $m))
1993      {
1994        return fetchRemote($m[1], $dest, $user_agent, $step+1);
1995      }
1996      $content = substr($content, $header_length);
1997      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1998      return true;
1999    }
2000  }
2001
2002  // Try file_get_contents to read remote file
2003  if (ini_get('allow_url_fopen'))
2004  {
2005    $content = @file_get_contents($src);
2006    if ($content !== false)
2007    {
2008      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
2009      return true;
2010    }
2011  }
2012
2013  // Try fsockopen to read remote file
2014  $src = parse_url($src);
2015  $host = $src['host'];
2016  $path = isset($src['path']) ? $src['path'] : '/';
2017  $path .= isset($src['query']) ? '?'.$src['query'] : '';
2018
2019  if (($s = @fsockopen($host,80,$errno,$errstr,5)) === false)
2020  {
2021    return false;
2022  }
2023
2024  fwrite($s,
2025    "GET ".$path." HTTP/1.0\r\n"
2026    ."Host: ".$host."\r\n"
2027    ."User-Agent: ".$user_agent."\r\n"
2028    ."Accept: */*\r\n"
2029    ."\r\n"
2030  );
2031
2032  $i = 0;
2033  $in_content = false;
2034  while (!feof($s))
2035  {
2036    $line = fgets($s);
2037
2038    if (rtrim($line,"\r\n") == '' && !$in_content)
2039    {
2040      $in_content = true;
2041      $i++;
2042      continue;
2043    }
2044    if ($i == 0)
2045    {
2046      if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/',rtrim($line,"\r\n"), $m))
2047      {
2048        fclose($s);
2049        return false;
2050      }
2051      $status = (integer) $m[2];
2052      if ($status < 200 || $status >= 400)
2053      {
2054        fclose($s);
2055        return false;
2056      }
2057    }
2058    if (!$in_content)
2059    {
2060      if (preg_match('/Location:\s+?(.+)$/',rtrim($line,"\r\n"),$m))
2061      {
2062        fclose($s);
2063        return fetchRemote(trim($m[1]),$dest,$user_agent,$step+1);
2064      }
2065      $i++;
2066      continue;
2067    }
2068    is_resource($dest) ? @fwrite($dest, $line) : $dest .= $line;
2069    $i++;
2070  }
2071  fclose($s);
2072  return true;
2073}
2074
2075
2076/**
2077 * returns the groupname corresponding to the given group identifier if
2078 * exists
2079 *
2080 * @param int group_id
2081 * @return mixed
2082 */
2083function get_groupname($group_id)
2084{
2085  $query = '
2086SELECT name
2087  FROM '.GROUPS_TABLE.'
2088  WHERE id = '.intval($group_id).'
2089;';
2090  $result = pwg_query($query);
2091  if (mysql_num_rows($result) > 0)
2092  {
2093    list($groupname) = mysql_fetch_row($result);
2094  }
2095  else
2096  {
2097    return false;
2098  }
2099
2100  return $groupname;
2101}
2102
2103/**
2104 * returns the username corresponding to the given user identifier if exists
2105 *
2106 * @param int user_id
2107 * @return mixed
2108 */
2109function get_username($user_id)
2110{
2111  global $conf;
2112
2113  $query = '
2114SELECT '.$conf['user_fields']['username'].'
2115  FROM '.USERS_TABLE.'
2116  WHERE '.$conf['user_fields']['id'].' = '.intval($user_id).'
2117;';
2118  $result = pwg_query($query);
2119  if (mysql_num_rows($result) > 0)
2120  {
2121    list($username) = mysql_fetch_row($result);
2122  }
2123  else
2124  {
2125    return false;
2126  }
2127
2128  return $username;
2129}
2130
2131function get_newsletter_subscribe_base_url($language) {
2132  $subscribe_domain = 'piwigo.org';
2133
2134  $domain_of = array(
2135    'fr_FR' => 'fr.piwigo.org',
2136    'it_IT' => 'it.piwigo.org',
2137    'de_DE' => 'de.piwigo.org',
2138    'es_ES' => 'es.piwigo.org',
2139    'zh_CN' => 'cn.piwigo.org',
2140    'pl_PL' => 'pl.piwigo.org',
2141    );
2142
2143  if (isset($domain_of[$language])) {
2144    $subscribe_domain = $domain_of[$language];
2145  }
2146
2147  return 'http://'.$subscribe_domain.'/announcement/subscribe/';
2148}
2149?>
Note: See TracBrowser for help on using the repository browser.