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

Last change on this file since 12543 was 12543, checked in by plg, 12 years ago

merge r12537 from branch 2.3 to trunk

feature 2352 added: pwg.categories.getList now returns a tn_url parameter.
This is the album thumbnail.

Warning: if the API method is called with $paramspublic, 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 $paramspublic

  • Property svn:eol-style set to LF
File size: 83.1 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    user_representative_picture_id, count_images,
494    date_last, max_date_last, count_categories AS nb_categories
495  FROM '.CATEGORIES_TABLE.'
496   '.$join_type.' JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON id=cat_id AND user_id='.$join_user.'
497  WHERE '. implode('
498    AND ', $where);
499
500  $result = pwg_query($query);
501
502  // management of the album thumbnail -- starts here
503  $image_ids = array();
504  $categories = array();
505  $user_representative_updates_for = array();
506  // management of the album thumbnail -- stops here
507 
508  $cats = array();
509  while ($row = pwg_db_fetch_assoc($result))
510  {
511    $row['url'] = make_index_url(
512        array(
513          'category' => $row
514          )
515      );
516    foreach( array('id','nb_images','total_nb_images','nb_categories') as $key)
517    {
518      $row[$key] = (int)$row[$key];
519    }
520
521    if ($params['fullname'])
522    {
523      $row['name'] = strip_tags(get_cat_display_name_cache($row['uppercats'], null, false));
524    }
525    else
526    {
527      $row['name'] = strip_tags(
528        trigger_event(
529          'render_category_name',
530          $row['name'],
531          'ws_categories_getList'
532          )
533        );
534    }
535
536    $row['comment'] = strip_tags(
537      trigger_event(
538        'render_category_description',
539        $row['comment'],
540        'ws_categories_getList'
541        )
542      );
543
544    // management of the album thumbnail -- starts here
545    //
546    // on branch 2.3, the algorithm is duplicated from
547    // include/category_cats, but we should use a common code for Piwigo 2.4
548    //
549    // warning : if the API method is called with $params['public'], the
550    // album thumbnail may be not accurate. The thumbnail can be viewed by
551    // the connected user, but maybe not by the guest. Changing the
552    // filtering method would be too complicated for now. We will simply
553    // avoid to persist the user_representative_picture_id in the database
554    // if $params['public']
555    if (!empty($row['user_representative_picture_id']))
556    {
557      $image_id = $row['user_representative_picture_id'];
558    }
559    else if (!empty($row['representative_picture_id']))
560    { // if a representative picture is set, it has priority
561      $image_id = $row['representative_picture_id'];
562    }
563    else if ($conf['allow_random_representative'])
564    {
565      // searching a random representant among elements in sub-categories
566      $image_id = get_random_image_in_category($row);
567    }
568    else
569    { // searching a random representant among representant of sub-categories
570      if ($row['count_categories']>0 and $row['count_images']>0)
571      {
572        $query = '
573  SELECT representative_picture_id
574    FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.'
575    ON id = cat_id and user_id = '.$user['id'].'
576    WHERE uppercats LIKE \''.$row['uppercats'].',%\'
577      AND representative_picture_id IS NOT NULL'
578          .get_sql_condition_FandF
579          (
580            array
581            (
582              'visible_categories' => 'id',
583              ),
584            "\n  AND"
585            ).'
586    ORDER BY '.DB_RANDOM_FUNCTION.'()
587    LIMIT 1
588  ;';
589        $subresult = pwg_query($query);
590        if (pwg_db_num_rows($subresult) > 0)
591        {
592          list($image_id) = pwg_db_fetch_row($subresult);
593        }
594      }
595    }
596   
597    if (isset($image_id))
598    {
599      if ($conf['representative_cache_on_subcats'] and $row['user_representative_picture_id'] != $image_id)
600      {
601        $user_representative_updates_for[ $user['id'].'#'.$row['id'] ] = $image_id;
602      }
603   
604      $row['representative_picture_id'] = $image_id;
605      array_push($image_ids, $image_id);
606      array_push($categories, $row);
607    }
608    unset($image_id);
609    // management of the album thumbnail -- stops here
610
611
612    array_push($cats, $row);
613  }
614  usort($cats, 'global_rank_compare');
615
616  // management of the album thumbnail -- starts here
617  if (count($categories) > 0)
618  {
619    $thumbnail_src_of = array();
620    $new_image_ids = array();
621
622    $query = '
623SELECT id, path, tn_ext, level
624  FROM '.IMAGES_TABLE.'
625  WHERE id IN ('.implode(',', $image_ids).')
626;';
627    $result = pwg_query($query);
628    while ($row = pwg_db_fetch_assoc($result))
629    {
630      if ($row['level'] <= $user['level'])
631      {
632        $thumbnail_src_of[$row['id']] = get_thumbnail_url($row);
633      }
634      else
635      {
636        // problem: we must not display the thumbnail of a photo which has a
637        // higher privacy level than user privacy level
638        //
639        // * what is the represented category?
640        // * find a random photo matching user permissions
641        // * register it at user_representative_picture_id
642        // * set it as the representative_picture_id for the category
643       
644        foreach ($categories as &$category)
645        {
646          if ($row['id'] == $category['representative_picture_id'])
647          {
648            // searching a random representant among elements in sub-categories
649            $image_id = get_random_image_in_category($category);
650           
651            if (isset($image_id) and !in_array($image_id, $image_ids))
652            {
653              array_push($new_image_ids, $image_id);
654            }
655           
656            if ($conf['representative_cache_on_level'])
657            {
658              $user_representative_updates_for[ $user['id'].'#'.$category['id'] ] = $image_id;
659            }
660           
661            $category['representative_picture_id'] = $image_id;
662          }
663        }
664        unset($category);
665      }
666    }
667   
668    if (count($new_image_ids) > 0)
669    {
670      $query = '
671SELECT id, path, tn_ext
672  FROM '.IMAGES_TABLE.'
673  WHERE id IN ('.implode(',', $new_image_ids).')
674;';
675      $result = pwg_query($query);
676      while ($row = pwg_db_fetch_assoc($result))
677      {
678        $thumbnail_src_of[$row['id']] = get_thumbnail_url($row);
679      }
680    }
681  }
682
683  // compared to code in include/category_cats, we only persist the new
684  // user_representative if we have used $user['id'] and not the guest id,
685  // or else the real guest may see thumbnail that he should not
686  if (!$params['public'] and count($user_representative_updates_for))
687  {
688    $updates = array();
689 
690    foreach ($user_representative_updates_for as $user_cat => $image_id)
691    {
692      list($user_id, $cat_id) = explode('#', $user_cat);
693   
694      array_push(
695        $updates,
696        array(
697          'user_id' => $user_id,
698          'cat_id' => $cat_id,
699          'user_representative_picture_id' => $image_id,
700          )
701        );
702    }
703
704    mass_updates(
705      USER_CACHE_CATEGORIES_TABLE,
706      array(
707        'primary' => array('user_id', 'cat_id'),
708        'update'  => array('user_representative_picture_id')
709        ),
710      $updates
711      );
712  }
713
714  foreach ($cats as &$cat)
715  {
716    foreach ($categories as $category)
717    {
718      if ($category['id'] == $cat['id'])
719      {
720        $cat['tn_url'] = $thumbnail_src_of[$category['representative_picture_id']];
721      }
722    }
723    // we don't want them in the output
724    unset($cat['user_representative_picture_id']);
725    unset($cat['count_images']);
726  }
727  unset($cat); 
728  // management of the album thumbnail -- stops here
729
730  if ($params['tree_output'])
731  {
732    return categories_flatlist_to_tree($cats);
733  }
734  else
735  {
736    return array(
737      'categories' => new PwgNamedArray(
738        $cats,
739        'category',
740        array(
741          'id',
742          'url',
743          'nb_images',
744          'total_nb_images',
745          'nb_categories',
746          'date_last',
747          'max_date_last',
748          )
749        )
750      );
751  }
752}
753
754/**
755 * returns the list of categories as you can see them in administration (web
756 * service method).
757 *
758 * Only admin can run this method and permissions are not taken into
759 * account.
760 */
761function ws_categories_getAdminList($params, &$service)
762{
763  if (!is_admin())
764  {
765    return new PwgError(401, 'Access denied');
766  }
767
768  $query = '
769SELECT
770    category_id,
771    COUNT(*) AS counter
772  FROM '.IMAGE_CATEGORY_TABLE.'
773  GROUP BY category_id
774;';
775  $nb_images_of = simple_hash_from_query($query, 'category_id', 'counter');
776
777  $query = '
778SELECT
779    id,
780    name,
781    comment,
782    uppercats,
783    global_rank
784  FROM '.CATEGORIES_TABLE.'
785;';
786  $result = pwg_query($query);
787  $cats = array();
788
789  while ($row = pwg_db_fetch_assoc($result))
790  {
791    $id = $row['id'];
792    $row['nb_images'] = isset($nb_images_of[$id]) ? $nb_images_of[$id] : 0;
793    $row['name'] = strip_tags(
794      trigger_event(
795        'render_category_name',
796        $row['name'],
797        'ws_categories_getAdminList'
798        )
799      );
800    $row['comment'] = strip_tags(
801      trigger_event(
802        'render_category_description',
803        $row['comment'],
804        'ws_categories_getAdminList'
805        )
806      );
807    array_push($cats, $row);
808  }
809
810  usort($cats, 'global_rank_compare');
811  return array(
812    'categories' => new PwgNamedArray(
813      $cats,
814      'category',
815      array(
816        'id',
817        'nb_images',
818        'name',
819        'uppercats',
820        'global_rank',
821        )
822      )
823    );
824}
825
826/**
827 * returns detailed information for an element (web service method)
828 */
829function ws_images_addComment($params, &$service)
830{
831  if (!$service->isPost())
832  {
833    return new PwgError(405, "This method requires HTTP POST");
834  }
835  $params['image_id'] = (int)$params['image_id'];
836  $query = '
837SELECT DISTINCT image_id
838  FROM '.IMAGE_CATEGORY_TABLE.' INNER JOIN '.CATEGORIES_TABLE.' ON category_id=id
839  WHERE commentable="true"
840    AND image_id='.$params['image_id'].
841    get_sql_condition_FandF(
842      array(
843        'forbidden_categories' => 'id',
844        'visible_categories' => 'id',
845        'visible_images' => 'image_id'
846      ),
847      ' AND'
848    );
849  if ( !pwg_db_num_rows( pwg_query( $query ) ) )
850  {
851    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
852  }
853
854  $comm = array(
855    'author' => trim( $params['author'] ),
856    'content' => trim( $params['content'] ),
857    'image_id' => $params['image_id'],
858   );
859
860  include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php');
861
862  $comment_action = insert_user_comment(
863      $comm, $params['key'], $infos
864    );
865
866  switch ($comment_action)
867  {
868    case 'reject':
869      array_push($infos, l10n('Your comment has NOT been registered because it did not pass the validation rules') );
870      return new PwgError(403, implode("; ", $infos) );
871    case 'validate':
872    case 'moderate':
873      $ret = array(
874          'id' => $comm['id'],
875          'validation' => $comment_action=='validate',
876        );
877      return new PwgNamedStruct(
878          'comment',
879          $ret,
880          null, array()
881        );
882    default:
883      return new PwgError(500, "Unknown comment action ".$comment_action );
884  }
885}
886
887/**
888 * returns detailed information for an element (web service method)
889 */
890function ws_images_getInfo($params, &$service)
891{
892  @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
893  global $user, $conf;
894  $params['image_id'] = (int)$params['image_id'];
895  if ( $params['image_id']<=0 )
896  {
897    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
898  }
899
900  $query='
901SELECT * FROM '.IMAGES_TABLE.'
902  WHERE id='.$params['image_id'].
903    get_sql_condition_FandF(
904      array('visible_images' => 'id'),
905      ' AND'
906    ).'
907LIMIT 1';
908
909  $image_row = pwg_db_fetch_assoc(pwg_query($query));
910  if ($image_row==null)
911  {
912    return new PwgError(404, "image_id not found");
913  }
914  $image_row = array_merge( $image_row, ws_std_get_urls($image_row) );
915
916  //-------------------------------------------------------- related categories
917  $query = '
918SELECT id, name, permalink, uppercats, global_rank, commentable
919  FROM '.IMAGE_CATEGORY_TABLE.'
920    INNER JOIN '.CATEGORIES_TABLE.' ON category_id = id
921  WHERE image_id = '.$image_row['id'].
922  get_sql_condition_FandF(
923      array( 'forbidden_categories' => 'category_id' ),
924      ' AND'
925    ).'
926;';
927  $result = pwg_query($query);
928  $is_commentable = false;
929  $related_categories = array();
930  while ($row = pwg_db_fetch_assoc($result))
931  {
932    if ($row['commentable']=='true')
933    {
934      $is_commentable = true;
935    }
936    unset($row['commentable']);
937    $row['url'] = make_index_url(
938        array(
939          'category' => $row
940          )
941      );
942
943    $row['page_url'] = make_picture_url(
944        array(
945          'image_id' => $image_row['id'],
946          'image_file' => $image_row['file'],
947          'category' => $row
948          )
949      );
950    $row['id']=(int)$row['id'];
951    array_push($related_categories, $row);
952  }
953  usort($related_categories, 'global_rank_compare');
954  if ( empty($related_categories) )
955  {
956    return new PwgError(401, 'Access denied');
957  }
958
959  //-------------------------------------------------------------- related tags
960  $related_tags = get_common_tags( array($image_row['id']), -1 );
961  foreach( $related_tags as $i=>$tag)
962  {
963    $tag['url'] = make_index_url(
964        array(
965          'tags' => array($tag)
966          )
967      );
968    $tag['page_url'] = make_picture_url(
969        array(
970          'image_id' => $image_row['id'],
971          'image_file' => $image_row['file'],
972          'tags' => array($tag),
973          )
974      );
975    unset($tag['counter']);
976    $tag['id']=(int)$tag['id'];
977    $related_tags[$i]=$tag;
978  }
979  //------------------------------------------------------------- related rates
980        $rating = array('score'=>$image_row['rating_score'], 'count'=>0, 'average'=>null);
981        if (isset($rating['score']))
982        {
983                $query = '
984SELECT COUNT(rate) AS count
985     , ROUND(AVG(rate),2) AS average
986  FROM '.RATE_TABLE.'
987  WHERE element_id = '.$image_row['id'].'
988;';
989                $row = pwg_db_fetch_assoc(pwg_query($query));
990                $rating['score'] = (float)$rating['score'];
991                $rating['average'] = (float)$row['average'];
992                $rating['count'] = (int)$row['count'];
993        }
994
995  //---------------------------------------------------------- related comments
996  $related_comments = array();
997
998  $where_comments = 'image_id = '.$image_row['id'];
999  if ( !is_admin() )
1000  {
1001    $where_comments .= '
1002    AND validated="true"';
1003  }
1004
1005  $query = '
1006SELECT COUNT(id) AS nb_comments
1007  FROM '.COMMENTS_TABLE.'
1008  WHERE '.$where_comments;
1009  list($nb_comments) = array_from_query($query, 'nb_comments');
1010  $nb_comments = (int)$nb_comments;
1011
1012  if ( $nb_comments>0 and $params['comments_per_page']>0 )
1013  {
1014    $query = '
1015SELECT id, date, author, content
1016  FROM '.COMMENTS_TABLE.'
1017  WHERE '.$where_comments.'
1018  ORDER BY date
1019  LIMIT '.(int)$params['comments_per_page'].
1020    ' OFFSET '.(int)($params['comments_per_page']*$params['comments_page']);
1021
1022    $result = pwg_query($query);
1023    while ($row = pwg_db_fetch_assoc($result))
1024    {
1025      $row['id']=(int)$row['id'];
1026      array_push($related_comments, $row);
1027    }
1028  }
1029
1030  $comment_post_data = null;
1031  if ($is_commentable and
1032      (!is_a_guest()
1033        or (is_a_guest() and $conf['comments_forall'] )
1034      )
1035      )
1036  {
1037    $comment_post_data['author'] = stripslashes($user['username']);
1038    $comment_post_data['key'] = get_ephemeral_key(2, $params['image_id']);
1039  }
1040
1041  $ret = $image_row;
1042  foreach ( array('id','width','height','hit','filesize') as $k )
1043  {
1044    if (isset($ret[$k]))
1045    {
1046      $ret[$k] = (int)$ret[$k];
1047    }
1048  }
1049  foreach ( array('path', 'storage_category_id') as $k )
1050  {
1051    unset($ret[$k]);
1052  }
1053
1054  $ret['rates'] = array( WS_XML_ATTRIBUTES => $rating );
1055  $ret['categories'] = new PwgNamedArray($related_categories, 'category', array('id','url', 'page_url') );
1056  $ret['tags'] = new PwgNamedArray($related_tags, 'tag', array('id','url_name','url','name','page_url') );
1057  if ( isset($comment_post_data) )
1058  {
1059    $ret['comment_post'] = array( WS_XML_ATTRIBUTES => $comment_post_data );
1060  }
1061  $ret['comments'] = array(
1062     WS_XML_ATTRIBUTES =>
1063        array(
1064          'page' => $params['comments_page'],
1065          'per_page' => $params['comments_per_page'],
1066          'count' => count($related_comments),
1067          'nb_comments' => $nb_comments,
1068        ),
1069     WS_XML_CONTENT => new PwgNamedArray($related_comments, 'comment', array('id','date') )
1070      );
1071
1072  return new PwgNamedStruct('image',$ret, null, array('name','comment') );
1073}
1074
1075
1076/**
1077 * rates the image_id in the parameter
1078 */
1079function ws_images_Rate($params, &$service)
1080{
1081  $image_id = (int)$params['image_id'];
1082  $query = '
1083SELECT DISTINCT id FROM '.IMAGES_TABLE.'
1084  INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id=image_id
1085  WHERE id='.$image_id
1086  .get_sql_condition_FandF(
1087    array(
1088        'forbidden_categories' => 'category_id',
1089        'forbidden_images' => 'id',
1090      ),
1091    '    AND'
1092    ).'
1093    LIMIT 1';
1094  if ( pwg_db_num_rows( pwg_query($query) )==0 )
1095  {
1096    return new PwgError(404, "Invalid image_id or access denied" );
1097  }
1098  $rate = (int)$params['rate'];
1099  include_once(PHPWG_ROOT_PATH.'include/functions_rate.inc.php');
1100  $res = rate_picture( $image_id, $rate );
1101  if ($res==false)
1102  {
1103    global $conf;
1104    return new PwgError( 403, "Forbidden or rate not in ". implode(',',$conf['rate_items']));
1105  }
1106  return $res;
1107}
1108
1109
1110/**
1111 * returns a list of elements corresponding to a query search
1112 */
1113function ws_images_search($params, &$service)
1114{
1115  global $page;
1116  $images = array();
1117  include_once( PHPWG_ROOT_PATH .'include/functions_search.inc.php' );
1118  include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
1119
1120  $where_clauses = ws_std_image_sql_filter( $params, 'i.' );
1121  $order_by = ws_std_image_sql_order($params, 'i.');
1122
1123  $super_order_by = false;
1124  if ( !empty($order_by) )
1125  {
1126    global $conf;
1127    $conf['order_by'] = 'ORDER BY '.$order_by;
1128    $super_order_by=true; // quick_search_result might be faster
1129  }
1130
1131  $search_result = get_quick_search_results($params['query'],
1132      $super_order_by,
1133      implode(',', $where_clauses)
1134    );
1135
1136  $image_ids = array_slice(
1137      $search_result['items'],
1138      $params['page']*$params['per_page'],
1139      $params['per_page']
1140    );
1141
1142  if ( count($image_ids) )
1143  {
1144    $query = '
1145SELECT * FROM '.IMAGES_TABLE.'
1146  WHERE id IN ('.implode(',', $image_ids).')';
1147
1148    $image_ids = array_flip($image_ids);
1149    $result = pwg_query($query);
1150    while ($row = pwg_db_fetch_assoc($result))
1151    {
1152      $image = array();
1153      foreach ( array('id', 'width', 'height', 'hit') as $k )
1154      {
1155        if (isset($row[$k]))
1156        {
1157          $image[$k] = (int)$row[$k];
1158        }
1159      }
1160      foreach ( array('file', 'name', 'comment', 'date_creation', 'date_available') as $k )
1161      {
1162        $image[$k] = $row[$k];
1163      }
1164      $image = array_merge( $image, ws_std_get_urls($row) );
1165      $images[$image_ids[$image['id']]] = $image;
1166    }
1167    ksort($images, SORT_NUMERIC);
1168    $images = array_values($images);
1169  }
1170
1171
1172  return array( 'images' =>
1173    array (
1174      WS_XML_ATTRIBUTES =>
1175        array(
1176            'page' => $params['page'],
1177            'per_page' => $params['per_page'],
1178            'count' => count($images)
1179          ),
1180       WS_XML_CONTENT => new PwgNamedArray($images, 'image',
1181          ws_std_get_image_xml_attributes() )
1182      )
1183    );
1184}
1185
1186function ws_images_setPrivacyLevel($params, &$service)
1187{
1188  if (!is_admin())
1189  {
1190    return new PwgError(401, 'Access denied');
1191  }
1192  if (!$service->isPost())
1193  {
1194    return new PwgError(405, "This method requires HTTP POST");
1195  }
1196  $params['image_id'] = array_map( 'intval',$params['image_id'] );
1197  if ( empty($params['image_id']) )
1198  {
1199    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
1200  }
1201  global $conf;
1202  if ( !in_array( (int)$params['level'], $conf['available_permission_levels']) )
1203  {
1204    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid level");
1205  }
1206
1207  $query = '
1208UPDATE '.IMAGES_TABLE.'
1209  SET level='.(int)$params['level'].'
1210  WHERE id IN ('.implode(',',$params['image_id']).')';
1211  $result = pwg_query($query);
1212  $affected_rows = pwg_db_changes($result);
1213  if ($affected_rows)
1214  {
1215    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1216    invalidate_user_cache();
1217  }
1218  return $affected_rows;
1219}
1220
1221function ws_images_setRank($params, &$service)
1222{
1223  if (!is_admin())
1224  {
1225    return new PwgError(401, 'Access denied');
1226  }
1227
1228  if (!$service->isPost())
1229  {
1230    return new PwgError(405, "This method requires HTTP POST");
1231  }
1232
1233  // is the image_id valid?
1234  $params['image_id'] = (int)$params['image_id'];
1235  if ($params['image_id'] <= 0)
1236  {
1237    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
1238  }
1239
1240  // is the category valid?
1241  $params['category_id'] = (int)$params['category_id'];
1242  if ($params['category_id'] <= 0)
1243  {
1244    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid category_id");
1245  }
1246
1247  // is the rank valid?
1248  $params['rank'] = (int)$params['rank'];
1249  if ($params['rank'] <= 0)
1250  {
1251    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid rank");
1252  }
1253
1254  // does the image really exist?
1255  $query='
1256SELECT
1257    *
1258  FROM '.IMAGES_TABLE.'
1259  WHERE id = '.$params['image_id'].'
1260;';
1261
1262  $image_row = pwg_db_fetch_assoc(pwg_query($query));
1263  if ($image_row == null)
1264  {
1265    return new PwgError(404, "image_id not found");
1266  }
1267
1268  // is the image associated to this category?
1269  $query = '
1270SELECT
1271    image_id,
1272    category_id,
1273    rank
1274  FROM '.IMAGE_CATEGORY_TABLE.'
1275  WHERE image_id = '.$params['image_id'].'
1276    AND category_id = '.$params['category_id'].'
1277;';
1278  $category_row = pwg_db_fetch_assoc(pwg_query($query));
1279  if ($category_row == null)
1280  {
1281    return new PwgError(404, "This image is not associated to this category");
1282  }
1283
1284  // what is the current higher rank for this category?
1285  $query = '
1286SELECT
1287    MAX(rank) AS max_rank
1288  FROM '.IMAGE_CATEGORY_TABLE.'
1289  WHERE category_id = '.$params['category_id'].'
1290;';
1291  $result = pwg_query($query);
1292  $row = pwg_db_fetch_assoc($result);
1293
1294  if (is_numeric($row['max_rank']))
1295  {
1296    if ($params['rank'] > $row['max_rank'])
1297    {
1298      $params['rank'] = $row['max_rank'] + 1;
1299    }
1300  }
1301  else
1302  {
1303    $params['rank'] = 1;
1304  }
1305
1306  // update rank for all other photos in the same category
1307  $query = '
1308UPDATE '.IMAGE_CATEGORY_TABLE.'
1309  SET rank = rank + 1
1310  WHERE category_id = '.$params['category_id'].'
1311    AND rank IS NOT NULL
1312    AND rank >= '.$params['rank'].'
1313;';
1314  pwg_query($query);
1315
1316  // set the new rank for the photo
1317  $query = '
1318UPDATE '.IMAGE_CATEGORY_TABLE.'
1319  SET rank = '.$params['rank'].'
1320  WHERE image_id = '.$params['image_id'].'
1321    AND category_id = '.$params['category_id'].'
1322;';
1323  pwg_query($query);
1324
1325  // return data for client
1326  return array(
1327    'image_id' => $params['image_id'],
1328    'category_id' => $params['category_id'],
1329    'rank' => $params['rank'],
1330    );
1331}
1332
1333function ws_images_add_chunk($params, &$service)
1334{
1335  global $conf;
1336
1337  ws_logfile('[ws_images_add_chunk] welcome');
1338  // data
1339  // original_sum
1340  // type {thumb, file, high}
1341  // position
1342
1343  if (!is_admin())
1344  {
1345    return new PwgError(401, 'Access denied');
1346  }
1347
1348  if (!$service->isPost())
1349  {
1350    return new PwgError(405, "This method requires HTTP POST");
1351  }
1352
1353  foreach ($params as $param_key => $param_value) {
1354    if ('data' == $param_key) {
1355      continue;
1356    }
1357
1358    ws_logfile(
1359      sprintf(
1360        '[ws_images_add_chunk] input param "%s" : "%s"',
1361        $param_key,
1362        is_null($param_value) ? 'NULL' : $param_value
1363        )
1364      );
1365  }
1366
1367  $upload_dir = $conf['upload_dir'].'/buffer';
1368
1369  // create the upload directory tree if not exists
1370  if (!is_dir($upload_dir)) {
1371    umask(0000);
1372    $recursive = true;
1373    if (!@mkdir($upload_dir, 0777, $recursive))
1374    {
1375      return new PwgError(500, 'error during buffer directory creation');
1376    }
1377  }
1378
1379  if (!is_writable($upload_dir))
1380  {
1381    // last chance to make the directory writable
1382    @chmod($upload_dir, 0777);
1383
1384    if (!is_writable($upload_dir))
1385    {
1386      return new PwgError(500, 'buffer directory has no write access');
1387    }
1388  }
1389
1390  secure_directory($upload_dir);
1391
1392  $filename = sprintf(
1393    '%s-%s-%05u.block',
1394    $params['original_sum'],
1395    $params['type'],
1396    $params['position']
1397    );
1398
1399  ws_logfile('[ws_images_add_chunk] data length : '.strlen($params['data']));
1400
1401  $bytes_written = file_put_contents(
1402    $upload_dir.'/'.$filename,
1403    base64_decode($params['data'])
1404    );
1405
1406  if (false === $bytes_written) {
1407    return new PwgError(
1408      500,
1409      'an error has occured while writting chunk '.$params['position'].' for '.$params['type']
1410      );
1411  }
1412}
1413
1414function merge_chunks($output_filepath, $original_sum, $type)
1415{
1416  global $conf;
1417
1418  ws_logfile('[merge_chunks] input parameter $output_filepath : '.$output_filepath);
1419
1420  if (is_file($output_filepath))
1421  {
1422    unlink($output_filepath);
1423
1424    if (is_file($output_filepath))
1425    {
1426      new PwgError(500, '[merge_chunks] error while trying to remove existing '.$output_filepath);
1427      exit();
1428    }
1429  }
1430
1431  $upload_dir = $conf['upload_dir'].'/buffer';
1432  $pattern = '/'.$original_sum.'-'.$type.'/';
1433  $chunks = array();
1434
1435  if ($handle = opendir($upload_dir))
1436  {
1437    while (false !== ($file = readdir($handle)))
1438    {
1439      if (preg_match($pattern, $file))
1440      {
1441        ws_logfile($file);
1442        array_push($chunks, $upload_dir.'/'.$file);
1443      }
1444    }
1445    closedir($handle);
1446  }
1447
1448  sort($chunks);
1449
1450  if (function_exists('memory_get_usage')) {
1451    ws_logfile('[merge_chunks] memory_get_usage before loading chunks: '.memory_get_usage());
1452  }
1453
1454  $i = 0;
1455
1456  foreach ($chunks as $chunk)
1457  {
1458    $string = file_get_contents($chunk);
1459
1460    if (function_exists('memory_get_usage')) {
1461      ws_logfile('[merge_chunks] memory_get_usage on chunk '.++$i.': '.memory_get_usage());
1462    }
1463
1464    if (!file_put_contents($output_filepath, $string, FILE_APPEND))
1465    {
1466      new PwgError(500, '[merge_chunks] error while writting chunks for '.$output_filepath);
1467      exit();
1468    }
1469
1470    unlink($chunk);
1471  }
1472
1473  if (function_exists('memory_get_usage')) {
1474    ws_logfile('[merge_chunks] memory_get_usage after loading chunks: '.memory_get_usage());
1475  }
1476}
1477
1478/*
1479 * The $file_path must be the path of the basic "web sized" photo
1480 * The $type value will automatically modify the $file_path to the corresponding file
1481 */
1482function add_file($file_path, $type, $original_sum, $file_sum)
1483{
1484  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
1485
1486  $file_path = file_path_for_type($file_path, $type);
1487
1488  $upload_dir = dirname($file_path);
1489  if (substr(PHP_OS, 0, 3) == 'WIN')
1490  {
1491    $upload_dir = str_replace('/', DIRECTORY_SEPARATOR, $upload_dir);
1492  }
1493
1494  ws_logfile('[add_file] file_path  : '.$file_path);
1495  ws_logfile('[add_file] upload_dir : '.$upload_dir);
1496
1497  if (!is_dir($upload_dir)) {
1498    umask(0000);
1499    $recursive = true;
1500    if (!@mkdir($upload_dir, 0777, $recursive))
1501    {
1502      new PwgError(500, '[add_file] error during '.$type.' directory creation');
1503      exit();
1504    }
1505  }
1506
1507  if (!is_writable($upload_dir))
1508  {
1509    // last chance to make the directory writable
1510    @chmod($upload_dir, 0777);
1511
1512    if (!is_writable($upload_dir))
1513    {
1514      new PwgError(500, '[add_file] '.$type.' directory has no write access');
1515      exit();
1516    }
1517  }
1518
1519  secure_directory($upload_dir);
1520
1521  // merge the thumbnail
1522  merge_chunks($file_path, $original_sum, $type);
1523  chmod($file_path, 0644);
1524
1525  // check dumped thumbnail md5
1526  $dumped_md5 = md5_file($file_path);
1527  if ($dumped_md5 != $file_sum) {
1528    new PwgError(500, '[add_file] '.$type.' transfer failed');
1529    exit();
1530  }
1531
1532  list($width, $height) = getimagesize($file_path);
1533  $filesize = floor(filesize($file_path)/1024);
1534
1535  return array(
1536    'width' => $width,
1537    'height' => $height,
1538    'filesize' => $filesize,
1539    );
1540}
1541
1542function ws_images_addFile($params, &$service)
1543{
1544  // image_id
1545  // type {thumb, file, high}
1546  // sum
1547
1548  global $conf;
1549  if (!is_admin())
1550  {
1551    return new PwgError(401, 'Access denied');
1552  }
1553
1554  $params['image_id'] = (int)$params['image_id'];
1555  if ($params['image_id'] <= 0)
1556  {
1557    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
1558  }
1559
1560  //
1561  // what is the path?
1562  //
1563  $query = '
1564SELECT
1565    path,
1566    md5sum
1567  FROM '.IMAGES_TABLE.'
1568  WHERE id = '.$params['image_id'].'
1569;';
1570  list($file_path, $original_sum) = pwg_db_fetch_row(pwg_query($query));
1571
1572  // TODO only files added with web API can be updated with web API
1573
1574  //
1575  // makes sure directories are there and call the merge_chunks
1576  //
1577  $infos = add_file($file_path, $params['type'], $original_sum, $params['sum']);
1578
1579  //
1580  // update basic metadata from file
1581  //
1582  $update = array();
1583
1584  if ('high' == $params['type'])
1585  {
1586    $update['high_filesize'] = $infos['filesize'];
1587    $update['high_width'] = $infos['width'];
1588    $update['high_height'] = $infos['height'];
1589    $update['has_high'] = 'true';
1590  }
1591
1592  if ('file' == $params['type'])
1593  {
1594    $update['filesize'] = $infos['filesize'];
1595    $update['width'] = $infos['width'];
1596    $update['height'] = $infos['height'];
1597  }
1598
1599  // we may have nothing to update at database level, for example with a
1600  // thumbnail update
1601  if (count($update) > 0)
1602  {
1603    $update['id'] = $params['image_id'];
1604
1605    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1606    mass_updates(
1607      IMAGES_TABLE,
1608      array(
1609        'primary' => array('id'),
1610        'update'  => array_diff(array_keys($update), array('id'))
1611        ),
1612      array($update)
1613      );
1614  }
1615}
1616
1617function ws_images_add($params, &$service)
1618{
1619  global $conf, $user;
1620  if (!is_admin())
1621  {
1622    return new PwgError(401, 'Access denied');
1623  }
1624
1625  foreach ($params as $param_key => $param_value) {
1626    ws_logfile(
1627      sprintf(
1628        '[pwg.images.add] input param "%s" : "%s"',
1629        $param_key,
1630        is_null($param_value) ? 'NULL' : $param_value
1631        )
1632      );
1633  }
1634
1635  // does the image already exists ?
1636  if ('md5sum' == $conf['uniqueness_mode'])
1637  {
1638    $where_clause = "md5sum = '".$params['original_sum']."'";
1639  }
1640  if ('filename' == $conf['uniqueness_mode'])
1641  {
1642    $where_clause = "file = '".$params['original_filename']."'";
1643  }
1644
1645  $query = '
1646SELECT
1647    COUNT(*) AS counter
1648  FROM '.IMAGES_TABLE.'
1649  WHERE '.$where_clause.'
1650;';
1651  list($counter) = pwg_db_fetch_row(pwg_query($query));
1652  if ($counter != 0) {
1653    return new PwgError(500, 'file already exists');
1654  }
1655
1656  // current date
1657  list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
1658  list($year, $month, $day) = preg_split('/[^\d]/', $dbnow, 4);
1659
1660  // upload directory hierarchy
1661  $upload_dir = sprintf(
1662    $conf['upload_dir'].'/%s/%s/%s',
1663    $year,
1664    $month,
1665    $day
1666    );
1667
1668  // compute file path
1669  $date_string = preg_replace('/[^\d]/', '', $dbnow);
1670  $random_string = substr($params['file_sum'], 0, 8);
1671  $filename_wo_ext = $date_string.'-'.$random_string;
1672  $file_path = $upload_dir.'/'.$filename_wo_ext.'.jpg';
1673
1674  // add files
1675  $file_infos  = add_file($file_path, 'file',  $params['original_sum'], $params['file_sum']);
1676  $thumb_infos = add_file($file_path, 'thumb', $params['original_sum'], $params['thumbnail_sum']);
1677
1678  if (isset($params['high_sum']))
1679  {
1680    $high_infos = add_file($file_path, 'high', $params['original_sum'], $params['high_sum']);
1681  }
1682
1683  // database registration
1684  $insert = array(
1685    'file' => !empty($params['original_filename']) ? $params['original_filename'] : $filename_wo_ext.'.jpg',
1686    'date_available' => $dbnow,
1687    'tn_ext' => 'jpg',
1688    'name' => $params['name'],
1689    'path' => $file_path,
1690    'filesize' => $file_infos['filesize'],
1691    'width' => $file_infos['width'],
1692    'height' => $file_infos['height'],
1693    'md5sum' => $params['original_sum'],
1694    'added_by' => $user['id'],
1695    );
1696
1697  $info_columns = array(
1698    'name',
1699    'author',
1700    'comment',
1701    'level',
1702    'date_creation',
1703    );
1704
1705  foreach ($info_columns as $key)
1706  {
1707    if (isset($params[$key]))
1708    {
1709      $insert[$key] = $params[$key];
1710    }
1711  }
1712
1713  if (isset($params['high_sum']))
1714  {
1715    $insert['has_high'] = 'true';
1716    $insert['high_filesize'] = $high_infos['filesize'];
1717    $insert['high_width'] = $high_infos['width'];
1718    $insert['high_height'] = $high_infos['height'];
1719  }
1720
1721  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1722  mass_inserts(
1723    IMAGES_TABLE,
1724    array_keys($insert),
1725    array($insert)
1726    );
1727
1728  $image_id = pwg_db_insert_id(IMAGES_TABLE);
1729
1730  // let's add links between the image and the categories
1731  if (isset($params['categories']))
1732  {
1733    ws_add_image_category_relations($image_id, $params['categories']);
1734  }
1735
1736  // and now, let's create tag associations
1737  if (isset($params['tag_ids']) and !empty($params['tag_ids']))
1738  {
1739    set_tags(
1740      explode(',', $params['tag_ids']),
1741      $image_id
1742      );
1743  }
1744
1745  // update metadata from the uploaded file (exif/iptc)
1746  require_once(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
1747  update_metadata(array($image_id=>$file_path));
1748
1749  invalidate_user_cache();
1750}
1751
1752function ws_images_addSimple($params, &$service)
1753{
1754  global $conf;
1755  if (!is_admin())
1756  {
1757    return new PwgError(401, 'Access denied');
1758  }
1759
1760  if (!$service->isPost())
1761  {
1762    return new PwgError(405, "This method requires HTTP POST");
1763  }
1764
1765  if (!isset($_FILES['image']))
1766  {
1767    return new PwgError(405, "The image (file) parameter is missing");
1768  }
1769
1770  $params['image_id'] = (int)$params['image_id'];
1771  if ($params['image_id'] > 0)
1772  {
1773    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1774
1775    $query='
1776SELECT *
1777  FROM '.IMAGES_TABLE.'
1778  WHERE id = '.$params['image_id'].'
1779;';
1780
1781    $image_row = pwg_db_fetch_assoc(pwg_query($query));
1782    if ($image_row == null)
1783    {
1784      return new PwgError(404, "image_id not found");
1785    }
1786  }
1787
1788  // category
1789  $params['category'] = (int)$params['category'];
1790  if ($params['category'] <= 0 and $params['image_id'] <= 0)
1791  {
1792    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid category_id");
1793  }
1794
1795  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
1796
1797  $image_id = add_uploaded_file(
1798    $_FILES['image']['tmp_name'],
1799    $_FILES['image']['name'],
1800    $params['category'] > 0 ? array($params['category']) : null,
1801    8,
1802    $params['image_id'] > 0 ? $params['image_id'] : null
1803    );
1804
1805  $info_columns = array(
1806    'name',
1807    'author',
1808    'comment',
1809    'level',
1810    'date_creation',
1811    );
1812
1813  foreach ($info_columns as $key)
1814  {
1815    if (isset($params[$key]))
1816    {
1817      $update[$key] = $params[$key];
1818    }
1819  }
1820
1821  if (count(array_keys($update)) > 0)
1822  {
1823    $update['id'] = $image_id;
1824
1825    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1826    mass_updates(
1827      IMAGES_TABLE,
1828      array(
1829        'primary' => array('id'),
1830        'update'  => array_diff(array_keys($update), array('id'))
1831        ),
1832      array($update)
1833      );
1834  }
1835
1836
1837  if (isset($params['tags']) and !empty($params['tags']))
1838  {
1839    $tag_ids = array();
1840    $tag_names = explode(',', $params['tags']);
1841    foreach ($tag_names as $tag_name)
1842    {
1843      $tag_id = tag_id_from_tag_name($tag_name);
1844      array_push($tag_ids, $tag_id);
1845    }
1846
1847    add_tags($tag_ids, array($image_id));
1848  }
1849
1850  $url_params = array('image_id' => $image_id);
1851
1852  if ($params['category'] > 0)
1853  {
1854    $query = '
1855SELECT id, name, permalink
1856  FROM '.CATEGORIES_TABLE.'
1857  WHERE id = '.$params['category'].'
1858;';
1859    $result = pwg_query($query);
1860    $category = pwg_db_fetch_assoc($result);
1861
1862    $url_params['section'] = 'categories';
1863    $url_params['category'] = $category;
1864  }
1865
1866  // update metadata from the uploaded file (exif/iptc), even if the sync
1867  // was already performed by add_uploaded_file().
1868  $query = '
1869SELECT
1870    path
1871  FROM '.IMAGES_TABLE.'
1872  WHERE id = '.$image_id.'
1873;';
1874  list($file_path) = pwg_db_fetch_row(pwg_query($query));
1875
1876  require_once(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
1877  update_metadata(array($image_id=>$file_path));
1878
1879  return array(
1880    'image_id' => $image_id,
1881    'url' => make_picture_url($url_params),
1882    );
1883}
1884
1885/**
1886 * perform a login (web service method)
1887 */
1888function ws_session_login($params, &$service)
1889{
1890  global $conf;
1891
1892  if (!$service->isPost())
1893  {
1894    return new PwgError(405, "This method requires HTTP POST");
1895  }
1896  if (try_log_user($params['username'], $params['password'],false))
1897  {
1898    return true;
1899  }
1900  return new PwgError(999, 'Invalid username/password');
1901}
1902
1903
1904/**
1905 * performs a logout (web service method)
1906 */
1907function ws_session_logout($params, &$service)
1908{
1909  if (!is_a_guest())
1910  {
1911    logout_user();
1912  }
1913  return true;
1914}
1915
1916function ws_session_getStatus($params, &$service)
1917{
1918  global $user;
1919  $res = array();
1920  $res['username'] = is_a_guest() ? 'guest' : stripslashes($user['username']);
1921  foreach ( array('status', 'theme', 'language') as $k )
1922  {
1923    $res[$k] = $user[$k];
1924  }
1925  $res['pwg_token'] = get_pwg_token();
1926  $res['charset'] = get_pwg_charset();
1927
1928  list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
1929  $res['current_datetime'] = $dbnow;
1930
1931  return $res;
1932}
1933
1934
1935/**
1936 * returns a list of tags (web service method)
1937 */
1938function ws_tags_getList($params, &$service)
1939{
1940  $tags = get_available_tags();
1941  if ($params['sort_by_counter'])
1942  {
1943    usort($tags, create_function('$a,$b', 'return -$a["counter"]+$b["counter"];') );
1944  }
1945  else
1946  {
1947    usort($tags, 'tag_alpha_compare');
1948  }
1949  for ($i=0; $i<count($tags); $i++)
1950  {
1951    $tags[$i]['id'] = (int)$tags[$i]['id'];
1952    $tags[$i]['counter'] = (int)$tags[$i]['counter'];
1953    $tags[$i]['url'] = make_index_url(
1954        array(
1955          'section'=>'tags',
1956          'tags'=>array($tags[$i])
1957        )
1958      );
1959  }
1960  return array('tags' => new PwgNamedArray($tags, 'tag', array('id','url_name','url', 'name', 'counter' )) );
1961}
1962
1963/**
1964 * returns the list of tags as you can see them in administration (web
1965 * service method).
1966 *
1967 * Only admin can run this method and permissions are not taken into
1968 * account.
1969 */
1970function ws_tags_getAdminList($params, &$service)
1971{
1972  if (!is_admin())
1973  {
1974    return new PwgError(401, 'Access denied');
1975  }
1976
1977  $tags = get_all_tags();
1978  return array(
1979    'tags' => new PwgNamedArray(
1980      $tags,
1981      'tag',
1982      array(
1983        'name',
1984        'id',
1985        'url_name',
1986        )
1987      )
1988    );
1989}
1990
1991/**
1992 * returns a list of images for tags (web service method)
1993 */
1994function ws_tags_getImages($params, &$service)
1995{
1996  @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
1997  global $conf;
1998
1999  // first build all the tag_ids we are interested in
2000  $params['tag_id'] = array_map( 'intval',$params['tag_id'] );
2001  $tags = find_tags($params['tag_id'], $params['tag_url_name'], $params['tag_name']);
2002  $tags_by_id = array();
2003  foreach( $tags as $tag )
2004  {
2005    $tags['id'] = (int)$tag['id'];
2006    $tags_by_id[ $tag['id'] ] = $tag;
2007  }
2008  unset($tags);
2009  $tag_ids = array_keys($tags_by_id);
2010
2011
2012  $where_clauses = ws_std_image_sql_filter($params);
2013  if (!empty($where_clauses))
2014  {
2015    $where_clauses = implode( ' AND ', $where_clauses);
2016  }
2017  $image_ids = get_image_ids_for_tags(
2018    $tag_ids,
2019    $params['tag_mode_and'] ? 'AND' : 'OR',
2020    $where_clauses,
2021    ws_std_image_sql_order($params) );
2022
2023
2024  $image_ids = array_slice($image_ids, (int)($params['per_page']*$params['page']), (int)$params['per_page'] );
2025
2026  $image_tag_map = array();
2027  if ( !empty($image_ids) and !$params['tag_mode_and'] )
2028  { // build list of image ids with associated tags per image
2029    $query = '
2030SELECT image_id, GROUP_CONCAT(tag_id) AS tag_ids
2031  FROM '.IMAGE_TAG_TABLE.'
2032  WHERE tag_id IN ('.implode(',',$tag_ids).') AND image_id IN ('.implode(',',$image_ids).')
2033  GROUP BY image_id';
2034    $result = pwg_query($query);
2035    while ( $row=pwg_db_fetch_assoc($result) )
2036    {
2037      $row['image_id'] = (int)$row['image_id'];
2038      array_push( $image_ids, $row['image_id'] );
2039      $image_tag_map[ $row['image_id'] ] = explode(',', $row['tag_ids']);
2040    }
2041  }
2042
2043  $images = array();
2044  if (!empty($image_ids))
2045  {
2046    $rank_of = array_flip($image_ids);
2047    $result = pwg_query('
2048SELECT * FROM '.IMAGES_TABLE.'
2049  WHERE id IN ('.implode(',',$image_ids).')');
2050    while ($row = pwg_db_fetch_assoc($result))
2051    {
2052      $image = array();
2053      $image['rank'] = $rank_of[ $row['id'] ];
2054      foreach ( array('id', 'width', 'height', 'hit') as $k )
2055      {
2056        if (isset($row[$k]))
2057        {
2058          $image[$k] = (int)$row[$k];
2059        }
2060      }
2061      foreach ( array('file', 'name', 'comment', 'date_creation', 'date_available') as $k )
2062      {
2063        $image[$k] = $row[$k];
2064      }
2065      $image = array_merge( $image, ws_std_get_urls($row) );
2066
2067      $image_tag_ids = ($params['tag_mode_and']) ? $tag_ids : $image_tag_map[$image['id']];
2068      $image_tags = array();
2069      foreach ($image_tag_ids as $tag_id)
2070      {
2071        $url = make_index_url(
2072                 array(
2073                  'section'=>'tags',
2074                  'tags'=> array($tags_by_id[$tag_id])
2075                )
2076              );
2077        $page_url = make_picture_url(
2078                 array(
2079                  'section'=>'tags',
2080                  'tags'=> array($tags_by_id[$tag_id]),
2081                  'image_id' => $row['id'],
2082                  'image_file' => $row['file'],
2083                )
2084              );
2085        array_push($image_tags, array(
2086                'id' => (int)$tag_id,
2087                'url' => $url,
2088                'page_url' => $page_url,
2089              )
2090            );
2091      }
2092      $image['tags'] = new PwgNamedArray($image_tags, 'tag',
2093              array('id','url_name','url','page_url')
2094            );
2095      array_push($images, $image);
2096    }
2097    usort($images, 'rank_compare');
2098    unset($rank_of);
2099  }
2100
2101  return array( 'images' =>
2102    array (
2103      WS_XML_ATTRIBUTES =>
2104        array(
2105            'page' => $params['page'],
2106            'per_page' => $params['per_page'],
2107            'count' => count($images)
2108          ),
2109       WS_XML_CONTENT => new PwgNamedArray($images, 'image',
2110          ws_std_get_image_xml_attributes() )
2111      )
2112    );
2113}
2114
2115function ws_categories_add($params, &$service)
2116{
2117  if (!is_admin())
2118  {
2119    return new PwgError(401, 'Access denied');
2120  }
2121
2122  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2123
2124  $creation_output = create_virtual_category(
2125    $params['name'],
2126    $params['parent']
2127    );
2128
2129  if (isset($creation_output['error']))
2130  {
2131    return new PwgError(500, $creation_output['error']);
2132  }
2133
2134  invalidate_user_cache();
2135
2136  return $creation_output;
2137}
2138
2139function ws_tags_add($params, &$service)
2140{
2141  if (!is_admin())
2142  {
2143    return new PwgError(401, 'Access denied');
2144  }
2145
2146  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2147
2148  $creation_output = create_tag($params['name']);
2149
2150  if (isset($creation_output['error']))
2151  {
2152    return new PwgError(500, $creation_output['error']);
2153  }
2154
2155  return $creation_output;
2156}
2157
2158function ws_images_exist($params, &$service)
2159{
2160  global $conf;
2161
2162  if (!is_admin())
2163  {
2164    return new PwgError(401, 'Access denied');
2165  }
2166
2167  $split_pattern = '/[\s,;\|]/';
2168
2169  if ('md5sum' == $conf['uniqueness_mode'])
2170  {
2171    // search among photos the list of photos already added, based on md5sum
2172    // list
2173    $md5sums = preg_split(
2174      $split_pattern,
2175      $params['md5sum_list'],
2176      -1,
2177      PREG_SPLIT_NO_EMPTY
2178    );
2179
2180    $query = '
2181SELECT
2182    id,
2183    md5sum
2184  FROM '.IMAGES_TABLE.'
2185  WHERE md5sum IN (\''.implode("','", $md5sums).'\')
2186;';
2187    $id_of_md5 = simple_hash_from_query($query, 'md5sum', 'id');
2188
2189    $result = array();
2190
2191    foreach ($md5sums as $md5sum)
2192    {
2193      $result[$md5sum] = null;
2194      if (isset($id_of_md5[$md5sum]))
2195      {
2196        $result[$md5sum] = $id_of_md5[$md5sum];
2197      }
2198    }
2199  }
2200
2201  if ('filename' == $conf['uniqueness_mode'])
2202  {
2203    // search among photos the list of photos already added, based on
2204    // filename list
2205    $filenames = preg_split(
2206      $split_pattern,
2207      $params['filename_list'],
2208      -1,
2209      PREG_SPLIT_NO_EMPTY
2210    );
2211
2212    $query = '
2213SELECT
2214    id,
2215    file
2216  FROM '.IMAGES_TABLE.'
2217  WHERE file IN (\''.implode("','", $filenames).'\')
2218;';
2219    $id_of_filename = simple_hash_from_query($query, 'file', 'id');
2220
2221    $result = array();
2222
2223    foreach ($filenames as $filename)
2224    {
2225      $result[$filename] = null;
2226      if (isset($id_of_filename[$filename]))
2227      {
2228        $result[$filename] = $id_of_filename[$filename];
2229      }
2230    }
2231  }
2232
2233  return $result;
2234}
2235
2236function ws_images_checkFiles($params, &$service)
2237{
2238  if (!is_admin())
2239  {
2240    return new PwgError(401, 'Access denied');
2241  }
2242
2243  // input parameters
2244  //
2245  // image_id
2246  // thumbnail_sum
2247  // file_sum
2248  // high_sum
2249
2250  $params['image_id'] = (int)$params['image_id'];
2251  if ($params['image_id'] <= 0)
2252  {
2253    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
2254  }
2255
2256  $query = '
2257SELECT
2258    path
2259  FROM '.IMAGES_TABLE.'
2260  WHERE id = '.$params['image_id'].'
2261;';
2262  $result = pwg_query($query);
2263  if (pwg_db_num_rows($result) == 0) {
2264    return new PwgError(404, "image_id not found");
2265  }
2266  list($path) = pwg_db_fetch_row($result);
2267
2268  $ret = array();
2269
2270  foreach (array('thumb', 'file', 'high') as $type) {
2271    $param_name = $type;
2272    if ('thumb' == $type) {
2273      $param_name = 'thumbnail';
2274    }
2275
2276    if (isset($params[$param_name.'_sum'])) {
2277      include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
2278      $type_path = file_path_for_type($path, $type);
2279      if (!is_file($type_path)) {
2280        $ret[$param_name] = 'missing';
2281      }
2282      else {
2283        if (md5_file($type_path) != $params[$param_name.'_sum']) {
2284          $ret[$param_name] = 'differs';
2285        }
2286        else {
2287          $ret[$param_name] = 'equals';
2288        }
2289      }
2290    }
2291  }
2292
2293  return $ret;
2294}
2295
2296function ws_images_setInfo($params, &$service)
2297{
2298  global $conf;
2299  if (!is_admin())
2300  {
2301    return new PwgError(401, 'Access denied');
2302  }
2303
2304  if (!$service->isPost())
2305  {
2306    return new PwgError(405, "This method requires HTTP POST");
2307  }
2308
2309  $params['image_id'] = (int)$params['image_id'];
2310  if ($params['image_id'] <= 0)
2311  {
2312    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
2313  }
2314
2315  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2316
2317  $query='
2318SELECT *
2319  FROM '.IMAGES_TABLE.'
2320  WHERE id = '.$params['image_id'].'
2321;';
2322
2323  $image_row = pwg_db_fetch_assoc(pwg_query($query));
2324  if ($image_row == null)
2325  {
2326    return new PwgError(404, "image_id not found");
2327  }
2328
2329  // database registration
2330  $update = array();
2331
2332  $info_columns = array(
2333    'name',
2334    'author',
2335    'comment',
2336    'level',
2337    'date_creation',
2338    );
2339
2340  foreach ($info_columns as $key)
2341  {
2342    if (isset($params[$key]))
2343    {
2344      if ('fill_if_empty' == $params['single_value_mode'])
2345      {
2346        if (empty($image_row[$key]))
2347        {
2348          $update[$key] = $params[$key];
2349        }
2350      }
2351      elseif ('replace' == $params['single_value_mode'])
2352      {
2353        $update[$key] = $params[$key];
2354      }
2355      else
2356      {
2357        new PwgError(
2358          500,
2359          '[ws_images_setInfo]'
2360          .' invalid parameter single_value_mode "'.$params['single_value_mode'].'"'
2361          .', possible values are {fill_if_empty, replace}.'
2362          );
2363        exit();
2364      }
2365    }
2366  }
2367
2368  if (count(array_keys($update)) > 0)
2369  {
2370    $update['id'] = $params['image_id'];
2371
2372    mass_updates(
2373      IMAGES_TABLE,
2374      array(
2375        'primary' => array('id'),
2376        'update'  => array_diff(array_keys($update), array('id'))
2377        ),
2378      array($update)
2379      );
2380  }
2381
2382  if (isset($params['categories']))
2383  {
2384    ws_add_image_category_relations(
2385      $params['image_id'],
2386      $params['categories'],
2387      ('replace' == $params['multiple_value_mode'] ? true : false)
2388      );
2389  }
2390
2391  // and now, let's create tag associations
2392  if (isset($params['tag_ids']))
2393  {
2394    $tag_ids = explode(',', $params['tag_ids']);
2395
2396    if ('replace' == $params['multiple_value_mode'])
2397    {
2398      set_tags(
2399        $tag_ids,
2400        $params['image_id']
2401        );
2402    }
2403    elseif ('append' == $params['multiple_value_mode'])
2404    {
2405      add_tags(
2406        $tag_ids,
2407        array($params['image_id'])
2408        );
2409    }
2410    else
2411    {
2412      new PwgError(
2413        500,
2414        '[ws_images_setInfo]'
2415        .' invalid parameter multiple_value_mode "'.$params['multiple_value_mode'].'"'
2416        .', possible values are {replace, append}.'
2417        );
2418      exit();
2419    }
2420  }
2421
2422  invalidate_user_cache();
2423}
2424
2425function ws_images_delete($params, &$service)
2426{
2427  global $conf;
2428  if (!is_admin())
2429  {
2430    return new PwgError(401, 'Access denied');
2431  }
2432
2433  if (!$service->isPost())
2434  {
2435    return new PwgError(405, "This method requires HTTP POST");
2436  }
2437
2438  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
2439  {
2440    return new PwgError(403, 'Invalid security token');
2441  }
2442
2443  $params['image_id'] = preg_split(
2444    '/[\s,;\|]/',
2445    $params['image_id'],
2446    -1,
2447    PREG_SPLIT_NO_EMPTY
2448    );
2449  $params['image_id'] = array_map('intval', $params['image_id']);
2450
2451  $image_ids = array();
2452  foreach ($params['image_id'] as $image_id)
2453  {
2454    if ($image_id > 0)
2455    {
2456      array_push($image_ids, $image_id);
2457    }
2458  }
2459
2460  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2461  delete_elements($image_ids, true);
2462}
2463
2464function ws_add_image_category_relations($image_id, $categories_string, $replace_mode=false)
2465{
2466  // let's add links between the image and the categories
2467  //
2468  // $params['categories'] should look like 123,12;456,auto;789 which means:
2469  //
2470  // 1. associate with category 123 on rank 12
2471  // 2. associate with category 456 on automatic rank
2472  // 3. associate with category 789 on automatic rank
2473  $cat_ids = array();
2474  $rank_on_category = array();
2475  $search_current_ranks = false;
2476
2477  $tokens = explode(';', $categories_string);
2478  foreach ($tokens as $token)
2479  {
2480    @list($cat_id, $rank) = explode(',', $token);
2481
2482    if (!preg_match('/^\d+$/', $cat_id))
2483    {
2484      continue;
2485    }
2486
2487    array_push($cat_ids, $cat_id);
2488
2489    if (!isset($rank))
2490    {
2491      $rank = 'auto';
2492    }
2493    $rank_on_category[$cat_id] = $rank;
2494
2495    if ($rank == 'auto')
2496    {
2497      $search_current_ranks = true;
2498    }
2499  }
2500
2501  $cat_ids = array_unique($cat_ids);
2502
2503  if (count($cat_ids) == 0)
2504  {
2505    new PwgError(
2506      500,
2507      '[ws_add_image_category_relations] there is no category defined in "'.$categories_string.'"'
2508      );
2509    exit();
2510  }
2511
2512  $query = '
2513SELECT
2514    id
2515  FROM '.CATEGORIES_TABLE.'
2516  WHERE id IN ('.implode(',', $cat_ids).')
2517;';
2518  $db_cat_ids = array_from_query($query, 'id');
2519
2520  $unknown_cat_ids = array_diff($cat_ids, $db_cat_ids);
2521  if (count($unknown_cat_ids) != 0)
2522  {
2523    new PwgError(
2524      500,
2525      '[ws_add_image_category_relations] the following categories are unknown: '.implode(', ', $unknown_cat_ids)
2526      );
2527    exit();
2528  }
2529
2530  $to_update_cat_ids = array();
2531
2532  // in case of replace mode, we first check the existing associations
2533  $query = '
2534SELECT
2535    category_id
2536  FROM '.IMAGE_CATEGORY_TABLE.'
2537  WHERE image_id = '.$image_id.'
2538;';
2539  $existing_cat_ids = array_from_query($query, 'category_id');
2540
2541  if ($replace_mode)
2542  {
2543    $to_remove_cat_ids = array_diff($existing_cat_ids, $cat_ids);
2544    if (count($to_remove_cat_ids) > 0)
2545    {
2546      $query = '
2547DELETE
2548  FROM '.IMAGE_CATEGORY_TABLE.'
2549  WHERE image_id = '.$image_id.'
2550    AND category_id IN ('.implode(', ', $to_remove_cat_ids).')
2551;';
2552      pwg_query($query);
2553      update_category($to_remove_cat_ids);
2554    }
2555  }
2556
2557  $new_cat_ids = array_diff($cat_ids, $existing_cat_ids);
2558  if (count($new_cat_ids) == 0)
2559  {
2560    return true;
2561  }
2562
2563  if ($search_current_ranks)
2564  {
2565    $query = '
2566SELECT
2567    category_id,
2568    MAX(rank) AS max_rank
2569  FROM '.IMAGE_CATEGORY_TABLE.'
2570  WHERE rank IS NOT NULL
2571    AND category_id IN ('.implode(',', $new_cat_ids).')
2572  GROUP BY category_id
2573;';
2574    $current_rank_of = simple_hash_from_query(
2575      $query,
2576      'category_id',
2577      'max_rank'
2578      );
2579
2580    foreach ($new_cat_ids as $cat_id)
2581    {
2582      if (!isset($current_rank_of[$cat_id]))
2583      {
2584        $current_rank_of[$cat_id] = 0;
2585      }
2586
2587      if ('auto' == $rank_on_category[$cat_id])
2588      {
2589        $rank_on_category[$cat_id] = $current_rank_of[$cat_id] + 1;
2590      }
2591    }
2592  }
2593
2594  $inserts = array();
2595
2596  foreach ($new_cat_ids as $cat_id)
2597  {
2598    array_push(
2599      $inserts,
2600      array(
2601        'image_id' => $image_id,
2602        'category_id' => $cat_id,
2603        'rank' => $rank_on_category[$cat_id],
2604        )
2605      );
2606  }
2607
2608  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2609  mass_inserts(
2610    IMAGE_CATEGORY_TABLE,
2611    array_keys($inserts[0]),
2612    $inserts
2613    );
2614
2615  update_category($new_cat_ids);
2616}
2617
2618function ws_categories_setInfo($params, &$service)
2619{
2620  global $conf;
2621  if (!is_admin())
2622  {
2623    return new PwgError(401, 'Access denied');
2624  }
2625
2626  if (!$service->isPost())
2627  {
2628    return new PwgError(405, "This method requires HTTP POST");
2629  }
2630
2631  // category_id
2632  // name
2633  // comment
2634
2635  $params['category_id'] = (int)$params['category_id'];
2636  if ($params['category_id'] <= 0)
2637  {
2638    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid category_id");
2639  }
2640
2641  // database registration
2642  $update = array(
2643    'id' => $params['category_id'],
2644    );
2645
2646  $info_columns = array(
2647    'name',
2648    'comment',
2649    );
2650
2651  $perform_update = false;
2652  foreach ($info_columns as $key)
2653  {
2654    if (isset($params[$key]))
2655    {
2656      $perform_update = true;
2657      $update[$key] = $params[$key];
2658    }
2659  }
2660
2661  if ($perform_update)
2662  {
2663    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2664    mass_updates(
2665      CATEGORIES_TABLE,
2666      array(
2667        'primary' => array('id'),
2668        'update'  => array_diff(array_keys($update), array('id'))
2669        ),
2670      array($update)
2671      );
2672  }
2673
2674}
2675
2676function ws_categories_setRepresentative($params, &$service)
2677{
2678  global $conf;
2679
2680  if (!is_admin())
2681  {
2682    return new PwgError(401, 'Access denied');
2683  }
2684
2685  if (!$service->isPost())
2686  {
2687    return new PwgError(405, "This method requires HTTP POST");
2688  }
2689
2690  // category_id
2691  // image_id
2692
2693  $params['category_id'] = (int)$params['category_id'];
2694  if ($params['category_id'] <= 0)
2695  {
2696    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid category_id");
2697  }
2698
2699  // does the category really exist?
2700  $query='
2701SELECT
2702    *
2703  FROM '.CATEGORIES_TABLE.'
2704  WHERE id = '.$params['category_id'].'
2705;';
2706  $row = pwg_db_fetch_assoc(pwg_query($query));
2707  if ($row == null)
2708  {
2709    return new PwgError(404, "category_id not found");
2710  }
2711
2712  $params['image_id'] = (int)$params['image_id'];
2713  if ($params['image_id'] <= 0)
2714  {
2715    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
2716  }
2717
2718  // does the image really exist?
2719  $query='
2720SELECT
2721    *
2722  FROM '.IMAGES_TABLE.'
2723  WHERE id = '.$params['image_id'].'
2724;';
2725
2726  $row = pwg_db_fetch_assoc(pwg_query($query));
2727  if ($row == null)
2728  {
2729    return new PwgError(404, "image_id not found");
2730  }
2731
2732  // apply change
2733  $query = '
2734UPDATE '.CATEGORIES_TABLE.'
2735  SET representative_picture_id = '.$params['image_id'].'
2736  WHERE id = '.$params['category_id'].'
2737;';
2738  pwg_query($query);
2739
2740  $query = '
2741UPDATE '.USER_CACHE_CATEGORIES_TABLE.'
2742  SET user_representative_picture_id = NULL
2743  WHERE cat_id = '.$params['category_id'].'
2744;';
2745  pwg_query($query);
2746}
2747
2748function ws_categories_delete($params, &$service)
2749{
2750  global $conf;
2751  if (!is_admin())
2752  {
2753    return new PwgError(401, 'Access denied');
2754  }
2755
2756  if (!$service->isPost())
2757  {
2758    return new PwgError(405, "This method requires HTTP POST");
2759  }
2760
2761  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
2762  {
2763    return new PwgError(403, 'Invalid security token');
2764  }
2765
2766  $modes = array('no_delete', 'delete_orphans', 'force_delete');
2767  if (!in_array($params['photo_deletion_mode'], $modes))
2768  {
2769    return new PwgError(
2770      500,
2771      '[ws_categories_delete]'
2772      .' invalid parameter photo_deletion_mode "'.$params['photo_deletion_mode'].'"'
2773      .', possible values are {'.implode(', ', $modes).'}.'
2774      );
2775  }
2776
2777  $params['category_id'] = preg_split(
2778    '/[\s,;\|]/',
2779    $params['category_id'],
2780    -1,
2781    PREG_SPLIT_NO_EMPTY
2782    );
2783  $params['category_id'] = array_map('intval', $params['category_id']);
2784
2785  $category_ids = array();
2786  foreach ($params['category_id'] as $category_id)
2787  {
2788    if ($category_id > 0)
2789    {
2790      array_push($category_ids, $category_id);
2791    }
2792  }
2793
2794  if (count($category_ids) == 0)
2795  {
2796    return;
2797  }
2798
2799  $query = '
2800SELECT id
2801  FROM '.CATEGORIES_TABLE.'
2802  WHERE id IN ('.implode(',', $category_ids).')
2803;';
2804  $category_ids = array_from_query($query, 'id');
2805
2806  if (count($category_ids) == 0)
2807  {
2808    return;
2809  }
2810
2811  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2812  delete_categories($category_ids, $params['photo_deletion_mode']);
2813  update_global_rank();
2814}
2815
2816function ws_categories_move($params, &$service)
2817{
2818  global $conf, $page;
2819
2820  if (!is_admin())
2821  {
2822    return new PwgError(401, 'Access denied');
2823  }
2824
2825  if (!$service->isPost())
2826  {
2827    return new PwgError(405, "This method requires HTTP POST");
2828  }
2829
2830  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
2831  {
2832    return new PwgError(403, 'Invalid security token');
2833  }
2834
2835  $params['category_id'] = preg_split(
2836    '/[\s,;\|]/',
2837    $params['category_id'],
2838    -1,
2839    PREG_SPLIT_NO_EMPTY
2840    );
2841  $params['category_id'] = array_map('intval', $params['category_id']);
2842
2843  $category_ids = array();
2844  foreach ($params['category_id'] as $category_id)
2845  {
2846    if ($category_id > 0)
2847    {
2848      array_push($category_ids, $category_id);
2849    }
2850  }
2851
2852  if (count($category_ids) == 0)
2853  {
2854    return new PwgError(403, 'Invalid category_id input parameter, no category to move');
2855  }
2856
2857  // we can't move physical categories
2858  $categories_in_db = array();
2859
2860  $query = '
2861SELECT
2862    id,
2863    name,
2864    dir
2865  FROM '.CATEGORIES_TABLE.'
2866  WHERE id IN ('.implode(',', $category_ids).')
2867;';
2868  $result = pwg_query($query);
2869  while ($row = pwg_db_fetch_assoc($result))
2870  {
2871    $categories_in_db[$row['id']] = $row;
2872    // we break on error at first physical category detected
2873    if (!empty($row['dir']))
2874    {
2875      $row['name'] = strip_tags(
2876        trigger_event(
2877          'render_category_name',
2878          $row['name'],
2879          'ws_categories_move'
2880          )
2881        );
2882
2883      return new PwgError(
2884        403,
2885        sprintf(
2886          'Category %s (%u) is not a virtual category, you cannot move it',
2887          $row['name'],
2888          $row['id']
2889          )
2890        );
2891    }
2892  }
2893
2894  if (count($categories_in_db) != count($category_ids))
2895  {
2896    $unknown_category_ids = array_diff($category_ids, array_keys($categories_in_db));
2897
2898    return new PwgError(
2899      403,
2900      sprintf(
2901        'Category %u does not exist',
2902        $unknown_category_ids[0]
2903        )
2904      );
2905  }
2906
2907  // does this parent exists? This check should be made in the
2908  // move_categories function, not here
2909  //
2910  // 0 as parent means "move categories at gallery root"
2911  if (!is_numeric($params['parent']))
2912  {
2913    return new PwgError(403, 'Invalid parent input parameter');
2914  }
2915
2916  if (0 != $params['parent']) {
2917    $params['parent'] = intval($params['parent']);
2918    $subcat_ids = get_subcat_ids(array($params['parent']));
2919    if (count($subcat_ids) == 0)
2920    {
2921      return new PwgError(403, 'Unknown parent category id');
2922    }
2923  }
2924
2925  $page['infos'] = array();
2926  $page['errors'] = array();
2927  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2928  move_categories($category_ids, $params['parent']);
2929  invalidate_user_cache();
2930
2931  if (count($page['errors']) != 0)
2932  {
2933    return new PwgError(403, implode('; ', $page['errors']));
2934  }
2935}
2936
2937function ws_logfile($string)
2938{
2939  global $conf;
2940
2941  if (!$conf['ws_enable_log']) {
2942    return true;
2943  }
2944
2945  file_put_contents(
2946    $conf['ws_log_filepath'],
2947    '['.date('c').'] '.$string."\n",
2948    FILE_APPEND
2949    );
2950}
2951
2952function ws_images_checkUpload($params, &$service)
2953{
2954  global $conf;
2955
2956  if (!is_admin())
2957  {
2958    return new PwgError(401, 'Access denied');
2959  }
2960
2961  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
2962  $ret['message'] = ready_for_upload_message();
2963  $ret['ready_for_upload'] = true;
2964
2965  if (!empty($ret['message']))
2966  {
2967    $ret['ready_for_upload'] = false;
2968  }
2969
2970  return $ret;
2971}
2972
2973function ws_plugins_getList($params, &$service)
2974{
2975  global $conf;
2976
2977  if (!is_admin())
2978  {
2979    return new PwgError(401, 'Access denied');
2980  }
2981
2982  include_once(PHPWG_ROOT_PATH.'admin/include/plugins.class.php');
2983  $plugins = new plugins();
2984  $plugins->sort_fs_plugins('name');
2985  $plugin_list = array();
2986
2987  foreach($plugins->fs_plugins as $plugin_id => $fs_plugin)
2988  {
2989    if (isset($plugins->db_plugins_by_id[$plugin_id]))
2990    {
2991      $state = $plugins->db_plugins_by_id[$plugin_id]['state'];
2992    }
2993    else
2994    {
2995      $state = 'uninstalled';
2996    }
2997
2998    array_push(
2999      $plugin_list,
3000      array(
3001        'id' => $plugin_id,
3002        'name' => $fs_plugin['name'],
3003        'version' => $fs_plugin['version'],
3004        'state' => $state,
3005        'description' => $fs_plugin['description'],
3006        )
3007      );
3008  }
3009
3010  return $plugin_list;
3011}
3012
3013function ws_plugins_performAction($params, &$service)
3014{
3015  global $template;
3016
3017  if (!is_admin())
3018  {
3019    return new PwgError(401, 'Access denied');
3020  }
3021
3022  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
3023  {
3024    return new PwgError(403, 'Invalid security token');
3025  }
3026
3027  define('IN_ADMIN', true);
3028  include_once(PHPWG_ROOT_PATH.'admin/include/plugins.class.php');
3029  $plugins = new plugins();
3030  $errors = $plugins->perform_action($params['action'], $params['plugin']);
3031
3032
3033  if (!empty($errors))
3034  {
3035    return new PwgError(500, $errors);
3036  }
3037  else
3038  {
3039    if (in_array($params['action'], array('activate', 'deactivate')))
3040    {
3041      $template->delete_compiled_templates();
3042    }
3043    return true;
3044  }
3045}
3046
3047function ws_themes_performAction($params, &$service)
3048{
3049  global $template;
3050
3051  if (!is_admin())
3052  {
3053    return new PwgError(401, 'Access denied');
3054  }
3055
3056  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
3057  {
3058    return new PwgError(403, 'Invalid security token');
3059  }
3060
3061  define('IN_ADMIN', true);
3062  include_once(PHPWG_ROOT_PATH.'admin/include/themes.class.php');
3063  $themes = new themes();
3064  $errors = $themes->perform_action($params['action'], $params['theme']);
3065
3066  if (!empty($errors))
3067  {
3068    return new PwgError(500, $errors);
3069  }
3070  else
3071  {
3072    if (in_array($params['action'], array('activate', 'deactivate')))
3073    {
3074      $template->delete_compiled_templates();
3075    }
3076    return true;
3077  }
3078}
3079
3080function ws_images_resizethumbnail($params, &$service)
3081{
3082  if (!is_admin())
3083  {
3084    return new PwgError(401, 'Access denied');
3085  }
3086
3087  if (empty($params['image_id']) and empty($params['image_path']))
3088  {
3089    return new PwgError(403, "image_id or image_path is missing");
3090  }
3091
3092  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
3093  include_once(PHPWG_ROOT_PATH.'admin/include/image.class.php');
3094
3095  if (!empty($params['image_id']))
3096  {
3097    $query='
3098SELECT id, path, tn_ext, has_high
3099  FROM '.IMAGES_TABLE.'
3100  WHERE id = '.(int)$params['image_id'].'
3101;';
3102    $image = pwg_db_fetch_assoc(pwg_query($query));
3103
3104    if ($image == null)
3105    {
3106      return new PwgError(403, "image_id not found");
3107    }
3108
3109    $image_path = $image['path'];
3110    $thumb_path = get_thumbnail_path($image);
3111  }
3112  else
3113  {
3114    $image_path = $params['image_path'];
3115    $thumb_path = file_path_for_type($image_path, 'thumb');
3116  }
3117
3118  if (!file_exists($image_path) or !is_valid_image_extension(get_extension($image_path)))
3119  {
3120    return new PwgError(403, "image can't be resized");
3121  }
3122
3123  $result = false;
3124  prepare_directory(dirname($thumb_path));
3125  $img = new pwg_image($image_path, $params['library']);
3126
3127  $result =  $img->pwg_resize(
3128    $thumb_path,
3129    $params['maxwidth'],
3130    $params['maxheight'],
3131    $params['quality'],
3132    false, // automatic rotation is not needed for thumbnails.
3133    true, // strip metadata
3134    get_boolean($params['crop']),
3135    get_boolean($params['follow_orientation'])
3136  );
3137
3138  $img->destroy();
3139  return $result;
3140}
3141
3142function ws_images_resizewebsize($params, &$service)
3143{
3144  if (!is_admin())
3145  {
3146    return new PwgError(401, 'Access denied');
3147  }
3148
3149  include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
3150  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
3151  include_once(PHPWG_ROOT_PATH.'admin/include/image.class.php');
3152
3153  $query='
3154SELECT id, path, tn_ext, has_high, width, height
3155  FROM '.IMAGES_TABLE.'
3156  WHERE id = '.(int)$params['image_id'].'
3157;';
3158  $image = pwg_db_fetch_assoc(pwg_query($query));
3159
3160  if ($image == null)
3161  {
3162    return new PwgError(403, "image_id not found");
3163  }
3164
3165  $image_path = $image['path'];
3166
3167  if (!is_valid_image_extension(get_extension($image_path)))
3168  {
3169    return new PwgError(403, "image can't be resized");
3170  }
3171 
3172  $hd_path = get_high_path($image);
3173
3174  if (empty($image['has_high']) or !file_exists($hd_path))
3175  {
3176    if ($image['width'] > $params['maxwidth'] or $image['height'] > $params['maxheight'])
3177    {
3178      $hd_path = file_path_for_type($image_path, 'high');
3179      $hd_dir = dirname($hd_path);
3180      prepare_directory($hd_dir);
3181     
3182      rename($image_path, $hd_path);
3183      $hd_infos = pwg_image_infos($hd_path);
3184
3185      single_update(
3186        IMAGES_TABLE,
3187        array(
3188          'has_high' => 'true',
3189          'high_filesize' => $hd_infos['filesize'],
3190          'high_width' => $hd_infos['width'],
3191          'high_height' => $hd_infos['height'],
3192          ),
3193        array(
3194          'id' => $image['id']
3195          )
3196        );
3197    }
3198    else
3199    {
3200      return new PwgError(403, "image can't be resized");
3201    }
3202  }
3203
3204  $result = false;
3205  $img = new pwg_image($hd_path, $params['library']);
3206
3207  $result = $img->pwg_resize(
3208    $image_path,
3209    $params['maxwidth'],
3210    $params['maxheight'],
3211    $params['quality'],
3212    $params['automatic_rotation'],
3213    false // strip metadata
3214    );
3215
3216  $img->destroy();
3217
3218  global $conf;
3219  $conf['use_exif'] = false;
3220  $conf['use_iptc'] = false;
3221  update_metadata(array($image['id'] => $image['path']));
3222
3223  return $result;
3224}
3225
3226function ws_extensions_update($params, &$service)
3227{
3228  if (!is_webmaster())
3229  {
3230    return new PwgError(401, l10n('Webmaster status is required.'));
3231  }
3232
3233  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
3234  {
3235    return new PwgError(403, 'Invalid security token');
3236  }
3237
3238  if (empty($params['type']) or !in_array($params['type'], array('plugins', 'themes', 'languages')))
3239  {
3240    return new PwgError(403, "invalid extension type");
3241  }
3242
3243  if (empty($params['id']) or empty($params['revision']))
3244  {
3245    return new PwgError(null, 'Wrong parameters');
3246  }
3247
3248  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
3249  include_once(PHPWG_ROOT_PATH.'admin/include/'.$params['type'].'.class.php');
3250
3251  $type = $params['type'];
3252  $extension_id = $params['id'];
3253  $revision = $params['revision'];
3254
3255  $extension = new $type();
3256
3257  if ($type == 'plugins')
3258  {
3259    if (isset($extension->db_plugins_by_id[$extension_id]) and $extension->db_plugins_by_id[$extension_id]['state'] == 'active')
3260    {
3261      $extension->perform_action('deactivate', $extension_id);
3262
3263      redirect(PHPWG_ROOT_PATH
3264        . 'ws.php'
3265        . '?method=pwg.extensions.update'
3266        . '&type=plugins'
3267        . '&id=' . $extension_id
3268        . '&revision=' . $revision
3269        . '&reactivate=true'
3270        . '&pwg_token=' . get_pwg_token()
3271        . '&format=json'
3272      );
3273    }
3274
3275    $upgrade_status = $extension->extract_plugin_files('upgrade', $revision, $extension_id);
3276    $extension_name = $extension->fs_plugins[$extension_id]['name'];
3277
3278    if (isset($params['reactivate']))
3279    {
3280      $extension->perform_action('activate', $extension_id);
3281    }
3282  }
3283  elseif ($type == 'themes')
3284  {
3285    $upgrade_status = $extension->extract_theme_files('upgrade', $revision, $extension_id);
3286    $extension_name = $extension->fs_themes[$extension_id]['name'];
3287  }
3288  elseif ($type == 'languages')
3289  {
3290    $upgrade_status = $extension->extract_language_files('upgrade', $revision, $extension_id);
3291    $extension_name = $extension->fs_languages[$extension_id]['name'];
3292  }
3293
3294  global $template;
3295  $template->delete_compiled_templates();
3296
3297  switch ($upgrade_status)
3298  {
3299    case 'ok':
3300      return sprintf(l10n('%s has been successfully updated.'), $extension_name);
3301
3302    case 'temp_path_error':
3303      return new PwgError(null, l10n('Can\'t create temporary file.'));
3304
3305    case 'dl_archive_error':
3306      return new PwgError(null, l10n('Can\'t download archive.'));
3307
3308    case 'archive_error':
3309      return new PwgError(null, l10n('Can\'t read or extract archive.'));
3310
3311    default:
3312      return new PwgError(null, sprintf(l10n('An error occured during extraction (%s).'), $upgrade_status));
3313  }
3314}
3315
3316function ws_extensions_ignoreupdate($params, &$service)
3317{
3318  global $conf;
3319
3320  define('IN_ADMIN', true);
3321  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
3322
3323  if (!is_webmaster())
3324  {
3325    return new PwgError(401, 'Access denied');
3326  }
3327
3328  if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
3329  {
3330    return new PwgError(403, 'Invalid security token');
3331  }
3332
3333  $conf['updates_ignored'] = unserialize($conf['updates_ignored']);
3334
3335  // Reset ignored extension
3336  if ($params['reset'])
3337  {
3338    if (!empty($params['type']) and isset($conf['updates_ignored'][$params['type']]))
3339    {
3340      $conf['updates_ignored'][$params['type']] = array();
3341    }
3342    else
3343    {
3344      $conf['updates_ignored'] = array(
3345        'plugins'=>array(),
3346        'themes'=>array(),
3347        'languages'=>array()
3348      );
3349    }
3350    conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
3351    unset($_SESSION['extensions_need_update']);
3352    return true;
3353  }
3354
3355  if (empty($params['id']) or empty($params['type']) or !in_array($params['type'], array('plugins', 'themes', 'languages')))
3356  {
3357    return new PwgError(403, 'Invalid parameters');
3358  }
3359
3360  // Add or remove extension from ignore list
3361  if (!in_array($params['id'], $conf['updates_ignored'][$params['type']]))
3362  {
3363    array_push($conf['updates_ignored'][$params['type']], $params['id']);
3364  }
3365  conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
3366  unset($_SESSION['extensions_need_update']);
3367  return true;
3368}
3369
3370function ws_extensions_checkupdates($params, &$service)
3371{
3372  global $conf;
3373
3374  define('IN_ADMIN', true);
3375  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
3376  include_once(PHPWG_ROOT_PATH.'admin/include/updates.class.php');
3377  $update = new updates();
3378
3379  if (!is_admin())
3380  {
3381    return new PwgError(401, 'Access denied');
3382  }
3383
3384  $result = array();
3385
3386  if (!isset($_SESSION['need_update']))
3387    $update->check_piwigo_upgrade();
3388
3389  $result['piwigo_need_update'] = $_SESSION['need_update'];
3390
3391  $conf['updates_ignored'] = unserialize($conf['updates_ignored']);
3392
3393  if (!isset($_SESSION['extensions_need_update']))
3394    $update->check_extensions();
3395  else
3396    $update->check_updated_extensions();
3397
3398  if (!is_array($_SESSION['extensions_need_update']))
3399    $result['ext_need_update'] = null;
3400  else
3401    $result['ext_need_update'] = !empty($_SESSION['extensions_need_update']);
3402
3403  return $result;
3404}
3405?>
Note: See TracBrowser for help on using the repository browser.