Overview

Packages

  • Ansel
  • None

Classes

  • Ansel
  • Ansel_Ajax_Application
  • Ansel_Ajax_Imple_EditCaption
  • Ansel_Ajax_Imple_EditFaces
  • Ansel_Ajax_Imple_EditGalleryFaces
  • Ansel_Ajax_Imple_Embed
  • Ansel_Ajax_Imple_GallerySlugCheck
  • Ansel_Ajax_Imple_ImageSaveGeotag
  • Ansel_Ajax_Imple_LocationAutoCompleter
  • Ansel_Ajax_Imple_MapLayerSelect
  • Ansel_Ajax_Imple_TagActions
  • Ansel_Ajax_Imple_ToggleGalleryActions
  • Ansel_Ajax_Imple_ToggleOtherGalleries
  • Ansel_Ajax_Imple_UploadNotification
  • Ansel_Api
  • Ansel_Exception
  • Ansel_Faces
  • Ansel_Faces_Base
  • Ansel_Faces_Facedetect
  • Ansel_Faces_User
  • Ansel_Factory_Faces
  • Ansel_Factory_Storage
  • Ansel_Factory_Styles
  • Ansel_Form_Ecard
  • Ansel_Form_Image
  • Ansel_Form_ImageDate
  • Ansel_Form_Upload
  • Ansel_Gallery
  • Ansel_Gallery_Decorator_Date
  • Ansel_GalleryMode_Base
  • Ansel_GalleryMode_Date
  • Ansel_GalleryMode_Normal
  • Ansel_Image
  • Ansel_ImageGenerator
  • Ansel_ImageGenerator_Mini
  • Ansel_ImageGenerator_PolaroidThumb
  • Ansel_ImageGenerator_PolaroidThumbStack
  • Ansel_ImageGenerator_RoundedThumb
  • Ansel_ImageGenerator_RoundedThumbStack
  • Ansel_ImageGenerator_Screen
  • Ansel_ImageGenerator_ShadowThumb
  • Ansel_ImageGenerator_ShadowThumbStack
  • Ansel_ImageGenerator_SquareThumb
  • Ansel_ImageGenerator_Thumb
  • Ansel_LoginTasks_SystemTask_Upgrade
  • Ansel_Report
  • Ansel_Report_letter
  • Ansel_Report_mail
  • Ansel_Report_tickets
  • Ansel_Search
  • Ansel_Search_exif
  • Ansel_Search_Tag
  • Ansel_Storage
  • Ansel_Style
  • Ansel_Tagger
  • Ansel_Test
  • Ansel_Tile_DateGallery
  • Ansel_Tile_Gallery
  • Ansel_Tile_Image
  • Ansel_View_Ansel
  • Ansel_View_Base
  • Ansel_View_EmbeddedRenderer_GalleryLink
  • Ansel_View_EmbeddedRenderer_Mini
  • Ansel_View_EmbeddedRenderer_Slideshow
  • Ansel_View_Gallery
  • Ansel_View_GalleryProperties
  • Ansel_View_GalleryRenderer_Base
  • Ansel_View_GalleryRenderer_Gallery
  • Ansel_View_GalleryRenderer_GalleryLightbox
  • Ansel_View_Image
  • Ansel_View_List
  • Ansel_View_Results
  • Ansel_View_Slideshow
  • Ansel_View_Upload
  • Ansel_Widget
  • Ansel_Widget_Actions
  • Ansel_Widget_Base
  • Ansel_Widget_GalleryFaces
  • Ansel_Widget_Geotag
  • Ansel_Widget_ImageFaces
  • Ansel_Widget_Links
  • Ansel_Widget_OtherGalleries
  • Ansel_Widget_OwnerFaces
  • Ansel_Widget_SimilarPhotos
  • Ansel_Widget_Tags
  • Ansel_XPPublisher
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: /**
   3:  * Ansel external API interface.
   4:  *
   5:  * Copyright 2004-2012 Horde LLC (http://www.horde.org/)
   6:  *
   7:  * See the enclosed file COPYING for license information (GPL). If you
   8:  * did not receive this file, see http://www.horde.org/licenses/gpl.
   9:  *
  10:  * @author  Jan Schneider <jan@horde.org>
  11:  * @author  Chuck Hagenbuch <chuck@horde.org>
  12:  * @author  Michael J. Rubinsky <mrubinsk@horde.org>
  13:  * @package Ansel
  14:  */
  15: class Ansel_Api extends Horde_Registry_Api
  16: {
  17:     /**
  18:      * Browse through Ansel's gallery tree.
  19:      *
  20:      * @param string $path       The level of the tree to browse.
  21:      * @param array $properties  The item properties to return. Defaults to 'name',
  22:      *                           'icon', and 'browseable'.
  23:      *
  24:      * @return array  The contents of $path
  25:      */
  26:     public function browse($path = '', array $properties = array())
  27:     {
  28:         // Default properties.
  29:         if (!$properties) {
  30:             $properties = array('name', 'icon', 'browseable');
  31:         }
  32: 
  33:         if (substr($path, 0, 5) == 'ansel') {
  34:             $path = substr($path, 5);
  35:         }
  36:         $path = trim($path, '/');
  37:         $parts = explode('/', $path);
  38: 
  39:         $storage = $GLOBALS['injector']->getInstance('Ansel_Storage');
  40:         if (empty($path)) {
  41:             $owners = array();
  42:             $galleries = $storage->listGalleries(array('all_levels' => false));
  43:             foreach ($galleries  as $gallery) {
  44:                 $owners[$gallery->get('owner') ? $gallery->get('owner') : '-system-'] = true;
  45:             }
  46: 
  47:             $results = array();
  48:             foreach (array_keys($owners) as $owner) {
  49:                 if (in_array('name', $properties)) {
  50:                     $results['ansel/' . $owner]['name'] = $owner;
  51:                 }
  52:                 if (in_array('icon', $properties)) {
  53:                     $results['ansel/' . $owner]['icon'] = Horde_Themes::img('user.png');
  54:                 }
  55:                 if (in_array('browseable', $properties)) {
  56:                     $results['ansel/' . $owner]['browseable'] = true;
  57:                 }
  58:                 if (in_array('contenttype', $properties)) {
  59:                     $results['ansel/' . $owner]['contenttype'] =
  60:                         'httpd/unix-directory';
  61:                 }
  62:                 if (in_array('contentlength', $properties)) {
  63:                     $results['ansel/' . $owner]['contentlength'] = 0;
  64:                 }
  65:                 if (in_array('modified', $properties)) {
  66:                     $results['ansel/' . $owner]['modified'] = time();
  67:                 }
  68:                 if (in_array('created', $properties)) {
  69:                     $results['ansel/' . $owner]['created'] = 0;
  70:                 }
  71:             }
  72:             return $results;
  73:         } else {
  74:             if (count($parts) == 1) {
  75:                 // This request is for all galleries owned by the requested user.
  76:                 $galleries = $storage->listGalleries(
  77:                     array('attributes' => $parts[0],
  78:                           'all_levels' => false));
  79:                 $images = array();
  80:             } elseif ($this->galleryExists(null, end($parts))) {
  81:                 // This request if for a certain gallery, list all sub-galleries
  82:                 // and images.
  83:                 $gallery_id = end($parts);
  84:                 $galleries = $storage->listGalleries(
  85:                     array('parent' => $gallery_id,
  86:                           'all_levels' => false,
  87:                           'perm' => Horde_Perms::SHOW));
  88:                 $images = $this->listImages(
  89:                     $gallery_id,
  90:                     array('perms' => Horde_Perms::SHOW,
  91:                           'view' => 'mini'));
  92: 
  93:             } elseif (count($parts) > 2 &&
  94:                       $this->galleryExists(null, $parts[count($parts) - 2]) &&
  95:                       ($image = $GLOBALS['injector']->getInstance('Ansel_Storage')->getImage(end($parts)))) {
  96: 
  97:                 return array(
  98:                     'data' => $image->raw(),
  99:                     'mimetype' => $image->type,
 100:                     'mtime' => $image->uploaded);
 101:             } else {
 102:                 throw new Horde_Exception_NotFound(_("File not found."));
 103:             }
 104: 
 105:             $results = array();
 106:             foreach ($galleries as $gallery) {
 107:                 $retpath = 'ansel/' . implode('/', $parts) . '/' . $gallery->id;
 108:                 if (in_array('name', $properties)) {
 109:                     $results[$retpath]['name'] = $gallery->get('name');
 110:                 }
 111:                 if (in_array('displayname', $properties)) {
 112:                     $results[$retpath]['displayname'] = rawurlencode($gallery->get('name'));
 113:                 }
 114:                 if (in_array('icon', $properties)) {
 115:                     $results[$retpath]['icon'] = Horde_Themes::img('ansel.png');
 116:                 }
 117:                 if (in_array('browseable', $properties)) {
 118:                     $results[$retpath]['browseable'] = $gallery->hasPermission(
 119:                         $GLOBALS['registry']->getAuth(), Horde_Perms::READ);
 120:                 }
 121:                 if (in_array('contenttype', $properties)) {
 122:                     $results[$retpath]['contenttype'] = 'httpd/unix-directory';
 123:                 }
 124:                 if (in_array('contentlength', $properties)) {
 125:                     $results[$retpath]['contentlength'] = 0;
 126:                 }
 127:                 if (in_array('modified', $properties)) {
 128:                     $results[$retpath]['modified'] = time();
 129:                 }
 130:                 if (in_array('created', $properties)) {
 131:                     $results[$retpath]['created'] = 0;
 132:                 }
 133:             }
 134: 
 135:             foreach ($images as $imageId => $image) {
 136:                 $retpath = 'ansel/' . implode('/', $parts) . '/' . $imageId;
 137:                 if (in_array('name', $properties)) {
 138:                     $results[$retpath]['name'] = $image['name'];
 139:                 }
 140:                 if (in_array('displayname', $properties)) {
 141:                     $results[$retpath]['displayname'] = rawurlencode($image['name']);
 142:                 }
 143:                 if (in_array('icon', $properties)) {
 144:                     $results[$retpath]['icon'] = Horde::url($image['url'], true);
 145:                 }
 146:                 if (in_array('browseable', $properties)) {
 147:                     $results[$retpath]['browseable'] = false;
 148:                 }
 149:                 if (in_array('contenttype', $properties)) {
 150:                     $results[$retpath]['contenttype'] = $image['type'];
 151:                 }
 152:                 if (in_array('contentlength', $properties)) {
 153:                     $results[$retpath]['contentlength'] = 0;
 154:                 }
 155:                 if (in_array('modified', $properties)) {
 156:                     $results[$retpath]['modified'] = $image['uploaded'];
 157:                 }
 158:                 if (in_array('created', $properties)) {
 159:                     $results[$retpath]['created'] = $image['uploaded'];
 160:                 }
 161:             }
 162:             return $results;
 163: 
 164:         }
 165: 
 166:         throw Horde_Exception_NotFound(_("File not found."), 404);
 167:     }
 168: 
 169:     /**
 170:      * Saves an image into the gallery tree.
 171:      *
 172:      * @param string $path          The path where to PUT the file.
 173:      * @param string $content       The file content.
 174:      * @param string $content_type  The file's content type.
 175:      *
 176:      * @return array  The event UIDs.
 177:      * @throws Horde_Exception_PermissionDenied
 178:      * @throws Horde_Exception_NotFound
 179:      */
 180:     public function put($path, $content, $content_type)
 181:     {
 182:         if (substr($path, 0, 5) == 'ansel') {
 183:             $path = substr($path, 9);
 184:         }
 185:         $path = trim($path, '/');
 186:         $parts = explode('/', $path);
 187: 
 188:         if (count($parts) < 3) {
 189:             throw new Horde_Exception_NotFound("Gallery does not exist");
 190:         }
 191:         $image_name = array_pop($parts);
 192:         $gallery_id = end($parts);
 193:         if (!$GLOBALS['injector']->getInstance('Ansel_Storage')->galleryExists($gallery_id)) {
 194:             throw new Horde_Exception_NotFound("Gallery does not exist");
 195:         }
 196:         $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')->getGallery($gallery_id);
 197:         if (!$gallery->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::EDIT)) {
 198:             throw new Horde_Exception_PermissionDenied(_("Access denied adding photos to \"%s\"."));
 199:         }
 200: 
 201:         return $gallery->addImage(array(
 202:             'image_type' => $content_type,
 203:             'image_filename' => $image_name,
 204:             'image_caption' => '',
 205:             'data' => $content));
 206:     }
 207: 
 208:     /**
 209:      * Callback for Agora comments.
 210:      *
 211:      * @param integer $image_id  Image id to check
 212:      *
 213:      * @return mixed Image filename on success | false on failure
 214:      */
 215:     public function commentCallback($image_id)
 216:     {
 217:         if (!$GLOBALS['conf']['comments']['allow']) {
 218:             return false;
 219:         }
 220: 
 221:         try {
 222:             if (!($image = $GLOBALS['injector']->getInstance('Ansel_Storage')->getImage($image_id))) {
 223:                 return false;
 224:             }
 225:         } catch (Ansel_Exception $e) {
 226:             return false;
 227:         }
 228: 
 229:         return $image->filename;
 230:     }
 231: 
 232:     /**
 233:      * Checks if applications allows comments
 234:      *
 235:      * @return boolean
 236:      */
 237:     public function hasComments()
 238:     {
 239:         if (($GLOBALS['conf']['comments']['allow'] == 'all' ||
 240:             ($GLOBALS['conf']['comments']['allow'] == 'authenticated' &&
 241:             $GLOBALS['registry']->getAuth()))) {
 242:             return true;
 243:         } else {
 244:             return false;
 245:         }
 246:     }
 247: 
 248:     /**
 249:      * Returns decoded image data
 250:      *
 251:      * @param string $data         The image data
 252:      * @param string $encoding     The encoding type for the image data.
 253:      *                             (none, base64, or binhex)
 254:      * @param string $compression  The compression type for the image data.
 255:      *                             (none, gzip, or lzf)
 256:      * @param boolean $upload      Process direction (true of encode/compress or false if decode/decompress)
 257:      *
 258:      * @return string  The decoded/encoded image data
 259:      */
 260:     protected function _getImageData($data, $encoding = 'none', $compression = 'none', $upload = true)
 261:     {
 262:         switch ($encoding) {
 263:         case 'base64':
 264:             $data = $upload ? base64_decode($data) : base64_encode($data);
 265:             break;
 266: 
 267:         case 'binhex':
 268:             $data = $upload ? pack('H*', $data) : unpack('H*', $data);
 269:         }
 270: 
 271:         switch ($compression) {
 272:         case 'gzip':
 273:             if (Horde_Util::loadExtension('zlib')) {
 274:                 return $upload ? gzuncompress($data) : gzcompress($data);
 275:             }
 276:             break;
 277: 
 278:         case 'lzf':
 279:             if (Horde_Util::loadExtension('lzf')) {
 280:                 return $upload ? lzf_decompress($data) : lzf_compress($data);
 281:             }
 282:             break;
 283: 
 284:         default:
 285:             return $data;
 286:         }
 287:     }
 288: 
 289:     /**
 290:      * Stores an image in a gallery and returns gallery and image data.
 291:      *
 292:      * @param integer $gallery_id  The gallery id to add the image to.
 293:      * @param array $image         Image data array. This can either be the
 294:      *                             return from Horde_Form_Type_image:: or an
 295:      *                             array with the following four fields:
 296:      *                             'filename', 'description', 'data', 'type' and
 297:      *                             optionally 'tags'
 298:      *
 299:      * @param array $params  An array of additional parameters:
 300:      * <pre>
 301:      *   (string)slug         If set, use this as the gallery slug
 302:      *                        (ignores $gallery_id)
 303:      *   (string)scope        The scope to use, if not the default.
 304:      *   (boolean)default     Set this as the key gallery image.
 305:      *   (array)gallery_data  Any gallery parameters to change at this time.
 306:      *   (string)encoding     The encoding type for the image data (base64 or binhex)
 307:      *   (string)compression  The compression type for image data (gzip,lzf)
 308:      *   (boolean)skiphook    Don't call the postupload hook(s).
 309:      * </pre>
 310:      *
 311:      * @return array  An array of image/gallery data
 312:      * @throws InvalidArgumentException
 313:      * @throws Horde_Exception_PermissionDenied
 314:      */
 315:     public function saveImage($gallery_id, array $image, array $params = array())
 316:     {
 317:         // Set application scope
 318:         if (!empty($params['scope'])) {
 319:             $GLOBALS['injector']->getInstance('Ansel_Config')->set('scope', $params['scope']);
 320:         }
 321: 
 322:         // Build image upload structure
 323:         if (isset($image['filename']) &&
 324:             isset($image['description']) &&
 325:             isset($image['data']) &&
 326:             isset($image['type'])) {
 327:                 Horde::logMessage(sprintf("Receiving image %s in saveImage() with a raw filesize of %i", $image['filename'], strlen($image['data'])), 'DEBUG');
 328:                 $image_data = array(
 329:                     'image_filename' => $image['filename'],
 330:                     'image_caption' => $image['description'],
 331:                     'image_type' => $image['type'],
 332:                     'data' => $this->_getImageData($image['data'], (empty($params['encoding']) ? 'none' : $params['encoding']), (empty($params['compression']) ? 'none' : $params['compression']), true));
 333:         }
 334: 
 335:         // Validate the image data and other requirements
 336:         if (empty($image_data) && getimagesize($image['file']) === false) {
 337:             throw new InvalidArgumentException(_("The file you uploaded does not appear to be a valid photo."));
 338:         }
 339:         if (empty($params['slug']) && empty($gallery_id)) {
 340:             throw new InvalidArgumentException(_("A gallery to add this photo to is required."));
 341:         }
 342:         if (!empty($params['slug'])) {
 343:             $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')->getGalleryBySlug($params['slug']);
 344:         } elseif ($GLOBALS['injector']->getInstance('Ansel_Storage')->galleryExists($gallery_id)) {
 345:             $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')->getGallery($gallery_id);
 346:         }
 347: 
 348:         // Check perms for requested gallery
 349:         if (!$gallery->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::EDIT)) {
 350:             throw new Horde_Exception_PermissionDenied(sprintf(_("Access denied adding photos to \"%s\"."), $gallery->get('name')));
 351:         }
 352: 
 353:         // Changing any values while we are at it?
 354:         if (!empty($params['gallery_data'])) {
 355:             foreach ($params['gallery_data'] as $key => $value) {
 356:                 $gallery->set($key, $value);
 357:             }
 358:             $gallery->save();
 359:         }
 360: 
 361:         if (empty($image_data)) {
 362:             $image_data = array(
 363:                 'image_filename' => $image['name'],
 364:                 'image_caption' => $image['name'],
 365:                 'image_type' => $image['name']['type'],
 366:                 'data' => file_get_contents($image['file']),
 367:             );
 368:         }
 369: 
 370:         if (isset($image['tags']) && is_array($image['tags']) && count($image['tags'])) {
 371:             $image_data['tags'] = $image['tags'];
 372:         }
 373:         $image_id = $gallery->addImage($image_data, !empty($params['default']));
 374: 
 375:         // Call the postupload hook if needed
 376:         if (empty($params['skiphook'])) {
 377:             $this->postBatchUpload($image_id);
 378:         }
 379: 
 380:         return array(
 381:             'image_id'   => (int)$image_id,
 382:             'gallery_id' => (int)$gallery->id,
 383:             'gallery_slug' => $gallery->get('slug'),
 384:             'image_count' => (int)$gallery->countImages());
 385:     }
 386: 
 387:     /**
 388:      * Notify Ansel that a group of images has just been uploaded. Used for when
 389:      * the postupload hook should be called with a group of recently
 390:      * uploaded images, as opposed to calling it once after each image is saved.
 391:      *
 392:      * @param array $image_ids  An array of image ids.
 393:      */
 394:     public function postBatchUpload(array $image_ids)
 395:     {
 396:         try {
 397:             Horde::callHook('postupload', array($image_ids), 'ansel');
 398:         } catch (Horde_Exception_HookNotSet $e) {}
 399:     }
 400: 
 401:     /**
 402:      * Removes an image from a gallery.
 403:      *
 404:      * @param integer $gallery_id The id of gallery.
 405:      * @param string $image_id    The id of image to remove.
 406:      * @param array $params       Additional parameters:
 407:      * <pre>
 408:      *   (string)scope  The scope to use, if not the default.
 409:      * </pre>
 410:      *
 411:      * @throws Horde_Exception_PermissionDenied
 412:      */
 413:     public function removeImage($gallery_id, $image_id, array $params = array())
 414:     {
 415:         // Check global Ansel permissions
 416:         if (!$GLOBALS['injector']->getInstance('Horde_Perms')->getPermissions('ansel', $GLOBALS['registry']->getAuth())) {
 417:             throw new Horde_Exception_PermissionDenied(_("Access denied deleting galleries."));
 418:         }
 419: 
 420:         // Set a custom scope, if needed
 421:         if (!empty($params['scope'])) {
 422:             $GLOBALS['injector']->getInstance('Ansel_Config')->set('scope', $params['scope']);
 423:         }
 424: 
 425:         $image = $GLOBALS['injector']->getInstance('Ansel_Storage')->getImage($image_id);
 426:         $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')->getGallery($image->gallery);
 427:         if (!$gallery->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::DELETE)) {
 428:             throw new Horde_Exception_PermissionDenied(sprintf(_("Access denied deleting photos from \"%s\"."), $gallery->get('name')));
 429:         }
 430: 
 431:         $gallery->removeImage($image);
 432:     }
 433: 
 434:     /**
 435:      * Add a new gallery to any application scope.
 436:      *
 437:      * @param array $attributes  The gallery attributes
 438:      * @param array $params      Additional (optional) parameters:
 439:      *<pre>
 440:      *    (string)scope    The scope to use, if not the default.
 441:      *    (array)perm      An array of permission data if Ansel's defaults are
 442:      *                     not desired. Takes an array like:
 443:      *                        array('guest' => Horde_Perms::SHOW | Horde_Perms::READ,
 444:      *                              'default' => Horde_Perms::SHOW | Horde_Perms::READ);
 445:      *    (integer)parent  The gallery id of the parent gallery, if not a top level gallery.
 446:      *</pre>
 447:      *
 448:      * @return integer  The gallery id of the new gallery
 449:      * @throws Horde_Exception_PermissionDenied
 450:      */
 451:     public function createGallery($attributes, array $params = array())
 452:     {
 453:         if (!($GLOBALS['registry']->isAdmin() ||
 454:             (!$GLOBALS['injector']->getInstance('Horde_Perms')->exists('ansel') && $GLOBALS['registry']->getAuth()) ||
 455:             $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission('ansel', $GLOBALS['registry']->getAuth(), Horde_Perms::EDIT))) {
 456: 
 457:             throw new Horde_Exception_PermissionDenied(_("Access denied creating new galleries."));
 458:         }
 459: 
 460:         // Custom scope?
 461:         if (!empty($params['scope'])) {
 462:             $GLOBALS['injector']->getInstance('Ansel_Config')
 463:                 ->set('scope', $params['scope']);
 464:         }
 465: 
 466:         // Non-default perms?
 467:         if (!empty($params['perm'])) {
 468:             // The name is inconsequential; it is only used as a container to
 469:             // represent permissions when passed to the Ansel backend.
 470:             $permobj = new Horde_Perms_Permission('');
 471:             $permobj->data = $perm;
 472:         } else {
 473:             $permobj = null;
 474:         }
 475: 
 476:         // Create the gallery
 477:         $gallery = $GLOBALS['injector']
 478:             ->getInstance('Ansel_Storage')
 479:             ->createGallery(
 480:                 $attributes,
 481:                 $permobj,
 482:                 (!empty($params['parent']) ? $params['parent'] : null));
 483: 
 484:         return $gallery->id;
 485:     }
 486: 
 487:     /**
 488:      * Removes a gallery and its images.
 489:      *
 490:      * @param integer $gallery_id  The id of gallery.
 491:      * @param array $params        Any additional, optional, parameters:
 492:      *  <pre>
 493:      *    (string)scope  the scope to use, if not the default
 494:      *  </pre>
 495:      *
 496:      * @throws Ansel_Exception
 497:      * @throws Horde_Exception_PermissionDenied
 498:      */
 499:     public function removeGallery($gallery_id, array $params = array())
 500:     {
 501:         // Check global Ansel permissions
 502:         if (!$GLOBALS['injector']->getInstance('Horde_Perms')->getPermissions('ansel', $GLOBALS['registry']->getAuth())) {
 503:             throw new Horde_Exception_PermissionDenied(_("Access denied deleting galleries."));
 504:         }
 505: 
 506:         // Custom scope, if needed
 507:         if (!empty($params['scope'])) {
 508:             $GLOBALS['injector']->getInstance('Ansel_Config')
 509:                 ->set('scope', $params['scope']);
 510:         }
 511: 
 512:         // Get, and check perms on the gallery
 513:         $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')->getGallery($gallery_id);
 514:         if (!$gallery->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::DELETE)) {
 515:             throw new Horde_Exception_PermissionDenied(sprintf(_("Access denied deleting gallery \"%s\"."), $gallery->get('name')));
 516:         } else {
 517:             $GLOBALS['injector']
 518:                 ->getInstance('Ansel_Storage')
 519:                 ->removeGallery($gallery);
 520:         }
 521:     }
 522: 
 523:     /**
 524:      * Returns the number of images in a gallery.
 525:      *
 526:      * @param integer $gallery_id   The gallery id.
 527:      * @param array $params         Array of optional parameters:
 528:      *<pre>
 529:      *    (string)scope  Scope to use, if not the default.
 530:      *    (string)slug   If set, ignore gallery_id and use this as the slug.
 531:      * </pre>
 532:      *
 533:      * @return integer  The number of images in the gallery.
 534:      * @throws Ansel_Exception
 535:      */
 536:     public function count($gallery_id = null, array $params = array())
 537:     {
 538:         if (!empty($params['scope'])) {
 539:             $GLOBALS['injector']->getInstance('Ansel_Config')->set('scope', $params['scope']);
 540:         }
 541: 
 542:         try {
 543:             if (!empty($params['slug'])) {
 544:                 $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')->getGalleryBySlug($params['slug']);
 545:             } else {
 546:                 $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')->getGallery($gallery_id);
 547:             }
 548:             return (int)$gallery->countImages();
 549:         } catch (Ansel_Exception $e) {
 550:             return 0;
 551:         }
 552:     }
 553: 
 554:     /**
 555:      * Returns the id of the specified gallery's key image.
 556:      *
 557:      * @param integer $gallery_id  The gallery id.
 558:      * @param array $params        Additional parameters:
 559:      *<pre>
 560:      *  (string)scope   Application scope, if not the default
 561:      *  (string)style   A named style to use, if not ansel_default
 562:      *  (string)slug    Ignore gallery_id, and use this as the slug
 563:      *</pre>
 564:      *
 565:      * @return integer  The key image id.
 566:      */
 567:     public function getGalleryKeyImage($gallery_id, array $params = array())
 568:     {
 569:         if (!empty($params['scope'])) {
 570:             $GLOBALS['injector']->getInstance('Ansel_Config')
 571:                 ->set('scope', $params['scope']);
 572:         }
 573: 
 574:         if (!empty($params['slug'])) {
 575:             $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')
 576:                 ->getGalleryBySlug($params['slug']);
 577:         } else {
 578:             $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')
 579:                 ->getGallery($gallery_id);
 580:         }
 581: 
 582:         $style = empty($params['style']) ?
 583:             Ansel::getStyleDefinition('ansel_default') :
 584:             Ansel::getStyleDefinition($params['style']);
 585: 
 586:         return $gallery->getKeyImage($style);
 587:     }
 588: 
 589:     /**
 590:      * Returns the URL to the specified image.
 591:      *
 592:      * @param integer $image_id  The id of the image.
 593:      * @param array $params      Additional optional parameters:
 594:      *  <pre>
 595:      *    (string)scope  The application scope, if not the default.
 596:      *    (string)view   The image view type to return (screen, thumb, etc...)
 597:      *    (string)full   Return a fully qualified path?
 598:      *    (string)style  Use this gallery style instead of ansel_default.
 599:      *  </pre>
 600:      *
 601:      * @return string  The image path.
 602:      */
 603:     public function getImageUrl($image_id, array $params = array())
 604:     {
 605:         if (!empty($params['scope'])) {
 606:             $GLOBALS['injector']->getInstance('Ansel_Config')
 607:                 ->set('scope', $params['scope']);
 608:         }
 609: 
 610:         $style = empty($params['style']) ?
 611:             Ansel::getStyleDefinition('ansel_default') :
 612:             Ansel::getStyleDefinition($params['style']);
 613: 
 614:         return (string)Ansel::getImageUrl(
 615:             $image_id,
 616:             empty($params['view']) ? 'screen': $params['view'],
 617:             empty($params['full']) ? false : $params['full'],
 618:             $style);
 619:     }
 620: 
 621:     /**
 622:      * Returns raw image data in specified encoding/compression format.
 623:      *
 624:      * @TODO: See about using a stream
 625:      *
 626:      * @param integer $image_id  The id of the image.
 627:      * @param array $params      Optional parameters:
 628:      *<pre>
 629:      *  (string)scope        Application scope, if not default.
 630:      *  (string)view         The image view type to return (screen, thumb etc...)
 631:      *  (string)style        Force the use of this gallery style
 632:      *  (string)encoding     Encoding type (base64, binhex)
 633:      *  (string)compression  Compression type (gzip, lzf)
 634:      *</pre>
 635:      *
 636:      * @return string  The raw image data.
 637:      * @throws Horde_Exception_Permission_Denied
 638:      * @throws Ansel_Exception
 639:      */
 640:     public function getImageContent($image_id, array $params = array())
 641:     {
 642:         if (!empty($params['scope'])) {
 643:             $GLOBALS['injector']->getInstance('Ansel_Config')
 644:                 ->set('scope', $params['scope']);
 645:         }
 646: 
 647:         // Get image and gallery
 648:         $image = $GLOBALS['injector']->getInstance('Ansel_Storage')
 649:             ->getImage($image_id);
 650:         $gallery = $GLOBALS['injector']->getInstance('Ansel_Storage')
 651:             ->getGallery($image->gallery);
 652: 
 653:         // Check age and password
 654:         if ($gallery->hasPasswd() || !$gallery->isOldEnough()) {
 655:             throw new Horde_Exception_PermissionDenied(
 656:                 _("Locked galleries are not viewable via the api."));
 657:         }
 658: 
 659:         if ($view == 'full') {
 660:             // Check permissions for full view
 661:             if (!$gallery->canDownload()) {
 662:                 throw new Horde_Exception_PermissionDenied(
 663:                     sprintf(_("Access denied downloading full sized photos from \"%s\"."), $gallery->get('name')));
 664:             }
 665: 
 666:             // Try reading the data
 667:             try {
 668:                 $data = $GLOBALS['injector']
 669:                     ->getInstance('Horde_Core_Factory_Vfs')
 670:                     ->create('images')
 671:                     ->read($image->getVFSPath('full'), $image->getVFSName('full'));
 672:             } catch (Horde_Vfs_Exception $e) {
 673:                 Horde::logMessage($e->getMessage(), 'ERR');
 674:                 throw new Ansel_Exception($e->getMessage());
 675:             }
 676:         } else {
 677:             if (!empty($params['style'])) {
 678:                 $params['style'] = Ansel::getStyleDefinition($style);
 679:             } else {
 680:                 $params['style'] = null;
 681:             }
 682:             $image->load($view, $params['style']);
 683:             $data = $image->_image->raw();
 684:         }
 685: 
 686:         return $this->_getImageData($data, $encoding, $compression, false);
 687:     }
 688: 
 689:     /**
 690:      * Returns a list of all galleries.
 691:      *
 692:      * @param array $params  Optional parameters:
 693:      *<pre>
 694:      *  (string)scope       The application scope, if not default.
 695:      *  (integer)perm       The permissions filter to use [Horde_Perms::SHOW]
 696:      *  (mixed)attributes   Restrict the galleries returned to those matching
 697:      *                      the filters. Can be an array of attribute/values
 698:      *                      pairs or a gallery owner username.
 699:      *  (integer)parent     The parent share to start listing at.
 700:      *  (boolean)all_levels If set, return all levels below parent, not just
 701:      *                      direct children [TRUE]
 702:      *  (integer)from       The gallery to start listing at.
 703:      *  (integer)count      The number of galleries to return.
 704:      *  (string)sort_by     Attribute to sort by
 705:      *  (integer)direction  The direction to sort by [Ansel::SORT_ASCENDING]
 706:      *  (array)tags        An array of tags to limit results by.
 707:      *</pre>
 708:      *
 709:      * @return array  An array of gallery information.
 710:      */
 711:     public function listGalleries(array $params = array())
 712:     {
 713:         // If no scope is given use Ansel's default
 714:         if (!empty($params['scope'])) {
 715:             $GLOBALS['injector']->getInstance('Ansel_Config')
 716:                 ->set('scope', $params['scope']);
 717:         }
 718:         $galleries = $GLOBALS['injector']
 719:             ->getInstance('Ansel_Storage')
 720:             ->listGalleries($params);
 721:         $return = array();
 722:         foreach ($galleries as $gallery) {
 723:             $return[] = array_merge(
 724:                 $gallery->toArray(),
 725:                 array('crumbs' => $gallery->getGalleryCrumbData()));
 726:         }
 727: 
 728:         return $return;
 729:     }
 730: 
 731:     /**
 732:      * Returns an array of gallery information.
 733:      *
 734:      * @param array $ids   An array of gallery ids.
 735:      * @param string $app  Application scope to use, if not the default.
 736:      * @param array $slugs An array of gallery slugs (ignore $ids).
 737:      *
 738:      * @return array An array of gallery data arrays
 739:      */
 740:     public function getGalleries(array $ids, $app = null, array $slugs = array())
 741:     {
 742:         if (!is_null($app)) {
 743:             $GLOBALS['injector']->getInstance('Ansel_Config')->set('scope', $app);
 744:         }
 745: 
 746:         if (count($slugs)) {
 747:             $results = $GLOBALS['injector']->getInstance('Ansel_Storage')
 748:                 ->getGalleriesBySlugs($slugs);
 749:         } else {
 750:             $results = $GLOBALS['injector']->getInstance('Ansel_Storage')
 751:                 ->getGalleries($ids);
 752:         }
 753: 
 754:         // We can't just return the results of the getGalleries call - we need
 755:         // to build the non-object return structure.
 756:         $galleries = array();
 757:         foreach ($results as $gallery) {
 758:             $galleries[$gallery->id] = array_merge(
 759:                 $gallery->toArray(),
 760:                 array('crumbs' => $gallery->getGalleryCrumbData()));
 761:         }
 762: 
 763:         return $galleries;
 764:     }
 765: 
 766:     /**
 767:      * Returns a 'select' menu from the list of galleries created by
 768:      * listGalleries().
 769:      *
 770:      * @param array $params  Optional parameters:
 771:      *<pre>
 772:      *  (string)scope      Application scope, if not default.
 773:      *  (integer)selected  The gallery_id of the gallery that is selected
 774:      *  (integer)perm      The permissions filter to use [Horde_Perms::SHOW]
 775:      *  (mixed)filter      Restrict the galleries returned to those matching
 776:      *                     the filters. Can be an array of attribute/values
 777:      *                     pairs or a gallery owner username.
 778:      *  (integer)parent    The parent share to start listing at.
 779:      *  (integer)from      The gallery to start listing at.
 780:      *  (integer)count     The number of galleries to return.
 781:      *  (integer)ignore    An Ansel_Gallery id to ignore when building the tree.
 782:      *</pre>
 783:      */
 784:     public function selectGalleries(array $params = array())
 785:     {
 786:         if (!empty($params['scope'])) {
 787:             $GLOBALS['injector']->getInstance('Ansel_Config')
 788:                 ->set('scope', $params['scope']);
 789:             unset($params['scope']);
 790:         }
 791: 
 792:         return Ansel::selectGalleries($params);
 793:     }
 794: 
 795:     /**
 796:      * Returns a list of all images in a gallery.
 797:      *
 798:      * The return has the URL because in a lot of cases you'll want the url
 799:      * also. Using api call getImageURL results in a lot of overhead when
 800:      * e.g. generating a select list.
 801:      *
 802:      * @param integer $gallery_id  Gallery id to get images from.
 803:      * @param array $params        Additional parameters:
 804:      *<pre>
 805:      *  (string)app          Application scope to use [ansel].
 806:      *  (string)view         View size to generate URLs for [thumb].
 807:      *  (boolean)full        Return a full URL [false].
 808:      *  (integer)from        Start image.
 809:      *  (integer)limit       Max count of images to return.
 810:      *  (string)style        Use this gallery style.
 811:      *  (string)slug         Gallery slug (ignore gallery_id).
 812:      *</pre>
 813:      *
 814:      * @return array  Hash of image data (see below) keyed by image_id.
 815:      *<pre>
 816:      *  name
 817:      *  caption
 818:      *  type
 819:      *  uploaded
 820:      *  original_date
 821:      *  url
 822:      *</pre>
 823:      */
 824:     public function listImages($gallery_id, array $params = array())
 825:     {
 826:         $params = new Horde_Support_Array($params);
 827:         if ($params->app) {
 828:             $GLOBALS['injector']->getInstance('Ansel_Config')
 829:                 ->set('scope', $params->app);
 830:         }
 831:         $storage = $GLOBALS['injector']->getInstance('Ansel_Storage');
 832:         if ($params->slug) {
 833:             $gallery = $storage->getGalleryBySlug($params->slug);
 834:         } else {
 835:             $gallery = $storage->getGallery($gallery_id);
 836:         }
 837:         $images = $gallery->listImages($params->get('from', 0), $params->get('limit', 0));
 838:         if ($params->style) {
 839:             $params->style = Ansel::getStyleDefinition($params->style);
 840:         } else {
 841:             $params->style = $gallery->getStyle();
 842:         }
 843: 
 844:         $counter = 0;
 845:         $imagelist = array();
 846:         foreach ($images as $id) {
 847:             $image = $storage->getImage($id);
 848:             $imagelist[$id]['name'] = $image->filename;
 849:             $imagelist[$id]['caption'] = $image->caption;
 850:             $imagelist[$id]['type'] = $image->type;
 851:             $imagelist[$id]['uploaded'] = $image->uploaded;
 852:             $imagelist[$id]['original_date'] = $image->originalDate;
 853:             $imagelist[$id]['url'] = Ansel::getImageUrl(
 854:                 $id, $params->get('view', 'thumb'), $params->get('full', false), $params->style);
 855:             if ($params->app && $GLOBALS['conf']['vfs']['src'] != 'direct') {
 856:                 $imagelist[$id]['url']->add('app', $params->app);
 857:             }
 858:             $imagelist[$id]['url'] = $imagelist[$id]['url']->toString();
 859:         }
 860: 
 861:         return $imagelist;
 862:     }
 863: 
 864:     /**
 865:      * Return a list of recently added images
 866:      *
 867:      * @param array $params  Parameter (optionally) containing:
 868:      *<pre>
 869:      *   (string)app       Application used if null then use default.
 870:      *   (array)galleries  An array of gallery ids to check.  If left empty,
 871:      *                     will search all galleries with the given
 872:      *                     permissions for the current user.
 873:      *   (string)view      The type of image view to return.
 874:      *   (boolean)full     Return a full URL if this is true.
 875:      *   (integer)limit    The maximum number of images to return.
 876:      *   (string)style     Force the use of this gallery style
 877:      *   (array)slugs      An array of gallery slugs
 878:      *
 879:      * @return array  A hash of image information arrays, keyed by image_id:
 880:      * @see Ansel_Api::getImages
 881:      */
 882:     public function getRecentImages(array $params = array())
 883:     {
 884:         $params = new Horde_Support_Array($params);
 885: 
 886:         if ($params->app) {
 887:             $GLOBALS['injector']->getInstance('Ansel_Config')
 888:                 ->set('scope', $params->app);
 889:         }
 890:         $images = $GLOBALS['injector']->getInstance('Ansel_Storage')
 891:             ->getRecentImages(
 892:                 $params->get('galleries', array()),
 893:                 $params->get('limit', 10),
 894:                 $params->get('slugs', array()));
 895:         $imagelist = array();
 896:         if ($params->style) {
 897:             $params->style = Ansel::getStyleDefinition($params->style);
 898:         }
 899:         foreach ($images as $image) {
 900:             $id = $image->id;
 901:             $imagelist[$id]['id'] = $id;
 902:             $imagelist[$id]['name'] = $image->filename;
 903:             $imagelist[$id]['url'] = Ansel::getImageUrl(
 904:                 $id,
 905:                 $params->get('view', 'screen'),
 906:                 $params->get('full', false),
 907:                 $params->style);
 908:             $imagelist[$id]['caption'] = $image->caption;
 909:             $imagelist[$id]['filename'] = $image->filename;
 910:             $imagelist[$id]['gallery'] = $image->gallery;
 911:             $imagelist[$id]['uploaded'] = $image->uploaded;
 912:             $imagelist[$id]['original_date'] = $image->originalDate;
 913: 
 914:             if ($params->app && $GLOBALS['conf']['vfs']['src'] != 'direct') {
 915:                 $imagelist[$id]['url']->add('app', $params->app);
 916:             }
 917:         }
 918:         return $imagelist;
 919: 
 920:     }
 921: 
 922:     /**
 923:      * Counts the number of galleries.
 924:      *
 925:      * @param array $params  Parameter array containing the following optional:
 926:      *<pre>
 927:      *  (string)app         Application scope to use, if not the default.
 928:      *  (integer)perm       The level of permissions to require for a gallery
 929:      *                      to return it.
 930:      *  (mixed)attributes   Restrict the galleries counted to those matching
 931:      *                      attributes. An array of attribute/value pairs or
 932:      *                      a gallery owner username.
 933:      *  (integer)parent     The parent gallery id to start searching at.
 934:      *  (boolean)all_levels  Return all levels, or just the direct children of
 935:      *                      $parent?
 936:      *
 937:      * @return integer  Returns the number of matching galleries.
 938:      */
 939:     public function countGalleries(array $params = array())
 940:     {
 941:         if (!empty($params['app'])) {
 942:             $GLOBALS['injector']->getInstance('Ansel_Config')
 943:                 ->set('scope', $params['app']);
 944:             unset($params['app']);
 945:         }
 946: 
 947:         return $GLOBALS['injector']->getInstance('Ansel_Storage')
 948:             ->countGalleries(
 949:                 $GLOBALS['registry']->getAuth(),
 950:                 $params);
 951:     }
 952: 
 953:     /**
 954:      * Retrieve the list of used tag_names, tag_ids and the total number
 955:      * of resources that are linked to that tag.
 956:      *
 957:      * @param array $tags  An optional array of tag_ids. If omitted, all tags
 958:      *                     will be included.
 959:      *
 960:      * @return array  An array containing tag_name, and total
 961:      */
 962:     public function listTagInfo($tags = null, $user = null)
 963:     {
 964:         return $GLOBALS['injector']->getInstance('Ansel_Tagger')->getTagInfo($tags, 500, null, $user);
 965:     }
 966: 
 967:     /**
 968:      * SearchTags API:
 969:      * Returns an application-agnostic array (useful for when doing a tag search
 970:      * across multiple applications)
 971:      *
 972:      * The 'raw' results array can be returned instead by setting $raw = true.
 973:      *
 974:      * @param array $names           An array of tag_names to search for.
 975:      * @param integer $max           The maximum number of resources to return.
 976:      * @param integer $from          The number of the resource to start with.
 977:      * @param string $resource_type  The resource type [gallery, image, '']
 978:      * @param string $user           Restrict results to resources owned by $user.
 979:      * @param boolean $raw           Return the raw data?
 980:      * @param string $app            Application scope to use, if not the default.
 981:      *
 982:      * @return array An array of results:
 983:      * <pre>
 984:      *  'title'    - The title for this resource.
 985:      *  'desc'     - A terse description of this resource.
 986:      *  'view_url' - The URL to view this resource.
 987:      *  'app'      - The Horde application this resource belongs to.
 988:      * </pre>
 989:      */
 990:     public function searchTags($names, $max = 10, $from = 0,
 991:                                $resource_type = '', $user = null, $raw = false,
 992:                                $app = 'ansel')
 993:     {
 994:         $GLOBALS['injector']->getInstance('Ansel_Config')->set('scope', $app);
 995:         $results = $GLOBALS['injector']
 996:             ->getInstance('Ansel_Tagger')
 997:             ->search(
 998:                 $names,
 999:                 array('type' => $resource_type, 'user' => $user));
1000: 
1001:         // Check for error or if we requested the raw data array.
1002:         if ($raw) {
1003:             return $results;
1004:         }
1005: 
1006:         $return = array();
1007:         if (!empty($results['images'])) {
1008:             foreach ($results['images'] as $image_id) {
1009:                 $image = $GLOBALS['injector']
1010:                     ->getInstance('Ansel_Storage')
1011:                     ->getImage($image_id);
1012:                 $g = $GLOBALS['injector']
1013:                     ->getInstance('Ansel_Storage')
1014:                     ->getGallery($image->gallery);
1015:                 $view_url = Ansel::getUrlFor('view',
1016:                     array('gallery' => $image->gallery,
1017:                     'image' => $image_id,
1018:                     'view' => 'Image'),
1019:                     true);
1020:                 $gurl = Ansel::getUrlFor('view', array('view' => 'Gallery', 'gallery' => $image->gallery));
1021:                 $return[] = array(
1022:                     'title' => $image->filename,
1023:                     'desc'=> $image->caption . ' '. _("from") . ' ' . $gurl->link() . $g->get('name') . '</a>',
1024:                     'view_url' => $view_url,
1025:                     'app' => $app,
1026:                     'icon' => Ansel::getImageUrl($image_id, 'mini'));
1027:             }
1028:         }
1029: 
1030:         if (!empty($results['galleries'])) {
1031:             foreach ($results['galleries'] as $gallery) {
1032:                 $gal = $GLOBALS['injector']
1033:                     ->getInstance('Ansel_Storage')
1034:                     ->getGallery($gallery);
1035:                 $view_url = Horde::url('view.php')
1036:                     ->add(
1037:                         array('gallery' => $gallery,
1038:                               'view' => 'Gallery'));
1039:                 $gurl = Ansel::getUrlFor('view', array('view' => 'Gallery', 'gallery' => $gallery));
1040:                 $return[] = array(
1041:                     'desc' => $gurl->link() . $gal->get('name') . '</a>',
1042:                     'view_url' => $view_url,
1043:                     'app' => $app,
1044:                     'icon' => Ansel::getImageUrl($gal->getKeyImage(), 'mini'));
1045:             }
1046:         }
1047: 
1048:         return $return;
1049:     }
1050: 
1051:     /**
1052:      * Checks if the gallery exists
1053:      *
1054:      * @param integer $gallery_id  The gallery id
1055:      * @param string $slug         The gallery slug
1056:      * @param string $app          Application scope to use, if not the default.
1057:      *
1058:      * @return boolean
1059:      */
1060:     public function galleryExists($gallery_id, $slug = '', $app = null)
1061:     {
1062:         if (!is_null($app)) {
1063:             $GLOBALS['injector']->getInstance('Ansel_Config')
1064:                 ->set('scope', $app);
1065:         }
1066: 
1067:         return $GLOBALS['injector']->getInstance('Ansel_Storage')
1068:             ->galleryExists($gallery_id, $slug);
1069:     }
1070: 
1071:     /**
1072:      * Get a list of all pre-configured styles.
1073:      *
1074:      * @return hash of style definitions.
1075:      */
1076:     public function getGalleryStyles()
1077:     {
1078:         return $GLOBALS['injector']->getInstance('Ansel_Styles');
1079:     }
1080: 
1081:     /**
1082:      * Renders a gallery view
1083:      *
1084:      * @param array $params         Any parameters that the view might need.
1085:      *                              @see Ansel_View_* classes for descriptions of
1086:      *                              available parameters to use here.
1087:      * @param string $app           Application scope to use, if not the default.
1088:      * @param string $view          The generic type of view we want.
1089:      *                              (Gallery, Image, List, Embedded)
1090:      *
1091:      * @return array  An array containing 'html' and 'crumbs' keys.
1092:      */
1093:     public function renderView($params = array(), $app = null, $view = 'Gallery')
1094:     {
1095:         if (!is_null($app)) {
1096:             $GLOBALS['injector']->getInstance('Ansel_Config')->set('scope', $app);
1097:         }
1098:         $classname = 'Ansel_View_' . basename($view);
1099:         $params['api'] = true;
1100:         $params['view'] = $view;
1101:         $trail = array();
1102:         $return = array();
1103:         try {
1104:             $view = new $classname($params);
1105:         } catch (Horde_Exception $e) {
1106:             $return['html'] = $e->getMessage();
1107:             $return['crumbs'] = array();
1108:             return $return;
1109:         }
1110:         $return['html'] = $view->html();
1111:         if ($params['view'] == 'Gallery' || $params['view'] == 'Image') {
1112:             $trail = $view->getGalleryCrumbData();
1113:         }
1114:         $return['crumbs'] = $trail;
1115: 
1116:         return $return;
1117:     }
1118: 
1119: }
1120: 
API documentation generated by ApiGen