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

Last change on this file since 12553 was 12553, checked in by patdenice, 12 years ago

feature:2322
feature:2493
Add a trigger for multi language tags in quick search and url

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