/** For every album in the gallery, look for its file. Delete from the database
  * if the file does not exist. Do the same for images. Clean up comments that have
  * been left orphaned.
  *
  * Returns true if the operation was interrupted because it was taking too long
  *
  * @param bool $cascade garbage collect every image and album in the gallery.
  * @param bool $complete garbage collect every image and album in the *database* - completely cleans the database.
  * @param  int $restart Image ID to restart scan from
  * @return bool
  */
 function garbageCollect($cascade = true, $complete = false, $restart = '')
 {
     if (empty($restart)) {
         // Check for the existence of top-level albums (subalbums handled recursively).
         $result = query("SELECT * FROM " . prefix('albums'));
         $dead = array();
         $live = array('');
         // purge the root album if it exists
         $deadalbumthemes = array();
         // Load the albums from disk
         $albumfolder = getAlbumFolder();
         while ($row = mysql_fetch_assoc($result)) {
             if (!file_exists($albumfolder . UTF8ToFilesystem($row['folder'])) || in_array($row['folder'], $live)) {
                 $dead[] = $row['id'];
                 if ($row['album_theme'] !== '') {
                     // orphaned album theme options table
                     $deadalbumthemes[$row['id']] = $row['folder'];
                 }
             } else {
                 $live[] = $row['folder'];
             }
         }
         if (count($dead) > 0) {
             /* delete the dead albums from the DB */
             $first = array_pop($dead);
             $sql1 = "DELETE FROM " . prefix('albums') . " WHERE `id`='{$first}'";
             $sql2 = "DELETE FROM " . prefix('images') . " WHERE `albumid`='{$first}'";
             $sql3 = "DELETE FROM " . prefix('comments') . " WHERE `type`='albums' AND `ownerid`='{$first}'";
             $sql4 = "DELETE FROM " . prefix('obj_to_tag') . " WHERE `type`='albums' AND `objectid`='{$first}'";
             foreach ($dead as $albumid) {
                 $sql1 .= " OR `id` = '{$albumid}'";
                 $sql2 .= " OR `albumid` = '{$albumid}'";
                 $sql3 .= " OR `ownerid` = '{$albumid}'";
                 $sql4 .= " OR `objectid` = '{$albumid}'";
             }
             $n = query($sql1);
             if (!$complete && $n > 0 && $cascade) {
                 query($sql2);
                 query($sql3);
                 query($sql4);
             }
         }
         if (count($deadalbumthemes) > 0) {
             // delete the album theme options tables for dead albums
             foreach ($deadalbumthemes as $id => $deadtable) {
                 $sql = 'DELETE FROM ' . prefix('options') . ' WHERE `ownerid`=' . $id;
                 query($sql, true);
             }
         }
     }
     if ($complete) {
         if (empty($restart)) {
             /* refresh 'metadata' of dynamic albums */
             $albumfolder = getAlbumFolder();
             $albumids = query_full_array("SELECT `id`, `mtime`, `folder` FROM " . prefix('albums') . " WHERE `dynamic`='1'");
             foreach ($albumids as $album) {
                 if (($mtime = filemtime($albumfolder . UTF8ToFilesystem($album['folder']))) > $album['mtime']) {
                     // refresh
                     $data = file_get_contents($albumfolder . UTF8ToFilesystem($album['folder']));
                     while (!empty($data)) {
                         $data1 = trim(substr($data, 0, $i = strpos($data, "\n")));
                         if ($i === false) {
                             $data1 = $data;
                             $data = '';
                         } else {
                             $data = substr($data, $i + 1);
                         }
                         if (strpos($data1, 'WORDS=') !== false) {
                             $words = "words=" . urlencode(substr($data1, 6));
                         }
                         if (strpos($data1, 'THUMB=') !== false) {
                             $thumb = trim(substr($data1, 6));
                         }
                         if (strpos($data1, 'FIELDS=') !== false) {
                             $fields = "&searchfields=" . trim(substr($data1, 7));
                         }
                     }
                     if (!empty($words)) {
                         if (empty($fields)) {
                             $fields = '&searchfields=4';
                         }
                     }
                     $sql = "UPDATE " . prefix('albums') . "SET `search_params`=\"{$words}.{$fields}\", `thumb`=\"{$thumb}\", `mtime`=\"{$mtime}\" WHERE `id`=\"" . $album['id'] . "\"";
                     query($sql);
                 }
             }
             /* Delete all image entries that don't belong to an album at all. */
             $albumids = query_full_array("SELECT `id` FROM " . prefix('albums'));
             /* all the album IDs */
             $idsofalbums = array();
             foreach ($albumids as $row) {
                 $idsofalbums[] = $row['id'];
             }
             $imageAlbums = query_full_array("SELECT DISTINCT `albumid` FROM " . prefix('images'));
             /* albumids of all the images */
             $albumidsofimages = array();
             foreach ($imageAlbums as $row) {
                 $albumidsofimages[] = $row['albumid'];
             }
             $orphans = array_diff($albumidsofimages, $idsofalbums);
             /* albumids of images with no album */
             if (count($orphans) > 0) {
                 /* delete dead images from the DB */
                 $firstrow = array_pop($orphans);
                 $sql = "DELETE FROM " . prefix('images') . " WHERE `albumid`='" . $firstrow . "'";
                 foreach ($orphans as $id) {
                     $sql .= " OR `albumid`='" . $id . "'";
                 }
                 query($sql);
                 // Then go into existing albums recursively to clean them... very invasive.
                 foreach ($this->getAlbums(0) as $folder) {
                     $album = new Album($this, $folder);
                     if (!$album->isDynamic()) {
                         if (is_null($album->getDateTime())) {
                             // see if we can get one from an image
                             $image = $album->getImage(0);
                             if (is_object($image)) {
                                 $album->setDateTime($image->getDateTime());
                             }
                         }
                         $album->garbageCollect(true);
                         $album->preLoad();
                     }
                 }
             }
         }
         /* Look for image records where the file no longer exists. While at it, check for images with IPTC data to update the DB */
         $start = array_sum(explode(" ", microtime()));
         // protect against too much processing.
         if (!empty($restart)) {
             $restartwhere = ' WHERE `id`>' . $restart;
         } else {
             $restartwhere = '';
         }
         $sql = 'SELECT `id`, `albumid`, `filename`, `desc`, `title`, `date`, `mtime` FROM ' . prefix('images') . $restartwhere . ' ORDER BY `id`';
         $images = query_full_array($sql);
         foreach ($images as $image) {
             $sql = 'SELECT `folder` FROM ' . prefix('albums') . ' WHERE `id`="' . $image['albumid'] . '";';
             $row = query_single_row($sql);
             $imageName = UTF8ToFilesystem(getAlbumFolder() . $row['folder'] . '/' . $image['filename']);
             if (file_exists($imageName)) {
                 if ($image['mtime'] != filemtime($imageName)) {
                     // file has changed since we last saw it
                     /* check metadata */
                     $metadata = getImageMetadata($imageName);
                     $set = '';
                     /* title */
                     $defaultTitle = substr($image['filename'], 0, strrpos($image['filename'], '.'));
                     if (empty($defaultTitle)) {
                         $defaultTitle = $image['filename'];
                     }
                     if ($defaultTitle == $image['title']) {
                         /* default title */
                         if (isset($metadata['title'])) {
                             $set = ',`title`="' . mysql_real_escape_string($metadata['title']) . '"';
                         }
                     }
                     /* description */
                     if (!isset($row['desc'])) {
                         if (isset($metadata['desc'])) {
                             $set .= ', `desc`="' . mysql_real_escape_string($metadata['desc']) . '"';
                         }
                     }
                     /* tags */
                     if (isset($metadata['tags'])) {
                         $tags = $metadata['tags'];
                         storeTags($tags, $image['id'], 'images');
                     }
                     /* location, city, state, and country */
                     if (isset($metadata['location'])) {
                         $set .= ', `location`="' . mysql_real_escape_string($metadata['location']) . '"';
                     }
                     if (isset($metadata['city'])) {
                         $set .= ', `city`="' . mysql_real_escape_string($metadata['city']) . '"';
                     }
                     if (isset($metadata['state'])) {
                         $set .= ', `state`="' . mysql_real_escape_string($metadata['state']) . '"';
                     }
                     if (isset($metadata['country'])) {
                         $set .= ', `country`="' . mysql_real_escape_string($metadata['country']) . '"';
                     }
                     /* credit & copyright */
                     if (isset($metadata['credit'])) {
                         $set .= ', `credit`="' . escape($metadata['credit']) . '"';
                     }
                     if (isset($metadata['copyright'])) {
                         $set .= ', `copyright`="' . escape($metadata['copyright']) . '"';
                     }
                     /* date (for sorting) */
                     $newDate = strftime('%Y-%m-%d %T', filemtime($imageName));
                     if (isset($metadata['date'])) {
                         $dt = dateTimeConvert($metadata['date']);
                         if ($dt !== false) {
                             // flaw in exif/iptc data?
                             $newDate = $dt;
                         }
                     }
                     $set .= ', `date`="' . $newDate . '"';
                     /* update DB is necessary */
                     $sql = "UPDATE " . prefix('images') . " SET `EXIFValid`=0,`mtime`=" . filemtime($imageName) . $set . " WHERE `id`='" . $image['id'] . "'";
                     query($sql);
                 }
             } else {
                 $sql = 'DELETE FROM ' . prefix('images') . ' WHERE `id`="' . $image['id'] . '";';
                 $result = query($sql);
                 $sql = 'DELETE FROM ' . prefix('comments') . ' WHERE `type` IN (' . zp_image_types('"') . ') AND `ownerid` ="' . $image['id'] . '";';
                 $result = query($sql);
             }
             if (array_sum(explode(" ", microtime())) - $start >= 10) {
                 return $image['id'];
                 // avoide excessive processing
             }
         }
         /* clean the comments table */
         /* do the images */
         $imageids = query_full_array('SELECT `id` FROM ' . prefix('images'));
         /* all the image IDs */
         $idsofimages = array();
         foreach ($imageids as $row) {
             $idsofimages[] = $row['id'];
         }
         $commentImages = query_full_array("SELECT DISTINCT `ownerid` FROM " . prefix('comments') . 'WHERE `type` IN (' . zp_image_types('"') . ')');
         /* imageids of all the comments */
         $imageidsofcomments = array();
         foreach ($commentImages as $row) {
             $imageidsofcomments[] = $row['ownerid'];
         }
         $orphans = array_diff($imageidsofcomments, $idsofimages);
         /* image ids of comments with no image */
         if (count($orphans) > 0) {
             /* delete dead comments from the DB */
             $firstrow = array_pop($orphans);
             $sql = "DELETE FROM " . prefix('comments') . " WHERE `type` IN (" . zp_image_types("'") . ") AND `ownerid`='" . $firstrow . "'";
             foreach ($orphans as $id) {
                 $sql .= " OR `ownerid`='" . $id . "'";
             }
             query($sql);
         }
         /* do the same for album comments */
         $albumids = query_full_array('SELECT `id` FROM ' . prefix('albums'));
         /* all the album IDs */
         $idsofalbums = array();
         foreach ($albumids as $row) {
             $idsofalbums[] = $row['id'];
         }
         $commentAlbums = query_full_array("SELECT DISTINCT `ownerid` FROM " . prefix('comments') . 'WHERE `type`="albums"');
         /* album ids of all the comments */
         $albumidsofcomments = array();
         foreach ($commentAlbums as $row) {
             $albumidsofcomments[] = $row['ownerid'];
         }
         $orphans = array_diff($albumidsofcomments, $idsofalbums);
         /* album ids of comments with no album */
         if (count($orphans) > 0) {
             /* delete dead comments from the DB */
             $firstrow = array_pop($orphans);
             $sql = "DELETE FROM " . prefix('comments') . "WHERE `type`='albums' AND `ownerid`='" . $firstrow . "'";
             foreach ($orphans as $id) {
                 $sql .= " OR `ownerid`='" . $id . "'";
             }
             query($sql);
         }
         /* clean the tags table */
         /* do the images */
         $tagImages = query_full_array("SELECT DISTINCT `objectid` FROM " . prefix('obj_to_tag') . 'WHERE `type` IN (' . zp_image_types('"') . ')');
         /* imageids of all the comments */
         $imageidsoftags = array();
         foreach ($tagImages as $row) {
             $imageidsoftags[] = $row['objectid'];
         }
         $orphans = array_diff($imageidsoftags, $idsofimages);
         /* image ids of comments with no image */
         if (count($orphans) > 0) {
             /* delete dead tags from the DB */
             $firstrow = array_pop($orphans);
             $sql = "DELETE FROM " . prefix('obj_to_tag') . " WHERE `type` IN (" . zp_image_types('"') . ") AND (`objectid`='" . $firstrow . "'";
             foreach ($orphans as $id) {
                 $sql .= " OR `objectid`='" . $id . "'";
             }
             $sql .= ')';
             query($sql);
         }
         /* do the same for album tags */
         $tagAlbums = query_full_array("SELECT DISTINCT `objectid` FROM " . prefix('obj_to_tag') . 'WHERE `type`="albums"');
         /* album ids of all the comments */
         $albumidsoftags = array();
         foreach ($tagAlbums as $row) {
             $albumidsoftags[] = $row['objectid'];
         }
         $orphans = array_diff($albumidsoftags, $idsofalbums);
         /* album ids of comments with no album */
         if (count($orphans) > 0) {
             /* delete dead tags from the DB */
             $firstrow = array_pop($orphans);
             $sql = "DELETE FROM " . prefix('obj_to_tag') . "WHERE `type`='albums' AND `objectid`='" . $firstrow . "'";
             foreach ($orphans as $id) {
                 $sql .= " OR `objectid`='" . $id . "'";
             }
             query($sql);
         }
     }
     return false;
 }
/**
 * Gets news articles and images of a gallery to show them together on the news section
 *
 * NOTE: This function does not exclude articles that are password protected via a category
 *
 * @param int $articles_per_page The number of articles to get
 * @param string $mode 	"latestimages-thumbnail"
 *											"latestimages-thumbnail-customcrop"
 *											"latestimages-sizedimage"
 *											"latestalbums-thumbnail"
 *		 									"latestalbums-thumbnail-customcrop"
 *		 									"latestalbums-sizedimage"
 *		 									"latestimagesbyalbum-thumbnail"
 *		 									"latestimagesbyalbum-thumbnail-customcrop"
 *		 									"latestimagesbyalbum-sizedimage"
 *		 									"latestupdatedalbums-thumbnail" (for RSS and getLatestNews() used only)
 *		 									"latestupdatedalbums-thumbnail-customcrop" (for RSS and getLatestNews() used only)
 *		 									"latestupdatedalbums-sizedimage" (for RSS and getLatestNews() used only)
 *	NOTE: The "latestupdatedalbums" variants do NOT support pagination as required on the news loop!
 *
 * @param string $published "published" for published articles,
 * 													"unpublished" for un-published articles,
 * 													"all" for all articles
 * @param string $sortorder 	id, date or mtime, only for latestimages-... modes
 * @param bool $sticky set to true to place "sticky" articles at the front of the list.
 * @return array
 */
function getCombiNews($articles_per_page = '', $mode = '', $published = NULL, $sortorder = '', $sticky = true)
{
    deprecated_function_notify(gettext('Use the Zenpage class method instead.'));
    global $_zp_gallery, $_zp_flash_player;
    processExpired('news');
    if (is_null($published)) {
        if (zp_loggedin(ZENPAGE_NEWS_RIGHTS)) {
            $published = "all";
        } else {
            $published = "published";
        }
    }
    if (empty($mode)) {
        $mode = getOption("zenpage_combinews_mode");
    }
    if ($published == "published") {
        $show = " WHERE `show` = 1 AND date <= '" . date('Y-m-d H:i:s') . "'";
        $imagesshow = " AND images.show = 1 ";
    } else {
        $show = "";
        $imagesshow = "";
    }
    $passwordcheck = "";
    if (zp_loggedin(ZENPAGE_NEWS_RIGHTS)) {
        $albumWhere = "";
        $passwordcheck = "";
    } else {
        $albumscheck = query_full_array("SELECT * FROM " . prefix('albums') . " ORDER BY title");
        foreach ($albumscheck as $albumcheck) {
            if (!checkAlbumPassword($albumcheck['folder'])) {
                $albumpasswordcheck = " AND albums.id != " . $albumcheck['id'];
                $passwordcheck = $passwordcheck . $albumpasswordcheck;
            }
        }
        $albumWhere = "AND albums.show=1" . $passwordcheck;
    }
    $limit = getLimitAndOffset($articles_per_page);
    if (empty($sortorder)) {
        $combinews_sortorder = getOption("zenpage_combinews_sortorder");
    } else {
        $combinews_sortorder = $sortorder;
    }
    $stickyorder = '';
    if ($sticky) {
        $stickyorder = 'sticky DESC,';
    }
    $type3 = query("SET @type3:='0'");
    switch ($mode) {
        case "latestimages-thumbnail":
        case "latestimages-thumbnail-customcrop":
        case "latestimages-sizedimage":
            $sortorder = "images." . $combinews_sortorder;
            $type1 = query("SET @type1:='news'");
            $type2 = query("SET @type2:='images'");
            switch ($combinews_sortorder) {
                case 'id':
                case 'date':
                    $imagequery = "(SELECT albums.folder, images.filename, images.date, @type2, @type3 as sticky FROM " . prefix('images') . " AS images, " . prefix('albums') . " AS albums\n\t\t\t\t\t\t\tWHERE albums.id = images.albumid " . $imagesshow . $albumWhere . ")";
                    break;
                case 'mtime':
                    $imagequery = "(SELECT albums.folder, images.filename, FROM_UNIXTIME(images.mtime), @type2, @type3 as sticky FROM " . prefix('images') . " AS images, " . prefix('albums') . " AS albums\n\t\t\t\t\t\t\tWHERE albums.id = images.albumid " . $imagesshow . $albumWhere . ")";
                    break;
            }
            $result = query_full_array("(SELECT title as albumname, titlelink, date, @type1 as type, sticky FROM " . prefix('news') . " " . $show . ")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tUNION\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" . $imagequery . "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tORDER BY {$stickyorder} date DESC {$limit}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
            break;
        case "latestalbums-thumbnail":
        case "latestalbums-thumbnail-customcrop":
        case "latestalbums-sizedimage":
            $sortorder = $combinews_sortorder;
            $type1 = query("SET @type1:='news'");
            $type2 = query("SET @type2:='albums'");
            switch ($combinews_sortorder) {
                case 'id':
                case 'date':
                    $albumquery = "(SELECT albums.folder, albums.title, albums.date, @type2, @type3 as sticky FROM " . prefix('albums') . " AS albums\n\t\t\t\t\t\t\t" . $show . $albumWhere . ")";
                    break;
                case 'mtime':
                    $albumquery = "(SELECT albums.folder, albums.title, FROM_UNIXTIME(albums.mtime), @type2, @type3 as sticky FROM " . prefix('albums') . " AS albums\n\t\t\t\t\t\t\t" . $show . $albumWhere . ")";
                    break;
            }
            $result = query_full_array("(SELECT title as albumname, titlelink, date, @type1 as type, sticky FROM " . prefix('news') . " " . $show . ")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tUNION\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" . $albumquery . "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tORDER BY {$stickyorder} date DESC {$limit}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
            break;
        case "latestimagesbyalbum-thumbnail":
        case "latestimagesbyalbum-thumbnail-customcrop":
        case "latestimagesbyalbum-sizedimage":
            $type1 = query("SET @type1:='news'");
            $type2 = query("SET @type2:='albums'");
            if (empty($combinews_sortorder) || $combinews_sortorder != "date" || $combinews_sortorder != "mtime") {
                $combinews_sortorder = "date";
            }
            $combinews_sortorder = "date";
            $sortorder = "images." . $combinews_sortorder;
            switch ($combinews_sortorder) {
                case "date":
                    $imagequery = "(SELECT DISTINCT DATE_FORMAT(" . $sortorder . ",'%Y-%m-%d'), albums.folder, DATE_FORMAT(images.`date`,'%Y-%m-%d'), @type2 FROM " . prefix('images') . " AS images, " . prefix('albums') . " AS albums\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE albums.id = images.albumid " . $imagesshow . $albumWhere . ")";
                    break;
                case "mtime":
                    $imagequery = "(SELECT DISTINCT FROM_UNIXTIME(" . $sortorder . ",'%Y-%m-%d'), albums.folder, DATE_FORMAT(images.`mtime`,'%Y-%m-%d'), @type2 FROM " . prefix('images') . " AS images, " . prefix('albums') . " AS albums\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE albums.id = images.albumid " . $imagesshow . $albumWhere . ")";
                    break;
            }
            $result = query_full_array("(SELECT title as albumname, titlelink, date, @type1 as type FROM " . prefix('news') . " " . $show . ")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tUNION\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" . $imagequery . "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tORDER By date DESC {$limit}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
            //echo "<pre>"; print_r($result); echo "</pre>";
            //$result = "";
            break;
        case "latestupdatedalbums-thumbnail":
        case "latestupdatedalbums-thumbnail-customcrop":
        case "latestupdatedalbums-sizedimage":
            $latest = getNewsArticles($articles_per_page, '', NULL, true);
            $counter = '';
            foreach ($latest as $news) {
                $article = new ZenpageNews($news['titlelink']);
                if ($article->checkAccess($hint, $show)) {
                    $counter++;
                    $latestnews[$counter] = array("albumname" => $article->getTitle(), "titlelink" => $article->getTitlelink(), "date" => $article->getDateTime(), "type" => "news");
                }
            }
            $albums = getAlbumStatistic($articles_per_page, "latestupdated");
            $latestalbums = array();
            $counter = "";
            foreach ($albums as $album) {
                $counter++;
                $tempalbum = new Album($_zp_gallery, $album['folder']);
                $tempalbumthumb = $tempalbum->getAlbumThumbImage();
                $timestamp = $tempalbum->get('mtime');
                if ($timestamp == 0) {
                    $albumdate = $tempalbum->getDateTime();
                } else {
                    $albumdate = strftime('%Y-%m-%d %H:%M:%S', $timestamp);
                }
                $latestalbums[$counter] = array("albumname" => $tempalbum->getFolder(), "titlelink" => $tempalbum->getTitle(), "date" => $albumdate, "type" => 'albums');
            }
            //$latestalbums = array_merge($latestalbums, $item);
            $latest = array_merge($latestnews, $latestalbums);
            $result = sortMultiArray($latest, "date", true);
            if (count($result) > $articles_per_page) {
                $result = array_slice($result, 0, 10);
            }
            break;
    }
    //$result = "";
    return $result;
}
 /** For every album in the gallery, look for its file. Delete from the database
  * if the file does not exist. Do the same for images. Clean up comments that have
  * been left orphaned.
  *
  * Returns true if the operation was interrupted because it was taking too long
  *
  * @param bool $cascade garbage collect every image and album in the gallery.
  * @param bool $complete garbage collect every image and album in the *database* - completely cleans the database.
  * @param  int $restart Image ID to restart scan from
  * @return bool
  */
 function garbageCollect($cascade = true, $complete = false, $restart = '')
 {
     if (empty($restart)) {
         setOption('last_garbage_collect', time());
         /* clean the comments table */
         $this->commentClean('images');
         $this->commentClean('albums');
         $this->commentClean('news');
         $this->commentClean('pages');
         // clean up obj_to_tag
         $dead = array();
         $result = query_full_array("SELECT * FROM " . prefix('obj_to_tag'));
         if (is_array($result)) {
             foreach ($result as $row) {
                 $dbtag = query_single_row("SELECT * FROM " . prefix('tags') . " WHERE `id`='" . $row['tagid'] . "'");
                 if (!$dbtag) {
                     $dead['id'] = $row['id'];
                 }
                 switch ($row['type']) {
                     case 'album':
                         $tbl = 'albums';
                         break;
                     default:
                         $tbl = $row['type'];
                         break;
                 }
                 $dbtag = query_single_row("SELECT * FROM " . prefix($tbl) . " WHERE `id`='" . $row['objectid'] . "'");
                 if (!$dbtag) {
                     $dead['id'] = $row['id'];
                 }
             }
         }
         if (!empty($dead)) {
             query('DELETE FROM ' . prefix('obj_to_tag') . ' WHERE `id`=' . implode(' OR `id`=', $dead));
         }
         // clean up admin_to_object
         $dead = array();
         $result = query_full_array("SELECT * FROM " . prefix('admin_to_object'));
         if (is_array($result)) {
             foreach ($result as $row) {
                 $dbtag = query_single_row("SELECT * FROM " . prefix('administrators') . " WHERE `id`='" . $row['adminid'] . "'");
                 if (!$dbtag) {
                     $dead['id'] = $row['id'];
                 }
                 switch ($row['type']) {
                     case 'album':
                         $tbl = 'albums';
                         break;
                     default:
                         $tbl = $row['type'];
                         break;
                 }
                 $dbtag = query_single_row("SELECT * FROM " . prefix($tbl) . " WHERE `id`='" . $row['objectid'] . "'");
                 if (!$dbtag) {
                     $dead['id'] = $row['id'];
                 }
             }
         }
         if (!empty($dead)) {
             query('DELETE FROM ' . prefix('admin_to_object') . ' WHERE `id`=' . implode(' OR `id`=', $dead));
         }
         // clean up news2cat
         $dead = array();
         $result = query_full_array("SELECT * FROM " . prefix('news2cat'));
         if (is_array($result)) {
             foreach ($result as $row) {
                 $dbtag = query_single_row("SELECT * FROM " . prefix('news') . " WHERE `id`='" . $row['news_id'] . "'");
                 if (!$dbtag) {
                     $dead['id'] = $row['id'];
                 }
                 $dbtag = query_single_row("SELECT * FROM " . prefix('news_categories') . " WHERE `id`='" . $row['cat_id'] . "'");
                 if (!$dbtag) {
                     $dead['id'] = $row['id'];
                 }
             }
         }
         if (!empty($dead)) {
             query('DELETE FROM ' . prefix('news2cat') . ' WHERE `id`=' . implode(' OR `id`=', $dead));
         }
         // Check for the existence of top-level albums (subalbums handled recursively).
         $sql = "SELECT * FROM " . prefix('albums');
         $result = query($sql);
         $dead = array();
         $live = array('');
         // purge the root album if it exists
         $deadalbumthemes = array();
         // Load the albums from disk
         while ($row = db_fetch_assoc($result)) {
             $valid = file_exists($albumpath = ALBUM_FOLDER_SERVERPATH . internalToFilesystem($row['folder'])) && (hasDynamicAlbumSuffix($albumpath) || is_dir($albumpath) && strpos($albumpath, '/./') === false && strpos($albumpath, '/../') === false);
             if (!$valid || in_array($row['folder'], $live)) {
                 $dead[] = $row['id'];
                 if ($row['album_theme'] !== '') {
                     // orphaned album theme options table
                     $deadalbumthemes[$row['id']] = $row['folder'];
                 }
             } else {
                 $live[] = $row['folder'];
             }
         }
         if (count($dead) > 0) {
             /* delete the dead albums from the DB */
             $first = array_pop($dead);
             $sql1 = "DELETE FROM " . prefix('albums') . " WHERE `id`='{$first}'";
             $sql2 = "DELETE FROM " . prefix('images') . " WHERE `albumid`='{$first}'";
             $sql3 = "DELETE FROM " . prefix('comments') . " WHERE `type`='albums' AND `ownerid`='{$first}'";
             $sql4 = "DELETE FROM " . prefix('obj_to_tag') . " WHERE `type`='albums' AND `objectid`='{$first}'";
             foreach ($dead as $albumid) {
                 $sql1 .= " OR `id` = '{$albumid}'";
                 $sql2 .= " OR `albumid` = '{$albumid}'";
                 $sql3 .= " OR `ownerid` = '{$albumid}'";
                 $sql4 .= " OR `objectid` = '{$albumid}'";
             }
             $n = query($sql1);
             if (!$complete && $n && $cascade) {
                 query($sql2);
                 query($sql3);
                 query($sql4);
             }
         }
         if (count($deadalbumthemes) > 0) {
             // delete the album theme options tables for dead albums
             foreach ($deadalbumthemes as $id => $deadtable) {
                 $sql = 'DELETE FROM ' . prefix('options') . ' WHERE `ownerid`=' . $id;
                 query($sql, false);
             }
         }
     }
     if ($complete) {
         if (empty($restart)) {
             /* refresh 'metadata' albums */
             $albumids = query_full_array("SELECT `id`, `mtime`, `folder`, `dynamic` FROM " . prefix('albums'));
             foreach ($albumids as $analbum) {
                 if (($mtime = filemtime(ALBUM_FOLDER_SERVERPATH . internalToFilesystem($analbum['folder']))) > $analbum['mtime']) {
                     // refresh
                     $album = new Album($this, $analbum['folder']);
                     $album->set('mtime', $mtime);
                     if ($album->isDynamic()) {
                         $data = file_get_contents($album->localpath);
                         while (!empty($data)) {
                             $data1 = trim(substr($data, 0, $i = strpos($data, "\n")));
                             if ($i === false) {
                                 $data1 = $data;
                                 $data = '';
                             } else {
                                 $data = substr($data, $i + 1);
                             }
                             if (strpos($data1, 'WORDS=') !== false) {
                                 $words = "words=" . urlencode(substr($data1, 6));
                             }
                             if (strpos($data1, 'THUMB=') !== false) {
                                 $thumb = trim(substr($data1, 6));
                             }
                             if (strpos($data1, 'FIELDS=') !== false) {
                                 $fields = "&searchfields=" . trim(substr($data1, 7));
                             }
                         }
                         if (!empty($words)) {
                             if (empty($fields)) {
                                 $fields = '&searchfields=tags';
                             }
                         }
                         $album->set('search_params', $words . $fields);
                         $album->set('thumb', $thumb);
                     }
                     $album->save();
                     zp_apply_filter('album_refresh', $album);
                 }
             }
             /* Delete all image entries that don't belong to an album at all. */
             $albumids = query_full_array("SELECT `id` FROM " . prefix('albums'));
             /* all the album IDs */
             $idsofalbums = array();
             foreach ($albumids as $row) {
                 $idsofalbums[] = $row['id'];
             }
             $imageAlbums = query_full_array("SELECT DISTINCT `albumid` FROM " . prefix('images'));
             /* albumids of all the images */
             $albumidsofimages = array();
             foreach ($imageAlbums as $row) {
                 $albumidsofimages[] = $row['albumid'];
             }
             $orphans = array_diff($albumidsofimages, $idsofalbums);
             /* albumids of images with no album */
             if (count($orphans) > 0) {
                 /* delete dead images from the DB */
                 $firstrow = array_pop($orphans);
                 $sql = "DELETE FROM " . prefix('images') . " WHERE `albumid`='" . $firstrow . "'";
                 foreach ($orphans as $id) {
                     $sql .= " OR `albumid`='" . $id . "'";
                 }
                 query($sql);
                 // Then go into existing albums recursively to clean them... very invasive.
                 foreach ($this->getAlbums(0) as $folder) {
                     $album = new Album($this, $folder);
                     if (!$album->isDynamic()) {
                         if (is_null($album->getDateTime())) {
                             // see if we can get one from an image
                             $images = $album->getImages(0, 0, 'date', 'DESC');
                             if (count($images) > 0) {
                                 $image = newImage($album, array_shift($images));
                                 $album->setDateTime($image->getDateTime());
                             }
                         }
                         $album->garbageCollect(true);
                         $album->preLoad();
                     }
                     $album->save();
                     zp_apply_filter('album_refresh', $album);
                 }
             }
         }
         /* Look for image records where the file no longer exists. While at it, check for images with IPTC data to update the DB */
         $start = array_sum(explode(" ", microtime()));
         // protect against too much processing.
         if (!empty($restart)) {
             $restartwhere = ' WHERE `id`>' . $restart . ' AND `mtime`=0';
         } else {
             $restartwhere = ' WHERE `mtime`=0';
         }
         define('RECORD_LIMIT', 5);
         $sql = 'SELECT * FROM ' . prefix('images') . $restartwhere . ' ORDER BY `id` LIMIT ' . (RECORD_LIMIT + 2);
         $images = query_full_array($sql);
         if (count($images) > 0) {
             $c = 0;
             foreach ($images as $image) {
                 $sql = 'SELECT `folder` FROM ' . prefix('albums') . ' WHERE `id`="' . $image['albumid'] . '";';
                 $row = query_single_row($sql);
                 $imageName = internalToFilesystem(ALBUM_FOLDER_SERVERPATH . $row['folder'] . '/' . $image['filename']);
                 if (file_exists($imageName)) {
                     $mtime = filemtime($imageName);
                     if ($image['mtime'] != $mtime) {
                         // file has changed since we last saw it
                         $imageobj = newImage(new Album($this, $row['folder']), $image['filename']);
                         $imageobj->set('mtime', $mtime);
                         $imageobj->updateMetaData();
                         // prime the EXIF/IPTC fields
                         $imageobj->updateDimensions();
                         // update the width/height & account for rotation
                         $imageobj->save();
                         zp_apply_filter('image_refresh', $imageobj);
                     }
                 } else {
                     $sql = 'DELETE FROM ' . prefix('images') . ' WHERE `id`="' . $image['id'] . '";';
                     $result = query($sql);
                     $sql = 'DELETE FROM ' . prefix('comments') . ' WHERE `type` IN (' . zp_image_types('"') . ') AND `ownerid` ="' . $image['id'] . '";';
                     $result = query($sql);
                 }
                 if (++$c >= RECORD_LIMIT) {
                     return $image['id'];
                     // avoide excessive processing
                 }
             }
         }
     }
     return false;
 }