diff options
| author | modela bitweaver <spiderr@bitweaver.org> | 2021-02-02 12:10:53 -0500 |
|---|---|---|
| committer | modela bitweaver <spiderr@bitweaver.org> | 2021-02-02 12:10:53 -0500 |
| commit | 5c6319e71df90b5adf98d145c06095d64356c311 (patch) | |
| tree | 5bf6435af4caed312727916a458df6474b0169c3 /includes | |
| parent | 1086b09bdce0b69ea6bf1c931cc0b6f3967921da (diff) | |
| download | fisheye-5c6319e71df90b5adf98d145c06095d64356c311.tar.gz fisheye-5c6319e71df90b5adf98d145c06095d64356c311.tar.bz2 fisheye-5c6319e71df90b5adf98d145c06095d64356c311.zip | |
move _inc and classes to includes/classes and use PKG_CLASS/INCLUDE_PATH constants
Diffstat (limited to 'includes')
| -rw-r--r-- | includes/classes/FisheyeBase.php | 268 | ||||
| -rw-r--r-- | includes/classes/FisheyeGallery.php | 1120 | ||||
| -rw-r--r-- | includes/classes/FisheyeImage.php | 900 | ||||
| -rw-r--r-- | includes/classes/FisheyeRemote.php | 351 | ||||
| -rw-r--r-- | includes/display_fisheye_gallery_inc.php | 59 | ||||
| -rw-r--r-- | includes/display_fisheye_image_inc.php | 25 | ||||
| -rw-r--r-- | includes/gallery_lookup_inc.php | 25 | ||||
| -rw-r--r-- | includes/image_lookup_inc.php | 46 | ||||
| -rw-r--r-- | includes/upload_inc.php | 360 |
9 files changed, 3154 insertions, 0 deletions
diff --git a/includes/classes/FisheyeBase.php b/includes/classes/FisheyeBase.php new file mode 100644 index 0000000..1519151 --- /dev/null +++ b/includes/classes/FisheyeBase.php @@ -0,0 +1,268 @@ +<?php +/** + * @package fisheye + */ + +/** + * required setup + */ +require_once( LIBERTY_PKG_CLASS_PATH.'LibertyMime.php' ); // FisheyeGallery base class + +/** + * @package fisheye + */ +abstract class FisheyeBase extends LibertyMime +{ + // Path of gallery images to get breadcrumbs + public $mGalleryPath; + + abstract public static function getServiceKey(); + + public function __sleep() { + return array_merge( parent::__sleep(), array( 'mGalleryPath' ) ); + } + + function __construct() { + $this->mGalleryPath = ''; + parent::__construct(); + } + + // regular expression to determine if the title was computer generated + function isMachineName( $pString ) { + return( preg_match( '/(^[0-9][-0-9 ]*$)|(^[-0-9 ]*(img|dsc|dscn|pict|htg|dscf|p)[-0-9 ][-0-9 ]*.*$)/i', trim( $pString ) ) ); + } + + // Gets a list of galleries which this item is attached to + function getParentGalleries( $pContentId=NULL ) { + if( !$this->verifyId( $pContentId ) ) { + $pContentId = $this->mContentId; + } + $ret = NULL; + + if( is_numeric( $pContentId ) ) { + $sql = "SELECT fg.`gallery_id` AS `hash_key`, fg.*, lc.`title` + FROM `".BIT_DB_PREFIX."fisheye_gallery` fg, `".BIT_DB_PREFIX."liberty_content` lc, `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim + WHERE fgim.`item_content_id` = ? AND fgim.`gallery_content_id`=fg.`content_id` AND fg.`content_id`=lc.`content_id`"; + $ret = $this->mDb->getAssoc( $sql, array( $pContentId ) ); + } + return $ret; + } + + function loadParentGalleries() { + if( $this->isValid() ) { + $this->mInfo['parent_galleries'] = $this->getParentGalleries(); + } + } + + function updatePosition($pGalleryContentId, $newPosition = NULL) { + if( $pGalleryContentId && $newPosition && $this->verifyId($this->mContentId) ) { + // SQL optimization to prevent stupid updates of identical data + if( $radixPosition = strpos( $newPosition, '.' ) ) { + // clean out newPosition to be a valid float, and nuke all extra . or extra crap + $significand = substr( $newPosition, 0, $radixPosition ); + $mantissa = preg_replace( '/[^0-9]/', '', substr( $newPosition, $radixPosition + 1 ) ); + $newPosition = $significand.'.'.$mantissa; + } + $cleanPosition = preg_replace( '/\./', '', $newPosition ); + $sql = "UPDATE `".BIT_DB_PREFIX."fisheye_gallery_image_map` SET `item_position` = ? + WHERE `item_content_id` = ? AND `gallery_content_id` = ? AND (`item_position` IS NULL OR `item_position`!=?)"; + $rs = $this->mDb->query($sql, array($newPosition, $this->mContentId, $pGalleryContentId, $newPosition)); + } + } + + function setGalleryPath( $pPath ) { + $this->setField( 'gallery_path', rtrim( $pPath, '/' ) ); + } + + function getThumbnailContentId() { + // PURE VIRTUAL + } + + function loadThumbnail( $pSize='small', $pContentId=NULL ) { + // Default does nothing + } + + // Possible derived read-only object such as Facebook, Instagram, etc.. default is TRUE + function isEditable() { + return TRUE; + } + + // THis is a function that creates a mack daddy function to get a breadcrumb path with a single query. + // Do not muck with this query unless you really, truly understand what is going on. +/* +not ready for primetime + function getPaths() { + global $gBitDb; + + $ret = NULL; + if( $this->isValid() ) { + if( $this->mDb->isAdvancedPostgresEnabled() ) { + $bindVars = array(); + $containVars = array(); + $selectSql = ''; + $joinSql = ''; + $whereSql = ''; + + $query = "SELECT fg.gallery_id, branch + FROM connectby('`".BIT_DB_PREFIX."fisheye_gallery_image_map`', '`gallery_content_id`', '`item_content_id`', ?, 0, '/') AS t(cb_item_content_id int,cb_gallery_content_id int, level int, branch text) + INNER JOIN `".BIT_DB_PREFIX."fisheye_gallery` fg ON (fg.`content_id`=cb_item_content_id) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON(lc.`content_id`=fg.`content_id`) + ORDER BY level DESC, branch, lc.`title`"; + if( $ret = $gBitDb->GetAssoc( $query, array( $this->mContentId ) ) ) { + } + } + } + return $ret; + } +*/ + + function getBreadcrumbLinks( $pIncludeSelf = FALSE ) { + global $gBitSystem; + //$ret['fisheye'] = $gBitSystem->getConfig('site_title'); + $ret = array(); + if( !$this->getField( 'gallery_path' ) ) { + if( $this->isValid() && $parents = $this->getParentGalleries() ) { + $gal = current( $parents ); + $this->setGalleryPath( '/'.$gal['gallery_id'] ); + } + } + if( $this->getField( 'gallery_path' ) ) { + $path = explode( '/', ltrim( $this->getField( 'gallery_path' ), '/' ) ); + $p = 0; + $c = 1; + $joinSql = ''; + $selectSql = '';//AS title$g, fg$g.gallery_id AS gallery_id$g"; + $whereSql = ''; + $bindVars = array(); + // We need to get min_content_status_id + $pListHash = array(); + LibertyContent::prepGetList($pListHash); + foreach( $path as $galleryId ) { + if( $galleryId ) { + $p++; $c++; + $selectSql .= " lc$p.`title` AS `title$p`, fg$p.`gallery_id` AS `gallery_id$p`,"; + $joinSql .= " `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim$p + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc$p ON(fgim$p.`gallery_content_id`=lc$p.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."fisheye_gallery` fg$p ON(fg$p.`content_id`=lc$p.`content_id`),"; + $whereSql .= " fg$p.`gallery_id`=? AND fgim$p.`item_content_id`=lc$c.`content_id` AND lc$p.`content_status_id` > ? AND"; + array_push( $bindVars, $galleryId ); + array_push( $bindVars, $pListHash['min_content_status_id']); + } + } +// $selectSql .= " lc$c.title AS title$c ";//AS title$g, fg$g.gallery_id AS gallery_id$g"; + $joinSql .= " `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim$c + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc$c ON(fgim$c.`item_content_id`=lc$c.`content_id`) "; + $whereSql .= " lc$c.`content_id`=? AND fgim$c.`gallery_content_id`=lc$p.`content_id` "; + array_push( $bindVars, $this->mContentId ); + $rs = $this->mDb->query( "SELECT ".rtrim( $selectSql, ',')." FROM ".rtrim( $joinSql, ',')." WHERE $whereSql", $bindVars ); + if( !empty( $rs->fields ) ) { + for( $i = 1; $i <= (count( $rs->fields ) / 2); $i++ ) { + $ret[$rs->fields['gallery_id'.$i]] = $rs->fields['title'.$i]; + } + } + } + + if( $this->isValid() && $pIncludeSelf && is_a( $this, 'FisheyeGallery' ) ) { + $ret[$this->mGalleryId] = $this->getTitle(); + } + + return $ret; + } + + + function addToGalleries( $pGalleryArray ) { + global $gBitSystem; + if( $this->isValid() ) { + $inGalleries = $this->mDb->getAssoc( "SELECT `gallery_id`,`gallery_content_id` FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim INNER JOIN `".BIT_DB_PREFIX."fisheye_gallery` fg ON (fgim.`gallery_content_id`=fg.`content_id`) WHERE `item_content_id` = ?", array( $this->mContentId ) ); + $galleries = array(); + if( count( $pGalleryArray ) ) { + foreach( $pGalleryArray as $galleryId ) { + // image has been requested to be put in a new gallery + if( !is_numeric( $galleryId ) ) { + switch( $galleryId ) { + case 'newest': + $galleryId = $this->mDb->getAssoc( "SELECT `gallery_id` FROM `".BIT_DB_PREFIX."fisheye_gallery` fg INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (fg.`content_id`=lg.`content_id`) WHERE `user_id` = ? ORDER BY gallery_id DESC", array( $this->getField( 'user_id' ) ) ); + break; + + } + } + if( empty( $inGalleries[$galleryId] ) ) { + if( empty( $galleries[$galleryId] ) ) { + if( $galleries[$galleryId] = FisheyeGallery::lookup( array( 'gallery_id' => $galleryId ) ) ) { + $galleries[$galleryId]->load(); + } + } + if( $galleries[$galleryId] && $galleries[$galleryId]->isValid() ) { + if( $galleries[$galleryId]->hasUserPermission( 'p_fisheye_upload', TRUE, FALSE ) || $galleries[$galleryId]->isPublic() ) { + if( $gBitSystem->isFeatureActive( 'fisheye_gallery_default_sort_mode' ) ) { + $pos = NULL; + } else { + $query = "SELECT MAX(`item_position`) + FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim + INNER JOIN `".BIT_DB_PREFIX."fisheye_gallery` fg ON(fgim.`gallery_content_id`=fg.`content_id`) + WHERE fg.`gallery_id`=?"; + $pos = $this->mDb->getOne( $query, array( $galleryId ) ) + 10; + } + + $galleries[$galleryId]->addItem( $this->mContentId, $pos ); + } else { + $this->mErrors[] = "You do not have permission to attach ".$this->getTitle()." to ".$galleries[$galleryId]->getTitle(); + } + } + } else { + // image already in an existing gallery. + unset( $inGalleries[$galleryId] ); + } + } + } + if( count( $inGalleries ) ) { + // if we have any left over in the inGalleries array, we should delete them. these were the "unchecked" boxes + foreach( $inGalleries as $galleryId ) { + $sql = "DELETE FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` WHERE `gallery_content_id` = ? AND `item_content_id` = ?"; + $rs = $this->mDb->query($sql, array( $galleryId, $this->mContentId ) ); + } + } + } + } + + function isPublic() { + if( $this->isValid() ) { + return ( $this->getPreference( 'is_public' ) == 'y' ); + } + } + + function isInGallery( $pGalleryContentId, $pItemContentId = NULL) { + if( !$this->verifyId( $pItemContentId ) ) { + $pItemContentId = $this->mContentId; + } + $ret = FALSE; + if ( is_numeric( $this->mGalleryId ) && is_numeric( $pGalleryContentId ) ) { + + if( $this->mDb->isAdvancedPostgresEnabled() ) { + global $gBitDb, $gBitSmarty; + // This code pulls all branches for the current node and determines if there is a path from this content to the root + // without hitting a security_id. If there is clear path it returns TRUE. If there is a security_id, then + // it determines if the current user has permission + $query = "SELECT branch,level,cb_item_content_id,cb_gallery_content_id + FROM connectby('`".BIT_DB_PREFIX."fisheye_gallery_image_map`', '`gallery_content_id`', '`item_content_id`', ?, 0, '/') AS t(`cb_gallery_content_id` int,`cb_item_content_id` int, `level` int, `branch` text) + WHERE `cb_gallery_content_id`=? + ORDER BY branch + "; + if ( $this->mDb->getOne($query, array( $pItemContentId, $pGalleryContentId ) ) ) { + $ret = TRUE; + } + } else { + $sql = "SELECT count(`item_content_id`) as `item_count` + FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` + WHERE `gallery_content_id` = ? AND `item_content_id` = ?"; + $rs = $this->mDb->query($sql, array($pGalleryContentId, $pItemContentId)); + if ($rs->fields['item_count'] > 0) { + $ret = TRUE; + } + } + } + return $ret; + } + +} +?> diff --git a/includes/classes/FisheyeGallery.php b/includes/classes/FisheyeGallery.php new file mode 100644 index 0000000..b0f710d --- /dev/null +++ b/includes/classes/FisheyeGallery.php @@ -0,0 +1,1120 @@ +<?php +/** + * @package fisheye + */ + +/** + * required setup + */ +require_once( FISHEYE_PKG_CLASS_PATH.'FisheyeImage.php' ); // A gallery is composed of FisheyeImages + +define('FISHEYEGALLERY_CONTENT_TYPE_GUID', 'fisheyegallery' ); + +define( 'FISHEYE_PAGINATION_FIXED_GRID', 'fixed_grid' ); +define( 'FISHEYE_PAGINATION_AUTO_FLOW', 'auto_flow' ); +define( 'FISHEYE_PAGINATION_POSITION_NUMBER', 'position_number' ); +define( 'FISHEYE_PAGINATION_SIMPLE_LIST', 'simple_list' ); +define( 'FISHEYE_PAGINATION_MATTEO', 'matteo' ); +define( 'FISHEYE_PAGINATION_GALLERIFFIC', 'galleriffic' ); + +/** + * FisheyeBase extends LibertyMime, which this class doesn't need, but we need a common base class + * + * @package fisheye + */ +class FisheyeGallery extends FisheyeBase { + public $mGalleryId; // fisheye_gallery.gallery_id + public $mItems; // Array of FisheyeImage class instances which belong to this gallery + + function __construct($pGalleryId = NULL, $pContentId = NULL) { + parent::__construct(); + if( $this->verifyId( $pGalleryId ) ) { + $this->mGalleryId = (int)$pGalleryId; // Set member variables according to the parameters we were passed + } + if( $this->verifyId( $pContentId ) ) { + $this->mContentId = (int)$pContentId; // liberty_content.content_id which this gallery references + } + $this->mItems = array(); // Assume no images (if $pAutoLoad is TRUE we will populate this array later) + $this->mAdminContentPerm = 'p_fisheye_admin'; + + // This registers the content type for FishEye galleries + // FYI: Any class which uses a table which inherits from liberty_content should create their own content type(s) + $this->registerContentType( + FISHEYEGALLERY_CONTENT_TYPE_GUID, array( 'content_type_guid' => FISHEYEGALLERY_CONTENT_TYPE_GUID, + 'content_name' => 'Image Gallery', + 'content_name_plural' => 'Image Galleries', + 'handler_class' => 'FisheyeGallery', + 'handler_package' => 'fisheye', + 'handler_file' => 'FisheyeGallery.php', + 'maintainer_url' => 'http://www.bitweaver.org' + )); + + // Permission setup + $this->mViewContentPerm = 'p_fisheye_view'; + $this->mCreateContentPerm = 'p_fisheye_create'; + $this->mUpdateContentPerm = 'p_fisheye_update'; + $this->mAdminContentPerm = 'p_fisheye_admin'; + } + + public function __wakeup() { + return parent::__wakeup(); + } + + public function __sleep() { + return array_merge( parent::__sleep(), array( 'mGalleryId' ) ); + } + + function isValid() { + return( @$this->verifyId( $this->mGalleryId ) || @$this->verifyId( $this->mContentId ) ); + } + + public static function lookup( $pLookupHash, $pLoadFromCache=TRUE ) { + global $gBitDb; + $ret = NULL; + + $lookupContentId = NULL; + if (!empty($pLookupHash['gallery_id']) && is_numeric($pLookupHash['gallery_id'])) { + if( $lookup = $gBitDb->getRow( "SELECT lc.`content_id`, lc.`content_type_guid` FROM `".BIT_DB_PREFIX."fisheye_gallery` fg INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON(lc.`content_id`=fg.`content_id`) WHERE `gallery_id`=?", array( $pLookupHash['gallery_id'] ) ) ) { + $lookupContentId = $lookup['content_id']; + $lookupContentGuid = $lookup['content_type_guid']; + } + } elseif (!empty($pLookupHash['content_id']) && is_numeric($pLookupHash['content_id'])) { + $lookupContentId = $pLookupHash['content_id']; + $lookupContentGuid = NULL; + } + + if( static::verifyId( $lookupContentId ) ) { + $ret = parent::getLibertyObject( $lookupContentId, $lookupContentGuid, $pLoadFromCache ); + } + + return $ret; + } + + function load( $pContentId = NULL, $pPluginParams = NULL ) { + global $gBitSystem; + $bindVars = array(); + $selectSql = $joinSql = $whereSql = ''; + + if( @$this->verifyId( $this->mGalleryId ) ) { + $whereSql = " WHERE fg.`gallery_id` = ?"; + $bindVars = array( $this->mGalleryId ); + } elseif ( @$this->verifyId( $this->mContentId ) ) { + $whereSql = " WHERE fg.`content_id` = ?"; + $bindVars = array($this->mContentId); + } else { + $whereSql = NULL; + } + + if ($whereSql) { // If we have some way to know what fisheye_gallery row to load... + $this->getServicesSql( 'content_load_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + $query = "SELECT fg.*, lc.* $selectSql + , uue.`login` AS modifier_user, uue.`real_name` AS `modifier_real_name` + , uuc.`login` AS creator_user, uuc.`real_name` AS `creator_real_name` + FROM `".BIT_DB_PREFIX."fisheye_gallery` fg + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (fg.`content_id` = lc.`content_id`) $joinSql + LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON (uue.`user_id` = lc.`modifier_user_id`) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON (uuc.`user_id` = lc.`user_id`) + $whereSql"; + + if( $rs = $this->mDb->query($query, $bindVars) ) { + $this->mInfo = $rs->fields; + $this->mContentId = $rs->fields['content_id']; + LibertyContent::load(); + if( @$this->verifyId($this->mInfo['gallery_id'] ) ) { + + $this->mGalleryId = $this->mInfo['gallery_id']; + $this->mContentId = $this->mInfo['content_id']; + + $this->mInfo['creator'] = (isset( $rs->fields['creator_real_name'] ) ? $rs->fields['creator_real_name'] : $rs->fields['creator_user'] ); + $this->mInfo['editor'] = (isset( $rs->fields['modifier_real_name'] ) ? $rs->fields['modifier_real_name'] : $rs->fields['modifier_user'] ); + + // Set some basic defaults for how to display a gallery if they're not already set + if (empty($this->mInfo['thumbnail_size'])) { + $this->mInfo['thumbnail_size'] = $this->getPreference( 'fisheye_gallery_default_thumbnail_size', NULL ); + } + if (empty($this->mInfo['rows_per_page'])) { + $this->mInfo['rows_per_page'] = $this->getPreference('fisheye_gallery_default_rows_per_page', FISHEYE_DEFAULT_ROWS_PER_PAGE); + } + if (empty($this->mInfo['cols_per_page'])) { + $this->mInfo['cols_per_page'] = $this->getPreference('fisheye_gallery_default_cols_per_page', FISHEYE_DEFAULT_COLS_PER_PAGE); + } + if (empty($this->mInfo['access_answer'])) { + $this->mInfo['access_answer'] = ''; + } + if ( $this->getPreference( 'gallery_pagination' ) == FISHEYE_PAGINATION_GALLERIFFIC and empty($this->mInfo['galleriffic_style'])) { + $this->mInfo['galleriffic_style'] = $this->getPreference('galleriffic_style', 1); + } + + $this->mInfo['num_images'] = $this->getImageCount(); + if( $this->getPreference( 'gallery_pagination' ) == FISHEYE_PAGINATION_POSITION_NUMBER ) { + $this->mInfo['num_pages'] = $this->mDb->getOne( "SELECT COUNT( distinct( floor(`item_position`) ) ) FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` WHERE gallery_content_id=?", array( $this->mContentId ) ); + } else { + $this->mInfo['images_per_page'] = ($this->mInfo['cols_per_page'] * $this->mInfo['rows_per_page']); + $this->mInfo['num_pages'] = (int)($this->mInfo['num_images'] / $this->mInfo['images_per_page'] + ($this->mInfo['num_images'] % $this->mInfo['images_per_page'] == 0 ? 0 : 1)); + } + + } else { + unset( $this->mContentId ); + unset( $this->mGalleryId ); + } + + } + } + + return count($this->mInfo); + } + + function loadCurrentImage( $pCurrentImageId ) { + if( $this->isValid() && @$this->verifyId( $pCurrentImageId ) ) { + // this code sucks but works - XOXO spiderr + $query = "SELECT fgim.*, fi.`image_id`, lf.`file_name`, lf.`user_id`, lf.`mime_type`, la.`attachment_id` + FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim + INNER JOIN `".BIT_DB_PREFIX."fisheye_image` fi ON ( fi.`content_id`=fgim.`item_content_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_attachments` la ON ( fi.`content_id`=la.`content_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_files` lf ON ( lf.`file_id`=la.`foreign_id` ) + WHERE fgim.`gallery_content_id` = ? + ORDER BY fgim.`item_position`, fi.`content_id` "; + if( $rs = $this->mDb->query($query, array( $this->mContentId ) ) ) { + $tempImage = new FisheyeImage(); + $rows = $rs->getRows(); + for( $i = 0; $i < count( $rows ); $i++ ) { + if( $rows[$i]['image_id'] == $pCurrentImageId ) { + if( $i > 0 ) { + $this->mInfo['previous_image_id'] = $rows[$i-1]['image_id']; + $this->mInfo['previous_image_avatar'] = liberty_fetch_thumbnail_url( array( + 'file_name' => $rows[$i-1]['file_name'], + 'source_file' => $tempImage->getSourceFile( $rows[$i-1] ), + 'mime_image' => TRUE, + 'size' => 'avatar', + )); + } + if( $i + 1 < count( $rows ) ) { + $this->mInfo['next_image_id'] = $rows[$i+1]['image_id']; + $this->mInfo['next_image_avatar'] = liberty_fetch_thumbnail_url( array( + 'file_name' => $rows[$i+1]['file_name'], + 'source_file' => $tempImage->getSourceFile( $rows[$i+1] ), + 'mime_image' => TRUE, + 'size' => 'avatar', + )); + } + } + } + } + } + } + + public function loadImages( $pPage=-1, $pImagesPerPage=-1, $pRefresh=FALSE ) { + global $gLibertySystem, $gBitSystem, $gBitUser; + if( !$this->isValid() ) { + return NULL; + } + if( empty( $this->mItems ) || $pRefresh ) { + $bindVars = array($this->mContentId); + $whereSql = $selectSql = $joinSql = $orderSql = ''; + $rowCount = $offset = NULL; + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + if( $gBitSystem->isFeatureActive( 'fisheye_gallery_default_sort_mode' ) ) { + $orderSql = ", ".$this->mDb->convertSortmode( $gBitSystem->getConfig( 'fisheye_gallery_default_sort_mode' ) ); + } else { + $orderSql = ", fgim.`item_content_id`"; + } + + // load for just a single page + if( $pPage != -1 ) { + if( $this->getLayout() == FISHEYE_PAGINATION_POSITION_NUMBER ) { + $query = "SELECT DISTINCT(FLOOR(`item_position`)) + FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` + WHERE gallery_content_id=? + ORDER BY floor(item_position)"; + $mantissa = $this->mDb->getOne( $query, array( $this->mContentId ), 1, ($pPage - 1) ); + // gallery image order with no positions set will have NULL mantissa, and all images will be shown + if( !is_null( $mantissa ) ) { + $whereSql .= " AND floor(item_position)=? "; + array_push( $bindVars, $mantissa ); + } + } elseif( $this->getLayout() == FISHEYE_PAGINATION_FIXED_GRID ) { + $rowCount = $this->getField( 'rows_per_page' ) * $this->getField( 'cols_per_page' ); + $offset = $rowCount * ($pPage - 1); + } else { + $rowCount = $pImagesPerPage; + $offset = $rowCount * ($pPage - 1); + } + } + + $this->mItems = array(); + + $query = "SELECT fgim.*, lc.`user_id`, lct.*, ufm.`favorite_content_id` AS is_favorite $selectSql + FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id`=fgim.`item_content_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_content_types` lct ON ( lct.`content_type_guid`=lc.`content_type_guid` ) + $joinSql + LEFT OUTER JOIN `".BIT_DB_PREFIX."users_favorites_map` ufm ON ( ufm.`favorite_content_id`=lc.`content_id` AND lc.`user_id`=ufm.`user_id` ) + WHERE fgim.`gallery_content_id` = ? $whereSql + ORDER BY fgim.`item_position` $orderSql"; + $rs = $this->mDb->query($query, $bindVars, $rowCount, $offset); + $rows = $rs->getRows(); + foreach ($rows as $row) { + $pass = TRUE; + if( $gBitSystem->isPackageActive( 'gatekeeper' ) ) { + $pass = $gBitUser->hasPermission( 'p_fisheye_admin' ) || !@$this->verifyId( $row['security_id'] ) || ( $row['user_id'] == $gBitUser->mUserId ) || @$this->verifyId( $_SESSION['gatekeeper_security'][$row['security_id']] ); + } + if( $pass ) { + if( $item = parent::getLibertyObject( $row['item_content_id'], $row['content_type_guid'], $this->isCacheableObject() ) ) { + $item->loadThumbnail( $this->mInfo['thumbnail_size'] ); + $item->setGalleryPath( $this->mGalleryPath.'/'.$this->mGalleryId ); + $item->mInfo['item_position'] = $row['item_position']; + $this->mItems[$row['item_content_id']] = $item; + } + } + } + } + return count( $this->mItems ); + } + + function getImageList() { + global $gLibertySystem, $gBitSystem, $gBitUser; + $ret = NULL; + if( $this->isValid() ) { + $bindVars = array($this->mContentId); + $whereSql = $selectSql = $joinSql = $orderSql = ''; + $rows = $offset = NULL; + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + if( $gBitSystem->isFeatureActive( 'fisheye_gallery_default_sort_mode' ) ) { + $orderSql = ", ".$this->mDb->convertSortmode( $gBitSystem->getConfig( 'fisheye_gallery_default_sort_mode' ) ); + } else { + $orderSql = ", fgim.`item_content_id`"; + } + + $this->mItems = array(); + + $query = "SELECT lc.`content_id` AS `has_key`, fgim.*, lc.*, lct.*, fi.`image_id`, ufm.`favorite_content_id` AS is_favorite $selectSql + FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id`=fgim.`item_content_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_content_types` lct ON ( lct.`content_type_guid`=lc.`content_type_guid` ) + LEFT OUTER JOIN `".BIT_DB_PREFIX."fisheye_image` fi ON ( fgim.`item_content_id`=fi.`content_id` ) + $joinSql + LEFT OUTER JOIN `".BIT_DB_PREFIX."users_favorites_map` ufm ON ( ufm.`favorite_content_id`=lc.`content_id` AND lc.`user_id`=ufm.`user_id` ) + WHERE fgim.`gallery_content_id` = ? $whereSql + ORDER BY fgim.`item_position` $orderSql"; + $ret = $this->mDb->getAssoc($query, $bindVars, $rows, $offset); + } + return $ret; + } + + function exportHash( $pPaginate = FALSE ) { + if( $ret = parent::exportHash() ) { + $ret['type'] = $this->getContentType(); + if( $this->loadImages() ) { + foreach( array_keys( $this->mItems ) as $key ) { + if( $pPaginate ) { + if( $exp = $this->mItems[$key]->exportHash( $pPaginate ) ) { + $ret['content']['page'][$this->getItemPage($key)][] = $exp; + } + } else { + $ret['content'][] = $this->mItems[$key]->exportHash( $pPaginate ); + } + } + } + } + return $ret; + } + + function getItemPage( $pItemContentId ) { + $ret = NULL; + if( empty( $this->mPaginationLookup ) ) { + $this->mPaginationLookup = $this->mDb->getAssoc( "SELECT `item_content_id`, floor(`item_position`) FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` WHERE `gallery_content_id`=?", array( $this->mContentId ) ); + } + if( !empty( $this->mPaginationLookup[$pItemContentId] ) ) { + $ret = $this->mPaginationLookup[$pItemContentId]; + } + return $ret; + } + + function getPreviewHash() { + $ret = array(); + if( !empty( $this->mInfo['preview_content'] ) ) { + $ret = $this->mInfo['preview_content']->mInfo; + } + // override $this->mInfo['preview_content']->mInfo['display_url'] so we don't drive directly to the image + $ret['display_url'] = $this->getDisplayUrl(); + return $ret; + } + + function getImageCount() { + $ret = 0; + + if ($this->mGalleryId) { + $bindVars = array($this->mContentId); + $whereSql = $selectSql = $joinSql = $orderSql = ''; + $rows = $offset = NULL; + $paramHash['no_fatal'] = TRUE; + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars, NULL, $paramHash ); + $query = 'SELECT COUNT(*) AS "count" + FROM `'.BIT_DB_PREFIX."fisheye_gallery_image_map` fgim + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id`=fgim.`item_content_id` ) + $joinSql WHERE `gallery_content_id` = ? $whereSql"; + $rs = $this->mDb->query($query, $bindVars); + $ret = $rs->fields['count']; + } + return $ret; + } + + function verifyGalleryData(&$pStorageHash) { + global $gBitSystem; + + if (empty($pStorageHash['rows_per_page'])) { + $pStorageHash['rows_per_page'] = $gBitSystem->getConfig('fisheye_gallery_default_rows_per_page', (!empty($this->mInfo['rows_per_page']) ? $this->mInfo['rows_per_page'] : FISHEYE_DEFAULT_ROWS_PER_PAGE)); + } + + if (empty($pStorageHash['cols_per_page'])) { + $pStorageHash['cols_per_page'] = $gBitSystem->getConfig('fisheye_gallery_default_cols_per_page', (!empty($this->mInfo['cols_per_page']) ? $this->mInfo['cols_per_page'] : FISHEYE_DEFAULT_COLS_PER_PAGE)); + } + + if (empty($pStorageHash['thumbnail_size'])) { + $pStorageHash['thumbnail_size'] = $gBitSystem->getConfig('fisheye_gallery_default_thumbnail_size', (!empty($this->mInfo['thumbnail_size']) ? $this->mInfo['thumbnail_size'] : NULL )); + } + + if (empty($pStorageHash['title'])) { + $this->mErrors[] = "You must specify a title for this image gallery"; + } + + $pStorageHash['content_type_guid'] = $this->getContentType(); + + return (count($this->mErrors) == 0); + } + + + function generateThumbnails() { + if( $this->isValid() ) { + if( $this->loadImages() ) { + foreach( array_keys( $this->mItems ) as $key ) { + $this->mItems[$key]->generateThumbnails(); + } + } + } + } + + + function getThumbnailContentId() { + if( !$this->getField( 'thumbnail_content_id' ) ) { + $this->getThumbnailImage(); + } + return( $this->getField( 'thumbnail_content_id' ) ); + } + + function getThumbnailUri( $pSize='small', $pInfoHash = NULL ) { + if( empty( $this->mInfo['preview_content'] ) ) { + $this->loadThumbnail(); + } + + if( is_object( $this->mInfo['preview_content'] ) ) { + return $this->mInfo['preview_content']->getThumbnailUri( $pSize ); + } + } + + + function getThumbnailUrl( $pSize = 'small', $pInfoHash = NULL, $pSecondaryId = NULL, $pDefault=TRUE ) { + if( empty( $this->mInfo['preview_content'] ) ) { + $this->loadThumbnail(); + } + + if( is_object( $this->mInfo['preview_content'] ) ) { + return $this->mInfo['preview_content']->getThumbnailUrl( $pSize ); + } + } + + + function getThumbnailImage( $pContentId=NULL, $pThumbnailContentId=NULL, $pThumbnailContentType=NULL ) { + global $gLibertySystem, $gBitUser; + $ret = NULL; + + if( !@$this->verifyId( $pContentId ) && !empty( $this->mContentId ) ) { + $pContentId = $this->mContentId; + } + + if( !@$this->verifyId( $pThumbnailContentId ) ) { + if( @$this->verifyId( $this->mInfo['preview_content_id'] ) ) { + $pThumbnailContentId = $this->mInfo['preview_content_id']; + } else { + if( $this->mDb->isAdvancedPostgresEnabled() ) { + $whereSql = ''; + $bindVars = array( $pContentId ); + if( !$gBitUser->isAdmin() ) { + $whereSql = " AND (cgm.`security_id` IS NULL OR lc.`user_id`=?) "; + $bindVars[] = $gBitUser->mUserId; + } + $query = "SELECT COALESCE( fg.`preview_content_id`, lc.`content_id` ) AS `content_id`, lc.`content_type_guid` + FROM connectby('`".BIT_DB_PREFIX."fisheye_gallery_image_map`', '`item_content_id`', '`gallery_content_id`', ?, 0, '/') AS t(`cb_item_content_id` int, `cb_parent_content_id` int, `level` int, `branch` text) + INNER JOIN liberty_content lc ON(content_id=cb_item_content_id) + LEFT OUTER JOIN `".BIT_DB_PREFIX."gatekeeper_security_map` cgm ON (cgm.`content_id`=lc.`content_id`), `".BIT_DB_PREFIX."fisheye_gallery` fg + WHERE `cb_parent_content_id`=fg.`content_id` $whereSql "; // ORDER BY RANDOM() is DOG slow (seq scans) + if( $row = $this->mDb->getRow( $query, $bindVars ) ) { + $pThumbnailContentType = $row['content_type_guid']; + $pThumbnailContentId = $row['content_id']; + } + } else { + $query = "SELECT fgim.`item_content_id`, lc.`content_type_guid` + FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( fgim.`item_content_id`=lc.`content_id` ) + WHERE fgim.`gallery_content_id` = ? + ORDER BY ".$this->mDb->convertSortmode('random'); + $rs = $this->mDb->query($query, array( $pContentId ), 1); + if( !empty( $rs->fields ) ) { + $pThumbnailContentId = $rs->fields['item_content_id']; + $pThumbnailContentType = $rs->fields['content_type_guid']; + } + } + } + } + + if( @$this->verifyId( $pThumbnailContentId ) ) { + $ret = parent::getLibertyObject( $pThumbnailContentId, $pThumbnailContentType, $this->isCacheableObject() ); + if( is_a( $ret, 'FisheyeGallery' ) ) { + //recurse down in to find the first image + if( $ret = $ret->getThumbnailImage() ) { + $this->mInfo['thumbnail_content_id'] = $ret->getField( 'content_id' ); + } + } else { + $this->mInfo['thumbnail_content_id'] = $pThumbnailContentId; + } + } + return $ret; + } + + + function loadThumbnail( $pSize='small', $pContentId=NULL ) { + if( $this->mPreviewImage = $this->getThumbnailImage( $pContentId ) ) { + $this->mInfo['preview_content'] = &$this->mPreviewImage; + $this->mInfo['image_file'] = &$this->mPreviewImage->mInfo['image_file']; + } + } + + + function storeGalleryThumbnail($pContentId = NULL) { + $ret = FALSE; + if ($pContentId && !$this->isInGallery( $this->mContentId, $pContentId ) ) { + return FALSE; + } + if ($this->mGalleryId) { + if (!$pContentId) + $pContentId = NULL; + $query = "UPDATE `".BIT_DB_PREFIX."fisheye_gallery` SET `preview_content_id` = ? WHERE `gallery_id`= ?"; + $rs = $this->mDb->query($query, array($pContentId, $this->mGalleryId)); + $this->mInfo['preview_content_id'] = $pContentId; + $ret = TRUE; + } + return $ret; + } + + function store(&$pStorageHash) { + if ($this->verifyGalleryData($pStorageHash)) { + $this->StartTrans(); + if( LibertyContent::store($pStorageHash)) { + $this->mContentId = $pStorageHash['content_id']; + $this->mInfo['content_id'] = $this->mContentId; + if ($this->galleryExistsInDatabase()) { + $query = "UPDATE `".BIT_DB_PREFIX."fisheye_gallery` + SET `rows_per_page` = ?, `cols_per_page` = ?, `thumbnail_size` = ? + WHERE `gallery_id` = ?"; + $bindVars = array($pStorageHash['rows_per_page'], $pStorageHash['cols_per_page'], $pStorageHash['thumbnail_size'], $this->mGalleryId); + } else { + $this->mGalleryId = $this->mDb->GenID('fisheye_gallery_id_seq'); + $this->mInfo['gallery_id'] = $this->mGalleryId; + $query = "INSERT INTO `".BIT_DB_PREFIX."fisheye_gallery` (`gallery_id`, `content_id`, `rows_per_page`, `cols_per_page`, `thumbnail_size`) VALUES (?,?,?,?,?)"; + $bindVars = array($this->mGalleryId, $this->mContentId, $pStorageHash['rows_per_page'], $pStorageHash['cols_per_page'], $pStorageHash['thumbnail_size']); + } + $rs = $this->mDb->query($query, $bindVars); + $this->CompleteTrans(); + } else { + $this->mDb->RollbackTrans(); + $this->mErrors[] = "There were errors while attempting to save this gallery"; + } + } else { + $this->mErrors[] = "There were errors while attempting to save this gallery"; + } + + return (count($this->mErrors) == 0); + } + + function removeItem( $pContentId ) { + $ret = FALSE; + if( $this->isValid() && @$this->verifyId( $pContentId ) ) { + $query = "DELETE FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` + WHERE `item_content_id`=? AND `gallery_content_id`=?"; + $rs = $this->mDb->query($query, array($pContentId, $this->mContentId ) ); + $ret = TRUE; + } + return $ret; + } + + /** + * Adds a new item (image or gallery) to this gallery. We check to make sure we are not a member + * of this gallery and this gallery is not a member of the new item to avoid infinite recursion scenarios + * @return boolean wheter or not the item was added + */ + function addItem( $pContentId, $pPosition=NULL ) { + global $gBitSystem; + $ret = FALSE; + if( @$this->verifyId( $this->mContentId ) && @$this->verifyId( $pContentId ) && ( $this->mContentId != $pContentId ) && !$this->isInGallery( $this->mContentId, $pContentId ) && !$this->isInGallery( $pContentId, $this->mContentId ) ) { + $query = "INSERT INTO `".BIT_DB_PREFIX."fisheye_gallery_image_map` (`item_content_id`, `gallery_content_id`, `item_position`) VALUES (?,?,?)"; + $rs = $this->mDb->query($query, array($pContentId, $this->mContentId, $pPosition ) ); + $query = "UPDATE `".BIT_DB_PREFIX."liberty_content` SET `last_modified`=? WHERE `content_id`=?"; + $rs = $this->mDb->query( $query, array( $gBitSystem->getUTCTime(), $this->mContentId ) ); + $ret = TRUE; + } + return $ret; + } + + function expunge( $pRecursiveDelete = FALSE ) { + if( $this->isValid() ) { + $this->StartTrans(); + + if( $this->loadImages() ) { + foreach( array_keys( $this->mItems ) as $key ) { + if( $pRecursiveDelete ) { + $this->mItems[$key]->expunge( $pRecursiveDelete ); + } elseif( is_a( $this->mItems[$key], 'FisheyeImage' ) ) { + // make sure we have a valid content_id before we exec + if( is_numeric( $this->mItems[$key]->mContentId ) ) { + $query = "SELECT COUNT(`item_content_id`) AS `other_gallery` + FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` + WHERE `item_content_id`=? AND `gallery_content_id`!=?"; + if( !($inOtherGallery = $this->mDb->getOne($query, array($this->mItems[$key]->mContentId, $this->mContentId ) )) ) { + $this->mItems[$key]->expunge(); + } + } + } + } + } + + $query = "DELETE FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` WHERE `gallery_content_id`=?"; + $rs = $this->mDb->query($query, array( $this->mContentId ) ); + $query = "DELETE FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` WHERE `item_content_id`=?"; + $rs = $this->mDb->query($query, array( $this->mContentId ) ); + $query = "DELETE FROM `".BIT_DB_PREFIX."fisheye_gallery` WHERE `content_id`=?"; + $rs = $this->mDb->query($query, array( $this->mContentId ) ); + if( LibertyContent::expunge() ) { + $this->CompleteTrans(); + } else { + $this->mDb->RollbackTrans(); + error_log( "Error expunging fisheye gallery: " . vc($this->mErrors ) ); + } + } + return( count( $this->mErrors ) == 0 ); + } + + + function galleryExistsInDatabase() { + $ret = FALSE; + + if( @$this->verifyId( $this->mGalleryId ) ) { + $query = "SELECT COUNT(`gallery_id`) AS `gcount` + FROM `".BIT_DB_PREFIX."fisheye_gallery` + WHERE `gallery_id` = ?"; + $rs = $this->mDb->query($query, array($this->mGalleryId)); + if ($rs->fields['gcount'] > 0) + $ret = TRUE; + } + + return $ret; + } + + /** + * Returns the layout of the gallery accounting for various defaults + * @return the layout string preference + */ + function getLayout() { + global $gBitSystem; + return $this->getPreference( 'gallery_pagination', $gBitSystem->getConfig( 'default_gallery_pagination', FISHEYE_PAGINATION_GALLERIFFIC ) ); + } + + public static function getAllLayouts() { + return array( + FISHEYE_PAGINATION_GALLERIFFIC => 'Galleriffic', + FISHEYE_PAGINATION_FIXED_GRID => 'Fixed Grid', + FISHEYE_PAGINATION_AUTO_FLOW => 'Auto-Flow Images', + FISHEYE_PAGINATION_POSITION_NUMBER => 'Image Order Page Number', + FISHEYE_PAGINATION_SIMPLE_LIST => 'Simple List', +// FISHEYE_PAGINATION_MATTEO => 'Matteo', + ); + } + + /** + * Returns include file that will setup the object for rendering + * @return the fully specified path to file to be included + */ + function getRenderFile() { + return FISHEYE_PKG_INCLUDE_PATH.'display_fisheye_gallery_inc.php'; + } + + /** + * Returns template file used for display + * @return the fully specified path to file to be included + */ + function getRenderTemplate() { + return 'bitpackage:fisheye/view_gallery.tpl'; + } + + /** + * Function that returns link to display a piece of content + * @param pGalleryId id of gallery to link + * @return the url to display the gallery. + */ + public static function getDisplayUrlFromHash( &$pParamHash ) { + $path = NULL; + + if( BitBase::verifyIdParameter( $pParamHash, 'gallery_id' ) ) { + $ret = FISHEYE_PKG_URL; + global $gBitSystem; + if( $gBitSystem->isFeatureActive( 'pretty_urls' ) ) { + $ret .= 'gallery'.$path.'/'.$pParamHash['gallery_id']; + } else { + $ret .= 'view.php?gallery_id='.$pParamHash['gallery_id']; + if( !empty( $pHash['path'] ) ) { + $ret .= '&gallery_path='.$pParamHash['path']; + } + } + } elseif( @BitBase::verifyId( $pParamHash['content_id'] ) ) { + $ret = FISHEYE_PKG_URL.'view.php?content_id='.$pParamHash['content_id']; + } + return $ret; + } + + function getTree( $pListHash ) { + global $gBitDb; + + $ret = array(); + if( $this->mDb->isAdvancedPostgresEnabled() ) { + $bindVars = array(); + $containVars = array(); + $selectSql = ''; + $joinSql = ''; + $whereSql = ''; + if( !empty( $pListHash['contain_item'] ) ) { + $selectSql = " , tfgim3.`item_content_id` AS `in_gallery` "; + $joinSql .= " LEFT OUTER JOIN `".BIT_DB_PREFIX."fisheye_gallery_image_map` tfgim3 ON (tfgim3.`gallery_content_id`=lc.`content_id`) AND tfgim3.`item_content_id`=? "; + $bindVars[] = $pListHash['contain_item']; + $containVars[] = $pListHash['contain_item']; + } + if( isset( $pListHash['contain_item'] ) ) { + // contain item might have squeaked in as 0, clear our from pListHash + unset( $pListHash['contain_item'] ); + } + foreach( $pListHash as $key=>$val ) { + $whereSql .= " $key=? AND "; + $bindVars[] = $val; + } + + $query = "SELECT lc.`content_id` AS `hash_key`, fg.*, lc.* $selectSql + FROM `".BIT_DB_PREFIX."fisheye_gallery` fg + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON(fg.`content_id`=lc.`content_id`) + $joinSql + WHERE $whereSql NOT EXISTS (SELECT gallery_content_id FROM fisheye_gallery_image_map tfgim2 WHERE tfgim2.item_content_id=lc.content_id) + ORDER BY lc.title"; + $rootContent = $gBitDb->GetAssoc( $query, $bindVars ); + + foreach( array_keys( $rootContent ) as $conId ) { + $splitVars = array(); + $query = "SELECT branch AS hash_key, * $selectSql + FROM connectby('`".BIT_DB_PREFIX."fisheye_gallery_image_map`', '`item_content_id`', '`gallery_content_id`', ?, 0, '/') AS t(cb_item_content_id int,cb_gallery_content_id int, level int, branch text) + INNER JOIN `".BIT_DB_PREFIX."fisheye_gallery` fg ON (fg.`content_id`=cb_item_content_id) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON(lc.`content_id`=fg.`content_id`) + $joinSql + ORDER BY branch, lc.`title`"; + $splitVars[] = $conId; + if( !empty( $containVars ) ) { + $splitVars[] = $containVars[0]; + } + + FisheyeGallery::splitConnectByTree( $ret, $gBitDb->GetAssoc( $query, $splitVars ) ); + FisheyeGallery::getTreeSort( $ret ); + } + } else if ( $this->mDb->mType == 'firebird' ) { + $bindVars = array(); + $containVars = array(); + $selectSql = ''; + $joinSql = ''; + $whereSql = ''; + + if( !empty( $pListHash['contain_item'] ) ) { + $selectSql = " , tfgim3.`item_content_id` AS `in_gallery` "; + $joinSql .= " LEFT OUTER JOIN `".BIT_DB_PREFIX."fisheye_gallery_image_map` tfgim3 ON (tfgim3.`gallery_content_id`=lc.`content_id`) AND tfgim3.`item_content_id`=? "; + $bindVars[] = $pListHash['contain_item']; + $containVars[] = $pListHash['contain_item']; + } + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + if( isset( $pListHash['contain_item'] ) ) { + // contain item might have squeaked in as 0, clear our from pListHash + unset( $pListHash['contain_item'] ); + } + foreach( $pListHash as $key=>$val ) { + $whereSql .= " AND lc.$key=? "; + $bindVars[] = $val; + } + + $splitVars = array(); + $query = "WITH RECURSIVE + GALLERY_TREE AS ( + SELECT B.`content_id` AS gallery_content_id, B.`content_id` AS item_content_id, 0 AS BLEVEL, CAST( lcp.`title` AS VARCHAR(255) ) AS BRANCH, 0 AS gallery_parent_id + FROM `".BIT_DB_PREFIX."fisheye_gallery` B + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lcp ON(lcp.`content_id`=B.`content_id`) + WHERE NOT EXISTS (SELECT gallery_content_id FROM fisheye_gallery_image_map tfgim2 WHERE tfgim2.item_content_id=B.content_id) + + UNION ALL + + SELECT `item_content_id` AS gallery_content_id, `item_content_id`, G.BLEVEL + 1, G.BRANCH || '/' || `item_content_id` AS BRANCH, `gallery_content_id` AS gallery_parent_id + FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` G1 + JOIN GALLERY_TREE G + ON G1.`gallery_content_id` = G.`item_content_id` + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lcg1 ON(lcg1.`content_id`=`item_content_id`) and lcg1.`content_type_guid` = 'fisheyegallery' + ) + SELECT T.BRANCH AS hash_key, T.BLEVEL, fg.*, lc.* $selectSql + FROM GALLERY_TREE T + INNER JOIN `".BIT_DB_PREFIX."fisheye_gallery` fg ON (fg.`content_id`=T.`gallery_content_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lc.`content_id`=T.`item_content_id`) + LEFT OUTER JOIN `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgimo ON (fgimo.`gallery_content_id`=T.gallery_parent_id) AND fgimo.`item_content_id`=T.gallery_content_id + $joinSql + WHERE lc.`content_type_guid` = 'fisheyegallery' $whereSql + ORDER BY T.BRANCH, fgimo.`item_position`"; + + + + if( !empty( $bindVars ) ) { + FisheyeGallery::splitConnectByTree( $ret, $gBitDb->GetAssoc( $query, $bindVars ) ); + } else { + FisheyeGallery::splitConnectByTree( $ret, $gBitDb->GetAssoc( $query ) ); + } + + } else { +// this needs replacing with a more suitable list query ... + $pListHash['show_empty'] = TRUE; + $galList = $this->getList( $pListHash ); + // index by content_id + foreach( $galList as $galId => $gal ) { + $ret[$gal['content_id']] = $gal; + } + FisheyeGallery::splitConnectByTree( $ret, $ret ); + FisheyeGallery::getTreeSort( $ret ); + } + return( $ret ); + } + + function getTreeSort( &$pTree ) { + if( $pTree ) { + foreach( array_keys( $pTree ) as $k ) { + if( !empty( $pTree[$k]['children'] ) ) { + FisheyeGallery::getTreeSort( $pTree[$k]['children'] ); + } + } + uasort( $pTree, array( 'FisheyeGallery', 'getTreeSortCmp' ) ); + } + } + + static function getTreeSortCmp( $a, $b ) { + return strcmp( $a['content']['title'], $b['content']['title'] ); + } + + function splitConnectByTree( &$pRet, $pTreeHash ) { + if( $pTreeHash ) { + foreach( array_keys( $pTreeHash ) as $conId ) { + $path = explode( '/', $conId ); + FisheyeGallery::recurseConnectByPath( $pRet, $pTreeHash[$conId], $path ); + } + } + } + + function recurseConnectByPath( &$pRet, $pTreeHash, $pPath ) { + $popId = array_shift( $pPath ); + if( count( $pPath ) > 0 ) { + if( empty( $pRet[$popId]['children'] ) ) { + $pRet[$popId]['children'] = array(); + } + FisheyeGallery::recurseConnectByPath( $pRet[$popId]['children'], $pTreeHash, $pPath ); + } else { + + $pRet[$popId]['content'] = $pTreeHash; + } + } + + // Generate a nested ul list of listed galleries + function generateList( $pListHash, $pOptions, $pLocate = FALSE ) { + $ret = ''; + if( $hash = FisheyeGallery::getTree( $pListHash ) ) { + + $class = ' structure-toc'; + $ret = "<ul "; + foreach( array( 'class', 'name', 'id', 'onchange' ) as $key ) { + if( !empty( $pOptions[$key] ) ) { + if( $key == 'class' ) { + $class .= ' '.$pOptions[$key]; + } else { + $ret .= " $key=\"$pOptions[$key]\" "; + } + } + } + $ret .= ' class="'.$class.'">'; + $ret .= self::generateListItems( $hash, $pOptions, $pLocate ); + $ret .= "</ul>"; + } + return $ret; + } + + // Helper method for generateMenu. See that method. Is Recursive + function generateListItems( &$pHash, $pOptions, $pLocate ) { + $ret = ''; + foreach( array_keys( $pHash ) as $conId ) { + $class = !empty( $pOptions['radio_checkbox'] ) ? 'checkbox' : ''; + $ret .= '<li id="fisheyegallery'.$pHash[$conId]['content']['gallery_id'].'" gallery_id="'.$pHash[$conId]['content']['gallery_id'].'" '; + if( !empty( $pOptions['item_attributes'] ) ) { + foreach( $pOptions['item_attributes'] as $key=>$value ) { + if( $key == 'class' ) { + $class .= ' '.$value; + } else { + $ret .= " $key=\"$value\" "; + } + } + } + $ret .= ' class="'.$class.'"><label>'; + if ( $pLocate || $pHash[$conId]['content']['content_id'] != $this->mContentId ) { + if( !empty( $pOptions['radio_checkbox'] ) ) { + $ret .= '<input type="checkbox" name="gallery_additions[]" value="'.$pHash[$conId]['content']['gallery_id'].'" '; + if( !empty( $pHash[$conId]['content']['in_gallery'] ) || $pHash[$conId]['content']['content_id'] == $this->mContentId ) { + $ret .= ' checked="checked" '; + } + $ret .= '/>'; + } + } + if ( $pHash[$conId]['content']['content_id'] == $this->mContentId + or ( isset( $pHash[$conId]['content']['in_gallery'] ) and $pHash[$conId]['content']['in_gallery'] ) ) { + $ret .= '<span class="active">'.htmlspecialchars( $pHash[$conId]['content']['title'] ).'</span>'; + } else { + $ret .= htmlspecialchars( $pHash[$conId]['content']['title'] ); + } + $ret .= '</label></li>'; + if( !empty( $pHash[$conId]['children'] ) ) { + $ret .= '<li><ul>'.FisheyeGallery::generateListItems( $pHash[$conId]['children'], $pOptions, $pLocate ).'</ul></li>'; + } + } + return $ret; + } + + + // Generate a select drop menu of listed galleries + function generateMenu( $pListHash, $pOptions, $pLocate=NULL ) { + $ret = "<select class='form-control' "; + foreach( array( 'class', 'name', 'id', 'onchange' ) as $key ) { + if( !empty( $pOptions[$key] ) ) { + $ret .= " $key=\"$pOptions[$key]\" "; + } + } + $ret .= ">"; + $ret .= !empty( $pOptions['first_option'] ) ? $pOptions['first_option'] : ''; + if( $hash = FisheyeGallery::getTree( $pListHash ) ) { + $ret .= FisheyeGallery::generateMenuOptions( $hash, $pOptions, $pLocate ); + } + $ret .= "</select>"; + return $ret; + } + + // Helper method for generateMenu. See that method. Is Recursive + function generateMenuOptions( &$pHash, $pOptions, $pLocate, $pPrefix='' ) { + $ret = ''; + foreach( array_keys( $pHash ) as $conId ) { + $ret .= '<option gallery_id="'.$pHash[$conId]['content']['gallery_id'].'" value="'.$pHash[$conId]['content']['gallery_id'].'"'; + if( !empty( $pOptions['item_attributes'] ) ) { + foreach( $pOptions['item_attributes'] as $key=>$value ) { + $ret .= " $key=\"$value\" "; + } + } + if ( $pLocate && $pLocate == $pHash[$conId]['content']['gallery_id'] ) { + $ret .= ' selected="selected" '; + } + $ret .= ' >'.($pPrefix?$pPrefix.'» ':'').htmlspecialchars( $pHash[$conId]['content']['title'] ).'</option>'; + + if( !empty( $pHash[$conId]['children'] ) ) { + $ret .= FisheyeGallery::generateMenuOptions( $pHash[$conId]['children'], $pOptions, $pLocate, ($pPrefix.'-') ); + } + } + return $ret; + } + + function getList( &$pListHash ) { + global $gBitUser,$gBitSystem, $gBitDbType; + + $pListHash['valid_sort_modes'] = array( 'real_name', 'login', 'hits', 'title', 'created', 'last_modified', 'last_hit', 'event_time', 'ip' ); + + LibertyContent::prepGetList( $pListHash ); + $bindVars = array(); + $selectSql = $joinSql = $whereSql = $sortSql = ''; + + if( $gBitDbType == 'mysql' ) { + // loser mysql without subselects + if( !empty( $pListHash['root_only'] ) ) { + $joinSql .= " LEFT OUTER JOIN `".BIT_DB_PREFIX."fisheye_gallery_image_map` tfgim2 ON (tfgim2.`item_content_id`=lc.`content_id`)"; + $whereSql .= ' AND tfgim2.`item_content_id` IS NULL '; + } + } + + if( !empty( $pListHash['contain_item'] ) ) { + $selectSql = " , tfgim3.`item_content_id` AS `in_gallery` "; + $joinSql .= " LEFT OUTER JOIN `".BIT_DB_PREFIX."fisheye_gallery_image_map` tfgim3 ON (tfgim3.`gallery_content_id`=lc.`content_id`) AND tfgim3.`item_content_id`=? "; + $bindVars[] = $pListHash['contain_item']; + } + + if( @$this->verifyId( $pListHash['user_id'] ) ) { + $whereSql .= " AND lc.`user_id` = ? "; + $bindVars[] = (int)$pListHash['user_id']; + } + + if( !empty( $pListHash['find'] ) ) { + $whereSql .= " AND UPPER( lc.`title` ) LIKE ? "; + $bindVars[] = '%'.strtoupper( $pListHash['find'] ).'%'; + } + + if( !empty( $pListHash['show_public'] ) ) { + $joinSql .= " LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content_prefs` lcp ON( lcp.`content_id`=lc.`content_id` )"; + $whereSql .= " OR ( lcp.`pref_name`=? AND lcp.`pref_value`=? ) "; + $bindVars[] = 'is_public'; + $bindVars[] = 'y'; + } + + $mapJoin = ""; + if( $gBitDbType != 'mysql' ) { + // weed out empty galleries if we don't need them. DO NOT get clever and change the IN and EXISTS choices here. + if( empty( $pListHash['show_empty'] ) ) { + $whereSql .= " AND fg.`content_id` IN (SELECT `gallery_content_id` FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim WHERE fgim.`gallery_content_id`=fg.`content_id`)"; + } + if( !empty( $pListHash['root_only'] ) ) { + $whereSql .= " AND NOT EXISTS (SELECT `gallery_content_id` FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` tfgim2 WHERE tfgim2.`item_content_id`=lc.`content_id`)"; + } + } else { + // weed out empty galleries if we don't need them + if( empty( $pListHash['show_empty'] ) ) { + $mapJoin = "INNER JOIN `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim ON (fgim.`gallery_content_id`=lc.`content_id`)"; + } + } + + if ( !empty( $pListHash['sort_mode'] ) ) { + //converted in prepGetList() + $sortSql .= " ORDER BY ".$this->mDb->convertSortmode( $pListHash['sort_mode'] )." "; + } + // Putting in the below hack because mssql cannot select distinct on a text blob column. + $selectSql .= $gBitDbType == 'mssql' ? " ,CAST(lc.`data` AS VARCHAR(250)) as `data` " : " ,lc.`data` "; + + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + if( !empty( $whereSql ) ) { + $whereSql = substr_replace( $whereSql, ' WHERE ', 0, 4 ); + } + + $query = "SELECT fg.`gallery_id` AS `hash_key`, fg.*, + lc.`user_id`, lc.`modifier_user_id`, lc.`created`, lc.`last_modified`, + lc.`content_type_guid`, lc.`format_guid`, lch.`hits`, lch.`last_hit`, lc.`event_time`, lc.`version`, + lc.`lang_code`, lc.`title`, lc.`ip`, uu.`login`, uu.`real_name`, plc.`content_type_guid` AS `preview_content_type_guid` + $selectSql + FROM `".BIT_DB_PREFIX."fisheye_gallery` fg + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (fg.`content_id` = lc.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."users_users` uu ON (uu.`user_id` = lc.`user_id`) + LEFT JOIN `".BIT_DB_PREFIX."liberty_content_hits` lch ON (lch.`content_id` = lc.`content_id`) + $mapJoin $joinSql + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content` plc ON (fg.`preview_content_id` = plc.`content_id`) + $whereSql $sortSql"; + if( $rs = $this->mDb->query( $query, $bindVars, $pListHash['max_records'], $pListHash['offset'] ) ) { + $data = $rs->GetAssoc(); + if( empty( $pListHash['no_thumbnails'] ) ) { + $thumbsize = !empty( $pListHash['thumbnail_size'] ) ? $pListHash['thumbnail_size'] : 'small'; + foreach( array_keys( $data ) as $galleryId ) { + $data[$galleryId]['display_url'] = static::getDisplayUrlFromHash( $data[$galleryId] ); + $data[$galleryId]['display_uri'] = static::getDisplayUriFromHash( $data[$galleryId] ); + if( $thumbImage = $this->getThumbnailImage( $data[$galleryId]['content_id'], $data[$galleryId]['preview_content_id'], $data[$galleryId]['preview_content_type_guid'] ) ) { + $data[$galleryId]['thumbnail_url'] = $thumbImage->getThumbnailUrl( $thumbsize ); + $data[$galleryId]['thumbnail_uri'] = $thumbImage->getThumbnailUri( $thumbsize ); + } elseif( !empty( $pListHash['show_empty'] ) ) { + $data[$galleryId]['thumbnail_url'] = FISHEYE_PKG_URL.'image/no_image.png'; + } else { + unset( $data[$galleryId] ); + } + } + } + } + + // count galleries + $query_c = "SELECT COUNT( fg.`gallery_id` ) + FROM `".BIT_DB_PREFIX."fisheye_gallery` fg + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (fg.`content_id` = lc.`content_id` ) + INNER JOIN `".BIT_DB_PREFIX."users_users` uu ON (uu.`user_id` = lc.`user_id`) + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content` ptc ON( fg.`preview_content_id`=ptc.`content_id` ) + $mapJoin $joinSql + $whereSql"; + $cant = $this->mDb->getOne( $query_c, $bindVars ); + + // add all pagination info to $ret + $pListHash['cant'] = $cant; + LibertyContent::postGetList( $pListHash ); + return $data; + } + + function download(){ + if($this->isValid()){ + $zip = new ZipArchive(); + + $filename = tempnam(TEMP_PKG_PATH,"galleryzip"); + $path = '/'; + + if( $zip->open ($filename, ZIPARCHIVE::OVERWRITE) !== TRUE ){ + $this->mErrors['download'] = "Unable to create zip file"; + }else{ + addGalleryRecursive( $this->mGalleryId , $path, $zip); + } + $zip->close(); + + //escape backslashes + $outputFileTitle = str_replace("\\",'\\\\',$this->getTitle()); + //escape double quotes + $outputFileTitle = str_replace('"','\\"',$outputFileTitle); + + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + Header ("Content-disposition: attachment; filename=\"".$outputFileTitle.".zip\""); + header('Content-Transfer-Encoding: binary'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + Header ("Content-Length: ".filesize( $filename ) ); + ob_end_flush(); + readfile($filename); + unlink($filename); + } + } + + public static function getServiceIcon() { + return '<i class="icon-camera"></i>'; + } + + public static function getServiceKey() { + return 'fisheye'; + } +} + +function addGalleryRecursive( $pGalleryId , $pPath = '/', &$pZip ){ + + if( $gallery = FisheyeGallery::lookup( array( 'gallery_id' => $pGalleryId ) ) ) { + $gallery->load(); + $gallery->loadImages(); + $pPath .= $gallery->getTitle().'/'; + foreach ( $gallery->mItems as $item ){ + if( is_a( $item , 'FisheyeImage' ) ){ + $sourcePath = $item->getSourceFile(); + $title = $item->getTitle(); + $pZip->addFile($sourcePath, $pPath.$title.substr($sourcePath,strrpos($sourcePath,'.')) ); + } elseif ( is_a( $item , 'FisheyeGallery' ) ) { + addGalleryRecursive($item->mGalleryId,$pPath,$pZip); + } + } + } +} + +?> diff --git a/includes/classes/FisheyeImage.php b/includes/classes/FisheyeImage.php new file mode 100644 index 0000000..84e08bf --- /dev/null +++ b/includes/classes/FisheyeImage.php @@ -0,0 +1,900 @@ +<?php +/** + * @package fisheye + */ + +/** + * required setup + */ +require_once( FISHEYE_PKG_CLASS_PATH.'FisheyeBase.php' ); +// Needed for getting event_time and possible image title and data +require_once( LIBERTY_PKG_PATH.'plugins/mime.image.php' ); + +define('FISHEYEIMAGE_CONTENT_TYPE_GUID', 'fisheyeimage'); + +/** + * @package fisheye + */ +class FisheyeImage extends FisheyeBase { + public $mImageId; + + function __construct($pImageId = NULL, $pContentId = NULL) { + parent::__construct(); + $this->mImageId = (int)$pImageId; + $this->mContentId = (int)$pContentId; + + $this->registerContentType( + FISHEYEIMAGE_CONTENT_TYPE_GUID, array( 'content_type_guid' => FISHEYEIMAGE_CONTENT_TYPE_GUID, + 'content_name' => 'Image', + 'handler_class' => 'FisheyeImage', + 'handler_package' => 'fisheye', + 'handler_file' => 'FisheyeImage.php', + 'maintainer_url' => 'http://www.bitweaver.org' + )); + + // Permission setup + $this->mViewContentPerm = 'p_fisheye_view'; + $this->mUpdateContentPerm = 'p_fisheye_update'; + $this->mAdminContentPerm = 'p_fisheye_admin'; + } + + public function __sleep() { + $ret = array_merge( parent::__sleep(), array( 'mImageId' ) ); + return $ret; + } + + public static function lookup( $pLookupHash ) { + global $gBitDb; + $ret = NULL; + + $lookupContentId = NULL; + if (!empty($pLookupHash['image_id']) && is_numeric($pLookupHash['image_id'])) { + if( $lookup = $gBitDb->getRow( "SELECT lc.`content_id`, lc.`content_type_guid` FROM `".BIT_DB_PREFIX."fisheye_image` fi INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON(lc.`content_id`=fi.`content_id`) WHERE `image_id`=?", array( $pLookupHash['image_id'] ) ) ) { + $lookupContentId = $lookup['content_id']; + $lookupContentGuid = $lookup['content_type_guid']; + } + } elseif (!empty($pLookupHash['content_id']) && is_numeric($pLookupHash['content_id'])) { + $lookupContentId = $pLookupHash['content_id']; + $lookupContentGuid = NULL; + } + + if( static::verifyId( $lookupContentId ) ) { + $ret = static::getLibertyObject( $lookupContentId, $lookupContentGuid ); + } + + return $ret; + } + + public function load() { + if( $this->isValid() ) { + global $gBitSystem; + $gateSql = NULL; + $selectSql = $joinSql = $whereSql = ''; + $bindVars = array(); + + if ( @$this->verifyId( $this->mImageId ) ) { + $whereSql = " WHERE fi.`image_id` = ?"; + $bindVars[] = $this->mImageId; + } elseif ( @$this->verifyId( $this->mContentId ) ) { + $whereSql = " WHERE fi.`content_id` = ?"; + $bindVars[] = $this->mContentId; + } + + $this->getServicesSql( 'content_load_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + $sql = "SELECT fi.*, lc.* $gateSql $selectSql + , uue.`login` AS `modifier_user`, uue.`real_name` AS `modifier_real_name` + , uuc.`login` AS `creator_user`, uuc.`real_name` AS `creator_real_name`, ufm.`favorite_content_id` AS `is_favorite` + , lch.`hits` + FROM `".BIT_DB_PREFIX."fisheye_image` fi + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lc.`content_id` = fi.`content_id`) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON (uue.`user_id` = lc.`modifier_user_id`) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON (uuc.`user_id` = lc.`user_id`) + LEFT JOIN `".BIT_DB_PREFIX."users_favorites_map` ufm ON (ufm.`favorite_content_id`=lc.`content_id` AND ufm.`user_id`=uuc.`user_id`) + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content_hits` lch ON ( lch.`content_id` = lc.`content_id` ) $joinSql + $whereSql"; + if( $this->mInfo = $this->mDb->getRow( $sql, $bindVars ) ) { + $this->mImageId = $this->mInfo['image_id']; + $this->mContentId = $this->mInfo['content_id']; + + $this->mInfo['creator'] = (isset( $this->mInfo['creator_real_name'] ) ? $this->mInfo['creator_real_name'] : $this->mInfo['creator_user'] ); + $this->mInfo['editor'] = (isset( $this->mInfo['modifier_real_name'] ) ? $this->mInfo['modifier_real_name'] : $this->mInfo['modifier_user'] ); + + if( $gBitSystem->isPackageActive( 'gatekeeper' ) && !@$this->verifyId( $this->mInfo['security_id'] ) ) { + // check to see if this image is in a protected gallery + // this burns an extra select but avoids an big and gnarly LEFT JOIN sequence that may be hard to optimize on all DB's + $query = "SELECT ls.* FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` fgim + INNER JOIN `".BIT_DB_PREFIX."gatekeeper_security_map` tsm ON(fgim.`gallery_content_id`=tsm.`content_id` ) + INNER JOIN `".BIT_DB_PREFIX."gatekeeper_security` ls ON(tsm.`security_id`=ls.`security_id` ) + WHERE fgim.`item_content_id`=?"; + $grs = $this->mDb->query($query, array( $this->mContentId ) ); + if( $grs && $grs->RecordCount() ) { + // order matters here + $this->mInfo = array_merge( $grs->fields, $this->mInfo ); + } + } + + // LibertyMime will load the attachment details in $this->mStorage + parent::load(); + + // Copy mStorage to mInfo['image_file'] for easy access + if( !empty( $this->mStorage ) && count( $this->mStorage ) > 0 ) { + // it seems that this is not necessary and causes confusing copies of the same stuff all over the place + $this->mInfo = array_merge( current( $this->mStorage ), $this->mInfo ); + // copy the image data by reference to reduce memory + reset( $this->mStorage ); + $this->mInfo['image_file'] = current( $this->mStorage ); + // override original display_url that mime knows where we keep the image + $this->mInfo['image_file']['display_url'] = $this->getDisplayUrl(); + } else { + $this->mInfo['image_file'] = NULL; + } + + if( empty( $this->mInfo['width'] ) || empty( $this->mInfo['height'] ) ) { + $details = $this->getImageDetails(); + // bounds checking on the width and height - corrupt photos can be ridiculously huge or negative + if( !empty($details) AND $details['width'] > 0 AND $details['width'] < 9999 AND $details['height'] > 0 AND $details['height'] < 9999 ) { + $this->mInfo['width'] = $details['width']; + $this->mInfo['height'] = $details['height']; + $this->mDb->query( "UPDATE `".BIT_DB_PREFIX."fisheye_image` SET `width`=?, `height`=? WHERE `content_id`=?", array( $this->mInfo['width'], $this->mInfo['height'], $this->mContentId ) ); + } + } + } + $ret = count($this->mInfo); + } else { + // We don't have an image_id or a content_id so there is no way to know what to load + $ret = NULL; + } + + return $ret; + } + + function storeDimensions( $pDetails ) { + if( $this->isValid() && $this->mInfo['width'] != $pDetails['width'] || $this->mInfo['height'] != $pDetails['height'] ) { + // if our data got out of sync with the database, force an update + $query = "UPDATE `".BIT_DB_PREFIX."fisheye_image` SET `width`=?, `height`=? WHERE `content_id`=?"; + $this->mDb->query( $query, array( $pDetails['width'], $pDetails['height'], $this->mContentId ) ); + $this->mInfo['width'] = $pDetails['width']; + $this->mInfo['height'] = $pDetails['height']; + $this->clearFromCache(); + } + } + + function exportHash() { + $ret = NULL; + // make sure we have a valid image file. + if( ($ret = parent::exportHash()) && ($details = $this->getImageDetails() ) ) { + $ret = array_merge( $ret, array( 'type' => $this->getContentType(), + 'landscape' => $this->isLandscape(), + 'has_description' => !empty( $this->mInfo['data'] ), + 'is_favorite' => $this->getField('is_favorite'), + ) ); + } + return $ret; + } + + function isLandscape() { + return( !empty( $this->mInfo['width'] ) && !empty( $this->mInfo['height'] ) && ($this->mInfo['width'] > $this->mInfo['height']) ); + } + + function verifyImageData(&$pParamHash) { + $pParamHash['content_type_guid'] = $this->getContentType(); + + if ( empty($pParamHash['purge_from_galleries']) ) { + $pParamHash['purge_from_galleries'] = FALSE; + } + + if( !empty( $pParamHash['resize'] ) ) { + $pParamHash['_files_override'][0]['max_height'] = $pParamHash['_files_override'][0]['max_width'] = $pParamHash['resize']; + } + + // Make sure we know what to update + if( $this->isValid() ) { + // these 2 entries will inform LibertyContent and LibertyMime that this is an update + $pParamHash['content_id'] = $this->mContentId; + if( !empty( $this->mInfo['attachment_id'] ) ) { + $pParamHash['_files_override'][0]['attachment_id'] = $this->mInfo['attachment_id']; + } + } + + if( function_exists( 'mime_image_get_exif_data' ) && !empty( $pParamHash['_files_override'][0]['tmp_name'] ) ) { + $exifFile['source_file'] = $pParamHash['_files_override'][0]['tmp_name']; + $exifFile['type'] = $pParamHash['_files_override'][0]['type']; + $exifHash = mime_image_get_exif_data( $exifFile ); + + // Set some default values based on the Exif data + if( !empty( $exifHash['IFD0']['ImageDescription'] ) ) { + if( empty( $pParamHash['title'] ) ) { + $exifTitle = trim( $exifHash['IFD0']['ImageDescription'] ); + if( !empty( $exifTitle ) ) { + $pParamHash['title'] = $exifTitle; + } + } elseif( empty( $pParamHash['edit'] ) && !$this->getField( 'data' ) && $pParamHash['title'] != $exifHash['IFD0']['ImageDescription'] ) { + $pParamHash['edit'] = $exifHash['IFD0']['ImageDescription']; + } + } + + // These come from Photoshop + if( !empty( $exifHash['headline'] ) ) { + if( empty( $pParamHash['title'] ) ) { + $pParamHash['title'] = $exifHash['headline']; + } elseif( empty( $pParamHash['edit'] ) && !$this->getField( 'data' ) && $pParamHash['title'] != $exifHash['headline'] ) { + $pParamHash['edit'] = $exifHash['headline']; + } + } + if( !empty( $exifFile['caption'] ) ) { + if( empty( $pParamHash['title'] ) ) { + $pParamHash['title'] = $exifFile['caption']; + } elseif( empty( $pParamHash['edit'] ) && !$this->getField( 'data' ) && $pParamHash['title'] != $exifFile['caption'] ) { + $pParamHash['edit'] = $exifFile['caption']; + } + } + + if( empty( $pParamHash['event_time'] ) && !$this->getField( 'event_time' ) && !empty( $exifHash['EXIF']['DateTimeOriginal'] ) ) { + $pParamHash['event_time'] = strtotime( $exifHash['EXIF']['DateTimeOriginal'] ); + } + + } + + // let's add a default title if we still don't have one or the user has chosen to use filename over exif data + if( (empty( $pParamHash['title'] ) || !empty($_REQUEST['use_filenames'])) && !empty( $pParamHash['_files_override'][0]['name'] ) ) { + if( preg_match( '/^[A-Z]:\\\/', $pParamHash['_files_override'][0]['name'] ) ) { + // MSIE shit file names if passthrough via gigaupload, etc. + // basename will not work - see http://us3.php.net/manual/en/function.basename.php + $tmp = preg_split("[\\\]", $pParamHash['_files_override'][0]['name'] ); + $defaultName = $tmp[count($tmp) - 1]; + $pParamHash['_files_override'][0]['name'] = $defaultName; + } else { + $defaultName = $pParamHash['_files_override'][0]['name']; + } + + if( strpos( $pParamHash['_files_override'][0]['name'], '.' ) ) { + list( $defaultName, $ext ) = explode( '.', $pParamHash['_files_override'][0]['name'] ); + } + $pParamHash['title'] = str_replace( '_', ' ', $defaultName ); + } + + if( count( $this->mErrors ) > 0 ){ + parent::verify( $pParamHash ); + } + + return (count($this->mErrors) == 0); + } + + function store(&$pParamHash) { + global $gBitSystem, $gLibertySystem; + + if ($this->verifyImageData($pParamHash)) { + // Save the current attachment ID for the image attached to this FisheyeImage so we can + // delete it after saving the new one + if (!empty($this->mInfo['attachment_id']) && !empty($pParamHash['_files_override'][0])) { + $currentImageAttachmentId = $this->mInfo['attachment_id']; + $pParamHash['attachment_id'] = $currentImageAttachmentId; + } else { + $currentImageAttachmentId = NULL; + } + + // we have already done all the permission checking needed for this user to upload an image + $pParamHash['no_perm_check'] = TRUE; + + $this->StartTrans(); + $pParamHash['thumbnail'] = !$gBitSystem->isFeatureActive( 'liberty_offline_thumbnailer' ); + if( LibertyMime::store( $pParamHash ) ) { + if( $currentImageAttachmentId && $currentImageAttachmentId != $this->mInfo['attachment_id'] ) { + $this->expungeAttachment($currentImageAttachmentId); + } + // get storage format back from LibertyMime + $this->mContentId = $pParamHash['content_id']; + $this->mInfo['content_id'] = $this->mContentId; + + if ( !empty( $this->mInfo['source_file'] ) && file_exists( $this->getSourceFile() )) { + $imageDetails = $this->getImageDetails( $this->getSourceFile() ); + } else { + $imageDetails = NULL; + } + + if (!$imageDetails) { + $imageDetails['width'] = (!empty($this->mInfo['width']) ? $this->mInfo['width'] : NULL); + $imageDetails['height'] = (!empty($this->mInfo['height']) ? $this->mInfo['height'] : NULL); + } + + if ($this->imageExistsInDatabase()) { + $sql = "UPDATE `".BIT_DB_PREFIX."fisheye_image` + SET `content_id` = ?, `width` = ?, `height` = ? + WHERE `image_id` = ?"; + $bindVars = array($this->mContentId, $imageDetails['width'], $imageDetails['height'], $this->mImageId); + } else { + $this->mImageId = defined( 'LINKED_ATTACHMENTS' ) ? $this->mContentId : $this->mDb->GenID('fisheye_image_id_seq'); + $this->mInfo['image_id'] = $this->mImageId; + $sql = "INSERT INTO `".BIT_DB_PREFIX."fisheye_image` (`image_id`, `content_id`, `width`, `height`) VALUES (?,?,?,?)"; + $bindVars = array($this->mImageId, $this->mContentId, $imageDetails['width'], $imageDetails['height']); + } + + $rs = $this->mDb->query($sql, $bindVars); + + // check to see if we need offline thumbnailing + if( $gBitSystem->isFeatureActive( 'liberty_offline_thumbnailer' ) ) { + $resize = !empty( $pParamHash['resize'] ) ? (int)$pParamHash['resize'] : NULL; + $this->generateThumbnails( $resize ); + } else { + if( !empty( $pParamHash['resize'] ) && is_numeric( $pParamHash['resize'] ) ) { + $this->resizeOriginal( $pParamHash['resize'] ); + } + } + $this->CompleteTrans(); + } else { + $this->mDb->RollbackTrans(); + } + $this->clearFromCache(); + } else { + $this->mErrors[] = "There were errors while attempting to save this gallery image"; + } + return (count($this->mErrors) == 0); + } + + function getExifField( $pExifField ) { + $ret = NULL; + if( function_exists( 'exif_read_data' ) ) { + $pExifField = strtolower( $pExifField ); + $file = $this->getSourceFile(); + // only attempt to get exif data from jpg or tiff files - chokes otherwise + if( empty( $this->mExif ) && preg_match( "!\.(jpe?g|tif{1,2})$!", $file ) ) { + if( $exif = @exif_read_data( $file ) ) { + $this->mExif = array_change_key_case( $exif, CASE_LOWER ); + } + } + if( !empty( $this->mExif[$pExifField] ) ) { + $ret = $this->mExif[$pExifField]; + } + } + return $ret; + } + + function rotateImage( $pDegrees, $pImmediateRender = FALSE ) { + global $gBitSystem; + if( $this->getField( 'file_name' ) || $this->load() ) { + $fileHash['source_file'] = $this->getSourceFile(); + $fileHash['dest_base_name'] = preg_replace('/(.+)\..*$/', '$1', basename( $fileHash['source_file'] ) ); + $fileHash['type'] = $gBitSystem->verifyMimeType( $fileHash['source_file'] ); + $fileHash['size'] = filesize( $fileHash['source_file'] ); + $fileHash['dest_branch'] = dirname( $this->getSourceFile() ).'/'; + $fileHash['name'] = $this->getField( 'file_name' ); + if( $pDegrees == 'auto' ) { + if( $exifOrientation = $this->getExifField( 'orientation' ) ) { + switch( $exifOrientation ) { + case 1: //) transform="";; + break; + case 2: //) transform="-flip horizontal";; + break; + case 3: //) transform="-rotate 180";; + $pDegrees = 180; + break; + case 4: //) transform="-flip vertical";; + break; + case 5: //) transform="-transpose";; + break; + case 6: //) transform="-rotate 90";; + // make sure image has not already been rotated + if( $this->isLandscape() ) { + $pDegrees = 90; + } + break; + case 7: //) transform="-transverse";; + break; + case 8: //) transform="-rotate 270";; + // make sure image has not already been rotated + if( $this->isLandscape() ) { + $pDegrees = 270; + } + break; + // *) transform="";; + } + } + } + if( is_numeric( $pDegrees ) ) { + $fileHash['degrees'] = $pDegrees; + + if( ($rotateFunc = liberty_get_function( 'rotate' )) && $rotateFunc( $fileHash ) ) { + liberty_clear_thumbnails( $fileHash ); + $this->mDb->query( "UPDATE `".BIT_DB_PREFIX."fisheye_image` SET `width`=`height`, `height`=`width` WHERE `content_id`=?", array( $this->mContentId ) ); + $this->clearFromCache(); + $this->generateThumbnails( FALSE, $pImmediateRender ); + } else { + $this->mErrors['rotate'] = $fileHash['error']; + } + } elseif( $pDegrees == 'auto' ) { + $this->mErrors['rotate'] = "Image was not auto-rotated."; + } + } + return (count($this->mErrors) == 0); + } + + + /** + * convertColorspace + * + * @param string $pColorSpace - target color space, only 'grayscale' is currently supported, and only when using the MagickWand image processor + * @access public + * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure + */ + function convertColorspace( $pColorSpace ) { + global $gBitSystem; + $ret = FALSE; + if( $this->getField( 'file_name' ) || $this->load() ) { + $fileHash['source_file'] = $this->getSourceFile(); + $fileHash['dest_base_name'] = preg_replace('/(.+)\..*$/', '$1', basename( $fileHash['source_file'] ) ); + $fileHash['type'] = $gBitSystem->verifyMimeType( $fileHash['source_file'] ); + $fileHash['size'] = filesize( $fileHash['source_file'] ); + $fileHash['dest_branch'] = dirname( $this->getSourceFile() ).'/'; + $fileHash['name'] = $this->getField( 'file_name' ); + if( $convertFunc = liberty_get_function( 'convert_colorspace' ) ) { + if( $ret = $convertFunc( $fileHash, $pColorSpace ) ) { + liberty_clear_thumbnails( $fileHash ); + $sql = "UPDATE `".BIT_DB_PREFIX."liberty_files SET `file_size`=? WHERE `file_id` = ?"; + $this->mDb->query( $sql, array( filesize( $fileHash['dest_file'] ), $this->mInfo['file_id'] ) ); + $this->generateThumbnails(); + } + } + } + return $ret; + } + + + function resizeOriginal( $pResizeOriginal ) { + global $gBitSystem; + if( $this->getField( 'file_name' ) || $this->load() ) { + $fileHash['source_file'] = $this->getSourceFile(); + $fileHash['dest_base_name'] = preg_replace('/(.+)\..*$/', '$1', basename( $fileHash['source_file'] ) ); + $fileHash['type'] = $gBitSystem->verifyMimeType( $fileHash['source_file'] ); + $fileHash['size'] = filesize( $fileHash['source_file'] ); + $fileHash['dest_branch'] = $this->getStorageBranch(); + $fileHash['name'] = $this->getField( 'file_name' ); + $fileHash['max_height'] = $fileHash['max_width'] = $pResizeOriginal; + // make a copy of the fileHash that we can compare output after processing + $preResize = $fileHash; + if( ($resizeFunc = liberty_get_function( 'resize' )) && ($resizeFile = $resizeFunc( $fileHash )) ) { + clearstatcache(); + // Ack this is evil direct bashing of the liberty tables! XOXO spiderr + // should be a cleaner way eventually + + // we need to update the souce_file in case it's changed from a non jpg to a jpg + if( $fileHash['name'] != $preResize['name'] ) { + $fileHash['source_file'] = dirname( $fileHash['source_file'] ).'/'.$fileHash['name']; + // make absolutely certain that we have 2 image files and that they are different, then remove the original + if( $fileHash['source_file'] != $preResize['source_file'] && is_file( $fileHash['source_file'] ) && is_file( $preResize['source_file'] ) ) { + @unlink( $preResize['source_file'] ); + } + } + $details = $this->getImageDetails( $resizeFile ); + // store all the values that might have changed due to the resize + $storeHash = array( + 'file_size' => filesize( $resizeFile ), + 'mime_type' => $details['mime'], + ); + $this->mDb->associateUpdate( BIT_DB_PREFIX."liberty_files", $storeHash, array( 'file_id' => $this->mInfo['file_id'] ) ); + //$query = "UPDATE `".BIT_DB_PREFIX."liberty_files` SET `file_size`=? WHERE `file_id`=?"; + //$this->mDb->query( $query, array( $details['size'], $this->mInfo['file_id'] ) ); + $query = "UPDATE `".BIT_DB_PREFIX."fisheye_image` SET `width`=?, `height`=? WHERE `content_id`=?"; + $this->mDb->query( $query, array( $details['width'], $details['height'], $this->mContentId ) ); + // if we've come this far, we can try removing the original if it's different to the resized image + // make absolutely certain that we have 2 image files and that they are different, then remove the original + if( $fileHash['source_file'] != $preResize['source_file'] && is_file( $fileHash['source_file'] ) && is_file( $preResize['source_file'] ) ) { + @unlink( $preResize['source_file'] ); + } + } else { + $this->mErrors['resize'] = $fileHash['error']; + } + } + return (count($this->mErrors) == 0); + } + + + function generateThumbnails( $pResizeOriginal=NULL, $pImmediateRender=FALSE ) { + global $gBitSystem; + $ret = FALSE; + // LibertyMime will take care of thumbnail generation of the offline thumbnailer is not active + if( $gBitSystem->isFeatureActive( 'liberty_offline_thumbnailer' ) && !$pImmediateRender ) { + $query = "DELETE FROM `".BIT_DB_PREFIX."liberty_process_queue` + WHERE `content_id`=?"; + $this->mDb->query( $query, array( $this->mContentId ) ); + $query = "INSERT INTO `".BIT_DB_PREFIX."liberty_process_queue` + (`content_id`, `queue_date`, `processor_parameters`) VALUES (?,?,?)"; + $this->mDb->query( $query, array( $this->mContentId, $gBitSystem->getUTCTime(), serialize( array( 'resize_original' => $pResizeOriginal ) ) ) ); + } else { + $ret = $this->renderThumbnails(); + } + return $ret; + } + + + function renderThumbnails( $pThumbSizes=NULL ) { + global $gBitSystem; + if( $this->getField( 'file_name' ) || $this->load() ) { + $fileHash['source_file'] = $this->getSourceFile(); + $fileHash['type'] = $gBitSystem->verifyMimeType( $fileHash['source_file'] ); + $fileHash['size'] = filesize( $fileHash['source_file'] ); + $fileHash['dest_branch'] = $this->getStorageBranch( $fileHash ); + $fileHash['name'] = $this->getField( 'file_name' ); + $fileHash['thumbnail_sizes'] = $pThumbSizes; + // just generate thumbnails + liberty_generate_thumbnails( $fileHash ); + if( !empty( $fileHash['error'] ) ) { + $this->mErrors['thumbnail'] = $fileHash['error']; + } + } + return( count($this->mErrors) == 0 ); + } + + function getStorageUrl( $pParamHash = array() ) { + $pParamHash['sub_dir'] = $this->getParameter( $pParamHash, 'sub_dir', liberty_mime_get_storage_sub_dir_name( array( 'type'=>$this->getField( 'mime_type' ), 'name'=>$this->getField('file_name') ) ) ); + $pParamHash['user_id'] = $this->getParameter( $pParamHash, 'user_id', $this->getField('user_id') ); + return parent::getStorageUrl( $pParamHash ).$this->getParameter( $pParamHash, 'attachment_id', $this->getField('attachment_id') ).'/'; + } + + function getStorageBranch( $pParamHash = array() ) { + $pParamHash['sub_dir'] = $this->getParameter( $pParamHash, 'sub_dir', liberty_mime_get_storage_sub_dir_name( array( 'type'=>$this->getField( 'mime_type' ), 'name'=>$this->getField('file_name') ) ) ); + $pParamHash['user_id'] = $this->getParameter( $pParamHash, 'user_id', $this->getField('user_id') ); + return parent::getStorageBranch( $pParamHash ).$this->getParameter( $pParamHash, 'attachment_id', $this->getField('attachment_id') ).'/'; + } + + function getStoragePath( $pParamHash, $pRootDir=NULL ) { + $pParamHash['sub_dir'] = liberty_mime_get_storage_sub_dir_name( array( 'type'=>BitBase::getParameter( $pParamHash, 'mime_type', $this->getField( 'mime_type' ) ), 'name'=>BitBase::getParameter( $pParamHash, 'file_name', $this->getField('file_name') ) ) ); + $pParamHash['user_id'] = $this->getParameter( $pParamHash, 'user_id', $this->getField('user_id') ); + return parent::getStoragePath( $pParamHash ).$this->getParameter( $pParamHash, 'attachment_id', $this->getField('attachment_id') ).'/'; + } + + function getPreviewHash() { + return $this->mInfo; + } + + // Get resolution, etc + function getImageDetails($pFilePath = NULL) { + $info = array(); + if( file_exists( $pFilePath ) ) { + $checkFiles = array( $pFilePath, dirname( $pFilePath ).'/original.jpg' ); + } else { + $sourceFile = $this->getSourceFile(); + $checkFiles = array( $sourceFile ); + // was an original file created? + $originalFile = dirname( $sourceFile ).'/original.jpg'; + if( file_exists( $originalFile ) && !is_link( $originalFile ) ) { + $checkFiles[] = $originalFile; + } + } + + foreach( $checkFiles as $cf ) { + if ($cf && file_exists( $cf ) && filesize( $cf ) ) { + if( $imageSize = getimagesize( rtrim( $cf ) ) ) { + $info = $imageSize; + $info['width'] = $info[0]; + $info['height'] = $info[1]; + $info['size'] = filesize( $cf ); + break; + } + } + } + return $info; + } + + function getWidth() { + if( !isset( $this->mInfo['width'] ) ) { + $this->mInfo = array_merge( $this->mInfo, $this->getImageDetails() ); + } + return $this->getField('width'); + } + + function getHeight() { + if( !isset( $this->mInfo['width'] ) ) { + $this->mInfo = array_merge( $this->mInfo, $this->getImageDetails() ); + } + return $this->getField('height'); + } + + /** + * Returns include file that will setup vars for display + * @return the fully specified path to file to be included + */ + function getRenderFile() { + return FISHEYE_PKG_INCLUDE_PATH.'display_fisheye_image_inc.php'; + } + + /** + * Returns template file used for display + * @return the fully specified path to file to be included + */ + function getRenderTemplate() { + return 'bitpackage:fisheye/view_image.tpl'; + } + + /** + * Function that returns link to display a piece of content + * @param pImageId id of gallery to link + * @param pParamHash if a string, it is assumed to be the size, if an array, it is assumed to be a mInfo hash + * @return the url to display the gallery. + */ + public static function getDisplayUrlFromHash( &$pParamHash ) { + $ret = ''; + $size = (!empty( $pParamHash['size'] ) && is_string( $pParamHash['size'] ) && isset( $pParamHash['thumbnail_url'][$pParamHash['size']] ) ) ? $pParamHash['size'] : NULL ; + + global $gBitSystem; + if( @BitBase::verifyId( $pParamHash['image_id'] ) ) { + if( $gBitSystem->isFeatureActive( 'pretty_urls' ) ) { + $ret = FISHEYE_PKG_URL.'image/'.$pParamHash['image_id']; + if( !empty( $pParamHash['gallery_path'] ) ) { + $ret .= $pParamHash['gallery_path']; + } + if( $size ) { + $ret .= '/'.$size; + } + } else { + $ret = FISHEYE_PKG_URL.'view_image.php?image_id='.$pParamHash['image_id']; + if( !empty( $this ) && !empty( $pParamHash['gallery_path'] ) ) { + $ret .= '&gallery_path='.$pParamHash['gallery_path']; + } + if( $size ) { + $ret .= '&size='.$size; + } + } + } elseif( @BitBase::verifyId( $pParamHash['content_id'] ) ) { + $ret = FISHEYE_PKG_URL.'view_image.php?content_id='.$pParamHash['content_id']; + } + return $ret; + } + + /** + * Function that returns link to display an image + * @return the url to display the gallery. + */ + public function getDisplayUrl() { + $info = &$this->mInfo; + $info['image_id'] = $this->mImageId; + $info['gallery_path'] = $this->mGalleryPath; + return static::getDisplayUrlFromHash( $info ); + } + + /** + * Function that returns link to display an image + * Used to display thumbnails for navigation bar + * @param pImageId id of image to link + * @return the url to display the image. + */ + public function getImageUrl( $pImageId ) { + $info = array( 'image_id' => $pImageId ); + return static::getDisplayUrlFromHash( $info ); + } + + /** + * Generate a valid display link for the Blog + * + * @param object PostId of the item to use + * @param array Not used + * @return object Fully formatted html link for use by Liberty + */ + static function getDisplayLinkFromHash( &$pParamHash, $pTitle=NULL, $pAnchor=NULL ) { + global $gBitSystem; + + $pTitle = trim( $pTitle ); + + if( empty( $pTitle ) ) { + $pTitle = FisheyeImage::getTitleFromHash( $pParamHash ); + } + + $ret = $pTitle; + if( $gBitSystem->isPackageActive( 'fisheye' ) ) { + $ret = '<a title="'.$pTitle.'" href="'.FisheyeImage::getDisplayUrlFromHash( $pParamHash ).'">'.$pTitle.'</a>'; + } + return $ret; + } + + static public function getTitleFromHash( &$pHash, $pDefault=TRUE ) { + $ret = trim( parent::getTitleFromHash( $pHash, $pDefault ) ); + if( empty( $ret ) && $pDefault ) { + $storage = (!empty( $this ) && !empty( $this->mStorage ) ? current( $this->mStorage ) : NULL); + if( !empty( $storage['file_name'] ) ) { + $ret = $storage['file_name']; + } else { + global $gLibertySystem; + $ret = $gLibertySystem->getContentTypeName( $pHash['content_type_guid'] ); + if( !empty( $pHash['image_id'] ) ) { + $ret .= " ".$pHash['image_id']; + } + } + } + return $ret; + } + + public function getTitle() { + $ret = NULL; + if( $this->isValid() ) { + $ret = self::getTitleFromHash( $this->mInfo ); + } + return $ret; + } + + + function getThumbnailContentId() { + return( $this->mContentId ); + } + + function getThumbnailUrl( $pSize = 'small', $pInfoHash = NULL, $pSecondaryId = NULL, $pDefault=TRUE ) { + $ret = NULL; + if( $this->isValid() && isset( $this->mInfo['thumbnail_url'][$pSize] ) ) { + $ret = $this->mInfo['thumbnail_url'][$pSize]; + } + return $ret; + } + + public static function getThumbnailUrlFromHash( &$pParamHash, $pSize = 'small', $pSecondaryId = NULL, $pDefault=TRUE ) { + $ret = NULL; + if( isset( $pParamHash['thumbnail_url'][$pSize] ) ) { + $ret = $pParamHash['thumbnail_url'][$pSize]; + } + return $ret; + } + + function expunge($pExpungeAttachment = TRUE) { + if( $this->isValid() ) { + $this->StartTrans(); + $query = "DELETE FROM `".BIT_DB_PREFIX."fisheye_gallery_image_map` WHERE `item_content_id` = ?"; + $rs = $this->mDb->query($query, array( $this->mContentId )); + $query = "UPDATE `".BIT_DB_PREFIX."fisheye_gallery` SET `preview_content_id`=NULL WHERE `preview_content_id` = ?"; + $rs = $this->mDb->query($query, array( $this->mContentId )); + $query = "DELETE FROM `".BIT_DB_PREFIX."fisheye_image` WHERE `content_id` = ?"; + $rs = $this->mDb->query($query, array( $this->mContentId )); + if( LibertyMime::expunge($pExpungeAttachment) ) { + $this->CompleteTrans(); + $this->mImageId = NULL; + $this->mContentId = NULL; + } else { + $this->mDb->RollbackTrans(); + } + } + return( count( $this->mErrors ) == 0 ); + } + + function expungingAttachment($pAttachmentId, $pContentIdArray) { + foreach ($pContentIdArray as $id) { + $this->mContentId = $id; + // Vital that we call LibertyMime::expunge with false since the attachment is already being deleted. + $this->expunge(FALSE); + } + } + + function isValid() { + return( @$this->verifyId( $this->mImageId ) || @$this->verifyId( $this->mContentId ) ); + } + + function imageExistsInDatabase() { + $ret = FALSE; + if( $this->isValid() && $this->mImageId ) { + $query = "SELECT COUNT(`image_id`) + FROM `".BIT_DB_PREFIX."fisheye_image` + WHERE `image_id` = ?"; + + $bindVars = array($this->mImageId); + + if($this->mDb->getOne($query, $bindVars) > 0){ + $ret = TRUE; + } + + } + return $ret; + } + + + function getList( &$pListHash ) { + global $gBitUser,$gBitSystem; + + LibertyContent::prepGetList( $pListHash ); + + $ret = $bindVars = array(); + $distinct = ''; + $select = ''; + $whereSql = ''; + $joinSql = ''; + + if( @$this->verifyId( $pListHash['user_id'] ) ) { + $whereSql .= " AND lc.`user_id` = ? "; + $bindVars[] = $pListHash['user_id']; + } elseif( !empty( $pListHash['recent_users'] )) { + $distinct = " DISTINCT ON ( lc.created/86400, uu.`user_id` ) "; + $pListHash['sort_mode'] = 'uu.user_id_desc'; + } + + if( @$this->verifyId( $pListHash['gallery_id'] ) ) { + $whereSql .= " AND fg.`gallery_id` = ? "; + $bindVars[] = $pListHash['gallery_id']; + } + + if( !empty( $pListHash['search'] ) ) { + $whereSql .= " AND UPPER(lc.`title`) LIKE ? "; + $bindVars[] = '%'.strtoupper( $pListHash['search'] ).'%'; + } + + if( !empty( $pListHash['max_age'] ) && is_numeric( $pListHash['max_age'] ) ) { + $whereSql .= " AND lc.`created` > ? "; + $bindVars[] = $pListHash['max_age']; + } + + $this->getServicesSql( 'content_user_collection_function', $selectSql, $joinSql, $whereSql, $bindVars, $this, $pListHash ); + + $orderby = ''; + if( !empty( $pListHash['recent_images'] )) { + // get images from recent user truncated by day. This is necessary because DISTINCT ON expressions must match initial ORDER BY expressions + $distinct = " DISTINCT ON ( lc.`created`/86400, uu.`user_id` ) "; + $orderby = " ORDER BY lc.`created`/86400 DESC, uu.`user_id`"; + } elseif ( !empty( $pListHash['sort_mode'] ) ) { + //converted in prepGetList() + $orderby = " ORDER BY ".$this->mDb->convertSortmode( $pListHash['sort_mode'] )." "; + } + + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + if( !empty( $whereSql ) ) { + $whereSql = substr_replace( $whereSql, ' WHERE ', 0, 4 ); + } + + $thumbSize = (!empty( $pListHash['size'] ) ? $pListHash['size'] : 'avatar' ); + + $query = "SELECT $distinct fi.`image_id` AS `hash_key`, fi.*, lf.*, la.attachment_id, lc.*, fg.`gallery_id`, uu.`login`, uu.`real_name` $select $selectSql + FROM `".BIT_DB_PREFIX."fisheye_image` fi + INNER JOIN `".BIT_DB_PREFIX."liberty_attachments` la ON(la.`content_id`=fi.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_files` lf ON(la.`foreign_id`=lf.`file_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON(fi.`content_id` = lc.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."users_users` uu ON(uu.`user_id` = lc.`user_id`) $joinSql + LEFT OUTER JOIN `".BIT_DB_PREFIX."fisheye_gallery_image_map` tfgim2 ON(tfgim2.`item_content_id`=lc.`content_id`) + LEFT OUTER JOIN `".BIT_DB_PREFIX."fisheye_gallery` fg ON(fg.`content_id`=tfgim2.`gallery_content_id`) + $whereSql $orderby"; + if( $rs = $this->mDb->query( $query, $bindVars, $pListHash['max_records'], $pListHash['offset'], $pListHash['query_cache_time'] ) ) { + while( $row = $rs->fetchRow() ) { + // legacy table data was named storage_path and included a partial path. strip out any path just in case + $row['file_name'] = basename( $row['file_name'] ); + $ret[$row['hash_key']] = $row; + $imageId = $row['image_id']; + if( empty( $pListHash['no_thumbnails'] ) ) { + $ret[$imageId]['display_url'] = static::getDisplayUrlFromHash( $row ); + $ret[$imageId]['has_machine_name'] = $this->isMachineName( $ret[$imageId]['title'] ); + $ret[$imageId]['source_url'] = $this->getStorageUrl( $row ).$row['file_name']; + $ret[$imageId]['thumbnail_url'] = liberty_fetch_thumbnail_url( array( + 'source_file' => $this->getSourceFile( $row ), + 'default_image' => FISHEYE_PKG_URL.'image/generating_thumbnails.png', + 'size' => $thumbSize, + 'type' => $row['mime_type'], + )); + } + } + } + return $ret; + } + + /** + * isCommentable + * + * @access public + * @return TRUE on success, FALSE on failure + */ + function isCommentable() { + global $gGallery; + + // if we have a loaded gallery, we just use that to work out if we can add comments to this image + if( is_object( $gGallery ) ) { + return $gGallery->isCommentable(); + } + + $ret = FALSE; + if( $parents = $this->getParentGalleries() ) { + // @TODO: No idea how to work out if you can add a comment to this image + // for now we'll take the mGalleryPath and use that gallery + $gal = current( $parents ); + $query = "SELECT `pref_value` FROM `".BIT_DB_PREFIX."liberty_content_prefs` WHERE `content_id` = ? AND `pref_name` = ?"; + $ret = ( $this->mDb->getOne( $query, array( $gal['content_id'], 'allow_comments' )) == 'y' ); + } + return $ret; + } + + public static function getServiceKey() { + return 'fisheye'; + } +} + +?> diff --git a/includes/classes/FisheyeRemote.php b/includes/classes/FisheyeRemote.php new file mode 100644 index 0000000..ec69114 --- /dev/null +++ b/includes/classes/FisheyeRemote.php @@ -0,0 +1,351 @@ +<?php +/** + * Gallery2 Remote support for fisheye + * + * @package fisheye + * @version $Header$ + * @author spider <spider@steelsun.com> + * @author tylerbello <tylerbello@gmail.com> + */ + +// +----------------------------------------------------------------------+ +// | Copyright (c) 2004, bitweaver.org +// +----------------------------------------------------------------------+ +// | All Rights Reserved. See below for details and a complete list of authors. +// | Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See http://www.gnu.org/copyleft/lesser.html for details +// | +// | For comments, please use phpdocu.sourceforge.net documentation standards!!! +// | -> see http://phpdocu.sourceforge.net/ +// +----------------------------------------------------------------------+ +// | Authors: spider <spider@steelsun.com> +// +----------------------------------------------------------------------+ + +define( 'FEG2REMOTE_SUCCESS', 0 ); + +define( 'FEG2REMOTE_PROTOCOL_MAJOR_VERSION_INVALID', 101 ); +define( 'FEG2REMOTE_PROTOCOL_MINOR_VERSION_INVALID', 102 ); +define( 'FEG2REMOTE_PROTOCOL_VERSION_FORMAT_INVALID', 103 ); +define( 'FEG2REMOTE_PROTOCOL_VERSION_MISSING', 104 ); + +define( 'FEG2REMOTE_PASSWORD_WRONG', 201 ); +define( 'FEG2REMOTE_LOGIN_MISSING', 202 ); + +define( 'FEG2REMOTE_UNKNOWN_COMMAND', 301 ); +define( 'FEG2REMOTE_MISSING_ARGUMENTS', 302 ); + +define( 'FEG2REMOTE_NO_ADD_PERMISSION', 401 ); +define( 'FEG2REMOTE_NO_FILENAME', 402 ); +define( 'FEG2REMOTE_UPLOAD_PHOTO_FAIL', 403 ); +define( 'FEG2REMOTE_NO_WRITE_PERMISSION', 404 ); +define( 'FEG2REMOTE_NO_VIEW PERMISSION', 405 ); + +define( 'FEG2REMOTE_NO_CREATE_ALBUM_PERMISSION', 501 ); +define( 'FEG2REMOTE_CREATE_ALBUM_FAILED', 502 ); +define( 'FEG2REMOTE_MOVE_ALBUM_FAILED', 503 ); +define( 'FEG2REMOTE_ROTATE_IMAGE_FAILED', 504 ); + +/** + * @package fisheye + */ +class FisheyeRemote { + + public $mResponse = array(); + + public $mSubGalIdx = 1; + + function getApiVersion() { + return '2.14'; + } + + + // separate out pPostData and pParamhash data since some plugins can populate _POST['g2_form'] and _GET['g2_form'] differently. + // weird but true. ubermind is an example + function processRequest( $pGetData, $pPostData ) { + $pData = array_merge($pGetData, $pPostData); //Some programs (galleryexport) pass both post and get...and the cmd can be in either get or post + + if(!empty($pData)){ + switch ($pData['cmd']) { + case 'login': + $response = $this->cmdLogin( $pPostData ); + break; + + case 'fetch-albums': + $response = $this->cmdFetchAlbums( $pPostData ); + break; + + case 'fetch-albums-prune': + $response = $this->cmdFetchAlbums( $pPostData ); + break; + + case 'add-item': + $response = $this->cmdAddItem( $pPostData ); + break; + + case 'album-properties': + // not implemented yet + break; + + case 'new-album': + $response = $this->cmdNewAlbum( $pPostData ); + break; + + case 'fetch-album-images': + // not implemented yet + break; + + case 'move-album': + // not implemented yet + break; + + case 'increment-view-count': + // not implemented yet + break; + + case 'image-properties': + // not implemented yet + break; + + case 'no-op': + $response = $this->cmdNoOp( $pPostData ); + // not implemented yet + break; + + default: + $response = $this->createResponse( FEG2REMOTE_UNKNOWN_COMMAND, "Command unknown: ".$pGetData['cmd'] ); + break; + } + } else { + $response = $this->createResponse( FEG2REMOTE_UNKNOWN_COMMAND, "No command received." ); + } + + if( !empty( $response ) ) { + print $this->sendResponse( $response ); + } + } + + + function cmdNoOp( $pParamHash ) { + global $gBitUser; + + $response = $this->createResponse( FEG2REMOTE_SUCCESS, 'No-op successful' ); + return $response; + } + + function cmdLogin( $pParamHash ) { + global $gBitUser, $gBitSystem; + $url = $gBitUser->login( $pParamHash['uname'], $pParamHash['password'] ); + if( $gBitUser->isRegistered() ) { + /* + $cookieTime = ( int )( time() + $gBitSystem->getConfig( 'users_remember_time', 86400 )); + $cookiePath = $gBitSystem->getConfig( 'cookie_path', BIT_ROOT_URL ); + $cookieDomain = $gBitSystem->getConfig( 'cookie_domain', "" ); + setcookie( 'GALLERYSID', session_id(), $cookieTime, $cookiePath, $cookieDomain ); + */ + $response = $this->createResponse( FEG2REMOTE_SUCCESS, 'Login successful.', array( 'server_version' => $this->getApiVersion() ) ); + } else { + $response = $this->createResponse( FEG2REMOTE_PASSWORD_WRONG, 'Invalid username or password' ); + } + return $response; + } + + // Recursively traverses a multi-dimensional array of galleries + function traverseGalleries( &$pGalHash, &$pResponse ) { + global $gBitUser; + + // Albums don't like being 0 indexed + $this->mSubGalIdx = 0; + + // the lightroom client is dumb, and can only handle one 0 level parent + if( stripos( $_SERVER['HTTP_USER_AGENT'], 'lightroom' ) !== FALSE ) { + $this->mSubGalIdx++; + $pResponse['album.parent.' . $this->mSubGalIdx] = 0; + $pResponse['album.name.' . $this->mSubGalIdx] = 1; + $pResponse['album.title.' . $this->mSubGalIdx] = tra( 'Select a Gallery' ); + $pResponse['album.perms.add.' . $this->mSubGalIdx] = 'false'; + $pResponse['album.perms.write.' . $this->mSubGalIdx] = 'false'; + $pResponse['album.perms.del_alb.' . $this->mSubGalIdx] = 'false'; + $pResponse['album.perms.create_sub.' . $this->mSubGalIdx] = 'true'; + } + + return $this->traverseSubGalleries( $pGalHash, $pResponse, 1 ); + } + + /** + * Function that returns link to display a piece of content + * @param $pGalHash branch of gallery information from FisheyeGallery::getTree + * @param $pResponse aggregate string containing response array + * @param $pParentRandom depth of pGalHash - this is used to non-definitively uniquify album.parent and album.name entries + * @return the url to display the gallery. + */ + function traverseSubGalleries( &$pGalHash, &$pResponse, $pParentRandom ) { + global $gBitUser; + foreach( $pGalHash as $key=>$gallery) { + $this->mSubGalIdx++; + + // Any number greater than 2 digits crashes iPhoto2Gallery + $randomizer = str_pad( rand( 1, 99 ), 2, '0' ); + if($gallery['content']['level'] != 0){ + // Fisheye allows directories to below to multiple parents - not in gallery. This confuses some clients + // We pad with a random number for uniqueness + $pResponse['album.parent.' . $this->mSubGalIdx] = $gallery['content']['cb_gallery_content_id'].$pParentRandom; + } else { + // the lightroom client is dumb, and can only handle one 0 level parent + if( stripos( $_SERVER['HTTP_USER_AGENT'], 'lightroom' ) !== FALSE ) { + $pResponse['album.parent.' . $this->mSubGalIdx] = 1; + } else { + $pResponse['album.parent.' . $this->mSubGalIdx] = 0; + } + } + // append pParentRandom to make .name probably unique since Fisheye can handle one gallery linked to multiple parents + $pResponse['album.name.' . $this->mSubGalIdx] = $gallery['content']['content_id'].$randomizer; + $pResponse['album.title.' . $this->mSubGalIdx] = $this->cleanResponseValue( $gallery['content']['title'] ); + + if( !empty( $gallery['content']['data'] ) ) { + $pResponse['album.summary.' . $this->mSubGalIdx] = $gallery['content']['data']; + $pResponse['album.info.extrafields.' . $this->mSubGalIdx] = "Summary"; + } + + $pResponse['album.perms.add.' . $this->mSubGalIdx] = 'true'; + $pResponse['album.perms.write.' . $this->mSubGalIdx] = 'true'; + $pResponse['album.perms.del_alb.' . $this->mSubGalIdx] = 'true'; + $pResponse['album.perms.create_sub.' . $this->mSubGalIdx] = 'true'; + + if( !empty( $gallery['children'] ) ) { + $this->traverseSubGalleries($gallery['children'],$pResponse, $randomizer ); + } + } + $ret = $this->mSubGalIdx; + return $ret; + } + + function cmdFetchAlbums( $pParamHash ) { + require_once( FISHEYE_PKG_CLASS_PATH.'FisheyeGallery.php' ); + global $gBitUser; + if( $gBitUser->isRegistered() ) { + $treeGallery = new FisheyeGallery(); + $listHash['user_id'] = $gBitUser->mUserId; + if( $galleryList = $treeGallery->getTree( $listHash, array( 'name' => "gallery_id", 'id' => "gallerylist", 'item_attributes' => array( 'class'=>'listingtitle' ) ) ) ) { + $galResponse = array(); + $galleryCount = $this->traverseGalleries( $galleryList, $galResponse ); + $galResponse['album_count'] = $galleryCount; + $galResponse['can_create_root'] = 'true'; + $response = $this->createResponse( FEG2REMOTE_SUCCESS, 'Gallery list successful', $galResponse ); + } else { + // perhaps we should make at least on gallery at this point? + $response = $this->createResponse( FEG2REMOTE_SUCCESS, 'No galleries', array( 'album_count' => 0 ) ); + } + } else { + $response = $this->createResponse( FEG2REMOTE_PASSWORD_WRONG, 'Application not logged in' ); + } + return $response; + } + + + function cmdAddItem( $pParamHash ) { + $response = array(); + + $uploadFile = (!empty( $_FILES['g2_userfile'] ) ? $_FILES['g2_userfile'] : NULL); + + if( empty( $pParamHash['set_albumName'] ) ) { + $response = $this->createResponse( CREATE_ALBUM_FAILED , 'No gallery specified' ); + } elseif( empty( $uploadFile ) || empty( $uploadFile['size'] ) ) { + $response = $this->createResponse( FEG2REMOTE_NO_FILENAME, 'No image uploaded' ); + } else { + $storeHash['title'] = !empty( $pParamHash['force_filename'] ) ? $pParamHash['force_filename'] : NULL; + $storeHash['summary'] = !empty( $pParamHash['extrafield.Summary'] ) ? $pParamHash['extrafield.Summary'] : NULL; + $storeHash['edit'] = !empty( $pParamHash['extrafield.Description'] ) ? $pParamHash['extrafield.Description'] : NULL; + + require_once (FISHEYE_PKG_INCLUDE_PATH.'upload_inc.php'); + + $parentGallery = new FisheyeGallery(); + if( $parentGallery = $parentGallery->lookup(array('content_id' => $pParamHash['set_albumName'] ) ) ) { + $parentGallery->load(); + $storeHash['gallery_additions'] = array($parentGallery->mGalleryId); + } + if( $errors = fisheye_store_upload( $uploadFile , $storeHash ) ){ + $response = $this->createResponse( FEG2REMOTE_UPLOAD_PHOTO_FAIL, 'Export Failed' ); + } else { + $response = $this->createResponse( FEG2REMOTE_SUCCESS, 'Image added', array( 'item_name'=>$uploadFile['name'] ) ); + } + } + + return $response; + } + + function cmdNewAlbum( $pParamHash ) { + global $gBitUser; + $response = array(); + + if( empty( $pParamHash['newAlbumTitle'] ) ) { + $pParamHash['newAlbumTitle'] = $gBitUser->getTitle()."'s Gallery"; + } + + $storeHash['title'] = !empty($pParamHash['newAlbumTitle']) ? $pParamHash['newAlbumTitle'] : ''; + $storeHash['edit'] = !empty($pParamHash['newAlbumDesc']) ? $pParamHash['newAlbumDesc'] : ''; + $gallery = new FisheyeGallery(); + $gallery->store( $storeHash ); + + if($pParamHash['set_albumName']){ + $parentGallery = new FisheyeGallery(); + if( $parentGallery = $parentGallery->lookup(array('content_id' => $pParamHash['set_albumName'] ) ) ) { + $parentGallery->load(); + $gallery->addToGalleries(array($parentGallery->mGalleryId)); + } + } + + $response = $this->createResponse( FEG2REMOTE_SUCCESS, 'Gallery created', array( 'album_name' => $storeHash['title'] ) ); + + return $response; + } + + function sendResponse( $pResponse ) { + global $gBitUser; + print "#__GR2PROTO__\n"; +//error_log( "#__GR2PROTO__".' : '.$gBitUser->mUserId ); + foreach ($pResponse as $k => $value) { + print "$k=$value\n"; +//error_log( "$k=$value" ); + } + // must be last + print "auth_token=".$gBitUser->mTicket; +//error_log( "auth_token=".$gBitUser->mTicket ); +//error_log( "#__end__" ); + } + + + function createResponse( $pStatus, $pStatusText, $pExtra = NULL ) { + $ret = array(); + + // Each response must contain at least the keys: status and status_text. + $ret['status'] = $this->cleanResponseValue( $pStatus ); + // translate the text response for i18n + $ret['status_text'] = $this->cleanResponseValue( tra( $pStatusText ) ); + // tack on any additional responses + if( !empty( $pExtra ) && is_array( $pExtra ) ) { + foreach( $pExtra as $k => $value ) { + $ret[$this->cleanResponseKey( $k )] = $this->cleanResponseValue( $value ); + } + } + return $ret; + } + + /** + * This will clean up the response value to make sure it is in an acceptable format for the remote client. + * Gallery apparently is very particular about the manner in which this data is cleaned up, and must be done + * in this specific order. + */ + function cleanResponseValue( $pValue ) { + $pValue = str_replace('\\', '\\\\', $pValue); + $pValue = str_replace("\r\n", '\n', $pValue); + $pValue = str_replace(array("\r", "\n", "\t"), array('\n', '\n', '\t'), $pValue); + $pValue = str_replace(array('#', '!', '='), array('\\#', '\\!', '\\='), $pValue); + return $pValue; + } + + + function cleanResponseKey( $pKey ) { + return str_replace(array('#', '!', '=', ':'), array('\\#', '\\!', '\\=', '\\:'), $pKey); + } + + +} diff --git a/includes/display_fisheye_gallery_inc.php b/includes/display_fisheye_gallery_inc.php new file mode 100644 index 0000000..f83d6e1 --- /dev/null +++ b/includes/display_fisheye_gallery_inc.php @@ -0,0 +1,59 @@ +<?php +/** + * @package fisheye + * @subpackage functions + */ + +$displayHash = array( 'perm_name' => 'p_fisheye_view' ); +$gContent->invokeServices( 'content_display_function', $displayHash ); + +if (!empty($_REQUEST['page']) && is_numeric($_REQUEST['page'])) { + $page = $_REQUEST['page']; +} else { + $page = 0; +} + +if( $page > $gContent->getField( 'num_pages' ) ) { + $page = $gContent->getField( 'num_pages' ); +} elseif ($page < 1) { + $page = 1; +} + +$imagesPerPage = $gContent->getField( 'rows_per_page' ) * $gContent->getField( 'cols_per_page', 10 ); + +switch( $gContent->getLayout() ) { + case 'auto_flow': + $gBitThemes->loadCss( FISHEYE_PKG_PATH."css/div_layout.css", TRUE ); + break; + case 'matteo': + $gBitThemes->loadCss( FISHEYE_PKG_PATH."gallery_view/matteo/mb_layout.css", TRUE ); + $gBitThemes->loadAjax( 'jquery' ); + $gBitThemes->loadJavascript( FISHEYE_PKG_PATH.'/gallery_views/matteo/mbGallery.js', FALSE, 500, FALSE ); + $gBitThemes->loadJavascript( FISHEYE_PKG_PATH.'/gallery_views/matteo/mbGalleryBox.js', FALSE, 501, FALSE ); + break; + case 'galleriffic': + $imagesPerPage = -1; + // Need to add options for different styles of layout + $gBitThemes->loadCss( FISHEYE_PKG_PATH."/gallery_views/galleriffic/css/galleriffic_style_1.css", TRUE ); + $gBitThemes->loadAjax( 'jquery' ); + $gBitThemes->loadJavascript( UTIL_PKG_PATH.'javascript/jquery/plugins/migrate/jquery.migrate.js', FALSE, 500, FALSE ); + $gBitThemes->loadJavascript( FISHEYE_PKG_PATH.'/gallery_views/galleriffic/js/jquery.galleriffic.js', FALSE, 500, FALSE ); + $gBitThemes->loadJavascript( FISHEYE_PKG_PATH.'/gallery_views/galleriffic/js/jquery.history.js', FALSE, 501, FALSE ); + $gBitThemes->loadJavascript( FISHEYE_PKG_PATH.'/gallery_views/galleriffic/js/jquery.opacityrollover.js', FALSE, 502, FALSE ); + $gBitThemes->loadJavascript( FISHEYE_PKG_PATH.'/gallery_views/galleriffic/gftop.js', FALSE, 503, FALSE ); + break; +} + +$imageOffset = $imagesPerPage * ($page-1); + +$gBitSmarty->assignByRef('pageCount', $page); +$gBitSmarty->assignByRef('imagesPerPage', $imagesPerPage); +$gBitSmarty->assignByRef('imageOffset', $imageOffset); +$gBitSmarty->assignByRef('rows_per_page', $gContent->mInfo['rows_per_page']); +$gBitSmarty->assign('cols_per_page', $gContent->getField( 'cols_per_page', 10 ) ); + +$gContent->loadImages( $page, $imagesPerPage ); +$gContent->addHit(); + +$gBitSystem->setBrowserTitle( $gContent->getTitle().' '.tra('Gallery') ); +$gBitSystem->display( $gContent->getRenderTemplate() , NULL, array( 'display_mode' => 'display' )); diff --git a/includes/display_fisheye_image_inc.php b/includes/display_fisheye_image_inc.php new file mode 100644 index 0000000..ae341e1 --- /dev/null +++ b/includes/display_fisheye_image_inc.php @@ -0,0 +1,25 @@ +<?php +/** + * @package fisheye + * @subpackage functions + */ + +if( !$gContent->isValid() ) { + $gBitSystem->fatalError( tra( "No image exists with the given ID" ) ,'error.tpl', '', HttpStatusCodes::HTTP_GONE ); +} + +$displayHash = array( 'perm_name' => 'p_fisheye_view' ); +$gContent->invokeServices( 'content_display_function', $displayHash ); + +// Get the proper thumbnail size to display on this page +if( empty( $_REQUEST['size'] )) { + $_REQUEST['size'] = $gBitSystem->getConfig( 'fisheye_image_default_thumbnail_size', FISHEYE_DEFAULT_THUMBNAIL_SIZE ); +} + +$gBitSystem->setBrowserTitle( $gContent->getTitle() ); +if( $gBitThemes->isAjaxRequest() ) { + $gBitSmarty->display( $gContent->getRenderTemplate() ); +} else { + $gBitSystem->display( $gContent->getRenderTemplate() , NULL, array( 'display_mode' => 'display' )); +} + diff --git a/includes/gallery_lookup_inc.php b/includes/gallery_lookup_inc.php new file mode 100644 index 0000000..b504585 --- /dev/null +++ b/includes/gallery_lookup_inc.php @@ -0,0 +1,25 @@ +<?php +/** + * @package fisheye + * @subpackage functions + */ + +global $gContent; + +$lookup = array(); + +if( !$gContent = FisheyeGallery::lookup( $_REQUEST ) ) { + $gContent = new FisheyeGallery(); + $galleryId = NULL; +} + +if( !empty( $_REQUEST['gallery_path'] ) ) { + $gContent->setGalleryPath( $_REQUEST['gallery_path'] ); +} elseif( $gContent->isValid() && $parents = $gContent->getParentGalleries() ) { + $gal = current( $parents ); + $gContent->setGalleryPath( '/'.$gal['gallery_id'] ); +} + +$gBitSmarty->assignByRef('gContent', $gContent); +$gBitSmarty->assignByRef('galleryId', $gContent->mGalleryId); + diff --git a/includes/image_lookup_inc.php b/includes/image_lookup_inc.php new file mode 100644 index 0000000..8de4b0e --- /dev/null +++ b/includes/image_lookup_inc.php @@ -0,0 +1,46 @@ +<?php +/** + * @version $Header$ + * @package fisheye + * @subpackage functions + */ + +global $gContent, $gGallery; + + +if( $gContent = FisheyeImage::lookup( $_REQUEST ) ) { + // nothing to do. ::lookup will do a full load +} else { + $gContent = new FisheyeImage(); + $imageId = NULL; +} + +if( !empty( $_REQUEST['gallery_path'] ) ) { + $_REQUEST['gallery_path'] = rtrim( $_REQUEST['gallery_path'], '/' ); + $gContent->setGalleryPath( $_REQUEST['gallery_path'] ); + $matches = array(); + $tail = strrpos( $_REQUEST['gallery_path'], '/' ); + $_REQUEST['gallery_id'] = substr( $_REQUEST['gallery_path'], $tail + 1 ); +} +if( empty( $_REQUEST['gallery_id'] ) ) { + if( $parents = $gContent->getParentGalleries() ) { + $gal = current( $parents ); + $gContent->setGalleryPath( '/'.$gal['gallery_id'] ); + $_REQUEST['gallery_id'] = $gal['gallery_id']; + } +} +// the image is considered the primary content, however the gallery is useful +if( !empty($_REQUEST['gallery_id']) && is_numeric($_REQUEST['gallery_id']) ) { + $gGallery = FisheyeGallery::lookup( $_REQUEST ); + $gBitSmarty->assignByRef('gGallery', $gGallery); + $gBitSmarty->assignByRef('galleryId', $_REQUEST['gallery_id']); +} + +// This user does not own this gallery and they have not been granted the permission to edit this gallery +$gContent->verifyViewPermission(); + +$gBitSmarty->assignByRef('gContent', $gContent); +$gBitSmarty->assignByRef('imageId', $gContent->mImageId ); + + +?> diff --git a/includes/upload_inc.php b/includes/upload_inc.php new file mode 100644 index 0000000..90957fb --- /dev/null +++ b/includes/upload_inc.php @@ -0,0 +1,360 @@ +<?php +/** + * @package fisheye + * @subpackage functions + */ + + + +/** + * fisheye_handle_upload + */ +function fisheye_handle_upload( &$pFiles ) { + global $gBitUser, $gContent, $gBitSystem, $fisheyeErrors, $fisheyeWarnings, $fisheyeSuccess, $gFisheyeUploads; + + // first of all set the execution time for this process to unlimited + set_time_limit(0); + + $upImages = array(); + $upArchives = array(); + $upErrors = array(); + $upData = array(); + + $i = 0; + usort( $pFiles, 'fisheye_sort_uploads' ); + + foreach( array_keys( $pFiles ) as $key ) { + $pFiles[$key]['type'] = $gBitSystem->verifyMimeType( $pFiles[$key]['tmp_name'] ); + if( preg_match( '/(^image|pdf|vnd)/i', $pFiles[$key]['type'] ) ) { + $upImages[$key] = $pFiles[$key]; + // clone the request data so edit service values are passed into store process + $upData[$key] = $_REQUEST; + // add the form data for each upload + if( !empty( $_REQUEST['imagedata'][$i] ) ) { + array_merge( $upData[$key], $_REQUEST['imagedata'][$i] ); + } + } elseif( !empty( $pFiles[$key]['tmp_name'] ) && !empty( $pFiles[$key]['name'] ) ) { + $upArchives[$key] = $pFiles[$key]; + } + $i++; + } + + $gallery_additions = array(); + + // No gallery was specified, let's try to find one or create one. + if( empty( $_REQUEST['gallery_additions'] ) ) { + if( $gBitUser->hasPermission( 'p_fisheye_create' )) { + $upData['gallery_additions'] = array( fisheye_get_default_gallery_id( $gBitUser->mUserId, $gBitUser->getDisplayName()."'s Gallery" ) ); + } else { + $gBitSystem->fatalError( tra( "You don't have permissions to create a new gallery. Please select an existing one to insert your images to." )); + } + } + + foreach( array_keys( $upArchives ) as $key ) { + $upErrors = fisheye_process_archive( $upArchives[$key], $gContent, TRUE ); + } + + foreach( array_keys( $upImages ) as $key ) { + // resize original if we the user requests it + if( !empty( $_REQUEST['resize'] ) ) { + $upImages[$key]['resize'] = $_REQUEST['resize']; + } + $upErrors = array_merge( $upErrors, fisheye_store_upload( $upImages[$key], $upData[$key], !empty( $_REQUEST['rotate_image'] ))); + } + + if( !is_object( $gContent ) || !$gContent->isValid() ) { + $gContent = new FisheyeGallery( $_REQUEST['gallery_additions'][0] ); + $gContent->load(); + } + + if( !empty( $gFisheyeUploads ) ){ + $_REQUEST['uploaded_objects'] = &$gFisheyeUploads; + $gContent->invokeServices( "content_post_upload_function", $_REQUEST ); + } + + return $upErrors; +} + + +/** + * fisheye_sort_upload + */ +function fisheye_sort_uploads( $a, $b ) { + return strnatcmp( $a['name'], $b['name'] ); +} + +/** + * fisheye_get_default_gallery_id + */ +function fisheye_get_default_gallery_id( $pUserId, $pNewName ) { + global $gBitUser; + $gal = new FisheyeGallery(); + $getHash = array( 'user_id' => $pUserId, 'max_records' => 1, 'sort_mode' => 'created_desc', 'show_empty' => TRUE ); + $upList = $gal->getList( $getHash ); + if( !empty( $upList ) ) { + $ret = key( $upList ); + } else { + $galleryHash = array( 'title' => $pNewName ); + if( $gal->store( $galleryHash ) ) { + $ret = $gal->mGalleryId; + } + } + + global $gContent; + if( $ret && (!is_object( $gContent ) || !$gContent->isValid()) ) { + $gContent = new FisheyeGallery( $ret ); + $gContent->load(); + } + return $ret; +} + +/** + * fisheye_store_upload + */ +function fisheye_store_upload( &$pFileHash, $pImageData = array(), $pAutoRotate=TRUE ) { + global $gBitSystem, $gFisheyeUploads; + $ret = array(); + + // verifyMimeType to make sure we are working with the proper file type assumptions + $pFileHash['type'] = $gBitSystem->verifyMimeType($pFileHash['tmp_name']); + if( !empty( $pFileHash ) && ( $pFileHash['size'] > 0 ) && is_file( $pFileHash['tmp_name'] ) && fisheye_verify_upload_item( $pFileHash ) ) { + // make a copy for each image we need to store + $image = new FisheyeImage(); + // Store/Update the image + $pImageData['_files_override'] = array( $pFileHash ); + $pImageData['process_storage'] = STORAGE_IMAGE; + $pImageData['purge_from_galleries'] = TRUE; + // store the image + if( !$image->store( $pImageData ) ) { + $ret = $image->mErrors; + } else { + $pFileHash['content_id'] = $image->getField( 'content_id' ); + $pFileHash['image_id'] = $image->getField( 'image_id' ); + $image->load(); + // play with image some more if user has requested it + if( $pAutoRotate ) { + $image->rotateImage( 'auto' ); + } + $image->addToGalleries( BitBase::getParameter( $pImageData, 'gallery_additions' ) ); + $gFisheyeUploads[] = $image; + } + + // when we're using xupload, we need to remove temp files manually + @unlink( $pFileHash['tmp_name'] ); + } + return $ret; +} + +/** + * Recursively builds a tree where each directory represents a gallery, and files are assumed to be images. + */ +function fisheye_process_archive( &$pFileHash, &$pParentGallery, $pRoot=FALSE ) { + global $gBitSystem, $gBitUser; + $errors = array(); + + if( ( $destDir = liberty_process_archive( $pFileHash ) ) && ( !empty( $_REQUEST['process_archive'] ) || !$gBitUser->hasPermission( 'p_fisheye_upload_nonimages' ) ) ) { + if( empty( $pParentGallery ) && !is_file( $pFileHash['tmp_name'] ) ) { + $pParentGallery = new FisheyeGallery(); + $galleryHash = array( 'title' => basename( $destDir ) ); + if( !$pParentGallery->store( $galleryHash ) ) { + $errors = array_merge( $errors, array_values( $pParentGallery->mErrors ) ); + } + global $gContent; + $gContent = &$pParentGallery; + } + + if( !empty( $pParentGallery ) ) { + $pFileHash['gallery_id'] = $pParentGallery->getField( 'gallery_id' ); + } + fisheye_process_directory( $destDir, $pParentGallery, $pRoot ); + } else { + global $gBitUser; + if( $gBitUser->hasPermission( 'p_fisheye_upload_nonimages' ) ) { + $errors = array_merge( $errors, fisheye_store_upload( $pFileHash )); + } else { + $errors['upload'] = tra( 'Your upload could not be processed because it was determined to be a non-image and you only have permission to upload images.' ); + } + } + return $errors; +} + +if( !function_exists( 'fisheye_verify_upload_item' ) ) { +// Possible override +function fisheye_verify_upload_item( $pScanFile ) { + global $gBitUser; + return $gBitUser->hasPermission( 'p_fisheye_upload_nonimages' ) || preg_match( '/^video\/*/', $pScanFile['type'] ) || preg_match( '/^image\/*/', $pScanFile['type'] ) || preg_match( '/pdf/i', $pScanFile['type'] ); +} +} + +/** + * Recursively builds a tree where each directory represents a gallery, and files are assumed to be images. + */ +function fisheye_process_directory( $pDestinationDir, &$pParentGallery, $pRoot=FALSE ) { + global $gBitSystem, $gBitUser; + $errors = array(); + if( $archiveDir = opendir( $pDestinationDir ) ) { + $order = 100; + while( $fileName = readdir($archiveDir) ) { + $sortedNames[] = $fileName; + } + sort( $sortedNames ); + foreach( $sortedNames as $fileName ) { + if( $fileName == 'Thumbs.db' ) { + unlink( "$pDestinationDir/$fileName" ); + } + if( !preg_match( '/^\./', $fileName ) && ( $fileName != 'Thumbs.db' ) ) { + $mimeResults = $gBitSystem->verifyFileExtension( $pDestinationDir.'/'.$fileName ); + $scanFile = array( + 'type' => $mimeResults[1], + 'name' => $fileName, + 'size' => filesize( "$pDestinationDir/$fileName" ), + 'tmp_name' => "$pDestinationDir/$fileName", + ); + + if( !empty( $_REQUEST['resize'] ) && is_numeric( $_REQUEST['resize'] ) ) { + $scanFile['max_height'] = $scanFile['max_width'] = $_REQUEST['resize']; + } + + if( is_dir( $pDestinationDir.'/'.$fileName ) ) { + if( $fileName == '__MACOSX' ) { + // Mac OS resources file + unlink_r( $pDestinationDir.'/'.$fileName ); + } else { + // We found a new Gallery! + $newGallery = new FisheyeGallery(); + $galleryHash = array( 'title' => str_replace( '_', ' ', $fileName ) ); + if( $newGallery->store( $galleryHash ) ) { + if( $pRoot ) { + $newGallery->addToGalleries( $_REQUEST['gallery_additions'] ); + } + if( is_object( $pParentGallery ) ) { + $pParentGallery->addItem( $newGallery->mContentId, $order ); + } + //recurse down in! + $errors = array_merge( $errors, fisheye_process_archive( $scanFile, $newGallery ) ); + } else { + $errors = array_merge( $errors, array_values( $newGallery->mErrors ) ); + } + } + } elseif( preg_match( '/.+\/*zip*/', $scanFile['type'] ) ) { + //recurse down in! + $errors = array_merge( $errors, fisheye_process_archive( $scanFile, $pParentGallery ) ); + } elseif( fisheye_verify_upload_item( $scanFile ) ) { + $newImage = new FisheyeImage(); + $imageHash = array( '_files_override' => array( $scanFile ) ); + if( $newImage->store( $imageHash ) ) { + if( $pRoot ) { + $newImage->addToGalleries( $_REQUEST['gallery_additions'] ); + } + if( !is_object( $pParentGallery ) ) { + global $gBitUser; + $pParentGallery = new FisheyeGallery( fisheye_get_default_gallery_id( $gBitUser->mUserId, $gBitUser->getDisplayName()."'s Gallery" ) ); + $pParentGallery->load(); + } + $pParentGallery->addItem( $newImage->mContentId ); + } else { + $errors = array_merge( $errors, array_values( $newImage->mErrors ) ); + } + } elseif( is_file( $scanFile['tmp_name'] ) ) { + // unknown file type, let's be tidy and clean it up + unlink( $scanFile['tmp_name'] ); + } + $order += 10; + } + } + if ( !is_windows() ) { + unlink_r( $pDestinationDir ); + } + } + return $errors; +} + + +// this function will process a directory and all it's sub directories without +// making any assumptions. hierarchy of sub directories is maintained and +// archives can be processed or simply added to the galleries. +function fisheye_process_ftp_directory( $pProcessDir ) { + global $gBitSystem, $gBitUser; + if( empty( $_REQUEST['gallery_additions'] ) ) { + $_REQUEST['gallery_additions'] = array(); + } + + $errors = array(); + if( $archiveDir = opendir( $pProcessDir ) ) { + $order = 100; + while( $fileName = readdir($archiveDir) ) { + $sortedNames[] = $fileName; + } + + sort( $sortedNames ); + $order = 100; + + foreach( $sortedNames as $fileName ) { + if( !preg_match( '/^\./', $fileName ) && ( $fileName != 'Thumbs.db' ) ) { + $scanFile = array( + 'type' => $gBitSystem->lookupMimeType( substr( $fileName, ( strrpos( $fileName, '.' ) + 1 ) ) ), + 'name' => $fileName, + 'size' => filesize( "$pProcessDir/$fileName" ), + 'tmp_name' => "$pProcessDir/$fileName", + ); + + if( is_dir( $pProcessDir.'/'.$fileName ) ) { + // create a new gallery from directory + $dirGallery = new FisheyeGallery(); + $galleryHash = array( 'title' => str_replace( '_', ' ', $fileName ) ); + if( $dirGallery->store( $galleryHash ) ) { + $dirGallery->addToGalleries( $_REQUEST['gallery_additions'] ); + $errors = array_merge( $errors, fisheye_process_directory( $pProcessDir.'/'.$fileName, $dirGallery ) ); + } else { + $errors = array_merge( $errors, array_values( $dirGallery->mErrors ) ); + } + unset( $dirGallery ); + } else { + if( preg_match( '/(^image|pdf)/i', $scanFile['type'] ) ) { + // process image + $newImage = new FisheyeImage(); + $imageHash = array( 'upload' => $scanFile ); + if( $newImage->store( $imageHash ) ) { + $newImage->addToGalleries( $_REQUEST['gallery_additions'] ); + + // if we have a gallery to add these images to, load one of them + if( !empty( $_REQUEST['gallery_additions'][0] ) && @!is_object( $imageGallery ) ) { + $imageGallery = new FisheyeGallery(); + $imageGallery->mGalleryId = $_REQUEST['gallery_additions'][0]; + $imageGallery->load(); + } + + if( @!is_object( $imageGallery ) ) { + global $gBitUser; + $galleryHash = array( 'title' => $gBitUser->getDisplayName()."'s Gallery" ); + $imageGallery = new FisheyeGallery(); + if( $imageGallery->store( $galleryHash ) ) { + $imageGallery->load(); + } else { + $errors = array_merge( $errors, array_values( $imageGallery->mErrors ) ); + } + } + + $imageGallery->addItem( $newImage->mContentId ); + } else { + $errors = array_merge( $errors, array_values( $newImage->mErrors ) ); + } + } else { + // create a new gallery from archive + $archiveGallery = new FisheyeGallery(); + $galleryHash = array( 'title' => substr( $fileName, 0, ( str_replace( '_', ' ', strrpos( $fileName, '.' ) ) ) ) ); + if( !$archiveGallery->store( $galleryHash ) ) { + $errors = array_merge( $errors, array_values( $archiveGallery->mErrors ) ); + } + + $errors = fisheye_process_archive( $scanFile, $archiveGallery, TRUE ); + unset( $archiveGallery ); + } + } + $order += 10; + } + } + } + return $errors; +} +?> |
