source: trunk/include/ws_functions/pwg.images.php @ 25968

Last change on this file since 25968 was 25281, checked in by mistic100, 11 years ago

splits ws_functions.inc.php in 8 files + comments + code cleaning

File size: 37.3 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2013 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// +-----------------------------------------------------------------------+
25// | UTILITIES                                                             |
26// +-----------------------------------------------------------------------+
27
28/**
29 * Sets associations of an image
30 * @param int $image_id
31 * @param string $categories_string - "cat_id[,rank];cat_id[,rank]"
32 * @param bool $replace_mode - removes old associations
33 */
34function ws_add_image_category_relations($image_id, $categories_string, $replace_mode=false)
35{
36  // let's add links between the image and the categories
37  //
38  // $params['categories'] should look like 123,12;456,auto;789 which means:
39  //
40  // 1. associate with category 123 on rank 12
41  // 2. associate with category 456 on automatic rank
42  // 3. associate with category 789 on automatic rank
43  $cat_ids = array();
44  $rank_on_category = array();
45  $search_current_ranks = false;
46
47  $tokens = explode(';', $categories_string);
48  foreach ($tokens as $token)
49  {
50    @list($cat_id, $rank) = explode(',', $token);
51
52    if (!preg_match('/^\d+$/', $cat_id))
53    {
54      continue;
55    }
56
57    $cat_ids[] = $cat_id;
58
59    if (!isset($rank))
60    {
61      $rank = 'auto';
62    }
63    $rank_on_category[$cat_id] = $rank;
64
65    if ($rank == 'auto')
66    {
67      $search_current_ranks = true;
68    }
69  }
70
71  $cat_ids = array_unique($cat_ids);
72
73  if (count($cat_ids) == 0)
74  {
75    return new PwgError(500,
76      '[ws_add_image_category_relations] there is no category defined in "'.$categories_string.'"'
77      );
78  }
79
80  $query = '
81SELECT id
82  FROM '.CATEGORIES_TABLE.'
83  WHERE id IN ('.implode(',', $cat_ids).')
84;';
85  $db_cat_ids = array_from_query($query, 'id');
86
87  $unknown_cat_ids = array_diff($cat_ids, $db_cat_ids);
88  if (count($unknown_cat_ids) != 0)
89  {
90    return new PwgError(500,
91      '[ws_add_image_category_relations] the following categories are unknown: '.implode(', ', $unknown_cat_ids)
92      );
93  }
94
95  $to_update_cat_ids = array();
96
97  // in case of replace mode, we first check the existing associations
98  $query = '
99SELECT category_id
100  FROM '.IMAGE_CATEGORY_TABLE.'
101  WHERE image_id = '.$image_id.'
102;';
103  $existing_cat_ids = array_from_query($query, 'category_id');
104
105  if ($replace_mode)
106  {
107    $to_remove_cat_ids = array_diff($existing_cat_ids, $cat_ids);
108    if (count($to_remove_cat_ids) > 0)
109    {
110      $query = '
111DELETE
112  FROM '.IMAGE_CATEGORY_TABLE.'
113  WHERE image_id = '.$image_id.'
114    AND category_id IN ('.implode(', ', $to_remove_cat_ids).')
115;';
116      pwg_query($query);
117      update_category($to_remove_cat_ids);
118    }
119  }
120
121  $new_cat_ids = array_diff($cat_ids, $existing_cat_ids);
122  if (count($new_cat_ids) == 0)
123  {
124    return true;
125  }
126
127  if ($search_current_ranks)
128  {
129    $query = '
130SELECT category_id, MAX(rank) AS max_rank
131  FROM '.IMAGE_CATEGORY_TABLE.'
132  WHERE rank IS NOT NULL
133    AND category_id IN ('.implode(',', $new_cat_ids).')
134  GROUP BY category_id
135;';
136    $current_rank_of = simple_hash_from_query(
137      $query,
138      'category_id',
139      'max_rank'
140      );
141
142    foreach ($new_cat_ids as $cat_id)
143    {
144      if (!isset($current_rank_of[$cat_id]))
145      {
146        $current_rank_of[$cat_id] = 0;
147      }
148
149      if ('auto' == $rank_on_category[$cat_id])
150      {
151        $rank_on_category[$cat_id] = $current_rank_of[$cat_id] + 1;
152      }
153    }
154  }
155
156  $inserts = array();
157
158  foreach ($new_cat_ids as $cat_id)
159  {
160    $inserts[] = array(
161      'image_id' => $image_id,
162      'category_id' => $cat_id,
163      'rank' => $rank_on_category[$cat_id],
164      );
165  }
166
167  mass_inserts(
168    IMAGE_CATEGORY_TABLE,
169    array_keys($inserts[0]),
170    $inserts
171    );
172
173  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
174  update_category($new_cat_ids);
175}
176
177/**
178 * Merge chunks added by pwg.images.addChunk
179 * @param string $output_filepath
180 * @param string $original_sum
181 * @param string $type
182 */
183function merge_chunks($output_filepath, $original_sum, $type)
184{
185  global $conf;
186
187  ws_logfile('[merge_chunks] input parameter $output_filepath : '.$output_filepath);
188
189  if (is_file($output_filepath))
190  {
191    unlink($output_filepath);
192
193    if (is_file($output_filepath))
194    {
195      return new PwgError(500, '[merge_chunks] error while trying to remove existing '.$output_filepath);
196    }
197  }
198
199  $upload_dir = $conf['upload_dir'].'/buffer';
200  $pattern = '/'.$original_sum.'-'.$type.'/';
201  $chunks = array();
202
203  if ($handle = opendir($upload_dir))
204  {
205    while (false !== ($file = readdir($handle)))
206    {
207      if (preg_match($pattern, $file))
208      {
209        ws_logfile($file);
210        $chunks[] = $upload_dir.'/'.$file;
211      }
212    }
213    closedir($handle);
214  }
215
216  sort($chunks);
217
218  if (function_exists('memory_get_usage')) {
219    ws_logfile('[merge_chunks] memory_get_usage before loading chunks: '.memory_get_usage());
220  }
221
222  $i = 0;
223
224  foreach ($chunks as $chunk)
225  {
226    $string = file_get_contents($chunk);
227
228    if (function_exists('memory_get_usage')) {
229      ws_logfile('[merge_chunks] memory_get_usage on chunk '.++$i.': '.memory_get_usage());
230    }
231
232    if (!file_put_contents($output_filepath, $string, FILE_APPEND))
233    {
234      return new PwgError(500, '[merge_chunks] error while writting chunks for '.$output_filepath);
235    }
236
237    unlink($chunk);
238  }
239
240  if (function_exists('memory_get_usage')) {
241    ws_logfile('[merge_chunks] memory_get_usage after loading chunks: '.memory_get_usage());
242  }
243}
244
245/**
246 * Deletes chunks added with pwg.images.addChunk
247 * @param string $original_sum
248 * @param string $type
249 *
250 * Function introduced for Piwigo 2.4 and the new "multiple size"
251 * (derivatives) feature. As we only need the biggest sent photo as
252 * "original", we remove chunks for smaller sizes. We can't make it earlier
253 * in ws_images_add_chunk because at this moment we don't know which $type
254 * will be the biggest (we could remove the thumb, but let's use the same
255 * algorithm)
256 */
257function remove_chunks($original_sum, $type)
258{
259  global $conf;
260
261  $upload_dir = $conf['upload_dir'].'/buffer';
262  $pattern = '/'.$original_sum.'-'.$type.'/';
263  $chunks = array();
264
265  if ($handle = opendir($upload_dir))
266  {
267    while (false !== ($file = readdir($handle)))
268    {
269      if (preg_match($pattern, $file))
270      {
271        $chunks[] = $upload_dir.'/'.$file;
272      }
273    }
274    closedir($handle);
275  }
276
277  foreach ($chunks as $chunk)
278  {
279    unlink($chunk);
280  }
281}
282
283
284// +-----------------------------------------------------------------------+
285// | METHODS                                                               |
286// +-----------------------------------------------------------------------+
287
288/**
289 * API method
290 * Adds a comment to an image
291 * @param mixed[] $params
292 *    @option int image_id
293 *    @option string author
294 *    @option string content
295 *    @option string key
296 */
297function ws_images_addComment($params, &$service)
298{
299  $query = '
300SELECT DISTINCT image_id
301  FROM '. IMAGE_CATEGORY_TABLE .'
302      INNER JOIN '.CATEGORIES_TABLE.' ON category_id=id
303  WHERE commentable="true"
304    AND image_id='.$params['image_id'].
305    get_sql_condition_FandF(
306      array(
307        'forbidden_categories' => 'id',
308        'visible_categories' => 'id',
309        'visible_images' => 'image_id'
310        ),
311      ' AND'
312      ).'
313;';
314
315  if (!pwg_db_num_rows(pwg_query($query)))
316  {
317    return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid image_id');
318  }
319
320  $comm = array(
321    'author' => trim($params['author']),
322    'content' => trim($params['content']),
323    'image_id' => $params['image_id'],
324   );
325
326  include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php');
327
328  $comment_action = insert_user_comment($comm, $params['key'], $infos);
329
330  switch ($comment_action)
331  {
332    case 'reject':
333      $infos[] = l10n('Your comment has NOT been registered because it did not pass the validation rules');
334      return new PwgError(403, implode("; ", $infos) );
335
336    case 'validate':
337    case 'moderate':
338      $ret = array(
339        'id' => $comm['id'],
340        'validation' => $comment_action=='validate',
341        );
342      return array('comment' => new PwgNamedStruct($ret));
343
344    default:
345      return new PwgError(500, "Unknown comment action ".$comment_action );
346  }
347}
348
349/**
350 * API method
351 * Returns detailed information for an element
352 * @param mixed[] $params
353 *    @option int image_id
354 *    @option int comments_page
355 *    @option int comments_per_page
356 */
357function ws_images_getInfo($params, &$service)
358{
359  global $user, $conf;
360
361  $query='
362SELECT *
363  FROM '. IMAGES_TABLE .'
364  WHERE id='. $params['image_id'] .
365    get_sql_condition_FandF(
366      array('visible_images' => 'id'),
367      ' AND'
368      ).'
369LIMIT 1
370;';
371  $result = pwg_query($query);
372
373  if (pwg_db_num_rows($result) == 0)
374  {
375    return new PwgError(404, 'image_id not found');
376  }
377
378  $image_row = pwg_db_fetch_assoc($result);
379  $image_row = array_merge($image_row, ws_std_get_urls($image_row));
380
381  //-------------------------------------------------------- related categories
382  $query = '
383SELECT id, name, permalink, uppercats, global_rank, commentable
384  FROM '. IMAGE_CATEGORY_TABLE .'
385    INNER JOIN '. CATEGORIES_TABLE .' ON category_id = id
386  WHERE image_id = '. $image_row['id'] .
387    get_sql_condition_FandF(
388      array('forbidden_categories' => 'category_id'),
389      ' AND'
390      ).'
391;';
392  $result = pwg_query($query);
393
394  $is_commentable = false;
395  $related_categories = array();
396  while ($row = pwg_db_fetch_assoc($result))
397  {
398    if ($row['commentable']=='true')
399    {
400      $is_commentable = true;
401    }
402    unset($row['commentable']);
403
404    $row['url'] = make_index_url(
405      array(
406        'category' => $row
407        )
408      );
409
410    $row['page_url'] = make_picture_url(
411      array(
412        'image_id' => $image_row['id'],
413        'image_file' => $image_row['file'],
414        'category' => $row
415        )
416      );
417
418    $row['id']=(int)$row['id'];
419    $related_categories[] = $row;
420  }
421  usort($related_categories, 'global_rank_compare');
422
423  if (empty($related_categories))
424  {
425    return new PwgError(401, 'Access denied');
426  }
427
428  //-------------------------------------------------------------- related tags
429  $related_tags = get_common_tags(array($image_row['id']), -1);
430  foreach ($related_tags as $i=>$tag)
431  {
432    $tag['url'] = make_index_url(
433      array(
434        'tags' => array($tag)
435        )
436      );
437    $tag['page_url'] = make_picture_url(
438      array(
439        'image_id' => $image_row['id'],
440        'image_file' => $image_row['file'],
441        'tags' => array($tag),
442        )
443      );
444
445    unset($tag['counter']);
446    $tag['id'] = (int)$tag['id'];
447    $related_tags[$i] = $tag;
448  }
449
450  //------------------------------------------------------------- related rates
451        $rating = array(
452    'score' => $image_row['rating_score'],
453    'count' => 0,
454    'average' => null,
455    );
456        if (isset($rating['score']))
457        {
458                $query = '
459SELECT COUNT(rate) AS count, ROUND(AVG(rate),2) AS average
460  FROM '. RATE_TABLE .'
461  WHERE element_id = '. $image_row['id'] .'
462;';
463                $row = pwg_db_fetch_assoc(pwg_query($query));
464
465                $rating['score'] = (float)$rating['score'];
466                $rating['average'] = (float)$row['average'];
467                $rating['count'] = (int)$row['count'];
468        }
469
470  //---------------------------------------------------------- related comments
471  $related_comments = array();
472
473  $where_comments = 'image_id = '.$image_row['id'];
474  if (!is_admin())
475  {
476    $where_comments .= ' AND validated="true"';
477  }
478
479  $query = '
480SELECT COUNT(id) AS nb_comments
481  FROM '. COMMENTS_TABLE .'
482  WHERE '. $where_comments .'
483;';
484  list($nb_comments) = array_from_query($query, 'nb_comments');
485  $nb_comments = (int)$nb_comments;
486
487  if ($nb_comments>0 and $params['comments_per_page']>0)
488  {
489    $query = '
490SELECT id, date, author, content
491  FROM '. COMMENTS_TABLE .'
492  WHERE '. $where_comments .'
493  ORDER BY date
494  LIMIT '. (int)$params['comments_per_page'] .'
495  OFFSET '. (int)($params['comments_per_page']*$params['comments_page']) .'
496;';
497    $result = pwg_query($query);
498
499    while ($row = pwg_db_fetch_assoc($result))
500    {
501      $row['id'] = (int)$row['id'];
502      $related_comments[] = $row;
503    }
504  }
505
506  $comment_post_data = null;
507  if ($is_commentable and
508      (!is_a_guest()
509        or (is_a_guest() and $conf['comments_forall'] )
510      )
511    )
512  {
513    $comment_post_data['author'] = stripslashes($user['username']);
514    $comment_post_data['key'] = get_ephemeral_key(2, $params['image_id']);
515  }
516
517  $ret = $image_row;
518  foreach (array('id','width','height','hit','filesize') as $k)
519  {
520    if (isset($ret[$k]))
521    {
522      $ret[$k] = (int)$ret[$k];
523    }
524  }
525  foreach (array('path', 'storage_category_id') as $k)
526  {
527    unset($ret[$k]);
528  }
529
530  $ret['rates'] = array(
531    WS_XML_ATTRIBUTES => $rating
532    );
533  $ret['categories'] = new PwgNamedArray(
534    $related_categories,
535    'category',
536    array('id','url', 'page_url')
537    );
538  $ret['tags'] = new PwgNamedArray(
539    $related_tags,
540    'tag',
541    ws_std_get_tag_xml_attributes()
542    );
543  if (isset($comment_post_data))
544  {
545    $ret['comment_post'] = array(
546      WS_XML_ATTRIBUTES => $comment_post_data
547      );
548  }
549  $ret['comments_paging'] = new PwgNamedStruct(
550    array(
551      'page' => $params['comments_page'],
552      'per_page' => $params['comments_per_page'],
553      'count' => count($related_comments),
554      'total_count' => $nb_comments,
555      )
556    );
557  $ret['comments'] = new PwgNamedArray(
558    $related_comments,
559    'comment',
560    array('id','date')
561    );
562
563  if ($service->_responseFormat != 'rest')
564  {
565    return $ret; // for backward compatibility only
566  }
567  else
568  {
569    return array(
570      'image' => new PwgNamedStruct($ret, null, array('name','comment'))
571      );
572  }
573}
574
575/**
576 * API method
577 * Rates an image
578 * @param mixed[] $params
579 *    @option int image_id
580 *    @option float rate
581 */
582function ws_images_rate($params, &$service)
583{
584  $query = '
585SELECT DISTINCT id
586  FROM '. IMAGES_TABLE .'
587    INNER JOIN '. IMAGE_CATEGORY_TABLE .' ON id=image_id
588  WHERE id='. $params['image_id']
589    .get_sql_condition_FandF(
590      array(
591        'forbidden_categories' => 'category_id',
592        'forbidden_images' => 'id',
593        ),
594      '    AND'
595      ).'
596  LIMIT 1
597;';
598  if (pwg_db_num_rows(pwg_query($query))==0)
599  {
600    return new PwgError(404, 'Invalid image_id or access denied');
601  }
602
603  include_once(PHPWG_ROOT_PATH.'include/functions_rate.inc.php');
604  $res = rate_picture($params['image_id'], (int)$params['rate']);
605
606  if ($res==false)
607  {
608    global $conf;
609    return new PwgError(403, 'Forbidden or rate not in '. implode(',', $conf['rate_items']));
610  }
611  return $res;
612}
613
614/**
615 * API method
616 * Returns a list of elements corresponding to a query search
617 * @param mixed[] $params
618 *    @option string query
619 *    @option int per_page
620 *    @option int page
621 *    @option string order (optional)
622 */
623function ws_images_search($params, &$service)
624{
625  include_once(PHPWG_ROOT_PATH .'include/functions_search.inc.php');
626
627  $images = array();
628  $where_clauses = ws_std_image_sql_filter($params, 'i.');
629  $order_by = ws_std_image_sql_order($params, 'i.');
630
631  $super_order_by = false;
632  if (!empty($order_by))
633  {
634    global $conf;
635    $conf['order_by'] = 'ORDER BY '.$order_by;
636    $super_order_by = true; // quick_search_result might be faster
637  }
638
639  $search_result = get_quick_search_results(
640    $params['query'],
641    $super_order_by,
642    implode(' AND ', $where_clauses)
643    );
644
645  $image_ids = array_slice(
646    $search_result['items'],
647    $params['page']*$params['per_page'],
648    $params['per_page']
649    );
650
651  if (count($image_ids))
652  {
653    $query = '
654SELECT *
655  FROM '. IMAGES_TABLE .'
656  WHERE id IN ('. implode(',', $image_ids) .')
657;';
658    $result = pwg_query($query);
659    $image_ids = array_flip($image_ids);
660
661    while ($row = pwg_db_fetch_assoc($result))
662    {
663      $image = array();
664      foreach (array('id', 'width', 'height', 'hit') as $k)
665      {
666        if (isset($row[$k]))
667        {
668          $image[$k] = (int)$row[$k];
669        }
670      }
671      foreach (array('file', 'name', 'comment', 'date_creation', 'date_available') as $k)
672      {
673        $image[$k] = $row[$k];
674      }
675
676      $image = array_merge($image, ws_std_get_urls($row));
677      $images[ $image_ids[ $image['id'] ] ] = $image;
678    }
679    ksort($images, SORT_NUMERIC);
680    $images = array_values($images);
681  }
682
683  return array (
684    'paging' => new PwgNamedStruct(
685      array(
686        'page' => $params['page'],
687        'per_page' => $params['per_page'],
688        'count' => count($images),
689        'total_count' => count($search_result['items']),
690        )
691      ),
692    'images' => new PwgNamedArray(
693      $images,
694      'image',
695      ws_std_get_image_xml_attributes()
696      )
697    );
698}
699
700/**
701 * API method
702 * Sets the level of an image
703 * @param mixed[] $params
704 *    @option int image_id
705 *    @option int level
706 */
707function ws_images_setPrivacyLevel($params, &$service)
708{
709  global $conf;
710
711  if (!in_array($params['level'], $conf['available_permission_levels']))
712  {
713    return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid level');
714  }
715
716  $query = '
717UPDATE '. IMAGES_TABLE .'
718  SET level='. (int)$params['level'] .'
719  WHERE id IN ('. implode(',',$params['image_id']) .')
720;';
721  $result = pwg_query($query);
722
723  $affected_rows = pwg_db_changes($result);
724  if ($affected_rows)
725  {
726    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
727    invalidate_user_cache();
728  }
729  return $affected_rows;
730}
731
732/**
733 * API method
734 * Sets the rank of an image in a category
735 * @param mixed[] $params
736 *    @option int image_id
737 *    @option int category_id
738 *    @option int rank
739 */
740function ws_images_setRank($params, &$service)
741{
742  // does the image really exist?
743  $query = '
744SELECT COUNT(*)
745  FROM '. IMAGES_TABLE .'
746  WHERE id = '. $params['image_id'] .'
747;';
748  list($count) = pwg_db_fetch_row(pwg_query($query));
749  if ($count == 0)
750  {
751    return new PwgError(404, 'image_id not found');
752  }
753
754  // is the image associated to this category?
755  $query = '
756SELECT COUNT(*)
757  FROM '. IMAGE_CATEGORY_TABLE .'
758  WHERE image_id = '. $params['image_id'] .'
759    AND category_id = '. $params['category_id'] .'
760;';
761  list($count) = pwg_db_fetch_row(pwg_query($query));
762  if ($count == 0)
763  {
764    return new PwgError(404, 'This image is not associated to this category');
765  }
766
767  // what is the current higher rank for this category?
768  $query = '
769SELECT MAX(rank) AS max_rank
770  FROM '. IMAGE_CATEGORY_TABLE .'
771  WHERE category_id = '. $params['category_id'] .'
772;';
773  $row = pwg_db_fetch_assoc(pwg_query($query));
774
775  if (is_numeric($row['max_rank']))
776  {
777    if ($params['rank'] > $row['max_rank'])
778    {
779      $params['rank'] = $row['max_rank'] + 1;
780    }
781  }
782  else
783  {
784    $params['rank'] = 1;
785  }
786
787  // update rank for all other photos in the same category
788  $query = '
789UPDATE '. IMAGE_CATEGORY_TABLE .'
790  SET rank = rank + 1
791  WHERE category_id = '. $params['category_id'] .'
792    AND rank IS NOT NULL
793    AND rank >= '. $params['rank'] .'
794;';
795  pwg_query($query);
796
797  // set the new rank for the photo
798  $query = '
799UPDATE '. IMAGE_CATEGORY_TABLE .'
800  SET rank = '. $params['rank'] .'
801  WHERE image_id = '. $params['image_id'] .'
802    AND category_id = '. $params['category_id'] .'
803;';
804  pwg_query($query);
805
806  // return data for client
807  return array(
808    'image_id' => $params['image_id'],
809    'category_id' => $params['category_id'],
810    'rank' => $params['rank'],
811    );
812}
813
814/**
815 * API method
816 * Adds a file chunk
817 * @param mixed[] $params
818 *    @option string data
819 *    @option string original_sum
820 *    @option string type = 'file'
821 *    @option int position
822 */
823function ws_images_add_chunk($params, &$service)
824{
825  global $conf;
826
827  foreach ($params as $param_key => $param_value)
828  {
829    if ('data' == $param_key)
830    {
831      continue;
832    }
833    ws_logfile(
834      sprintf(
835        '[ws_images_add_chunk] input param "%s" : "%s"',
836        $param_key,
837        is_null($param_value) ? 'NULL' : $param_value
838        )
839      );
840  }
841
842  $upload_dir = $conf['upload_dir'].'/buffer';
843
844  // create the upload directory tree if not exists
845  if (!mkgetdir($upload_dir, MKGETDIR_DEFAULT&~MKGETDIR_DIE_ON_ERROR))
846  {
847    return new PwgError(500, 'error during buffer directory creation');
848  }
849
850  $filename = sprintf(
851    '%s-%s-%05u.block',
852    $params['original_sum'],
853    $params['type'],
854    $params['position']
855    );
856
857  ws_logfile('[ws_images_add_chunk] data length : '.strlen($params['data']));
858
859  $bytes_written = file_put_contents(
860    $upload_dir.'/'.$filename,
861    base64_decode($params['data'])
862    );
863
864  if (false === $bytes_written)
865  {
866    return new PwgError(500,
867      'an error has occured while writting chunk '.$params['position'].' for '.$params['type']
868      );
869  }
870}
871
872/**
873 * API method
874 * Adds a file
875 * @param mixed[] $params
876 *    @option int image_id
877 *    @option string type = 'file'
878 *    @option string sum
879 */
880function ws_images_addFile($params, &$service)
881{
882  ws_logfile(__FUNCTION__.', input :  '.var_export($params, true));
883
884  global $conf;
885
886  // what is the path and other infos about the photo?
887  $query = '
888SELECT
889    path, file, md5sum,
890    width, height, filesize
891  FROM '. IMAGES_TABLE .'
892  WHERE id = '. $params['image_id'] .'
893;';
894  $result = pwg_query($query);
895
896  if (pwg_db_num_rows($result) == 0)
897  {
898    return new PwgError(404, "image_id not found");
899  }
900
901  $image = pwg_db_fetch_assoc($result);
902
903  // since Piwigo 2.4 and derivatives, we do not take the imported "thumb" into account
904  if ('thumb' == $params['type'])
905  {
906    remove_chunks($image['md5sum'], $type);
907    return true;
908  }
909
910  // since Piwigo 2.4 and derivatives, we only care about the "original"
911  $original_type = 'file';
912  if ('high' == $params['type'])
913  {
914    $original_type = 'high';
915  }
916
917  $file_path = $conf['upload_dir'].'/buffer/'.$image['md5sum'].'-original';
918
919  merge_chunks($file_path, $image['md5sum'], $original_type);
920  chmod($file_path, 0644);
921
922  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
923
924  // if we receive the "file", we only update the original if the "file" is
925  // bigger than current original
926  if ('file' == $params['type'])
927  {
928    $do_update = false;
929
930    $infos = pwg_image_infos($file_path);
931
932    foreach (array('width', 'height', 'filesize') as $image_info)
933    {
934      if ($infos[$image_info] > $image[$image_info])
935      {
936        $do_update = true;
937      }
938    }
939
940    if (!$do_update)
941    {
942      unlink($file_path);
943      return true;
944    }
945  }
946
947  $image_id = add_uploaded_file(
948    $file_path,
949    $image['file'],
950    null,
951    null,
952    $params['image_id'],
953    $image['md5sum'] // we force the md5sum to remain the same
954    );
955}
956
957/**
958 * API method
959 * Adds an image
960 * @param mixed[] $params
961 *    @option string original_sum
962 *    @option string original_filename (optional)
963 *    @option string name (optional)
964 *    @option string author (optional)
965 *    @option string date_creation (optional)
966 *    @option string comment (optional)
967 *    @option string categories (optional) - "cat_id[,rank];cat_id[,rank]"
968 *    @option string tags_ids (optional) - "tag_id,tag_id"
969 *    @option int level
970 *    @option bool check_uniqueness
971 *    @option int image_id (optional)
972 */
973function ws_images_add($params, &$service)
974{
975  global $conf, $user;
976
977  foreach ($params as $param_key => $param_value)
978  {
979    ws_logfile(
980      sprintf(
981        '[pwg.images.add] input param "%s" : "%s"',
982        $param_key,
983        is_null($param_value) ? 'NULL' : $param_value
984        )
985      );
986  }
987
988  if ($params['image_id'] > 0)
989  {
990    $query = '
991SELECT COUNT(*)
992  FROM '. IMAGES_TABLE .'
993  WHERE id = '. $params['image_id'] .'
994;';
995    list($count) = pwg_db_fetch_row(pwg_query($query));
996    if ($count == 0)
997    {
998      return new PwgError(404, 'image_id not found');
999    }
1000  }
1001
1002  // does the image already exists ?
1003  if ($params['check_uniqueness'])
1004  {
1005    if ('md5sum' == $conf['uniqueness_mode'])
1006    {
1007      $where_clause = "md5sum = '".$params['original_sum']."'";
1008    }
1009    if ('filename' == $conf['uniqueness_mode'])
1010    {
1011      $where_clause = "file = '".$params['original_filename']."'";
1012    }
1013
1014    $query = '
1015SELECT COUNT(*)
1016  FROM '. IMAGES_TABLE .'
1017  WHERE '. $where_clause .'
1018;';
1019    list($counter) = pwg_db_fetch_row(pwg_query($query));
1020    if ($counter != 0)
1021    {
1022      return new PwgError(500, 'file already exists');
1023    }
1024  }
1025
1026  // due to the new feature "derivatives" (multiple sizes) introduced for
1027  // Piwigo 2.4, we only take the biggest photos sent on
1028  // pwg.images.addChunk. If "high" is available we use it as "original"
1029  // else we use "file".
1030  remove_chunks($params['original_sum'], 'thumb');
1031
1032  if (isset($params['high_sum']))
1033  {
1034    $original_type = 'high';
1035    remove_chunks($params['original_sum'], 'file');
1036  }
1037  else
1038  {
1039    $original_type = 'file';
1040  }
1041
1042  $file_path = $conf['upload_dir'].'/buffer/'.$params['original_sum'].'-original';
1043
1044  merge_chunks($file_path, $params['original_sum'], $original_type);
1045  chmod($file_path, 0644);
1046
1047  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
1048
1049  $image_id = add_uploaded_file(
1050    $file_path,
1051    $params['original_filename'],
1052    null, // categories
1053    isset($params['level']) ? $params['level'] : null,
1054    $params['image_id'] > 0 ? $params['image_id'] : null,
1055    $params['original_sum']
1056    );
1057
1058  $info_columns = array(
1059    'name',
1060    'author',
1061    'comment',
1062    'date_creation',
1063    );
1064
1065  $update = array();
1066  foreach ($info_columns as $key)
1067  {
1068    if (isset($params[$key]))
1069    {
1070      $update[$key] = $params[$key];
1071    }
1072  }
1073
1074  if (count(array_keys($update)) > 0)
1075  {
1076    single_update(
1077      IMAGES_TABLE,
1078      $update,
1079      array('id' => $image_id)
1080      );
1081  }
1082
1083  $url_params = array('image_id' => $image_id);
1084
1085  // let's add links between the image and the categories
1086  if (isset($params['categories']))
1087  {
1088    ws_add_image_category_relations($image_id, $params['categories']);
1089
1090    if (preg_match('/^\d+/', $params['categories'], $matches))
1091    {
1092      $category_id = $matches[0];
1093
1094      $query = '
1095SELECT id, name, permalink
1096  FROM '. CATEGORIES_TABLE .'
1097  WHERE id = '. $category_id .'
1098;';
1099      $result = pwg_query($query);
1100      $category = pwg_db_fetch_assoc($result);
1101
1102      $url_params['section'] = 'categories';
1103      $url_params['category'] = $category;
1104    }
1105  }
1106
1107  // and now, let's create tag associations
1108  if (isset($params['tag_ids']) and !empty($params['tag_ids']))
1109  {
1110    set_tags(
1111      explode(',', $params['tag_ids']),
1112      $image_id
1113      );
1114  }
1115
1116  invalidate_user_cache();
1117
1118  return array(
1119    'image_id' => $image_id,
1120    'url' => make_picture_url($url_params),
1121    );
1122}
1123
1124/**
1125 * API method
1126 * Adds a image (simple way)
1127 * @param mixed[] $params
1128 *    @option int[] category
1129 *    @option string name (optional)
1130 *    @option string author (optional)
1131 *    @option string comment (optional)
1132 *    @option int level
1133 *    @option string|string[] tags
1134 *    @option int image_id (optional)
1135 */
1136function ws_images_addSimple($params, &$service)
1137{
1138  global $conf;
1139
1140  if (!isset($_FILES['image']))
1141  {
1142    return new PwgError(405, 'The image (file) is missing');
1143  }
1144
1145  if ($params['image_id'] > 0)
1146  {
1147    $query='
1148SELECT COUNT(*)
1149  FROM '. IMAGES_TABLE .'
1150  WHERE id = '. $params['image_id'] .'
1151;';
1152    list($count) = pwg_db_fetch_row(pwg_query($query));
1153    if ($count == 0)
1154    {
1155      return new PwgError(404, 'image_id not found');
1156    }
1157  }
1158
1159  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
1160
1161  $image_id = add_uploaded_file(
1162    $_FILES['image']['tmp_name'],
1163    $_FILES['image']['name'],
1164    $params['category'],
1165    8,
1166    $params['image_id'] > 0 ? $params['image_id'] : null
1167    );
1168
1169  $info_columns = array(
1170    'name',
1171    'author',
1172    'comment',
1173    'level',
1174    'date_creation',
1175    );
1176
1177  $update = array();
1178  foreach ($info_columns as $key)
1179  {
1180    if (isset($params[$key]))
1181    {
1182      $update[$key] = $params[$key];
1183    }
1184  }
1185
1186  single_update(
1187    IMAGES_TABLE,
1188    $update,
1189    array('id' => $image_id)
1190    );
1191
1192  if (isset($params['tags']) and !empty($params['tags']))
1193  {
1194    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1195
1196    $tag_ids = array();
1197    if (is_array($params['tags']))
1198    {
1199      foreach ($params['tags'] as $tag_name)
1200      {
1201        $tag_ids[] = tag_id_from_tag_name($tag_name);
1202      }
1203    }
1204    else
1205    {
1206      $tag_names = preg_split('~(?<!\\\),~', $params['tags']);
1207      foreach ($tag_names as $tag_name)
1208      {
1209        $tag_ids[] = tag_id_from_tag_name(preg_replace('#\\\\*,#', ',', $tag_name));
1210      }
1211    }
1212
1213    add_tags($tag_ids, array($image_id));
1214  }
1215
1216  $url_params = array('image_id' => $image_id);
1217
1218  if (!empty($params['category']))
1219  {
1220    $query = '
1221SELECT id, name, permalink
1222  FROM '. CATEGORIES_TABLE .'
1223  WHERE id = '. $params['category'][0] .'
1224;';
1225    $result = pwg_query($query);
1226    $category = pwg_db_fetch_assoc($result);
1227
1228    $url_params['section'] = 'categories';
1229    $url_params['category'] = $category;
1230  }
1231
1232  // update metadata from the uploaded file (exif/iptc), even if the sync
1233  // was already performed by add_uploaded_file().
1234  require_once(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
1235  sync_metadata(array($image_id));
1236
1237  return array(
1238    'image_id' => $image_id,
1239    'url' => make_picture_url($url_params),
1240    );
1241}
1242
1243/**
1244 * API method
1245 * Check if an image exists by it's name or md5 sum
1246 * @param mixed[] $params
1247 *    @option string md5sum_list (optional)
1248 *    @option string filename_list (optional)
1249 */
1250function ws_images_exist($params, &$service)
1251{
1252  ws_logfile(__FUNCTION__.' '.var_export($params, true));
1253
1254  global $conf;
1255
1256  $split_pattern = '/[\s,;\|]/';
1257  $result = array();
1258
1259  if ('md5sum' == $conf['uniqueness_mode'])
1260  {
1261    // search among photos the list of photos already added, based on md5sum list
1262    $md5sums = preg_split(
1263      $split_pattern,
1264      $params['md5sum_list'],
1265      -1,
1266      PREG_SPLIT_NO_EMPTY
1267    );
1268
1269    $query = '
1270SELECT id, md5sum
1271  FROM '. IMAGES_TABLE .'
1272  WHERE md5sum IN (\''. implode("','", $md5sums) .'\')
1273;';
1274    $id_of_md5 = simple_hash_from_query($query, 'md5sum', 'id');
1275
1276    foreach ($md5sums as $md5sum)
1277    {
1278      $result[$md5sum] = null;
1279      if (isset($id_of_md5[$md5sum]))
1280      {
1281        $result[$md5sum] = $id_of_md5[$md5sum];
1282      }
1283    }
1284  }
1285  else if ('filename' == $conf['uniqueness_mode'])
1286  {
1287    // search among photos the list of photos already added, based on
1288    // filename list
1289    $filenames = preg_split(
1290      $split_pattern,
1291      $params['filename_list'],
1292      -1,
1293      PREG_SPLIT_NO_EMPTY
1294    );
1295
1296    $query = '
1297SELECT id, file
1298  FROM '.IMAGES_TABLE.'
1299  WHERE file IN (\''. implode("','", $filenames) .'\')
1300;';
1301    $id_of_filename = simple_hash_from_query($query, 'file', 'id');
1302
1303    foreach ($filenames as $filename)
1304    {
1305      $result[$filename] = null;
1306      if (isset($id_of_filename[$filename]))
1307      {
1308        $result[$filename] = $id_of_filename[$filename];
1309      }
1310    }
1311  }
1312
1313  return $result;
1314}
1315
1316/**
1317 * API method
1318 * Check is file has been update
1319 * @param mixed[] $params
1320 *    @option int image_id
1321 *    @option string file_sum
1322 */
1323function ws_images_checkFiles($params, &$service)
1324{
1325  ws_logfile(__FUNCTION__.', input :  '.var_export($params, true));
1326
1327  $query = '
1328SELECT path
1329  FROM '. IMAGES_TABLE .'
1330  WHERE id = '. $params['image_id'] .'
1331;';
1332  $result = pwg_query($query);
1333
1334  if (pwg_db_num_rows($result) == 0)
1335  {
1336    return new PwgError(404, 'image_id not found');
1337  }
1338
1339  list($path) = pwg_db_fetch_row($result);
1340
1341  $ret = array();
1342
1343  if (isset($params['thumbnail_sum']))
1344  {
1345    // We always say the thumbnail is equal to create no reaction on the
1346    // other side. Since Piwigo 2.4 and derivatives, the thumbnails and web
1347    // sizes are always generated by Piwigo
1348    $ret['thumbnail'] = 'equals';
1349  }
1350
1351  if (isset($params['high_sum']))
1352  {
1353    $ret['file'] = 'equals';
1354    $compare_type = 'high';
1355  }
1356  else if (isset($params['file_sum']))
1357  {
1358    $compare_type = 'file';
1359  }
1360
1361  if (isset($compare_type))
1362  {
1363    ws_logfile(__FUNCTION__.', md5_file($path) = '.md5_file($path));
1364    if (md5_file($path) != $params[$compare_type.'_sum'])
1365    {
1366      $ret[$compare_type] = 'differs';
1367    }
1368    else
1369    {
1370      $ret[$compare_type] = 'equals';
1371    }
1372  }
1373
1374  ws_logfile(__FUNCTION__.', output :  '.var_export($ret, true));
1375
1376  return $ret;
1377}
1378
1379/**
1380 * API method
1381 * Sets details of an image
1382 * @param mixed[] $params
1383 *    @option int image_id
1384 *    @option string file (optional)
1385 *    @option string name (optional)
1386 *    @option string author (optional)
1387 *    @option string date_creation (optional)
1388 *    @option string comment (optional)
1389 *    @option string categories (optional) - "cat_id[,rank];cat_id[,rank]"
1390 *    @option string tags_ids (optional) - "tag_id,tag_id"
1391 *    @option int level (optional)
1392 *    @option string single_value_mode
1393 *    @option string multiple_value_mode
1394 */
1395function ws_images_setInfo($params, &$service)
1396{
1397  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1398
1399  $query='
1400SELECT *
1401  FROM '. IMAGES_TABLE .'
1402  WHERE id = '. $params['image_id'] .'
1403;';
1404  $result = pwg_query($query);
1405
1406  if (pwg_db_num_rows($result) == 0)
1407  {
1408    return new PwgError(404, 'image_id not found');
1409  }
1410
1411  $image_row = pwg_db_fetch_assoc($result);
1412
1413  // database registration
1414  $update = array();
1415
1416  $info_columns = array(
1417    'name',
1418    'author',
1419    'comment',
1420    'level',
1421    'date_creation',
1422    );
1423
1424  foreach ($info_columns as $key)
1425  {
1426    if (isset($params[$key]))
1427    {
1428      if ('fill_if_empty' == $params['single_value_mode'])
1429      {
1430        if (empty($image_row[$key]))
1431        {
1432          $update[$key] = $params[$key];
1433        }
1434      }
1435      elseif ('replace' == $params['single_value_mode'])
1436      {
1437        $update[$key] = $params[$key];
1438      }
1439      else
1440      {
1441        return new PwgError(500,
1442          '[ws_images_setInfo]'
1443          .' invalid parameter single_value_mode "'.$params['single_value_mode'].'"'
1444          .', possible values are {fill_if_empty, replace}.'
1445          );
1446      }
1447    }
1448  }
1449
1450  if (isset($params['file']))
1451  {
1452    if (!empty($image_row['storage_category_id']))
1453    {
1454      return new PwgError(500,
1455        '[ws_images_setInfo] updating "file" is forbidden on photos added by synchronization'
1456        );
1457    }
1458
1459    $update['file'] = $params['file'];
1460  }
1461
1462  if (count(array_keys($update)) > 0)
1463  {
1464    $update['id'] = $params['image_id'];
1465
1466    single_update(
1467      IMAGES_TABLE,
1468      $update,
1469      array('id' => $update['id'])
1470      );
1471  }
1472
1473  if (isset($params['categories']))
1474  {
1475    ws_add_image_category_relations(
1476      $params['image_id'],
1477      $params['categories'],
1478      ('replace' == $params['multiple_value_mode'] ? true : false)
1479      );
1480  }
1481
1482  // and now, let's create tag associations
1483  if (isset($params['tag_ids']))
1484  {
1485    $tag_ids = array();
1486
1487    foreach (explode(',', $params['tag_ids']) as $candidate)
1488    {
1489      $candidate = trim($candidate);
1490
1491      if (preg_match(PATTERN_ID, $candidate))
1492      {
1493        $tag_ids[] = $candidate;
1494      }
1495    }
1496
1497    if ('replace' == $params['multiple_value_mode'])
1498    {
1499      set_tags(
1500        $tag_ids,
1501        $params['image_id']
1502        );
1503    }
1504    elseif ('append' == $params['multiple_value_mode'])
1505    {
1506      add_tags(
1507        $tag_ids,
1508        array($params['image_id'])
1509        );
1510    }
1511    else
1512    {
1513      return new PwgError(500,
1514        '[ws_images_setInfo]'
1515        .' invalid parameter multiple_value_mode "'.$params['multiple_value_mode'].'"'
1516        .', possible values are {replace, append}.'
1517        );
1518    }
1519  }
1520
1521  invalidate_user_cache();
1522}
1523
1524/**
1525 * API method
1526 * Deletes an image
1527 * @param mixed[] $params
1528 *    @option int|int[] image_id
1529 *    @option string pwg_token
1530 */
1531function ws_images_delete($params, &$service)
1532{
1533  if (get_pwg_token() != $params['pwg_token'])
1534  {
1535    return new PwgError(403, 'Invalid security token');
1536  }
1537
1538  if (!is_array($params['image_id']))
1539  {
1540    $params['image_id'] = preg_split(
1541      '/[\s,;\|]/',
1542      $params['image_id'],
1543      -1,
1544      PREG_SPLIT_NO_EMPTY
1545      );
1546  }
1547  $params['image_id'] = array_map('intval', $params['image_id']);
1548
1549  $image_ids = array();
1550  foreach ($params['image_id'] as $image_id)
1551  {
1552    if ($image_id > 0)
1553    {
1554      $image_ids[] = $image_id;
1555    }
1556  }
1557
1558  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
1559  delete_elements($image_ids, true);
1560  invalidate_user_cache();
1561}
1562
1563/**
1564 * API method
1565 * Checks if Piwigo is ready for upload
1566 * @param mixed[] $params
1567 */
1568function ws_images_checkUpload($params, &$service)
1569{
1570  include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
1571
1572  $ret['message'] = ready_for_upload_message();
1573  $ret['ready_for_upload'] = true;
1574  if (!empty($ret['message']))
1575  {
1576    $ret['ready_for_upload'] = false;
1577  }
1578
1579  return $ret;
1580}
1581
1582?>
Note: See TracBrowser for help on using the repository browser.