source: branches/2.1/include/ws_functions.inc.php @ 6314

Last change on this file since 6314 was 6125, checked in by nikrou, 14 years ago

Amend bug 1559. standard deviation was not removed in some places.
So, sqlite crashed because std function has been removed.

File size: 52.1 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based picture gallery                                  |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2010 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.'average_rate>'.$params['f_min_rate'];
58  }
59  if ( is_numeric($params['f_max_rate']) )
60  {
61    $clauses[] = $tbl_name.'average_rate<='.$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_posted']) )
72  {
73    $clauses[] = $tbl_name."date_available>='".$params['f_min_date_posted']."'";
74  }
75  if ( isset($params['f_max_date_posted']) )
76  {
77    $clauses[] = $tbl_name."date_available<'".$params['f_max_date_posted']."'";
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', 'average_rate',
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'
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'])
179    return PHPWG_VERSION;
180  else
181    return new PwgError(403, 'Forbidden');
182}
183
184function ws_caddie_add($params, &$service)
185{
186  if (!is_admin())
187  {
188    return new PwgError(401, 'Access denied');
189  }
190  $params['image_id'] = array_map( 'intval',$params['image_id'] );
191  if ( empty($params['image_id']) )
192  {
193    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
194  }
195  global $user;
196  $query = '
197SELECT id
198  FROM '.IMAGES_TABLE.' LEFT JOIN '.CADDIE_TABLE.' ON id=element_id AND user_id='.$user['id'].'
199  WHERE id IN ('.implode(',',$params['image_id']).')
200    AND element_id IS NULL';
201  $datas = array();
202  foreach ( array_from_query($query, 'id') as $id )
203  {
204    array_push($datas, array('element_id'=>$id, 'user_id'=>$user['id']) );
205  }
206  if (count($datas))
207  {
208    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
209    mass_inserts(CADDIE_TABLE, array('element_id','user_id'), $datas);
210  }
211  return count($datas);
212}
213
214/**
215 * returns images per category (web service method)
216 */
217function ws_categories_getImages($params, &$service)
218{
219  @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
220  global $user, $conf;
221
222  $images = array();
223
224  //------------------------------------------------- get the related categories
225  $where_clauses = array();
226  foreach($params['cat_id'] as $cat_id)
227  {
228    $cat_id = (int)$cat_id;
229    if ($cat_id<=0)
230      continue;
231    if ($params['recursive'])
232    {
233      $where_clauses[] = 'uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.$cat_id.'(,|$)\'';
234    }
235    else
236    {
237      $where_clauses[] = 'id='.$cat_id;
238    }
239  }
240  if (!empty($where_clauses))
241  {
242    $where_clauses = array( '('.
243    implode('
244    OR ', $where_clauses) . ')'
245      );
246  }
247  $where_clauses[] = get_sql_condition_FandF(
248        array('forbidden_categories' => 'id'),
249        NULL, true
250      );
251
252  $query = '
253SELECT id, name, permalink, image_order
254  FROM '.CATEGORIES_TABLE.'
255  WHERE '. implode('
256    AND ', $where_clauses);
257  $result = pwg_query($query);
258  $cats = array();
259  while ($row = pwg_db_fetch_assoc($result))
260  {
261    $row['id'] = (int)$row['id'];
262    $cats[ $row['id'] ] = $row;
263  }
264
265  //-------------------------------------------------------- get the images
266  if ( !empty($cats) )
267  {
268    $where_clauses = ws_std_image_sql_filter( $params, 'i.' );
269    $where_clauses[] = 'category_id IN ('
270      .implode(',', array_keys($cats) )
271      .')';
272    $where_clauses[] = get_sql_condition_FandF( array(
273          'visible_images' => 'i.id'
274        ), null, true
275      );
276
277    $order_by = ws_std_image_sql_order($params, 'i.');
278    if ( empty($order_by)
279          and count($params['cat_id'])==1
280          and isset($cats[ $params['cat_id'][0] ]['image_order'])
281        )
282    {
283      $order_by = $cats[ $params['cat_id'][0] ]['image_order'];
284    }
285    $order_by = empty($order_by) ? $conf['order_by'] : 'ORDER BY '.$order_by;
286
287    $query = '
288SELECT i.*, GROUP_CONCAT(category_id) cat_ids
289  FROM '.IMAGES_TABLE.' i
290    INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON i.id=image_id
291  WHERE '. implode('
292    AND ', $where_clauses).'
293GROUP BY i.id
294'.$order_by.'
295LIMIT '.(int)$params['per_page'].' OFFSET '.(int)($params['per_page']*$params['page']);
296
297    $result = pwg_query($query);
298    while ($row = pwg_db_fetch_assoc($result))
299    {
300      $image = array();
301      foreach ( array('id', 'width', 'height', 'hit') as $k )
302      {
303        if (isset($row[$k]))
304        {
305          $image[$k] = (int)$row[$k];
306        }
307      }
308      foreach ( array('file', 'name', 'comment') as $k )
309      {
310        $image[$k] = $row[$k];
311      }
312      $image = array_merge( $image, ws_std_get_urls($row) );
313
314      $image_cats = array();
315      foreach ( explode(',', $row['cat_ids']) as $cat_id )
316      {
317        $url = make_index_url(
318                array(
319                  'category' => $cats[$cat_id],
320                  )
321                );
322        $page_url = make_picture_url(
323                array(
324                  'category' => $cats[$cat_id],
325                  'image_id' => $row['id'],
326                  'image_file' => $row['file'],
327                  )
328                );
329        array_push( $image_cats,  array(
330              WS_XML_ATTRIBUTES => array (
331                  'id' => (int)$cat_id,
332                  'url' => $url,
333                  'page_url' => $page_url,
334                )
335            )
336          );
337      }
338
339      $image['categories'] = new PwgNamedArray(
340            $image_cats,'category', array('id','url','page_url')
341          );
342      array_push($images, $image);
343    }
344  }
345
346  return array( 'images' =>
347    array (
348      WS_XML_ATTRIBUTES =>
349        array(
350            'page' => $params['page'],
351            'per_page' => $params['per_page'],
352            'count' => count($images)
353          ),
354       WS_XML_CONTENT => new PwgNamedArray($images, 'image',
355          ws_std_get_image_xml_attributes() )
356      )
357    );
358}
359
360
361/**
362 * returns a list of categories (web service method)
363 */
364function ws_categories_getList($params, &$service)
365{
366  global $user,$conf;
367
368  $where = array('1=1');
369  $join_type = 'INNER';
370  $join_user = $user['id'];
371
372  if (!$params['recursive'])
373  {
374    if ($params['cat_id']>0)
375      $where[] = '(id_uppercat='.(int)($params['cat_id']).'
376    OR id='.(int)($params['cat_id']).')';
377    else
378      $where[] = 'id_uppercat IS NULL';
379  }
380  else if ($params['cat_id']>0)
381  {
382    $where[] = 'uppercats '.DB_REGEX_OPERATOR.' \'(^|,)'.
383      (int)($params['cat_id'])
384      .'(,|$)\'';
385  }
386
387  if ($params['public'])
388  {
389    $where[] = 'status = "public"';
390    $where[] = 'visible = "true"';
391   
392    $join_user = $conf['guest_id'];
393  }
394  elseif (is_admin())
395  {
396    // in this very specific case, we don't want to hide empty
397    // categories. Function calculate_permissions will only return
398    // categories that are either locked or private and not permitted
399    //
400    // calculate_permissions does not consider empty categories as forbidden
401    $forbidden_categories = calculate_permissions($user['id'], $user['status']);
402    $where[]= 'id NOT IN ('.$forbidden_categories.')';
403    $join_type = 'LEFT';
404  }
405
406  $query = '
407SELECT id, name, permalink, uppercats, global_rank,
408    nb_images, count_images AS total_nb_images,
409    date_last, max_date_last, count_categories AS nb_categories
410  FROM '.CATEGORIES_TABLE.'
411   '.$join_type.' JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON id=cat_id AND user_id='.$join_user.'
412  WHERE '. implode('
413    AND ', $where);
414
415  $result = pwg_query($query);
416
417  $cats = array();
418  while ($row = pwg_db_fetch_assoc($result))
419  {
420    $row['url'] = make_index_url(
421        array(
422          'category' => $row
423          )
424      );
425    foreach( array('id','nb_images','total_nb_images','nb_categories') as $key)
426    {
427      $row[$key] = (int)$row[$key];
428    }
429
430    $row['name'] = strip_tags(
431      trigger_event(
432        'render_category_name',
433        $row['name'],
434        'ws_categories_getList'
435        )
436      );
437   
438    array_push($cats, $row);
439  }
440  usort($cats, 'global_rank_compare');
441  return array(
442    'categories' => new PwgNamedArray(
443      $cats,
444      'category',
445      array(
446        'id',
447        'url',
448        'nb_images',
449        'total_nb_images',
450        'nb_categories',
451        'date_last',
452        'max_date_last',
453        )
454      )
455    );
456}
457
458/**
459 * returns the list of categories as you can see them in administration (web
460 * service method).
461 *
462 * Only admin can run this method and permissions are not taken into
463 * account.
464 */
465function ws_categories_getAdminList($params, &$service)
466{
467  if (!is_admin())
468  {
469    return new PwgError(401, 'Access denied');
470  }
471
472  $query = '
473SELECT
474    category_id,
475    COUNT(*) AS counter
476  FROM '.IMAGE_CATEGORY_TABLE.'
477  GROUP BY category_id
478;';
479  $nb_images_of = simple_hash_from_query($query, 'category_id', 'counter');
480
481  $query = '
482SELECT
483    id,
484    name,
485    uppercats,
486    global_rank
487  FROM '.CATEGORIES_TABLE.'
488;';
489  $result = pwg_query($query);
490  $cats = array();
491
492  while ($row = pwg_db_fetch_assoc($result))
493  {
494    $id = $row['id'];
495    $row['nb_images'] = isset($nb_images_of[$id]) ? $nb_images_of[$id] : 0;
496    $row['name'] = strip_tags(
497      trigger_event(
498        'render_category_name',
499        $row['name'],
500        'ws_categories_getAdminList'
501        )
502      );
503    array_push($cats, $row);
504  }
505
506  usort($cats, 'global_rank_compare');
507  return array(
508    'categories' => new PwgNamedArray(
509      $cats,
510      'category',
511      array(
512        'id',
513        'nb_images',
514        'name',
515        'uppercats',
516        'global_rank',
517        )
518      )
519    );
520}
521
522/**
523 * returns detailed information for an element (web service method)
524 */
525function ws_images_addComment($params, &$service)
526{
527  if (!$service->isPost())
528  {
529    return new PwgError(405, "This method requires HTTP POST");
530  }
531  $params['image_id'] = (int)$params['image_id'];
532  $query = '
533SELECT DISTINCT image_id
534  FROM '.IMAGE_CATEGORY_TABLE.' INNER JOIN '.CATEGORIES_TABLE.' ON category_id=id
535  WHERE commentable="true"
536    AND image_id='.$params['image_id'].
537    get_sql_condition_FandF(
538      array(
539        'forbidden_categories' => 'id',
540        'visible_categories' => 'id',
541        'visible_images' => 'image_id'
542      ),
543      ' AND'
544    );
545  if ( !pwg_db_num_rows( pwg_query( $query ) ) )
546  {
547    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
548  }
549
550  $comm = array(
551    'author' => trim( stripslashes($params['author']) ),
552    'content' => trim( stripslashes($params['content']) ),
553    'image_id' => $params['image_id'],
554   );
555
556  include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php');
557
558  $comment_action = insert_user_comment(
559      $comm, $params['key'], $infos
560    );
561
562  switch ($comment_action)
563  {
564    case 'reject':
565      array_push($infos, l10n('Your comment has NOT been registered because it did not pass the validation rules') );
566      return new PwgError(403, implode("\n", $infos) );
567    case 'validate':
568    case 'moderate':
569      $ret = array(
570          'id' => $comm['id'],
571          'validation' => $comment_action=='validate',
572        );
573      return new PwgNamedStruct(
574          'comment',
575          $ret,
576          null, array()
577        );
578    default:
579      return new PwgError(500, "Unknown comment action ".$comment_action );
580  }
581}
582
583/**
584 * returns detailed information for an element (web service method)
585 */
586function ws_images_getInfo($params, &$service)
587{
588  @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
589  global $user, $conf;
590  $params['image_id'] = (int)$params['image_id'];
591  if ( $params['image_id']<=0 )
592  {
593    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
594  }
595
596  $query='
597SELECT * FROM '.IMAGES_TABLE.'
598  WHERE id='.$params['image_id'].
599    get_sql_condition_FandF(
600      array('visible_images' => 'id'),
601      ' AND'
602    ).'
603LIMIT 1';
604
605  $image_row = pwg_db_fetch_assoc(pwg_query($query));
606  if ($image_row==null)
607  {
608    return new PwgError(404, "image_id not found");
609  }
610  $image_row = array_merge( $image_row, ws_std_get_urls($image_row) );
611
612  //-------------------------------------------------------- related categories
613  $query = '
614SELECT id, name, permalink, uppercats, global_rank, commentable
615  FROM '.IMAGE_CATEGORY_TABLE.'
616    INNER JOIN '.CATEGORIES_TABLE.' ON category_id = id
617  WHERE image_id = '.$image_row['id'].
618  get_sql_condition_FandF(
619      array( 'forbidden_categories' => 'category_id' ),
620      ' AND'
621    ).'
622;';
623  $result = pwg_query($query);
624  $is_commentable = false;
625  $related_categories = array();
626  while ($row = pwg_db_fetch_assoc($result))
627  {
628    if ($row['commentable']=='true')
629    {
630      $is_commentable = true;
631    }
632    unset($row['commentable']);
633    $row['url'] = make_index_url(
634        array(
635          'category' => $row
636          )
637      );
638
639    $row['page_url'] = make_picture_url(
640        array(
641          'image_id' => $image_row['id'],
642          'image_file' => $image_row['file'],
643          'category' => $row
644          )
645      );
646    $row['id']=(int)$row['id'];
647    array_push($related_categories, $row);
648  }
649  usort($related_categories, 'global_rank_compare');
650  if ( empty($related_categories) )
651  {
652    return new PwgError(401, 'Access denied');
653  }
654
655  //-------------------------------------------------------------- related tags
656  $related_tags = get_common_tags( array($image_row['id']), -1 );
657  foreach( $related_tags as $i=>$tag)
658  {
659    $tag['url'] = make_index_url(
660        array(
661          'tags' => array($tag)
662          )
663      );
664    $tag['page_url'] = make_picture_url(
665        array(
666          'image_id' => $image_row['id'],
667          'image_file' => $image_row['file'],
668          'tags' => array($tag),
669          )
670      );
671    unset($tag['counter']);
672    $tag['id']=(int)$tag['id'];
673    $related_tags[$i]=$tag;
674  }
675  //------------------------------------------------------------- related rates
676  $query = '
677SELECT COUNT(rate) AS count
678     , ROUND(AVG(rate),2) AS average
679  FROM '.RATE_TABLE.'
680  WHERE element_id = '.$image_row['id'].'
681;';
682  $rating = pwg_db_fetch_assoc(pwg_query($query));
683  $rating['count'] = (int)$rating['count'];
684
685  //---------------------------------------------------------- related comments
686  $related_comments = array();
687
688  $where_comments = 'image_id = '.$image_row['id'];
689  if ( !is_admin() )
690  {
691    $where_comments .= '
692    AND validated="true"';
693  }
694
695  $query = '
696SELECT COUNT(id) nb_comments
697  FROM '.COMMENTS_TABLE.'
698  WHERE '.$where_comments;
699  list($nb_comments) = array_from_query($query, 'nb_comments');
700  $nb_comments = (int)$nb_comments;
701
702  if ( $nb_comments>0 and $params['comments_per_page']>0 )
703  {
704    $query = '
705SELECT id, date, author, content
706  FROM '.COMMENTS_TABLE.'
707  WHERE '.$where_comments.'
708  ORDER BY date
709  LIMIT '.(int)$params['comments_per_page'].
710    ' OFFSET '.(int)($params['comments_per_page']*$params['comments_page']);
711
712    $result = pwg_query($query);
713    while ($row = pwg_db_fetch_assoc($result))
714    {
715      $row['id']=(int)$row['id'];
716      array_push($related_comments, $row);
717    }
718  }
719
720  $comment_post_data = null;
721  if ($is_commentable and
722      (!is_a_guest()
723        or (is_a_guest() and $conf['comments_forall'] )
724      )
725      )
726  {
727    $comment_post_data['author'] = stripslashes($user['username']);
728    $comment_post_data['key'] = get_comment_post_key($params['image_id']);
729  }
730
731  $ret = $image_row;
732  foreach ( array('id','width','height','hit','filesize') as $k )
733  {
734    if (isset($ret[$k]))
735    {
736      $ret[$k] = (int)$ret[$k];
737    }
738  }
739  foreach ( array('path', 'storage_category_id') as $k )
740  {
741    unset($ret[$k]);
742  }
743
744  $ret['rates'] = array( WS_XML_ATTRIBUTES => $rating );
745  $ret['categories'] = new PwgNamedArray($related_categories, 'category', array('id','url', 'page_url') );
746  $ret['tags'] = new PwgNamedArray($related_tags, 'tag', array('id','url_name','url','name','page_url') );
747  if ( isset($comment_post_data) )
748  {
749    $ret['comment_post'] = array( WS_XML_ATTRIBUTES => $comment_post_data );
750  }
751  $ret['comments'] = array(
752     WS_XML_ATTRIBUTES =>
753        array(
754          'page' => $params['comments_page'],
755          'per_page' => $params['comments_per_page'],
756          'count' => count($related_comments),
757          'nb_comments' => $nb_comments,
758        ),
759     WS_XML_CONTENT => new PwgNamedArray($related_comments, 'comment', array('id','date') )
760      );
761
762  return new PwgNamedStruct('image',$ret, null, array('name','comment') );
763}
764
765
766/**
767 * rates the image_id in the parameter
768 */
769function ws_images_Rate($params, &$service)
770{
771  $image_id = (int)$params['image_id'];
772  $query = '
773SELECT DISTINCT id FROM '.IMAGES_TABLE.'
774  INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id=image_id
775  WHERE id='.$image_id
776  .get_sql_condition_FandF(
777    array(
778        'forbidden_categories' => 'category_id',
779        'forbidden_images' => 'id',
780      ),
781    '    AND'
782    ).'
783    LIMIT 1';
784  if ( pwg_db_num_rows( pwg_query($query) )==0 )
785  {
786    return new PwgError(404, "Invalid image_id or access denied" );
787  }
788  $rate = (int)$params['rate'];
789  include_once(PHPWG_ROOT_PATH.'include/functions_rate.inc.php');
790  $res = rate_picture( $image_id, $rate );
791  if ($res==false)
792  {
793    global $conf;
794    return new PwgError( 403, "Forbidden or rate not in ". implode(',',$conf['rate_items']));
795  }
796  return $res;
797}
798
799
800/**
801 * returns a list of elements corresponding to a query search
802 */
803function ws_images_search($params, &$service)
804{
805  global $page;
806  $images = array();
807  include_once( PHPWG_ROOT_PATH .'include/functions_search.inc.php' );
808  include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
809
810  $where_clauses = ws_std_image_sql_filter( $params, 'i.' );
811  $order_by = ws_std_image_sql_order($params, 'i.');
812
813  $super_order_by = false;
814  if ( !empty($order_by) )
815  {
816    global $conf;
817    $conf['order_by'] = 'ORDER BY '.$order_by;
818    $super_order_by=true; // quick_search_result might be faster
819  }
820
821  $search_result = get_quick_search_results($params['query'],
822      $super_order_by,
823      implode(',', $where_clauses)
824    );
825
826  $image_ids = array_slice(
827      $search_result['items'],
828      $params['page']*$params['per_page'],
829      $params['per_page']
830    );
831
832  if ( count($image_ids) )
833  {
834    $query = '
835SELECT * FROM '.IMAGES_TABLE.'
836  WHERE id IN ('.implode(',', $image_ids).')';
837
838    $image_ids = array_flip($image_ids);
839    $result = pwg_query($query);
840    while ($row = pwg_db_fetch_assoc($result))
841    {
842      $image = array();
843      foreach ( array('id', 'width', 'height', 'hit') as $k )
844      {
845        if (isset($row[$k]))
846        {
847          $image[$k] = (int)$row[$k];
848        }
849      }
850      foreach ( array('file', 'name', 'comment') as $k )
851      {
852        $image[$k] = $row[$k];
853      }
854      $image = array_merge( $image, ws_std_get_urls($row) );
855      $images[$image_ids[$image['id']]] = $image;
856    }
857    ksort($images, SORT_NUMERIC);
858    $images = array_values($images);
859  }
860
861
862  return array( 'images' =>
863    array (
864      WS_XML_ATTRIBUTES =>
865        array(
866            'page' => $params['page'],
867            'per_page' => $params['per_page'],
868            'count' => count($images)
869          ),
870       WS_XML_CONTENT => new PwgNamedArray($images, 'image',
871          ws_std_get_image_xml_attributes() )
872      )
873    );
874}
875
876function ws_images_setPrivacyLevel($params, &$service)
877{
878  if (!is_admin() || is_adviser() )
879  {
880    return new PwgError(401, 'Access denied');
881  }
882  if (!$service->isPost())
883  {
884    return new PwgError(405, "This method requires HTTP POST");
885  }
886  $params['image_id'] = array_map( 'intval',$params['image_id'] );
887  if ( empty($params['image_id']) )
888  {
889    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
890  }
891  global $conf;
892  if ( !in_array( (int)$params['level'], $conf['available_permission_levels']) )
893  {
894    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid level");
895  }
896
897  $query = '
898UPDATE '.IMAGES_TABLE.'
899  SET level='.(int)$params['level'].'
900  WHERE id IN ('.implode(',',$params['image_id']).')';
901  $result = pwg_query($query);
902  $affected_rows = pwg_db_changes($result);
903  if ($affected_rows)
904  {
905    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
906    invalidate_user_cache();
907  }
908  return $affected_rows;
909}
910
911function ws_images_add_chunk($params, &$service)
912{
913  global $conf;
914 
915  ws_logfile('[ws_images_add_chunk] welcome');
916  // data
917  // original_sum
918  // type {thumb, file, high}
919  // position
920
921  if (!is_admin() || is_adviser() )
922  {
923    return new PwgError(401, 'Access denied');
924  }
925
926  if (!$service->isPost())
927  {
928    return new PwgError(405, "This method requires HTTP POST");
929  }
930
931  foreach ($params as $param_key => $param_value) {
932    if ('data' == $param_key) {
933      continue;
934    }
935   
936    ws_logfile(
937      sprintf(
938        '[ws_images_add_chunk] input param "%s" : "%s"',
939        $param_key,
940        is_null($param_value) ? 'NULL' : $param_value
941        )
942      );
943  }
944
945  $upload_dir = $conf['upload_dir'].'/buffer';
946
947  // create the upload directory tree if not exists
948  if (!is_dir($upload_dir)) {
949    umask(0000);
950    $recursive = true;
951    if (!@mkdir($upload_dir, 0777, $recursive))
952    {
953      return new PwgError(500, 'error during buffer directory creation');
954    }
955  }
956
957  if (!is_writable($upload_dir))
958  {
959    // last chance to make the directory writable
960    @chmod($upload_dir, 0777);
961
962    if (!is_writable($upload_dir))
963    {
964      return new PwgError(500, 'buffer directory has no write access');
965    }
966  }
967
968  secure_directory($upload_dir);
969
970  $filename = sprintf(
971    '%s-%s-%05u.block',
972    $params['original_sum'],
973    $params['type'],
974    $params['position']
975    );
976
977  ws_logfile('[ws_images_add_chunk] data length : '.strlen($params['data']));
978
979  $bytes_written = file_put_contents(
980    $upload_dir.'/'.$filename,
981    base64_decode($params['data'])
982    );
983
984  if (false === $bytes_written) {
985    return new PwgError(
986      500,
987      'an error has occured while writting chunk '.$params['position'].' for '.$params['type']
988      );
989  }
990}
991
992function merge_chunks($output_filepath, $original_sum, $type)
993{
994  global $conf;
995 
996  ws_logfile('[merge_chunks] input parameter $output_filepath : '.$output_filepath);
997
998  if (is_file($output_filepath))
999  {
1000    unlink($output_filepath);
1001
1002    if (is_file($output_filepath))
1003    {
1004      new PwgError(500, '[merge_chunks] error while trying to remove existing '.$output_filepath);
1005      exit();
1006    }
1007  }
1008
1009  $upload_dir = $conf['upload_dir'].'/buffer';
1010  $pattern = '/'.$original_sum.'-'.$type.'/';
1011  $chunks = array();
1012
1013  if ($handle = opendir($upload_dir))
1014  {
1015    while (false !== ($file = readdir($handle)))
1016    {
1017      if (preg_match($pattern, $file))
1018      {
1019        ws_logfile($file);
1020        array_push($chunks, $upload_dir.'/'.$file);
1021      }
1022    }
1023    closedir($handle);
1024  }
1025
1026  sort($chunks);
1027
1028  if (function_exists('memory_get_usage')) {
1029    ws_logfile('[merge_chunks] memory_get_usage before loading chunks: '.memory_get_usage());
1030  }
1031
1032  $i = 0;
1033
1034  foreach ($chunks as $chunk)
1035  {
1036    $string = file_get_contents($chunk);
1037
1038    if (function_exists('memory_get_usage')) {
1039      ws_logfile('[merge_chunks] memory_get_usage on chunk '.++$i.': '.memory_get_usage());
1040    }
1041
1042    if (!file_put_contents($output_filepath, $string, FILE_APPEND))
1043    {
1044      new PwgError(500, '[merge_chunks] error while writting chunks for '.$output_filepath);
1045      exit();
1046    }
1047
1048    unlink($chunk);
1049  }
1050
1051  if (function_exists('memory_get_usage')) {
1052    ws_logfile('[merge_chunks] memory_get_usage after loading chunks: '.memory_get_usage());
1053  }
1054}
1055
1056/*
1057 * The $file_path must be the path of the basic "web sized" photo
1058 * The $type value will automatically modify the $file_path to the corresponding file
1059 */
1060function add_file($file_path, $type, $original_sum, $file_sum)
1061{
1062  $file_path = file_path_for_type($file_path, $type);
1063
1064  $upload_dir = dirname($file_path);
1065  if (substr(PHP_OS, 0, 3) == 'WIN')
1066  {
1067    $upload_dir = str_replace('/', DIRECTORY_SEPARATOR, $upload_dir);
1068  }
1069
1070  ws_logfile('[add_file] file_path  : '.$file_path);
1071  ws_logfile('[add_file] upload_dir : '.$upload_dir);
1072 
1073  if (!is_dir($upload_dir)) {
1074    umask(0000);
1075    $recursive = true;
1076    if (!@mkdir($upload_dir, 0777, $recursive))
1077    {
1078      new PwgError(500, '[add_file] error during '.$type.' directory creation');
1079      exit();
1080    }
1081  }
1082
1083  if (!is_writable($upload_dir))
1084  {
1085    // last chance to make the directory writable
1086    @chmod($upload_dir, 0777);
1087
1088    if (!is_writable($upload_dir))
1089    {
1090      new PwgError(500, '[add_file] '.$type.' directory has no write access');
1091      exit();
1092    }
1093  }
1094
1095  secure_directory($upload_dir);
1096
1097  // merge the thumbnail
1098  merge_chunks($file_path, $original_sum, $type);
1099  chmod($file_path, 0644);
1100
1101  // check dumped thumbnail md5
1102  $dumped_md5 = md5_file($file_path);
1103  if ($dumped_md5 != $file_sum) {
1104    new PwgError(500, '[add_file] '.$type.' transfer failed');
1105    exit();
1106  }
1107
1108  list($width, $height) = getimagesize($file_path);
1109  $filesize = floor(filesize($file_path)/1024);
1110
1111  return array(
1112    'width' => $width,
1113    'height' => $height,
1114    'filesize' => $filesize,
1115    );
1116}
1117
1118function ws_images_addFile($params, &$service)
1119{
1120  // image_id
1121  // type {thumb, file, high}
1122  // sum
1123
1124  global $conf;
1125  if (!is_admin() || is_adviser() )
1126  {
1127    return new PwgError(401, 'Access denied');
1128  }
1129
1130  $params['image_id'] = (int)$params['image_id'];
1131  if ($params['image_id'] <= 0)
1132  {
1133    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
1134  }
1135
1136  //
1137  // what is the path?
1138  //
1139  $query = '
1140SELECT
1141    path,
1142    md5sum
1143  FROM '.IMAGES_TABLE.'
1144  WHERE id = '.$params['image_id'].'
1145;';
1146  list($file_path, $original_sum) = mysql_fetch_row(pwg_query($query));
1147
1148  // TODO only files added with web API can be updated with web API
1149
1150  //
1151  // makes sure directories are there and call the merge_chunks
1152  //
1153  $infos = add_file($file_path, $params['type'], $original_sum, $params['sum']);
1154
1155  //
1156  // update basic metadata from file
1157  //
1158  $update = array();
1159
1160  if ('high' == $params['type'])
1161  {
1162    $update['high_filesize'] = $infos['filesize'];
1163    $update['has_high'] = 'true';
1164  }
1165
1166  if ('file' == $params['type'])
1167  {
1168    $update['filesize'] = $infos['filesize'];
1169    $update['width'] = $infos['width'];
1170    $update['height'] = $infos['height'];
1171  }
1172
1173  // we may have nothing to update at database level, for example with a
1174  // thumbnail update
1175  if (count($update) > 0)
1176  {
1177    $update['id'] = $params['image_id'];
1178
1179    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1180    mass_updates(
1181      IMAGES_TABLE,
1182      array(
1183        'primary' => array('id'),
1184        'update'  => array_diff(array_keys($update), array('id'))
1185        ),
1186      array($update)
1187      );
1188  }
1189}
1190
1191function ws_images_add($params, &$service)
1192{
1193  global $conf;
1194  if (!is_admin() || is_adviser() )
1195  {
1196    return new PwgError(401, 'Access denied');
1197  }
1198
1199  foreach ($params as $param_key => $param_value) {
1200    ws_logfile(
1201      sprintf(
1202        '[pwg.images.add] input param "%s" : "%s"',
1203        $param_key,
1204        is_null($param_value) ? 'NULL' : $param_value
1205        )
1206      );
1207  }
1208
1209  // does the image already exists ?
1210  if ('md5sum' == $conf['uniqueness_mode'])
1211  {
1212    $where_clause = "md5sum = '".$params['original_sum']."'";
1213  }
1214  if ('filename' == $conf['uniqueness_mode'])
1215  {
1216    $where_clause = "file = '".$params['original_filename']."'";
1217  }
1218 
1219  $query = '
1220SELECT
1221    COUNT(*) AS counter
1222  FROM '.IMAGES_TABLE.'
1223  WHERE '.$where_clause.'
1224;';
1225  list($counter) = pwg_db_fetch_row(pwg_query($query));
1226  if ($counter != 0) {
1227    return new PwgError(500, 'file already exists');
1228  }
1229
1230  // current date
1231  list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
1232  list($year, $month, $day) = preg_split('/[^\d]/', $dbnow, 4);
1233
1234  // upload directory hierarchy
1235  $upload_dir = sprintf(
1236    $conf['upload_dir'].'/%s/%s/%s',
1237    $year,
1238    $month,
1239    $day
1240    );
1241
1242  // compute file path
1243  $date_string = preg_replace('/[^\d]/', '', $dbnow);
1244  $random_string = substr($params['file_sum'], 0, 8);
1245  $filename_wo_ext = $date_string.'-'.$random_string;
1246  $file_path = $upload_dir.'/'.$filename_wo_ext.'.jpg';
1247
1248  // add files
1249  $file_infos  = add_file($file_path, 'file',  $params['original_sum'], $params['file_sum']);
1250  $thumb_infos = add_file($file_path, 'thumb', $params['original_sum'], $params['thumbnail_sum']);
1251
1252  if (isset($params['high_sum']))
1253  {
1254    $high_infos = add_file($file_path, 'high', $params['original_sum'], $params['high_sum']);
1255  }
1256
1257  // database registration
1258  $insert = array(
1259    'file' => !empty($params['original_filename']) ? $params['original_filename'] : $filename_wo_ext.'.jpg',
1260    'date_available' => $dbnow,
1261    'tn_ext' => 'jpg',
1262    'name' => $params['name'],
1263    'path' => $file_path,
1264    'filesize' => $file_infos['filesize'],
1265    'width' => $file_infos['width'],
1266    'height' => $file_infos['height'],
1267    'md5sum' => $params['original_sum'],
1268    );
1269
1270  $info_columns = array(
1271    'name',
1272    'author',
1273    'comment',
1274    'level',
1275    'date_creation',
1276    );
1277
1278  foreach ($info_columns as $key)
1279  {
1280    if (isset($params[$key]))
1281    {
1282      $insert[$key] = $params[$key];
1283    }
1284  }
1285
1286  if (isset($params['high_sum']))
1287  {
1288    $insert['has_high'] = 'true';
1289    $insert['high_filesize'] = $high_infos['filesize'];
1290  }
1291
1292  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1293  mass_inserts(
1294    IMAGES_TABLE,
1295    array_keys($insert),
1296    array($insert)
1297    );
1298
1299  $image_id = pwg_db_insert_id(IMAGES_TABLE);
1300
1301  // let's add links between the image and the categories
1302  if (isset($params['categories']))
1303  {
1304    ws_add_image_category_relations($image_id, $params['categories']);
1305  }
1306
1307  // and now, let's create tag associations
1308  if (isset($params['tag_ids']) and !empty($params['tag_ids']))
1309  {
1310    set_tags(
1311      explode(',', $params['tag_ids']),
1312      $image_id
1313      );
1314  }
1315
1316  // update metadata from the uploaded file (exif/iptc)
1317  require_once(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
1318  update_metadata(array($image_id=>$file_path));
1319 
1320  invalidate_user_cache();
1321}
1322
1323/**
1324 * perform a login (web service method)
1325 */
1326function ws_session_login($params, &$service)
1327{
1328  global $conf;
1329
1330  if (!$service->isPost())
1331  {
1332    return new PwgError(405, "This method requires HTTP POST");
1333  }
1334  if (try_log_user($params['username'], $params['password'],false))
1335  {
1336    return true;
1337  }
1338  return new PwgError(999, 'Invalid username/password');
1339}
1340
1341
1342/**
1343 * performs a logout (web service method)
1344 */
1345function ws_session_logout($params, &$service)
1346{
1347  if (!is_a_guest())
1348  {
1349    logout_user();
1350  }
1351  return true;
1352}
1353
1354function ws_session_getStatus($params, &$service)
1355{
1356  global $user;
1357  $res = array();
1358  $res['username'] = is_a_guest() ? 'guest' : stripslashes($user['username']);
1359  foreach ( array('status', 'template', 'theme', 'language') as $k )
1360  {
1361    $res[$k] = $user[$k];
1362  }
1363  $res['charset'] = get_pwg_charset();
1364  return $res;
1365}
1366
1367
1368/**
1369 * returns a list of tags (web service method)
1370 */
1371function ws_tags_getList($params, &$service)
1372{
1373  $tags = get_available_tags();
1374  if ($params['sort_by_counter'])
1375  {
1376    usort($tags, create_function('$a,$b', 'return -$a["counter"]+$b["counter"];') );
1377  }
1378  else
1379  {
1380    usort($tags, 'tag_alpha_compare');
1381  }
1382  for ($i=0; $i<count($tags); $i++)
1383  {
1384    $tags[$i]['id'] = (int)$tags[$i]['id'];
1385    $tags[$i]['counter'] = (int)$tags[$i]['counter'];
1386    $tags[$i]['url'] = make_index_url(
1387        array(
1388          'section'=>'tags',
1389          'tags'=>array($tags[$i])
1390        )
1391      );
1392  }
1393  return array('tags' => new PwgNamedArray($tags, 'tag', array('id','url_name','url', 'name', 'counter' )) );
1394}
1395
1396/**
1397 * returns the list of tags as you can see them in administration (web
1398 * service method).
1399 *
1400 * Only admin can run this method and permissions are not taken into
1401 * account.
1402 */
1403function ws_tags_getAdminList($params, &$service)
1404{
1405  if (!is_admin())
1406  {
1407    return new PwgError(401, 'Access denied');
1408  }
1409
1410  $tags = get_all_tags();
1411  return array(
1412    'tags' => new PwgNamedArray(
1413      $tags,
1414      'tag',
1415      array(
1416        'name',
1417        'id',
1418        'url_name',
1419        )
1420      )
1421    );
1422}
1423
1424/**
1425 * returns a list of images for tags (web service method)
1426 */
1427function ws_tags_getImages($params, &$service)
1428{
1429  @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
1430  global $conf;
1431
1432  // first build all the tag_ids we are interested in
1433  $params['tag_id'] = array_map( 'intval',$params['tag_id'] );
1434  $tags = find_tags($params['tag_id'], $params['tag_url_name'], $params['tag_name']);
1435  $tags_by_id = array();
1436  foreach( $tags as $tag )
1437  {
1438    $tags['id'] = (int)$tag['id'];
1439    $tags_by_id[ $tag['id'] ] = $tag;
1440  }
1441  unset($tags);
1442  $tag_ids = array_keys($tags_by_id);
1443
1444
1445  $image_ids = array();
1446  $image_tag_map = array();
1447
1448  if ( !empty($tag_ids) )
1449  { // build list of image ids with associated tags per image
1450    if ($params['tag_mode_and'])
1451    {
1452      $image_ids = get_image_ids_for_tags( $tag_ids );
1453    }
1454    else
1455    {
1456      $query = '
1457SELECT image_id, GROUP_CONCAT(tag_id) tag_ids
1458  FROM '.IMAGE_TAG_TABLE.'
1459  WHERE tag_id IN ('.implode(',',$tag_ids).')
1460  GROUP BY image_id';
1461      $result = pwg_query($query);
1462      while ( $row=pwg_db_fetch_assoc($result) )
1463      {
1464        $row['image_id'] = (int)$row['image_id'];
1465        array_push( $image_ids, $row['image_id'] );
1466        $image_tag_map[ $row['image_id'] ] = explode(',', $row['tag_ids']);
1467      }
1468    }
1469  }
1470
1471  $images = array();
1472  if ( !empty($image_ids))
1473  {
1474    $where_clauses = ws_std_image_sql_filter($params);
1475    $where_clauses[] = get_sql_condition_FandF(
1476        array
1477          (
1478            'forbidden_categories' => 'category_id',
1479            'visible_categories' => 'category_id',
1480            'visible_images' => 'i.id'
1481          ),
1482        '', true
1483      );
1484    $where_clauses[] = 'id IN ('.implode(',',$image_ids).')';
1485
1486    $order_by = ws_std_image_sql_order($params);
1487    if (empty($order_by))
1488    {
1489      $order_by = $conf['order_by'];
1490    }
1491    else
1492    {
1493      $order_by = 'ORDER BY '.$order_by;
1494    }
1495
1496    $query = '
1497SELECT DISTINCT i.* FROM '.IMAGES_TABLE.' i
1498  INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON i.id=image_id
1499  WHERE '. implode('
1500    AND ', $where_clauses).'
1501'.$order_by.'
1502LIMIT '.(int)$params['per_page'].' OFFSET '.(int)($params['per_page']*$params['page']);
1503
1504    $result = pwg_query($query);
1505    while ($row = pwg_db_fetch_assoc($result))
1506    {
1507      $image = array();
1508      foreach ( array('id', 'width', 'height', 'hit') as $k )
1509      {
1510        if (isset($row[$k]))
1511        {
1512          $image[$k] = (int)$row[$k];
1513        }
1514      }
1515      foreach ( array('file', 'name', 'comment') as $k )
1516      {
1517        $image[$k] = $row[$k];
1518      }
1519      $image = array_merge( $image, ws_std_get_urls($row) );
1520
1521      $image_tag_ids = ($params['tag_mode_and']) ? $tag_ids : $image_tag_map[$image['id']];
1522      $image_tags = array();
1523      foreach ($image_tag_ids as $tag_id)
1524      {
1525        $url = make_index_url(
1526                 array(
1527                  'section'=>'tags',
1528                  'tags'=> array($tags_by_id[$tag_id])
1529                )
1530              );
1531        $page_url = make_picture_url(
1532                 array(
1533                  'section'=>'tags',
1534                  'tags'=> array($tags_by_id[$tag_id]),
1535                  'image_id' => $row['id'],
1536                  'image_file' => $row['file'],
1537                )
1538              );
1539        array_push($image_tags, array(
1540                'id' => (int)$tag_id,
1541                'url' => $url,
1542                'page_url' => $page_url,
1543              )
1544            );
1545      }
1546      $image['tags'] = new PwgNamedArray($image_tags, 'tag',
1547              array('id','url_name','url','page_url')
1548            );
1549      array_push($images, $image);
1550    }
1551  }
1552
1553  return array( 'images' =>
1554    array (
1555      WS_XML_ATTRIBUTES =>
1556        array(
1557            'page' => $params['page'],
1558            'per_page' => $params['per_page'],
1559            'count' => count($images)
1560          ),
1561       WS_XML_CONTENT => new PwgNamedArray($images, 'image',
1562          ws_std_get_image_xml_attributes() )
1563      )
1564    );
1565}
1566
1567function ws_categories_add($params, &$service)
1568{
1569  if (!is_admin() or is_adviser())
1570  {
1571    return new PwgError(401, 'Access denied');
1572  }
1573
1574  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1575
1576  $creation_output = create_virtual_category(
1577    $params['name'],
1578    $params['parent']
1579    );
1580
1581  if (isset($creation_output['error']))
1582  {
1583    return new PwgError(500, $creation_output['error']);
1584  }
1585
1586  invalidate_user_cache();
1587
1588  return $creation_output;
1589}
1590
1591function ws_tags_add($params, &$service)
1592{
1593  if (!is_admin() or is_adviser())
1594  {
1595    return new PwgError(401, 'Access denied');
1596  }
1597
1598  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1599
1600  $creation_output = create_tag($params['name']);
1601
1602  if (isset($creation_output['error']))
1603  {
1604    return new PwgError(500, $creation_output['error']);
1605  }
1606
1607  return $creation_output;
1608}
1609
1610function ws_images_exist($params, &$service)
1611{
1612  global $conf;
1613 
1614  if (!is_admin() or is_adviser())
1615  {
1616    return new PwgError(401, 'Access denied');
1617  }
1618
1619  $split_pattern = '/[\s,;\|]/';
1620
1621  if ('md5sum' == $conf['uniqueness_mode'])
1622  {
1623    // search among photos the list of photos already added, based on md5sum
1624    // list
1625    $md5sums = preg_split(
1626      $split_pattern,
1627      $params['md5sum_list'],
1628      -1,
1629      PREG_SPLIT_NO_EMPTY
1630    );
1631
1632    $query = '
1633SELECT
1634    id,
1635    md5sum
1636  FROM '.IMAGES_TABLE.'
1637  WHERE md5sum IN (\''.implode("','", $md5sums).'\')
1638;';
1639    $id_of_md5 = simple_hash_from_query($query, 'md5sum', 'id');
1640
1641    $result = array();
1642
1643    foreach ($md5sums as $md5sum)
1644    {
1645      $result[$md5sum] = null;
1646      if (isset($id_of_md5[$md5sum]))
1647      {
1648        $result[$md5sum] = $id_of_md5[$md5sum];
1649      }
1650    }
1651  }
1652 
1653  if ('filename' == $conf['uniqueness_mode'])
1654  {
1655    // search among photos the list of photos already added, based on
1656    // filename list
1657    $filenames = preg_split(
1658      $split_pattern,
1659      $params['filename_list'],
1660      -1,
1661      PREG_SPLIT_NO_EMPTY
1662    );
1663
1664    $query = '
1665SELECT
1666    id,
1667    file
1668  FROM '.IMAGES_TABLE.'
1669  WHERE file IN (\''.implode("','", $filenames).'\')
1670;';
1671    $id_of_filename = simple_hash_from_query($query, 'file', 'id');
1672
1673    $result = array();
1674
1675    foreach ($filenames as $filename)
1676    {
1677      $result[$filename] = null;
1678      if (isset($id_of_filename[$filename]))
1679      {
1680        $result[$filename] = $id_of_filename[$filename];
1681      }
1682    }
1683  }
1684
1685  return $result;
1686}
1687
1688function ws_images_checkFiles($params, &$service)
1689{
1690  if (!is_admin() or is_adviser())
1691  {
1692    return new PwgError(401, 'Access denied');
1693  }
1694
1695  // input parameters
1696  //
1697  // image_id
1698  // thumbnail_sum
1699  // file_sum
1700  // high_sum
1701
1702  $params['image_id'] = (int)$params['image_id'];
1703  if ($params['image_id'] <= 0)
1704  {
1705    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
1706  }
1707
1708  $query = '
1709SELECT
1710    path
1711  FROM '.IMAGES_TABLE.'
1712  WHERE id = '.$params['image_id'].'
1713;';
1714  $result = pwg_query($query);
1715  if (mysql_num_rows($result) == 0) {
1716    return new PwgError(404, "image_id not found");
1717  }
1718  list($path) = mysql_fetch_row($result);
1719
1720  $ret = array();
1721
1722  foreach (array('thumb', 'file', 'high') as $type) {
1723    $param_name = $type;
1724    if ('thumb' == $type) {
1725      $param_name = 'thumbnail';
1726    }
1727
1728    if (isset($params[$param_name.'_sum'])) {
1729      $type_path = file_path_for_type($path, $type);
1730      if (!is_file($type_path)) {
1731        $ret[$param_name] = 'missing';
1732      }
1733      else {
1734        if (md5_file($type_path) != $params[$param_name.'_sum']) {
1735          $ret[$param_name] = 'differs';
1736        }
1737        else {
1738          $ret[$param_name] = 'equals';
1739        }
1740      }
1741    }
1742  }
1743
1744  return $ret;
1745}
1746
1747function file_path_for_type($file_path, $type='thumb')
1748{
1749  // resolve the $file_path depending on the $type
1750  if ('thumb' == $type) {
1751    $file_path = get_thumbnail_location(
1752      array(
1753        'path' => $file_path,
1754        'tn_ext' => 'jpg',
1755        )
1756      );
1757  }
1758
1759  if ('high' == $type) {
1760    @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php');
1761    $file_path = get_high_location(
1762      array(
1763        'path' => $file_path,
1764        'has_high' => 'true'
1765        )
1766      );
1767  }
1768
1769  return $file_path;
1770}
1771
1772function ws_images_setInfo($params, &$service)
1773{
1774  global $conf;
1775  if (!is_admin() || is_adviser() )
1776  {
1777    return new PwgError(401, 'Access denied');
1778  }
1779
1780  if (!$service->isPost())
1781  {
1782    return new PwgError(405, "This method requires HTTP POST");
1783  }
1784
1785  $params['image_id'] = (int)$params['image_id'];
1786  if ($params['image_id'] <= 0)
1787  {
1788    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id");
1789  }
1790
1791  $query='
1792SELECT *
1793  FROM '.IMAGES_TABLE.'
1794  WHERE id = '.$params['image_id'].'
1795;';
1796
1797  $image_row = pwg_db_fetch_assoc(pwg_query($query));
1798  if ($image_row == null)
1799  {
1800    return new PwgError(404, "image_id not found");
1801  }
1802
1803  // database registration
1804  $update = array();
1805
1806  $info_columns = array(
1807    'name',
1808    'author',
1809    'comment',
1810    'level',
1811    'date_creation',
1812    );
1813
1814  foreach ($info_columns as $key)
1815  {
1816    if (isset($params[$key]))
1817    {
1818      if ('fill_if_empty' == $params['single_value_mode'])
1819      {
1820        if (empty($image_row[$key]))
1821        {
1822          $update[$key] = $params[$key];
1823        }
1824      }
1825      elseif ('replace' == $params['single_value_mode'])
1826      {
1827        $update[$key] = $params[$key];
1828      }
1829      else
1830      {
1831        new PwgError(
1832          500,
1833          '[ws_images_setInfo]'
1834          .' invalid parameter single_value_mode "'.$params['single_value_mode'].'"'
1835          .', possible values are {fill_if_empty, replace}.'
1836          );
1837        exit();
1838      }
1839    }
1840  }
1841
1842  if (count(array_keys($update)) > 0)
1843  {
1844    $update['id'] = $params['image_id'];
1845
1846    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1847    mass_updates(
1848      IMAGES_TABLE,
1849      array(
1850        'primary' => array('id'),
1851        'update'  => array_diff(array_keys($update), array('id'))
1852        ),
1853      array($update)
1854      );
1855  }
1856
1857  if (isset($params['categories']))
1858  {
1859    ws_add_image_category_relations(
1860      $params['image_id'],
1861      $params['categories'],
1862      ('replace' == $params['multiple_value_mode'] ? true : false)
1863      );
1864  }
1865
1866  // and now, let's create tag associations
1867  if (isset($params['tag_ids']))
1868  {
1869    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1870
1871    $tag_ids = explode(',', $params['tag_ids']);
1872
1873    if ('replace' == $params['multiple_value_mode'])
1874    {
1875      set_tags(
1876        $tag_ids,
1877        $params['image_id']
1878        );
1879    }
1880    elseif ('append' == $params['multiple_value_mode'])
1881    {
1882      add_tags(
1883        $tag_ids,
1884        array($params['image_id'])
1885        );
1886    }
1887    else
1888    {
1889      new PwgError(
1890        500,
1891        '[ws_images_setInfo]'
1892        .' invalid parameter multiple_value_mode "'.$params['multiple_value_mode'].'"'
1893        .', possible values are {replace, append}.'
1894        );
1895      exit();
1896    }
1897  }
1898
1899  invalidate_user_cache();
1900}
1901
1902function ws_add_image_category_relations($image_id, $categories_string, $replace_mode=false)
1903{
1904  // let's add links between the image and the categories
1905  //
1906  // $params['categories'] should look like 123,12;456,auto;789 which means:
1907  //
1908  // 1. associate with category 123 on rank 12
1909  // 2. associate with category 456 on automatic rank
1910  // 3. associate with category 789 on automatic rank
1911  $cat_ids = array();
1912  $rank_on_category = array();
1913  $search_current_ranks = false;
1914
1915  $tokens = explode(';', $categories_string);
1916  foreach ($tokens as $token)
1917  {
1918    @list($cat_id, $rank) = explode(',', $token);
1919
1920    if (!preg_match('/^\d+$/', $cat_id))
1921    {
1922      continue;
1923    }
1924
1925    array_push($cat_ids, $cat_id);
1926
1927    if (!isset($rank))
1928    {
1929      $rank = 'auto';
1930    }
1931    $rank_on_category[$cat_id] = $rank;
1932
1933    if ($rank == 'auto')
1934    {
1935      $search_current_ranks = true;
1936    }
1937  }
1938
1939  $cat_ids = array_unique($cat_ids);
1940
1941  if (count($cat_ids) == 0)
1942  {
1943    new PwgError(
1944      500,
1945      '[ws_add_image_category_relations] there is no category defined in "'.$categories_string.'"'
1946      );
1947    exit();
1948  }
1949
1950  $query = '
1951SELECT
1952    id
1953  FROM '.CATEGORIES_TABLE.'
1954  WHERE id IN ('.implode(',', $cat_ids).')
1955;';
1956  $db_cat_ids = array_from_query($query, 'id');
1957
1958  $unknown_cat_ids = array_diff($cat_ids, $db_cat_ids);
1959  if (count($unknown_cat_ids) != 0)
1960  {
1961    new PwgError(
1962      500,
1963      '[ws_add_image_category_relations] the following categories are unknown: '.implode(', ', $unknown_cat_ids)
1964      );
1965    exit();
1966  }
1967
1968  $to_update_cat_ids = array();
1969
1970  // in case of replace mode, we first check the existing associations
1971  $query = '
1972SELECT
1973    category_id
1974  FROM '.IMAGE_CATEGORY_TABLE.'
1975  WHERE image_id = '.$image_id.'
1976;';
1977  $existing_cat_ids = array_from_query($query, 'category_id');
1978
1979  if ($replace_mode)
1980  {
1981    $to_remove_cat_ids = array_diff($existing_cat_ids, $cat_ids);
1982    if (count($to_remove_cat_ids) > 0)
1983    {
1984      $query = '
1985DELETE
1986  FROM '.IMAGE_CATEGORY_TABLE.'
1987  WHERE image_id = '.$image_id.'
1988    AND category_id IN ('.implode(', ', $to_remove_cat_ids).')
1989;';
1990      pwg_query($query);
1991      update_category($to_remove_cat_ids);
1992    }
1993  }
1994
1995  $new_cat_ids = array_diff($cat_ids, $existing_cat_ids);
1996  if (count($new_cat_ids) == 0)
1997  {
1998    return true;
1999  }
2000
2001  if ($search_current_ranks)
2002  {
2003    $query = '
2004SELECT
2005    category_id,
2006    MAX(rank) AS max_rank
2007  FROM '.IMAGE_CATEGORY_TABLE.'
2008  WHERE rank IS NOT NULL
2009    AND category_id IN ('.implode(',', $new_cat_ids).')
2010  GROUP BY category_id
2011;';
2012    $current_rank_of = simple_hash_from_query(
2013      $query,
2014      'category_id',
2015      'max_rank'
2016      );
2017
2018    foreach ($new_cat_ids as $cat_id)
2019    {
2020      if (!isset($current_rank_of[$cat_id]))
2021      {
2022        $current_rank_of[$cat_id] = 0;
2023      }
2024
2025      if ('auto' == $rank_on_category[$cat_id])
2026      {
2027        $rank_on_category[$cat_id] = $current_rank_of[$cat_id] + 1;
2028      }
2029    }
2030  }
2031
2032  $inserts = array();
2033
2034  foreach ($new_cat_ids as $cat_id)
2035  {
2036    array_push(
2037      $inserts,
2038      array(
2039        'image_id' => $image_id,
2040        'category_id' => $cat_id,
2041        'rank' => $rank_on_category[$cat_id],
2042        )
2043      );
2044  }
2045
2046  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2047  mass_inserts(
2048    IMAGE_CATEGORY_TABLE,
2049    array_keys($inserts[0]),
2050    $inserts
2051    );
2052
2053  update_category($new_cat_ids);
2054}
2055
2056function ws_categories_setInfo($params, &$service)
2057{
2058  global $conf;
2059  if (!is_admin() || is_adviser() )
2060  {
2061    return new PwgError(401, 'Access denied');
2062  }
2063
2064  if (!$service->isPost())
2065  {
2066    return new PwgError(405, "This method requires HTTP POST");
2067  }
2068
2069  // category_id
2070  // name
2071  // comment
2072
2073  $params['category_id'] = (int)$params['category_id'];
2074  if ($params['category_id'] <= 0)
2075  {
2076    return new PwgError(WS_ERR_INVALID_PARAM, "Invalid category_id");
2077  }
2078
2079  // database registration
2080  $update = array(
2081    'id' => $params['category_id'],
2082    );
2083
2084  $info_columns = array(
2085    'name',
2086    'comment',
2087    );
2088
2089  $perform_update = false;
2090  foreach ($info_columns as $key)
2091  {
2092    if (isset($params[$key]))
2093    {
2094      $perform_update = true;
2095      $update[$key] = $params[$key];
2096    }
2097  }
2098
2099  if ($perform_update)
2100  {
2101    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
2102    mass_updates(
2103      CATEGORIES_TABLE,
2104      array(
2105        'primary' => array('id'),
2106        'update'  => array_diff(array_keys($update), array('id'))
2107        ),
2108      array($update)
2109      );
2110  }
2111
2112}
2113
2114function ws_logfile($string)
2115{
2116  global $conf;
2117
2118  if (!$conf['ws_enable_log']) {
2119    return true;
2120  }
2121
2122  file_put_contents(
2123    $conf['ws_log_filepath'],
2124    '['.date('c').'] '.$string."\n",
2125    FILE_APPEND
2126    );
2127}
2128
2129function ws_images_checkUpload($params, &$service)
2130{
2131  global $conf;
2132
2133  if (!is_admin() or is_adviser())
2134  {
2135    return new PwgError(401, 'Access denied');
2136  }
2137
2138  $ret['message'] = ready_for_upload_message();
2139  $ret['ready_for_upload'] = true;
2140 
2141  if (!empty($ret['message']))
2142  {
2143    $ret['ready_for_upload'] = false;
2144  }
2145 
2146  return $ret;
2147}
2148
2149function ready_for_upload_message()
2150{
2151  global $conf;
2152
2153  $relative_dir = preg_replace('#^'.PHPWG_ROOT_PATH.'#', '', $conf['upload_dir']);
2154
2155  if (!is_dir($conf['upload_dir']))
2156  {
2157    if (!is_writable(dirname($conf['upload_dir'])))
2158    {
2159      return sprintf(
2160        l10n('Create the "%s" directory at the root of your Piwigo installation'),
2161        $relative_dir
2162        );
2163    }
2164  }
2165  else
2166  {
2167    if (!is_writable($conf['upload_dir']))
2168    {
2169      @chmod($conf['upload_dir'], 0777);
2170     
2171      if (!is_writable($conf['upload_dir']))
2172      {
2173        return sprintf(
2174          l10n('Give write access (chmod 777) to "%s" directory at the root of your Piwigo installation'),
2175          $relative_dir
2176          );
2177      }
2178    }
2179  }
2180
2181  return null;
2182}
2183?>
Note: See TracBrowser for help on using the repository browser.