aboutsummaryrefslogtreecommitdiffstats
path: root/include/ws_functions
diff options
context:
space:
mode:
Diffstat (limited to 'include/ws_functions')
-rw-r--r--include/ws_functions/index.php30
-rw-r--r--include/ws_functions/pwg.categories.php838
-rw-r--r--include/ws_functions/pwg.extensions.php343
-rw-r--r--include/ws_functions/pwg.groups.php284
-rw-r--r--include/ws_functions/pwg.images.php1582
-rw-r--r--include/ws_functions/pwg.permissions.php235
-rw-r--r--include/ws_functions/pwg.php338
-rw-r--r--include/ws_functions/pwg.tags.php244
-rw-r--r--include/ws_functions/pwg.users.php446
9 files changed, 4340 insertions, 0 deletions
diff --git a/include/ws_functions/index.php b/include/ws_functions/index.php
new file mode 100644
index 000000000..41732f2fd
--- /dev/null
+++ b/include/ws_functions/index.php
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2013 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
diff --git a/include/ws_functions/pwg.categories.php b/include/ws_functions/pwg.categories.php
new file mode 100644
index 000000000..70a555398
--- /dev/null
+++ b/include/ws_functions/pwg.categories.php
@@ -0,0 +1,838 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2013 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+/**
+ * API method
+ * Returns images per category
+ * @param mixed[] $params
+ * @option int[] cat_id (optional)
+ * @option bool recursive
+ * @option int per_page
+ * @option int page
+ * @option string order (optional)
+ */
+function ws_categories_getImages($params, &$service)
+{
+ global $user, $conf;
+
+ $images = array();
+
+ //------------------------------------------------- get the related categories
+ $where_clauses = array();
+ foreach ($params['cat_id'] as $cat_id)
+ {
+ if ($params['recursive'])
+ {
+ $where_clauses[] = 'uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.$cat_id.'(,|$)\'';
+ }
+ else
+ {
+ $where_clauses[] = 'id='.$cat_id;
+ }
+ }
+ if (!empty($where_clauses))
+ {
+ $where_clauses = array('('. implode("\n OR ", $where_clauses) . ')');
+ }
+ $where_clauses[] = get_sql_condition_FandF(
+ array('forbidden_categories' => 'id'),
+ null, true
+ );
+
+ $query = '
+SELECT id, name, permalink, image_order
+ FROM '. CATEGORIES_TABLE .'
+ WHERE '. implode("\n AND ", $where_clauses) .'
+;';
+ $result = pwg_query($query);
+
+ $cats = array();
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $row['id'] = (int)$row['id'];
+ $cats[ $row['id'] ] = $row;
+ }
+
+ //-------------------------------------------------------- get the images
+ if (!empty($cats))
+ {
+ $where_clauses = ws_std_image_sql_filter($params, 'i.');
+ $where_clauses[] = 'category_id IN ('. implode(',', array_keys($cats)) .')';
+ $where_clauses[] = get_sql_condition_FandF(
+ array('visible_images' => 'i.id'),
+ null, true
+ );
+
+ $order_by = ws_std_image_sql_order($params, 'i.');
+ if ( empty($order_by)
+ and count($params['cat_id'])==1
+ and isset($cats[ $params['cat_id'][0] ]['image_order'])
+ )
+ {
+ $order_by = $cats[ $params['cat_id'][0] ]['image_order'];
+ }
+ $order_by = empty($order_by) ? $conf['order_by'] : 'ORDER BY '.$order_by;
+
+ $query = '
+SELECT i.*, GROUP_CONCAT(category_id) AS cat_ids
+ FROM '. IMAGES_TABLE .' i
+ INNER JOIN '. IMAGE_CATEGORY_TABLE .' ON i.id=image_id
+ WHERE '. implode("\n AND ", $where_clauses) .'
+ GROUP BY i.id
+ '. $order_by .'
+ LIMIT '. $params['per_page'] .'
+ OFFSET '. ($params['per_page']*$params['page']) .'
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $image = array();
+ foreach (array('id', 'width', 'height', 'hit') as $k)
+ {
+ if (isset($row[$k]))
+ {
+ $image[$k] = (int)$row[$k];
+ }
+ }
+ foreach (array('file', 'name', 'comment', 'date_creation', 'date_available') as $k)
+ {
+ $image[$k] = $row[$k];
+ }
+ $image = array_merge($image, ws_std_get_urls($row));
+
+ $image_cats = array();
+ foreach (explode(',', $row['cat_ids']) as $cat_id)
+ {
+ $url = make_index_url(
+ array(
+ 'category' => $cats[$cat_id],
+ )
+ );
+ $page_url = make_picture_url(
+ array(
+ 'category' => $cats[$cat_id],
+ 'image_id' => $row['id'],
+ 'image_file' => $row['file'],
+ )
+ );
+ $image_cats[] = array(
+ 'id' => (int)$cat_id,
+ 'url' => $url,
+ 'page_url' => $page_url,
+ );
+ }
+
+ $image['categories'] = new PwgNamedArray(
+ $image_cats,
+ 'category',
+ array('id', 'url', 'page_url')
+ );
+ $images[] = $image;
+ }
+ }
+
+ return array(
+ 'paging' => new PwgNamedStruct(
+ array(
+ 'page' => $params['page'],
+ 'per_page' => $params['per_page'],
+ 'count' => count($images)
+ )
+ ),
+ 'images' => new PwgNamedArray(
+ $images, 'image',
+ ws_std_get_image_xml_attributes()
+ )
+ );
+}
+
+/**
+ * API method
+ * Returns a list of categories
+ * @param mixed[] $params
+ * @option int cat_id (optional)
+ * @option bool recursive
+ * @option bool public
+ * @option bool tree_output
+ * @option bool fullname
+ */
+function ws_categories_getList($params, &$service)
+{
+ global $user, $conf;
+
+ $where = array('1=1');
+ $join_type = 'INNER';
+ $join_user = $user['id'];
+
+ if (!$params['recursive'])
+ {
+ if ($params['cat_id']>0)
+ {
+ $where[] = '(
+ id_uppercat = '. (int)($params['cat_id']) .'
+ OR id='.(int)($params['cat_id']).'
+ )';
+ }
+ else
+ {
+ $where[] = 'id_uppercat IS NULL';
+ }
+ }
+ else if ($params['cat_id']>0)
+ {
+ $where[] = 'uppercats '. DB_REGEX_OPERATOR .' \'(^|,)'.
+ (int)($params['cat_id']) .'(,|$)\'';
+ }
+
+ if ($params['public'])
+ {
+ $where[] = 'status = "public"';
+ $where[] = 'visible = "true"';
+
+ $join_user = $conf['guest_id'];
+ }
+ else if (is_admin())
+ {
+ // in this very specific case, we don't want to hide empty
+ // categories. Function calculate_permissions will only return
+ // categories that are either locked or private and not permitted
+ //
+ // calculate_permissions does not consider empty categories as forbidden
+ $forbidden_categories = calculate_permissions($user['id'], $user['status']);
+ $where[]= 'id NOT IN ('.$forbidden_categories.')';
+ $join_type = 'LEFT';
+ }
+
+ $query = '
+SELECT
+ id, name, comment, permalink,
+ uppercats, global_rank, id_uppercat,
+ nb_images, count_images AS total_nb_images,
+ representative_picture_id, user_representative_picture_id, count_images, count_categories,
+ date_last, max_date_last, count_categories AS nb_categories
+ FROM '. CATEGORIES_TABLE .'
+ '.$join_type.' JOIN '. USER_CACHE_CATEGORIES_TABLE .'
+ ON id=cat_id AND user_id='.$join_user.'
+ WHERE '. implode("\n AND ", $where) .'
+;';
+ $result = pwg_query($query);
+
+ // management of the album thumbnail -- starts here
+ $image_ids = array();
+ $categories = array();
+ $user_representative_updates_for = array();
+ // management of the album thumbnail -- stops here
+
+ $cats = array();
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $row['url'] = make_index_url(
+ array(
+ 'category' => $row
+ )
+ );
+ foreach (array('id','nb_images','total_nb_images','nb_categories') as $key)
+ {
+ $row[$key] = (int)$row[$key];
+ }
+
+ if ($params['fullname'])
+ {
+ $row['name'] = strip_tags(get_cat_display_name_cache($row['uppercats'], null, false));
+ }
+ else
+ {
+ $row['name'] = strip_tags(
+ trigger_event(
+ 'render_category_name',
+ $row['name'],
+ 'ws_categories_getList'
+ )
+ );
+ }
+
+ $row['comment'] = strip_tags(
+ trigger_event(
+ 'render_category_description',
+ $row['comment'],
+ 'ws_categories_getList'
+ )
+ );
+
+ // management of the album thumbnail -- starts here
+ //
+ // on branch 2.3, the algorithm is duplicated from
+ // include/category_cats, but we should use a common code for Piwigo 2.4
+ //
+ // warning : if the API method is called with $params['public'], the
+ // album thumbnail may be not accurate. The thumbnail can be viewed by
+ // the connected user, but maybe not by the guest. Changing the
+ // filtering method would be too complicated for now. We will simply
+ // avoid to persist the user_representative_picture_id in the database
+ // if $params['public']
+ if (!empty($row['user_representative_picture_id']))
+ {
+ $image_id = $row['user_representative_picture_id'];
+ }
+ else if (!empty($row['representative_picture_id']))
+ { // if a representative picture is set, it has priority
+ $image_id = $row['representative_picture_id'];
+ }
+ else if ($conf['allow_random_representative'])
+ {
+ // searching a random representant among elements in sub-categories
+ $image_id = get_random_image_in_category($row);
+ }
+ else
+ { // searching a random representant among representant of sub-categories
+ if ($row['count_categories']>0 and $row['count_images']>0)
+ {
+ $query = '
+SELECT representative_picture_id
+ FROM '. CATEGORIES_TABLE .'
+ INNER JOIN '. USER_CACHE_CATEGORIES_TABLE .'
+ ON id=cat_id AND user_id='.$user['id'].'
+ WHERE uppercats LIKE \''.$row['uppercats'].',%\'
+ AND representative_picture_id IS NOT NULL
+ '.get_sql_condition_FandF(
+ array('visible_categories' => 'id'),
+ "\n AND"
+ ).'
+ ORDER BY '. DB_RANDOM_FUNCTION .'()
+ LIMIT 1
+;';
+ $subresult = pwg_query($query);
+
+ if (pwg_db_num_rows($subresult) > 0)
+ {
+ list($image_id) = pwg_db_fetch_row($subresult);
+ }
+ }
+ }
+
+ if (isset($image_id))
+ {
+ if ($conf['representative_cache_on_subcats'] and $row['user_representative_picture_id'] != $image_id)
+ {
+ $user_representative_updates_for[ $row['id'] ] = $image_id;
+ }
+
+ $row['representative_picture_id'] = $image_id;
+ $image_ids[] = $image_id;
+ $categories[] = $row;
+ }
+ unset($image_id);
+ // management of the album thumbnail -- stops here
+
+ $cats[] = $row;
+ }
+ usort($cats, 'global_rank_compare');
+
+ // management of the album thumbnail -- starts here
+ if (count($categories) > 0)
+ {
+ $thumbnail_src_of = array();
+ $new_image_ids = array();
+
+ $query = '
+SELECT id, path, representative_ext, level
+ FROM '. IMAGES_TABLE .'
+ WHERE id IN ('. implode(',', $image_ids) .')
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ if ($row['level'] <= $user['level'])
+ {
+ $thumbnail_src_of[$row['id']] = DerivativeImage::thumb_url($row);
+ }
+ else
+ {
+ // problem: we must not display the thumbnail of a photo which has a
+ // higher privacy level than user privacy level
+ //
+ // * what is the represented category?
+ // * find a random photo matching user permissions
+ // * register it at user_representative_picture_id
+ // * set it as the representative_picture_id for the category
+ foreach ($categories as &$category)
+ {
+ if ($row['id'] == $category['representative_picture_id'])
+ {
+ // searching a random representant among elements in sub-categories
+ $image_id = get_random_image_in_category($category);
+
+ if (isset($image_id) and !in_array($image_id, $image_ids))
+ {
+ $new_image_ids[] = $image_id;
+ }
+ if ($conf['representative_cache_on_level'])
+ {
+ $user_representative_updates_for[ $category['id'] ] = $image_id;
+ }
+
+ $category['representative_picture_id'] = $image_id;
+ }
+ }
+ unset($category);
+ }
+ }
+
+ if (count($new_image_ids) > 0)
+ {
+ $query = '
+SELECT id, path, representative_ext
+ FROM '. IMAGES_TABLE .'
+ WHERE id IN ('. implode(',', $new_image_ids) .')
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $thumbnail_src_of[ $row['id'] ] = DerivativeImage::thumb_url($row);
+ }
+ }
+ }
+
+ // compared to code in include/category_cats, we only persist the new
+ // user_representative if we have used $user['id'] and not the guest id,
+ // or else the real guest may see thumbnail that he should not
+ if (!$params['public'] and count($user_representative_updates_for))
+ {
+ $updates = array();
+
+ foreach ($user_representative_updates_for as $cat_id => $image_id)
+ {
+ $updates[] = array(
+ 'user_id' => $user['id'],
+ 'cat_id' => $cat_id,
+ 'user_representative_picture_id' => $image_id,
+ );
+ }
+
+ mass_updates(
+ USER_CACHE_CATEGORIES_TABLE,
+ array(
+ 'primary' => array('user_id', 'cat_id'),
+ 'update' => array('user_representative_picture_id')
+ ),
+ $updates
+ );
+ }
+
+ foreach ($cats as &$cat)
+ {
+ foreach ($categories as $category)
+ {
+ if ($category['id'] == $cat['id'] and isset($category['representative_picture_id']))
+ {
+ $cat['tn_url'] = $thumbnail_src_of[$category['representative_picture_id']];
+ }
+ }
+ // we don't want them in the output
+ unset($cat['user_representative_picture_id'], $cat['count_images'], $cat['count_categories']);
+ }
+ unset($cat);
+ // management of the album thumbnail -- stops here
+
+ if ($params['tree_output'])
+ {
+ $cats = categories_flatlist_to_tree($cats);
+ }
+
+ return array(
+ 'categories' => new PwgNamedArray(
+ $cats,
+ 'category',
+ ws_std_get_category_xml_attributes()
+ )
+ );
+}
+
+/**
+ * API method
+ * Returns the list of categories as you can see them in administration
+ * @param mixed[] $params
+ *
+ * Only admin can run this method and permissions are not taken into
+ * account.
+ */
+function ws_categories_getAdminList($params, &$service)
+{
+ $query = '
+SELECT category_id, COUNT(*) AS counter
+ FROM '. IMAGE_CATEGORY_TABLE .'
+ GROUP BY category_id
+;';
+ $nb_images_of = simple_hash_from_query($query, 'category_id', 'counter');
+
+ $query = '
+SELECT id, name, comment, uppercats, global_rank
+ FROM '. CATEGORIES_TABLE .'
+;';
+ $result = pwg_query($query);
+
+ $cats = array();
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $id = $row['id'];
+ $row['nb_images'] = isset($nb_images_of[$id]) ? $nb_images_of[$id] : 0;
+
+ $row['name'] = strip_tags(
+ trigger_event(
+ 'render_category_name',
+ $row['name'],
+ 'ws_categories_getAdminList'
+ )
+ );
+ $row['comment'] = strip_tags(
+ trigger_event(
+ 'render_category_description',
+ $row['comment'],
+ 'ws_categories_getAdminList'
+ )
+ );
+
+ $cats[] = $row;
+ }
+
+ usort($cats, 'global_rank_compare');
+ return array(
+ 'categories' => new PwgNamedArray(
+ $cats,
+ 'category',
+ array('id', 'nb_images', 'name', 'uppercats', 'global_rank')
+ )
+ );
+}
+
+/**
+ * API method
+ * Adds a category
+ * @param mixed[] $params
+ * @option string name
+ * @option int parent (optional)
+ * @option string comment (optional)
+ * @option bool visible
+ * @option string status (optional)
+ * @option bool commentable
+ */
+function ws_categories_add($params, &$service)
+{
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ $options = array();
+ if (!empty($params['status']) and in_array($params['status'], array('private','public')))
+ {
+ $options['status'] = $params['status'];
+ }
+
+ if (!empty($params['comment']))
+ {
+ $options['comment'] = $params['comment'];
+ }
+
+ $creation_output = create_virtual_category(
+ $params['name'],
+ $params['parent'],
+ $options
+ );
+
+ if (isset($creation_output['error']))
+ {
+ return new PwgError(500, $creation_output['error']);
+ }
+
+ invalidate_user_cache();
+
+ return $creation_output;
+}
+
+/**
+ * API method
+ * Sets details of a category
+ * @param mixed[] $params
+ * @option int cat_id
+ * @option string name (optional)
+ * @option string comment (optional)
+ */
+function ws_categories_setInfo($params, &$service)
+{
+ $update = array(
+ 'id' => $params['category_id'],
+ );
+
+ $info_columns = array('name', 'comment',);
+
+ $perform_update = false;
+ foreach ($info_columns as $key)
+ {
+ if (isset($params[$key]))
+ {
+ $perform_update = true;
+ $update[$key] = $params[$key];
+ }
+ }
+
+ if ($perform_update)
+ {
+ single_update(
+ CATEGORIES_TABLE,
+ $update,
+ array('id' => $update['id'])
+ );
+ }
+}
+
+/**
+ * API method
+ * Sets representative image of a category
+ * @param mixed[] $params
+ * @option int category_id
+ * @option int image_id
+ */
+function ws_categories_setRepresentative($params, &$service)
+{
+ // does the category really exist?
+ $query = '
+SELECT COUNT(*)
+ FROM '. CATEGORIES_TABLE .'
+ WHERE id = '. $params['category_id'] .'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(404, 'category_id not found');
+ }
+
+ // does the image really exist?
+ $query = '
+SELECT COUNT(*)
+ FROM '. IMAGES_TABLE .'
+ WHERE id = '. $params['image_id'] .'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(404, 'image_id not found');
+ }
+
+ // apply change
+ $query = '
+UPDATE '. CATEGORIES_TABLE .'
+ SET representative_picture_id = '. $params['image_id'] .'
+ WHERE id = '. $params['category_id'] .'
+;';
+ pwg_query($query);
+
+ $query = '
+UPDATE '. USER_CACHE_CATEGORIES_TABLE .'
+ SET user_representative_picture_id = NULL
+ WHERE cat_id = '. $params['category_id'] .'
+;';
+ pwg_query($query);
+}
+
+/**
+ * API method
+ * Deletes a category
+ * @param mixed[] $params
+ * @option string|int[] category_id
+ * @option string photo_deletion_mode
+ * @option string pwg_token
+ */
+function ws_categories_delete($params, &$service)
+{
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ $modes = array('no_delete', 'delete_orphans', 'force_delete');
+ if (!in_array($params['photo_deletion_mode'], $modes))
+ {
+ return new PwgError(500,
+ '[ws_categories_delete]'
+ .' invalid parameter photo_deletion_mode "'.$params['photo_deletion_mode'].'"'
+ .', possible values are {'.implode(', ', $modes).'}.'
+ );
+ }
+
+ if (!is_array($params['category_id']))
+ {
+ $params['category_id'] = preg_split(
+ '/[\s,;\|]/',
+ $params['category_id'],
+ -1,
+ PREG_SPLIT_NO_EMPTY
+ );
+ }
+ $params['category_id'] = array_map('intval', $params['category_id']);
+
+ $category_ids = array();
+ foreach ($params['category_id'] as $category_id)
+ {
+ if ($category_id > 0)
+ {
+ $category_ids[] = $category_id;
+ }
+ }
+
+ if (count($category_ids) == 0)
+ {
+ return;
+ }
+
+ $query = '
+SELECT id
+ FROM '. CATEGORIES_TABLE .'
+ WHERE id IN ('. implode(',', $category_ids) .')
+;';
+ $category_ids = array_from_query($query, 'id');
+
+ if (count($category_ids) == 0)
+ {
+ return;
+ }
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ delete_categories($category_ids, $params['photo_deletion_mode']);
+ update_global_rank();
+}
+
+/**
+ * API method
+ * Moves a category
+ * @param mixed[] $params
+ * @option string|int[] category_id
+ * @option int parent
+ * @option string pwg_token
+ */
+function ws_categories_move($params, &$service)
+{
+ global $page;
+
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ if (!is_array($params['category_id']))
+ {
+ $params['category_id'] = preg_split(
+ '/[\s,;\|]/',
+ $params['category_id'],
+ -1,
+ PREG_SPLIT_NO_EMPTY
+ );
+ }
+ $params['category_id'] = array_map('intval', $params['category_id']);
+
+ $category_ids = array();
+ foreach ($params['category_id'] as $category_id)
+ {
+ if ($category_id > 0)
+ {
+ $category_ids[] = $category_id;
+ }
+ }
+
+ if (count($category_ids) == 0)
+ {
+ return new PwgError(403, 'Invalid category_id input parameter, no category to move');
+ }
+
+ // we can't move physical categories
+ $categories_in_db = array();
+
+ $query = '
+SELECT id, name, dir
+ FROM '. CATEGORIES_TABLE .'
+ WHERE id IN ('. implode(',', $category_ids) .')
+;';
+ $result = pwg_query($query);
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $categories_in_db[ $row['id'] ] = $row;
+
+ // we break on error at first physical category detected
+ if (!empty($row['dir']))
+ {
+ $row['name'] = strip_tags(
+ trigger_event(
+ 'render_category_name',
+ $row['name'],
+ 'ws_categories_move'
+ )
+ );
+
+ return new PwgError(403,
+ sprintf(
+ 'Category %s (%u) is not a virtual category, you cannot move it',
+ $row['name'],
+ $row['id']
+ )
+ );
+ }
+ }
+
+ if (count($categories_in_db) != count($category_ids))
+ {
+ $unknown_category_ids = array_diff($category_ids, array_keys($categories_in_db));
+
+ return new PwgError(403,
+ sprintf(
+ 'Category %u does not exist',
+ $unknown_category_ids[0]
+ )
+ );
+ }
+
+ // does this parent exists? This check should be made in the
+ // move_categories function, not here
+ // 0 as parent means "move categories at gallery root"
+ if (0 != $params['parent'])
+ {
+ $subcat_ids = get_subcat_ids(array($params['parent']));
+ if (count($subcat_ids) == 0)
+ {
+ return new PwgError(403, 'Unknown parent category id');
+ }
+ }
+
+ $page['infos'] = array();
+ $page['errors'] = array();
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ move_categories($category_ids, $params['parent']);
+ invalidate_user_cache();
+
+ if (count($page['errors']) != 0)
+ {
+ return new PwgError(403, implode('; ', $page['errors']));
+ }
+}
+
+?> \ No newline at end of file
diff --git a/include/ws_functions/pwg.extensions.php b/include/ws_functions/pwg.extensions.php
new file mode 100644
index 000000000..3eb8f092d
--- /dev/null
+++ b/include/ws_functions/pwg.extensions.php
@@ -0,0 +1,343 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2013 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+/**
+ * API method
+ * Returns the list of all plugins
+ * @param mixed[] $params
+ */
+function ws_plugins_getList($params, &$service)
+{
+ include_once(PHPWG_ROOT_PATH.'admin/include/plugins.class.php');
+
+ $plugins = new plugins();
+ $plugins->sort_fs_plugins('name');
+ $plugin_list = array();
+
+ foreach ($plugins->fs_plugins as $plugin_id => $fs_plugin)
+ {
+ if (isset($plugins->db_plugins_by_id[$plugin_id]))
+ {
+ $state = $plugins->db_plugins_by_id[$plugin_id]['state'];
+ }
+ else
+ {
+ $state = 'uninstalled';
+ }
+
+ $plugin_list[] = array(
+ 'id' => $plugin_id,
+ 'name' => $fs_plugin['name'],
+ 'version' => $fs_plugin['version'],
+ 'state' => $state,
+ 'description' => $fs_plugin['description'],
+ );
+ }
+
+ return $plugin_list;
+}
+
+/**
+ * API method
+ * Performs an action on a plugin
+ * @param mixed[] $params
+ * @option string action
+ * @option string plugin
+ * @option string pwg_token
+ */
+function ws_plugins_performAction($params, &$service)
+{
+ global $template;
+
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ define('IN_ADMIN', true);
+ include_once(PHPWG_ROOT_PATH.'admin/include/plugins.class.php');
+
+ $plugins = new plugins();
+ $errors = $plugins->perform_action($params['action'], $params['plugin']);
+
+ if (!empty($errors))
+ {
+ return new PwgError(500, $errors);
+ }
+ else
+ {
+ if (in_array($params['action'], array('activate', 'deactivate')))
+ {
+ $template->delete_compiled_templates();
+ }
+ return true;
+ }
+}
+
+/**
+ * API method
+ * Performs an action on a theme
+ * @param mixed[] $params
+ * @option string action
+ * @option string theme
+ * @option string pwg_token
+ */
+function ws_themes_performAction($params, &$service)
+{
+ global $template;
+
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ define('IN_ADMIN', true);
+ include_once(PHPWG_ROOT_PATH.'admin/include/themes.class.php');
+
+ $themes = new themes();
+ $errors = $themes->perform_action($params['action'], $params['theme']);
+
+ if (!empty($errors))
+ {
+ return new PwgError(500, $errors);
+ }
+ else
+ {
+ if (in_array($params['action'], array('activate', 'deactivate')))
+ {
+ $template->delete_compiled_templates();
+ }
+ return true;
+ }
+}
+
+/**
+ * API method
+ * Updates an extension
+ * @param mixed[] $params
+ * @option string type
+ * @option string id
+ * @option string revision
+ * @option string pwg_token
+ * @option bool reactivate (optional - undocumented)
+ */
+function ws_extensions_update($params, &$service)
+{
+ if (!is_webmaster())
+ {
+ return new PwgError(401, l10n('Webmaster status is required.'));
+ }
+
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ if (!in_array($params['type'], array('plugins', 'themes', 'languages')))
+ {
+ return new PwgError(403, "invalid extension type");
+ }
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ include_once(PHPWG_ROOT_PATH.'admin/include/'.$params['type'].'.class.php');
+
+ $type = $params['type'];
+ $extension_id = $params['id'];
+ $revision = $params['revision'];
+
+ $extension = new $type();
+
+ if ($type == 'plugins')
+ {
+ if (
+ isset($extension->db_plugins_by_id[$extension_id])
+ and $extension->db_plugins_by_id[$extension_id]['state'] == 'active'
+ )
+ {
+ $extension->perform_action('deactivate', $extension_id);
+
+ redirect(PHPWG_ROOT_PATH
+ . 'ws.php'
+ . '?method=pwg.extensions.update'
+ . '&type=plugins'
+ . '&id=' . $extension_id
+ . '&revision=' . $revision
+ . '&reactivate=true'
+ . '&pwg_token=' . get_pwg_token()
+ . '&format=json'
+ );
+ }
+
+ $upgrade_status = $extension->extract_plugin_files('upgrade', $revision, $extension_id);
+ $extension_name = $extension->fs_plugins[$extension_id]['name'];
+
+ if (isset($params['reactivate']))
+ {
+ $extension->perform_action('activate', $extension_id);
+ }
+ }
+ else if ($type == 'themes')
+ {
+ $upgrade_status = $extension->extract_theme_files('upgrade', $revision, $extension_id);
+ $extension_name = $extension->fs_themes[$extension_id]['name'];
+ }
+ else if ($type == 'languages')
+ {
+ $upgrade_status = $extension->extract_language_files('upgrade', $revision, $extension_id);
+ $extension_name = $extension->fs_languages[$extension_id]['name'];
+ }
+
+ global $template;
+ $template->delete_compiled_templates();
+
+ switch ($upgrade_status)
+ {
+ case 'ok':
+ return l10n('%s has been successfully updated.', $extension_name);
+
+ case 'temp_path_error':
+ return new PwgError(null, l10n('Can\'t create temporary file.'));
+
+ case 'dl_archive_error':
+ return new PwgError(null, l10n('Can\'t download archive.'));
+
+ case 'archive_error':
+ return new PwgError(null, l10n('Can\'t read or extract archive.'));
+
+ default:
+ return new PwgError(null, l10n('An error occured during extraction (%s).', $upgrade_status));
+ }
+}
+
+/**
+ * API method
+ * Ignore an update
+ * @param mixed[] $params
+ * @option string type (optional)
+ * @option string id (optional)
+ * @option bool reset
+ * @option string pwg_token
+ */
+function ws_extensions_ignoreupdate($params, &$service)
+{
+ global $conf;
+
+ define('IN_ADMIN', true);
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ if (!is_webmaster())
+ {
+ return new PwgError(401, 'Access denied');
+ }
+
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ $conf['updates_ignored'] = unserialize($conf['updates_ignored']);
+
+ // Reset ignored extension
+ if ($params['reset'])
+ {
+ if (!empty($params['type']) and isset($conf['updates_ignored'][ $params['type'] ]))
+ {
+ $conf['updates_ignored'][$params['type']] = array();
+ }
+ else
+ {
+ $conf['updates_ignored'] = array(
+ 'plugins'=>array(),
+ 'themes'=>array(),
+ 'languages'=>array()
+ );
+ }
+
+ conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
+ unset($_SESSION['extensions_need_update']);
+ return true;
+ }
+
+ if (empty($params['id']) or empty($params['type']) or !in_array($params['type'], array('plugins', 'themes', 'languages')))
+ {
+ return new PwgError(403, 'Invalid parameters');
+ }
+
+ // Add or remove extension from ignore list
+ if (!in_array($params['id'], $conf['updates_ignored'][ $params['type'] ]))
+ {
+ $conf['updates_ignored'][ $params['type'] ][] = $params['id'];
+ }
+
+ conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
+ unset($_SESSION['extensions_need_update']);
+ return true;
+}
+
+/**
+ * API method
+ * Checks for updates (core and extensions)
+ * @param mixed[] $params
+ */
+function ws_extensions_checkupdates($params, &$service)
+{
+ global $conf;
+
+ define('IN_ADMIN', true);
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ include_once(PHPWG_ROOT_PATH.'admin/include/updates.class.php');
+
+ $update = new updates();
+ $result = array();
+
+ if (!isset($_SESSION['need_update']))
+ {
+ $update->check_piwigo_upgrade();
+ }
+
+ $result['piwigo_need_update'] = $_SESSION['need_update'];
+
+ $conf['updates_ignored'] = unserialize($conf['updates_ignored']);
+
+ if (!isset($_SESSION['extensions_need_update']))
+ {
+ $update->check_extensions();
+ }
+ else
+ {
+ $update->check_updated_extensions();
+ }
+
+ if (!is_array($_SESSION['extensions_need_update']))
+ {
+ $result['ext_need_update'] = null;
+ }
+ else
+ {
+ $result['ext_need_update'] = !empty($_SESSION['extensions_need_update']);
+ }
+
+ return $result;
+}
+
+?> \ No newline at end of file
diff --git a/include/ws_functions/pwg.groups.php b/include/ws_functions/pwg.groups.php
new file mode 100644
index 000000000..3401bcaf2
--- /dev/null
+++ b/include/ws_functions/pwg.groups.php
@@ -0,0 +1,284 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2013 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+/**
+ * API method
+ * Returns the list of groups
+ * @param mixed[] $params
+ * @option int[] group_id (optional)
+ * @option string name (optional)
+ */
+function ws_groups_getList($params, &$service)
+{
+ $where_clauses = array('1=1');
+
+ if (!empty($params['name']))
+ {
+ $where_clauses[] = 'LOWER(name) LIKE \''. pwg_db_real_escape_string($params['name']) .'\'';
+ }
+
+ if (!empty($params['group_id']))
+ {
+ $where_clauses[] = 'id IN('. implode(',', $params['group_id']) .')';
+ }
+
+ $query = '
+SELECT
+ g.*, COUNT(user_id) AS nb_users
+ FROM '. GROUPS_TABLE .' AS g
+ LEFT JOIN '. USER_GROUP_TABLE .' AS ug
+ ON ug.group_id = g.id
+ WHERE '. implode(' AND ', $where_clauses) .'
+ GROUP BY id
+ ORDER BY '. $params['order'] .'
+ LIMIT '. $params['per_page'] .'
+ OFFSET '. ($params['per_page']*$params['page']) .'
+;';
+
+ $groups = array_from_query($query);
+
+ return array(
+ 'paging' => new PwgNamedStruct(array(
+ 'page' => $params['page'],
+ 'per_page' => $params['per_page'],
+ 'count' => count($groups)
+ )),
+ 'groups' => new PwgNamedArray($groups, 'group')
+ );
+}
+
+/**
+ * API method
+ * Adds a group
+ * @param mixed[] $params
+ * @option string name
+ * @option bool is_default
+ */
+function ws_groups_add($params, &$service)
+{
+ $params['name'] = pwg_db_real_escape_string($params['name']);
+
+ // is the name not already used ?
+ $query = '
+SELECT COUNT(*)
+ FROM '.GROUPS_TABLE.'
+ WHERE name = \''.$params['name'].'\'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count != 0)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'This name is already used by another group.');
+ }
+
+ // creating the group
+ single_insert(
+ GROUPS_TABLE,
+ array(
+ 'name' => $params['name'],
+ 'is_default' => boolean_to_string($params['is_default']),
+ )
+ );
+
+ return $service->invoke('pwg.groups.getList', array('group_id' => pwg_db_insert_id()));
+}
+
+/**
+ * API method
+ * Deletes a group
+ * @param mixed[] $params
+ * @option int[] group_id
+ * @option string pwg_token
+ */
+function ws_groups_delete($params, &$service)
+{
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ $group_id_string = implode(',', $params['group_id']);
+
+ // destruction of the access linked to the group
+ $query = '
+DELETE
+ FROM '. GROUP_ACCESS_TABLE .'
+ WHERE group_id IN('. $group_id_string .')
+;';
+ pwg_query($query);
+
+ // destruction of the users links for this group
+ $query = '
+DELETE
+ FROM '. USER_GROUP_TABLE .'
+ WHERE group_id IN('. $group_id_string .')
+;';
+ pwg_query($query);
+
+ $query = '
+SELECT name
+ FROM '. GROUPS_TABLE .'
+ WHERE id IN('. $group_id_string .')
+;';
+ $groupnames = array_from_query($query, 'name');
+
+ // destruction of the group
+ $query = '
+DELETE
+ FROM '. GROUPS_TABLE .'
+ WHERE id IN('. $group_id_string .')
+;';
+ pwg_query($query);
+
+ return new PwgNamedArray($groupnames, 'group_deleted');
+}
+
+/**
+ * API method
+ * Updates a group
+ * @param mixed[] $params
+ * @option int group_id
+ * @option string name (optional)
+ * @option bool is_default (optional)
+ */
+function ws_groups_setInfo($params, &$service)
+{
+ $updates = array();
+
+ // does the group exist ?
+ $query = '
+SELECT COUNT(*)
+ FROM '. GROUPS_TABLE .'
+ WHERE id = '. $params['group_id'] .'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'This group does not exist.');
+ }
+
+ if (!empty($params['name']))
+ {
+ $params['name'] = pwg_db_real_escape_string($params['name']);
+
+ // is the name not already used ?
+ $query = '
+SELECT COUNT(*)
+ FROM '. GROUPS_TABLE .'
+ WHERE name = \''. $params['name'] .'\'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count != 0)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'This name is already used by another group.');
+ }
+
+ $updates['name'] = $params['name'];
+ }
+
+ if (!empty($params['is_default']) or @$params['is_default']===false)
+ {
+ $updates['is_default'] = boolean_to_string($params['is_default']);
+ }
+
+ single_update(
+ GROUPS_TABLE,
+ $updates,
+ array('id' => $params['group_id'])
+ );
+
+ return $service->invoke('pwg.groups.getList', array('group_id' => $params['group_id']));
+}
+
+/**
+ * API method
+ * Adds user(s) to a group
+ * @param mixed[] $params
+ * @option int group_id
+ * @option int[] user_id
+ */
+function ws_groups_addUser($params, &$service)
+{
+ // does the group exist ?
+ $query = '
+SELECT COUNT(*)
+ FROM '. GROUPS_TABLE .'
+ WHERE id = '. $params['group_id'] .'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'This group does not exist.');
+ }
+
+ $inserts = array();
+ foreach ($params['user_id'] as $user_id)
+ {
+ $inserts[] = array(
+ 'group_id' => $params['group_id'],
+ 'user_id' => $user_id,
+ );
+ }
+
+ mass_inserts(
+ USER_GROUP_TABLE,
+ array('group_id', 'user_id'),
+ $inserts,
+ array('ignore'=>true)
+ );
+
+ return $service->invoke('pwg.groups.getList', array('group_id' => $params['group_id']));
+}
+
+/**
+ * API method
+ * Removes user(s) from a group
+ * @param mixed[] $params
+ * @option int group_id
+ * @option int[] user_id
+ */
+function ws_groups_deleteUser($params, &$service)
+{
+ // does the group exist ?
+ $query = '
+SELECT COUNT(*)
+ FROM '. GROUPS_TABLE .'
+ WHERE id = '. $params['group_id'] .'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'This group does not exist.');
+ }
+
+ $query = '
+DELETE FROM '. USER_GROUP_TABLE .'
+ WHERE
+ group_id = '. $params['group_id'] .'
+ AND user_id IN('. implode(',', $params['user_id']) .')
+;';
+ pwg_query($query);
+
+ return $service->invoke('pwg.groups.getList', array('group_id' => $params['group_id']));
+}
+
+?> \ No newline at end of file
diff --git a/include/ws_functions/pwg.images.php b/include/ws_functions/pwg.images.php
new file mode 100644
index 000000000..3b694892f
--- /dev/null
+++ b/include/ws_functions/pwg.images.php
@@ -0,0 +1,1582 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2013 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+// +-----------------------------------------------------------------------+
+// | UTILITIES |
+// +-----------------------------------------------------------------------+
+
+/**
+ * Sets associations of an image
+ * @param int $image_id
+ * @param string $categories_string - "cat_id[,rank];cat_id[,rank]"
+ * @param bool $replace_mode - removes old associations
+ */
+function ws_add_image_category_relations($image_id, $categories_string, $replace_mode=false)
+{
+ // let's add links between the image and the categories
+ //
+ // $params['categories'] should look like 123,12;456,auto;789 which means:
+ //
+ // 1. associate with category 123 on rank 12
+ // 2. associate with category 456 on automatic rank
+ // 3. associate with category 789 on automatic rank
+ $cat_ids = array();
+ $rank_on_category = array();
+ $search_current_ranks = false;
+
+ $tokens = explode(';', $categories_string);
+ foreach ($tokens as $token)
+ {
+ @list($cat_id, $rank) = explode(',', $token);
+
+ if (!preg_match('/^\d+$/', $cat_id))
+ {
+ continue;
+ }
+
+ $cat_ids[] = $cat_id;
+
+ if (!isset($rank))
+ {
+ $rank = 'auto';
+ }
+ $rank_on_category[$cat_id] = $rank;
+
+ if ($rank == 'auto')
+ {
+ $search_current_ranks = true;
+ }
+ }
+
+ $cat_ids = array_unique($cat_ids);
+
+ if (count($cat_ids) == 0)
+ {
+ return new PwgError(500,
+ '[ws_add_image_category_relations] there is no category defined in "'.$categories_string.'"'
+ );
+ }
+
+ $query = '
+SELECT id
+ FROM '.CATEGORIES_TABLE.'
+ WHERE id IN ('.implode(',', $cat_ids).')
+;';
+ $db_cat_ids = array_from_query($query, 'id');
+
+ $unknown_cat_ids = array_diff($cat_ids, $db_cat_ids);
+ if (count($unknown_cat_ids) != 0)
+ {
+ return new PwgError(500,
+ '[ws_add_image_category_relations] the following categories are unknown: '.implode(', ', $unknown_cat_ids)
+ );
+ }
+
+ $to_update_cat_ids = array();
+
+ // in case of replace mode, we first check the existing associations
+ $query = '
+SELECT category_id
+ FROM '.IMAGE_CATEGORY_TABLE.'
+ WHERE image_id = '.$image_id.'
+;';
+ $existing_cat_ids = array_from_query($query, 'category_id');
+
+ if ($replace_mode)
+ {
+ $to_remove_cat_ids = array_diff($existing_cat_ids, $cat_ids);
+ if (count($to_remove_cat_ids) > 0)
+ {
+ $query = '
+DELETE
+ FROM '.IMAGE_CATEGORY_TABLE.'
+ WHERE image_id = '.$image_id.'
+ AND category_id IN ('.implode(', ', $to_remove_cat_ids).')
+;';
+ pwg_query($query);
+ update_category($to_remove_cat_ids);
+ }
+ }
+
+ $new_cat_ids = array_diff($cat_ids, $existing_cat_ids);
+ if (count($new_cat_ids) == 0)
+ {
+ return true;
+ }
+
+ if ($search_current_ranks)
+ {
+ $query = '
+SELECT category_id, MAX(rank) AS max_rank
+ FROM '.IMAGE_CATEGORY_TABLE.'
+ WHERE rank IS NOT NULL
+ AND category_id IN ('.implode(',', $new_cat_ids).')
+ GROUP BY category_id
+;';
+ $current_rank_of = simple_hash_from_query(
+ $query,
+ 'category_id',
+ 'max_rank'
+ );
+
+ foreach ($new_cat_ids as $cat_id)
+ {
+ if (!isset($current_rank_of[$cat_id]))
+ {
+ $current_rank_of[$cat_id] = 0;
+ }
+
+ if ('auto' == $rank_on_category[$cat_id])
+ {
+ $rank_on_category[$cat_id] = $current_rank_of[$cat_id] + 1;
+ }
+ }
+ }
+
+ $inserts = array();
+
+ foreach ($new_cat_ids as $cat_id)
+ {
+ $inserts[] = array(
+ 'image_id' => $image_id,
+ 'category_id' => $cat_id,
+ 'rank' => $rank_on_category[$cat_id],
+ );
+ }
+
+ mass_inserts(
+ IMAGE_CATEGORY_TABLE,
+ array_keys($inserts[0]),
+ $inserts
+ );
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ update_category($new_cat_ids);
+}
+
+/**
+ * Merge chunks added by pwg.images.addChunk
+ * @param string $output_filepath
+ * @param string $original_sum
+ * @param string $type
+ */
+function merge_chunks($output_filepath, $original_sum, $type)
+{
+ global $conf;
+
+ ws_logfile('[merge_chunks] input parameter $output_filepath : '.$output_filepath);
+
+ if (is_file($output_filepath))
+ {
+ unlink($output_filepath);
+
+ if (is_file($output_filepath))
+ {
+ return new PwgError(500, '[merge_chunks] error while trying to remove existing '.$output_filepath);
+ }
+ }
+
+ $upload_dir = $conf['upload_dir'].'/buffer';
+ $pattern = '/'.$original_sum.'-'.$type.'/';
+ $chunks = array();
+
+ if ($handle = opendir($upload_dir))
+ {
+ while (false !== ($file = readdir($handle)))
+ {
+ if (preg_match($pattern, $file))
+ {
+ ws_logfile($file);
+ $chunks[] = $upload_dir.'/'.$file;
+ }
+ }
+ closedir($handle);
+ }
+
+ sort($chunks);
+
+ if (function_exists('memory_get_usage')) {
+ ws_logfile('[merge_chunks] memory_get_usage before loading chunks: '.memory_get_usage());
+ }
+
+ $i = 0;
+
+ foreach ($chunks as $chunk)
+ {
+ $string = file_get_contents($chunk);
+
+ if (function_exists('memory_get_usage')) {
+ ws_logfile('[merge_chunks] memory_get_usage on chunk '.++$i.': '.memory_get_usage());
+ }
+
+ if (!file_put_contents($output_filepath, $string, FILE_APPEND))
+ {
+ return new PwgError(500, '[merge_chunks] error while writting chunks for '.$output_filepath);
+ }
+
+ unlink($chunk);
+ }
+
+ if (function_exists('memory_get_usage')) {
+ ws_logfile('[merge_chunks] memory_get_usage after loading chunks: '.memory_get_usage());
+ }
+}
+
+/**
+ * Deletes chunks added with pwg.images.addChunk
+ * @param string $original_sum
+ * @param string $type
+ *
+ * Function introduced for Piwigo 2.4 and the new "multiple size"
+ * (derivatives) feature. As we only need the biggest sent photo as
+ * "original", we remove chunks for smaller sizes. We can't make it earlier
+ * in ws_images_add_chunk because at this moment we don't know which $type
+ * will be the biggest (we could remove the thumb, but let's use the same
+ * algorithm)
+ */
+function remove_chunks($original_sum, $type)
+{
+ global $conf;
+
+ $upload_dir = $conf['upload_dir'].'/buffer';
+ $pattern = '/'.$original_sum.'-'.$type.'/';
+ $chunks = array();
+
+ if ($handle = opendir($upload_dir))
+ {
+ while (false !== ($file = readdir($handle)))
+ {
+ if (preg_match($pattern, $file))
+ {
+ $chunks[] = $upload_dir.'/'.$file;
+ }
+ }
+ closedir($handle);
+ }
+
+ foreach ($chunks as $chunk)
+ {
+ unlink($chunk);
+ }
+}
+
+
+// +-----------------------------------------------------------------------+
+// | METHODS |
+// +-----------------------------------------------------------------------+
+
+/**
+ * API method
+ * Adds a comment to an image
+ * @param mixed[] $params
+ * @option int image_id
+ * @option string author
+ * @option string content
+ * @option string key
+ */
+function ws_images_addComment($params, &$service)
+{
+ $query = '
+SELECT DISTINCT image_id
+ FROM '. IMAGE_CATEGORY_TABLE .'
+ INNER JOIN '.CATEGORIES_TABLE.' ON category_id=id
+ WHERE commentable="true"
+ AND image_id='.$params['image_id'].
+ get_sql_condition_FandF(
+ array(
+ 'forbidden_categories' => 'id',
+ 'visible_categories' => 'id',
+ 'visible_images' => 'image_id'
+ ),
+ ' AND'
+ ).'
+;';
+
+ if (!pwg_db_num_rows(pwg_query($query)))
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid image_id');
+ }
+
+ $comm = array(
+ 'author' => trim($params['author']),
+ 'content' => trim($params['content']),
+ 'image_id' => $params['image_id'],
+ );
+
+ include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php');
+
+ $comment_action = insert_user_comment($comm, $params['key'], $infos);
+
+ switch ($comment_action)
+ {
+ case 'reject':
+ $infos[] = l10n('Your comment has NOT been registered because it did not pass the validation rules');
+ return new PwgError(403, implode("; ", $infos) );
+
+ case 'validate':
+ case 'moderate':
+ $ret = array(
+ 'id' => $comm['id'],
+ 'validation' => $comment_action=='validate',
+ );
+ return array('comment' => new PwgNamedStruct($ret));
+
+ default:
+ return new PwgError(500, "Unknown comment action ".$comment_action );
+ }
+}
+
+/**
+ * API method
+ * Returns detailed information for an element
+ * @param mixed[] $params
+ * @option int image_id
+ * @option int comments_page
+ * @option int comments_per_page
+ */
+function ws_images_getInfo($params, &$service)
+{
+ global $user, $conf;
+
+ $query='
+SELECT *
+ FROM '. IMAGES_TABLE .'
+ WHERE id='. $params['image_id'] .
+ get_sql_condition_FandF(
+ array('visible_images' => 'id'),
+ ' AND'
+ ).'
+LIMIT 1
+;';
+ $result = pwg_query($query);
+
+ if (pwg_db_num_rows($result) == 0)
+ {
+ return new PwgError(404, 'image_id not found');
+ }
+
+ $image_row = pwg_db_fetch_assoc($result);
+ $image_row = array_merge($image_row, ws_std_get_urls($image_row));
+
+ //-------------------------------------------------------- related categories
+ $query = '
+SELECT id, name, permalink, uppercats, global_rank, commentable
+ FROM '. IMAGE_CATEGORY_TABLE .'
+ INNER JOIN '. CATEGORIES_TABLE .' ON category_id = id
+ WHERE image_id = '. $image_row['id'] .
+ get_sql_condition_FandF(
+ array('forbidden_categories' => 'category_id'),
+ ' AND'
+ ).'
+;';
+ $result = pwg_query($query);
+
+ $is_commentable = false;
+ $related_categories = array();
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ if ($row['commentable']=='true')
+ {
+ $is_commentable = true;
+ }
+ unset($row['commentable']);
+
+ $row['url'] = make_index_url(
+ array(
+ 'category' => $row
+ )
+ );
+
+ $row['page_url'] = make_picture_url(
+ array(
+ 'image_id' => $image_row['id'],
+ 'image_file' => $image_row['file'],
+ 'category' => $row
+ )
+ );
+
+ $row['id']=(int)$row['id'];
+ $related_categories[] = $row;
+ }
+ usort($related_categories, 'global_rank_compare');
+
+ if (empty($related_categories))
+ {
+ return new PwgError(401, 'Access denied');
+ }
+
+ //-------------------------------------------------------------- related tags
+ $related_tags = get_common_tags(array($image_row['id']), -1);
+ foreach ($related_tags as $i=>$tag)
+ {
+ $tag['url'] = make_index_url(
+ array(
+ 'tags' => array($tag)
+ )
+ );
+ $tag['page_url'] = make_picture_url(
+ array(
+ 'image_id' => $image_row['id'],
+ 'image_file' => $image_row['file'],
+ 'tags' => array($tag),
+ )
+ );
+
+ unset($tag['counter']);
+ $tag['id'] = (int)$tag['id'];
+ $related_tags[$i] = $tag;
+ }
+
+ //------------------------------------------------------------- related rates
+ $rating = array(
+ 'score' => $image_row['rating_score'],
+ 'count' => 0,
+ 'average' => null,
+ );
+ if (isset($rating['score']))
+ {
+ $query = '
+SELECT COUNT(rate) AS count, ROUND(AVG(rate),2) AS average
+ FROM '. RATE_TABLE .'
+ WHERE element_id = '. $image_row['id'] .'
+;';
+ $row = pwg_db_fetch_assoc(pwg_query($query));
+
+ $rating['score'] = (float)$rating['score'];
+ $rating['average'] = (float)$row['average'];
+ $rating['count'] = (int)$row['count'];
+ }
+
+ //---------------------------------------------------------- related comments
+ $related_comments = array();
+
+ $where_comments = 'image_id = '.$image_row['id'];
+ if (!is_admin())
+ {
+ $where_comments .= ' AND validated="true"';
+ }
+
+ $query = '
+SELECT COUNT(id) AS nb_comments
+ FROM '. COMMENTS_TABLE .'
+ WHERE '. $where_comments .'
+;';
+ list($nb_comments) = array_from_query($query, 'nb_comments');
+ $nb_comments = (int)$nb_comments;
+
+ if ($nb_comments>0 and $params['comments_per_page']>0)
+ {
+ $query = '
+SELECT id, date, author, content
+ FROM '. COMMENTS_TABLE .'
+ WHERE '. $where_comments .'
+ ORDER BY date
+ LIMIT '. (int)$params['comments_per_page'] .'
+ OFFSET '. (int)($params['comments_per_page']*$params['comments_page']) .'
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $row['id'] = (int)$row['id'];
+ $related_comments[] = $row;
+ }
+ }
+
+ $comment_post_data = null;
+ if ($is_commentable and
+ (!is_a_guest()
+ or (is_a_guest() and $conf['comments_forall'] )
+ )
+ )
+ {
+ $comment_post_data['author'] = stripslashes($user['username']);
+ $comment_post_data['key'] = get_ephemeral_key(2, $params['image_id']);
+ }
+
+ $ret = $image_row;
+ foreach (array('id','width','height','hit','filesize') as $k)
+ {
+ if (isset($ret[$k]))
+ {
+ $ret[$k] = (int)$ret[$k];
+ }
+ }
+ foreach (array('path', 'storage_category_id') as $k)
+ {
+ unset($ret[$k]);
+ }
+
+ $ret['rates'] = array(
+ WS_XML_ATTRIBUTES => $rating
+ );
+ $ret['categories'] = new PwgNamedArray(
+ $related_categories,
+ 'category',
+ array('id','url', 'page_url')
+ );
+ $ret['tags'] = new PwgNamedArray(
+ $related_tags,
+ 'tag',
+ ws_std_get_tag_xml_attributes()
+ );
+ if (isset($comment_post_data))
+ {
+ $ret['comment_post'] = array(
+ WS_XML_ATTRIBUTES => $comment_post_data
+ );
+ }
+ $ret['comments_paging'] = new PwgNamedStruct(
+ array(
+ 'page' => $params['comments_page'],
+ 'per_page' => $params['comments_per_page'],
+ 'count' => count($related_comments),
+ 'total_count' => $nb_comments,
+ )
+ );
+ $ret['comments'] = new PwgNamedArray(
+ $related_comments,
+ 'comment',
+ array('id','date')
+ );
+
+ if ($service->_responseFormat != 'rest')
+ {
+ return $ret; // for backward compatibility only
+ }
+ else
+ {
+ return array(
+ 'image' => new PwgNamedStruct($ret, null, array('name','comment'))
+ );
+ }
+}
+
+/**
+ * API method
+ * Rates an image
+ * @param mixed[] $params
+ * @option int image_id
+ * @option float rate
+ */
+function ws_images_rate($params, &$service)
+{
+ $query = '
+SELECT DISTINCT id
+ FROM '. IMAGES_TABLE .'
+ INNER JOIN '. IMAGE_CATEGORY_TABLE .' ON id=image_id
+ WHERE id='. $params['image_id']
+ .get_sql_condition_FandF(
+ array(
+ 'forbidden_categories' => 'category_id',
+ 'forbidden_images' => 'id',
+ ),
+ ' AND'
+ ).'
+ LIMIT 1
+;';
+ if (pwg_db_num_rows(pwg_query($query))==0)
+ {
+ return new PwgError(404, 'Invalid image_id or access denied');
+ }
+
+ include_once(PHPWG_ROOT_PATH.'include/functions_rate.inc.php');
+ $res = rate_picture($params['image_id'], (int)$params['rate']);
+
+ if ($res==false)
+ {
+ global $conf;
+ return new PwgError(403, 'Forbidden or rate not in '. implode(',', $conf['rate_items']));
+ }
+ return $res;
+}
+
+/**
+ * API method
+ * Returns a list of elements corresponding to a query search
+ * @param mixed[] $params
+ * @option string query
+ * @option int per_page
+ * @option int page
+ * @option string order (optional)
+ */
+function ws_images_search($params, &$service)
+{
+ include_once(PHPWG_ROOT_PATH .'include/functions_search.inc.php');
+
+ $images = array();
+ $where_clauses = ws_std_image_sql_filter($params, 'i.');
+ $order_by = ws_std_image_sql_order($params, 'i.');
+
+ $super_order_by = false;
+ if (!empty($order_by))
+ {
+ global $conf;
+ $conf['order_by'] = 'ORDER BY '.$order_by;
+ $super_order_by = true; // quick_search_result might be faster
+ }
+
+ $search_result = get_quick_search_results(
+ $params['query'],
+ $super_order_by,
+ implode(' AND ', $where_clauses)
+ );
+
+ $image_ids = array_slice(
+ $search_result['items'],
+ $params['page']*$params['per_page'],
+ $params['per_page']
+ );
+
+ if (count($image_ids))
+ {
+ $query = '
+SELECT *
+ FROM '. IMAGES_TABLE .'
+ WHERE id IN ('. implode(',', $image_ids) .')
+;';
+ $result = pwg_query($query);
+ $image_ids = array_flip($image_ids);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $image = array();
+ foreach (array('id', 'width', 'height', 'hit') as $k)
+ {
+ if (isset($row[$k]))
+ {
+ $image[$k] = (int)$row[$k];
+ }
+ }
+ foreach (array('file', 'name', 'comment', 'date_creation', 'date_available') as $k)
+ {
+ $image[$k] = $row[$k];
+ }
+
+ $image = array_merge($image, ws_std_get_urls($row));
+ $images[ $image_ids[ $image['id'] ] ] = $image;
+ }
+ ksort($images, SORT_NUMERIC);
+ $images = array_values($images);
+ }
+
+ return array (
+ 'paging' => new PwgNamedStruct(
+ array(
+ 'page' => $params['page'],
+ 'per_page' => $params['per_page'],
+ 'count' => count($images),
+ 'total_count' => count($search_result['items']),
+ )
+ ),
+ 'images' => new PwgNamedArray(
+ $images,
+ 'image',
+ ws_std_get_image_xml_attributes()
+ )
+ );
+}
+
+/**
+ * API method
+ * Sets the level of an image
+ * @param mixed[] $params
+ * @option int image_id
+ * @option int level
+ */
+function ws_images_setPrivacyLevel($params, &$service)
+{
+ global $conf;
+
+ if (!in_array($params['level'], $conf['available_permission_levels']))
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid level');
+ }
+
+ $query = '
+UPDATE '. IMAGES_TABLE .'
+ SET level='. (int)$params['level'] .'
+ WHERE id IN ('. implode(',',$params['image_id']) .')
+;';
+ $result = pwg_query($query);
+
+ $affected_rows = pwg_db_changes($result);
+ if ($affected_rows)
+ {
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ invalidate_user_cache();
+ }
+ return $affected_rows;
+}
+
+/**
+ * API method
+ * Sets the rank of an image in a category
+ * @param mixed[] $params
+ * @option int image_id
+ * @option int category_id
+ * @option int rank
+ */
+function ws_images_setRank($params, &$service)
+{
+ // does the image really exist?
+ $query = '
+SELECT COUNT(*)
+ FROM '. IMAGES_TABLE .'
+ WHERE id = '. $params['image_id'] .'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(404, 'image_id not found');
+ }
+
+ // is the image associated to this category?
+ $query = '
+SELECT COUNT(*)
+ FROM '. IMAGE_CATEGORY_TABLE .'
+ WHERE image_id = '. $params['image_id'] .'
+ AND category_id = '. $params['category_id'] .'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(404, 'This image is not associated to this category');
+ }
+
+ // what is the current higher rank for this category?
+ $query = '
+SELECT MAX(rank) AS max_rank
+ FROM '. IMAGE_CATEGORY_TABLE .'
+ WHERE category_id = '. $params['category_id'] .'
+;';
+ $row = pwg_db_fetch_assoc(pwg_query($query));
+
+ if (is_numeric($row['max_rank']))
+ {
+ if ($params['rank'] > $row['max_rank'])
+ {
+ $params['rank'] = $row['max_rank'] + 1;
+ }
+ }
+ else
+ {
+ $params['rank'] = 1;
+ }
+
+ // update rank for all other photos in the same category
+ $query = '
+UPDATE '. IMAGE_CATEGORY_TABLE .'
+ SET rank = rank + 1
+ WHERE category_id = '. $params['category_id'] .'
+ AND rank IS NOT NULL
+ AND rank >= '. $params['rank'] .'
+;';
+ pwg_query($query);
+
+ // set the new rank for the photo
+ $query = '
+UPDATE '. IMAGE_CATEGORY_TABLE .'
+ SET rank = '. $params['rank'] .'
+ WHERE image_id = '. $params['image_id'] .'
+ AND category_id = '. $params['category_id'] .'
+;';
+ pwg_query($query);
+
+ // return data for client
+ return array(
+ 'image_id' => $params['image_id'],
+ 'category_id' => $params['category_id'],
+ 'rank' => $params['rank'],
+ );
+}
+
+/**
+ * API method
+ * Adds a file chunk
+ * @param mixed[] $params
+ * @option string data
+ * @option string original_sum
+ * @option string type = 'file'
+ * @option int position
+ */
+function ws_images_add_chunk($params, &$service)
+{
+ global $conf;
+
+ foreach ($params as $param_key => $param_value)
+ {
+ if ('data' == $param_key)
+ {
+ continue;
+ }
+ ws_logfile(
+ sprintf(
+ '[ws_images_add_chunk] input param "%s" : "%s"',
+ $param_key,
+ is_null($param_value) ? 'NULL' : $param_value
+ )
+ );
+ }
+
+ $upload_dir = $conf['upload_dir'].'/buffer';
+
+ // create the upload directory tree if not exists
+ if (!mkgetdir($upload_dir, MKGETDIR_DEFAULT&~MKGETDIR_DIE_ON_ERROR))
+ {
+ return new PwgError(500, 'error during buffer directory creation');
+ }
+
+ $filename = sprintf(
+ '%s-%s-%05u.block',
+ $params['original_sum'],
+ $params['type'],
+ $params['position']
+ );
+
+ ws_logfile('[ws_images_add_chunk] data length : '.strlen($params['data']));
+
+ $bytes_written = file_put_contents(
+ $upload_dir.'/'.$filename,
+ base64_decode($params['data'])
+ );
+
+ if (false === $bytes_written)
+ {
+ return new PwgError(500,
+ 'an error has occured while writting chunk '.$params['position'].' for '.$params['type']
+ );
+ }
+}
+
+/**
+ * API method
+ * Adds a file
+ * @param mixed[] $params
+ * @option int image_id
+ * @option string type = 'file'
+ * @option string sum
+ */
+function ws_images_addFile($params, &$service)
+{
+ ws_logfile(__FUNCTION__.', input : '.var_export($params, true));
+
+ global $conf;
+
+ // what is the path and other infos about the photo?
+ $query = '
+SELECT
+ path, file, md5sum,
+ width, height, filesize
+ FROM '. IMAGES_TABLE .'
+ WHERE id = '. $params['image_id'] .'
+;';
+ $result = pwg_query($query);
+
+ if (pwg_db_num_rows($result) == 0)
+ {
+ return new PwgError(404, "image_id not found");
+ }
+
+ $image = pwg_db_fetch_assoc($result);
+
+ // since Piwigo 2.4 and derivatives, we do not take the imported "thumb" into account
+ if ('thumb' == $params['type'])
+ {
+ remove_chunks($image['md5sum'], $type);
+ return true;
+ }
+
+ // since Piwigo 2.4 and derivatives, we only care about the "original"
+ $original_type = 'file';
+ if ('high' == $params['type'])
+ {
+ $original_type = 'high';
+ }
+
+ $file_path = $conf['upload_dir'].'/buffer/'.$image['md5sum'].'-original';
+
+ merge_chunks($file_path, $image['md5sum'], $original_type);
+ chmod($file_path, 0644);
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
+
+ // if we receive the "file", we only update the original if the "file" is
+ // bigger than current original
+ if ('file' == $params['type'])
+ {
+ $do_update = false;
+
+ $infos = pwg_image_infos($file_path);
+
+ foreach (array('width', 'height', 'filesize') as $image_info)
+ {
+ if ($infos[$image_info] > $image[$image_info])
+ {
+ $do_update = true;
+ }
+ }
+
+ if (!$do_update)
+ {
+ unlink($file_path);
+ return true;
+ }
+ }
+
+ $image_id = add_uploaded_file(
+ $file_path,
+ $image['file'],
+ null,
+ null,
+ $params['image_id'],
+ $image['md5sum'] // we force the md5sum to remain the same
+ );
+}
+
+/**
+ * API method
+ * Adds an image
+ * @param mixed[] $params
+ * @option string original_sum
+ * @option string original_filename (optional)
+ * @option string name (optional)
+ * @option string author (optional)
+ * @option string date_creation (optional)
+ * @option string comment (optional)
+ * @option string categories (optional) - "cat_id[,rank];cat_id[,rank]"
+ * @option string tags_ids (optional) - "tag_id,tag_id"
+ * @option int level
+ * @option bool check_uniqueness
+ * @option int image_id (optional)
+ */
+function ws_images_add($params, &$service)
+{
+ global $conf, $user;
+
+ foreach ($params as $param_key => $param_value)
+ {
+ ws_logfile(
+ sprintf(
+ '[pwg.images.add] input param "%s" : "%s"',
+ $param_key,
+ is_null($param_value) ? 'NULL' : $param_value
+ )
+ );
+ }
+
+ if ($params['image_id'] > 0)
+ {
+ $query = '
+SELECT COUNT(*)
+ FROM '. IMAGES_TABLE .'
+ WHERE id = '. $params['image_id'] .'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(404, 'image_id not found');
+ }
+ }
+
+ // does the image already exists ?
+ if ($params['check_uniqueness'])
+ {
+ if ('md5sum' == $conf['uniqueness_mode'])
+ {
+ $where_clause = "md5sum = '".$params['original_sum']."'";
+ }
+ if ('filename' == $conf['uniqueness_mode'])
+ {
+ $where_clause = "file = '".$params['original_filename']."'";
+ }
+
+ $query = '
+SELECT COUNT(*)
+ FROM '. IMAGES_TABLE .'
+ WHERE '. $where_clause .'
+;';
+ list($counter) = pwg_db_fetch_row(pwg_query($query));
+ if ($counter != 0)
+ {
+ return new PwgError(500, 'file already exists');
+ }
+ }
+
+ // due to the new feature "derivatives" (multiple sizes) introduced for
+ // Piwigo 2.4, we only take the biggest photos sent on
+ // pwg.images.addChunk. If "high" is available we use it as "original"
+ // else we use "file".
+ remove_chunks($params['original_sum'], 'thumb');
+
+ if (isset($params['high_sum']))
+ {
+ $original_type = 'high';
+ remove_chunks($params['original_sum'], 'file');
+ }
+ else
+ {
+ $original_type = 'file';
+ }
+
+ $file_path = $conf['upload_dir'].'/buffer/'.$params['original_sum'].'-original';
+
+ merge_chunks($file_path, $params['original_sum'], $original_type);
+ chmod($file_path, 0644);
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
+
+ $image_id = add_uploaded_file(
+ $file_path,
+ $params['original_filename'],
+ null, // categories
+ isset($params['level']) ? $params['level'] : null,
+ $params['image_id'] > 0 ? $params['image_id'] : null,
+ $params['original_sum']
+ );
+
+ $info_columns = array(
+ 'name',
+ 'author',
+ 'comment',
+ 'date_creation',
+ );
+
+ $update = array();
+ foreach ($info_columns as $key)
+ {
+ if (isset($params[$key]))
+ {
+ $update[$key] = $params[$key];
+ }
+ }
+
+ if (count(array_keys($update)) > 0)
+ {
+ single_update(
+ IMAGES_TABLE,
+ $update,
+ array('id' => $image_id)
+ );
+ }
+
+ $url_params = array('image_id' => $image_id);
+
+ // let's add links between the image and the categories
+ if (isset($params['categories']))
+ {
+ ws_add_image_category_relations($image_id, $params['categories']);
+
+ if (preg_match('/^\d+/', $params['categories'], $matches))
+ {
+ $category_id = $matches[0];
+
+ $query = '
+SELECT id, name, permalink
+ FROM '. CATEGORIES_TABLE .'
+ WHERE id = '. $category_id .'
+;';
+ $result = pwg_query($query);
+ $category = pwg_db_fetch_assoc($result);
+
+ $url_params['section'] = 'categories';
+ $url_params['category'] = $category;
+ }
+ }
+
+ // and now, let's create tag associations
+ if (isset($params['tag_ids']) and !empty($params['tag_ids']))
+ {
+ set_tags(
+ explode(',', $params['tag_ids']),
+ $image_id
+ );
+ }
+
+ invalidate_user_cache();
+
+ return array(
+ 'image_id' => $image_id,
+ 'url' => make_picture_url($url_params),
+ );
+}
+
+/**
+ * API method
+ * Adds a image (simple way)
+ * @param mixed[] $params
+ * @option int[] category
+ * @option string name (optional)
+ * @option string author (optional)
+ * @option string comment (optional)
+ * @option int level
+ * @option string|string[] tags
+ * @option int image_id (optional)
+ */
+function ws_images_addSimple($params, &$service)
+{
+ global $conf;
+
+ if (!isset($_FILES['image']))
+ {
+ return new PwgError(405, 'The image (file) is missing');
+ }
+
+ if ($params['image_id'] > 0)
+ {
+ $query='
+SELECT COUNT(*)
+ FROM '. IMAGES_TABLE .'
+ WHERE id = '. $params['image_id'] .'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(404, 'image_id not found');
+ }
+ }
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
+
+ $image_id = add_uploaded_file(
+ $_FILES['image']['tmp_name'],
+ $_FILES['image']['name'],
+ $params['category'],
+ 8,
+ $params['image_id'] > 0 ? $params['image_id'] : null
+ );
+
+ $info_columns = array(
+ 'name',
+ 'author',
+ 'comment',
+ 'level',
+ 'date_creation',
+ );
+
+ $update = array();
+ foreach ($info_columns as $key)
+ {
+ if (isset($params[$key]))
+ {
+ $update[$key] = $params[$key];
+ }
+ }
+
+ single_update(
+ IMAGES_TABLE,
+ $update,
+ array('id' => $image_id)
+ );
+
+ if (isset($params['tags']) and !empty($params['tags']))
+ {
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ $tag_ids = array();
+ if (is_array($params['tags']))
+ {
+ foreach ($params['tags'] as $tag_name)
+ {
+ $tag_ids[] = tag_id_from_tag_name($tag_name);
+ }
+ }
+ else
+ {
+ $tag_names = preg_split('~(?<!\\\),~', $params['tags']);
+ foreach ($tag_names as $tag_name)
+ {
+ $tag_ids[] = tag_id_from_tag_name(preg_replace('#\\\\*,#', ',', $tag_name));
+ }
+ }
+
+ add_tags($tag_ids, array($image_id));
+ }
+
+ $url_params = array('image_id' => $image_id);
+
+ if (!empty($params['category']))
+ {
+ $query = '
+SELECT id, name, permalink
+ FROM '. CATEGORIES_TABLE .'
+ WHERE id = '. $params['category'][0] .'
+;';
+ $result = pwg_query($query);
+ $category = pwg_db_fetch_assoc($result);
+
+ $url_params['section'] = 'categories';
+ $url_params['category'] = $category;
+ }
+
+ // update metadata from the uploaded file (exif/iptc), even if the sync
+ // was already performed by add_uploaded_file().
+ require_once(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
+ sync_metadata(array($image_id));
+
+ return array(
+ 'image_id' => $image_id,
+ 'url' => make_picture_url($url_params),
+ );
+}
+
+/**
+ * API method
+ * Check if an image exists by it's name or md5 sum
+ * @param mixed[] $params
+ * @option string md5sum_list (optional)
+ * @option string filename_list (optional)
+ */
+function ws_images_exist($params, &$service)
+{
+ ws_logfile(__FUNCTION__.' '.var_export($params, true));
+
+ global $conf;
+
+ $split_pattern = '/[\s,;\|]/';
+ $result = array();
+
+ if ('md5sum' == $conf['uniqueness_mode'])
+ {
+ // search among photos the list of photos already added, based on md5sum list
+ $md5sums = preg_split(
+ $split_pattern,
+ $params['md5sum_list'],
+ -1,
+ PREG_SPLIT_NO_EMPTY
+ );
+
+ $query = '
+SELECT id, md5sum
+ FROM '. IMAGES_TABLE .'
+ WHERE md5sum IN (\''. implode("','", $md5sums) .'\')
+;';
+ $id_of_md5 = simple_hash_from_query($query, 'md5sum', 'id');
+
+ foreach ($md5sums as $md5sum)
+ {
+ $result[$md5sum] = null;
+ if (isset($id_of_md5[$md5sum]))
+ {
+ $result[$md5sum] = $id_of_md5[$md5sum];
+ }
+ }
+ }
+ else if ('filename' == $conf['uniqueness_mode'])
+ {
+ // search among photos the list of photos already added, based on
+ // filename list
+ $filenames = preg_split(
+ $split_pattern,
+ $params['filename_list'],
+ -1,
+ PREG_SPLIT_NO_EMPTY
+ );
+
+ $query = '
+SELECT id, file
+ FROM '.IMAGES_TABLE.'
+ WHERE file IN (\''. implode("','", $filenames) .'\')
+;';
+ $id_of_filename = simple_hash_from_query($query, 'file', 'id');
+
+ foreach ($filenames as $filename)
+ {
+ $result[$filename] = null;
+ if (isset($id_of_filename[$filename]))
+ {
+ $result[$filename] = $id_of_filename[$filename];
+ }
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * API method
+ * Check is file has been update
+ * @param mixed[] $params
+ * @option int image_id
+ * @option string file_sum
+ */
+function ws_images_checkFiles($params, &$service)
+{
+ ws_logfile(__FUNCTION__.', input : '.var_export($params, true));
+
+ $query = '
+SELECT path
+ FROM '. IMAGES_TABLE .'
+ WHERE id = '. $params['image_id'] .'
+;';
+ $result = pwg_query($query);
+
+ if (pwg_db_num_rows($result) == 0)
+ {
+ return new PwgError(404, 'image_id not found');
+ }
+
+ list($path) = pwg_db_fetch_row($result);
+
+ $ret = array();
+
+ if (isset($params['thumbnail_sum']))
+ {
+ // We always say the thumbnail is equal to create no reaction on the
+ // other side. Since Piwigo 2.4 and derivatives, the thumbnails and web
+ // sizes are always generated by Piwigo
+ $ret['thumbnail'] = 'equals';
+ }
+
+ if (isset($params['high_sum']))
+ {
+ $ret['file'] = 'equals';
+ $compare_type = 'high';
+ }
+ else if (isset($params['file_sum']))
+ {
+ $compare_type = 'file';
+ }
+
+ if (isset($compare_type))
+ {
+ ws_logfile(__FUNCTION__.', md5_file($path) = '.md5_file($path));
+ if (md5_file($path) != $params[$compare_type.'_sum'])
+ {
+ $ret[$compare_type] = 'differs';
+ }
+ else
+ {
+ $ret[$compare_type] = 'equals';
+ }
+ }
+
+ ws_logfile(__FUNCTION__.', output : '.var_export($ret, true));
+
+ return $ret;
+}
+
+/**
+ * API method
+ * Sets details of an image
+ * @param mixed[] $params
+ * @option int image_id
+ * @option string file (optional)
+ * @option string name (optional)
+ * @option string author (optional)
+ * @option string date_creation (optional)
+ * @option string comment (optional)
+ * @option string categories (optional) - "cat_id[,rank];cat_id[,rank]"
+ * @option string tags_ids (optional) - "tag_id,tag_id"
+ * @option int level (optional)
+ * @option string single_value_mode
+ * @option string multiple_value_mode
+ */
+function ws_images_setInfo($params, &$service)
+{
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ $query='
+SELECT *
+ FROM '. IMAGES_TABLE .'
+ WHERE id = '. $params['image_id'] .'
+;';
+ $result = pwg_query($query);
+
+ if (pwg_db_num_rows($result) == 0)
+ {
+ return new PwgError(404, 'image_id not found');
+ }
+
+ $image_row = pwg_db_fetch_assoc($result);
+
+ // database registration
+ $update = array();
+
+ $info_columns = array(
+ 'name',
+ 'author',
+ 'comment',
+ 'level',
+ 'date_creation',
+ );
+
+ foreach ($info_columns as $key)
+ {
+ if (isset($params[$key]))
+ {
+ if ('fill_if_empty' == $params['single_value_mode'])
+ {
+ if (empty($image_row[$key]))
+ {
+ $update[$key] = $params[$key];
+ }
+ }
+ elseif ('replace' == $params['single_value_mode'])
+ {
+ $update[$key] = $params[$key];
+ }
+ else
+ {
+ return new PwgError(500,
+ '[ws_images_setInfo]'
+ .' invalid parameter single_value_mode "'.$params['single_value_mode'].'"'
+ .', possible values are {fill_if_empty, replace}.'
+ );
+ }
+ }
+ }
+
+ if (isset($params['file']))
+ {
+ if (!empty($image_row['storage_category_id']))
+ {
+ return new PwgError(500,
+ '[ws_images_setInfo] updating "file" is forbidden on photos added by synchronization'
+ );
+ }
+
+ $update['file'] = $params['file'];
+ }
+
+ if (count(array_keys($update)) > 0)
+ {
+ $update['id'] = $params['image_id'];
+
+ single_update(
+ IMAGES_TABLE,
+ $update,
+ array('id' => $update['id'])
+ );
+ }
+
+ if (isset($params['categories']))
+ {
+ ws_add_image_category_relations(
+ $params['image_id'],
+ $params['categories'],
+ ('replace' == $params['multiple_value_mode'] ? true : false)
+ );
+ }
+
+ // and now, let's create tag associations
+ if (isset($params['tag_ids']))
+ {
+ $tag_ids = array();
+
+ foreach (explode(',', $params['tag_ids']) as $candidate)
+ {
+ $candidate = trim($candidate);
+
+ if (preg_match(PATTERN_ID, $candidate))
+ {
+ $tag_ids[] = $candidate;
+ }
+ }
+
+ if ('replace' == $params['multiple_value_mode'])
+ {
+ set_tags(
+ $tag_ids,
+ $params['image_id']
+ );
+ }
+ elseif ('append' == $params['multiple_value_mode'])
+ {
+ add_tags(
+ $tag_ids,
+ array($params['image_id'])
+ );
+ }
+ else
+ {
+ return new PwgError(500,
+ '[ws_images_setInfo]'
+ .' invalid parameter multiple_value_mode "'.$params['multiple_value_mode'].'"'
+ .', possible values are {replace, append}.'
+ );
+ }
+ }
+
+ invalidate_user_cache();
+}
+
+/**
+ * API method
+ * Deletes an image
+ * @param mixed[] $params
+ * @option int|int[] image_id
+ * @option string pwg_token
+ */
+function ws_images_delete($params, &$service)
+{
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ if (!is_array($params['image_id']))
+ {
+ $params['image_id'] = preg_split(
+ '/[\s,;\|]/',
+ $params['image_id'],
+ -1,
+ PREG_SPLIT_NO_EMPTY
+ );
+ }
+ $params['image_id'] = array_map('intval', $params['image_id']);
+
+ $image_ids = array();
+ foreach ($params['image_id'] as $image_id)
+ {
+ if ($image_id > 0)
+ {
+ $image_ids[] = $image_id;
+ }
+ }
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ delete_elements($image_ids, true);
+ invalidate_user_cache();
+}
+
+/**
+ * API method
+ * Checks if Piwigo is ready for upload
+ * @param mixed[] $params
+ */
+function ws_images_checkUpload($params, &$service)
+{
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
+
+ $ret['message'] = ready_for_upload_message();
+ $ret['ready_for_upload'] = true;
+ if (!empty($ret['message']))
+ {
+ $ret['ready_for_upload'] = false;
+ }
+
+ return $ret;
+}
+
+?> \ No newline at end of file
diff --git a/include/ws_functions/pwg.permissions.php b/include/ws_functions/pwg.permissions.php
new file mode 100644
index 000000000..67fc80f9f
--- /dev/null
+++ b/include/ws_functions/pwg.permissions.php
@@ -0,0 +1,235 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2013 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+/**
+ * API method
+ * Returns permissions
+ * @param mixed[] $params
+ * @option int[] cat_id (optional)
+ * @option int[] group_id (optional)
+ * @option int[] user_id (optional)
+ */
+function ws_permissions_getList($params, &$service)
+{
+ $my_params = array_intersect(array_keys($params), array('cat_id','group_id','user_id'));
+ if (count($my_params) > 1)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'Too many parameters, provide cat_id OR user_id OR group_id');
+ }
+
+ $cat_filter = '';
+ if (!empty($params['cat_id']))
+ {
+ $cat_filter = 'WHERE cat_id IN('. implode(',', $params['cat_id']) .')';
+ }
+
+ $perms = array();
+
+ // direct users
+ $query = '
+SELECT user_id, cat_id
+ FROM '. USER_ACCESS_TABLE .'
+ '. $cat_filter .'
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ if (!isset($perms[ $row['cat_id'] ]))
+ {
+ $perms[ $row['cat_id'] ]['id'] = $row['cat_id'];
+ }
+ $perms[ $row['cat_id'] ]['users'][] = $row['user_id'];
+ }
+
+ // indirect users
+ $query = '
+SELECT ug.user_id, ga.cat_id
+ FROM '. USER_GROUP_TABLE .' AS ug
+ INNER JOIN '. GROUP_ACCESS_TABLE .' AS ga
+ ON ug.group_id = ga.group_id
+ '. $cat_filter .'
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ if (!isset($perms[ $row['cat_id'] ]))
+ {
+ $perms[ $row['cat_id'] ]['id'] = $row['cat_id'];
+ }
+ $perms[ $row['cat_id'] ]['users_indirect'][] = $row['user_id'];
+ }
+
+ // groups
+ $query = '
+SELECT group_id, cat_id
+ FROM '. GROUP_ACCESS_TABLE .'
+ '. $cat_filter .'
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ if (!isset($perms[ $row['cat_id'] ]))
+ {
+ $perms[ $row['cat_id'] ]['id'] = $row['cat_id'];
+ }
+ $perms[ $row['cat_id'] ]['groups'][] = $row['group_id'];
+ }
+
+ // filter by group and user
+ foreach ($perms as $cat_id => &$cat)
+ {
+ if (isset($filters['group_id']))
+ {
+ if (empty($cat['groups']) or count(array_intersect($cat['groups'], $params['group_id'])) == 0)
+ {
+ unset($perms[$cat_id]);
+ continue;
+ }
+ }
+ if (isset($filters['user_id']))
+ {
+ if (
+ (empty($cat['users_indirect']) or count(array_intersect($cat['users_indirect'], $params['user_id'])) == 0)
+ and (empty($cat['users']) or count(array_intersect($cat['users'], $params['user_id'])) == 0)
+ ) {
+ unset($perms[$cat_id]);
+ continue;
+ }
+ }
+
+ $cat['groups'] = !empty($cat['groups']) ? array_unique($cat['groups']) : array();
+ $cat['users'] = !empty($cat['users']) ? array_unique($cat['users']) : array();
+ $cat['users_indirect'] = !empty($cat['users_indirect']) ? array_unique($cat['users_indirect']) : array();
+ }
+ unset($cat);
+
+ return array(
+ 'categories' => new PwgNamedArray(
+ array_values($perms),
+ 'category',
+ array('id')
+ )
+ );
+}
+
+/**
+ * API method
+ * Add permissions
+ * @param mixed[] $params
+ * @option int[] cat_id
+ * @option int[] group_id (optional)
+ * @option int[] user_id (optional)
+ * @option bool recursive
+ */
+function ws_permissions_add($params, &$service)
+{
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ if (!empty($params['group_id']))
+ {
+ $cat_ids = get_uppercat_ids($params['cat_id']);
+ if ($params['recursive'])
+ {
+ $cat_ids = array_merge($cat_ids, get_subcat_ids($params['cat_id']));
+ }
+
+ $query = '
+SELECT id
+ FROM '. CATEGORIES_TABLE .'
+ WHERE id IN ('. implode(',', $cat_ids) .')
+ AND status = \'private\'
+;';
+ $private_cats = array_from_query($query, 'id');
+
+ $inserts = array();
+ foreach ($private_cats as $cat_id)
+ {
+ foreach ($params['group_id'] as $group_id)
+ {
+ $inserts[] = array(
+ 'group_id' => $group_id,
+ 'cat_id' => $cat_id
+ );
+ }
+ }
+
+ mass_inserts(
+ GROUP_ACCESS_TABLE,
+ array('group_id','cat_id'),
+ $inserts,
+ array('ignore'=>true)
+ );
+ }
+
+ if (!empty($params['user_id']))
+ {
+ if ($params['recursive']) $_POST['apply_on_sub'] = true;
+ add_permission_on_category($params['cat_id'], $params['user_id']);
+ }
+
+ return $service->invoke('pwg.permissions.getList', array('cat_id'=>$params['cat_id']));
+}
+
+/**
+ * API method
+ * Removes permissions
+ * @param mixed[] $params
+ * @option int[] cat_id
+ * @option int[] group_id (optional)
+ * @option int[] user_id (optional)
+ */
+function ws_permissions_remove($params, &$service)
+{
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ $cat_ids = get_subcat_ids($params['cat_id']);
+
+ if (!empty($params['group_id']))
+ {
+ $query = '
+DELETE
+ FROM '. GROUP_ACCESS_TABLE .'
+ WHERE group_id IN ('. implode(',', $params['group_id']).')
+ AND cat_id IN ('. implode(',', $cat_ids).')
+;';
+ pwg_query($query);
+ }
+
+ if (!empty($params['user_id']))
+ {
+ $query = '
+DELETE
+ FROM '. USER_ACCESS_TABLE .'
+ WHERE user_id IN ('. implode(',', $params['user_id']) .')
+ AND cat_id IN ('. implode(',', $cat_ids) .')
+;';
+ pwg_query($query);
+ }
+
+ return $service->invoke('pwg.permissions.getList', array('cat_id'=>$params['cat_id']));
+}
+
+?> \ No newline at end of file
diff --git a/include/ws_functions/pwg.php b/include/ws_functions/pwg.php
new file mode 100644
index 000000000..2fd69951e
--- /dev/null
+++ b/include/ws_functions/pwg.php
@@ -0,0 +1,338 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2013 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+/**
+ * API method
+ * Returns a list of missing derivatives (not generated yet)
+ * @param mixed[] $params
+ * @option string types (optional)
+ * @option int[] ids
+ * @option int max_urls
+ * @option int prev_page (optional)
+ */
+function ws_getMissingDerivatives($params, &$service)
+{
+ global $conf;
+
+ if (empty($params['types']))
+ {
+ $types = array_keys(ImageStdParams::get_defined_type_map());
+ }
+ else
+ {
+ $types = array_intersect(array_keys(ImageStdParams::get_defined_type_map()), $params['types']);
+ if (count($types)==0)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, "Invalid types");
+ }
+ }
+
+ $max_urls = $params['max_urls'];
+ $query = 'SELECT MAX(id)+1, COUNT(*) FROM '. IMAGES_TABLE .';';
+ list($max_id, $image_count) = pwg_db_fetch_row(pwg_query($query));
+
+ if (0 == $image_count)
+ {
+ return array();
+ }
+
+ $start_id = $params['prev_page'];
+ if ($start_id<=0)
+ {
+ $start_id = $max_id;
+ }
+
+ $uid = '&b='.time();
+
+ $conf['question_mark_in_urls'] = $conf['php_extension_in_urls'] = true;
+ $conf['derivative_url_style'] = 2; //script
+
+ $qlimit = min(5000, ceil(max($image_count/500, $max_urls/count($types))));
+ $where_clauses = ws_std_image_sql_filter( $params, '' );
+ $where_clauses[] = 'id<start_id';
+
+ if (!empty($params['ids']))
+ {
+ $where_clauses[] = 'id IN ('.implode(',',$params['ids']).')';
+ }
+
+ $query_model = '
+SELECT id, path, representative_ext, width, height, rotation
+ FROM '. IMAGES_TABLE .'
+ WHERE '. implode(' AND ', $where_clauses) .'
+ ORDER BY id DESC
+ LIMIT '. $qlimit .'
+;';
+
+ $urls = array();
+ do
+ {
+ $result = pwg_query(str_replace('start_id', $start_id, $query_model));
+ $is_last = pwg_db_num_rows($result) < $qlimit;
+
+ while ($row=pwg_db_fetch_assoc($result))
+ {
+ $start_id = $row['id'];
+ $src_image = new SrcImage($row);
+ if ($src_image->is_mimetype())
+ {
+ continue;
+ }
+
+ foreach($types as $type)
+ {
+ $derivative = new DerivativeImage($type, $src_image);
+ if ($type != $derivative->get_type())
+ {
+ continue;
+ }
+ if (@filemtime($derivative->get_path())===false)
+ {
+ $urls[] = $derivative->get_url().$uid;
+ }
+ }
+
+ if (count($urls)>=$max_urls and !$is_last)
+ {
+ break;
+ }
+ }
+ if ($is_last)
+ {
+ $start_id = 0;
+ }
+ } while (count($urls)<$max_urls and $start_id);
+
+ $ret = array();
+ if ($start_id)
+ {
+ $ret['next_page'] = $start_id;
+ }
+ $ret['urls'] = $urls;
+ return $ret;
+}
+
+/**
+ * API method
+ * Returns Piwigo version
+ * @param mixed[] $params
+ */
+function ws_getVersion($params, &$service)
+{
+ global $conf;
+
+ if ($conf['show_version'] or is_admin())
+ {
+ return PHPWG_VERSION;
+ }
+ else
+ {
+ return new PwgError(403, 'Forbidden');
+ }
+}
+
+/**
+ * API method
+ * Returns general informations about the installation
+ * @param mixed[] $params
+ */
+function ws_getInfos($params, &$service)
+{
+ $infos['version'] = PHPWG_VERSION;
+
+ $query = 'SELECT COUNT(*) FROM '.IMAGES_TABLE.';';
+ list($infos['nb_elements']) = pwg_db_fetch_row(pwg_query($query));
+
+ $query = 'SELECT COUNT(*) FROM '.CATEGORIES_TABLE.';';
+ list($infos['nb_categories']) = pwg_db_fetch_row(pwg_query($query));
+
+ $query = 'SELECT COUNT(*) FROM '.CATEGORIES_TABLE.' WHERE dir IS NULL;';
+ list($infos['nb_virtual']) = pwg_db_fetch_row(pwg_query($query));
+
+ $query = 'SELECT COUNT(*) FROM '.CATEGORIES_TABLE.' WHERE dir IS NOT NULL;';
+ list($infos['nb_physical']) = pwg_db_fetch_row(pwg_query($query));
+
+ $query = 'SELECT COUNT(*) FROM '.IMAGE_CATEGORY_TABLE.';';
+ list($infos['nb_image_category']) = pwg_db_fetch_row(pwg_query($query));
+
+ $query = 'SELECT COUNT(*) FROM '.TAGS_TABLE.';';
+ list($infos['nb_tags']) = pwg_db_fetch_row(pwg_query($query));
+
+ $query = 'SELECT COUNT(*) FROM '.IMAGE_TAG_TABLE.';';
+ list($infos['nb_image_tag']) = pwg_db_fetch_row(pwg_query($query));
+
+ $query = 'SELECT COUNT(*) FROM '.USERS_TABLE.';';
+ list($infos['nb_users']) = pwg_db_fetch_row(pwg_query($query));
+
+ $query = 'SELECT COUNT(*) FROM '.GROUPS_TABLE.';';
+ list($infos['nb_groups']) = pwg_db_fetch_row(pwg_query($query));
+
+ $query = 'SELECT COUNT(*) FROM '.COMMENTS_TABLE.';';
+ list($infos['nb_comments']) = pwg_db_fetch_row(pwg_query($query));
+
+ // first element
+ if ($infos['nb_elements'] > 0)
+ {
+ $query = 'SELECT MIN(date_available) FROM '.IMAGES_TABLE.';';
+ list($infos['first_date']) = pwg_db_fetch_row(pwg_query($query));
+ }
+
+ // unvalidated comments
+ if ($infos['nb_comments'] > 0)
+ {
+ $query = 'SELECT COUNT(*) FROM '.COMMENTS_TABLE.' WHERE validated=\'false\';';
+ list($infos['nb_unvalidated_comments']) = pwg_db_fetch_row(pwg_query($query));
+ }
+
+ foreach ($infos as $name => $value)
+ {
+ $output[] = array(
+ 'name' => $name,
+ 'value' => $value,
+ );
+ }
+
+ return array('infos' => new PwgNamedArray($output, 'item'));
+}
+
+/**
+ * API method
+ * Adds images to the caddie
+ * @param mixed[] $params
+ * @option int[] image_id
+ */
+function ws_caddie_add($params, &$service)
+{
+ global $user;
+
+ $query = '
+SELECT id
+ FROM '. IMAGES_TABLE .'
+ LEFT JOIN '. CADDIE_TABLE .'
+ ON id=element_id AND user_id='. $user['id'] .'
+ WHERE id IN ('. implode(',',$params['image_id']) .')
+ AND element_id IS NULL
+;';
+ $result = array_from_query($query, 'id');
+
+ $datas = array();
+ foreach ($result as $id)
+ {
+ $datas[] = array(
+ 'element_id' => $id,
+ 'user_id' => $user['id'],
+ );
+ }
+ if (count($datas))
+ {
+ mass_inserts(
+ CADDIE_TABLE,
+ array('element_id','user_id'),
+ $datas
+ );
+ }
+ return count($datas);
+}
+
+/**
+ * API method
+ * Deletes rates of an user
+ * @param mixed[] $params
+ * @option int user_id
+ * @option string anonymous_id (optional)
+ */
+function ws_rates_delete($params, &$service)
+{
+ $query = '
+DELETE FROM '. RATE_TABLE .'
+ WHERE user_id='. $params['user_id'];
+
+ if (!empty($params['anonymous_id']))
+ {
+ $query .= ' AND anonymous_id=\''.$params['anonymous_id'].'\'';
+ }
+
+ $changes = pwg_db_changes(pwg_query($query));
+ if ($changes)
+ {
+ include_once(PHPWG_ROOT_PATH.'include/functions_rate.inc.php');
+ update_rating_score();
+ }
+ return $changes;
+}
+
+/**
+ * API method
+ * Performs a login
+ * @param mixed[] $params
+ * @option string username
+ * @option string password
+ */
+function ws_session_login($params, &$service)
+{
+ if (try_log_user($params['username'], $params['password'], false))
+ {
+ return true;
+ }
+ return new PwgError(999, 'Invalid username/password');
+}
+
+
+/**
+ * API method
+ * Performs a logout
+ * @param mixed[] $params
+ */
+function ws_session_logout($params, &$service)
+{
+ if (!is_a_guest())
+ {
+ logout_user();
+ }
+ return true;
+}
+
+/**
+ * API method
+ * Returns info about the current user
+ * @param mixed[] $params
+ */
+function ws_session_getStatus($params, &$service)
+{
+ global $user;
+
+ $res['username'] = is_a_guest() ? 'guest' : stripslashes($user['username']);
+ foreach ( array('status', 'theme', 'language') as $k )
+ {
+ $res[$k] = $user[$k];
+ }
+ $res['pwg_token'] = get_pwg_token();
+ $res['charset'] = get_pwg_charset();
+
+ list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
+ $res['current_datetime'] = $dbnow;
+
+ return $res;
+}
+
+?> \ No newline at end of file
diff --git a/include/ws_functions/pwg.tags.php b/include/ws_functions/pwg.tags.php
new file mode 100644
index 000000000..003993e62
--- /dev/null
+++ b/include/ws_functions/pwg.tags.php
@@ -0,0 +1,244 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2013 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+/**
+ * API method
+ * Returns a list of tags
+ * @param mixed[] $params
+ * @option bool sort_by_counter
+ */
+function ws_tags_getList($params, &$service)
+{
+ $tags = get_available_tags();
+ if ($params['sort_by_counter'])
+ {
+ usort($tags, create_function('$a,$b', 'return -$a["counter"]+$b["counter"];') );
+ }
+ else
+ {
+ usort($tags, 'tag_alpha_compare');
+ }
+
+ for ($i=0; $i<count($tags); $i++)
+ {
+ $tags[$i]['id'] = (int)$tags[$i]['id'];
+ $tags[$i]['counter'] = (int)$tags[$i]['counter'];
+ $tags[$i]['url'] = make_index_url(
+ array(
+ 'section'=>'tags',
+ 'tags'=>array($tags[$i])
+ )
+ );
+ }
+
+ return array(
+ 'tags' => new PwgNamedArray(
+ $tags,
+ 'tag',
+ ws_std_get_tag_xml_attributes()
+ )
+ );
+}
+
+/**
+ * API method
+ * Returns the list of tags as you can see them in administration
+ * @param mixed[] $params
+ *
+ * Only admin can run this method and permissions are not taken into
+ * account.
+ */
+function ws_tags_getAdminList($params, &$service)
+{
+ return array(
+ 'tags' => new PwgNamedArray(
+ get_all_tags(),
+ 'tag',
+ ws_std_get_tag_xml_attributes()
+ )
+ );
+}
+
+/**
+ * API method
+ * Returns a list of images for tags
+ * @param mixed[] $params
+ * @option int[] tag_id (optional)
+ * @option string[] tag_url_name (optional)
+ * @option string[] tag_name (optional)
+ * @option bool tag_mode_and
+ * @option int per_page
+ * @option int page
+ * @option string order
+ */
+function ws_tags_getImages($params, &$service)
+{
+ // first build all the tag_ids we are interested in
+ $tags = find_tags($params['tag_id'], $params['tag_url_name'], $params['tag_name']);
+ $tags_by_id = array();
+ foreach ($tags as $tag)
+ {
+ $tags['id'] = (int)$tag['id'];
+ $tags_by_id[ $tag['id'] ] = $tag;
+ }
+ unset($tags);
+ $tag_ids = array_keys($tags_by_id);
+
+ $where_clauses = ws_std_image_sql_filter($params);
+ if (!empty($where_clauses))
+ {
+ $where_clauses = implode(' AND ', $where_clauses);
+ }
+
+ $image_ids = get_image_ids_for_tags(
+ $tag_ids,
+ $params['tag_mode_and'] ? 'AND' : 'OR',
+ $where_clauses,
+ ws_std_image_sql_order($params)
+ );
+
+ $count_set = count($image_ids);
+ $image_ids = array_slice($image_ids, $params['per_page']*$params['page'], $params['per_page'] );
+
+ $image_tag_map = array();
+ // build list of image ids with associated tags per image
+ if (!empty($image_ids) and !$params['tag_mode_and'])
+ {
+ $query = '
+SELECT image_id, GROUP_CONCAT(tag_id) AS tag_ids
+ FROM '. IMAGE_TAG_TABLE .'
+ WHERE tag_id IN ('. implode(',', $tag_ids) .')
+ AND image_id IN ('. implode(',', $image_ids) .')
+ GROUP BY image_id
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $row['image_id'] = (int)$row['image_id'];
+ $image_ids[] = $row['image_id'];
+ $image_tag_map[ $row['image_id'] ] = explode(',', $row['tag_ids']);
+ }
+ }
+
+ $images = array();
+ if (!empty($image_ids))
+ {
+ $rank_of = array_flip($image_ids);
+
+ $query = '
+SELECT *
+ FROM '. IMAGES_TABLE .'
+ WHERE id IN ('. implode(',',$image_ids) .')
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $image = array();
+ $image['rank'] = $rank_of[ $row['id'] ];
+
+ foreach (array('id', 'width', 'height', 'hit') as $k)
+ {
+ if (isset($row[$k]))
+ {
+ $image[$k] = (int)$row[$k];
+ }
+ }
+ foreach (array('file', 'name', 'comment', 'date_creation', 'date_available') as $k)
+ {
+ $image[$k] = $row[$k];
+ }
+ $image = array_merge( $image, ws_std_get_urls($row) );
+
+ $image_tag_ids = ($params['tag_mode_and']) ? $tag_ids : $image_tag_map[$image['id']];
+ $image_tags = array();
+ foreach ($image_tag_ids as $tag_id)
+ {
+ $url = make_index_url(
+ array(
+ 'section'=>'tags',
+ 'tags'=> array($tags_by_id[$tag_id])
+ )
+ );
+ $page_url = make_picture_url(
+ array(
+ 'section'=>'tags',
+ 'tags'=> array($tags_by_id[$tag_id]),
+ 'image_id' => $row['id'],
+ 'image_file' => $row['file'],
+ )
+ );
+ $image_tags[] = array(
+ 'id' => (int)$tag_id,
+ 'url' => $url,
+ 'page_url' => $page_url,
+ );
+ }
+
+ $image['tags'] = new PwgNamedArray($image_tags, 'tag', ws_std_get_tag_xml_attributes() );
+ $images[] = $image;
+ }
+
+ usort($images, 'rank_compare');
+ unset($rank_of);
+ }
+
+ return array(
+ 'paging' => new PwgNamedStruct(
+ array(
+ 'page' => $params['page'],
+ 'per_page' => $params['per_page'],
+ 'count' => count($images),
+ 'total_count' => $count_set,
+ )
+ ),
+ 'images' => new PwgNamedArray(
+ $images,
+ 'image',
+ ws_std_get_image_xml_attributes()
+ )
+ );
+}
+
+/**
+ * API method
+ * Adds a tag
+ * @param mixed[] $params
+ * @option string name
+ */
+function ws_tags_add($params, &$service)
+{
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ $creation_output = create_tag($params['name']);
+
+ if (isset($creation_output['error']))
+ {
+ return new PwgError(500, $creation_output['error']);
+ }
+
+ return $creation_output;
+}
+
+?> \ No newline at end of file
diff --git a/include/ws_functions/pwg.users.php b/include/ws_functions/pwg.users.php
new file mode 100644
index 000000000..aacc92ed0
--- /dev/null
+++ b/include/ws_functions/pwg.users.php
@@ -0,0 +1,446 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2013 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+/**
+ * API method
+ * Returns a list of users
+ * @param mixed[] $params
+ * @option int[] user_id (optional)
+ * @option string username (optional)
+ * @option string[] status (optional)
+ * @option int min_level (optional)
+ * @option int[] group_id (optional)
+ * @option int per_page
+ * @option int page
+ * @option string order
+ */
+function ws_users_getList($params, &$service)
+{
+ global $conf;
+
+ $where_clauses = array('1=1');
+
+ if (!empty($params['user_id']))
+ {
+ $where_clauses[] = 'u.'.$conf['user_fields']['id'].' IN('. implode(',', $params['user_id']) .')';
+ }
+
+ if (!empty($params['username']))
+ {
+ $where_clauses[] = 'u.'.$conf['user_fields']['username'].' LIKE \''.pwg_db_real_escape_string($params['username']).'\'';
+ }
+
+ if (!empty($params['status']))
+ {
+ $params['status'] = array_intersect($params['status'], get_enums(USER_INFOS_TABLE, 'status'));
+ if (count($params['status']) > 0)
+ {
+ $where_clauses[] = 'ui.status IN("'. implode('","', $params['status']) .'")';
+ }
+ }
+
+ if (!empty($params['min_level']))
+ {
+ if ( !in_array($params['min_level'], $conf['available_permission_levels']) )
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid level');
+ }
+ $where_clauses[] = 'ui.level >= '.$params['min_level'];
+ }
+
+ if (!empty($params['group_id']))
+ {
+ $where_clauses[] = 'ug.group_id IN('. implode(',', $params['group_id']) .')';
+ }
+
+ $display = array('u.'.$conf['user_fields']['id'] => 'id');
+
+ if ($params['display'] != 'none')
+ {
+ $params['display'] = explode(',', $params['display']);
+
+ if (in_array('all', $params['display']))
+ {
+ $params['display'] = array_merge($params['display'], array(
+ 'username','email','status','level','groups','language','theme',
+ 'nb_image_page','recent_period','expand','show_nb_comments','show_nb_hits',
+ 'enabled_high',
+ ));
+ }
+ else if (in_array('basics', $params['display']))
+ {
+ $params['display'] = array_merge($params['display'], array(
+ 'username','email','status','level','groups',
+ ));
+ }
+
+ if (in_array('username', $params['display']))
+ {
+ $display['u.'.$conf['user_fields']['username']] = 'username';
+ }
+ if (in_array('email', $params['display']))
+ {
+ $display['u.'.$conf['user_fields']['email']] = 'email';
+ }
+
+ $ui_fields = array(
+ 'status','level','language','theme','nb_image_page','recent_period','expand',
+ 'show_nb_comments','show_nb_hits','enabled_high',
+ );
+ foreach ($ui_fields as $field)
+ {
+ if (in_array($field, $params['display']))
+ {
+ $display['ui.'.$field] = $field;
+ }
+ }
+ }
+ else
+ {
+ $params['display'] = array();
+ }
+
+ $query = '
+SELECT DISTINCT ';
+
+ $first = true;
+ foreach ($display as $field => $name)
+ {
+ if (!$first) $query.= ', ';
+ else $first = false;
+ $query.= $field .' AS '. $name;
+ }
+ if (in_array('groups', $params['display']))
+ {
+ if (!$first) $query.= ', ';
+ $query.= '"" AS groups';
+ }
+
+ $query.= '
+ FROM '. USERS_TABLE .' AS u
+ INNER JOIN '. USER_INFOS_TABLE .' AS ui
+ ON u.'. $conf['user_fields']['id'] .' = ui.user_id
+ LEFT JOIN '. USER_GROUP_TABLE .' AS ug
+ ON u.'. $conf['user_fields']['id'] .' = ug.user_id
+ WHERE
+ '. implode(' AND ', $where_clauses) .'
+ ORDER BY '. $params['order'] .'
+ LIMIT '. $params['per_page'] .'
+ OFFSET '. ($params['per_page']*$params['page']) .'
+;';
+
+ $users = hash_from_query($query, 'id');
+
+ if (count($users) > 0 and in_array('groups', $params['display']))
+ {
+ $query = '
+SELECT user_id, group_id
+ FROM '. USER_GROUP_TABLE .'
+ WHERE user_id IN ('. implode(',', array_keys($users)) .')
+;';
+ $result = pwg_query($query);
+
+ while ($row = pwg_db_fetch_assoc($result))
+ {
+ $users[ $row['user_id'] ]['groups'][] = $row['group_id'];
+ }
+ }
+
+ return array(
+ 'paging' => new PwgNamedStruct(
+ array(
+ 'page' => $params['page'],
+ 'per_page' => $params['per_page'],
+ 'count' => count($users)
+ )
+ ),
+ 'users' => new PwgNamedArray(array_values($users), 'user')
+ );
+}
+
+/**
+ * API method
+ * Adds a user
+ * @param mixed[] $params
+ * @option string username
+ * @option string password (optional)
+ * @option string email (optional)
+ */
+function ws_users_add($params, &$service)
+{
+ global $conf;
+
+ if ($conf['double_password_type_in_admin'])
+ {
+ if ($params['password'] != $params['password_confirm'])
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, l10n('The passwords do not match'));
+ }
+ }
+
+ $user_id = register_user(
+ $params['username'],
+ $params['password'],
+ $params['email'],
+ false, // notify admin
+ $errors,
+ $params['send_password_by_mail']
+ );
+
+ if (!$user_id)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, $errors[0]);
+ }
+
+ return $service->invoke('pwg.users.getList', array('user_id'=>$user_id));
+}
+
+/**
+ * API method
+ * Deletes users
+ * @param mixed[] $params
+ * @option int[] user_id
+ * @option string pwg_token
+ */
+function ws_users_delete($params, &$service)
+{
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ global $conf, $user;
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ // protect some users
+ $params['user_id'] = array_diff(
+ $params['user_id'],
+ array(
+ $user['id'],
+ $conf['guest_id'],
+ $conf['default_user_id'],
+ $conf['webmaster_id'],
+ )
+ );
+
+ foreach ($params['user_id'] as $user_id)
+ {
+ delete_user($user_id);
+ }
+
+ return l10n_dec(
+ '%d user deleted', '%d users deleted',
+ count($params['user_id'])
+ );
+}
+
+/**
+ * API method
+ * Updates users
+ * @param mixed[] $params
+ * @option int[] user_id
+ * @option string username (optional)
+ * @option string password (optional)
+ * @option string email (optional)
+ * @option string status (optional)
+ * @option int level (optional)
+ * @option string language (optional)
+ * @option string theme (optional)
+ * @option int nb_image_page (optional)
+ * @option int recent_period (optional)
+ * @option bool expand (optional)
+ * @option bool show_nb_comments (optional)
+ * @option bool show_nb_hits (optional)
+ * @option bool enabled_high (optional)
+ */
+function ws_users_setInfo($params, &$service)
+{
+ global $conf, $user;
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ $updates = $updates_infos = array();
+ $update_status = null;
+
+ if (count($params['user_id']) == 1)
+ {
+ if (get_username($params['user_id'][0]) === false)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'This user does not exist.');
+ }
+
+ if (!empty($params['username']))
+ {
+ $user_id = get_userid($params['username']);
+ if ($user_id and $user_id != $params['user_id'][0])
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, l10n('this login is already used'));
+ }
+ if ($params['username'] != strip_tags($params['username']))
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, l10n('html tags are not allowed in login'));
+ }
+ $updates[ $conf['user_fields']['username'] ] = $params['username'];
+ }
+
+ if (!empty($params['email']))
+ {
+ if ( ($error = validate_mail_address($params['user_id'][0], $params['email'])) != '')
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, $error);
+ }
+ $updates[ $conf['user_fields']['email'] ] = $params['email'];
+ }
+
+ if (!empty($params['password']))
+ {
+ $updates[ $conf['user_fields']['password'] ] = $conf['password_hash']($params['password']);
+ }
+ }
+
+ if (!empty($params['status']))
+ {
+ if ( $params['status'] == 'webmaster' and !is_webmaster() )
+ {
+ return new PwgError(403, 'Only webmasters can grant "webmaster" status');
+ }
+ if ( !in_array($params['status'], array('guest','generic','normal','admin','webmaster')) )
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid status');
+ }
+
+ // status update query is separated from the rest as not applying to the same
+ // set of users (current, guest and webmaster can't be changed)
+ $params['user_id_for_status'] = array_diff(
+ $params['user_id'],
+ array(
+ $user['id'],
+ $conf['guest_id'],
+ $conf['webmaster_id'],
+ )
+ );
+
+ $update_status = $params['status'];
+ }
+
+ if (!empty($params['level']) or @$params['level']===0)
+ {
+ if ( !in_array($params['level'], $conf['available_permission_levels']) )
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid level');
+ }
+ $updates_infos['level'] = $params['level'];
+ }
+
+ if (!empty($params['language']))
+ {
+ if ( !in_array($params['language'], array_keys(get_languages())) )
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid language');
+ }
+ $updates_infos['language'] = $params['language'];
+ }
+
+ if (!empty($params['theme']))
+ {
+ if ( !in_array($params['theme'], array_keys(get_pwg_themes())) )
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid theme');
+ }
+ $updates_infos['theme'] = $params['theme'];
+ }
+
+ if (!empty($params['nb_image_page']))
+ {
+ $updates_infos['nb_image_page'] = $params['nb_image_page'];
+ }
+
+ if (!empty($params['recent_period']) or @$params['recent_period']===0)
+ {
+ $updates_infos['recent_period'] = $params['recent_period'];
+ }
+
+ if (!empty($params['expand']) or @$params['expand']===false)
+ {
+ $updates_infos['expand'] = boolean_to_string($params['expand']);
+ }
+
+ if (!empty($params['show_nb_comments']) or @$params['show_nb_comments']===false)
+ {
+ $updates_infos['show_nb_comments'] = boolean_to_string($params['show_nb_comments']);
+ }
+
+ if (!empty($params['show_nb_hits']) or @$params['show_nb_hits']===false)
+ {
+ $updates_infos['show_nb_hits'] = boolean_to_string($params['show_nb_hits']);
+ }
+
+ if (!empty($params['enabled_high']) or @$params['enabled_high']===false)
+ {
+ $updates_infos['enabled_high'] = boolean_to_string($params['enabled_high']);
+ }
+
+ // perform updates
+ single_update(
+ USERS_TABLE,
+ $updates,
+ array($conf['user_fields']['id'] => $params['user_id'][0])
+ );
+
+ if (isset($update_status) and count($params['user_id_for_status']) > 0)
+ {
+ $query = '
+UPDATE '. USER_INFOS_TABLE .' SET
+ status = "'. $update_status .'"
+ WHERE user_id IN('. implode(',', $params['user_id_for_status']) .')
+;';
+ pwg_query($query);
+ }
+
+ if (count($updates_infos) > 0)
+ {
+ $query = '
+UPDATE '. USER_INFOS_TABLE .' SET ';
+
+ $first = true;
+ foreach ($updates_infos as $field => $value)
+ {
+ if (!$first) $query.= ', ';
+ else $first = false;
+ $query.= $field .' = "'. $value .'"';
+ }
+
+ $query.= '
+ WHERE user_id IN('. implode(',', $params['user_id']) .')
+;';
+ pwg_query($query);
+ }
+
+ return $service->invoke('pwg.users.getList', array(
+ 'user_id' => $params['user_id'],
+ 'display' => 'basics,'.implode(',', array_keys($updates_infos)),
+ ));
+}
+
+?> \ No newline at end of file