Index: trunk/admin/include/functions.php
===================================================================
--- trunk/admin/include/functions.php	(revision 26649)
+++ trunk/admin/include/functions.php	(revision 26807)
@@ -22,9 +22,17 @@
 // +-----------------------------------------------------------------------+
 
-include(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
-
-// The function delete_site deletes a site and call the function
-// delete_categories for each primary category of the site
-function delete_site( $id )
+/**
+ * @package functions\admin\___
+ */
+
+include_once(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
+
+
+/**
+ * Deletes a site and call delete_categories for each primary category of the site
+ *
+ * @param int $id
+ */
+function delete_site($id)
 {
   // destruction of the categories of the site
@@ -45,16 +53,17 @@
 }
 
-
-// The function delete_categories deletes the categories identified by the
-// (numeric) key of the array $ids. It also deletes (in the database) :
-//    - all the elements physically linked to the category (delete_elements, see further)
-//    - all the links between elements and this category
-//    - all the restrictions linked to the category
-// The function works recursively.
-//
-// the $photo_deletion_mode is for photos virtually linked to the categorty
-//   * no_delete : delete no photo, may create orphans
-//   * delete_orphans : delete photos that are no longer linked to any category
-//   * force_delete : delete photos even if they are linked to another category
+/**
+ * Recursively deletes one or more categories.
+ * It also deletes :
+ *    - all the elements physically linked to the category (with delete_elements)
+ *    - all the links between elements and this category
+ *    - all the restrictions linked to the category
+ *
+ * @param int[] $ids
+ * @param string $photo_deletion_mode
+ *    - no_delete : delete no photo, may create orphans
+ *    - delete_orphans : delete photos that are no longer linked to any category
+ *    - force_delete : delete photos even if they are linked to another category
+ */
 function delete_categories($ids, $photo_deletion_mode='no_delete')
 {
@@ -157,6 +166,10 @@
 }
 
-// Deletes all files (on disk) related to given image ids
-// @return image ids where files are deleted successfully
+/**
+ * Deletes all files (on disk) related to given image ids.
+ *
+ * @param int[] $ids
+ * @return 0|int[] image ids where files were successfully deleted
+ */
 function delete_element_files($ids)
 {
@@ -220,10 +233,16 @@
 }
 
-// The function delete_elements deletes the elements identified by the
-// (numeric) values of the array $ids. It also deletes (in the database) :
-//    - all the comments related to elements
-//    - all the links between categories and elements
-//    - all the favorites associated to elements
-// @return number of deleted elements
+/**
+ * Deletes elements from database.
+ * It also deletes :
+ *    - all the comments related to elements
+ *    - all the links between categories/tags and elements
+ *    - all the favorites/rates associated to elements
+ *    - removes elements from caddie
+ *
+ * @param int[] $ids
+ * @param bool $physical_deletion
+ * @return int number of deleted elements
+ */
 function delete_elements($ids, $physical_deletion=false)
 {
@@ -242,18 +261,18 @@
     }
   }
+  
+  $ids_str = wordwrap(implode(', ', $ids), 80, "\n");
 
   // destruction of the comments on the image
   $query = '
 DELETE FROM '.COMMENTS_TABLE.'
-  WHERE image_id IN (
-'.wordwrap(implode(', ', $ids), 80, "\n").')
+  WHERE image_id IN ('. $ids_str .')
 ;';
   pwg_query($query);
 
-  // destruction of the links between images and this category
+  // destruction of the links between images and categories
   $query = '
 DELETE FROM '.IMAGE_CATEGORY_TABLE.'
-  WHERE image_id IN (
-'.wordwrap(implode(', ', $ids), 80, "\n").')
+  WHERE image_id IN ('. $ids_str .')
 ;';
   pwg_query($query);
@@ -262,6 +281,5 @@
   $query = '
 DELETE FROM '.IMAGE_TAG_TABLE.'
-  WHERE image_id IN (
-'.wordwrap(implode(', ', $ids), 80, "\n").')
+  WHERE image_id IN ('. $ids_str .')
 ;';
   pwg_query($query);
@@ -270,6 +288,5 @@
   $query = '
 DELETE FROM '.FAVORITES_TABLE.'
-  WHERE image_id IN (
-'.wordwrap(implode(', ', $ids), 80, "\n").')
+  WHERE image_id IN ('. $ids_str .')
 ;';
   pwg_query($query);
@@ -278,14 +295,12 @@
   $query = '
 DELETE FROM '.RATE_TABLE.'
-  WHERE element_id IN (
-'.wordwrap(implode(', ', $ids), 80, "\n").')
+  WHERE element_id IN ('. $ids_str .')
 ;';
   pwg_query($query);
 
-  // destruction of the rates associated to this element
+  // destruction of the caddie associated to this element
   $query = '
 DELETE FROM '.CADDIE_TABLE.'
-  WHERE element_id IN (
-'.wordwrap(implode(', ', $ids), 80, "\n").')
+  WHERE element_id IN ('. $ids_str .')
 ;';
   pwg_query($query);
@@ -294,6 +309,5 @@
   $query = '
 DELETE FROM '.IMAGES_TABLE.'
-  WHERE id IN (
-'.wordwrap(implode(', ', $ids), 80, "\n").')
+  WHERE id IN ('. $ids_str .')
 ;';
   pwg_query($query);
@@ -304,6 +318,5 @@
     id
   FROM '.CATEGORIES_TABLE.'
-  WHERE representative_picture_id IN (
-'.wordwrap(implode(', ', $ids), 80, "\n").')
+  WHERE representative_picture_id IN ('. $ids_str .')
 ;';
   $category_ids = array_from_query($query, 'id');
@@ -317,11 +330,11 @@
 }
 
-// The delete_user function delete a user identified by the $user_id
-// It also deletes :
-//     - all the access linked to this user
-//     - all the links to any group
-//     - all the favorites linked to this user
-//     - calculated permissions linked to the user
-//     - all datas about notifications for the user
+/**
+ * Deletes an user.
+ * It also deletes all related data (accesses, favorites, permissions, etc.)
+ * @todo : accept array input
+ *
+ * @param int $user_id
+ */
 function delete_user($user_id)
 {
@@ -357,5 +370,5 @@
   }
 
-  // destruction of the user
+  // purge of sessions
   $query = '
 DELETE FROM '.SESSIONS_TABLE.'
@@ -416,8 +429,7 @@
 /**
  * Verifies that the representative picture really exists in the db and
- * picks up a random represantive if possible and based on config.
- *
- * @param mixed category id
- * @returns void
+ * picks up a random representative if possible and based on config.
+ *
+ * @param 'all'|int|int[] $ids
  */
 function update_category($ids = 'all')
@@ -486,7 +498,6 @@
 
 /**
- * check and repair images integrity
- *
- * TODO see delete_elements function to check all linked tables
+ * Checks and repairs IMAGE_CATEGORY_TABLE integrity.
+ * Removes all entries from the table which correspond to a deleted image.
  */
 function images_integrity()
@@ -514,16 +525,16 @@
 
 /**
- * returns an array containing sub-directories which can be a category,
- * recursive by default
- *
- * directories nammed "thumbnail", "pwg_high" or "pwg_representative" are
- * omitted
- *
- * @param string $basedir
- * @return array
+ * Returns an array containing sub-directories which are potentially
+ * a category.
+ * Directories named ".svn", "thumbnail", "pwg_high" or "pwg_representative"
+ * are omitted.
+ *
+ * @param string $basedir (eg: ./galleries)
+ * @return string[]
  */
 function get_fs_directories($path, $recursive = true)
 {
   $dirs = array();
+  $path = rtrim($path, '/');
 
   if (is_dir($path))
@@ -556,7 +567,6 @@
 
 /**
- * order categories (update categories.rank and global_rank database fields)
- * so that rank field are consecutive integers starting at 1 for each child
- * @return void
+ * Orders categories (update categories.rank and global_rank database fields)
+ * so that rank field are consecutive integers starting at 1 for each child.
  */
 function update_global_rank()
@@ -624,13 +634,12 @@
 
 /**
- * change the visible property on a set of categories
- *
- * @param array categories
- * @param string value
- * @return void
+ * Change the **visible** property on a set of categories.
+ *
+ * @param int[] $categories
+ * @param boolean|string $value
  */
 function set_cat_visible($categories, $value)
 {
-  if (!in_array($value, array('true', 'false')))
+  if ( ($value = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) === null )
   {
     trigger_error("set_cat_visible invalid param $value", E_USER_WARNING);
@@ -639,5 +648,5 @@
 
   // unlocking a category => all its parent categories become unlocked
-  if ($value == 'true')
+  if ($value)
   {
     $uppercats = get_uppercat_ids($categories);
@@ -649,5 +658,5 @@
   }
   // locking a category   => all its child categories become locked
-  if ($value == 'false')
+  else
   {
     $subcats = get_subcat_ids($categories);
@@ -661,9 +670,8 @@
 
 /**
- * change the status property on a set of categories : private or public
- *
- * @param array categories
- * @param string value
- * @return void
+ * Change the **status** property on a set of categories : private or public.
+ *
+ * @param int[] $categories
+ * @param string $value
  */
 function set_cat_status($categories, $value)
@@ -699,8 +707,8 @@
 
 /**
- * returns all uppercats category ids of the given category ids
- *
- * @param array cat_ids
- * @return array
+ * Returns all uppercats category ids of the given category ids.
+ *
+ * @param int[] $cat_ids
+ * @return int[]
  */
 function get_uppercat_ids($cat_ids)
@@ -730,7 +738,7 @@
 
 /**
- * set a new random representant to the categories
- *
- * @param array categories
+ * Set a new random representant to the categories.
+ *
+ * @param int[] $categories
  */
 function set_random_representant($categories)
@@ -765,8 +773,8 @@
 
 /**
- * returns the fulldir for each given category id
- *
- * @param array cat_ids
- * @return array
+ * Returns the fulldir for each given category id.
+ *
+ * @param int[] intcat_ids
+ * @return string[]
  */
 function get_fulldirs($cat_ids)
@@ -817,9 +825,8 @@
 
 /**
- * returns an array with all file system files according to
- * $conf['file_ext']
+ * Returns an array with all file system files according to $conf['file_ext']
  *
  * @param string $path
- * @param bool recursive
+ * @param bool $recursive
  * @return array
  */
@@ -903,12 +910,10 @@
 
 /**
- * synchronize base users list and related users list
- *
- * compares and synchronizes base users table (USERS_TABLE) with its child
+ * Synchronize base users list and related users list.
+ *
+ * Compares and synchronizes base users table (USERS_TABLE) with its child
  * tables (USER_INFOS_TABLE, USER_ACCESS, USER_CACHE, USER_GROUP) : each
  * base user must be present in child tables, users in child tables not
  * present in base table must be deleted.
- *
- * @return void
  */
 function sync_users()
@@ -972,8 +977,5 @@
 
 /**
- * updates categories.uppercats field based on categories.id +
- * categories.id_uppercat
- *
- * @return void
+ * Updates categories.uppercats field based on categories.id + categories.id_uppercat
  */
 function update_uppercats()
@@ -1011,7 +1013,5 @@
 
 /**
- * update images.path field
- *
- * @return void
+ * Update images.path field base on images.file and storage categories fulldirs.
  */
 function update_path()
@@ -1037,10 +1037,9 @@
 
 /**
- * change the parent category of the given categories. The categories are
+ * Change the parent category of the given categories. The categories are
  * supposed virtual.
  *
- * @param array category identifiers
- * @param int parent category identifier
- * @return void
+ * @param int[] $category_ids
+ * @param int $new_parent (-1 for root)
  */
 function move_categories($category_ids, $new_parent = -1)
@@ -1096,9 +1095,8 @@
   }
 
-  $tables =
-    array(
-      USER_ACCESS_TABLE => 'user_id',
-      GROUP_ACCESS_TABLE => 'group_id'
-      );
+  $tables = array(
+    USER_ACCESS_TABLE => 'user_id',
+    GROUP_ACCESS_TABLE => 'group_id'
+    );
 
   $query = '
@@ -1176,9 +1174,15 @@
 
 /**
- * create a virtual category
- *
- * @param string category name
- * @param int parent category id
- * @return array with ('info' and 'id') or ('error') key
+ * Create a virtual category.
+ *
+ * @param string $category_name
+ * @param int $parent_id
+ * @param array $options
+ *    - boolean commentable
+ *    - boolean visible
+ *    - string status
+ *    - string comment
+ *    - boolean inherit
+ * @return array ('info', 'id') or ('error')
  */
 function create_virtual_category($category_name, $parent_id=null, $options=array())
@@ -1323,10 +1327,9 @@
 
 /**
- * Set tags to an image. Warning: given tags are all tags associated to the
- * image, not additionnal tags.
- *
- * @param array tag ids
- * @param int image id
- * @return void
+ * Set tags to an image.
+ * Warning: given tags are all tags associated to the image, not additionnal tags.
+ *
+ * @param int[] $tags
+ * @param int $image_id
  */
 function set_tags($tags, $image_id)
@@ -1338,7 +1341,6 @@
  * Add new tags to a set of images.
  *
- * @param array tag ids
- * @param array image ids
- * @return void
+ * @param int[] $tags
+ * @param int[] $images
  */
 function add_tags($tags, $images)
@@ -1379,5 +1381,7 @@
 
 /**
- *
+ * Delete tags and tags associations.
+ *
+ * @param int[] $tag_ids
  */
 function delete_tags($tag_ids)
@@ -1410,5 +1414,11 @@
 }
 
-function tag_id_from_tag_name($tag_name)
+/**
+ * Returns a tag id from its name. If nothing found, create a new tag.
+ *
+ * @param string $tag_name
+ * @return int
+ */
+function tag_id_from_tag_name($tag_name, $create=true)
 {
   global $page;
@@ -1455,4 +1465,7 @@
             )
           );
+
+        invalidate_user_cache_nb_tags();
+
         $page['tag_id_from_tag_name_cache'][$tag_name] = pwg_db_insert_id(TAGS_TABLE);
         return $page['tag_id_from_tag_name_cache'][$tag_name];
@@ -1465,4 +1478,9 @@
 }
 
+/**
+ * Set tags of images. Overwrites all existing associations.
+ *
+ * @param array $tags_of - keys are image ids, values are array of tag ids
+ */
 function set_tags_of($tags_of)
 {
@@ -1504,10 +1522,8 @@
 /**
  * Associate a list of images to a list of categories.
- *
- * The function will not duplicate links and will preserve ranks
- *
- * @param array images
- * @param array categories
- * @return void
+ * The function will not duplicate links and will preserve ranks.
+ *
+ * @param int[] $images
+ * @param int[] $categories
  */
 function associate_images_to_categories($images, $categories)
@@ -1596,10 +1612,8 @@
  * Dissociate images from all old categories except their storage category and
  * associate to new categories.
- *
- * This function will preserve ranks
- *
- * @param array images
- * @param array categories
- * @return void
+ * This function will preserve ranks.
+ *
+ * @param int[] $images
+ * @param int[] $categories
  */
 function move_images_to_categories($images, $categories)
@@ -1640,7 +1654,6 @@
  * destination categories.
  *
- * @param array sources
- * @param array destinations
- * @return void
+ * @param int[] $sources
+ * @param int[] $destinations
  */
 function associate_categories_to_categories($sources, $destinations)
@@ -1664,6 +1677,5 @@
  * Refer main Piwigo URLs (currently PHPWG_DOMAIN domain)
  *
- * @param void
- * @return array like $conf['links']
+ * @return string[]
  */
 function pwg_URL()
@@ -1681,5 +1693,5 @@
 
 /**
- * Invalidates cahed data (permissions and category counts) for all users.
+ * Invalidates cached data (permissions and category counts) for all users.
  */
 function invalidate_user_cache($full = true)
@@ -1704,9 +1716,12 @@
 }
 
-
+/**
+ * Invalidates cached tags counter for all users.
+ */
 function invalidate_user_cache_nb_tags()
 {
   global $user;
   unset($user['nb_available_tags']);
+
   $query = '
 UPDATE '.USER_CACHE_TABLE.'
@@ -1716,7 +1731,9 @@
 
 /**
- * adds the caracter set to a create table sql query.
- * all CREATE TABLE queries must call this function
- * @param string query - the sql query
+ * Adds the caracter set to a create table sql query.
+ * All CREATE TABLE queries must call this function
+ *
+ * @param string $query
+ * @return string
  */
 function create_table_add_character_set($query)
@@ -1763,7 +1780,9 @@
 
 /**
- * Returns array use on template with html_options method
- * @param Min and Max access to use
- * @return array of user access level
+ * Returns access levels as array used on template with html_options functions.
+ *
+ * @param int $MinLevelAccess
+ * @param int $MaxLevelAccess
+ * @return array
  */
 function get_user_access_level_html_options($MinLevelAccess = ACCESS_FREE, $MaxLevelAccess = ACCESS_CLOSED)
@@ -1778,7 +1797,9 @@
 
 /**
- * returns a list of templates currently available in template-extension
+ * returns a list of templates currently available in template-extension.
  * Each .tpl file is extracted from template-extension.
- * @return array
+ *
+ * @param string $start (internal use)
+ * @return string[]
  */
 function get_extents($start='')
@@ -1805,4 +1826,10 @@
 }
 
+/**
+ * Create a new tag.
+ *
+ * @param string $tag_name
+ * @return array ('id', info') or ('error')
+ */
 function create_tag($tag_name)
 {
@@ -1842,9 +1869,8 @@
 /**
  * Is the category accessible to the (Admin) user ?
- *
  * Note : if the user is not authorized to see this category, category jump
  * will be replaced by admin cat_modify page
  *
- * @param int category id to verify
+ * @param int $category_id
  * @return bool
  */
@@ -1863,8 +1889,12 @@
 
 /**
- * Retrieve data from external URL
- *
- * @param string $src: URL
- * @param global $dest: can be a file ressource or string
+ * Retrieve data from external URL.
+ *
+ * @param string $src
+ * @param string|Ressource $dest - can be a file ressource or string
+ * @param array $get_data - data added to request url
+ * @param array $post_data - data transmitted with POST
+ * @param string $user_agent
+ * @param int $step (internal use)
  * @return bool
  */
@@ -2020,11 +2050,9 @@
 }
 
-
-/**
- * returns the groupname corresponding to the given group identifier if
- * exists
- *
- * @param int group_id
- * @return mixed
+/**
+ * Returns the groupname corresponding to the given group identifier if exists.
+ *
+ * @param int $group_id
+ * @return string|false
  */
 function get_groupname($group_id)
@@ -2049,8 +2077,8 @@
 
 /**
- * returns the username corresponding to the given user identifier if exists
- *
- * @param int user_id
- * @return mixed
+ * Returns the username corresponding to the given user identifier if exists.
+ *
+ * @param int $user_id
+ * @return string|false
  */
 function get_username($user_id)
@@ -2076,11 +2104,20 @@
 }
 
-function get_newsletter_subscribe_base_url($language) {
+/**
+ * Get url on piwigo.org for newsletter subscription
+ *
+ * @param string $language (unused)
+ * @return string
+ */
+function get_newsletter_subscribe_base_url($language='en_UK')
+{
   return PHPWG_URL.'/announcement/subscribe/';
 }
 
 /**
- * Accordion menus need to know which section to open by default when
- * loading the page
+ * Return admin menu id for accordion.
+ *
+ * @param string $menu_page
+ * @return int
  */
 function get_active_menu($menu_page)
@@ -2137,12 +2174,17 @@
     case 'languages':
       return 5;
-  }
-  return 0;
-}
-
-/*
- * get tags list from SQL query (ids are surrounded by ~~, for get_tag_ids())
- * @param string: query
- * @param boolean: only_user_language, if true, only local name is returned for multilingual tags
+
+    default:
+      return 0;
+  }
+}
+
+/**
+ * Get tags list from SQL query (ids are surrounded by ~~, for get_tag_ids()).
+ *
+ * @param string $query
+ * @param boolean $only_user_language - if true, only local name is returned for
+ *    multilingual tags (if ExtendedDescription plugin is active)
+ * @return array[] ('id', 'name')
  */
 function get_taglist($query, $only_user_language=true)
@@ -2186,16 +2228,18 @@
 }
 
-/*
- * get tags ids from a list of raw tags (existing tags or new tags)
- * @param mixed: raw_tags, array or comma separated string
- * @param boolean: allow_create
+/**
+ * Get tags ids from a list of raw tags (existing tags or new tags).
+ *
+ * In $raw_tags we receive something like array('~~6~~', '~~59~~', 'New
+ * tag', 'Another new tag') The ~~34~~ means that it is an existing
+ * tag. We added the surrounding ~~ to permit creation of tags like "10"
+ * or "1234" (numeric characters only)
+ *
+ * @param string|string[] $raw_tags - array or comma separated string
+ * @param boolean $allow_create
+ * @return int[]
  */
 function get_tag_ids($raw_tags, $allow_create=true)
 {
-  // In $raw_tags we receive something like array('~~6~~', '~~59~~', 'New
-  // tag', 'Another new tag') The ~~34~~ means that it is an existing
-  // tag. I've added the surrounding ~~ to permit creation of tags like "10"
-  // or "1234" (numeric characters only)
-
   $tag_ids = array();
   if (!is_array($raw_tags))
@@ -2220,9 +2264,14 @@
 }
 
-/** returns the argument_ids array with new sequenced keys based on related
+/**
+ * Returns the argument_ids array with new sequenced keys based on related
  * names. Sequence is not case sensitive.
- * Warning: By definition, this function breaks original keys
- */
-function order_by_name($element_ids,$name)
+ * Warning: By definition, this function breaks original keys.
+ *
+ * @param int[] $elements_ids
+ * @param string[] $name - names of elements, indexed by ids
+ * @return int[]
+ */
+function order_by_name($element_ids, $name)
 {
   $ordered_element_ids = array();
@@ -2236,12 +2285,16 @@
 }
 
+/**
+ * Grant access to a list of categories for a list of users.
+ *
+ * @param int[] $category_ids
+ * @param int[] $user_ids
+ */
 function add_permission_on_category($category_ids, $user_ids)
 {
-  // array-ify categories and users
   if (!is_array($category_ids))
   {
     $category_ids = array($category_ids);
   }
-
   if (!is_array($user_ids))
   {
@@ -2295,5 +2348,10 @@
 }
 
-
+/**
+ * Returns the list of admin users.
+ *
+ * @param boolean $include_webmaster
+ * @return int[]
+ */
 function get_admins($include_webmaster=true)
 {
@@ -2315,5 +2373,9 @@
 }
 
-/** delete all derivative files for one or several types */
+/**
+ * Delete all derivative files for one or several types
+ *
+ * @param 'all'|int[] $types
+ */
 function clear_derivative_cache($types='all')
 {
@@ -2372,4 +2434,8 @@
 }
 
+/**
+ * Used by clear_derivative_cache()
+ * @ignore
+ */
 function clear_derivative_cache_rec($path, $pattern)
 {
@@ -2418,4 +2484,10 @@
 }
 
+/**
+ * Deletes derivatives of a particular element
+ *
+ * @param array $infos ('path'[, 'representative_ext'])
+ * @param 'all'|int $type
+ */
 function delete_element_derivatives($infos, $type='all')
 {
@@ -2449,8 +2521,8 @@
 
 /**
- * returns an array contening sub-directories, excluding ".svn"
- *
- * @param string $dir
- * @return array
+ * Returns an array containing sub-directories, excluding ".svn"
+ *
+ * @param string $directory
+ * @return string[]
  */
 function get_dirs($directory)
@@ -2475,5 +2547,6 @@
 
 /**
- * recursively delete a directory
+ * Recursively delete a directory.
+ *
  * @param string $path
  * @param string $trash_path, try to move the directory to this path if it cannot be delete
