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

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

bug 1328: implement check_pwg_token for emails on user comments management.

The check_pwg_token and get_pwg_token functions were moved to the public side
(for use on comments.php)

The email sent to admins on new user comment does not directly includes
validate/delete actions.

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