source: trunk/include/ws_functions.inc.php @ 12175

Last change on this file since 12175 was 12175, checked in by plg, 13 years ago

feature 2441 added: no need to have the HD to regenerate the websize if the
current websize is bigger than resize settings. When it occurs, we move the
current websize as HD and create the new websize from it.

  • Property svn:eol-style set to LF
File size: 77.2 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24/**** IMPLEMENTATION OF WEB SERVICE METHODS ***********************************/
25
26/**
27 * Event handler for method invocation security check. Should return a PwgError
28 * if the preconditions are not satifsied for method invocation.
29 */
30function ws_isInvokeAllowed($res, $methodName, $params)
31{
32  global $conf;
33
34  if ( strpos($methodName,'reflection.')===0 )
35  { // OK for reflection
36    return $res;
37  }
38
39  if ( !is_autorize_status(ACCESS_GUEST) and
40      strpos($methodName,'pwg.session.')!==0 )
41  {
42    return new PwgError(401, 'Access denied');
43  }
44
45  return $res;
46}
47
48/**
49 * returns a "standard" (for our web service) array of sql where clauses that
50 * filters the images (images table only)
51 */
52function ws_std_image_sql_filter( $params, $tbl_name='' )
53{
54  $clauses = array();
55  if ( is_numeric($params['f_min_rate']) )
56  {
57    $clauses[] = $tbl_name.'rating_score>'.$params['f_min_rate'];
58  }
59  if ( is_numeric($params['f_max_rate']) )
60  {
61    $clauses[] = $tbl_name.'rating_score<='.$params['f_max_rate'];
62  }
63  if ( is_numeric($params['f_min_hit']) )
64  {
65    $clauses[] = $tbl_name.'hit>'.$params['f_min_hit'];
66  }
67  if ( is_numeric($params['f_max_hit']) )
68  {
69    $clauses[] = $tbl_name.'hit<='.$params['f_max_hit'];
70  }
71  if ( isset($params['f_min_date_available']) )
72  {
73    $clauses[] = $tbl_name."date_available>='".$params['f_min_date_available']."'";
74  }
75  if ( isset($params['f_max_date_available']) )
76  {
77    $clauses[] = $tbl_name."date_available<'".$params['f_max_date_available']."'";
78  }
79  if ( isset($params['f_min_date_created']) )
80  {
81    $clauses[] = $tbl_name."date_creation>='".$params['f_min_date_created']."'";
82  }
83  if ( isset($params['f_max_date_created']) )
84  {
85    $clauses[] = $tbl_name."date_creation<'".$params['f_max_date_created']."'";
86  }
87  if ( is_numeric($params['f_min_ratio']) )
88  {
89    $clauses[] = $tbl_name.'width/'.$tbl_name.'height>'.$params['f_min_ratio'];
90  }
91  if ( is_numeric($params['f_max_ratio']) )
92  {
93    $clauses[] = $tbl_name.'width/'.$tbl_name.'height<='.$params['f_max_ratio'];
94  }
95  if ( $params['f_with_thumbnail'] )
96  {
97    $clauses[] = $tbl_name.'tn_ext IS NOT NULL';
98  }
99  return $clauses;
100}
101
102/**
103 * returns a "standard" (for our web service) ORDER BY sql clause for images
104 */
105function ws_std_image_sql_order( $params, $tbl_name='' )
106{
107  $ret = '';
108  if ( empty($params['order']) )
109  {
110    return $ret;
111  }
112  $matches = array();
113  preg_match_all('/([a-z_]+) *(?:(asc|desc)(?:ending)?)? *(?:, *|$)/i',
114    $params['order'], $matches);
115  for ($i=0; $i<count($matches[1]); $i++)
116  {
117    switch ($matches[1][$i])
118    {
119      case 'date_created':
120        $matches[1][$i] = 'date_creation'; break;
121      case 'date_posted':
122        $matches[1][$i] = 'date_available'; break;
123      case 'rand': case 'random':
124        $matches[1][$i] = DB_RANDOM_FUNCTION.'()'; break;
125    }
126    $sortable_fields = array('id', 'file', 'name', 'hit', 'rating_score',
127      'date_creation', 'date_available', DB_RANDOM_FUNCTION.'()' );
128    if ( in_array($matches[1][$i], $sortable_fields) )
129    {
130      if (!empty($ret))
131        $ret .= ', ';
132      if ($matches[1][$i] != DB_RANDOM_FUNCTION.'()' )
133      {
134        $ret .= $tbl_name;
135      }
136      $ret .= $matches[1][$i];
137      $ret .= ' '.$matches[2][$i];
138    }
139  }
140  return $ret;
141}
142
143/**
144 * returns an array map of urls (thumb/element) for image_row - to be returned
145 * in a standard way by different web service methods
146 */
147function ws_std_get_urls($image_row)
148{
149  $ret = array(
150    'tn_url' => get_thumbnail_url($image_row),
151    'element_url' => get_element_url($image_row)
152  );
153  global $user;
154  if ($user['enabled_high'] and $image_row['has_high'] )
155  {
156    $ret['high_url'] = get_high_url($image_row);
157  }
158  return $ret;
159}
160
161/**
162 * returns an array of image attributes that are to be encoded as xml attributes
163 * instead of xml elements
164 */
165function ws_std_get_image_xml_attributes()
166{
167  return array(
168    'id','tn_url','element_url','high_url', 'file','width','height','hit','date_available','date_creation'
169    );
170}
171
172/**
173 * returns PWG version (web service method)
174 */
175function ws_getVersion($params, &$service)
176{
177  global $conf;
178  if ($conf['show_version'] or is_admin() )
179    return PHPWG_VERSION;
180  else
181    return new PwgError(403, 'Forbidden');
182}
183
184/**
185 * returns general informations (web service method)
186 */
187function ws_getInfos($params, &$service)
188{
189  if (!is_admin())
190  {
191    return new PwgError(403, 'Forbidden');
192  }
193
194  $infos['version'] = PHPWG_VERSION;
195
196  $query = 'SELECT COUNT(*) FROM '.IMAGES_TABLE.';';
197  list($infos['nb_elements']) = pwg_db_fetch_row(pwg_query($query));
198
199  $query = 'SELECT COUNT(*) FROM '.CATEGORIES_TABLE.';';
200  list($infos['nb_categories']) = pwg_db_fetch_row(pwg_query($query));
201
202  $query = 'SELECT COUNT(*) FROM '.CATEGORIES_TABLE.' WHERE dir IS NULL;';
203  list($infos['nb_virtual']) = pwg_db_fetch_row(pwg_query($query));
204
205  $query = 'SELECT COUNT(*) FROM '.CATEGORIES_TABLE.' WHERE dir IS NOT NULL;';
206  list($infos['nb_physical']) = pwg_db_fetch_row(pwg_query($query));
207
208  $query = 'SELECT COUNT(*) FROM '.IMAGE_CATEGORY_TABLE.';';
209  list($infos['nb_image_category']) = pwg_db_fetch_row(pwg_query($query));
210
211  $query = 'SELECT COUNT(*) FROM '.TAGS_TABLE.';';
212  list($infos['nb_tags']) = pwg_db_fetch_row(pwg_query($query));
213
214  $query = 'SELECT COUNT(*) FROM '.IMAGE_TAG_TABLE.';';
215  list($infos['nb_image_tag']) = pwg_db_fetch_row(pwg_query($query));
216
217  $query = 'SELECT COUNT(*) FROM '.USERS_TABLE.';';
218  list($infos['nb_users']) = pwg_db_fetch_row(pwg_query($query));
219
220  $query = 'SELECT COUNT(*) FROM '.GROUPS_TABLE.';';
221  list($infos['nb_groups']) = pwg_db_fetch_row(pwg_query($query));
222
223  $query = 'SELECT COUNT(*) FROM '.COMMENTS_TABLE.';';
224  list($infos['nb_comments']) = pwg_db_fetch_row(pwg_query($query));
225
226  // first element
227  if ($infos['nb_elements'] > 0)
228  {
229    $query = 'SELECT MIN(date_available) FROM '.IMAGES_TABLE.';';
230    list($infos['first_date']) = pwg_db_fetch_row(pwg_query($query));
231  }
232
233  // unvalidated comments
234  if ($infos['nb_comments'] > 0)
235  {
236    $query = 'SELECT COUNT(*) FROM '.COMMENTS_TABLE.' WHERE validated=\'false\';';
237    list($infos['nb_unvalidated_comments']) = pwg_db_fetch_row(pwg_query($query));
238  }
239
240  foreach ($infos as $name => $value)
241  {
242    $output[] = array(
243      'name' => $name,
244      'value' => $value,
245    );
246  }
247
248  return array('infos' => new PwgNamedArray($output, 'item'));
249}
250
251function ws_caddie_add($params, &$service)
252{
253  if (!is_admin())
254  {
255    return new PwgError(401, 'Access denied');
256  }
257  $params['image_id'] = array_map( 'intval',$params['image_id'] );
258  if ( empty($params['image_id']) )
259  {
260    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
261  }
262  global $user;
263  $query = '
264SELECT id
265  FROM '.IMAGES_TABLE.' LEFT JOIN '.CADDIE_TABLE.' ON id=element_id AND user_id='.$user['id'].'
266  WHERE id IN ('.implode(',',$params['image_id']).')
267    AND element_id IS NULL';
268  $datas = array();
269  foreach ( array_from_query($query, 'id') as $id )
270  {
271    array_push($datas, array('element_id'=>$id, 'user_id'=>$user['id']) );
272  }
273  if (count($datas))
274  {
275    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
276    mass_inserts(CADDIE_TABLE, array('element_id','user_id'), $datas);
277  }
278  return count($datas);
279}
280
281/**
282 * returns images per category (web service method)
283 */
284function ws_categories_getImages($params, &$service)
285{
286  @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
287  global $user, $conf;
288
289  $images = array();
290
291  //------------------------------------------------- get the related categories
292  $where_clauses = array();
293  foreach($params['cat_id'] as $cat_id)
294  {
295    $cat_id = (int)$cat_id;
296    if ($cat_id<=0)
297      continue;
298    if ($params['recursive'])
299    {
300      $where_clauses[] = 'uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.$cat_id.'(,|$)\'';
301    }
302    else
303    {
304      $where_clauses[] = 'id='.$cat_id;
305    }
306  }
307  if (!empty($where_clauses))
308  {
309    $where_clauses = array( '('.
310    implode('
311    OR ', $where_clauses) . ')'
312      );
313  }
314  $where_clauses[] = get_sql_condition_FandF(
315        array('forbidden_categories' => 'id'),
316        NULL, true
317      );
318
319  $query = '
320SELECT id, name, permalink, image_order
321  FROM '.CATEGORIES_TABLE.'
322  WHERE '. implode('
323    AND ', $where_clauses);
324  $result = pwg_query($query);
325  $cats = array();
326  while ($row = pwg_db_fetch_assoc($result))
327  {
328    $row['id'] = (int)$row['id'];
329    $cats[ $row['id'] ] = $row;
330  }
331
332  //-------------------------------------------------------- get the images
333  if ( !empty($cats) )
334  {
335    $where_clauses = ws_std_image_sql_filter( $params, 'i.' );
336    $where_clauses[] = 'category_id IN ('
337      .implode(',', array_keys($cats) )
338      .')';
339    $where_clauses[] = get_sql_condition_FandF( array(
340          'visible_images' => 'i.id'
341        ), null, true
342      );
343
344    $order_by = ws_std_image_sql_order($params, 'i.');
345    if ( empty($order_by)
346          and count($params['cat_id'])==1
347          and isset($cats[ $params['cat_id'][0] ]['image_order'])
348        )
349    {
350      $order_by = $cats[ $params['cat_id'][0] ]['image_order'];
351    }
352    $order_by = empty($order_by) ? $conf['order_by'] : 'ORDER BY '.$order_by;
353
354    $query = '
355SELECT i.*, GROUP_CONCAT(category_id) AS cat_ids
356  FROM '.IMAGES_TABLE.' i
357    INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON i.id=image_id
358  WHERE '. implode('
359    AND ', $where_clauses).'
360GROUP BY i.id
361'.$order_by.'
362LIMIT '.(int)$params['per_page'].' OFFSET '.(int)($params['per_page']*$params['page']);
363
364    $result = pwg_query($query);
365    while ($row = pwg_db_fetch_assoc($result))
366    {
367      $image = array();
368      foreach ( array('id', 'width', 'height', 'hit') as $k )
369      {
370        if (isset($row[$k]))
371        {
372          $image[$k] = (int)$row[$k];
373        }
374      }
375      foreach ( array('file', 'name', 'comment', 'date_creation', 'date_available') as $k )
376      {
377        $image[$k] = $row[$k];
378      }
379      $image = array_merge( $image, ws_std_get_urls($row) );
380
381      $image_cats = array();
382      foreach ( explode(',', $row['cat_ids']) as $cat_id )
383      {
384        $url = make_index_url(
385                array(
386                  'category' => $cats[$cat_id],
387                  )
388                );
389        $page_url = make_picture_url(
390                array(
391                  'category' => $cats[$cat_id],
392                  'image_id' => $row['id'],
393                  'image_file' => $row['file'],
394                  )
395                );
396        array_push( $image_cats,  array(
397              WS_XML_ATTRIBUTES => array (
398                  'id' => (int)$cat_id,
399                  'url' => $url,
400                  'page_url' => $page_url,
401                )
402            )
403          );
404      }
405
406      $image['categories'] = new PwgNamedArray(
407            $image_cats,'category', array('id','url','page_url')
408          );
409      array_push($images, $image);
410    }
411  }
412
413  return array( 'images' =>
414    array (
415      WS_XML_ATTRIBUTES =>
416        array(
417            'page' => $params['page'],
418            'per_page' => $params['per_page'],
419            'count' => count($images)
420          ),
421       WS_XML_CONTENT => new PwgNamedArray($images, 'image',
422          ws_std_get_image_xml_attributes() )
423      )
424    );
425}
426
427
428/**
429 * returns a list of categories (web service method)
430 */
431function ws_categories_getList($params, &$service)
432{
433  global $user,$conf;
434
435  if ($params['tree_output'])
436  {
437    if (!isset($_GET['format']) or !in_array($_GET['format'], array('php', 'json')))
438    {
439      // the algorithm used to build a tree from a flat list of categories
440      // keeps original array keys, which is not compatible with
441      // PwgNamedArray.
442      //
443      // PwgNamedArray is useful to define which data is an attribute and
444      // which is an element in the XML output. The "hierarchy" output is
445      // only compatible with json/php output.
446
447      return new PwgError(405, "The tree_output option is only compatible with json/php output formats");
448    }
449  }
450
451  $where = array('1=1');
452  $join_type = 'INNER';
453  $join_user = $user['id'];
454
455  if (!$params['recursive'])
456  {
457    if ($params['cat_id']>0)
458      $where[] = '(id_uppercat='.(int)($params['cat_id']).'
459    OR id='.(int)($params['cat_id']).')';
460    else
461      $where[] = 'id_uppercat IS NULL';
462  }
463  else if ($params['cat_id']>0)
464  {
465    $where[] = 'uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.
466      (int)($params['cat_id'])
467      .'(,|$)\'';
468  }
469
470  if ($params['public'])
471  {
472    $where[] = 'status = "public"';
473    $where[] = 'visible = "true"';
474
475    $join_user = $conf['guest_id'];
476  }
477  elseif (is_admin())
478  {
479    // in this very specific case, we don't want to hide empty
480    // categories. Function calculate_permissions will only return
481    // categories that are either locked or private and not permitted
482    //
483    // calculate_permissions does not consider empty categories as forbidden
484    $forbidden_categories = calculate_permissions($user['id'], $user['status']);
485    $where[]= 'id NOT IN ('.$forbidden_categories.')';
486    $join_type = 'LEFT';
487  }
488
489  $query = '
490SELECT id, name, permalink, uppercats, global_rank, id_uppercat,
491    comment,
492    nb_images, count_images AS total_nb_images,
493    date_last, max_date_last, count_categories AS nb_categories
494  FROM '.CATEGORIES_TABLE.'
495   '.$join_type.' JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON id=cat_id AND user_id='.$join_user.'
496  WHERE '. implode('
497    AND ', $where);
498
499  $result = pwg_query($query);
500
501  $cats = array();
502  while ($row = pwg_db_fetch_assoc($result))
503  {
504    $row['url'] = make_index_url(
505        array(
506          'category' => $row
507          )
508      );
509    foreach( array('id','nb_images','total_nb_images','nb_categories') as $key)
510    {
511      $row[$key] = (int)$row[$key];
512    }
513
514    if ($params['fullname'])
515    {
516      $row['name'] = strip_tags(get_cat_display_name_cache($row['uppercats'], null, false));
517    }
518    else
519    {
520      $row['name'] = strip_tags(
521        trigger_event(
522          'render_category_name',
523          $row['name'],
524          'ws_categories_getList'
525          )
526        );
527    }
528
529    $row['comment'] = strip_tags(
530      trigger_event(
531        'render_category_description',
532        $row['comment'],
533        'ws_categories_getList'
534        )
535      );
536
537    array_push($cats, $row);
538  }
539  usort($cats, 'global_rank_compare');
540
541  if ($params['tree_output'])
542  {
543    return categories_flatlist_to_tree($cats);
544  }
545  else
546  {
547    return array(
548      'categories' => new PwgNamedArray(
549        $cats,
550        'category',
551        array(
552          'id',
553          'url',
554          'nb_images',
555          'total_nb_images',
556          'nb_categories',
557          'date_last',
558          'max_date_last',
559          )
560        )
561      );
562  }
563}
564
565/**
566 * returns the list of categories as you can see them in administration (web
567 * service method).
568 *
569 * Only admin can run this method and permissions are not taken into
570 * account.
571 */
572function ws_categories_getAdminList($params, &$service)
573{
574  if (!is_admin())
575  {
576    return new PwgError(401, 'Access denied');
577  }
578
579  $query = '
580SELECT
581    category_id,
582    COUNT(*) AS counter
583  FROM '.IMAGE_CATEGORY_TABLE.'
584  GROUP BY category_id
585;';
586  $nb_images_of = simple_hash_from_query($query, 'category_id', 'counter');
587
588  $query = '
589SELECT
590    id,
591    name,
592    comment,
593    uppercats,
594    global_rank
595  FROM '.CATEGORIES_TABLE.'
596;';
597  $result = pwg_query($query);
598  $cats = array();
599
600  while ($row = pwg_db_fetch_assoc($result))
601  {
602    $id = $row['id'];
603    $row['nb_images'] = isset($nb_images_of[$id]) ? $nb_images_of[$id] : 0;
604    $row['name'] = strip_tags(
605      trigger_event(
606        'render_category_name',
607        $row['name'],
608        'ws_categories_getAdminList'
609        )
610      );
611    $row['comment'] = strip_tags(
612      trigger_event(
613        'render_category_description',
614        $row['comment'],
615        'ws_categories_getAdminList'
616        )
617      );
618    array_push($cats, $row);
619  }
620
621  usort($cats, 'global_rank_compare');
622  return array(
623    'categories' => new PwgNamedArray(
624      $cats,
625      'category',
626      array(
627        'id',
628        'nb_images',
629        'name',
630        'uppercats',
631        'global_rank',
632        )
633      )
634    );
635}
636
637/**
638 * returns detailed information for an element (web service method)
639 */
640function ws_images_addComment($params, &$service)
641{
642  if (!$service->isPost())
643  {
644    return new PwgError(405, "This method requires HTTP POST");
645  }
646  $params['image_id'] = (int)$params['image_id'];
647  $query = '
648SELECT DISTINCT image_id
649  FROM '.IMAGE_CATEGORY_TABLE.' INNER JOIN '.CATEGORIES_TABLE.' ON category_id=id
650  WHERE commentable="true"
651    AND image_id='.$params['image_id'].
652    get_sql_condition_FandF(
653      array(
654        'forbidden_categories' => 'id',
655        'visible_categories' => 'id',
656        'visible_images' => 'image_id'
657      ),
658      ' AND'
659    );
660  if ( !pwg_db_num_rows( pwg_query( $query ) ) )
661  {
662    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
663  }
664
665  $comm = array(
666    'author' => trim( $params['author'] ),
667    'content' => trim( $params['content'] ),
668    'image_id' => $params['image_id'],
669   );
670
671  include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php');
672
673  $comment_action = insert_user_comment(
674      $comm, $params['key'], $infos
675    );
676
677  switch ($comment_action)
678  {
679    case 'reject':
680      array_push($infos, l10n('Your comment has NOT been registered because it did not pass the validation rules') );
681      return new PwgError(403, implode("; ", $infos) );
682    case 'validate':
683    case 'moderate':
684      $ret = array(
685          'id' => $comm['id'],
686          'validation' => $comment_action=='validate',
687        );
688      return new PwgNamedStruct(
689          'comment',
690          $ret,
691          null, array()
692        );
693    default:
694      return new PwgError(500, "Unknown comment action ".$comment_action );
695  }
696}
697
698/**
699 * returns detailed information for an element (web service method)
700 */
701function ws_images_getInfo($params, &$service)
702{
703  @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
704  global $user, $conf;
705  $params['image_id'] = (int)$params['image_id'];
706  if ( $params['image_id']<=0 )
707  {
708    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
709  }
710
711  $query='
712SELECT * FROM '.IMAGES_TABLE.'
713  WHERE id='.$params['image_id'].
714    get_sql_condition_FandF(
715      array('visible_images' => 'id'),
716      ' AND'
717    ).'
718LIMIT 1';
719
720  $image_row = pwg_db_fetch_assoc(pwg_query($query));
721  if ($image_row==null)
722  {
723    return new PwgError(404, "image_id not found");
724  }
725  $image_row = array_merge( $image_row, ws_std_get_urls($image_row) );
726
727  //-------------------------------------------------------- related categories
728  $query = '
729SELECT id, name, permalink, uppercats, global_rank, commentable
730  FROM '.IMAGE_CATEGORY_TABLE.'
731    INNER JOIN '.CATEGORIES_TABLE.' ON category_id = id
732  WHERE image_id = '.$image_row['id'].
733  get_sql_condition_FandF(
734      array( 'forbidden_categories' => 'category_id' ),
735      ' AND'
736    ).'
737;';
738  $result = pwg_query($query);
739  $is_commentable = false;
740  $related_categories = array();
741  while ($row = pwg_db_fetch_assoc($result))
742  {
743    if ($row['commentable']=='true')
744    {
745      $is_commentable = true;
746    }
747    unset($row['commentable']);
748    $row['url'] = make_index_url(
749        array(
750          'category' => $row
751          )
752      );
753
754    $row['page_url'] = make_picture_url(
755        array(
756          'image_id' => $image_row['id'],
757          'image_file' => $image_row['file'],
758          'category' => $row
759          )
760      );
761    $row['id']=(int)$row['id'];
762    array_push($related_categories, $row);
763  }
764  usort($related_categories, 'global_rank_compare');
765  if ( empty($related_categories) )
766  {
767    return new PwgError(401, 'Access denied');
768  }
769
770  //-------------------------------------------------------------- related tags
771  $related_tags = get_common_tags( array($image_row['id']), -1 );
772  foreach( $related_tags as $i=>$tag)
773  {
774    $tag['url'] = make_index_url(
775        array(
776          'tags' => array($tag)
777          )
778      );
779    $tag['page_url'] = make_picture_url(
780        array(
781          'image_id' => $image_row['id'],
782          'image_file' => $image_row['file'],
783          'tags' => array($tag),
784          )
785      );
786    unset($tag['counter']);
787    $tag['id']=(int)$tag['id'];
788    $related_tags[$i]=$tag;
789  }
790  //------------------------------------------------------------- related rates
791        $rating = array('score'=>$image_row['rating_score'], 'count'=>0, 'average'=>null);
792        if (isset($rating['score']))
793        {
794                $query = '
795SELECT COUNT(rate) AS count
796     , ROUND(AVG(rate),2) AS average
797  FROM '.RATE_TABLE.'
798  WHERE element_id = '.$image_row['id'].'
799;';
800                $row = pwg_db_fetch_assoc(pwg_query($query));
801                $rating['score'] = (float)$rating['score'];
802                $rating['average'] = (float)$row['average'];
803                $rating['count'] = (int)$row['count'];
804        }
805
806  //---------------------------------------------------------- related comments
807  $related_comments = array();
808
809  $where_comments = 'image_id = '.$image_row['id'];
810  if ( !is_admin() )
811  {
812    $where_comments .= '
813    AND validated="true"';
814  }
815
816  $query = '
817SELECT COUNT(id) AS nb_comments
818  FROM '.COMMENTS_TABLE.'
819  WHERE '.$where_comments;
820  list($nb_comments) = array_from_query($query, 'nb_comments');
821  $nb_comments = (int)$nb_comments;
822
823  if ( $nb_comments>0 and $params['comments_per_page']>0 )
824  {
825    $query = '
826SELECT id, date, author, content
827  FROM '.COMMENTS_TABLE.'
828  WHERE '.$where_comments.'
829  ORDER BY date
830  LIMIT '.(int)$params['comments_per_page'].
831    ' OFFSET '.(int)($params['comments_per_page']*$params['comments_page']);
832
833    $result = pwg_query($query);
834    while ($row = pwg_db_fetch_assoc($result))
835    {
836      $row['id']=(int)$row['id'];
837      array_push($related_comments, $row);
838    }
839  }
840
841  $comment_post_data = null;
842  if ($is_commentable and
843      (!is_a_guest()
844        or (is_a_guest() and $conf['comments_forall'] )
845      )
846      )
847  {
848    $comment_post_data['author'] = stripslashes($user['username']);
849    $comment_post_data['key'] = get_ephemeral_key(2, $params['image_id']);
850  }
851
852  $ret = $image_row;
853  foreach ( array('id','width','height','hit','filesize') as $k )
854  {
855    if (isset($ret[$k]))
856    {
857      $ret[$k] = (int)$ret[$k];
858    }
859  }
860  foreach ( array('path', 'storage_category_id') as $k )
861  {
862    unset($ret[$k]);
863  }
864
865  $ret['rates'] = array( WS_XML_ATTRIBUTES => $rating );
866  $ret['categories'] = new PwgNamedArray($related_categories, 'category', array('id','url', 'page_url') );
867  $ret['tags'] = new PwgNamedArray($related_tags, 'tag', array('id','url_name','url','name','page_url') );
868  if ( isset($comment_post_data) )
869  {
870    $ret['comment_post'] = array( WS_XML_ATTRIBUTES => $comment_post_data );
871  }
872  $ret['comments'] = array(
873     WS_XML_ATTRIBUTES =>
874        array(
875          'page' => $params['comments_page'],
876          'per_page' => $params['comments_per_page'],
877          'count' => count($related_comments),
878          'nb_comments' => $nb_comments,
879        ),
880     WS_XML_CONTENT => new PwgNamedArray($related_comments, 'comment', array('id','date') )
881      );
882
883  return new PwgNamedStruct('image',$ret, null, array('name','comment') );
884}
885
886
887/**
888 * rates the image_id in the parameter
889 */
890function ws_images_Rate($params, &$service)
891{
892  $image_id = (int)$params['image_id'];
893  $query = '
894SELECT DISTINCT id FROM '.IMAGES_TABLE.'
895  INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id=image_id
896  WHERE id='.$image_id
897  .get_sql_condition_FandF(
898    array(
899        'forbidden_categories' => 'category_id',
900        'forbidden_images' => 'id',
901      ),
902    '    AND'
903    ).'
904    LIMIT 1';
905  if ( pwg_db_num_rows( pwg_query($query) )==0 )
906  {
907    return new PwgError(404, "Invalid image_id or access denied" );
908  }
909  $rate = (int)$params['rate'];
910  include_once(PHPWG_ROOT_PATH.'include/functions_rate.inc.php');
911  $res = rate_picture( $image_id, $rate );
912  if ($res==false)
913  {
914    global $conf;
915    return new PwgError( 403, "Forbidden or rate not in ". implode(',',$conf['rate_items']));
916  }
917  return $res;
918}
919
920
921/**
922 * returns a list of elements corresponding to a query search
923 */
924function ws_images_search($params, &$service)
925{
926  global $page;
927  $images = array();
928  include_once( PHPWG_ROOT_PATH .'include/functions_search.inc.php' );
929  include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
930
931  $where_clauses = ws_std_image_sql_filter( $params, 'i.' );
932  $order_by = ws_std_image_sql_order($params, 'i.');
933
934  $super_order_by = false;
935  if ( !empty($order_by) )
936  {
937    global $conf;
938    $conf['order_by'] = 'ORDER BY '.$order_by;
939    $super_order_by=true; // quick_search_result might be faster
940  }
941
942  $search_result = get_quick_search_results($params['query'],
943      $super_order_by,
944      implode(',', $where_clauses)
945    );
946
947  $image_ids = array_slice(
948      $search_result['items'],
949      $params['page']*$params['per_page'],
950      $params['per_page']
951    );
952
953  if ( count($image_ids) )
954  {
955    $query = '
956SELECT * FROM '.IMAGES_TABLE.'
957  WHERE id IN ('.implode(',', $image_ids).')';
958
959    $image_ids = array_flip($image_ids);
960    $result = pwg_query($query);
961    while ($row = pwg_db_fetch_assoc($result))
962    {
963      $image = array();
964      foreach ( array('id', 'width', 'height', 'hit') as $k )
965      {
966        if (isset($row[$k]))
967        {
968          $image[$k] = (int)$row[$k];
969        }
970      }
971      foreach ( array('file', 'name', 'comment', 'date_creation', 'date_available') as $k )
972      {
973        $image[$k] = $row[$k];
974      }
975      $image = array_merge( $image, ws_std_get_urls($row) );
976      $images[$image_ids[$image['id']]] = $image;
977    }
978    ksort($images, SORT_NUMERIC);
979    $images = array_values($images);
980  }
981
982
983  return array( 'images' =>
984    array (
985      WS_XML_ATTRIBUTES =>
986        array(
987            'page' => $params['page'],
988            'per_page' => $params['per_page'],
989            'count' => count($images)
990          ),
991       WS_XML_CONTENT => new PwgNamedArray($images, 'image',
992          ws_std_get_image_xml_attributes() )
993      )
994    );
995}
996
997function ws_images_setPrivacyLevel($params, &$service)
998{
999  if (!is_admin())
1000  {
1001    return new PwgError(401, 'Access denied');
1002  }
1003  if (!$service->isPost())
1004  {
1005    return new PwgError(405, "This method requires HTTP POST");
1006  }
1007  $params['image_id'] = array_map( 'intval',$params['image_id'] );
1008  if ( empty($params['image_id']) )
1009  {
1010    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
1011  }
1012  global $conf;
1013  if ( !in_array( (int)$params['level'], $conf['available_permission_levels']) )
1014  {
1015    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid level");
1016  }
1017
1018  $query = '
1019UPDATE '.IMAGES_TABLE.'
1020  SET level='.(int)$params['level'].'
1021  WHERE id IN ('.implode(',',$params['image_id']).')';
1022  $result = pwg_query($query);
1023  $affected_rows = pwg_db_changes($result);
1024  if ($affected_rows)
1025  {
1026    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1027    invalidate_user_cache();
1028  }
1029  return $affected_rows;
1030}
1031
1032function ws_images_setRank($params, &$service)
1033{
1034  if (!is_admin())
1035  {
1036    return new PwgError(401, 'Access denied');
1037  }
1038
1039  if (!$service->isPost())
1040  {
1041    return new PwgError(405, "This method requires HTTP POST");
1042  }
1043
1044  // is the image_id valid?
1045  $params['image_id'] = (int)$params['image_id'];
1046  if ($params['image_id'] <= 0)
1047  {
1048    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
1049  }
1050
1051  // is the category valid?
1052  $params['category_id'] = (int)$params['category_id'];
1053  if ($params['category_id'] <= 0)
1054  {
1055    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid category_id");
1056  }
1057
1058  // is the rank valid?
1059  $params['rank'] = (int)$params['rank'];
1060  if ($params['rank'] <= 0)
1061  {
1062    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid rank");
1063  }
1064
1065  // does the image really exist?
1066  $query='
1067SELECT
1068    *
1069  FROM '.IMAGES_TABLE.'
1070  WHERE id = '.$params['image_id'].'
1071;';
1072
1073  $image_row = pwg_db_fetch_assoc(pwg_query($query));
1074  if ($image_row == null)
1075  {
1076    return new PwgError(404, "image_id not found");
1077  }
1078
1079  // is the image associated to this category?
1080  $query = '
1081SELECT
1082    image_id,
1083    category_id,
1084    rank
1085  FROM '.IMAGE_CATEGORY_TABLE.'
1086  WHERE image_id = '.$params['image_id'].'
1087    AND category_id = '.$params['category_id'].'
1088;';
1089  $category_row = pwg_db_fetch_assoc(pwg_query($query));
1090  if ($category_row == null)
1091  {
1092    return new PwgError(404, "This image is not associated to this category");
1093  }
1094
1095  // what is the current higher rank for this category?
1096  $query = '
1097SELECT
1098    MAX(rank) AS max_rank
1099  FROM '.IMAGE_CATEGORY_TABLE.'
1100  WHERE category_id = '.$params['category_id'].'
1101;';
1102  $result = pwg_query($query);
1103  $row = pwg_db_fetch_assoc($result);
1104
1105  if (is_numeric($row['max_rank']))
1106  {
1107    if ($params['rank'] > $row['max_rank'])
1108    {
1109      $params['rank'] = $row['max_rank'] + 1;
1110    }
1111  }
1112  else
1113  {
1114    $params['rank'] = 1;
1115  }
1116
1117  // update rank for all other photos in the same category
1118  $query = '
1119UPDATE '.IMAGE_CATEGORY_TABLE.'
1120  SET rank = rank + 1
1121  WHERE category_id = '.$params['category_id'].'
1122    AND rank IS NOT NULL
1123    AND rank >= '.$params['rank'].'
1124;';
1125  pwg_query($query);
1126
1127  // set the new rank for the photo
1128  $query = '
1129UPDATE '.IMAGE_CATEGORY_TABLE.'
1130  SET rank = '.$params['rank'].'
1131  WHERE image_id = '.$params['image_id'].'
1132    AND category_id = '.$params['category_id'].'
1133;';
1134  pwg_query($query);
1135
1136  // return data for client
1137  return array(
1138    'image_id' => $params['image_id'],
1139    'category_id' => $params['category_id'],
1140    'rank' => $params['rank'],
1141    );
1142}
1143
1144function ws_images_add_chunk($params, &$service)
1145{
1146  global $conf;
1147
1148  ws_logfile('[ws_images_add_chunk] welcome');
1149  // data
1150  // original_sum
1151  // type {thumb, file, high}
1152  // position
1153
1154  if (!is_admin())
1155  {
1156    return new PwgError(401, 'Access denied');
1157  }
1158
1159  if (!$service->isPost())
1160  {
1161    return new PwgError(405, "This method requires HTTP POST");
1162  }
1163
1164  foreach ($params as $param_key => $param_value) {
1165    if ('data' == $param_key) {
1166      continue;
1167    }
1168
1169    ws_logfile(
1170      sprintf(
1171        '[ws_images_add_chunk] input param "%s" : "%s"',
1172        $param_key,
1173        is_null($param_value) ? 'NULL' : $param_value
1174        )
1175      );
1176  }
1177
1178  $upload_dir = $conf['upload_dir'].'/buffer';
1179
1180  // create the upload directory tree if not exists
1181  if (!is_dir($upload_dir)) {
1182    umask(0000);
1183    $recursive = true;
1184    if (!@mkdir($upload_dir, 0777, $recursive))
1185    {
1186      return new PwgError(500, 'error during buffer directory creation');
1187    }
1188  }
1189
1190  if (!is_writable($upload_dir))
1191  {
1192    // last chance to make the directory writable
1193    @chmod($upload_dir, 0777);
1194
1195    if (!is_writable($upload_dir))
1196    {
1197      return new PwgError(500, 'buffer directory has no write access');
1198    }
1199  }
1200
1201  secure_directory($upload_dir);
1202
1203  $filename = sprintf(
1204    '%s-%s-%05u.block',
1205    $params['original_sum'],
1206    $params['type'],
1207    $params['position']
1208    );
1209
1210  ws_logfile('[ws_images_add_chunk] data length : '.strlen($params['data']));
1211
1212  $bytes_written = file_put_contents(
1213    $upload_dir.'/'.$filename,
1214    base64_decode($params['data'])
1215    );
1216
1217  if (false === $bytes_written) {
1218    return new PwgError(
1219      500,
1220      'an error has occured while writting chunk '.$params['position'].' for '.$params['type']
1221      );
1222  }
1223}
1224
1225function merge_chunks($output_filepath, $original_sum, $type)
1226{
1227  global $conf;
1228
1229  ws_logfile('[merge_chunks] input parameter $output_filepath : '.$output_filepath);
1230
1231  if (is_file($output_filepath))
1232  {
1233    unlink($output_filepath);
1234
1235    if (is_file($output_filepath))
1236    {
1237      new PwgError(500, '[merge_chunks] error while trying to remove existing '.$output_filepath);
1238      exit();
1239    }
1240  }
1241
1242  $upload_dir = $conf['upload_dir'].'/buffer';
1243  $pattern = '/'.$original_sum.'-'.$type.'/';
1244  $chunks = array();
1245
1246  if ($handle = opendir($upload_dir))
1247  {
1248    while (false !== ($file = readdir($handle)))
1249    {
1250      if (preg_match($pattern, $file))
1251      {
1252        ws_logfile($file);
1253        array_push($chunks, $upload_dir.'/'.$file);
1254      }
1255    }
1256    closedir($handle);
1257  }
1258
1259  sort($chunks);
1260
1261  if (function_exists('memory_get_usage')) {
1262    ws_logfile('[merge_chunks] memory_get_usage before loading chunks: '.memory_get_usage());
1263  }
1264
1265  $i = 0;
1266
1267  foreach ($chunks as $chunk)
1268  {
1269    $string = file_get_contents($chunk);
1270
1271    if (function_exists('memory_get_usage')) {
1272      ws_logfile('[merge_chunks] memory_get_usage on chunk '.++$i.': '.memory_get_usage());
1273    }
1274
1275    if (!file_put_contents($output_filepath, $string, FILE_APPEND))
1276    {
1277      new PwgError(500, '[merge_chunks] error while writting chunks for '.$output_filepath);
1278      exit();
1279    }
1280
1281    unlink($chunk);
1282  }
1283
1284  if (function_exists('memory_get_usage')) {
1285    ws_logfile('[merge_chunks] memory_get_usage after loading chunks: '.memory_get_usage());
1286  }
1287}
1288
1289/*
1290 * The $file_path must be the path of the basic "web sized" photo
1291 * The $type value will automatically modify the $file_path to the corresponding file
1292 */
1293function add_file($file_path, $type, $original_sum, $file_sum)
1294{
1295  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
1296
1297  $file_path = file_path_for_type($file_path, $type);
1298
1299  $upload_dir = dirname($file_path);
1300  if (substr(PHP_OS, 0, 3) == 'WIN')
1301  {
1302    $upload_dir = str_replace('/', DIRECTORY_SEPARATOR, $upload_dir);
1303  }
1304
1305  ws_logfile('[add_file] file_path  : '.$file_path);
1306  ws_logfile('[add_file] upload_dir : '.$upload_dir);
1307
1308  if (!is_dir($upload_dir)) {
1309    umask(0000);
1310    $recursive = true;
1311    if (!@mkdir($upload_dir, 0777, $recursive))
1312    {
1313      new PwgError(500, '[add_file] error during '.$type.' directory creation');
1314      exit();
1315    }
1316  }
1317
1318  if (!is_writable($upload_dir))
1319  {
1320    // last chance to make the directory writable
1321    @chmod($upload_dir, 0777);
1322
1323    if (!is_writable($upload_dir))
1324    {
1325      new PwgError(500, '[add_file] '.$type.' directory has no write access');
1326      exit();
1327    }
1328  }
1329
1330  secure_directory($upload_dir);
1331
1332  // merge the thumbnail
1333  merge_chunks($file_path, $original_sum, $type);
1334  chmod($file_path, 0644);
1335
1336  // check dumped thumbnail md5
1337  $dumped_md5 = md5_file($file_path);
1338  if ($dumped_md5 != $file_sum) {
1339    new PwgError(500, '[add_file] '.$type.' transfer failed');
1340    exit();
1341  }
1342
1343  list($width, $height) = getimagesize($file_path);
1344  $filesize = floor(filesize($file_path)/1024);
1345
1346  return array(
1347    'width' => $width,
1348    'height' => $height,
1349    'filesize' => $filesize,
1350    );
1351}
1352
1353function ws_images_addFile($params, &$service)
1354{
1355  // image_id
1356  // type {thumb, file, high}
1357  // sum
1358
1359  global $conf;
1360  if (!is_admin())
1361  {
1362    return new PwgError(401, 'Access denied');
1363  }
1364
1365  $params['image_id'] = (int)$params['image_id'];
1366  if ($params['image_id'] <= 0)
1367  {
1368    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
1369  }
1370
1371  //
1372  // what is the path?
1373  //
1374  $query = '
1375SELECT
1376    path,
1377    md5sum
1378  FROM '.IMAGES_TABLE.'
1379  WHERE id = '.$params['image_id'].'
1380;';
1381  list($file_path, $original_sum) = pwg_db_fetch_row(pwg_query($query));
1382
1383  // TODO only files added with web API can be updated with web API
1384
1385  //
1386  // makes sure directories are there and call the merge_chunks
1387  //
1388  $infos = add_file($file_path, $params['type'], $original_sum, $params['sum']);
1389
1390  //
1391  // update basic metadata from file
1392  //
1393  $update = array();
1394
1395  if ('high' == $params['type'])
1396  {
1397    $update['high_filesize'] = $infos['filesize'];
1398    $update['high_width'] = $infos['width'];
1399    $update['high_height'] = $infos['height'];
1400    $update['has_high'] = 'true';
1401  }
1402
1403  if ('file' == $params['type'])
1404  {
1405    $update['filesize'] = $infos['filesize'];
1406    $update['width'] = $infos['width'];
1407    $update['height'] = $infos['height'];
1408  }
1409
1410  // we may have nothing to update at database level, for example with a
1411  // thumbnail update
1412  if (count($update) > 0)
1413  {
1414    $update['id'] = $params['image_id'];
1415
1416    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1417    mass_updates(
1418      IMAGES_TABLE,
1419      array(
1420        'primary' => array('id'),
1421        'update'  => array_diff(array_keys($update), array('id'))
1422        ),
1423      array($update)
1424      );
1425  }
1426}
1427
1428function ws_images_add($params, &$service)
1429{
1430  global $conf, $user;
1431  if (!is_admin())
1432  {
1433    return new PwgError(401, 'Access denied');
1434  }
1435
1436  foreach ($params as $param_key => $param_value) {
1437    ws_logfile(
1438      sprintf(
1439        '[pwg.images.add] input param "%s" : "%s"',
1440        $param_key,
1441        is_null($param_value) ? 'NULL' : $param_value
1442        )
1443      );
1444  }
1445
1446  // does the image already exists ?
1447  if ('md5sum' == $conf['uniqueness_mode'])
1448  {
1449    $where_clause = "md5sum = '".$params['original_sum']."'";
1450  }
1451  if ('filename' == $conf['uniqueness_mode'])
1452  {
1453    $where_clause = "file = '".$params['original_filename']."'";
1454  }
1455
1456  $query = '
1457SELECT
1458    COUNT(*) AS counter
1459  FROM '.IMAGES_TABLE.'
1460  WHERE '.$where_clause.'
1461;';
1462  list($counter) = pwg_db_fetch_row(pwg_query($query));
1463  if ($counter != 0) {
1464    return new PwgError(500, 'file already exists');
1465  }
1466
1467  // current date
1468  list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
1469  list($year, $month, $day) = preg_split('/[^\d]/', $dbnow, 4);
1470
1471  // upload directory hierarchy
1472  $upload_dir = sprintf(
1473    $conf['upload_dir'].'/%s/%s/%s',
1474    $year,
1475    $month,
1476    $day
1477    );
1478
1479  // compute file path
1480  $date_string = preg_replace('/[^\d]/', '', $dbnow);
1481  $random_string = substr($params['file_sum'], 0, 8);
1482  $filename_wo_ext = $date_string.'-'.$random_string;
1483  $file_path = $upload_dir.'/'.$filename_wo_ext.'.jpg';
1484
1485  // add files
1486  $file_infos  = add_file($file_path, 'file',  $params['original_sum'], $params['file_sum']);
1487  $thumb_infos = add_file($file_path, 'thumb', $params['original_sum'], $params['thumbnail_sum']);
1488
1489  if (isset($params['high_sum']))
1490  {
1491    $high_infos = add_file($file_path, 'high', $params['original_sum'], $params['high_sum']);
1492  }
1493
1494  // database registration
1495  $insert = array(
1496    'file' => !empty($params['original_filename']) ? $params['original_filename'] : $filename_wo_ext.'.jpg',
1497    'date_available' => $dbnow,
1498    'tn_ext' => 'jpg',
1499    'name' => $params['name'],
1500    'path' => $file_path,
1501    'filesize' => $file_infos['filesize'],
1502    'width' => $file_infos['width'],
1503    'height' => $file_infos['height'],
1504    'md5sum' => $params['original_sum'],
1505    'added_by' => $user['id'],
1506    );
1507
1508  $info_columns = array(
1509    'name',
1510    'author',
1511    'comment',
1512    'level',
1513    'date_creation',
1514    );
1515
1516  foreach ($info_columns as $key)
1517  {
1518    if (isset($params[$key]))
1519    {
1520      $insert[$key] = $params[$key];
1521    }
1522  }
1523
1524  if (isset($params['high_sum']))
1525  {
1526    $insert['has_high'] = 'true';
1527    $insert['high_filesize'] = $high_infos['filesize'];
1528    $insert['high_width'] = $high_infos['width'];
1529    $insert['high_height'] = $high_infos['height'];
1530  }
1531
1532  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1533  mass_inserts(
1534    IMAGES_TABLE,
1535    array_keys($insert),
1536    array($insert)
1537    );
1538
1539  $image_id = pwg_db_insert_id(IMAGES_TABLE);
1540
1541  // let's add links between the image and the categories
1542  if (isset($params['categories']))
1543  {
1544    ws_add_image_category_relations($image_id, $params['categories']);
1545  }
1546
1547  // and now, let's create tag associations
1548  if (isset($params['tag_ids']) and !empty($params['tag_ids']))
1549  {
1550    set_tags(
1551      explode(',', $params['tag_ids']),
1552      $image_id
1553      );
1554  }
1555
1556  // update metadata from the uploaded file (exif/iptc)
1557  require_once(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
1558  update_metadata(array($image_id=>$file_path));
1559
1560  invalidate_user_cache();
1561}
1562
1563function ws_images_addSimple($params, &$service)
1564{
1565  global $conf;
1566  if (!is_admin())
1567  {
1568    return new PwgError(401, 'Access denied');
1569  }
1570
1571  if (!$service->isPost())
1572  {
1573    return new PwgError(405, "This method requires HTTP POST");
1574  }
1575
1576  if (!isset($_FILES['image']))
1577  {
1578    return new PwgError(405, "The image (file) parameter is missing");
1579  }
1580
1581  $params['image_id'] = (int)$params['image_id'];
1582  if ($params['image_id'] > 0)
1583  {
1584    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1585
1586    $query='
1587SELECT *
1588  FROM '.IMAGES_TABLE.'
1589  WHERE id = '.$params['image_id'].'
1590;';
1591
1592    $image_row = pwg_db_fetch_assoc(pwg_query($query));
1593    if ($image_row == null)
1594    {
1595      return new PwgError(404, "image_id not found");
1596    }
1597  }
1598
1599  // category
1600  $params['category'] = (int)$params['category'];
1601  if ($params['category'] <= 0 and $params['image_id'] <= 0)
1602  {
1603    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid category_id");
1604  }
1605
1606  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
1607
1608  $image_id = add_uploaded_file(
1609    $_FILES['image']['tmp_name'],
1610    $_FILES['image']['name'],
1611    $params['category'] > 0 ? array($params['category']) : null,
1612    8,
1613    $params['image_id'] > 0 ? $params['image_id'] : null
1614    );
1615
1616  $info_columns = array(
1617    'name',
1618    'author',
1619    'comment',
1620    'level',
1621    'date_creation',
1622    );
1623
1624  foreach ($info_columns as $key)
1625  {
1626    if (isset($params[$key]))
1627    {
1628      $update[$key] = $params[$key];
1629    }
1630  }
1631
1632  if (count(array_keys($update)) > 0)
1633  {
1634    $update['id'] = $image_id;
1635
1636    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1637    mass_updates(
1638      IMAGES_TABLE,
1639      array(
1640        'primary' => array('id'),
1641        'update'  => array_diff(array_keys($update), array('id'))
1642        ),
1643      array($update)
1644      );
1645  }
1646
1647
1648  if (isset($params['tags']) and !empty($params['tags']))
1649  {
1650    $tag_ids = array();
1651    $tag_names = explode(',', $params['tags']);
1652    foreach ($tag_names as $tag_name)
1653    {
1654      $tag_id = tag_id_from_tag_name($tag_name);
1655      array_push($tag_ids, $tag_id);
1656    }
1657
1658    add_tags($tag_ids, array($image_id));
1659  }
1660
1661  $url_params = array('image_id' => $image_id);
1662
1663  if ($params['category'] > 0)
1664  {
1665    $query = '
1666SELECT id, name, permalink
1667  FROM '.CATEGORIES_TABLE.'
1668  WHERE id = '.$params['category'].'
1669;';
1670    $result = pwg_query($query);
1671    $category = pwg_db_fetch_assoc($result);
1672
1673    $url_params['section'] = 'categories';
1674    $url_params['category'] = $category;
1675  }
1676
1677  // update metadata from the uploaded file (exif/iptc), even if the sync
1678  // was already performed by add_uploaded_file().
1679  $query = '
1680SELECT
1681    path
1682  FROM '.IMAGES_TABLE.'
1683  WHERE id = '.$image_id.'
1684;';
1685  list($file_path) = pwg_db_fetch_row(pwg_query($query));
1686
1687  require_once(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
1688  update_metadata(array($image_id=>$file_path));
1689
1690  return array(
1691    'image_id' => $image_id,
1692    'url' => make_picture_url($url_params),
1693    );
1694}
1695
1696/**
1697 * perform a login (web service method)
1698 */
1699function ws_session_login($params, &$service)
1700{
1701  global $conf;
1702
1703  if (!$service->isPost())
1704  {
1705    return new PwgError(405, "This method requires HTTP POST");
1706  }
1707  if (try_log_user($params['username'], $params['password'],false))
1708  {
1709    return true;
1710  }
1711  return new PwgError(999, 'Invalid username/password');
1712}
1713
1714
1715/**
1716 * performs a logout (web service method)
1717 */
1718function ws_session_logout($params, &$service)
1719{
1720  if (!is_a_guest())
1721  {
1722    logout_user();
1723  }
1724  return true;
1725}
1726
1727function ws_session_getStatus($params, &$service)
1728{
1729  global $user;
1730  $res = array();
1731  $res['username'] = is_a_guest() ? 'guest' : stripslashes($user['username']);
1732  foreach ( array('status', 'theme', 'language') as $k )
1733  {
1734    $res[$k] = $user[$k];
1735  }
1736  $res['pwg_token'] = get_pwg_token();
1737  $res['charset'] = get_pwg_charset();
1738
1739  list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
1740  $res['current_datetime'] = $dbnow;
1741
1742  return $res;
1743}
1744
1745
1746/**
1747 * returns a list of tags (web service method)
1748 */
1749function ws_tags_getList($params, &$service)
1750{
1751  $tags = get_available_tags();
1752  if ($params['sort_by_counter'])
1753  {
1754    usort($tags, create_function('$a,$b', 'return -$a["counter"]+$b["counter"];') );
1755  }
1756  else
1757  {
1758    usort($tags, 'tag_alpha_compare');
1759  }
1760  for ($i=0; $i<count($tags); $i++)
1761  {
1762    $tags[$i]['id'] = (int)$tags[$i]['id'];
1763    $tags[$i]['counter'] = (int)$tags[$i]['counter'];
1764    $tags[$i]['url'] = make_index_url(
1765        array(
1766          'section'=>'tags',
1767          'tags'=>array($tags[$i])
1768        )
1769      );
1770  }
1771  return array('tags' => new PwgNamedArray($tags, 'tag', array('id','url_name','url', 'name', 'counter' )) );
1772}
1773
1774/**
1775 * returns the list of tags as you can see them in administration (web
1776 * service method).
1777 *
1778 * Only admin can run this method and permissions are not taken into
1779 * account.
1780 */
1781function ws_tags_getAdminList($params, &$service)
1782{
1783  if (!is_admin())
1784  {
1785    return new PwgError(401, 'Access denied');
1786  }
1787
1788  $tags = get_all_tags();
1789  return array(
1790    'tags' => new PwgNamedArray(
1791      $tags,
1792      'tag',
1793      array(
1794        'name',
1795        'id',
1796        'url_name',
1797        )
1798      )
1799    );
1800}
1801
1802/**
1803 * returns a list of images for tags (web service method)
1804 */
1805function ws_tags_getImages($params, &$service)
1806{
1807  @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
1808  global $conf;
1809
1810  // first build all the tag_ids we are interested in
1811  $params['tag_id'] = array_map( 'intval',$params['tag_id'] );
1812  $tags = find_tags($params['tag_id'], $params['tag_url_name'], $params['tag_name']);
1813  $tags_by_id = array();
1814  foreach( $tags as $tag )
1815  {
1816    $tags['id'] = (int)$tag['id'];
1817    $tags_by_id[ $tag['id'] ] = $tag;
1818  }
1819  unset($tags);
1820  $tag_ids = array_keys($tags_by_id);
1821
1822
1823  $where_clauses = ws_std_image_sql_filter($params);
1824  if (!empty($where_clauses))
1825  {
1826    $where_clauses = implode( ' AND ', $where_clauses);
1827  }
1828  $image_ids = get_image_ids_for_tags(
1829    $tag_ids,
1830    $params['tag_mode_and'] ? 'AND' : 'OR',
1831    $where_clauses,
1832    ws_std_image_sql_order($params) );
1833
1834
1835  $image_ids = array_slice($image_ids, (int)($params['per_page']*$params['page']), (int)$params['per_page'] );
1836
1837  $image_tag_map = array();
1838  if ( !empty($image_ids) and !$params['tag_mode_and'] )
1839  { // build list of image ids with associated tags per image
1840    $query = '
1841SELECT image_id, GROUP_CONCAT(tag_id) AS tag_ids
1842  FROM '.IMAGE_TAG_TABLE.'
1843  WHERE tag_id IN ('.implode(',',$tag_ids).') AND image_id IN ('.implode(',',$image_ids).')
1844  GROUP BY image_id';
1845    $result = pwg_query($query);
1846    while ( $row=pwg_db_fetch_assoc($result) )
1847    {
1848      $row['image_id'] = (int)$row['image_id'];
1849      array_push( $image_ids, $row['image_id'] );
1850      $image_tag_map[ $row['image_id'] ] = explode(',', $row['tag_ids']);
1851    }
1852  }
1853
1854  $images = array();
1855  if (!empty($image_ids))
1856  {
1857    $rank_of = array_flip($image_ids);
1858    $result = pwg_query('
1859SELECT * FROM '.IMAGES_TABLE.'
1860  WHERE id IN ('.implode(',',$image_ids).')');
1861    while ($row = pwg_db_fetch_assoc($result))
1862    {
1863      $image = array();
1864      $image['rank'] = $rank_of[ $row['id'] ];
1865      foreach ( array('id', 'width', 'height', 'hit') as $k )
1866      {
1867        if (isset($row[$k]))
1868        {
1869          $image[$k] = (int)$row[$k];
1870        }
1871      }
1872      foreach ( array('file', 'name', 'comment', 'date_creation', 'date_available') as $k )
1873      {
1874        $image[$k] = $row[$k];
1875      }
1876      $image = array_merge( $image, ws_std_get_urls($row) );
1877
1878      $image_tag_ids = ($params['tag_mode_and']) ? $tag_ids : $image_tag_map[$image['id']];
1879      $image_tags = array();
1880      foreach ($image_tag_ids as $tag_id)
1881      {
1882        $url = make_index_url(
1883                 array(
1884                  'section'=>'tags',
1885                  'tags'=> array($tags_by_id[$tag_id])
1886                )
1887              );
1888        $page_url = make_picture_url(
1889                 array(
1890                  'section'=>'tags',
1891                  'tags'=> array($tags_by_id[$tag_id]),
1892                  'image_id' => $row['id'],
1893                  'image_file' => $row['file'],
1894                )
1895              );
1896        array_push($image_tags, array(
1897                'id' => (int)$tag_id,
1898                'url' => $url,
1899                'page_url' => $page_url,
1900              )
1901            );
1902      }
1903      $image['tags'] = new PwgNamedArray($image_tags, 'tag',
1904              array('id','url_name','url','page_url')
1905            );
1906      array_push($images, $image);
1907    }
1908    usort($images, 'rank_compare');
1909    unset($rank_of);
1910  }
1911
1912  return array( 'images' =>
1913    array (
1914      WS_XML_ATTRIBUTES =>
1915        array(
1916            'page' => $params['page'],
1917            'per_page' => $params['per_page'],
1918            'count' => count($images)
1919          ),
1920       WS_XML_CONTENT => new PwgNamedArray($images, 'image',
1921          ws_std_get_image_xml_attributes() )
1922      )
1923    );
1924}
1925
1926function ws_categories_add($params, &$service)
1927{
1928  if (!is_admin())
1929  {
1930    return new PwgError(401, 'Access denied');
1931  }
1932
1933  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1934
1935  $creation_output = create_virtual_category(
1936    $params['name'],
1937    $params['parent']
1938    );
1939
1940  if (isset($creation_output['error']))
1941  {
1942    return new PwgError(500, $creation_output['error']);
1943  }
1944
1945  invalidate_user_cache();
1946
1947  return $creation_output;
1948}
1949
1950function ws_tags_add($params, &$service)
1951{
1952  if (!is_admin())
1953  {
1954    return new PwgError(401, 'Access denied');
1955  }
1956
1957  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1958
1959  $creation_output = create_tag($params['name']);
1960
1961  if (isset($creation_output['error']))
1962  {
1963    return new PwgError(500, $creation_output['error']);
1964  }
1965
1966  return $creation_output;
1967}
1968
1969function ws_images_exist($params, &$service)
1970{
1971  global $conf;
1972
1973  if (!is_admin())
1974  {
1975    return new PwgError(401, 'Access denied');
1976  }
1977
1978  $split_pattern = '/[\s,;\|]/';
1979
1980  if ('md5sum' == $conf['uniqueness_mode'])
1981  {
1982    // search among photos the list of photos already added, based on md5sum
1983    // list
1984    $md5sums = preg_split(
1985      $split_pattern,
1986      $params['md5sum_list'],
1987      -1,
1988      PREG_SPLIT_NO_EMPTY
1989    );
1990
1991    $query = '
1992SELECT
1993    id,
1994    md5sum
1995  FROM '.IMAGES_TABLE.'
1996  WHERE md5sum IN (\''.implode("','", $md5sums).'\')
1997;';
1998    $id_of_md5 = simple_hash_from_query($query, 'md5sum', 'id');
1999
2000    $result = array();
2001
2002    foreach ($md5sums as $md5sum)
2003    {
2004      $result[$md5sum] = null;
2005      if (isset($id_of_md5[$md5sum]))
2006      {
2007        $result[$md5sum] = $id_of_md5[$md5sum];
2008      }
2009    }
2010  }
2011
2012  if ('filename' == $conf['uniqueness_mode'])
2013  {
2014    // search among photos the list of photos already added, based on
2015    // filename list
2016    $filenames = preg_split(
2017      $split_pattern,
2018      $params['filename_list'],
2019      -1,
2020      PREG_SPLIT_NO_EMPTY
2021    );
2022
2023    $query = '
2024SELECT
2025    id,
2026    file
2027  FROM '.IMAGES_TABLE.'
2028  WHERE file IN (\''.implode("','", $filenames).'\')
2029;';
2030    $id_of_filename = simple_hash_from_query($query, 'file', 'id');
2031
2032    $result = array();
2033
2034    foreach ($filenames as $filename)
2035    {
2036      $result[$filename] = null;
2037      if (isset($id_of_filename[$filename]))
2038      {
2039        $result[$filename] = $id_of_filename[$filename];
2040      }
2041    }
2042  }
2043
2044  return $result;
2045}
2046
2047function ws_images_checkFiles($params, &$service)
2048{
2049  if (!is_admin())
2050  {
2051    return new PwgError(401, 'Access denied');
2052  }
2053
2054  // input parameters
2055  //
2056  // image_id
2057  // thumbnail_sum
2058  // file_sum
2059  // high_sum
2060
2061  $params['image_id'] = (int)$params['image_id'];
2062  if ($params['image_id'] <= 0)
2063  {
2064    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
2065  }
2066
2067  $query = '
2068SELECT
2069    path
2070  FROM '.IMAGES_TABLE.'
2071  WHERE id = '.$params['image_id'].'
2072;';
2073  $result = pwg_query($query);
2074  if (pwg_db_num_rows($result) == 0) {
2075    return new PwgError(404, "image_id not found");
2076  }
2077  list($path) = pwg_db_fetch_row($result);
2078
2079  $ret = array();
2080
2081  foreach (array('thumb', 'file', 'high') as $type) {
2082    $param_name = $type;
2083    if ('thumb' == $type) {
2084      $param_name = 'thumbnail';
2085    }
2086
2087    if (isset($params[$param_name.'_sum'])) {
2088      include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
2089      $type_path = file_path_for_type($path, $type);
2090      if (!is_file($type_path)) {
2091        $ret[$param_name] = 'missing';
2092      }
2093      else {
2094        if (md5_file($type_path) != $params[$param_name.'_sum']) {
2095          $ret[$param_name] = 'differs';
2096        }
2097        else {
2098          $ret[$param_name] = 'equals';
2099        }
2100      }
2101    }
2102  }
2103
2104  return $ret;
2105}
2106
2107function ws_images_setInfo($params, &$service)
2108{
2109  global $conf;
2110  if (!is_admin())
2111  {
2112    return new PwgError(401, 'Access denied');
2113  }
2114
2115  if (!$service->isPost())
2116  {
2117    return new PwgError(405, "This method requires HTTP POST");
2118  }
2119
2120  $params['image_id'] = (int)$params['image_id'];
2121  if ($params['image_id'] <= 0)
2122  {
2123    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
2124  }
2125
2126  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2127
2128  $query='
2129SELECT *
2130  FROM '.IMAGES_TABLE.'
2131  WHERE id = '.$params['image_id'].'
2132;';
2133
2134  $image_row = pwg_db_fetch_assoc(pwg_query($query));
2135  if ($image_row == null)
2136  {
2137    return new PwgError(404, "image_id not found");
2138  }
2139
2140  // database registration
2141  $update = array();
2142
2143  $info_columns = array(
2144    'name',
2145    'author',
2146    'comment',
2147    'level',
2148    'date_creation',
2149    );
2150
2151  foreach ($info_columns as $key)
2152  {
2153    if (isset($params[$key]))
2154    {
2155      if ('fill_if_empty' == $params['single_value_mode'])
2156      {
2157        if (empty($image_row[$key]))
2158        {
2159          $update[$key] = $params[$key];
2160        }
2161      }
2162      elseif ('replace' == $params['single_value_mode'])
2163      {
2164        $update[$key] = $params[$key];
2165      }
2166      else
2167      {
2168        new PwgError(
2169          500,
2170          '[ws_images_setInfo]'
2171          .' invalid parameter single_value_mode "'.$params['single_value_mode'].'"'
2172          .', possible values are {fill_if_empty, replace}.'
2173          );
2174        exit();
2175      }
2176    }
2177  }
2178
2179  if (count(array_keys($update)) > 0)
2180  {
2181    $update['id'] = $params['image_id'];
2182
2183    mass_updates(
2184      IMAGES_TABLE,
2185      array(
2186        'primary' => array('id'),
2187        'update'  => array_diff(array_keys($update), array('id'))
2188        ),
2189      array($update)
2190      );
2191  }
2192
2193  if (isset($params['categories']))
2194  {
2195    ws_add_image_category_relations(
2196      $params['image_id'],
2197      $params['categories'],
2198      ('replace' == $params['multiple_value_mode'] ? true : false)
2199      );
2200  }
2201
2202  // and now, let's create tag associations
2203  if (isset($params['tag_ids']))
2204  {
2205    $tag_ids = explode(',', $params['tag_ids']);
2206
2207    if ('replace' == $params['multiple_value_mode'])
2208    {
2209      set_tags(
2210        $tag_ids,
2211        $params['image_id']
2212        );
2213    }
2214    elseif ('append' == $params['multiple_value_mode'])
2215    {
2216      add_tags(
2217        $tag_ids,
2218        array($params['image_id'])
2219        );
2220    }
2221    else
2222    {
2223      new PwgError(
2224        500,
2225        '[ws_images_setInfo]'
2226        .' invalid parameter multiple_value_mode "'.$params['multiple_value_mode'].'"'
2227        .', possible values are {replace, append}.'
2228        );
2229      exit();
2230    }
2231  }
2232
2233  invalidate_user_cache();
2234}
2235
2236function ws_images_delete($params, &$service)
2237{
2238  global $conf;
2239  if (!is_admin())
2240  {
2241    return new PwgError(401, 'Access denied');
2242  }
2243
2244  if (!$service->isPost())
2245  {
2246    return new PwgError(405, "This method requires HTTP POST");
2247  }
2248
2249  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
2250  {
2251    return new PwgError(403, 'Invalid security token');
2252  }
2253
2254  $params['image_id'] = preg_split(
2255    '/[\s,;\|]/',
2256    $params['image_id'],
2257    -1,
2258    PREG_SPLIT_NO_EMPTY
2259    );
2260  $params['image_id'] = array_map('intval', $params['image_id']);
2261
2262  $image_ids = array();
2263  foreach ($params['image_id'] as $image_id)
2264  {
2265    if ($image_id > 0)
2266    {
2267      array_push($image_ids, $image_id);
2268    }
2269  }
2270
2271  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2272  delete_elements($image_ids, true);
2273}
2274
2275function ws_add_image_category_relations($image_id, $categories_string, $replace_mode=false)
2276{
2277  // let's add links between the image and the categories
2278  //
2279  // $params['categories'] should look like 123,12;456,auto;789 which means:
2280  //
2281  // 1. associate with category 123 on rank 12
2282  // 2. associate with category 456 on automatic rank
2283  // 3. associate with category 789 on automatic rank
2284  $cat_ids = array();
2285  $rank_on_category = array();
2286  $search_current_ranks = false;
2287
2288  $tokens = explode(';', $categories_string);
2289  foreach ($tokens as $token)
2290  {
2291    @list($cat_id, $rank) = explode(',', $token);
2292
2293    if (!preg_match('/^\d+$/', $cat_id))
2294    {
2295      continue;
2296    }
2297
2298    array_push($cat_ids, $cat_id);
2299
2300    if (!isset($rank))
2301    {
2302      $rank = 'auto';
2303    }
2304    $rank_on_category[$cat_id] = $rank;
2305
2306    if ($rank == 'auto')
2307    {
2308      $search_current_ranks = true;
2309    }
2310  }
2311
2312  $cat_ids = array_unique($cat_ids);
2313
2314  if (count($cat_ids) == 0)
2315  {
2316    new PwgError(
2317      500,
2318      '[ws_add_image_category_relations] there is no category defined in "'.$categories_string.'"'
2319      );
2320    exit();
2321  }
2322
2323  $query = '
2324SELECT
2325    id
2326  FROM '.CATEGORIES_TABLE.'
2327  WHERE id IN ('.implode(',', $cat_ids).')
2328;';
2329  $db_cat_ids = array_from_query($query, 'id');
2330
2331  $unknown_cat_ids = array_diff($cat_ids, $db_cat_ids);
2332  if (count($unknown_cat_ids) != 0)
2333  {
2334    new PwgError(
2335      500,
2336      '[ws_add_image_category_relations] the following categories are unknown: '.implode(', ', $unknown_cat_ids)
2337      );
2338    exit();
2339  }
2340
2341  $to_update_cat_ids = array();
2342
2343  // in case of replace mode, we first check the existing associations
2344  $query = '
2345SELECT
2346    category_id
2347  FROM '.IMAGE_CATEGORY_TABLE.'
2348  WHERE image_id = '.$image_id.'
2349;';
2350  $existing_cat_ids = array_from_query($query, 'category_id');
2351
2352  if ($replace_mode)
2353  {
2354    $to_remove_cat_ids = array_diff($existing_cat_ids, $cat_ids);
2355    if (count($to_remove_cat_ids) > 0)
2356    {
2357      $query = '
2358DELETE
2359  FROM '.IMAGE_CATEGORY_TABLE.'
2360  WHERE image_id = '.$image_id.'
2361    AND category_id IN ('.implode(', ', $to_remove_cat_ids).')
2362;';
2363      pwg_query($query);
2364      update_category($to_remove_cat_ids);
2365    }
2366  }
2367
2368  $new_cat_ids = array_diff($cat_ids, $existing_cat_ids);
2369  if (count($new_cat_ids) == 0)
2370  {
2371    return true;
2372  }
2373
2374  if ($search_current_ranks)
2375  {
2376    $query = '
2377SELECT
2378    category_id,
2379    MAX(rank) AS max_rank
2380  FROM '.IMAGE_CATEGORY_TABLE.'
2381  WHERE rank IS NOT NULL
2382    AND category_id IN ('.implode(',', $new_cat_ids).')
2383  GROUP BY category_id
2384;';
2385    $current_rank_of = simple_hash_from_query(
2386      $query,
2387      'category_id',
2388      'max_rank'
2389      );
2390
2391    foreach ($new_cat_ids as $cat_id)
2392    {
2393      if (!isset($current_rank_of[$cat_id]))
2394      {
2395        $current_rank_of[$cat_id] = 0;
2396      }
2397
2398      if ('auto' == $rank_on_category[$cat_id])
2399      {
2400        $rank_on_category[$cat_id] = $current_rank_of[$cat_id] + 1;
2401      }
2402    }
2403  }
2404
2405  $inserts = array();
2406
2407  foreach ($new_cat_ids as $cat_id)
2408  {
2409    array_push(
2410      $inserts,
2411      array(
2412        'image_id' => $image_id,
2413        'category_id' => $cat_id,
2414        'rank' => $rank_on_category[$cat_id],
2415        )
2416      );
2417  }
2418
2419  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2420  mass_inserts(
2421    IMAGE_CATEGORY_TABLE,
2422    array_keys($inserts[0]),
2423    $inserts
2424    );
2425
2426  update_category($new_cat_ids);
2427}
2428
2429function ws_categories_setInfo($params, &$service)
2430{
2431  global $conf;
2432  if (!is_admin())
2433  {
2434    return new PwgError(401, 'Access denied');
2435  }
2436
2437  if (!$service->isPost())
2438  {
2439    return new PwgError(405, "This method requires HTTP POST");
2440  }
2441
2442  // category_id
2443  // name
2444  // comment
2445
2446  $params['category_id'] = (int)$params['category_id'];
2447  if ($params['category_id'] <= 0)
2448  {
2449    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid category_id");
2450  }
2451
2452  // database registration
2453  $update = array(
2454    'id' => $params['category_id'],
2455    );
2456
2457  $info_columns = array(
2458    'name',
2459    'comment',
2460    );
2461
2462  $perform_update = false;
2463  foreach ($info_columns as $key)
2464  {
2465    if (isset($params[$key]))
2466    {
2467      $perform_update = true;
2468      $update[$key] = $params[$key];
2469    }
2470  }
2471
2472  if ($perform_update)
2473  {
2474    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2475    mass_updates(
2476      CATEGORIES_TABLE,
2477      array(
2478        'primary' => array('id'),
2479        'update'  => array_diff(array_keys($update), array('id'))
2480        ),
2481      array($update)
2482      );
2483  }
2484
2485}
2486
2487function ws_categories_setRepresentative($params, &$service)
2488{
2489  global $conf;
2490
2491  if (!is_admin())
2492  {
2493    return new PwgError(401, 'Access denied');
2494  }
2495
2496  if (!$service->isPost())
2497  {
2498    return new PwgError(405, "This method requires HTTP POST");
2499  }
2500
2501  // category_id
2502  // image_id
2503
2504  $params['category_id'] = (int)$params['category_id'];
2505  if ($params['category_id'] <= 0)
2506  {
2507    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid category_id");
2508  }
2509
2510  // does the category really exist?
2511  $query='
2512SELECT
2513    *
2514  FROM '.CATEGORIES_TABLE.'
2515  WHERE id = '.$params['category_id'].'
2516;';
2517  $row = pwg_db_fetch_assoc(pwg_query($query));
2518  if ($row == null)
2519  {
2520    return new PwgError(404, "category_id not found");
2521  }
2522
2523  $params['image_id'] = (int)$params['image_id'];
2524  if ($params['image_id'] <= 0)
2525  {
2526    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
2527  }
2528
2529  // does the image really exist?
2530  $query='
2531SELECT
2532    *
2533  FROM '.IMAGES_TABLE.'
2534  WHERE id = '.$params['image_id'].'
2535;';
2536
2537  $row = pwg_db_fetch_assoc(pwg_query($query));
2538  if ($row == null)
2539  {
2540    return new PwgError(404, "image_id not found");
2541  }
2542
2543  // apply change
2544  $query = '
2545UPDATE '.CATEGORIES_TABLE.'
2546  SET representative_picture_id = '.$params['image_id'].'
2547  WHERE id = '.$params['category_id'].'
2548;';
2549  pwg_query($query);
2550
2551  $query = '
2552UPDATE '.USER_CACHE_CATEGORIES_TABLE.'
2553  SET user_representative_picture_id = NULL
2554  WHERE cat_id = '.$params['category_id'].'
2555;';
2556  pwg_query($query);
2557}
2558
2559function ws_categories_delete($params, &$service)
2560{
2561  global $conf;
2562  if (!is_admin())
2563  {
2564    return new PwgError(401, 'Access denied');
2565  }
2566
2567  if (!$service->isPost())
2568  {
2569    return new PwgError(405, "This method requires HTTP POST");
2570  }
2571
2572  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
2573  {
2574    return new PwgError(403, 'Invalid security token');
2575  }
2576
2577  $modes = array('no_delete', 'delete_orphans', 'force_delete');
2578  if (!in_array($params['photo_deletion_mode'], $modes))
2579  {
2580    return new PwgError(
2581      500,
2582      '[ws_categories_delete]'
2583      .' invalid parameter photo_deletion_mode "'.$params['photo_deletion_mode'].'"'
2584      .', possible values are {'.implode(', ', $modes).'}.'
2585      );
2586  }
2587
2588  $params['category_id'] = preg_split(
2589    '/[\s,;\|]/',
2590    $params['category_id'],
2591    -1,
2592    PREG_SPLIT_NO_EMPTY
2593    );
2594  $params['category_id'] = array_map('intval', $params['category_id']);
2595
2596  $category_ids = array();
2597  foreach ($params['category_id'] as $category_id)
2598  {
2599    if ($category_id > 0)
2600    {
2601      array_push($category_ids, $category_id);
2602    }
2603  }
2604
2605  if (count($category_ids) == 0)
2606  {
2607    return;
2608  }
2609
2610  $query = '
2611SELECT id
2612  FROM '.CATEGORIES_TABLE.'
2613  WHERE id IN ('.implode(',', $category_ids).')
2614;';
2615  $category_ids = array_from_query($query, 'id');
2616
2617  if (count($category_ids) == 0)
2618  {
2619    return;
2620  }
2621
2622  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2623  delete_categories($category_ids, $params['photo_deletion_mode']);
2624  update_global_rank();
2625}
2626
2627function ws_categories_move($params, &$service)
2628{
2629  global $conf, $page;
2630
2631  if (!is_admin())
2632  {
2633    return new PwgError(401, 'Access denied');
2634  }
2635
2636  if (!$service->isPost())
2637  {
2638    return new PwgError(405, "This method requires HTTP POST");
2639  }
2640
2641  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
2642  {
2643    return new PwgError(403, 'Invalid security token');
2644  }
2645
2646  $params['category_id'] = preg_split(
2647    '/[\s,;\|]/',
2648    $params['category_id'],
2649    -1,
2650    PREG_SPLIT_NO_EMPTY
2651    );
2652  $params['category_id'] = array_map('intval', $params['category_id']);
2653
2654  $category_ids = array();
2655  foreach ($params['category_id'] as $category_id)
2656  {
2657    if ($category_id > 0)
2658    {
2659      array_push($category_ids, $category_id);
2660    }
2661  }
2662
2663  if (count($category_ids) == 0)
2664  {
2665    return new PwgError(403, 'Invalid category_id input parameter, no category to move');
2666  }
2667
2668  // we can't move physical categories
2669  $categories_in_db = array();
2670
2671  $query = '
2672SELECT
2673    id,
2674    name,
2675    dir
2676  FROM '.CATEGORIES_TABLE.'
2677  WHERE id IN ('.implode(',', $category_ids).')
2678;';
2679  $result = pwg_query($query);
2680  while ($row = pwg_db_fetch_assoc($result))
2681  {
2682    $categories_in_db[$row['id']] = $row;
2683    // we break on error at first physical category detected
2684    if (!empty($row['dir']))
2685    {
2686      $row['name'] = strip_tags(
2687        trigger_event(
2688          'render_category_name',
2689          $row['name'],
2690          'ws_categories_move'
2691          )
2692        );
2693
2694      return new PwgError(
2695        403,
2696        sprintf(
2697          'Category %s (%u) is not a virtual category, you cannot move it',
2698          $row['name'],
2699          $row['id']
2700          )
2701        );
2702    }
2703  }
2704
2705  if (count($categories_in_db) != count($category_ids))
2706  {
2707    $unknown_category_ids = array_diff($category_ids, array_keys($categories_in_db));
2708
2709    return new PwgError(
2710      403,
2711      sprintf(
2712        'Category %u does not exist',
2713        $unknown_category_ids[0]
2714        )
2715      );
2716  }
2717
2718  // does this parent exists? This check should be made in the
2719  // move_categories function, not here
2720  //
2721  // 0 as parent means "move categories at gallery root"
2722  if (!is_numeric($params['parent']))
2723  {
2724    return new PwgError(403, 'Invalid parent input parameter');
2725  }
2726
2727  if (0 != $params['parent']) {
2728    $params['parent'] = intval($params['parent']);
2729    $subcat_ids = get_subcat_ids(array($params['parent']));
2730    if (count($subcat_ids) == 0)
2731    {
2732      return new PwgError(403, 'Unknown parent category id');
2733    }
2734  }
2735
2736  $page['infos'] = array();
2737  $page['errors'] = array();
2738  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2739  move_categories($category_ids, $params['parent']);
2740  invalidate_user_cache();
2741
2742  if (count($page['errors']) != 0)
2743  {
2744    return new PwgError(403, implode('; ', $page['errors']));
2745  }
2746}
2747
2748function ws_logfile($string)
2749{
2750  global $conf;
2751
2752  if (!$conf['ws_enable_log']) {
2753    return true;
2754  }
2755
2756  file_put_contents(
2757    $conf['ws_log_filepath'],
2758    '['.date('c').'] '.$string."\n",
2759    FILE_APPEND
2760    );
2761}
2762
2763function ws_images_checkUpload($params, &$service)
2764{
2765  global $conf;
2766
2767  if (!is_admin())
2768  {
2769    return new PwgError(401, 'Access denied');
2770  }
2771
2772  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
2773  $ret['message'] = ready_for_upload_message();
2774  $ret['ready_for_upload'] = true;
2775
2776  if (!empty($ret['message']))
2777  {
2778    $ret['ready_for_upload'] = false;
2779  }
2780
2781  return $ret;
2782}
2783
2784function ws_plugins_getList($params, &$service)
2785{
2786  global $conf;
2787
2788  if (!is_admin())
2789  {
2790    return new PwgError(401, 'Access denied');
2791  }
2792
2793  include_once(PHPWG_ROOT_PATH.'admin/include/plugins.class.php');
2794  $plugins = new plugins();
2795  $plugins->sort_fs_plugins('name');
2796  $plugin_list = array();
2797
2798  foreach($plugins->fs_plugins as $plugin_id => $fs_plugin)
2799  {
2800    if (isset($plugins->db_plugins_by_id[$plugin_id]))
2801    {
2802      $state = $plugins->db_plugins_by_id[$plugin_id]['state'];
2803    }
2804    else
2805    {
2806      $state = 'uninstalled';
2807    }
2808
2809    array_push(
2810      $plugin_list,
2811      array(
2812        'id' => $plugin_id,
2813        'name' => $fs_plugin['name'],
2814        'version' => $fs_plugin['version'],
2815        'state' => $state,
2816        'description' => $fs_plugin['description'],
2817        )
2818      );
2819  }
2820
2821  return $plugin_list;
2822}
2823
2824function ws_plugins_performAction($params, &$service)
2825{
2826  global $template;
2827
2828  if (!is_admin())
2829  {
2830    return new PwgError(401, 'Access denied');
2831  }
2832
2833  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
2834  {
2835    return new PwgError(403, 'Invalid security token');
2836  }
2837
2838  define('IN_ADMIN', true);
2839  include_once(PHPWG_ROOT_PATH.'admin/include/plugins.class.php');
2840  $plugins = new plugins();
2841  $errors = $plugins->perform_action($params['action'], $params['plugin']);
2842
2843
2844  if (!empty($errors))
2845  {
2846    return new PwgError(500, $errors);
2847  }
2848  else
2849  {
2850    if (in_array($params['action'], array('activate', 'deactivate')))
2851    {
2852      $template->delete_compiled_templates();
2853    }
2854    return true;
2855  }
2856}
2857
2858function ws_themes_performAction($params, &$service)
2859{
2860  global $template;
2861
2862  if (!is_admin())
2863  {
2864    return new PwgError(401, 'Access denied');
2865  }
2866
2867  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
2868  {
2869    return new PwgError(403, 'Invalid security token');
2870  }
2871
2872  define('IN_ADMIN', true);
2873  include_once(PHPWG_ROOT_PATH.'admin/include/themes.class.php');
2874  $themes = new themes();
2875  $errors = $themes->perform_action($params['action'], $params['theme']);
2876
2877  if (!empty($errors))
2878  {
2879    return new PwgError(500, $errors);
2880  }
2881  else
2882  {
2883    if (in_array($params['action'], array('activate', 'deactivate')))
2884    {
2885      $template->delete_compiled_templates();
2886    }
2887    return true;
2888  }
2889}
2890
2891function ws_images_resizethumbnail($params, &$service)
2892{
2893  if (!is_admin())
2894  {
2895    return new PwgError(401, 'Access denied');
2896  }
2897
2898  if (empty($params['image_id']) and empty($params['image_path']))
2899  {
2900    return new PwgError(403, "image_id or image_path is missing");
2901  }
2902
2903  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
2904  include_once(PHPWG_ROOT_PATH.'admin/include/image.class.php');
2905
2906  if (!empty($params['image_id']))
2907  {
2908    $query='
2909SELECT id, path, tn_ext, has_high
2910  FROM '.IMAGES_TABLE.'
2911  WHERE id = '.(int)$params['image_id'].'
2912;';
2913    $image = pwg_db_fetch_assoc(pwg_query($query));
2914
2915    if ($image == null)
2916    {
2917      return new PwgError(403, "image_id not found");
2918    }
2919
2920    $image_path = $image['path'];
2921    $thumb_path = get_thumbnail_path($image);
2922  }
2923  else
2924  {
2925    $image_path = $params['image_path'];
2926    $thumb_path = file_path_for_type($image_path, 'thumb');
2927  }
2928
2929  if (!file_exists($image_path) or !is_valid_image_extension(get_extension($image_path)))
2930  {
2931    return new PwgError(403, "image can't be resized");
2932  }
2933
2934  $result = false;
2935  prepare_directory(dirname($thumb_path));
2936  $img = new pwg_image($image_path, $params['library']);
2937
2938  $result =  $img->pwg_resize(
2939    $thumb_path,
2940    $params['maxwidth'],
2941    $params['maxheight'],
2942    $params['quality'],
2943    false, // automatic rotation is not needed for thumbnails.
2944    true, // strip metadata
2945    get_boolean($params['crop']),
2946    get_boolean($params['follow_orientation'])
2947  );
2948
2949  $img->destroy();
2950  return $result;
2951}
2952
2953function ws_images_resizewebsize($params, &$service)
2954{
2955  if (!is_admin())
2956  {
2957    return new PwgError(401, 'Access denied');
2958  }
2959
2960  include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
2961  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
2962  include_once(PHPWG_ROOT_PATH.'admin/include/image.class.php');
2963
2964  $query='
2965SELECT id, path, tn_ext, has_high, width, height
2966  FROM '.IMAGES_TABLE.'
2967  WHERE id = '.(int)$params['image_id'].'
2968;';
2969  $image = pwg_db_fetch_assoc(pwg_query($query));
2970
2971  if ($image == null)
2972  {
2973    return new PwgError(403, "image_id not found");
2974  }
2975
2976  $image_path = $image['path'];
2977
2978  if (!is_valid_image_extension(get_extension($image_path)))
2979  {
2980    return new PwgError(403, "image can't be resized");
2981  }
2982 
2983  $hd_path = get_high_path($image);
2984
2985  if (empty($image['has_high']) or !file_exists($hd_path))
2986  {
2987    if ($image['width'] > $params['maxwidth'] or $image['height'] > $params['maxheight'])
2988    {
2989      $hd_path = file_path_for_type($image_path, 'high');
2990      $hd_dir = dirname($hd_path);
2991      prepare_directory($hd_dir);
2992     
2993      rename($image_path, $hd_path);
2994      $hd_infos = pwg_image_infos($hd_path);
2995
2996      single_update(
2997        IMAGES_TABLE,
2998        array(
2999          'has_high' => 'true',
3000          'high_filesize' => $hd_infos['filesize'],
3001          'high_width' => $hd_infos['width'],
3002          'high_height' => $hd_infos['height'],
3003          ),
3004        array(
3005          'id' => $image['id']
3006          )
3007        );
3008    }
3009    else
3010    {
3011      return new PwgError(403, "image can't be resized");
3012    }
3013  }
3014
3015  $result = false;
3016  $img = new pwg_image($hd_path, $params['library']);
3017
3018  $result = $img->pwg_resize(
3019    $image_path,
3020    $params['maxwidth'],
3021    $params['maxheight'],
3022    $params['quality'],
3023    $params['automatic_rotation'],
3024    false // strip metadata
3025    );
3026
3027  $img->destroy();
3028
3029  global $conf;
3030  $conf['use_exif'] = false;
3031  $conf['use_iptc'] = false;
3032  update_metadata(array($image['id'] => $image['path']));
3033
3034  return $result;
3035}
3036
3037function ws_extensions_update($params, &$service)
3038{
3039  if (!is_webmaster())
3040  {
3041    return new PwgError(401, l10n('Webmaster status is required.'));
3042  }
3043
3044  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
3045  {
3046    return new PwgError(403, 'Invalid security token');
3047  }
3048
3049  if (empty($params['type']) or !in_array($params['type'], array('plugins', 'themes', 'languages')))
3050  {
3051    return new PwgError(403, "invalid extension type");
3052  }
3053
3054  if (empty($params['id']) or empty($params['revision']))
3055  {
3056    return new PwgError(null, 'Wrong parameters');
3057  }
3058
3059  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
3060  include_once(PHPWG_ROOT_PATH.'admin/include/'.$params['type'].'.class.php');
3061
3062  $type = $params['type'];
3063  $extension_id = $params['id'];
3064  $revision = $params['revision'];
3065
3066  $extension = new $type();
3067
3068  if ($type == 'plugins')
3069  {
3070    if (isset($extension->db_plugins_by_id[$extension_id]) and $extension->db_plugins_by_id[$extension_id]['state'] == 'active')
3071    {
3072      $extension->perform_action('deactivate', $extension_id);
3073
3074      redirect(PHPWG_ROOT_PATH
3075        . 'ws.php'
3076        . '?method=pwg.extensions.update'
3077        . '&type=plugins'
3078        . '&id=' . $extension_id
3079        . '&revision=' . $revision
3080        . '&reactivate=true'
3081        . '&pwg_token=' . get_pwg_token()
3082        . '&format=json'
3083      );
3084    }
3085
3086    $upgrade_status = $extension->extract_plugin_files('upgrade', $revision, $extension_id);
3087    $extension_name = $extension->fs_plugins[$extension_id]['name'];
3088
3089    if (isset($params['reactivate']))
3090    {
3091      $extension->perform_action('activate', $extension_id);
3092    }
3093  }
3094  elseif ($type == 'themes')
3095  {
3096    $upgrade_status = $extension->extract_theme_files('upgrade', $revision, $extension_id);
3097    $extension_name = $extension->fs_themes[$extension_id]['name'];
3098  }
3099  elseif ($type == 'languages')
3100  {
3101    $upgrade_status = $extension->extract_language_files('upgrade', $revision, $extension_id);
3102    $extension_name = $extension->fs_languages[$extension_id]['name'];
3103  }
3104
3105  global $template;
3106  $template->delete_compiled_templates();
3107
3108  switch ($upgrade_status)
3109  {
3110    case 'ok':
3111      return sprintf(l10n('%s has been successfully updated.'), $extension_name);
3112
3113    case 'temp_path_error':
3114      return new PwgError(null, l10n('Can\'t create temporary file.'));
3115
3116    case 'dl_archive_error':
3117      return new PwgError(null, l10n('Can\'t download archive.'));
3118
3119    case 'archive_error':
3120      return new PwgError(null, l10n('Can\'t read or extract archive.'));
3121
3122    default:
3123      return new PwgError(null, sprintf(l10n('An error occured during extraction (%s).'), $upgrade_status));
3124  }
3125}
3126
3127function ws_extensions_ignoreupdate($params, &$service)
3128{
3129  global $conf;
3130
3131  define('IN_ADMIN', true);
3132  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
3133
3134  if (!is_webmaster())
3135  {
3136    return new PwgError(401, 'Access denied');
3137  }
3138
3139  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
3140  {
3141    return new PwgError(403, 'Invalid security token');
3142  }
3143
3144  $conf['updates_ignored'] = unserialize($conf['updates_ignored']);
3145
3146  // Reset ignored extension
3147  if ($params['reset'])
3148  {
3149    if (!empty($params['type']) and isset($conf['updates_ignored'][$params['type']]))
3150    {
3151      $conf['updates_ignored'][$params['type']] = array();
3152    }
3153    else
3154    {
3155      $conf['updates_ignored'] = array(
3156        'plugins'=>array(),
3157        'themes'=>array(),
3158        'languages'=>array()
3159      );
3160    }
3161    conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
3162    unset($_SESSION['extensions_need_update']);
3163    return true;
3164  }
3165
3166  if (empty($params['id']) or empty($params['type']) or !in_array($params['type'], array('plugins', 'themes', 'languages')))
3167  {
3168    return new PwgError(403, 'Invalid parameters');
3169  }
3170
3171  // Add or remove extension from ignore list
3172  if (!in_array($params['id'], $conf['updates_ignored'][$params['type']]))
3173  {
3174    array_push($conf['updates_ignored'][$params['type']], $params['id']);
3175  }
3176  conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
3177  unset($_SESSION['extensions_need_update']);
3178  return true;
3179}
3180
3181function ws_extensions_checkupdates($params, &$service)
3182{
3183  global $conf;
3184
3185  define('IN_ADMIN', true);
3186  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
3187  include_once(PHPWG_ROOT_PATH.'admin/include/updates.class.php');
3188  $update = new updates();
3189
3190  if (!is_admin())
3191  {
3192    return new PwgError(401, 'Access denied');
3193  }
3194
3195  $result = array();
3196
3197  if (!isset($_SESSION['need_update']))
3198    $update->check_piwigo_upgrade();
3199
3200  $result['piwigo_need_update'] = $_SESSION['need_update'];
3201
3202  $conf['updates_ignored'] = unserialize($conf['updates_ignored']);
3203
3204  if (!isset($_SESSION['extensions_need_update']))
3205    $update->check_extensions();
3206  else
3207    $update->check_updated_extensions();
3208
3209  if (!is_array($_SESSION['extensions_need_update']))
3210    $result['ext_need_update'] = null;
3211  else
3212    $result['ext_need_update'] = !empty($_SESSION['extensions_need_update']);
3213
3214  return $result;
3215}
3216?>
Note: See TracBrowser for help on using the repository browser.