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

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

bug 1328: first specific implementation of the check_pwg_token for the
admin/tags page (all actions : add/edit/delete).

The "check_token" function was renammed into check_pwg_token because the
word "token" is too much generic.

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