diff options
Diffstat (limited to 'include/ws_functions/pwg.images.php')
-rw-r--r-- | include/ws_functions/pwg.images.php | 1582 |
1 files changed, 1582 insertions, 0 deletions
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 |