/home/coolpkct/www/websites/cake3.cool.rocks/admin/classes/gallery.php
<?php
/**
 * Part of Showkase web site management package
 *
 * @package Showkase
 * @author Jack Hardie {@link http://www.jhardie.com}
 * @copyright Copyright (c) 2013, SimpleViewer Inc.
 */
defined('SK_ACCESS')||die('<h1>403: Forbidden</h1>'); 
require_once 'classes'.DIRECTORY_SEPARATOR.'pathparser.php';
require_once 'classes'.DIRECTORY_SEPARATOR.'helpers.php';
require_once 'classes'.DIRECTORY_SEPARATOR.'thumbnail.php';
 
/**
 * Models a generalised gallery
 *
 * @package Showkase
 */
abstract class Gallery
{
    /**
     * @var object Page creating this gallery
     */
    protected $page;
    
    /**
     * @var integer unique gallery reference
     */
    protected $galleryRef;
    
    /**
     * @var array of image objects
     */
    protected $imageObjects = array();
    
    /**
     * @var string settings tag in gallery xml file
     */
    protected $xmlSettingsTag;
    
    /**
     * @var string gallery.xml file image tag name
     */
    protected $xmlImageTag;
    
    /**
     * @var string gallery path relative to cwd
     */
    protected $galleryPathRelSvm;
    
    /**
     * Viewer default settings
     *
     * @var array
     */
    private $viewerDefaults = array();
    /**
     * @var object instance of pathParser class
     */
    protected $pathParser;
        
    /**
     * @var string sort order 'dragndrop', 'alpha', 'ralpha', 'date', 'rdate'
     */
    protected $sortOrder = GALLERY_DEFAULT_SORT;
    
    /**
     * @var instance of site singleton
     */
    protected $site;
    
    /**
     * @var string file name of source image for gallery index page
     */
    protected $indexThumb = '';
     
    /**
     * Constructor
     * 
     * @param object Page
     * @param string gallery reference (permanent reference, not the    galleriesData index)
     * @param string gallery path
     * @param boolean new gallery
     */    
    function __construct(Page $page, $ref, $path)
    {
        $this->page = $page;
        $this->pathParser = new PathParser();
        $this->config = SkConfig::getInstance();
        $this->galleryRef = $ref;
        $this->galleryPathRelSvm = $path;
        $imageDir = rtrim($this->getImageDirPathRelSvm(), '\\/');
        $thumbDir = rtrim($this->getThumbDirPathRelSvm(), '\\/');
        $defaultsFile = 
            'plugins'.DIRECTORY_SEPARATOR.
            $this->page->getPageType().DIRECTORY_SEPARATOR.
            'defaults.ini'
        ;
        if (file_exists($defaultsFile)) {
            $this->viewerDefaults = @parse_ini_file($defaultsFile);
            if ($this->viewerDefaults === false) {
                Board::addMessage('Cannot read default settings from '.$defaultsFile, 'warning');
            }
        }
        if (!is_dir($imageDir) || !is_dir($thumbDir)) {
            try {
                $this->addGalleryDirectories($imageDir, $thumbDir);
            } catch (Exception $e) {
            Board::addExceptionMessage($e);
            } 
        }
        if (!is_dir(rtrim($this->galleryPathRelSvm, '\\/'))) {
            throw new Exception('Cannot find gallery folder '.$this->galleryPathRelSvm);
        }
        try {
            $prefs = $this->readPreferences();
            if (isset($prefs['sortOrder'])) {
                $this->sortOrder = $prefs['sortOrder'];
            }
            if (isset($prefs['indexThumb'])) {
                $this->indexThumb = $prefs['indexThumb'];
            }
        } catch (Exception $e) {
            Board::addExceptionMessage($e);
        }     
        try {
            $imagesData = $this->readImageExchangeFile();
            $this->makeImageObjects($imagesData);
        } catch (Exception $e) {
            Board::addExceptionMessage($e);
        }
    }
    
    /**
     * enforce child methods
     */
    abstract protected function getXmlPath();
    abstract public function getColorPrefix();
    abstract public function importConfig();
    
    /**
     * Get image data path
     *
     * @access private
     * @return string calculated image data path
     */
    function getImageDataPath()
    {
        return $this->galleryPathRelSvm.IMAGE_DATA_FILE;
    }
    
    /** 
      * Get stored image data from class
      *
      * @access public
      * @return array
      */
     public function getImageObjects()
     {
         return $this->imageObjects;
     }
    /**
     * Get gallery ref
     *
     * @access public
     * @return integer
     */
    function getGalleryRef()
    {
        return $this->galleryRef;
    }
    
    /**
     * Get gallery path
     *
     * @access public
     * @return string
     */
    function getGalleryPathRelSvm()
    {
        return $this->galleryPathRelSvm;
    }
    
    /**
     * Get index thumb source image file name
     *
     * @return string
     */
    public function getIndexThumb()
    {
        return $this->indexThumb;
    }
    
    /**
     * Set index thumb source image file name
     *
     * @return string
     * @param string image source file name
     */
    public function setIndexThumb($file)
    {
        $this->indexThumb = $file;
    }
    
    /**
     * Translate a path rel gallery to a url rel svm
     *
     * @access public
     * @return string
     * @param string path or url rel gallery
     */
    function getUrlRelSvm($pathRelGallery)
    {
        return $this->pathParser->fix($this->galleryPathRelSvm.$pathRelGallery);
    }
    
    /* Get image path relative to cwd with trailing separator
     * Image directory paths that start with ../ are fixed with pathparser
     *
     * @access private
     * @return string
     */
    function getImageDirPathRelSvm()
    {
        return str_replace(
            '/', DIRECTORY_SEPARATOR, $this->pathParser->fix(
                $this->galleryPathRelSvm.$this->imageDirPathRelGallery
            )
        );
    }
    
 /* Get thumb path relative to cwd with trailing separator
     *
     * @access private
     * @return string
     */
    function getThumbDirPathRelSvm()
    {
        return str_replace(
            '/', DIRECTORY_SEPARATOR, $this->pathParser->fix(
                $this->galleryPathRelSvm.$this->thumbDirPathRelGallery
            )
        );
    }
    
    /* Get image url relative to cwd
     * pathParser->fix gives forward slashes and fixes image paths that start ../
     *
     * @access public
     * @return string
     */
    function getImageDirUrlRelSvm()
    {
        return $this->pathParser->fix($this->galleryPathRelSvm.$this->imageDirPathRelGallery);
    }
    
    /* Get thumb url relative to cwd
     * pathParser->fix gives forward slashes and fixes thumb paths that start ../
     *
     * @access public
     * @return string
     */
    function getThumbDirUrlRelSvm()
    {
        return $this->pathParser->fix($this->galleryPathRelSvm.$this->thumbDirPathRelGallery);
    }
    
    /**
      * Update preferences and save
      *
      * @access public
      * @return void
      */
    function saveGalleryPreferences()
     {
         $newPrefs = array('sortOrder'=>$this->sortOrder, 'indexThumb'=>$this->indexThumb);
         if (false === Filer::skPutContents($this->galleryPathRelSvm.PREFERENCES_PATH, serialize($newPrefs), LOCK_EX)) {
             Board::addMessage('Unable to save gallery preferences to '.$this->galleryPathRelSvm.PREFERENCES_PATH, 'warning');
         }
     }
    
    /**
     * Create new image and thumb directories if necessary
     *
     * @return void
     * 
     */
    private function addGalleryDirectories($imageDir, $thumbDir)
    {
    
        if (!is_dir($imageDir)) {
            if (!Filer::skMkdir($imageDir, NEW_DIR_MODE)) {
                throw new Exception ('Unable to create image directory');
            }
        }
        if (!is_dir($thumbDir)) {
            if (!Filer::skMkdir($thumbDir, NEW_DIR_MODE)) {
                throw new Exception ('Unable to create thumb directory');
            }
        }
    
    }
    /**
     * Rebuild the local xml file
     * Unsets image object reference if file does not exist
     * Recreates all thumbs
     *
     * @access public
     * @return void
     */
    function rebuild()
    {
        $relImagePath = $this->getImageDirPathRelSvm();
        $relThumbPath = $this->getThumbDirPathRelSvm();
        foreach ($this->imageObjects as $key=>$imageObject) {
            if (!file_exists($this->galleryPathRelSvm.$imageObject->getimagePathRelGallery())) {
                unset($this->imageObjects[$key]);
            }
        }
        $scannedImageObjects = $this->scanImageData($relImagePath);
        $newImageObjects = $this->extractNewImageData($this->imageObjects, $scannedImageObjects);
        $this->imageObjects = array_merge($this->imageObjects, $newImageObjects);
        $this->sortImages();
        // if image is its own thumbnail, return
        if ($relImagePath == $relThumbPath) return;
        try {
            $this->makeThumbs($relThumbPath, $this->imageObjects, true);
        } catch (Exception $e) {
            Board::addExceptionMessage($e);
        }
    }
    /**
     * Add new images
     *
     * Similar to rebuild but does not unset image references or overwrite existing thumbs
     * retains existing captions etc
     *
     * @return void
     */
    public function addNewImages()
    {
        $relImagePath = $this->getImageDirPathRelSvm();
        $relThumbPath = $this->getThumbDirPathRelSvm();
        $scannedImageObjects = $this->scanImageData($relImagePath);
        $newImageObjects = $this->extractNewImageData($this->imageObjects, $scannedImageObjects);
        $this->imageObjects = array_merge($newImageObjects, $this->imageObjects);
        $this->sortImages();
        // if image is its own thumbnail, return
        if ($relImagePath == $relThumbPath) return;
        // Note exceptions bubble up to Pluploader
        $this->makeThumbs($relThumbPath, $newImageObjects, OVERWRITE_THUMBNAILS);
    }
    
    /**
     * returns array of imageObjects for files found in default image location
     *
     * @param string relative image directory path
     * @return array
     */
    private function scanImageData($relImagePath)
    {
        $imageObjects = array();              
        if (!is_dir($relImagePath)) {
            if (!Filer::skMkdir($relImagePath, NEW_DIR_MODE)) {
                throw new Exception ('ScanImageData cannot create the image directory '.$relImagePath);
            }
        }
        $handle = @opendir($relImagePath);
        if ($handle === false) {
            throw new Exception ('ScanImageData cannot open the '.$relImagePath.' directory – check the file permissions');
        }
        while (false !== ($fileName = readdir($handle))) {
          	if (!$this->isImage($fileName)) {
          	    continue;
            }
          	$imageSize = @getimagesize($relImagePath.$fileName);
          	$imageObjects[] = new $this->imageClass($this->page, $this->galleryPathRelSvm, $this->imageDirPathRelGallery.$fileName, null);
        }
        closedir($handle);
        return $imageObjects;
    }
    
    /**
     * Extract new image data from scan containing all current image data
     *
     * @access private
     * @return array new image data
     * @param array old image data
     * @param array scanned image data
     */
    function extractNewImageData($oldImageObjects, $scannedImageObjects)
    {
        $newImageObjects = array();
        foreach ($scannedImageObjects as $key=>$imageObject) {
            if ($this->fileInImageData($imageObject->getImageFileName(), $oldImageObjects) === false) {
                $newImageObjects[] = $imageObject;
            }
        }
        return $newImageObjects;
    }
    
    /** Test if fileName already present in the imageData array
     *
     * @access private
     * @return integer array key
     * @param string needle
     * @param array haystack
     */
    function fileInImageData($fileName, $imageObjects)
    {
        foreach ($imageObjects as $key=>$imageObject) {
            if ($imageObject->getImageFileName() === $fileName) return $key;
        }
        return false;
    }
    /**
     * Get root url
     *
     * @access public
     * @return string calculated root url with forward slashes
     */
    function getRootUrl()
    {
    	  return '/'.ltrim($this->pathParser->fix(dirname($_SERVER['PHP_SELF']).'/'.$this->galleryPathRelSvm),'/');
    }
        
    /**
     * Read preferences file
     * 
     * @access private
     * @return array as in preferences file
     */
    function readPreferences()
    {
        if (!file_exists($this->galleryPathRelSvm.PREFERENCES_PATH)) {
            // no exception here - normal condition for new gallery
            return array();
        }        
        $prefs = @file_get_contents($this->galleryPathRelSvm.PREFERENCES_PATH);
        if ($prefs === false) {
            throw new Exception('cannot read preferences file '.$this->galleryPathRelSvm.PREFERENCES_PATH.', default values will be used');
        }
        $prefs = unserialize($prefs);
        if ($prefs === false) {
            throw new Exception('preferences file '.$this->galleryPathRelSvm.PREFERENCES_PATH.', is corrupt; default values will be used');
        }
        return $prefs;                 
    }
    
    /**
     * test for jpg
     *
     * Note that preg_match_all returns a number and false for badly formed utf-8
     * version including swf is (0 == preg_match_all('(.*\.((jpe?g)|(swf)|(png)|(gif))$)ui', $fileName, $matches))
     *
     * @return boolean true if filename ends in jpg, jpeg, png or gif (case insensitive)
     * @parameter string file name
     * @access private
     */
    protected function isImage($fileName)
    {
        return (0 != preg_match_all('(.*\.((jpe?g)|(png)|(gif))$)ui', $fileName, $matches));
    }
    
    /**
     * creates new thumbnails
     *
     * @param string path with trailing separator
     * @param string path with trailing separator
     * @param array file names and captions
     * @param boolean overwrite existing thumbnails (only relevant for rebuild)
     * @return integer number of thumbnails created or zero on error
     */
    protected function makeThumbs($thumbsPath, $imageObjects, $overwrite = true)
    {
        $thumbCount = 0;
        $thumbsDir = rtrim($thumbsPath, '\\/');
        if (!is_dir($thumbsDir)) {
            if (!Filer::skMkdir($thumbsDir, NEW_DIR_MODE)) {
                throw new Exception('Notice: no thumbnails, cannot create the thumbnail directory '.$thumbsDir);
            }
        }
        $gdVersion = Helpers::getGDversion();
        if (version_compare($gdVersion, '2.0', '<')) {
            throw new Exception('The GD imaging library was not found on this server or it is an old version that does not support jpeg images. Thumbnails will not be created. Either upgrade to a later version of GD or create the thumbnails yourself in a graphics application such as Photoshop.');
        }
        foreach ($imageObjects as $key=>$imageObject) {
            $fileName = $imageObject->getImageFileName();
            $image = $this->galleryPathRelSvm.$imageObject->getImagePathRelGallery();
            $thumbPath = $thumbsPath.$fileName;
            if (@file_exists($thumbPath) && !$overwrite) {
                continue;
            }
            if (@!file_exists($image)) {
                Board::addExceptionMessage('Image '.$image.' cannot be found');
                continue;
            }
            $thumbnail = new Thumbnail($this->thumbWidth, $this->thumbHeight, $this->thumbQuality);
            $thumbnail->createThumb($image, $thumbPath);
            $thumbCount ++;
        }
        return $thumbCount;
    }
    
       /**
      * return an array of properly formatted hex color strings
      *
      * @access private
      * @return array
      * @param array of strings containing hex color
      * @param integer required length of hex number in characters
      */
     function cleanHexArray($colors, $length = 6)
     {
         foreach ($colors as &$color) {
             $color = Helpers::cleanHex($color, $length);
         }
         return $colors;
     }
     
    /**
     * Flag images for deletion
     *
     * @return void
     * @param array indices of deleted images
     */
    public function flagDeletedImages(array $delFiles)
    {
        foreach ($delFiles as $key=>$checked) {
            if (array_key_exists($key, $this->imageObjects)) {
                $this->imageObjects[$key]->setImageDeleted(true);
            }
        }
    }
    /**
     * Remove image from this->imageData, delete image and thumbnail
     *
     * @access private
     * @return true on success
     */
    function deleteImages()
    {
        $relThumbPath = $this->getThumbDirPathRelSvm();
        foreach ($this->imageObjects as $key=>$image) {
            if (!$image->isDeleted()) continue;
            $filePath = $this->galleryPathRelSvm.$image->getImagePathRelGallery();
            $fileName = basename($filePath);
            if ($fileName == $this->indexThumb) {
                $this->indexThumb = '';
            }
            $info = pathinfo($filePath);
            $thumbName =    basename($filePath,'.'.$info['extension']).'.jpg';
            unset ($this->imageObjects[$key]);
            if (file_exists($filePath)) {
                if (!Filer::skUnlink($filePath)) {
                    Board::addMessage('unable to delete image file '.$filePath, 'warning');
                }
            }
            if (file_exists($relThumbPath.$thumbName)) {
                if (!Filer::skUnlink($relThumbPath.$thumbName)) {
                    Board::addMessage('unable to delete thumbnail '.$thumbName, 'warning');
                }
            }
        }
        // re-index
        $this->imageObjects = array_values($this->imageObjects);
    }
    
    /**
     * Get current image sort order, e.g. 'dragndrop'
     *
     * @return string
     */
    public function getSortOrder()
    {
        return $this->sortOrder;
    }
    
    /**
     * Set current image sort order, e.g. 'dragndrop'
     *
     * @param string
     * @return void
     */
    public function setSortOrder($sortOrder)
    {
        $this->sortOrder = $sortOrder;
    }
    
    /**
     * Sort images
     *
     * @access private
     * @return void
     * @param array to sort
     * @param string sort order ['dragndrop' | 'alpha' | 'ralpha' | 'date' | 'rdate']
     */
    public function sortImages($sortOutput = 'nosort')
    {
        $relImagePath = $this->getImageDirPathRelSvm();
        if (
            $this->sortOrder == 'dragndrop'
            && $sortOutput == 'nosort'
        ) {
            return;
        }
        $fileName = array();
        $fileMTime = array();
        foreach ($this->imageObjects as $key => $row) {
            $fileName[$key]  = $row->getImageFileName();
            $fileMTime[$key] = filemtime($relImagePath.$fileName[$key]);
        }
        switch ($this->sortOrder) {
            case 'dragndrop' :
                parse_str($sortOutput, $temp);
                $newIndex = $temp['image'];
                foreach ($this->imageObjects as $key=>$imageObject) {
                    $newImageObjects[$key] = $this->imageObjects[$newIndex[$key]];
                }
                $this->imageObjects = $newImageObjects;
                break;
            case 'alpha':
                array_multisort($fileName, SORT_ASC, $this->imageObjects);
                break;
            case 'ralpha':
                array_multisort($fileName, SORT_DESC, $this->imageObjects);
                break;
            case 'date':
                array_multisort($fileMTime, SORT_ASC, SORT_NUMERIC, $this->imageObjects);
                break;
            case 'rdate':
                array_multisort($fileMTime, SORT_DESC, SORT_NUMERIC, $this->imageObjects);
                break;
        }
     }
    /** Save thumbnail for galleries index screen
     *
     * @access private
     * @return void
     */
    public function saveIndexThumb()
    {
        if ($this->page->getPageType() == 'library') return;
        $theme = $this->page->getTheme();
        $size = $theme->getIndexThumbSize();
        $relThumbPath = $this->getThumbDirPathRelSvm();
        $thumbCache = rtrim($this->config->getThumbCachePath(), '\\/');
        $destThumb = $thumbCache.DIRECTORY_SEPARATOR.INDEX_THUMB_PREFIX.$this->galleryRef.'.jpg';
        if (!file_exists($thumbCache)) {
            if (!Filer::skMkdir($thumbCache, NEW_DIR_MODE)) {
                throw new Exception('Unable to create thumbnail cache for gallery index ');
            }
        }
        $image = '';
        switch (true) {
            case !empty($this->indexThumb) :
                $image = $this->galleryPathRelSvm.$this->imageDirPathRelGallery.$this->indexThumb;
                break;
            case isset($this->imageObjects[0]) :
                $image = $this->galleryPathRelSvm.$this->imageObjects[0]->getImagePathRelGallery();
        }
        if (!file_exists($image)) {
            $image = rtrim(IMAGE_SRC, '\\/').DIRECTORY_SEPARATOR.'noindexthumb.gif';
        }
        if (file_exists($destThumb) && !OVERWRITE_INDEX_THUMBS) return;
        try {
            $thumbnail = new Thumbnail($size['width'], $size['height'], $this->thumbQuality);
            $thumbnail->createThumb($image, $destThumb);
        } catch (Exception $e) {
            if (!Filer::skCopy(IMAGE_SRC.'nothumb.gif', $destThumb)) {
                throw new Exception('Unable to create new thumbnail ('.$e->getMessage().')');
            }
        }
    }
        
    /**
     * Construct xml string and write to file
     * May be overriden for some gallery types
     * htmlspecialchars is used in case any xml reserved characters sneak into attributes
     *
     * @param string file path
     * @return void
     */
    protected function writeXml($xmlPath)
    {
        $imageObjects = $this->imageObjects;
        $attributes = $this->getGallerySettings();
        $pageDoc = new domDocument('1.0', 'utf-8');
        $pageDoc->formatOutput = true;
        $root = $pageDoc->createElement($this->xmlSettingsTag);
        $rootElement = $pageDoc->appendChild($root);
        foreach ($attributes as $name=>$value) {
            $rootElement->setAttribute($name, $value);
        }
        foreach ($imageObjects as $key=>$imageObject) {
            $imageDoc = $imageObject->getXml();
            $imageElements = $imageDoc->getElementsByTagName($this->xmlImageTag);
            $imageElement = $imageElements->item(0);
            $newNode = $pageDoc->importNode($imageElement, true);
            $rootElement->appendChild($newNode);
        } 
        $xml = $pageDoc->saveXml();
        if (false === Filer::skPutContents($xmlPath, $xml, LOCK_EX)) {
            throw new Exception('Unable to write xml to file '.basename($xmlPath));
        } 
    }
    
    /**
     * get gallery settings
     *
     * @return array
     */
    private function getGallerySettings()
    {
        $pageVars = $this->page->getAllVars($this->getColorPrefix());
        // $diffs contains gallery variables changed from default + page variables
        $diffs = array_diff_assoc($pageVars, $this->viewerDefaults);
        // remove non-gallery variables
        return array_intersect_key($diffs, $this->viewerDefaults);
    }    
    
    /**
      * Save all gallery data to xml file and preferences file
      *
      * @access public
      * @return void
      */
    function saveGallery()
    {
        $xmlPath = $this->getXmlPath();
        $this->writeXml($xmlPath);
        $this->saveImageData();
        $this->saveGalleryPreferences();
        $this->saveIndexThumb();
    }
    
    /**
     * Save image data in generalised format
     */
    protected function saveImageData()
    {
        $imageDataPath = $this->getImageDataPath();
        $imageData = array();
        foreach ($this->imageObjects as $imageObject) {
            $imageData[] = $imageObject->getImageData();
        }
        if (false === Filer::skPutContents($this->getImageDataPath(), serialize($imageData), LOCK_EX)) {
            throw new Exception('cannot save image data to '.basename($this->getImageDataPath()));
        }
        
    }
    
    /**
     * Make array of image objects from image data file
     *
     * @return void
     * @param array of image data in gallery exchange format
     */
    public function makeImageObjects(array $imagesData)
    {
        $this->imageObjects = array();
        foreach ($imagesData as $imageData) {
            try {
                $this->imageObjects[] = new $this->imageClass($this->page, $this->galleryPathRelSvm, null, $imageData);
            } catch (Exception $e) {
                Board::addExceptionMessage($e);
            }
        }
    }
    
    /**
     * Read image data from Showkase gallery interchange file
     *
     * @return array
     */
    protected function readImageExchangeFile()
    {
        if (!file_exists($this->getImageDataPath())) return array();
        $contents = @file_get_contents($this->getImageDataPath());
        if ($contents === false) {
            throw new Exception('Warning: cannot read image data file '.basename($this->getImageDataPath()));
        }
        $imagesData = @unserialize($contents);
        if (!is_array($imagesData)) {
            throw new Exception('Warning: cannot recover image data from file '.basename($this->getImageDataPath()));
        }
        return $imagesData;
    }
    
    /**
     * Extract final directory name and file name from a URL
     *
     * @param string url
     * @return string
     */
    protected function relativeUrl($url)
    {
        if (
            $url[0] != '/'
            && stripos($url, 'http') !== 0
        ) {
            return $url;
        }
        return substr(strrchr(dirname($url), '/'), 1).'/'.basename($url);
    }
    
    /**
     * Reads image section of gallery xml file
     * Some galleries, e.g. Listviewer may not use an xml file
     *
     * @return array of image variables in gallery exchange format
     */
    public function readImagesData()
    {
      $imageExchangeData = $this->readImageExchangeFile();
      if (!empty($imageExchangeData)) {
          return $imageExchangeData;
      }
      if (empty($this->galleryXmlFile)) return array();
      $xmlPath = $this->galleryPathRelSvm.$this->galleryXmlFile;
      if (!file_exists($xmlPath)) return array();
      $pageXml = new Xml($xmlPath);
      $vars = array();
      $domDoc = $pageXml->getDomDoc();
      $imageTags = $domDoc->getElementsByTagName('image');
      foreach ($imageTags as $key=>$tag) {
          $titles = $tag->getElementsByTagName('title');
          $captions = $tag->getElementsByTagName('caption');
          $imageUrl = $tag->getAttribute('imageURL');
          if ($imageUrl == '') continue;
          $vars[$key]['imageUrl'] = $this->relativeUrl($imageUrl);
          $vars[$key]['thumbUrl'] = $this->relativeUrl($tag->getAttribute('thumbURL')); 
          $vars[$key]['imageTitle'] = ($titles->length > 0)
              ? $titles->item(0)->nodeValue
              : '';
          $vars[$key]['imageCaption'] = ($captions->length > 0)
              ? $captions->item(0)->nodeValue
              : '';
          $vars[$key]['imageLinkUrl']    = $tag->getAttribute('linkURL');
          $vars[$key]['imageLinkTarget'] = $tag->getAttribute('linkTarget');
      }
      return $vars;
   }
}