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

Last change on this file since 3621 was 3621, checked in by plg, 15 years ago

merge r3620 from branch 2.0 to trunk

feature 1057 added: let the IT/DE/ES users subscribe to the ID/DE/ES Piwigo
announcement newsletter.

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