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

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

merge r12722 from branch 2.3 into trunk
merge r12723 from branch 2.3 into trunk

feature 2531 added: pwg.images.add is able to generate web size + thumbnail
(remote client needs to set "resize" option to something else than 0). When
the "resize" is On, only the "file" must be send with pwg.images.addChunk.

Small improvement compared to code implemented in branch 2.3 : use of
single_insert when resize is Off, single algorithm to update $info_colums (resize On/Off)

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