diff options
Diffstat (limited to 'include/ws_functions')
-rw-r--r-- | include/ws_functions/index.php | 30 | ||||
-rw-r--r-- | include/ws_functions/pwg.categories.php | 838 | ||||
-rw-r--r-- | include/ws_functions/pwg.extensions.php | 343 | ||||
-rw-r--r-- | include/ws_functions/pwg.groups.php | 293 | ||||
-rw-r--r-- | include/ws_functions/pwg.images.php | 1582 | ||||
-rw-r--r-- | include/ws_functions/pwg.permissions.php | 235 | ||||
-rw-r--r-- | include/ws_functions/pwg.php | 338 | ||||
-rw-r--r-- | include/ws_functions/pwg.tags.php | 244 | ||||
-rw-r--r-- | include/ws_functions/pwg.users.php | 571 |
9 files changed, 4474 insertions, 0 deletions
diff --git a/include/ws_functions/index.php b/include/ws_functions/index.php new file mode 100644 index 000000000..c8de97f60 --- /dev/null +++ b/include/ws_functions/index.php @@ -0,0 +1,30 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 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..d77b88580 --- /dev/null +++ b/include/ws_functions/pwg.categories.php @@ -0,0 +1,838 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 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)); + } + 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..a1c8ae1b8 --- /dev/null +++ b/include/ws_functions/pwg.extensions.php @@ -0,0 +1,343 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 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..773623eaf --- /dev/null +++ b/include/ws_functions/pwg.groups.php @@ -0,0 +1,293 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 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); + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + invalidate_user_cache(); + + 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) + ); + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + invalidate_user_cache(); + + 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); + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + invalidate_user_cache(); + + 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..6eebd4482 --- /dev/null +++ b/include/ws_functions/pwg.images.php @@ -0,0 +1,1582 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 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..936999ab8 --- /dev/null +++ b/include/ws_functions/pwg.permissions.php @@ -0,0 +1,235 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 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'] = intval($row['cat_id']); + } + $perms[ $row['cat_id'] ]['users'][] = intval($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'] = intval($row['cat_id']); + } + $perms[ $row['cat_id'] ]['users_indirect'][] = intval($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'] = intval($row['cat_id']); + } + $perms[ $row['cat_id'] ]['groups'][] = intval($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_values(array_unique($cat['groups'])) : array(); + $cat['users'] = !empty($cat['users']) ? array_values(array_unique($cat['users'])) : array(); + $cat['users_indirect'] = !empty($cat['users_indirect']) ? array_values(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..0def2031f --- /dev/null +++ b/include/ws_functions/pwg.php @@ -0,0 +1,338 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 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..09ce21bd0 --- /dev/null +++ b/include/ws_functions/pwg.tags.php @@ -0,0 +1,244 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 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..d8b70c6ae --- /dev/null +++ b/include/ws_functions/pwg.users.php @@ -0,0 +1,571 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 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 + * @option string display + */ +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'] = array_map('trim', explode(',', $params['display'])); + + if (in_array('all', $params['display'])) + { + $params['display'] = array( + 'username','email','status','level','groups','language','theme', + 'nb_image_page','recent_period','expand','show_nb_comments','show_nb_hits', + 'enabled_high','registration_date','registration_date_string', + 'registration_date_since', 'last_visit', 'last_visit_string', + 'last_visit_since' + ); + } + else if (in_array('basics', $params['display'])) + { + $params['display'] = array_merge($params['display'], array( + 'username','email','status','level','groups', + )); + } + $params['display'] = array_flip($params['display']); + + // if registration_date_string or registration_date_since is requested, + // then registration_date is automatically added + if (isset($params['display']['registration_date_string']) or isset($params['display']['registration_date_since'])) + { + $params['display']['registration_date'] = true; + } + + // if last_visit_string or last_visit_since is requested, then + // last_visit is automatically added + if (isset($params['display']['last_visit_string']) or isset($params['display']['last_visit_since'])) + { + $params['display']['last_visit'] = true; + } + + if (isset($params['display']['username'])) + { + $display['u.'.$conf['user_fields']['username']] = 'username'; + } + if (isset($params['display']['email'])) + { + $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','registration_date' + ); + foreach ($ui_fields as $field) + { + if (isset($params['display'][$field])) + { + $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 (isset($params['display']['groups'])) + { + 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 = array(); + $result = pwg_query($query); + while ($row = pwg_db_fetch_assoc($result)) + { + $row['id'] = intval($row['id']); + $users[ $row['id'] ] = $row; + } + + if (count($users) > 0) + { + if (isset($params['display']['groups'])) + { + $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'][] = intval($row['group_id']); + } + } + + if (isset($params['display']['registration_date_string'])) + { + foreach ($users as $cur_user) + { + $users[$cur_user['id']]['registration_date_string'] = format_date($cur_user['registration_date'], false, false); + } + } + + if (isset($params['display']['registration_date_since'])) + { + foreach ($users as $cur_user) + { + $users[ $cur_user['id'] ]['registration_date_since'] = time_since($cur_user['registration_date'], 'month'); + } + } + + if (isset($params['display']['last_visit'])) + { + $query = ' +SELECT + MAX(id) as history_id + FROM '.HISTORY_TABLE.' + WHERE user_id IN ('.implode(',', array_keys($users)).') + GROUP BY user_id +;'; + $history_ids = array_from_query($query, 'history_id'); + + if (count($history_ids) == 0) + { + $history_ids[] = -1; + } + + $query = ' +SELECT + user_id, + date, + time + FROM '.HISTORY_TABLE.' + WHERE id IN ('.implode(',', $history_ids).') +;'; + $result = pwg_query($query); + while ($row = pwg_db_fetch_assoc($result)) + { + $last_visit = $row['date'].' '.$row['time']; + $users[ $row['user_id'] ]['last_visit'] = $last_visit; + + if (isset($params['display']['last_visit_string'])) + { + $users[ $row['user_id'] ]['last_visit_string'] = format_date($last_visit, false, false); + } + + if (isset($params['display']['last_visit_since'])) + { + $users[ $row['user_id'] ]['last_visit_since'] = time_since($last_visit, 'day'); + } + } + } + } + + 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); + } + + // manage association to groups + if (!empty($params['group_id'])) + { + $query = ' +DELETE + FROM '.USER_GROUP_TABLE.' + WHERE user_id IN ('.implode(',', $params['user_id']).') +;'; + pwg_query($query); + + // we remove all provided groups that do not really exist + $query = ' +SELECT + id + FROM '.GROUPS_TABLE.' + WHERE id IN ('.implode(',', $params['group_id']).') +;'; + $group_ids = array_from_query($query, 'id'); + + // if only -1 (a group id that can't exist) is in the list, then no + // group is associated + + if (count($group_ids) > 0) + { + $inserts = array(); + + foreach ($group_ids as $group_id) + { + foreach ($params['user_id'] as $user_id) + { + $inserts[] = array('user_id' => $user_id, 'group_id' => $group_id); + } + } + + mass_inserts(USER_GROUP_TABLE, array_keys($inserts[0]), $inserts); + } + } + + invalidate_user_cache(); + + 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 |