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

Last change on this file since 23886 was 23886, checked in by flop25, 11 years ago

bug:2855
bug corrected (if that was a virtual album created without parent)

  • Property svn:eol-style set to LF
File size: 58.8 KB
RevLine 
[2]1<?php
[362]2// +-----------------------------------------------------------------------+
[8728]3// | Piwigo - a PHP based photo gallery                                    |
[2297]4// +-----------------------------------------------------------------------+
[19703]5// | Copyright(C) 2008-2013 Piwigo Team                  http://piwigo.org |
[2297]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// +-----------------------------------------------------------------------+
[2]23
[491]24include(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
25
[467]26// The function delete_site deletes a site and call the function
27// delete_categories for each primary category of the site
[12]28function delete_site( $id )
29{
30  // destruction of the categories of the site
[467]31  $query = '
32SELECT id
33  FROM '.CATEGORIES_TABLE.'
34  WHERE site_id = '.$id.'
35;';
[18628]36  $category_ids = array_from_query($query, 'id');
[467]37  delete_categories($category_ids);
[1060]38
[12]39  // destruction of the site
[467]40  $query = '
41DELETE FROM '.SITES_TABLE.'
42  WHERE id = '.$id.'
43;';
[587]44  pwg_query($query);
[12]45}
[345]46
[1060]47
[467]48// The function delete_categories deletes the categories identified by the
49// (numeric) key of the array $ids. It also deletes (in the database) :
[8265]50//    - all the elements physically linked to the category (delete_elements, see further)
[467]51//    - all the links between elements and this category
[12]52//    - all the restrictions linked to the category
53// The function works recursively.
[8265]54//
55// the $photo_deletion_mode is for photos virtually linked to the categorty
56//   * no_delete : delete no photo, may create orphans
57//   * delete_orphans : delete photos that are no longer linked to any category
58//   * force_delete : delete photos even if they are linked to another category
59function delete_categories($ids, $photo_deletion_mode='no_delete')
[12]60{
[521]61  if (count($ids) == 0)
62  {
63    return;
64  }
[657]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);
[1060]69
[8265]70  // destruction of all photos physically linked to the category
[467]71  $query = '
[1121]72SELECT id
73  FROM '.IMAGES_TABLE.'
74  WHERE storage_category_id IN (
75'.wordwrap(implode(', ', $ids), 80, "\n").')
[467]76;';
[18628]77  $element_ids = array_from_query($query, 'id');
[521]78  delete_elements($element_ids);
[21]79
[8265]80  // now, should we delete photos that are virtually linked to the category?
81  if ('delete_orphans' == $photo_deletion_mode or 'force_delete' == $photo_deletion_mode)
82  {
83    $query = '
84SELECT
85    DISTINCT(image_id)
86  FROM '.IMAGE_CATEGORY_TABLE.'
87  WHERE category_id IN ('.implode(',', $ids).')
88;';
89    $image_ids_linked = array_from_query($query, 'image_id');
[8848]90
91    if (count($image_ids_linked) > 0)
[8265]92    {
[8848]93      if ('delete_orphans' == $photo_deletion_mode)
94      {
95        $query = '
[8265]96SELECT
97    DISTINCT(image_id)
98  FROM '.IMAGE_CATEGORY_TABLE.'
99  WHERE image_id IN ('.implode(',', $image_ids_linked).')
100    AND category_id NOT IN ('.implode(',', $ids).')
101;';
[8848]102        $image_ids_not_orphans = array_from_query($query, 'image_id');
103        $image_ids_to_delete = array_diff($image_ids_linked, $image_ids_not_orphans);
104      }
[8265]105
[8848]106      if ('force_delete' == $photo_deletion_mode)
107      {
108        $image_ids_to_delete = $image_ids_linked;
109      }
110
111      delete_elements($image_ids_to_delete, true);
[8265]112    }
113  }
114
[61]115  // destruction of the links between images and this category
[467]116  $query = '
117DELETE FROM '.IMAGE_CATEGORY_TABLE.'
[657]118  WHERE category_id IN (
119'.wordwrap(implode(', ', $ids), 80, "\n").')
[467]120;';
[587]121  pwg_query($query);
[61]122
[21]123  // destruction of the access linked to the category
[467]124  $query = '
125DELETE FROM '.USER_ACCESS_TABLE.'
[657]126  WHERE cat_id IN (
127'.wordwrap(implode(', ', $ids), 80, "\n").')
[467]128;';
[587]129  pwg_query($query);
[1068]130
[467]131  $query = '
132DELETE FROM '.GROUP_ACCESS_TABLE.'
[657]133  WHERE cat_id IN (
134'.wordwrap(implode(', ', $ids), 80, "\n").')
[467]135;';
[587]136  pwg_query($query);
[21]137
[12]138  // destruction of the category
[467]139  $query = '
140DELETE FROM '.CATEGORIES_TABLE.'
[657]141  WHERE id IN (
142'.wordwrap(implode(', ', $ids), 80, "\n").')
[467]143;';
[587]144  pwg_query($query);
[498]145
[2882]146  $query='
[1866]147DELETE FROM '.OLD_PERMALINKS_TABLE.'
[1879]148  WHERE cat_id IN ('.implode(',',$ids).')';
[1866]149  pwg_query($query);
150
[2882]151  $query='
152DELETE FROM '.USER_CACHE_CATEGORIES_TABLE.'
153  WHERE cat_id IN ('.implode(',',$ids).')';
154  pwg_query($query);
155
[1605]156  trigger_action('delete_categories', $ids);
[12]157}
[345]158
[9191]159// Deletes all files (on disk) related to given image ids
160// @return image ids where files are deleted successfully
161function delete_element_files($ids)
[12]162{
[13651]163  global $conf;
[521]164  if (count($ids) == 0)
165  {
[6873]166    return 0;
[521]167  }
[1060]168
[9191]169  $new_ids = array();
[3145]170
[9191]171  $query = '
[2678]172SELECT
173    id,
174    path,
[6873]175    representative_ext
[2678]176  FROM '.IMAGES_TABLE.'
177  WHERE id IN ('.implode(',', $ids).')
178;';
[9191]179  $result = pwg_query($query);
180  while ($row = pwg_db_fetch_assoc($result))
181  {
182    if (url_is_remote($row['path']))
[2678]183    {
[9191]184      continue;
185    }
[12917]186
[9191]187    $files = array();
188    $files[] = get_element_path($row);
[2678]189
[9191]190    if (!empty($row['representative_ext']))
191    {
[12855]192      $files[] = original_to_representative( $files[0], $row['representative_ext']);
[9191]193    }
194
195    $ok = true;
[13052]196    if (!isset($conf['never_delete_originals']))
197    {
198      foreach ($files as $path)
199      {
200        if (is_file($path) and !unlink($path))
201        {
202          $ok = false;
203          trigger_error('"'.$path.'" cannot be removed', E_USER_WARNING);
204          break;
205        }
206      }
207    }
[12917]208
[9191]209    if ($ok)
210    {
[12917]211      delete_element_derivatives($row);
[17724]212      $new_ids[] = $row['id'];
[9191]213    }
214    else
215    {
216      break;
217    }
218  }
219  return $new_ids;
220}
221
222// The function delete_elements deletes the elements identified by the
223// (numeric) values of the array $ids. It also deletes (in the database) :
224//    - all the comments related to elements
225//    - all the links between categories and elements
226//    - all the favorites associated to elements
227// @return number of deleted elements
228function delete_elements($ids, $physical_deletion=false)
229{
230  if (count($ids) == 0)
231  {
232    return 0;
233  }
234  trigger_action('begin_delete_elements', $ids);
235
236  if ($physical_deletion)
237  {
238    $ids = delete_element_files($ids);
[6873]239    if (count($ids)==0)
240    {
241      return 0;
242    }
[2678]243  }
244
[12]245  // destruction of the comments on the image
[467]246  $query = '
247DELETE FROM '.COMMENTS_TABLE.'
[491]248  WHERE image_id IN (
249'.wordwrap(implode(', ', $ids), 80, "\n").')
[467]250;';
[587]251  pwg_query($query);
[61]252
253  // destruction of the links between images and this category
[467]254  $query = '
255DELETE FROM '.IMAGE_CATEGORY_TABLE.'
[491]256  WHERE image_id IN (
257'.wordwrap(implode(', ', $ids), 80, "\n").')
[467]258;';
[587]259  pwg_query($query);
[61]260
[1119]261  // destruction of the links between images and tags
262  $query = '
263DELETE FROM '.IMAGE_TAG_TABLE.'
264  WHERE image_id IN (
265'.wordwrap(implode(', ', $ids), 80, "\n").')
266;';
267  pwg_query($query);
268
[12]269  // destruction of the favorites associated with the picture
[467]270  $query = '
271DELETE FROM '.FAVORITES_TABLE.'
[491]272  WHERE image_id IN (
273'.wordwrap(implode(', ', $ids), 80, "\n").')
[467]274;';
[587]275  pwg_query($query);
[523]276
277  // destruction of the rates associated to this element
278  $query = '
279DELETE FROM '.RATE_TABLE.'
280  WHERE element_id IN (
281'.wordwrap(implode(', ', $ids), 80, "\n").')
282;';
[587]283  pwg_query($query);
[764]284
285  // destruction of the rates associated to this element
286  $query = '
287DELETE FROM '.CADDIE_TABLE.'
288  WHERE element_id IN (
289'.wordwrap(implode(', ', $ids), 80, "\n").')
290;';
291  pwg_query($query);
[1060]292
[12]293  // destruction of the image
[467]294  $query = '
295DELETE FROM '.IMAGES_TABLE.'
[491]296  WHERE id IN (
297'.wordwrap(implode(', ', $ids), 80, "\n").')
[467]298;';
[587]299  pwg_query($query);
[491]300
[4731]301  // are the photo used as category representant?
302  $query = '
303SELECT
304    id
305  FROM '.CATEGORIES_TABLE.'
306  WHERE representative_picture_id IN (
307'.wordwrap(implode(', ', $ids), 80, "\n").')
308;';
309  $category_ids = array_from_query($query, 'id');
310  if (count($category_ids) > 0)
311  {
312    update_category($category_ids);
313  }
[5691]314
[1605]315  trigger_action('delete_elements', $ids);
[6873]316  return count($ids);
[12]317}
[345]318
[12]319// The delete_user function delete a user identified by the $user_id
320// It also deletes :
[21]321//     - all the access linked to this user
322//     - all the links to any group
[12]323//     - all the favorites linked to this user
[680]324//     - calculated permissions linked to the user
[1028]325//     - all datas about notifications for the user
[650]326function delete_user($user_id)
[12]327{
[808]328  global $conf;
[1863]329  $tables = array(
330    // destruction of the access linked to the user
331    USER_ACCESS_TABLE,
332    // destruction of data notification by mail for this user
333    USER_MAIL_NOTIFICATION_TABLE,
334    // destruction of data RSS notification for this user
335    USER_FEED_TABLE,
336    // deletion of calculated permissions linked to the user
337    USER_CACHE_TABLE,
338    // deletion of computed cache data linked to the user
339    USER_CACHE_CATEGORIES_TABLE,
340    // destruction of the group links for this user
341    USER_GROUP_TABLE,
342    // destruction of the favorites associated with the user
343    FAVORITES_TABLE,
344    // destruction of the caddie associated with the user
345    CADDIE_TABLE,
[2339]346    // deletion of piwigo specific informations
[1863]347    USER_INFOS_TABLE,
348    );
[1060]349
[1863]350  foreach ($tables as $table)
351  {
352    $query = '
353DELETE FROM '.$table.'
[650]354  WHERE user_id = '.$user_id.'
355;';
[1863]356    pwg_query($query);
357  }
[21]358
[1863]359  // destruction of the user
[650]360  $query = '
[1863]361DELETE FROM '.SESSIONS_TABLE.'
[6664]362  WHERE data LIKE \'pwg_uid|i:'.(int)$user_id.';%\'
[650]363;';
364  pwg_query($query);
[21]365
[12]366  // destruction of the user
[650]367  $query = '
368DELETE FROM '.USERS_TABLE.'
[808]369  WHERE '.$conf['user_fields']['id'].' = '.$user_id.'
[650]370;';
371  pwg_query($query);
[1605]372
373  trigger_action('delete_user', $user_id);
[12]374}
[21]375
[491]376/**
[8762]377 * Deletes all tags linked to no photo
378 */
379function delete_orphan_tags()
380{
381  $orphan_tags = get_orphan_tags();
[12917]382
[8762]383  if (count($orphan_tags) > 0)
384  {
385    $orphan_tag_ids = array();
386    foreach ($orphan_tags as $tag)
387    {
[18628]388      $orphan_tag_ids[] = $tag['id'];
[8762]389    }
390
391    $query = '
392DELETE
393  FROM '.TAGS_TABLE.'
394  WHERE id IN ('.implode(',', $orphan_tag_ids).')
395;';
396    pwg_query($query);
397  }
398}
399
400/**
401 * Get all tags (id + name) linked to no photo
402 */
403function get_orphan_tags()
404{
405  $query = '
406SELECT
407    id,
408    name
409  FROM '.TAGS_TABLE.'
410    LEFT JOIN '.IMAGE_TAG_TABLE.' ON id = tag_id
411  WHERE tag_id IS NULL
412;';
[18628]413  return array_from_query($query);
[8762]414}
415
416/**
[2324]417 * Verifies that the representative picture really exists in the db and
418 * picks up a random represantive if possible and based on config.
[491]419 *
420 * @param mixed category id
421 * @returns void
422 */
[2324]423function update_category($ids = 'all')
[61]424{
[809]425  global $conf;
[1060]426
[2324]427  if ($ids=='all')
[61]428  {
[2324]429    $where_cats = '1=1';
[61]430  }
[2324]431  elseif ( !is_array($ids) )
[635]432  {
[2324]433    $where_cats = '%s='.$ids;
[635]434  }
[2324]435  else
[61]436  {
[2324]437    if (count($ids) == 0)
438    {
439      return false;
440    }
441    $where_cats = '%s IN('.wordwrap(implode(', ', $ids), 120, "\n").')';
[491]442  }
[2333]443
[2324]444  // find all categories where the setted representative is not possible :
445  // the picture does not exist
446  $query = '
447SELECT DISTINCT c.id
[809]448  FROM '.CATEGORIES_TABLE.' AS c LEFT JOIN '.IMAGES_TABLE.' AS i
449    ON c.representative_picture_id = i.id
[491]450  WHERE representative_picture_id IS NOT NULL
[2324]451    AND '.sprintf($where_cats, 'c.id').'
[809]452    AND i.id IS NULL
[491]453;';
[2324]454  $wrong_representant = array_from_query($query, 'id');
[809]455
[2324]456  if (count($wrong_representant) > 0)
457  {
458    $query = '
[809]459UPDATE '.CATEGORIES_TABLE.'
460  SET representative_picture_id = NULL
[2324]461  WHERE id IN ('.wordwrap(implode(', ', $wrong_representant), 120, "\n").')
[809]462;';
[2324]463    pwg_query($query);
464  }
[809]465
[2324]466  if (!$conf['allow_random_representative'])
467  {
468    // If the random representant is not allowed, we need to find
469    // categories with elements and with no representant. Those categories
470    // must be added to the list of categories to set to a random
471    // representant.
472    $query = '
473SELECT DISTINCT id
474  FROM '.CATEGORIES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.'
475    ON id = category_id
[635]476  WHERE representative_picture_id IS NULL
[2324]477    AND '.sprintf($where_cats, 'category_id').'
[491]478;';
[2324]479    $to_rand = array_from_query($query, 'id');
480    if (count($to_rand) > 0)
481    {
482      set_random_representant($to_rand);
[133]483    }
[61]484  }
485}
486
[825]487/**
[20544]488 * check and repair images integrity
489 *
490 * TODO see delete_elements function to check all linked tables
491 */
492function images_integrity()
493{
494  $query = '
495SELECT
496    image_id
497  FROM '.IMAGE_CATEGORY_TABLE.'
498    LEFT JOIN '.IMAGES_TABLE.' ON id = image_id
499  WHERE id IS NULL
500;';
501  $result = pwg_query($query);
502  $orphan_image_ids = array_from_query($query, 'image_id');
503
504  if (count($orphan_image_ids) > 0)
505  {
506    $query = '
507DELETE
508  FROM '.IMAGE_CATEGORY_TABLE.'
509  WHERE image_id IN ('.implode(',', $orphan_image_ids).')
510;';
511    pwg_query($query);
512  }
513}
514
515/**
[657]516 * returns an array containing sub-directories which can be a category,
517 * recursive by default
518 *
519 * directories nammed "thumbnail", "pwg_high" or "pwg_representative" are
520 * omitted
521 *
522 * @param string $basedir
523 * @return array
524 */
525function get_fs_directories($path, $recursive = true)
526{
527  $dirs = array();
[1060]528
[657]529  if (is_dir($path))
530  {
531    if ($contents = opendir($path))
532    {
533      while (($node = readdir($contents)) !== false)
534      {
[12642]535        if ($node != '.'
[657]536            and $node != '..'
[1006]537            and $node != '.svn'
[657]538            and $node != 'thumbnail'
539            and $node != 'pwg_high'
[12642]540            and $node != 'pwg_representative'
541            and is_dir($path.'/'.$node))
[657]542        {
543          array_push($dirs, $path.'/'.$node);
544          if ($recursive)
545          {
546            $dirs = array_merge($dirs, get_fs_directories($path.'/'.$node));
547          }
548        }
549      }
[2478]550      closedir($contents);
[657]551    }
552  }
553
554  return $dirs;
555}
556
[606]557/**
[2306]558 * order categories (update categories.rank and global_rank database fields)
559 * so that rank field are consecutive integers starting at 1 for each child
[625]560 * @return void
561 */
[2306]562function update_global_rank()
[625]563{
564  $query = '
[4385]565SELECT id, id_uppercat, uppercats, rank, global_rank
[625]566  FROM '.CATEGORIES_TABLE.'
[2491]567  ORDER BY id_uppercat,rank,name';
[625]568
[2306]569  $cat_map = array();
[625]570
[2306]571  $current_rank = 0;
572  $current_uppercat = '';
573
[625]574  $result = pwg_query($query);
[4325]575  while ($row = pwg_db_fetch_assoc($result))
[625]576  {
[2306]577    if ($row['id_uppercat'] != $current_uppercat)
578    {
579      $current_rank = 0;
580      $current_uppercat = $row['id_uppercat'];
581    }
582    ++$current_rank;
583    $cat =
584      array(
585        'rank' =>        $current_rank,
586        'rank_changed' =>$current_rank!=$row['rank'],
587        'global_rank' => $row['global_rank'],
588        'uppercats' =>   $row['uppercats'],
589        );
590    $cat_map[ $row['id'] ] = $cat;
[625]591  }
[1060]592
[625]593  $datas = array();
[2306]594
595  foreach( $cat_map as $id=>$cat )
[625]596  {
[2306]597    $new_global_rank = preg_replace(
[1082]598          '/(\d+)/e',
[2306]599          "\$cat_map['$1']['rank']",
600          str_replace(',', '.', $cat['uppercats'] )
601          );
602    if ( $cat['rank_changed']
603      or $new_global_rank!=$cat['global_rank']
604      )
605    {
606      $datas[] = array(
607          'id' => $id,
608          'rank' => $cat['rank'],
609          'global_rank' => $new_global_rank,
610        );
611    }
[625]612  }
613
[1082]614  mass_updates(
615    CATEGORIES_TABLE,
616    array(
617      'primary' => array('id'),
[2306]618      'update'  => array('rank', 'global_rank')
[1082]619      ),
620    $datas
621    );
[2306]622  return count($datas);
[625]623}
[632]624
625/**
626 * change the visible property on a set of categories
627 *
628 * @param array categories
629 * @param string value
630 * @return void
631 */
632function set_cat_visible($categories, $value)
633{
634  if (!in_array($value, array('true', 'false')))
635  {
[2491]636    trigger_error("set_cat_visible invalid param $value", E_USER_WARNING);
[632]637    return false;
638  }
639
640  // unlocking a category => all its parent categories become unlocked
641  if ($value == 'true')
642  {
[657]643    $uppercats = get_uppercat_ids($categories);
[632]644    $query = '
645UPDATE '.CATEGORIES_TABLE.'
646  SET visible = \'true\'
[2491]647  WHERE id IN ('.implode(',', $uppercats).')';
[632]648    pwg_query($query);
649  }
650  // locking a category   => all its child categories become locked
651  if ($value == 'false')
652  {
653    $subcats = get_subcat_ids($categories);
654    $query = '
655UPDATE '.CATEGORIES_TABLE.'
656  SET visible = \'false\'
[2491]657  WHERE id IN ('.implode(',', $subcats).')';
[632]658    pwg_query($query);
659  }
660}
661
662/**
663 * change the status property on a set of categories : private or public
664 *
665 * @param array categories
666 * @param string value
667 * @return void
668 */
669function set_cat_status($categories, $value)
670{
671  if (!in_array($value, array('public', 'private')))
672  {
[2491]673    trigger_error("set_cat_status invalid param $value", E_USER_WARNING);
[632]674    return false;
675  }
676
677  // make public a category => all its parent categories become public
678  if ($value == 'public')
679  {
[657]680    $uppercats = get_uppercat_ids($categories);
[632]681    $query = '
682UPDATE '.CATEGORIES_TABLE.'
683  SET status = \'public\'
684  WHERE id IN ('.implode(',', $uppercats).')
685;';
686    pwg_query($query);
687  }
688  // make a category private => all its child categories become private
689  if ($value == 'private')
690  {
691    $subcats = get_subcat_ids($categories);
692    $query = '
693UPDATE '.CATEGORIES_TABLE.'
694  SET status = \'private\'
[2491]695  WHERE id IN ('.implode(',', $subcats).')';
[632]696    pwg_query($query);
697  }
698}
[633]699
700/**
[657]701 * returns all uppercats category ids of the given category ids
702 *
703 * @param array cat_ids
704 * @return array
705 */
706function get_uppercat_ids($cat_ids)
707{
708  if (!is_array($cat_ids) or count($cat_ids) < 1)
709  {
710    return array();
711  }
[1060]712
[657]713  $uppercats = array();
714
715  $query = '
716SELECT uppercats
717  FROM '.CATEGORIES_TABLE.'
718  WHERE id IN ('.implode(',', $cat_ids).')
719;';
720  $result = pwg_query($query);
[4325]721  while ($row = pwg_db_fetch_assoc($result))
[657]722  {
723    $uppercats = array_merge($uppercats,
724                             explode(',', $row['uppercats']));
725  }
726  $uppercats = array_unique($uppercats);
727
728  return $uppercats;
729}
730
731/**
[633]732 * set a new random representant to the categories
733 *
734 * @param array categories
735 */
736function set_random_representant($categories)
737{
738  $datas = array();
739  foreach ($categories as $category_id)
740  {
741    $query = '
742SELECT image_id
743  FROM '.IMAGE_CATEGORY_TABLE.'
744  WHERE category_id = '.$category_id.'
[4331]745  ORDER BY '.DB_RANDOM_FUNCTION.'()
[4334]746  LIMIT 1
[633]747;';
[4325]748    list($representative) = pwg_db_fetch_row(pwg_query($query));
[1428]749
750    array_push(
751      $datas,
752      array(
753        'id' => $category_id,
754        'representative_picture_id' => $representative,
755        )
756      );
[633]757  }
758
[1428]759  mass_updates(
760    CATEGORIES_TABLE,
761    array(
762      'primary' => array('id'),
763      'update' => array('representative_picture_id')
764      ),
765    $datas
766    );
[633]767}
[638]768
769/**
[657]770 * returns the fulldir for each given category id
771 *
772 * @param array cat_ids
773 * @return array
774 */
775function get_fulldirs($cat_ids)
776{
777  if (count($cat_ids) == 0)
778  {
779    return array();
780  }
[1060]781
[657]782  // caching directories of existing categories
783  $query = '
784SELECT id, dir
785  FROM '.CATEGORIES_TABLE.'
786  WHERE dir IS NOT NULL
787;';
[2560]788  $cat_dirs = simple_hash_from_query($query, 'id', 'dir');
[657]789
[672]790  // caching galleries_url
791  $query = '
792SELECT id, galleries_url
793  FROM '.SITES_TABLE.'
794;';
[2560]795  $galleries_url = simple_hash_from_query($query, 'id', 'galleries_url');
[672]796
797  // categories : id, site_id, uppercats
[657]798  $query = '
[672]799SELECT id, uppercats, site_id
[657]800  FROM '.CATEGORIES_TABLE.'
[2560]801  WHERE dir IS NOT NULL
802    AND id IN (
[657]803'.wordwrap(implode(', ', $cat_ids), 80, "\n").')
804;';
[18628]805  $categories = array_from_query($query);
[1060]806
[657]807  // filling $cat_fulldirs
808  $cat_fulldirs = array();
[672]809  foreach ($categories as $category)
[657]810  {
[672]811    $uppercats = str_replace(',', '/', $category['uppercats']);
812    $cat_fulldirs[$category['id']] = $galleries_url[$category['site_id']];
813    $cat_fulldirs[$category['id']].= preg_replace('/(\d+)/e',
814                                                  "\$cat_dirs['$1']",
815                                                  $uppercats);
[657]816  }
817
818  return $cat_fulldirs;
819}
820
821/**
822 * returns an array with all file system files according to
823 * $conf['file_ext']
824 *
825 * @param string $path
826 * @param bool recursive
827 * @return array
828 */
829function get_fs($path, $recursive = true)
830{
831  global $conf;
832
833  // because isset is faster than in_array...
834  if (!isset($conf['flip_picture_ext']))
835  {
836    $conf['flip_picture_ext'] = array_flip($conf['picture_ext']);
837  }
838  if (!isset($conf['flip_file_ext']))
839  {
840    $conf['flip_file_ext'] = array_flip($conf['file_ext']);
841  }
842
843  $fs['elements'] = array();
844  $fs['thumbnails'] = array();
845  $fs['representatives'] = array();
846  $subdirs = array();
847
848  if (is_dir($path))
849  {
850    if ($contents = opendir($path))
851    {
852      while (($node = readdir($contents)) !== false)
853      {
[12640]854        if ($node == '.' or $node == '..') continue;
855
[657]856        if (is_file($path.'/'.$node))
857        {
858          $extension = get_extension($node);
[1060]859
[657]860//          if (in_array($extension, $conf['picture_ext']))
861          if (isset($conf['flip_picture_ext'][$extension]))
862          {
863            if (basename($path) == 'thumbnail')
864            {
865              array_push($fs['thumbnails'], $path.'/'.$node);
866            }
867            else if (basename($path) == 'pwg_representative')
868            {
869              array_push($fs['representatives'], $path.'/'.$node);
870            }
871            else
872            {
873              array_push($fs['elements'], $path.'/'.$node);
874            }
875          }
876//          else if (in_array($extension, $conf['file_ext']))
877          else if (isset($conf['flip_file_ext'][$extension]))
878          {
879            array_push($fs['elements'], $path.'/'.$node);
880          }
881        }
[12640]882        else if (is_dir($path.'/'.$node) and $node != 'pwg_high' and $recursive)
[657]883        {
884          array_push($subdirs, $node);
885        }
886      }
887    }
888    closedir($contents);
889
890    foreach ($subdirs as $subdir)
891    {
892      $tmp_fs = get_fs($path.'/'.$subdir);
893
894      $fs['elements']        = array_merge($fs['elements'],
895                                           $tmp_fs['elements']);
[1060]896
[657]897      $fs['thumbnails']      = array_merge($fs['thumbnails'],
898                                           $tmp_fs['thumbnails']);
[1060]899
[657]900      $fs['representatives'] = array_merge($fs['representatives'],
901                                           $tmp_fs['representatives']);
902    }
903  }
904  return $fs;
905}
[672]906
907/**
[809]908 * synchronize base users list and related users list
909 *
910 * compares and synchronizes base users table (USERS_TABLE) with its child
911 * tables (USER_INFOS_TABLE, USER_ACCESS, USER_CACHE, USER_GROUP) : each
912 * base user must be present in child tables, users in child tables not
913 * present in base table must be deleted.
914 *
915 * @return void
[808]916 */
917function sync_users()
918{
919  global $conf;
[1060]920
[808]921  $query = '
922SELECT '.$conf['user_fields']['id'].' AS id
923  FROM '.USERS_TABLE.'
924;';
925  $base_users = array_from_query($query, 'id');
926
927  $query = '
928SELECT user_id
929  FROM '.USER_INFOS_TABLE.'
930;';
931  $infos_users = array_from_query($query, 'user_id');
932
933  // users present in $base_users and not in $infos_users must be added
934  $to_create = array_diff($base_users, $infos_users);
935
936  if (count($to_create) > 0)
937  {
[1926]938    create_user_infos($to_create);
[808]939  }
940
[809]941  // users present in user related tables must be present in the base user
942  // table
[1082]943  $tables = array(
944    USER_MAIL_NOTIFICATION_TABLE,
945    USER_FEED_TABLE,
946    USER_INFOS_TABLE,
947    USER_ACCESS_TABLE,
948    USER_CACHE_TABLE,
[1624]949    USER_CACHE_CATEGORIES_TABLE,
[1082]950    USER_GROUP_TABLE
951    );
[1592]952
[809]953  foreach ($tables as $table)
[808]954  {
955    $query = '
[2095]956SELECT DISTINCT user_id
[809]957  FROM '.$table.'
958;';
[1082]959    $to_delete = array_diff(
960      array_from_query($query, 'user_id'),
961      $base_users
962      );
[1060]963
[809]964    if (count($to_delete) > 0)
965    {
966      $query = '
[808]967DELETE
[809]968  FROM '.$table.'
[808]969  WHERE user_id in ('.implode(',', $to_delete).')
970;';
[809]971      pwg_query($query);
972    }
973  }
974}
975
976/**
977 * updates categories.uppercats field based on categories.id +
978 * categories.id_uppercat
979 *
980 * @return void
981 */
982function update_uppercats()
983{
984  $query = '
[2304]985SELECT id, id_uppercat, uppercats
[809]986  FROM '.CATEGORIES_TABLE.'
987;';
[2304]988  $cat_map = hash_from_query($query, 'id');
[1060]989
[2304]990  $datas = array();
991  foreach ($cat_map as $id => $cat)
[809]992  {
[2304]993    $upper_list = array();
[809]994
995    $uppercat = $id;
[2304]996    while ($uppercat)
997    {
998      array_push($upper_list, $uppercat);
999      $uppercat = $cat_map[$uppercat]['id_uppercat'];
1000    }
[809]1001
[2304]1002    $new_uppercats = implode(',', array_reverse($upper_list));
1003    if ($new_uppercats != $cat['uppercats'])
[809]1004    {
[2304]1005      array_push(
1006        $datas,
1007        array(
1008          'id' => $id,
1009          'uppercats' => $new_uppercats
1010          )
1011        );
[809]1012    }
1013  }
1014  $fields = array('primary' => array('id'), 'update' => array('uppercats'));
1015  mass_updates(CATEGORIES_TABLE, $fields, $datas);
1016}
1017
1018/**
1019 * update images.path field
1020 *
1021 * @return void
1022 */
1023function update_path()
1024{
1025  $query = '
[1121]1026SELECT DISTINCT(storage_category_id)
1027  FROM '.IMAGES_TABLE.'
[2575]1028  WHERE storage_category_id IS NOT NULL
[809]1029;';
[1121]1030  $cat_ids = array_from_query($query, 'storage_category_id');
1031  $fulldirs = get_fulldirs($cat_ids);
[1060]1032
[1121]1033  foreach ($cat_ids as $cat_id)
[809]1034  {
1035    $query = '
1036UPDATE '.IMAGES_TABLE.'
[5691]1037  SET path = '.pwg_db_concat(array("'".$fulldirs[$cat_id]."/'",'file')).'
[1121]1038  WHERE storage_category_id = '.$cat_id.'
[809]1039;';
[808]1040    pwg_query($query);
[809]1041  }
[808]1042}
[809]1043
1044/**
[881]1045 * change the parent category of the given categories. The categories are
[809]1046 * supposed virtual.
1047 *
[881]1048 * @param array category identifiers
[809]1049 * @param int parent category identifier
1050 * @return void
1051 */
[881]1052function move_categories($category_ids, $new_parent = -1)
[809]1053{
[881]1054  global $page;
1055
1056  if (count($category_ids) == 0)
1057  {
1058    return;
1059  }
1060
1061  $new_parent = $new_parent < 1 ? 'NULL' : $new_parent;
1062
1063  $categories = array();
[1060]1064
[809]1065  $query = '
[881]1066SELECT id, id_uppercat, status, uppercats
[809]1067  FROM '.CATEGORIES_TABLE.'
[881]1068  WHERE id IN ('.implode(',', $category_ids).')
[809]1069;';
[881]1070  $result = pwg_query($query);
[4325]1071  while ($row = pwg_db_fetch_assoc($result))
[809]1072  {
[881]1073    $categories[$row['id']] =
1074      array(
1075        'parent' => empty($row['id_uppercat']) ? 'NULL' : $row['id_uppercat'],
1076        'status' => $row['status'],
1077        'uppercats' => $row['uppercats']
1078        );
[809]1079  }
[1060]1080
[881]1081  // is the movement possible? The movement is impossible if you try to move
1082  // a category in a sub-category or itself
1083  if ('NULL' != $new_parent)
1084  {
1085    $query = '
1086SELECT uppercats
1087  FROM '.CATEGORIES_TABLE.'
1088  WHERE id = '.$new_parent.'
1089;';
[4325]1090    list($new_parent_uppercats) = pwg_db_fetch_row(pwg_query($query));
[881]1091
1092    foreach ($categories as $category)
1093    {
1094      // technically, you can't move a category with uppercats 12,125,13,14
1095      // into a new parent category with uppercats 12,125,13,14,24
[8967]1096      if (preg_match('/^'.$category['uppercats'].'(,|$)/', $new_parent_uppercats))
[881]1097      {
1098        array_push(
1099          $page['errors'],
[6993]1100          l10n('You cannot move an album in its own sub album')
[881]1101          );
1102        return;
1103      }
1104    }
1105  }
[1060]1106
[881]1107  $tables =
1108    array(
1109      USER_ACCESS_TABLE => 'user_id',
1110      GROUP_ACCESS_TABLE => 'group_id'
1111      );
[1060]1112
[809]1113  $query = '
1114UPDATE '.CATEGORIES_TABLE.'
1115  SET id_uppercat = '.$new_parent.'
[881]1116  WHERE id IN ('.implode(',', $category_ids).')
[809]1117;';
1118  pwg_query($query);
1119
1120  update_uppercats();
1121  update_global_rank();
1122
1123  // status and related permissions management
1124  if ('NULL' == $new_parent)
1125  {
1126    $parent_status = 'public';
1127  }
1128  else
1129  {
1130    $query = '
1131SELECT status
1132  FROM '.CATEGORIES_TABLE.'
1133  WHERE id = '.$new_parent.'
1134;';
[4325]1135    list($parent_status) = pwg_db_fetch_row(pwg_query($query));
[809]1136  }
1137
1138  if ('private' == $parent_status)
1139  {
[881]1140    foreach ($categories as $cat_id => $category)
[809]1141    {
[881]1142      switch ($category['status'])
[809]1143      {
[881]1144        case 'public' :
1145        {
1146          set_cat_status(array($cat_id), 'private');
1147          break;
1148        }
1149        case 'private' :
1150        {
1151          $subcats = get_subcat_ids(array($cat_id));
[1060]1152
[881]1153          foreach ($tables as $table => $field)
1154          {
1155            $query = '
[809]1156SELECT '.$field.'
1157  FROM '.$table.'
[881]1158  WHERE cat_id = '.$cat_id.'
[809]1159;';
[881]1160            $category_access = array_from_query($query, $field);
[809]1161
[881]1162            $query = '
[809]1163SELECT '.$field.'
1164  FROM '.$table.'
[881]1165  WHERE cat_id = '.$new_parent.'
[809]1166;';
[881]1167            $parent_access = array_from_query($query, $field);
[1060]1168
[881]1169            $to_delete = array_diff($parent_access, $category_access);
[1060]1170
[881]1171            if (count($to_delete) > 0)
1172            {
1173              $query = '
[809]1174DELETE FROM '.$table.'
1175  WHERE '.$field.' IN ('.implode(',', $to_delete).')
[881]1176    AND cat_id IN ('.implode(',', $subcats).')
[809]1177;';
[881]1178              pwg_query($query);
1179            }
[809]1180          }
[881]1181          break;
[809]1182        }
1183      }
1184    }
1185  }
[881]1186
1187  array_push(
1188    $page['infos'],
[1932]1189    l10n_dec(
[6951]1190      '%d album moved', '%d albums moved',
[881]1191      count($categories)
1192      )
1193    );
[809]1194}
[1064]1195
1196/**
1197 * create a virtual category
1198 *
1199 * @param string category name
1200 * @param int parent category id
1201 * @return array with ('info' and 'id') or ('error') key
1202 */
[17669]1203function create_virtual_category($category_name, $parent_id=null, $options=array())
[1064]1204{
[11728]1205  global $conf, $user;
[1068]1206
[1064]1207  // is the given category name only containing blank spaces ?
1208  if (preg_match('/^\s*$/', $category_name))
1209  {
[6988]1210    return array('error' => l10n('The name of an album must not be empty'));
[1064]1211  }
[17765]1212
[1064]1213  $insert = array(
1214    'name' => $category_name,
[12763]1215    'rank' => 0,
[17669]1216    'global_rank' => 0,
[1064]1217    );
[1068]1218
[17669]1219  // is the album commentable?
1220  if (isset($options['commentable']) and is_bool($options['commentable']))
[1064]1221  {
[17669]1222    $insert['commentable'] = $options['commentable'];
1223  }
1224  else
1225  {
1226    $insert['commentable'] = $conf['newcat_default_commentable'];
1227  }
1228  $insert['commentable'] = boolean_to_string($insert['commentable']);
1229
1230  // is the album temporarily locked? (only visible by administrators,
1231  // whatever permissions) (may be overwritten if parent album is not
1232  // visible)
1233  if (isset($options['visible']) and is_bool($options['visible']))
1234  {
1235    $insert['visible'] = $options['visible'];
1236  }
1237  else
1238  {
1239    $insert['visible'] = $conf['newcat_default_visible'];
1240  }
1241  $insert['visible'] = boolean_to_string($insert['visible']);
1242
1243  // is the album private? (may be overwritten if parent album is private)
1244  if (isset($options['status']) and 'private' == $options['status'])
1245  {
1246    $insert['status'] = 'private';
1247  }
1248  else
1249  {
1250    $insert['status'] = $conf['newcat_default_status'];
1251  }
1252
1253  // any description for this album?
1254  if (isset($options['comment']))
1255  {
[21070]1256    $insert['comment'] = $conf['allow_html_descriptions'] ? $options['comment'] : strip_tags($options['comment']);
[17669]1257  }
1258
1259  if (!empty($parent_id) and is_numeric($parent_id))
1260  {
[1064]1261    $query = '
1262SELECT id, uppercats, global_rank, visible, status
1263  FROM '.CATEGORIES_TABLE.'
1264  WHERE id = '.$parent_id.'
1265;';
[4325]1266    $parent = pwg_db_fetch_assoc(pwg_query($query));
[1064]1267
[4265]1268    $insert['id_uppercat'] = $parent['id'];
1269    $insert['global_rank'] = $parent['global_rank'].'.'.$insert['rank'];
[1068]1270
[1064]1271    // at creation, must a category be visible or not ? Warning : if the
1272    // parent category is invisible, the category is automatically create
1273    // invisible. (invisible = locked)
1274    if ('false' == $parent['visible'])
1275    {
[4265]1276      $insert['visible'] = 'false';
[1064]1277    }
[1068]1278
[1064]1279    // at creation, must a category be public or private ? Warning : if the
1280    // parent category is private, the category is automatically create
1281    // private.
1282    if ('private' == $parent['status'])
1283    {
[4265]1284      $insert['status'] = 'private';
[1064]1285    }
[17669]1286
1287    $uppercats_prefix = $parent['uppercats'].',';
[1064]1288  }
1289  else
1290  {
[17669]1291    $uppercats_prefix = '';
[1064]1292  }
1293
1294  // we have then to add the virtual category
[17669]1295  single_insert(CATEGORIES_TABLE, $insert);
1296  $inserted_id = pwg_db_insert_id(CATEGORIES_TABLE);
1297
1298  single_update(
[1064]1299    CATEGORIES_TABLE,
[17669]1300    array('uppercats' => $uppercats_prefix.$inserted_id),
1301    array('id' => $inserted_id)
[1064]1302    );
1303
[12763]1304  update_global_rank();
1305
[23886]1306  if ('private' == $insert['status'] and !empty($insert['id_uppercat']) and ((isset($options['inherit']) and $options['inherit']) or $conf['inheritance_by_default']) )
[11728]1307  {
[23272]1308    $query = '
1309      SELECT group_id
1310      FROM '.GROUP_ACCESS_TABLE.'
1311      WHERE cat_id = '.$insert['id_uppercat'].'
1312    ;';
1313    $granted_grps =  array_from_query($query, 'group_id');
1314    $inserts = array();
1315    foreach ($granted_grps as $granted_grp)
1316    {
1317      array_push(
1318        $inserts,
1319        array(
1320          'group_id' => $granted_grp,
1321          'cat_id' => $inserted_id
1322          )
1323        );
1324    }
1325    mass_inserts(GROUP_ACCESS_TABLE, array('group_id','cat_id'), $inserts);
1326
1327    $query = '
1328      SELECT user_id
1329      FROM '.USER_ACCESS_TABLE.'
1330      WHERE cat_id = '.$insert['id_uppercat'].'
1331    ;';
1332    $granted_users =  array_from_query($query, 'user_id');
1333    add_permission_on_category($inserted_id, array_unique(array_merge(get_admins(), array($user['id']), $granted_users)));
1334  }
1335  else if ('private' == $insert['status'])
1336  {
[11728]1337    add_permission_on_category($inserted_id, array_unique(array_merge(get_admins(), array($user['id']))));
1338  }
1339
[1064]1340  return array(
[6969]1341    'info' => l10n('Virtual album added'),
[1064]1342    'id'   => $inserted_id,
1343    );
1344}
[1111]1345
1346/**
[1119]1347 * Set tags to an image. Warning: given tags are all tags associated to the
1348 * image, not additionnal tags.
1349 *
1350 * @param array tag ids
1351 * @param int image id
1352 * @return void
1353 */
1354function set_tags($tags, $image_id)
1355{
[17724]1356  set_tags_of( array($image_id=>$tags) );
[1119]1357}
1358
1359/**
1360 * Add new tags to a set of images.
1361 *
1362 * @param array tag ids
1363 * @param array image ids
1364 * @return void
1365 */
1366function add_tags($tags, $images)
1367{
[5691]1368  if (count($tags) == 0 or count($images) == 0)
[1119]1369  {
1370    return;
1371  }
[1592]1372
[1119]1373  // we can't insert twice the same {image_id,tag_id} so we must first
1374  // delete lines we'll insert later
1375  $query = '
1376DELETE
1377  FROM '.IMAGE_TAG_TABLE.'
1378  WHERE image_id IN ('.implode(',', $images).')
1379    AND tag_id IN ('.implode(',', $tags).')
1380;';
1381  pwg_query($query);
1382
1383  $inserts = array();
1384  foreach ($images as $image_id)
1385  {
[17724]1386    foreach ( array_unique($tags) as $tag_id)
[1119]1387    {
[17724]1388      $inserts[] = array(
[1119]1389          'image_id' => $image_id,
1390          'tag_id' => $tag_id,
1391        );
1392    }
1393  }
1394  mass_inserts(
1395    IMAGE_TAG_TABLE,
1396    array_keys($inserts[0]),
1397    $inserts
1398    );
[21817]1399  invalidate_user_cache_nb_tags();
[1119]1400}
1401
[12032]1402/**
1403 *
1404 */
1405function delete_tags($tag_ids)
1406{
1407  if (is_numeric($tag_ids))
1408  {
1409    $tag_ids = array($tag_ids);
1410  }
1411
1412  if (!is_array($tag_ids))
1413  {
1414    return false;
1415  }
[12917]1416
[12032]1417  $query = '
1418DELETE
1419  FROM '.IMAGE_TAG_TABLE.'
1420  WHERE tag_id IN ('.implode(',', $tag_ids).')
1421;';
1422  pwg_query($query);
[12917]1423
[12032]1424  $query = '
1425DELETE
1426  FROM '.TAGS_TABLE.'
1427  WHERE id IN ('.implode(',', $tag_ids).')
1428;';
1429  pwg_query($query);
[21817]1430
1431  invalidate_user_cache_nb_tags();
[12032]1432}
1433
[1119]1434function tag_id_from_tag_name($tag_name)
1435{
1436  global $page;
[2478]1437
[2350]1438  $tag_name = trim($tag_name);
[1119]1439  if (isset($page['tag_id_from_tag_name_cache'][$tag_name]))
1440  {
1441    return $page['tag_id_from_tag_name_cache'][$tag_name];
1442  }
[1592]1443
[17724]1444  // search existing by exact name
[1119]1445  $query = '
1446SELECT id
1447  FROM '.TAGS_TABLE.'
1448  WHERE name = \''.$tag_name.'\'
1449;';
[17724]1450  if (count($existing_tags = array_from_query($query, 'id')) == 0)
[1119]1451  {
[17724]1452    // search existing by case insensitive name
1453    $query = '
1454SELECT id
1455  FROM '.TAGS_TABLE.'
1456  WHERE CONVERT(name, CHAR) = \''.$tag_name.'\'
1457;';
1458    if (count($existing_tags = array_from_query($query, 'id')) == 0)
1459    {
1460      $url_name = trigger_event('render_tag_url', $tag_name);
1461      // search existing by url name
1462      $query = '
1463SELECT id
1464  FROM '.TAGS_TABLE.'
1465  WHERE url_name = \''.$url_name.'\'
1466;';
1467      if (count($existing_tags = array_from_query($query, 'id')) == 0)
1468      {
1469        mass_inserts(
1470          TAGS_TABLE,
1471          array('name', 'url_name'),
1472          array(
1473            array(
1474              'name' => $tag_name,
1475              'url_name' => $url_name,
1476              )
1477            )
1478          );
1479        $page['tag_id_from_tag_name_cache'][$tag_name] = pwg_db_insert_id(TAGS_TABLE);
1480        return $page['tag_id_from_tag_name_cache'][$tag_name];
1481      }
1482    }
[1119]1483  }
1484
[17724]1485  $page['tag_id_from_tag_name_cache'][$tag_name] = $existing_tags[0];
[1119]1486  return $page['tag_id_from_tag_name_cache'][$tag_name];
1487}
1488
1489function set_tags_of($tags_of)
1490{
1491  if (count($tags_of) > 0)
1492  {
1493    $query = '
1494DELETE
1495  FROM '.IMAGE_TAG_TABLE.'
1496  WHERE image_id IN ('.implode(',', array_keys($tags_of)).')
1497;';
1498    pwg_query($query);
1499
1500    $inserts = array();
[1592]1501
[1119]1502    foreach ($tags_of as $image_id => $tag_ids)
1503    {
[17724]1504      foreach (array_unique($tag_ids) as $tag_id)
[1119]1505      {
[17724]1506        $inserts[] = array(
[1119]1507            'image_id' => $image_id,
1508            'tag_id' => $tag_id,
1509          );
1510      }
1511    }
1512
[17765]1513    if (count($inserts))
1514    {
1515      mass_inserts(
1516        IMAGE_TAG_TABLE,
1517        array_keys($inserts[0]),
1518        $inserts
1519        );
1520    }
[21817]1521
1522    invalidate_user_cache_nb_tags();
[1119]1523  }
1524}
1525
1526/**
[1121]1527 * Associate a list of images to a list of categories.
1528 *
[17424]1529 * The function will not duplicate links and will preserve ranks
[1121]1530 *
1531 * @param array images
1532 * @param array categories
1533 * @return void
1534 */
1535function associate_images_to_categories($images, $categories)
1536{
1537  if (count($images) == 0
1538      or count($categories) == 0)
1539  {
1540    return false;
1541  }
[17765]1542
[17424]1543  // get existing associations
[1121]1544  $query = '
[17424]1545SELECT
1546    image_id,
1547    category_id
[1121]1548  FROM '.IMAGE_CATEGORY_TABLE.'
1549  WHERE image_id IN ('.implode(',', $images).')
1550    AND category_id IN ('.implode(',', $categories).')
1551;';
[17424]1552  $result = pwg_query($query);
[17765]1553
[17424]1554  $existing = array();
1555  while ($row = pwg_db_fetch_assoc($result))
1556  {
1557    $existing[ $row['category_id'] ][] = $row['image_id'];
1558  }
[1121]1559
[17424]1560  // get max rank of each categories
[17002]1561  $query = '
1562SELECT
1563    category_id,
1564    MAX(rank) AS max_rank
1565  FROM '.IMAGE_CATEGORY_TABLE.'
1566  WHERE rank IS NOT NULL
1567    AND category_id IN ('.implode(',', $categories).')
1568  GROUP BY category_id
1569;';
1570
1571  $current_rank_of = simple_hash_from_query(
1572    $query,
1573    'category_id',
1574    'max_rank'
1575    );
1576
[17424]1577  // associate only not already associated images
[1121]1578  $inserts = array();
1579  foreach ($categories as $category_id)
1580  {
[17002]1581    if (!isset($current_rank_of[$category_id]))
1582    {
1583      $current_rank_of[$category_id] = 0;
1584    }
[17424]1585    if (!isset($existing[$category_id]))
1586    {
1587      $existing[$category_id] = array();
1588    }
[17002]1589
[1121]1590    foreach ($images as $image_id)
1591    {
[17424]1592      if (!in_array($image_id, $existing[$category_id]))
1593      {
1594        $rank = ++$current_rank_of[$category_id];
[17002]1595
[17424]1596        array_push(
1597          $inserts,
1598          array(
1599            'image_id' => $image_id,
1600            'category_id' => $category_id,
1601            'rank' => $rank,
1602            )
1603          );
1604      }
[1121]1605    }
1606  }
[1592]1607
[17424]1608  if (count($inserts))
1609  {
1610    mass_inserts(
1611      IMAGE_CATEGORY_TABLE,
1612      array_keys($inserts[0]),
1613      $inserts
1614      );
[1121]1615
[17424]1616    update_category($categories);
1617  }
[1121]1618}
1619
1620/**
[17424]1621 * Dissociate images from all old categories except their storage category and
[13077]1622 * associate to new categories.
1623 *
[17424]1624 * This function will preserve ranks
1625 *
[13077]1626 * @param array images
1627 * @param array categories
1628 * @return void
1629 */
1630function move_images_to_categories($images, $categories)
1631{
1632  if (count($images) == 0)
1633  {
1634    return false;
1635  }
[17302]1636
[17424]1637  // let's first break links with all old albums but their "storage album"
[13077]1638  $query = '
1639DELETE '.IMAGE_CATEGORY_TABLE.'.*
1640  FROM '.IMAGE_CATEGORY_TABLE.'
1641    JOIN '.IMAGES_TABLE.' ON image_id=id
1642  WHERE id IN ('.implode(',', $images).')
[17980]1643';
[18628]1644
[17980]1645  if (is_array($categories) and count($categories) > 0)
1646  {
1647    $query.= '
1648    AND category_id NOT IN ('.implode(',', $categories).')
1649';
1650  }
1651
1652  $query.= '
[13077]1653    AND (storage_category_id IS NULL OR storage_category_id != category_id)
1654;';
1655  pwg_query($query);
[17302]1656
[13077]1657  if (is_array($categories) and count($categories) > 0)
1658  {
1659    associate_images_to_categories($images, $categories);
1660  }
1661}
1662
1663/**
[1121]1664 * Associate images associated to a list of source categories to a list of
1665 * destination categories.
1666 *
1667 * @param array sources
1668 * @param array destinations
1669 * @return void
1670 */
1671function associate_categories_to_categories($sources, $destinations)
1672{
1673  if (count($sources) == 0)
1674  {
1675    return false;
1676  }
1677
1678  $query = '
1679SELECT image_id
1680  FROM '.IMAGE_CATEGORY_TABLE.'
1681  WHERE category_id IN ('.implode(',', $sources).')
1682;';
1683  $images = array_from_query($query, 'image_id');
1684
1685  associate_images_to_categories($images, $destinations);
1686}
[1682]1687
1688/**
[2339]1689 * Refer main Piwigo URLs (currently PHPWG_DOMAIN domain)
[1724]1690 *
1691 * @param void
1692 * @return array like $conf['links']
1693 */
1694function pwg_URL()
1695{
1696  $urls = array(
[12875]1697    'HOME'       => PHPWG_URL,
1698    'WIKI'       => PHPWG_URL.'/doc',
1699    'DEMO'       => PHPWG_URL.'/demo',
1700    'FORUM'      => PHPWG_URL.'/forum',
1701    'BUGS'       => PHPWG_URL.'/bugs',
1702    'EXTENSIONS' => PHPWG_URL.'/ext',
[1724]1703    );
1704  return $urls;
1705}
1706
[1978]1707/**
1708 * Invalidates cahed data (permissions and category counts) for all users.
1709 */
[2890]1710function invalidate_user_cache($full = true)
[1978]1711{
[2890]1712  if ($full)
1713  {
1714    $query = '
1715TRUNCATE TABLE '.USER_CACHE_CATEGORIES_TABLE.';';
1716    pwg_query($query);
1717    $query = '
1718TRUNCATE TABLE '.USER_CACHE_TABLE.';';
1719    pwg_query($query);
1720  }
1721  else
1722  {
1723    $query = '
[1978]1724UPDATE '.USER_CACHE_TABLE.'
[2890]1725  SET need_update = \'true\';';
1726    pwg_query($query);
1727  }
[2892]1728  trigger_action('invalidate_user_cache', $full);
[1978]1729}
[2127]1730
[21817]1731
1732function invalidate_user_cache_nb_tags()
1733{
1734  global $user;
1735  unset($user['nb_available_tags']);
1736  $query = '
1737UPDATE '.USER_CACHE_TABLE.'
1738  SET nb_available_tags = NULL';
1739  pwg_query($query);
1740}
1741
[2127]1742/**
1743 * adds the caracter set to a create table sql query.
1744 * all CREATE TABLE queries must call this function
1745 * @param string query - the sql query
1746 */
1747function create_table_add_character_set($query)
1748{
[2502]1749  defined('DB_CHARSET') or fatal_error('create_table_add_character_set DB_CHARSET undefined');
[2127]1750  if ('DB_CHARSET'!='')
1751  {
[18634]1752    if ( version_compare(pwg_get_db_version(), '4.1.0', '<') )
[2127]1753    {
1754      return $query;
1755    }
1756    $charset_collate = " DEFAULT CHARACTER SET ".DB_CHARSET;
[2488]1757    if (DB_COLLATE!='')
[2127]1758    {
1759      $charset_collate .= " COLLATE ".DB_COLLATE;
1760    }
[2488]1761    if ( is_array($query) )
[2127]1762    {
[2488]1763      foreach( $query as $id=>$q)
1764      {
1765        $q=trim($q);
1766        $q=trim($q, ';');
1767        if (preg_match('/^CREATE\s+TABLE/i',$q))
1768        {
1769          $q.=$charset_collate;
1770        }
1771        $q .= ';';
1772        $query[$id] = $q;
1773      }
[2127]1774    }
[2488]1775    else
1776    {
1777      $query=trim($query);
1778      $query=trim($query, ';');
1779      if (preg_match('/^CREATE\s+TABLE/i',$query))
1780      {
1781        $query.=$charset_collate;
1782      }
1783      $query .= ';';
1784    }
[2127]1785  }
1786  return $query;
1787}
[2325]1788
1789/**
1790 * Returns array use on template with html_options method
1791 * @param Min and Max access to use
1792 * @return array of user access level
1793 */
1794function get_user_access_level_html_options($MinLevelAccess = ACCESS_FREE, $MaxLevelAccess = ACCESS_CLOSED)
1795{
1796  $tpl_options = array();
1797  for ($level = $MinLevelAccess; $level <= $MaxLevelAccess; $level++)
1798  {
1799    $tpl_options[$level] = l10n(sprintf('ACCESS_%d', $level));
1800  }
1801  return $tpl_options;
1802}
1803
[2588]1804/**
1805 * returns a list of templates currently available in template-extension
1806 * Each .tpl file is extracted from template-extension.
1807 * @return array
1808 */
1809function get_extents($start='')
1810{
1811  if ($start == '') { $start = './template-extension'; }
1812  $dir = opendir($start);
1813  $extents = array();
1814
1815  while (($file = readdir($dir)) !== false)
1816  {
1817    if ( $file == '.' or $file == '..' or $file == '.svn') continue;
1818    $path = $start . '/' . $file;
1819    if (is_dir($path))
1820    {
1821      $extents = array_merge($extents, get_extents($path));
1822    }
[3145]1823    elseif ( !is_link($path) and file_exists($path)
[2588]1824            and get_extension($path) == 'tpl' )
1825    {
1826      $extents[] = substr($path, 21);
1827    }
1828  }
1829  return $extents;
1830}
1831
[2634]1832function create_tag($tag_name)
1833{
1834  // does the tag already exists?
1835  $query = '
1836SELECT id
1837  FROM '.TAGS_TABLE.'
1838  WHERE name = \''.$tag_name.'\'
1839;';
1840  $existing_tags = array_from_query($query, 'id');
1841
1842  if (count($existing_tags) == 0)
1843  {
1844    mass_inserts(
1845      TAGS_TABLE,
1846      array('name', 'url_name'),
1847      array(
1848        array(
1849          'name' => $tag_name,
[12553]1850          'url_name' => trigger_event('render_tag_url', $tag_name),
[2634]1851          )
1852        )
1853      );
1854
[4892]1855    $inserted_id = pwg_db_insert_id(TAGS_TABLE);
[2634]1856
1857    return array(
1858      'info' => sprintf(
[5036]1859        l10n('Tag "%s" was added'),
[2634]1860        stripslashes($tag_name)
1861        ),
1862      'id' => $inserted_id,
1863      );
1864  }
1865  else
1866  {
1867    return array(
1868      'error' => sprintf(
[5036]1869        l10n('Tag "%s" already exists'),
[2634]1870        stripslashes($tag_name)
1871        )
1872      );
1873  }
1874}
[2777]1875
[11828]1876/**
1877 * Is the category accessible to the (Admin) user ?
1878 *
1879 * Note : if the user is not authorized to see this category, category jump
1880 * will be replaced by admin cat_modify page
1881 *
1882 * @param int category id to verify
1883 * @return bool
1884 */
1885function cat_admin_access($category_id)
1886{
1887  global $user;
[2777]1888
[11828]1889  // $filter['visible_categories'] and $filter['visible_images']
1890  // are not used because it's not necessary (filter <> restriction)
1891  if (in_array($category_id, explode(',', $user['forbidden_categories'])))
1892  {
1893    return false;
1894  }
1895  return true;
1896}
1897
[2880]1898/**
1899 * Retrieve data from external URL
1900 *
1901 * @param string $src: URL
1902 * @param global $dest: can be a file ressource or string
1903 * @return bool
1904 */
[8079]1905function fetchRemote($src, &$dest, $get_data=array(), $post_data=array(), $user_agent='Piwigo', $step=0)
[2880]1906{
[2902]1907  // Try to retrieve data from local file?
1908  if (!url_is_remote($src))
1909  {
1910    $content = @file_get_contents($src);
1911    if ($content !== false)
1912    {
1913      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1914      return true;
1915    }
1916    else
1917    {
1918      return false;
1919    }
1920  }
1921
[8079]1922  // After 3 redirections, return false
1923  if ($step > 3) return false;
1924
[8080]1925  // Initialization
1926  $method  = empty($post_data) ? 'GET' : 'POST';
1927  $request = empty($post_data) ? '' : http_build_query($post_data, '', '&');
[8090]1928  if (!empty($get_data))
1929  {
1930    $src .= strpos($src, '?') === false ? '?' : '&';
1931    $src .= http_build_query($get_data, '', '&');
1932  }
[8080]1933
[2900]1934  // Initialize $dest
[2880]1935  is_resource($dest) or $dest = '';
1936
1937  // Try curl to read remote file
1938  if (function_exists('curl_init'))
1939  {
1940    $ch = @curl_init();
1941    @curl_setopt($ch, CURLOPT_URL, $src);
[2900]1942    @curl_setopt($ch, CURLOPT_HEADER, 1);
[2880]1943    @curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
[2900]1944    @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
[8079]1945    if ($method == 'POST')
1946    {
1947      @curl_setopt($ch, CURLOPT_POST, 1);
[8090]1948      @curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
[8079]1949    }
[2880]1950    $content = @curl_exec($ch);
[2900]1951    $header_length = @curl_getinfo($ch, CURLINFO_HEADER_SIZE);
[2902]1952    $status = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
[2880]1953    @curl_close($ch);
[2902]1954    if ($content !== false and $status >= 200 and $status < 400)
[2880]1955    {
[2900]1956      if (preg_match('/Location:\s+?(.+)/', substr($content, 0, $header_length), $m))
1957      {
[8079]1958        return fetchRemote($m[1], $dest, array(), array(), $user_agent, $step+1);
[2900]1959      }
1960      $content = substr($content, $header_length);
1961      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
[2880]1962      return true;
1963    }
1964  }
1965
1966  // Try file_get_contents to read remote file
1967  if (ini_get('allow_url_fopen'))
1968  {
[8079]1969    $opts = array(
1970      'http' => array(
1971        'method' => $method,
1972        'user_agent' => $user_agent,
1973      )
1974    );
[8090]1975    if ($method == 'POST')
1976    {
1977      $opts['http']['content'] = $request;
1978    }
[8079]1979    $context = @stream_context_create($opts);
1980    $content = @file_get_contents($src, false, $context);
[2880]1981    if ($content !== false)
1982    {
1983      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
1984      return true;
1985    }
1986  }
1987
1988  // Try fsockopen to read remote file
1989  $src = parse_url($src);
1990  $host = $src['host'];
1991  $path = isset($src['path']) ? $src['path'] : '/';
1992  $path .= isset($src['query']) ? '?'.$src['query'] : '';
[3145]1993
[2880]1994  if (($s = @fsockopen($host,80,$errno,$errstr,5)) === false)
1995  {
1996    return false;
1997  }
1998
[8079]1999  $http_request  = $method." ".$path." HTTP/1.0\r\n";
2000  $http_request .= "Host: ".$host."\r\n";
[8090]2001  if ($method == 'POST')
2002  {
2003    $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
2004    $http_request .= "Content-Length: ".strlen($request)."\r\n";
2005  }
[8079]2006  $http_request .= "User-Agent: ".$user_agent."\r\n";
2007  $http_request .= "Accept: */*\r\n";
2008  $http_request .= "\r\n";
2009  $http_request .= $request;
[2880]2010
[8079]2011  fwrite($s, $http_request);
2012
[2880]2013  $i = 0;
2014  $in_content = false;
2015  while (!feof($s))
2016  {
2017    $line = fgets($s);
2018
2019    if (rtrim($line,"\r\n") == '' && !$in_content)
2020    {
2021      $in_content = true;
2022      $i++;
2023      continue;
2024    }
2025    if ($i == 0)
2026    {
2027      if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/',rtrim($line,"\r\n"), $m))
2028      {
2029        fclose($s);
2030        return false;
2031      }
2032      $status = (integer) $m[2];
2033      if ($status < 200 || $status >= 400)
2034      {
2035        fclose($s);
2036        return false;
2037      }
2038    }
2039    if (!$in_content)
2040    {
2041      if (preg_match('/Location:\s+?(.+)$/',rtrim($line,"\r\n"),$m))
2042      {
2043        fclose($s);
[8079]2044        return fetchRemote(trim($m[1]),$dest,array(),array(),$user_agent,$step+1);
[2880]2045      }
2046      $i++;
2047      continue;
2048    }
2049    is_resource($dest) ? @fwrite($dest, $line) : $dest .= $line;
2050    $i++;
2051  }
2052  fclose($s);
2053  return true;
2054}
2055
[3145]2056
2057/**
2058 * returns the groupname corresponding to the given group identifier if
2059 * exists
2060 *
2061 * @param int group_id
2062 * @return mixed
2063 */
2064function get_groupname($group_id)
2065{
2066  $query = '
2067SELECT name
2068  FROM '.GROUPS_TABLE.'
2069  WHERE id = '.intval($group_id).'
2070;';
2071  $result = pwg_query($query);
[4325]2072  if (pwg_db_num_rows($result) > 0)
[3145]2073  {
[4325]2074    list($groupname) = pwg_db_fetch_row($result);
[3145]2075  }
2076  else
2077  {
2078    return false;
2079  }
2080
2081  return $groupname;
2082}
2083
2084/**
2085 * returns the username corresponding to the given user identifier if exists
2086 *
2087 * @param int user_id
2088 * @return mixed
2089 */
2090function get_username($user_id)
2091{
2092  global $conf;
2093
2094  $query = '
2095SELECT '.$conf['user_fields']['username'].'
2096  FROM '.USERS_TABLE.'
2097  WHERE '.$conf['user_fields']['id'].' = '.intval($user_id).'
2098;';
2099  $result = pwg_query($query);
[4325]2100  if (pwg_db_num_rows($result) > 0)
[3145]2101  {
[4325]2102    list($username) = pwg_db_fetch_row($result);
[3145]2103  }
2104  else
2105  {
2106    return false;
2107  }
2108
[4304]2109  return stripslashes($username);
[3145]2110}
[3382]2111
2112function get_newsletter_subscribe_base_url($language) {
[12875]2113  return PHPWG_URL.'/announcement/subscribe/';
[3382]2114}
[5173]2115
2116/**
2117 * Accordion menus need to know which section to open by default when
2118 * loading the page
2119 */
2120function get_active_menu($menu_page)
2121{
2122  global $page;
2123
2124  if (isset($page['active_menu']))
2125  {
2126    return $page['active_menu'];
2127  }
2128
2129  switch ($menu_page)
2130  {
[13077]2131    case 'photo':
[5173]2132    case 'photos_add':
2133    case 'rating':
2134    case 'tags':
[8417]2135    case 'batch_manager':
[5173]2136      return 0;
2137
[13013]2138    case 'album':
[5173]2139    case 'cat_list':
2140    case 'cat_move':
2141    case 'cat_options':
2142    case 'permalinks':
2143      return 1;
[5691]2144
[5173]2145    case 'user_list':
2146    case 'user_perm':
2147    case 'group_list':
2148    case 'group_perm':
2149    case 'notification_by_mail':
2150      return 2;
2151
[10594]2152    case 'plugins':
[5173]2153    case 'plugin':
2154      return 3;
[5691]2155
[6056]2156    case 'site_manager':
2157    case 'site_update':
[5173]2158    case 'stats':
2159    case 'history':
2160    case 'maintenance':
[5997]2161    case 'comments':
[10511]2162    case 'updates':
[5173]2163      return 4;
2164
2165    case 'configuration':
[12820]2166    case 'derivatives':
[5173]2167    case 'extend_for_templates':
2168    case 'menubar':
[10594]2169    case 'themes':
[5448]2170    case 'theme':
[10594]2171    case 'languages':
[5173]2172      return 5;
2173  }
2174  return 0;
2175}
[5188]2176
[20805]2177/*
2178 * get tags list from SQL query (ids are surrounded by ~~, for get_tag_ids())
2179 * @param string: query
2180 * @param boolean: only_user_language, if true, only local name is returned for multilingual tags
2181 */
[12259]2182function get_taglist($query, $only_user_language=true)
[5188]2183{
2184  $result = pwg_query($query);
[12917]2185
[5188]2186  $taglist = array();
[17765]2187  $altlist = array();
[5188]2188  while ($row = pwg_db_fetch_assoc($result))
2189  {
[17765]2190    $raw_name = $row['name'];
2191    $name = trigger_event('render_tag_name', $raw_name);
2192
2193    $taglist[] =  array(
2194        'name' => $name,
2195        'id' => '~~'.$row['id'].'~~',
2196      );
2197
2198    if (!$only_user_language)
[11487]2199    {
[17765]2200      $alt_names = trigger_event('get_tag_alt_names', array(), $raw_name);
2201
2202      foreach( array_diff( array_unique($alt_names), array($name) ) as $alt)
2203      {
2204        $altlist[] =  array(
2205            'name' => $alt,
[11853]2206            'id' => '~~'.$row['id'].'~~',
[11487]2207          );
2208      }
2209    }
[17765]2210  }
[12917]2211
[17765]2212  usort($taglist, 'tag_alpha_compare');
2213  if (count($altlist))
2214  {
2215    usort($altlist, 'tag_alpha_compare');
2216    $taglist = array_merge($taglist, $altlist);
[5188]2217  }
[12917]2218
[5188]2219  return $taglist;
2220}
2221
[20805]2222/*
2223 * get tags ids from a list of raw tags (existing tags or new tags)
2224 * @param mixed: raw_tags, array or comma separated string
2225 * @param boolean: allow_create
2226 */
[11853]2227function get_tag_ids($raw_tags, $allow_create=true)
[5188]2228{
2229  // In $raw_tags we receive something like array('~~6~~', '~~59~~', 'New
2230  // tag', 'Another new tag') The ~~34~~ means that it is an existing
2231  // tag. I've added the surrounding ~~ to permit creation of tags like "10"
2232  // or "1234" (numeric characters only)
2233
2234  $tag_ids = array();
[20805]2235  if (!is_array($raw_tags))
2236  {
2237    $raw_tags = explode(',',$raw_tags);
2238  }
[5691]2239
[5188]2240  foreach ($raw_tags as $raw_tag)
2241  {
2242    if (preg_match('/^~~(\d+)~~$/', $raw_tag, $matches))
2243    {
[17724]2244      $tag_ids[] = $matches[1];
[5188]2245    }
[11853]2246    elseif ($allow_create)
[5188]2247    {
2248      // we have to create a new tag
[11853]2249      $tag_ids[] = tag_id_from_tag_name($raw_tag);
[5188]2250    }
2251  }
2252
2253  return $tag_ids;
2254}
[8247]2255
2256/** returns the argument_ids array with new sequenced keys based on related
2257 * names. Sequence is not case sensitive.
2258 * Warning: By definition, this function breaks original keys
2259 */
2260function order_by_name($element_ids,$name)
2261{
2262  $ordered_element_ids = array();
2263  foreach ($element_ids as $k_id => $element_id)
2264  {
2265    $key = strtolower($name[$element_id]) .'-'. $name[$element_id] .'-'. $k_id;
2266    $ordered_element_ids[$key] = $element_id;
2267  }
2268  ksort($ordered_element_ids);
2269  return $ordered_element_ids;
2270}
2271
[11728]2272function add_permission_on_category($category_ids, $user_ids)
2273{
2274  // array-ify categories and users
2275  if (!is_array($category_ids))
2276  {
2277    $category_ids = array($category_ids);
2278  }
2279
2280  if (!is_array($user_ids))
2281  {
2282    $user_ids = array($user_ids);
2283  }
2284
2285  // check for emptiness
2286  if (count($category_ids) == 0 or count($user_ids) == 0)
2287  {
2288    return;
2289  }
[12917]2290
[12019]2291  // make sure categories are private and select uppercats or subcats
2292  $cat_ids = (isset($_POST['apply_on_sub'])) ? implode(',', get_subcat_ids($category_ids)).",".implode(',', get_uppercat_ids($category_ids)) : implode(',', get_uppercat_ids($category_ids));
[11728]2293  $query = '
2294SELECT
2295    id
2296  FROM '.CATEGORIES_TABLE.'
[12019]2297  WHERE id IN ('.$cat_ids.')
[11728]2298    AND status = \'private\'
2299;';
[12019]2300  $private_cats = array_from_query($query, 'id');
[11728]2301
[12019]2302  if (count($private_cats) == 0)
[11728]2303  {
2304    return;
2305  }
[12917]2306
[11728]2307  // We must not reinsert already existing lines in user_access table
2308  $granteds = array();
[12019]2309  foreach ($private_cats as $cat_id)
[11728]2310  {
2311    $granteds[$cat_id] = array();
2312  }
[12917]2313
[11728]2314  $query = '
2315SELECT
2316    user_id,
2317    cat_id
2318  FROM '.USER_ACCESS_TABLE.'
[12019]2319  WHERE cat_id IN ('.implode(',', $private_cats).')
[11728]2320    AND user_id IN ('.implode(',', $user_ids).')
2321;';
2322  $result = pwg_query($query);
2323  while ($row = pwg_db_fetch_assoc($result))
2324  {
2325    array_push($granteds[$row['cat_id']], $row['user_id']);
2326  }
2327
2328  $inserts = array();
[12917]2329
[12019]2330  foreach ($private_cats as $cat_id)
[11728]2331  {
2332    $grant_to_users = array_diff($user_ids, $granteds[$cat_id]);
[12917]2333
[11728]2334    foreach ($grant_to_users as $user_id)
2335    {
2336      array_push(
2337        $inserts,
2338        array(
2339          'user_id' => $user_id,
2340          'cat_id' => $cat_id
2341          )
2342        );
2343    }
2344  }
2345
2346  if (count($inserts) > 0)
2347  {
2348    mass_inserts(USER_ACCESS_TABLE, array_keys($inserts[0]), $inserts);
2349  }
2350}
2351
2352
2353function get_admins($include_webmaster=true)
2354{
2355  $status_list = array('admin');
2356
2357  if ($include_webmaster)
2358  {
2359    $status_list[] = 'webmaster';
2360  }
[12917]2361
[11728]2362  $query = '
2363SELECT
2364    user_id
2365  FROM '.USER_INFOS_TABLE.'
2366  WHERE status in (\''.implode("','", $status_list).'\')
2367;';
2368
2369  return array_from_query($query, 'user_id');
2370}
[12797]2371
[12820]2372/** delete all derivative files for one or several types */
2373function clear_derivative_cache($types='all')
[12797]2374{
[17302]2375  if ($types === 'all')
[12797]2376  {
[12820]2377    $types = ImageStdParams::get_all_types();
2378    $types[] = IMG_CUSTOM;
2379  }
2380  elseif (!is_array($types))
2381  {
2382    $types = array($types);
2383  }
2384
[17302]2385  for ($i=0; $i<count($types); $i++)
[12820]2386  {
[17302]2387    $type = $types[$i];
2388    if ($type == IMG_CUSTOM)
[12797]2389    {
[17302]2390      $type = derivative_to_url($type).'[a-zA-Z0-9]+';
[12797]2391    }
[17302]2392    elseif (in_array($type, ImageStdParams::get_all_types()))
2393    {
2394      $type = derivative_to_url($type);
2395    }
2396    else
2397    {//assume a custom type
2398      $type = derivative_to_url(IMG_CUSTOM).'_'.$type;
2399    }
2400    $types[$i] = $type;
[12797]2401  }
[17302]2402
2403  $pattern='#.*-';
2404  if (count($types)>1)
2405  {
2406    $pattern .= '(' . implode('|',$types) . ')';
2407  }
[12797]2408  else
2409  {
[17302]2410    $pattern .= $types[0];
[12797]2411  }
[17302]2412  $pattern.='\.[a-zA-Z0-9]{3,4}$#';
[12917]2413
[13651]2414  if ($contents = @opendir(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR))
[12797]2415  {
2416    while (($node = readdir($contents)) !== false)
2417    {
2418      if ($node != '.'
2419          and $node != '..'
2420          and is_dir(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR.$node))
2421      {
2422        clear_derivative_cache_rec(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR.$node, $pattern);
2423      }
2424    }
2425    closedir($contents);
2426  }
2427}
2428
2429function clear_derivative_cache_rec($path, $pattern)
2430{
2431  $rmdir = true;
2432  $rm_index = false;
2433
2434  if ($contents = opendir($path))
2435  {
2436    while (($node = readdir($contents)) !== false)
2437    {
2438      if ($node == '.' or $node == '..')
2439        continue;
2440      if (is_dir($path.'/'.$node))
2441      {
2442        $rmdir &= clear_derivative_cache_rec($path.'/'.$node, $pattern);
2443      }
2444      else
2445      {
2446        if (preg_match($pattern, $node))
2447        {
2448          unlink($path.'/'.$node);
2449        }
2450        elseif ($node=='index.htm')
2451        {
2452          $rm_index = true;
2453        }
2454        else
2455        {
2456          $rmdir = false;
2457        }
2458      }
2459    }
2460    closedir($contents);
[12917]2461
[12797]2462    if ($rmdir)
2463    {
2464      if ($rm_index)
2465      {
2466        unlink($path.'/index.htm');
2467      }
2468      clearstatcache();
[12820]2469      @rmdir($path);
[12797]2470    }
2471    return $rmdir;
2472  }
2473}
[12906]2474
[13052]2475function delete_element_derivatives($infos, $type='all')
[12906]2476{
[12917]2477  $path = $infos['path'];
2478  if (!empty($infos['representative_ext']))
[12906]2479  {
[12917]2480    $path = original_to_representative( $path, $infos['representative_ext']);
[12906]2481  }
[12917]2482  if (substr_compare($path, '../', 0, 3)==0)
2483  {
2484    $path = substr($path, 3);
2485  }
[13052]2486  $dot = strrpos($path, '.');
2487  if ($type=='all')
2488  {
2489    $pattern = '-*';
2490  }
2491  else
2492  {
2493    $pattern = '-'.derivative_to_url($type).'*';
2494  }
2495  $path = substr_replace($path, $pattern, $dot, 0);
[16167]2496  if ( ($glob=glob(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR.$path)) !== false)
[12917]2497  {
[16167]2498    foreach( $glob as $file)
2499    {
2500      @unlink($file);
2501    }
[12917]2502  }
[12906]2503}
[21567]2504
2505/**
2506 * returns an array contening sub-directories, excluding ".svn"
2507 *
2508 * @param string $dir
2509 * @return array
2510 */
2511function get_dirs($directory)
2512{
2513  $sub_dirs = array();
2514  if ($opendir = opendir($directory))
2515  {
2516    while ($file = readdir($opendir))
2517    {
2518      if ($file != '.'
2519          and $file != '..'
2520          and is_dir($directory.'/'.$file)
2521          and $file != '.svn')
2522      {
2523        array_push($sub_dirs, $file);
2524      }
2525    }
2526    closedir($opendir);
2527  }
2528  return $sub_dirs;
2529}
[23821]2530
2531/**
2532 * recursively delete a directory
2533 * @param string $path
2534 * @param string $trash_path, try to move the directory to this path if it cannot be delete
2535 */
2536function deltree($path, $trash_path=null)
2537{
2538  if (is_dir($path))
2539  {
2540    $fh = opendir($path);
2541    while ($file = readdir($fh))
2542    {
2543      if ($file != '.' and $file != '..')
2544      {
2545        $pathfile = $path . '/' . $file;
2546        if (is_dir($pathfile))
2547        {
2548          deltree($pathfile, $trash_path);
2549        }
2550        else
2551        {
2552          @unlink($pathfile);
2553        }
2554      }
2555    }
2556    closedir($fh);
2557   
2558    if (@rmdir($path))
2559    {
2560      return true;
2561    }
2562    elseif (!empty($trash_path))
2563    {
2564      if (!is_dir($trash_path))
2565      {
2566        @mkgetdir($trash_path, MKGETDIR_RECURSIVE|MKGETDIR_DIE_ON_ERROR|MKGETDIR_PROTECT_HTACCESS);
2567      }
2568      while ($r = $trash_path . '/' . md5(uniqid(rand(), true)))
2569      {
2570        if (!is_dir($r))
2571        {
2572          @rename($path, $r);
2573          break;
2574        }
2575      }
2576    }
2577    else
2578    {
2579      return false;
2580    }
2581  }
2582}
2583
[8247]2584?>
Note: See TracBrowser for help on using the repository browser.