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