forked from horde/horde
/
Storage.php
1400 lines (1290 loc) · 48.8 KB
/
Storage.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/**
* See the enclosed file COPYING for license information (GPL). If you
* did not receive this file, see http://www.horde.org/licenses/gpl.
*
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @category Horde
* @license http://www.horde.org/licenses/gpl GPL
* @package Ansel
*/
/**
* Class for interfacing with back end data storage.
*
* Copyright 2001-2014 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (GPL). If you
* did not receive this file, see http://www.horde.org/licenses/gpl.
*
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @category Horde
* @license http://www.horde.org/licenses/gpl GPL
* @package Ansel
*/
class Ansel_Storage
{
/**
* database handle
*
* @var Horde_Db_Adapter
*/
protected $_db;
/**
* The Horde_Shares object to use for this scope.
*
* @var Horde_Share
*/
protected $_shares;
/**
* Local cache of retrieved images
*
* @var array
*/
protected $_images = array();
/**
* Const'r
*
* @param Horde_Core_Share_Driver The share object
*
* @return Ansel_Storage
*/
public function __construct(Horde_Core_Share_Driver $shareOb)
{
$this->_shares = $shareOb;
}
/**
* Property accessor
*
* @param string $property The property to access.
*/
public function __get($property)
{
switch ($property) {
case 'shares':
return $this->{'_' . $property};
default: // Just for now until everything is refactored.
return null;
}
}
/**
* Backend setter
*
* @param mixed $storage The backend storage driver.
*/
public function setStorage($storage)
{
$this->_db = $storage;
}
/**
* Create and initialise a new gallery object.
*
* @param array $attributes The gallery attributes.
* @param Horde_Perms_Permission $perm The permissions for the gallery if
* the defaults are not desirable.
* @param integer $parent The id of the parent gallery (if any)
*
* @return Ansel_Gallery A new gallery object.
* @throws Ansel_Exception
*/
public function createGallery(array $attributes = array(),
Horde_Perms_Permission $perm = null,
$parent = null)
{
// Required values.
if (empty($attributes['owner'])) {
$attributes['owner'] = $GLOBALS['registry']->getAuth();
}
if (empty($attributes['name'])) {
$attributes['name'] = _("Unnamed");
}
if (empty($attributes['desc'])) {
$attributes['desc'] = '';
}
// Default values
$attributes['default_type'] = isset($attributes['default_type']) ?
$attributes['default_type'] :
'auto';
$attributes['default'] = isset($attributes['default']) ?
(int)$attributes['default'] :
0;
$attributes['default_prettythumb'] = isset($attributes['default_prettythumb']) ?
$attributes['default_prettythumb'] :
'';
// No value for style now means to use the 'default_ansel' style as
// defined in styles.php
$attributes['style'] = isset($attributes['style']) ? $attributes['style'] : '';
$attributes['date_created'] = time();
$attributes['last_modified'] = $attributes['date_created'];
$attributes['images'] = isset($attributes['images']) ?
(int)$attributes['images'] :
0;
$attributes['slug'] = isset($attributes['slug']) ? $attributes['slug'] : '';
$attributes['age'] = isset($attributes['age']) ? (int)$attributes['age'] : 0;
$attributes['download'] = isset($attributes['download']) ?
$attributes['download'] :
$GLOBALS['prefs']->getValue('default_download');
$attributes['view_mode'] = isset($attributes['view_mode']) ?
$attributes['view_mode'] :
'Normal';
$attributes['passwd'] = isset($attributes['passwd']) ?
$attributes['passwd'] :
'';
// Don't pass tags to the share creation method.
if (isset($attributes['tags'])) {
$tags = $attributes['tags'];
unset($attributes['tags']);
} else {
$tags = array();
}
// Check for slug uniqueness
if (!empty($attributes['slug']) &&
$this->galleryExists(null, $attributes['slug'])) {
throw new Ansel_Exception(
sprintf(_("The slug \"%s\" already exists."), $attributes['slug']));
}
// Create the gallery's share, and then the gallery.
try {
$gallery_share = $this->_shares->newShare(
$GLOBALS['registry']->getAuth(),
strval(new Horde_Support_Randomid()),
$attributes['name']);
} catch (Horde_Share_Exception $e) {
Horde::log($e->getMessage, 'ERR');
throw new Ansel_Exception($e);
}
$gallery = $this->buildGallery($gallery_share);
// Set the gallery's parent if needed, and clear the parent's cache
if (!is_null($parent)) {
$gallery->setParent($parent);
if ($GLOBALS['conf']['ansel_cache']['usecache']) {
$GLOBALS['injector']->getInstance('Horde_Cache')
->expire('Ansel_Gallery' . $parent);
}
}
// Fill up the new gallery
foreach ($attributes as $key => $value) {
if ($key != 'name') {
$gallery->set($key, $value);
}
}
// Save it to storage
try {
$result = $this->_shares->addShare($gallery_share);
} catch (Horde_Share_Exception $e) {
$error = sprintf(_("The gallery \"%s\" could not be created: %s"),
$attributes['name'], $e->getMessage());
Horde::log($error, 'ERR');
throw new Ansel_Exception($error);
}
// Add default permissions.
if (empty($perm)) {
$perm = $gallery->getPermission();
// Default permissions for logged in users
switch ($GLOBALS['prefs']->getValue('default_permissions')) {
case 'read':
$perms = Horde_Perms::SHOW | Horde_Perms::READ;
break;
case 'edit':
$perms = Horde_Perms::SHOW | Horde_Perms::READ | Horde_Perms::EDIT;
break;
case 'none':
$perms = 0;
break;
}
$perm->addDefaultPermission($perms, false);
// Default guest permissions
switch ($GLOBALS['prefs']->getValue('guest_permissions')) {
case 'read':
$perms = Horde_Perms::SHOW | Horde_Perms::READ;
break;
case 'none':
default:
$perms = 0;
break;
}
$perm->addGuestPermission($perms, false);
// Default user groups permissions
switch ($GLOBALS['prefs']->getValue('group_permissions')) {
case 'read':
$perms = Horde_Perms::SHOW | Horde_Perms::READ;
break;
case 'edit':
$perms = Horde_Perms::SHOW | Horde_Perms::READ | Horde_Perms::EDIT;
break;
case 'delete':
$perms = Horde_Perms::SHOW | Horde_Perms::READ | Horde_Perms::EDIT | Horde_Perms::DELETE;
break;
case 'none':
default:
$perms = 0;
break;
}
if ($perms) {
$group_list = $GLOBALS['injector']
->getInstance('Horde_Group')
->listGroups($GLOBALS['registry']->getAuth());
if (count($group_list)) {
foreach ($group_list as $group_id => $group_name) {
$perm->addGroupPermission($group_id, $perms, false);
}
}
}
}
$gallery->setPermission($perm);
// Initial tags
if (count($tags)) {
$gallery->setTags($tags);
}
return $gallery;
}
/**
* Retrieve an Ansel_Gallery given the gallery's slug
*
* @param string $slug The gallery slug
* @param array $overrides An array of attributes that should be overridden
* when the gallery is returned.
*
* @return Ansel_Gallery The gallery object
* @throws Horde_Exception_NotFound
*/
public function getGalleryBySlug($slug, array $overrides = array())
{
$shares = $this->buildGalleries(
$this->_shares->listShares(
$GLOBALS['registry']->getAuth(),
array('attributes' => array('slug' => $slug))));
if (!count($shares)) {
throw new Horde_Exception_NotFound(sprintf(_("Gallery %s not found."), $slug));
}
return current($shares);
}
/**
* Retrieve an Ansel_Gallery given the share id
*
* @param integer $gallery_id The gallery_id to fetch
* @param array $overrides An array of attributes that should be
* overridden when the gallery is returned.
*
* @return Ansel_Gallery
* @throws Ansel_Exception
*/
public function getGallery($gallery_id, array $overrides = array())
{
if (!count($overrides) && $GLOBALS['conf']['ansel_cache']['usecache'] &&
($gallery = $GLOBALS['injector']->getInstance('Horde_Cache')->get('Ansel_Gallery' . $gallery_id, $GLOBALS['conf']['cache']['default_lifetime'])) !== false) {
if ($cached_gallery = unserialize($gallery)) {
return $cached_gallery;
}
}
try {
$result = $this->buildGallery($this->_shares->getShareById($gallery_id));
} catch (Horde_Share_Exception $e) {
throw new Ansel_Exception($e);
} catch (Horde_Exception_NotFound $e) {
throw new Ansel_Exception($e);
}
// Don't cache if we have overridden anything
if (!count($overrides)) {
if ($GLOBALS['conf']['ansel_cache']['usecache']) {
$GLOBALS['injector']->getInstance('Horde_Cache')
->set('Ansel_Gallery' . $gallery_id, serialize($result));
}
} else {
foreach ($overrides as $key => $value) {
$result->set($key, $value, false);
}
}
return $result;
}
/**
* Retrieve an array of Ansel_Gallery objects for the given slugs.
*
* @param array $slugs The gallery slugs.
*
* @return array An array of Ansel_Gallery objects.
* @throws Ansel_Exception
*/
public function getGalleriesBySlugs(array $slugs, $perms = Horde_Perms::SHOW)
{
try {
return $this->buildGalleries(
$this->_shares->listShares(
$GLOBALS['registry']->getAuth(),
array(
'perm' => $perms,
'attribtues' => array('slugs' => $slugs))));
} catch (Horde_Share_Exception $e) {
throw new Ansel_Exception($e);
} catch (Horde_Exception_NotFound $e) {
throw new Ansel_Exception($e);
}
}
/**
* Retrieve an array of Ansel_Gallery objects for the requested ids
*
* @param array $ids Gallery ids to fetch
* @param integer $perms Horde_Perms constant for the perms required.
*
* @return array An array of Ansel_Gallery objects
* @throws Ansel_Exception
*/
public function getGalleries(array $ids, $perms = Horde_Perms::SHOW)
{
try {
$shares = $this->buildGalleries($this->_shares->getShares($ids));
} catch (Horde_Share_Exception $e) {
throw new Ansel_Exception($e);
} catch (Horde_Exception_NotFound $e) {
throw new Ansel_Exception($e);
}
$galleries = array();
foreach ($shares as $gallery) {
if ($gallery->hasPermission($GLOBALS['registry']->getAuth(), $perms)) {
$galleries[] = $gallery;
}
}
return $galleries;
}
/**
* Empties a gallery of all images.
*
* @param Ansel_Gallery $gallery The ansel gallery to empty.
*
* @throws Ansel_Exception
*/
public function emptyGallery(Ansel_Gallery $gallery)
{
$gallery->clearStacks();
$images = $gallery->listImages();
foreach ($images as $image) {
// Pretend we are a stack so we don't update the images count
// for every image deletion, since we know the end result will
// be zero.
try {
$gallery->removeImage($image, true);
} catch (Horde_Exception_NotFound $e) {
throw new Ansel_Exception($e);
}
}
$gallery->set('images', 0, true);
// Clear the OtherGalleries widget cache
if ($GLOBALS['conf']['ansel_cache']['usecache']) {
$GLOBALS['injector']
->getInstance('Horde_Cache')
->expire('Ansel_OtherGalleries' . $gallery->get('owner'));
$GLOBALS['injector']
->getInstance('Horde_Cache')
->expire('Ansel_Gallery' . $gallery->id);
}
}
/**
* Removes an Ansel_Gallery.
*
* @param Ansel_Gallery $gallery The gallery to delete
*
* @throws Ansel_Exception
*/
public function removeGallery(Ansel_Gallery $gallery)
{
// Get any children and empty them
$children = $gallery->getChildren(null, null, true);
foreach ($children as $child) {
$this->emptyGallery($child);
$child->setTags(array());
}
// Now empty the selected gallery of images
$this->emptyGallery($gallery);
// Clear all the tags.
$gallery->setTags(array());
// Get the parent, if it exists, before we delete the gallery.
$parent = $gallery->getParent();
$id = $gallery->id;
// Delete the gallery from storage
try {
$this->_shares->removeShare($gallery->getShare());
} catch (Horde_Share_Exception $e) {
throw new Ansel_Exception($e);
} catch (Horde_Exception_NotFound $e) {
throw new Ansel_Exception($e);
}
// Expire the cache
if ($GLOBALS['conf']['ansel_cache']['usecache']) {
$GLOBALS['injector']->getInstance('Horde_Cache')
->expire('Ansel_Gallery' . $id);
}
// See if we need to clear the has_subgalleries field
if ($parent instanceof Ansel_Gallery) {
if (!$parent->countChildren($GLOBALS['registry']->getAuth(), Horde_Perms::SHOW, false)) {
$parent->set('has_subgalleries', 0, true);
if ($GLOBALS['conf']['ansel_cache']['usecache']) {
$GLOBALS['injector']
->getInstance('Horde_Cache')
->expire('Ansel_Gallery' . $parent->id);
}
}
}
}
/**
* Returns the image corresponding to the given id.
*
* @param integer $id The image_id of the image to retrieve.
*
* @return Ansel_Image The image object requested..
* @throws Ansel_Exception, Horde_Exception_NotFound
*/
public function &getImage($id)
{
if (isset($this->_images[$id])) {
return $this->_images[$id];
}
$q = 'SELECT ' . $this->_getImageFields()
. ' FROM ansel_images WHERE image_id = ?';
try {
$image = $this->_db->selectOne($q, array((int)$id));
} catch (Horde_Db_Exception $e) {
throw new Ansel_Exception($e);
}
if (!$image) {
throw new Horde_Exception_NotFound(_("Photo not found"));
} else {
$image['image_filename'] = Horde_String::convertCharset(
$image['image_filename'],
$GLOBALS['conf']['sql']['charset'],
'UTF-8');
$image['image_caption'] = Horde_String::convertCharset(
$image['image_caption'],
$GLOBALS['conf']['sql']['charset'],
'UTF-8');
$this->_images[$id] = new Ansel_Image($image);
return $this->_images[$id];
}
}
/**
* Save image details to storage. Does NOT update the cached image files.
*
* @param Ansel_Image $image The image to save.
*
* @return integer The image id
* @throws Ansel_Exception
*/
public function saveImage(Ansel_Image $image)
{
// If we have an id, then it's an existing image.
if ($image->id) {
$update = 'UPDATE ansel_images SET image_filename = ?, '
. 'image_type = ?, image_caption = ?, image_sort = ?, '
. 'image_original_date = ?, image_latitude = ?, '
. 'image_longitude = ?, image_location = ?, '
. 'image_geotag_date = ? WHERE image_id = ?';
try {
return $this->_db->update(
$update,
array(Horde_String::convertCharset($image->filename, 'UTF-8', $GLOBALS['conf']['sql']['charset']),
$image->type,
Horde_String::convertCharset($image->caption, 'UTF-8', $GLOBALS['conf']['sql']['charset']),
$image->sort,
$image->originalDate,
$image->lat,
$image->lng,
$image->location,
$image->geotag_timestamp,
$image->id));
} catch (Horde_Db_Exception $e) {
throw new Ansel_Exception($e);
}
}
// Saving a new Image
if (!$image->gallery || !strlen($image->filename) || !$image->type) {
throw new Ansel_Exception('Incomplete photo');
}
// Prepare the SQL statement
$insert = 'INSERT INTO ansel_images (gallery_id, image_filename, '
. 'image_type, image_caption, image_uploaded_date, image_sort, '
. 'image_original_date, image_latitude, image_longitude, '
. 'image_location, image_geotag_date) VALUES '
. '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
try {
$image->id = $this->_db->insert(
$insert,
array($image->gallery,
Horde_String::convertCharset(
$image->filename,
'UTF-8',
$GLOBALS['conf']['sql']['charset']),
$image->type,
Horde_String::convertCharset(
$image->caption,
'UTF-8',
$GLOBALS['conf']['sql']['charset']),
$image->uploaded,
$image->sort,
$image->originalDate,
$image->lat,
$image->lng,
$image->location,
(empty($image->lat) ? 0 : $image->uploaded)));
} catch (Horde_Db_Exception $e) {
throw new Ansel_Exception($e);
}
return $image->id;
}
/**
* Store an image attribute to storage
*
* @param integer $image_id The image id
* @param string $attributes The attribute name
* @param string $value The attrbute value
*
* @throws Ansel_Exception
*/
public function saveImageAttribute($image_id, $attribute, $value)
{
try {
$this->_db->insert(
'INSERT INTO ansel_image_attributes '
. '(image_id, attr_name, attr_value) VALUES (?, ?, ?)',
array(
$image_id,
$attribute,
Horde_String::convertCharset($value, 'UTF-8', $GLOBALS['conf']['sql']['charset'])));
} catch (Horde_Db_Exception $e) {
throw new Ansel_Exception($e);
}
}
/**
* Clears an image's attributes from storage.
*
* @param integer $image_id The image to clear
*
* @throws Ansel_Exception
*/
public function clearImageAttributes($image_id)
{
try {
$this->_db->delete('DELETE FROM ansel_image_attributes WHERE image_id = ' . (int)$image_id);
} catch (Horde_Db_Exception $e) {
throw new Ansel_Exception($e);
}
}
/**
* Get image's attribtues from storage
*
* @param int $image_id The image id
*
* @return array A image attribute hash
* @throws Horde_Exception
*/
public function getImageAttributes($image_id)
{
try {
return $this->_db->selectAssoc(
'SELECT attr_name, attr_value FROM ansel_image_attributes WHERE '
. ' image_id = ' . (int)$image_id);
} catch (Horde_Db_Exception $e) {
throw new Ansel_Exception($e);
}
}
/**
* Set image sort order
*
* @param integer $imageId The image id
* @param integer $pos The new sort order position
*
* @throws Ansel_Exception
*/
public function setImageSortOrder($imageId, $pos)
{
try {
$this->_db->update(
'UPDATE ansel_images SET image_sort = '
. (int)$pos . ' WHERE image_id = ' . (int)$imageId);
} catch (Horde_Db_Exception $e) {
Horde::log($e->getMessage(), 'ERR');
throw new Ansel_Exception($e);
}
}
/**
* Return the images corresponding to the given ids.
*
* @param array $params function parameters:
* <pre>
* 'ids' - An array of image ids to fetch.
* 'preserve' - Preserve the order of the image ids when returned.
* 'gallery_id' - Return all images from requested gallery (ignores 'ids').
* 'from' - If passing a gallery, start at this image.
* 'count' - If passing a gallery, return this many images.
* </pre>
*
* @return array An array of Ansel_Image objects.
* @throws Ansel_Exception, Horde_Exception_NotFound, InvalidArgumentException
*/
public function getImages(array $params = array())
{
// First check if we want a specific gallery or a list of images
if (!empty($params['gallery_id'])) {
$sql = 'SELECT ' . $this->_getImageFields()
. ' FROM ansel_images WHERE gallery_id = '
. $params['gallery_id'] . ' ORDER BY image_sort';
} elseif (!empty($params['ids']) && is_array($params['ids']) && count($params['ids']) > 0) {
$sql = 'SELECT ' . $this->_getImageFields() . ' FROM ansel_images WHERE image_id IN (';
$i = 1;
$cnt = count($params['ids']);
foreach ($params['ids'] as $id) {
$sql .= (int)$id . (($i++ < $cnt) ? ',' : ');');
}
} else {
throw new InvalidArgumentException('Ansel_Storage::getImages requires either a gallery_id or an array of image ids');
}
// Limit the query?
if (isset($params['count']) && isset($params['from'])) {
$sql = $this->_db->addLimitOffset($sql, array('limit' => $params['count'], 'offset' => $params['from']));
}
try {
$images = $this->_db->select($sql);
} catch (Horde_Db_Exception $e) {
throw new Ansel_Exception($images);
}
// Throw exception if we asked for specific image ids and not found.
if (empty($images) && empty($params['gallery_id'])) {
throw new Horde_Exception_NotFound(_("Images not found"));
} elseif (empty($images)) {
return array();
}
$return = array();
foreach ($images as $image) {
$image['image_filename'] = Horde_String::convertCharset($image['image_filename'], $GLOBALS['conf']['sql']['charset'], 'UTF-8');
$image['image_caption'] = Horde_String::convertCharset($image['image_caption'], $GLOBALS['conf']['sql']['charset'], 'UTF-8');
$return[$image['image_id']] = new Ansel_Image($image);
$this->_images[(int)$image['image_id']] = &$return[$image['image_id']];
}
// Need to get comment counts if comments are enabled
$ccounts = $this->_getImageCommentCounts(array_keys($return));
if (count($ccounts)) {
foreach ($return as $key => $image) {
$return[$key]->commentCount = (!empty($ccounts[$key]) ? $ccounts[$key] : 0);
}
}
// Preserve the order the images_ids were passed in
if (empty($params['gallery_id']) && !empty($params['preserve'])) {
foreach ($params['ids'] as $id) {
$ordered[$id] = $return[$id];
}
return $ordered;
}
return $return;
}
/**
* Get the total number of comments for an image.
*
* @param array $ids Array of image ids
*
* @return array of results. @see forums/numMessagesBatch api call
*/
protected function _getImageCommentCounts(array $ids)
{
global $conf, $registry;
// Need to get comment counts if comments are enabled
if (($conf['comments']['allow'] == 'all' || ($conf['comments']['allow'] == 'authenticated' && $GLOBALS['registry']->getAuth())) &&
$registry->hasMethod('forums/numMessagesBatch')) {
return $registry->call('forums/numMessagesBatch', array($ids, 'ansel'));
}
return array();
}
/**
* Returns a list of Ansel_Images of the most recently added images for the
* current user.
*
* @param array $galleries An array of gallery ids to search in. If
* left empty, will search all galleries
* with Horde_Perms::SHOW.
* @param integer $limit The maximum number of images to return
* @param string $slugs An array of gallery slugs.
* @param string $where Additional where clause
*
* @return array An array of Ansel_Image objects
* @throws Ansel_Exception
*/
public function getRecentImages(array $galleries = array(), $limit = 10, array $slugs = array())
{
$results = array();
if (!count($galleries) && !count($slugs)) {
// Don't need the Ansel_Gallery object, so save some resources and
// only query the share system.
foreach ($this->_shares->listShares($GLOBALS['registry']->getAuth()) as $share) {
$galleries[] = $share->getId();
}
if (empty($galleries)) {
return array();
}
}
if (!count($slugs)) {
// Searching by gallery_id
$sql = 'SELECT ' . $this->_getImageFields() . ' FROM ansel_images '
. 'WHERE gallery_id IN ('
. str_repeat('?, ', count($galleries) - 1) . '?) ';
$criteria = $galleries;
} elseif (count($slugs)) {
// Searching by gallery_slug so we need to join the share table
$sql = 'SELECT ' . $this->_getImageFields() . ' FROM ansel_images LEFT JOIN '
. $this->_shares->getTable() . ' ON ansel_images.gallery_id = '
. $this->_shares->getTable() . '.share_id ' . 'WHERE attribute_slug IN ('
. str_repeat('?, ', count($slugs) - 1) . '?) ';
$criteria = $slugs;
}
$sql .= ' ORDER BY image_uploaded_date DESC';
if ($limit > 0) {
$sql = $this->_db->addLimitOffset($sql, array('limit' => (int)$limit));
}
try {
$images = $this->_db->selectAll($sql, $criteria);
} catch (Horde_Db_Exception $e) {
throw new Ansel_Exception($e);
}
foreach($images as $image) {
$image['image_filename'] = Horde_String::convertCharset($image['image_filename'], $GLOBALS['conf']['sql']['charset'], 'UTF-8');
$image['image_caption'] = Horde_String::convertCharset($image['image_caption'], $GLOBALS['conf']['sql']['charset'], 'UTF-8');
$results[] = new Ansel_Image($image);
}
return $results;
}
/**
* Check if a gallery exists. Need to do this here so we can also check by
* gallery slug.
*
* @param integer $gallery_id The gallery id
* @param string $slug The gallery slug
*
* @return boolean
* @throws Ansel_Exception
*/
public function galleryExists($gallery_id = null, $slug = null)
{
if (empty($slug)) {
$results = $this->_shares->idExists($gallery_id);
} else {
$results = $this->_shares->countShares($GLOBALS['registry']->getAuth(), Horde_Perms::READ, array('slug' => $slug));
}
return (bool)$results;
}
/**
* Return the count of galleries that the user has specified permissions to
* and that match any of the requested attributes.
*
* @param string userid The user to check access for.
* @param array $params Parameter array:
*<pre>
* (integer)perm The level of permissions to require for a
* gallery to return it [Horde_Perms::SHOW]
* (mixed)attributes Restrict the galleries counted to those
* matching $attributes. An array of
* attribute/values pairs or a gallery owner
* username.
* (Ansel_Gallery)parent The parent share to start counting at.
* (boolean)all_levels Return all levels, or just the direct children of
* $parent? [true]
* (array)tags Filter results by galleries tagged with tags.
*</pre>
*
* @return integer The count
* @throws Ansel_Exception
*/
public function countGalleries($userid, array $params = array())
{
static $counts;
$oparams = new Horde_Support_Array($params);
if ($oparams->parent) {
$parent_id = $oparams->parent->id;
} else {
$parent_id = null;
}
$perm = $oparams->get('perm', Horde_Perms::SHOW);
$key = "$userid,$perm,$parent_id,{$oparams->all_levels}" . serialize($oparams->get('attributes', array())) . serialize($oparams->get('tags', array()));
if (isset($counts[$key])) {
return $counts[$key];
}
// Unfortunately, we need to go the long way around to count shares if
// we are filtering by tags.
if ($oparams->tags) {
$count = count($this->listGalleries($params));
} else {
try {
$count = $this->_shares->countShares(
$userid,
$perm, $oparams->get('attributes', array()),
$parent_id,
$oparams->get('all_levels', true));
} catch (Horde_Share_Exception $e) {
throw new Ansel_Exception($e);
}
}
$counts[$key] = $count;
return $count;
}
/**
* Retrieves the current user's gallery list from storage.
*
* @param array $params Optional parameters:
* <pre>
* (integer)perm The permissions filter to use [Horde_Perms::SHOW]
* (mixed)attributes Restrict the galleries returned to those matching
* the filters. Can be an array of attribute/values
* pairs or a gallery owner username.
* (integer)parent The parent share to start listing at.
* (boolean)all_levels If set, return all levels below parent, not just
* direct children [TRUE]
* (integer)from The gallery to start listing at.
* (integer)count The number of galleries to return.
* (string)sort_by Attribute to sort by.
* (integer)direction The direction to sort by [Ansel::SORT_ASCENDING]
* (array)tags An array of tags to limit results by.
* </pre>
*
* @return array An array of Ansel_Gallery objects
* @throws Ansel_Exception
*/
public function listGalleries($params = array())
{
$galleries = array();
try {
if (!empty($params['tags'])) {
$count = !empty($params['count']) ? $params['count'] : null;
$from = !empty($params['from']) ? $params['from'] : null;
unset($params['count'], $params['from']);
$shares = $this->_shares->listShares($GLOBALS['registry']->getAuth(), $params);
if (!empty($params['attributes']) && !is_array($params['attributes'])) {
$user = $params['attributes'];
} elseif (!empty($params['attributes']['owner'])) {
$user = $params['attributes']['owner'];
} else {
$user = null;
}
$tagged = $GLOBALS['injector']
->getInstance('Ansel_Tagger')
->search(
$params['tags'],
array(
'type' => 'gallery',
'user' => $user));
foreach ($shares as $share) {
if (in_array($share->getId(), $tagged['galleries'])) {
$galleries[] = $share;
}
}
$galleries = array_slice($galleries, $from, $count);
} else {
$galleries = $this->_shares->listShares($GLOBALS['registry']->getAuth(), $params);
}
$shares = $this->buildGalleries($galleries);
} catch (Horde_Share_Exception $e) {
throw new Ansel_Exception($e);
}
return $shares;
}
/**
* Returns a list of ALL galleries, regardless of permissions.
*
* @return array
*/
public function listAllGalleries()
{
return $this->buildGalleries($this->_shares->listAllShares());
}
/**
* Retrieve json data for an arbitrary list of image ids, not necessarily
* from the same gallery.
*
* @param array $images An array of image ids
* @param Ansel_Style $style A gallery style to force if requesting
* pretty thumbs.
* @param boolean $full Generate full urls
* @param string $image_view Which image view to use? screen, thumb etc..
* @param boolean $view_links Include links to the image view
*
* @return string The json data
*/
public function getImageJson(array $images, Ansel_Style $style = null,
$full = false, $image_view = 'mini', $view_links = false)
{
$galleries = array();
if (is_null($style)) {
$style = Ansel::getStyleDefinition('ansel_default');
}
$json = array();
foreach ($images as $id) {
$image = $this->getImage($id);
$gallery_id = abs($image->gallery);
if (empty($galleries[$gallery_id])) {
$galleries[$gallery_id]['gallery'] = $GLOBALS['injector']->getInstance('Ansel_Storage')->getGallery($gallery_id);
}