* @version $Revision: 16630 $
* @static
*/
class CoreModuleExtras {
/**
* @see GalleryModule::upgrade
* @param object GalleryModule $module the core module
* @param string $currentVersion the current installed version
*/
function upgrade($module, $currentVersion, $statusMonitor) {
global $gallery;
$storage =& $gallery->getStorage();
$platform =& $gallery->getPlatform();
$gallery->debug('Entering CoreModuleExtras::upgrade');
/*
* We store our version outside of the database so that we can upgrade even if the database
* is in an undependable state
*/
$versions = $module->getInstalledVersions();
$currentVersion = $versions['core'];
if (!isset($currentVersion)) {
$gallery->debug('Current version not set');
/*
* This is either an initial install or an upgrade from version 0.8 (which didn't have
* the core versions.dat file). Use a module parameter as our acid test.
*
* @todo Get rid of this when we stop supporting upgrades from alphas
*/
list ($ret, $paramValue) = $module->getParameter('permissions.directory');
if (isset($paramValue)) {
$currentVersion = '0.8';
} else {
$currentVersion = '0';
}
}
$gallery->debug('Old version: ' . $currentVersion
. ' New version: ' . $module->getVersion());
/* Enable upgrade from any patch release version */
$currentVersion = preg_replace('/^(1\.[01]\.0)\.\d+$/', '$1.x', $currentVersion);
/*
* We converted the character set for MySQL to UTF8 in version 1.0.27, but this only
* applies if you are running MySQL 4. If you install MySQL 4 after upgrading past 1.0.27
* then you'd get stuck with the non-UTF8 character set and you'd get scrambled output.
* To remedy this, we check here to see if you're using a version more recent than 1.0.26
* and if so, we perform the conversion now. Otherwise, we perform the conversion in-line
* in the 1.0.26 upgrade block below.
*/
if (version_compare($currentVersion, '1.0.26', '>')) {
list ($ret, $converted) =
CoreModuleExtras::convertCharacterSetToUtf8($module, $statusMonitor);
if ($ret) {
return $ret;
}
}
/**
* README: How to update the block below
*
* If you add a new feature to the core module and revise the version, you should do the
* following. Supposing the current version is 1.0.1 and you're adding 1.0.2. Go to the
* end of the switch and find the 'end of upgrade path' case. Create a new case *above*
* that one with the old version number. For our example you'd add: "case '1.0.1':" and
* then your code. Do *not* put in a break statement. (Update _prepareConfigUpgrade too).
*/
$gallery->debug(sprintf('The current version is %s', $currentVersion));
switch ($currentVersion) {
case '0':
$gallery->debug('Install core module');
/*
* Checkpoint (commit configureStore transaction)
* Later in the installation code, we create the root album and therefore need locking.
* Locks are acquired with a non-transactional db connection. So before we can query
* the db with a second connection, the INSERT id into SequenceLock needs to be
* committed. Related bug 1235284.
*/
$ret = $storage->checkPoint();
if ($ret) {
return $ret;
}
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Installing the core module'), '', 0.15);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(180);
if (GalleryUtilities::isA($platform, 'WinNtPlatform')) {
$flockType = 'database';
} else {
$fileToLock = $platform->fopen(__FILE__, 'r');
$wouldBlock = false;
if ($platform->flock($fileToLock, LOCK_SH, $wouldBlock) || $wouldBlock) {
$flockType = 'flock';
} else {
$flockType = 'database';
}
$platform->fclose($fileToLock);
}
$gallery->debug(sprintf('Locktype %s selected', $flockType));
/* Initial install. Make sure all our module parameters are set. */
$gallery->debug('Set core module parameters');
GalleryCoreApi::requireOnce('modules/core/classes/GalleryTranslator.class');
foreach (array('permissions.directory' => '0755',
'permissions.file' => '0644',
'exec.expectedStatus' => '0',
'exec.beNice' => '0',
'default.orderBy' => 'orderWeight',
'default.orderDirection' => '1',
'default.theme' => 'matrix',
'default.language' => GalleryTranslator::getLanguageCodeFromRequest(),
'language.useBrowserPref' => '0',
'default.newAlbumsUseDefaults' => 'false',
'session.lifetime' => 21 * 86400, /* Three weeks */
'session.inactivityTimeout' => 7 * 86400, /* One week */
'misc.markup' => 'bbcode',
'lock.system' => $flockType,
'format.date' => '%x',
'format.time' => '%X',
'format.datetime' => '%c',
'repository.updateTime' => '0',
'acceleration' => serialize(array('guest' => array('type' => 'none'),
'user' => array('type' => 'none'))),
'validation.level' => 'MEDIUM',
'core.repositories' => serialize(array('released' => 1)),
) as $key => $value) {
if (!isset($param[$key])) {
$ret = $module->setParameter($key, (string)$value);
if ($ret) {
$gallery->debug(sprintf('Error: Failed to set core module parameter %s, ' .
'this is the error stack trace: %s', $key,
$ret->getAsText()));
return $ret;
}
}
}
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Installing the core module'), '', 0.2);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(180);
/* Activate the default theme */
$gallery->debug('Load default theme');
list ($ret, $themeList) = GalleryCoreApi::fetchPluginStatus('theme');
if ($ret) {
return $ret;
}
$defaultThemeId = 'matrix';
if (empty($themeList[$defaultThemeId]['available'])) {
$gallery->debug(sprintf('Warning: %s theme is not available. Trying to fall ' .
'back to another theme.', $defaultThemeId));
$defaultThemeId = null;
foreach ($themeList as $themeId => $themeInfo) {
if (!empty($themeInfo['available'])) {
$defaultThemeId = $themeId;
break;
}
}
if (empty($defaultThemeId)) {
return GalleryCoreApi::error(ERROR_UNKNOWN, __FILE__, __LINE__,
'There is no theme available!');
}
$ret = $module->setParameter('default.theme', $defaultThemeId);
if ($ret) {
return $ret;
}
}
$gallery->debug(sprintf('Using %s as default theme', $defaultThemeId));
list ($ret, $theme) = GalleryCoreApi::loadPlugin('theme', $defaultThemeId);
if ($ret) {
$gallery->debug(sprintf('Error: Failed to load %s theme, this is the error ' .
'stack trace; %s', $defaultThemeId, $ret->getAsText()));
return $ret;
}
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Installing the core module'), '', 0.25);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(180);
$gallery->debug('InstallOrUpgrade default theme');
$ret = $theme->installOrUpgrade();
if ($ret) {
$gallery->debug(sprintf('Error: Failed to installOrUpgrade %s theme, this is ' .
'the error stack trace; %s', $defaultThemeId, $ret->getAsText()));
return $ret;
}
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Installing the core module'), '', 0.3);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(180);
$gallery->debug('Activate default theme');
list ($ret, $ignored) = $theme->activate(false);
if ($ret) {
$gallery->debug(sprintf('Error: Failed to activate %s theme, this is ' .
'the error stack trace; %s', $defaultThemeId, $ret->getAsText()));
return $ret;
}
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Installing the core module'), '', 0.4);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(180);
/*
* Register our permissions. Since we're storing internationalized strings in the
* database, we have to give our internationalized string extractor a clue that these
* strings get translated. So put a line like this translate('key') in for each
* description so that our extractor can find it.
*/
$gallery->debug('Register core module permissions');
$permissions[] = array('all', $gallery->i18n('All access'),
GALLERY_PERMISSION_ALL_ACCESS, array());
$permissions[] = array('view', $gallery->i18n('[core] View item'), 0, array());
$permissions[] = array('viewResizes', $gallery->i18n('[core] View resized version(s)'),
0, array());
$permissions[] = array('viewSource', $gallery->i18n('[core] View original version'),
0, array());
$permissions[] = array('viewAll', $gallery->i18n('[core] View all versions'),
GALLERY_PERMISSION_COMPOSITE,
array('core.view', 'core.viewResizes', 'core.viewSource'));
$permissions[] = array('addAlbumItem', $gallery->i18n('[core] Add sub-album'),
0, array());
$permissions[] = array('addDataItem', $gallery->i18n('[core] Add sub-item'),
0, array());
$permissions[] = array('edit', $gallery->i18n('[core] Edit item'), 0, array());
$permissions[] = array('changePermissions',
$gallery->i18n('[core] Change item permissions'), 0, array());
$permissions[] = array('delete', $gallery->i18n('[core] Delete item'), 0, array());
foreach ($permissions as $p) {
$ret = GalleryCoreApi::registerPermission(
$module->getId(), 'core.' . $p[0], $p[1], $p[2], $p[3]);
if ($ret) {
$gallery->debug(sprintf('Error: Failed to register a permission, ' .
'this is the error stack trace: %s',
$ret->getAsText()));
return $ret;
}
}
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Installing the core module'), '', 0.5);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(180);
foreach (array('_createAccessListCompacterLock',
'_createAllUsersGroup',
'_createSiteAdminsGroup',
'_createEverybodyGroup',
'_createAnonymousUser',
'_createAdminUser',
'_createRootAlbumItem') as $func) {
$gallery->debug(sprintf('Call user func %s', $func));
$ret = call_user_func(array('CoreModuleExtras', $func), $module);
if ($ret) {
$gallery->debug(sprintf('Error: %s returned an error, ' .
'this is the error stack trace: %s', $func,
$ret->getAsText()));
return $ret;
}
}
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Installing the core module'), '', 0.6);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(180);
$gallery->debug('Initialize MIME types');
GalleryCoreApi::requireOnce(
'modules/core/classes/helpers/GalleryMimeTypeHelper_advanced.class');
$ret = GalleryMimeTypeHelper_advanced::initializeMimeTypes();
if ($ret) {
$gallery->debug(sprintf('Error: Failed to initialize MIME types, this is ' .
'the error stack trace: %s', $ret->getAsText()));
return $ret;
}
$gallery->debug('CoreModulesExtra::upgrade: successfully installed core');
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Installing the core module'), '', 0.7);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(180);
break;
case '0.8':
$gallery->debug('Warning: Upgrading from version 0.8 (not supported)');
case '0.8.1':
case '0.8.2':
/*
* Update our framework module parameters to have a leading underscore so that we have
* our own separate namespace
*/
$query = '
UPDATE
[GalleryPluginParameterMap]
SET
[::parameterName] = ?
WHERE
[GalleryPluginParameterMap::parameterName] = ?
AND
[GalleryPluginParameterMap::pluginType] = \'module\'
AND
[GalleryPluginParameterMap::itemId] = 0
';
$ret = $storage->execute($query, array('_version', 'version'));
if ($ret) {
return $ret;
}
$ret = $storage->execute($query, array('_callbacks', 'callbacks'));
if ($ret) {
return $ret;
}
/* Added a new parameter */
$ret = $module->setParameter('misc.login', 'both');
if ($ret) {
return $ret;
}
case '0.8.3':
case '0.8.4':
case '0.8.5':
/* Added GalleryItem::originationTimestamp */
$ret = $storage->configureStore($module->getId(), array('GalleryItem:1.0'));
if ($ret) {
return $ret;
}
/* Copy viewedSinceTimestamp to originationTimestamp as both default to time() */
$query = '
UPDATE
[GalleryItem]
SET
[::originationTimestamp] = [::viewedSinceTimestamp]
';
$ret = $storage->execute($query, array());
if ($ret) {
return $ret;
}
case '0.8.6':
case '0.8.7':
$ret = $module->setParameter('default.newAlbumsUseDefaults', 'false');
if ($ret) {
return $ret;
}
case '0.8.8':
/*
* This was not originally part of the 0.8.9 upgrade, but added much later. Upgrade
* code after this will need valid factory registrations so we can't wait until
* upgrade() completes to register during reactivate().
*/
$ret = CoreModuleExtras::performFactoryRegistrations($module);
if ($ret) {
return $ret;
}
case '0.8.9':
/*
* Set all factory implementation weights to 5. We'll re-register all core
* implementations with a weight of 4 so that they get precedence.
*/
$query = 'UPDATE [GalleryFactoryMap] SET [::orderWeight] = 5';
$ret = $storage->execute($query, array());
if ($ret) {
return $ret;
}
case '0.8.10':
case '0.8.11':
case '0.8.12':
$ret = $module->setParameter('lock.system', 'flock');
if ($ret) {
return $ret;
}
case '0.8.13':
/* We used to add layout versioning here. Now that's been moved to the 0.9.29 block. */
case '0.8.14':
/* Added Entity::onLoadHandlers; default all values to null */
$ret = $storage->configureStore($module->getId(), array('GalleryEntity:1.0'));
if ($ret) {
return $ret;
}
case '0.8.15':
/* Removed GalleryItemPropertiesMap */
case '0.8.16':
/* Schema updates: GalleryPluginMap, GalleryPluginParameterMap, GalleryGroup */
$ret = $storage->configureStore($module->getId(),
array('GalleryPluginMap:1.0', 'GalleryPluginParameterMap:1.0', 'GalleryGroup:1.0'));
if ($ret) {
return $ret;
}
case '0.8.17':
/* Beta 1! */
case '0.9.0':
$ret = $module->removeParameter('misc.useShortUrls');
if ($ret) {
return $ret;
}
case '0.9.1':
/* Set Gallery version to 2.0-beta-1+ */
case '0.9.2':
/* Changed the data cache format */
case '0.9.3':
/* CSS refactor across entire app */
case '0.9.4':
$gallery->guaranteeTimeLimit(30);
GalleryCoreApi::requireOnce(
'modules/core/classes/helpers/GalleryMimeTypeHelper_advanced.class');
$ret = GalleryMimeTypeHelper_advanced::initializeMimeTypes();
if ($ret) {
return $ret;
}
case '0.9.5':
$gallery->guaranteeTimeLimit(30);
$ret = CoreModuleExtras::_createAccessListCompacterLock($module);
if ($ret) {
return $ret;
}
/*
* Choose an item that has permission rows. Find all other items with the same exact
* permissions. Create a new ACL, assign all those items to the ACL, delete those rows
* from the permissions table. Repeat.
*/
$totalRowsQuery = '
SELECT
COUNT(DISTINCT [GalleryPermissionMap::itemId])
FROM
[GalleryPermissionMap]
';
$findItemIdQuery = '
SELECT
[GalleryPermissionMap::itemId], COUNT(*) AS C
FROM
[GalleryPermissionMap]
GROUP BY
[GalleryPermissionMap::itemId]
ORDER BY
C DESC
';
$permissionRowCountQuery = '
SELECT
COUNT(*)
FROM
[GalleryPermissionMap]
WHERE
[GalleryPermissionMap::itemId] = ?
';
/* Updated this query for core 1.0.11 to write to userOrGroupId column */
$createAclQuery = '
INSERT INTO
[GalleryAccessMap] ([::accessListId], [::userOrGroupId], [::permission])
SELECT
?,
[GalleryPermissionMap::userId] + [GalleryPermissionMap::groupId],
[GalleryPermissionMap::permission]
FROM
[GalleryPermissionMap]
WHERE
[GalleryPermissionMap::itemId] = ?
';
$findPossibleDupesQuery = '
SELECT
[GalleryPermissionMap=2::itemId], COUNT(*)
FROM
[GalleryPermissionMap=1], [GalleryPermissionMap=2]
WHERE
[GalleryPermissionMap=1::itemId] = ?
AND
[GalleryPermissionMap=1::userId] = [GalleryPermissionMap=2::userId]
AND
[GalleryPermissionMap=1::groupId] = [GalleryPermissionMap=2::groupId]
AND
[GalleryPermissionMap=1::permission] = [GalleryPermissionMap=2::permission]
GROUP BY
[GalleryPermissionMap=2::itemId]
HAVING
COUNT(*) = ?
';
$refineDupesQuery = '
SELECT
[GalleryPermissionMap::itemId], COUNT(*)
FROM
[GalleryPermissionMap]
WHERE
[GalleryPermissionMap::itemId] IN (%s)
GROUP BY
[GalleryPermissionMap::itemId]
HAVING
COUNT(*) = ?
';
$assignAclQuery = '
INSERT INTO
[GalleryAccessSubscriberMap] ([::itemId], [::accessListId])
SELECT DISTINCT
[GalleryPermissionMap::itemId], ?
FROM
[GalleryPermissionMap]
WHERE
[GalleryPermissionMap::itemId] IN (%s)
';
$deleteOldPermsQuery = '
DELETE FROM
[GalleryPermissionMap]
WHERE
[GalleryPermissionMap::itemId] IN (%s)
';
/* Determine how many items we are going to process for our status message */
list ($ret, $results) =
$gallery->search($totalRowsQuery, array(), array('limit' => array('count' => 1)));
if ($ret) {
return $ret;
}
if ($results->resultCount() == 0) {
break;
}
$result = $results->nextResult();
$totalPermissionItems = $result[0];
$itemsProcessed = 0;
if ($totalPermissionItems > 0) {
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Upgrading permissions'),
null,
$itemsProcessed / $totalPermissionItems);
if ($ret) {
return $ret;
}
}
while ($totalPermissionItems > 0 && true) {
$gallery->guaranteeTimeLimit(60);
/* Find the next item in the permissions table */
list ($ret, $results) = $storage->search($findItemIdQuery);
if ($ret) {
return $ret;
}
if ($results->resultCount() == 0) {
break;
}
$result = $results->nextResult();
list ($targetItemId, $permissionRowCount) = array((int)$result[0], (int)$result[1]);
/* Create a new ACL */
list ($ret, $newAclId) = $storage->getUniqueId();
if ($ret) {
return $ret;
}
$ret = $storage->execute($createAclQuery, array($newAclId, $targetItemId));
if ($ret) {
return $ret;
}
/*
* Find all items that share the same permissions as the target. I haven't figured
* out a good way to do aggregation without using temporary tables, which I'd like
* to avoid for portability. So, figure out how many rows have at least as many
* matching permissions as our target item. These are potentially dupes. We'll
* refine them later on.
*/
list ($ret, $results) = $gallery->search(
$findPossibleDupesQuery, array($targetItemId, $permissionRowCount));
if ($ret) {
return $ret;
}
$possibleDupeIds = array();
while ($result = $results->nextResult()) {
$possibleDupeIds[] = (int)$result[0];
}
/*
* Process these queries in chunks since we may have thousands of items with the
* same permissions and we don't want to give the database a heart attack
*/
$chunkSize = 200;
while (!empty($possibleDupeIds)) {
$chunk = array_splice($possibleDupeIds, 0, $chunkSize);
$count = count($chunk);
/*
* Refine our dupes by eliminating ones that don't have exactly the same number
* of permission rows as our target. Our target item is included in the dupes,
* so this will always return at least 1 row.
*/
$markers = GalleryUtilities::makeMarkers($count);
$query = sprintf($refineDupesQuery, $markers);
list ($ret, $results) = $gallery->search(
$query, array_merge($chunk, array($permissionRowCount)));
$possibleDupeIds = array();
$dupeIds = array();
while ($result = $results->nextResult()) {
$dupeIds[] = (int)$result[0];
}
if (empty($dupeIds)) {
/* No actual dupes? Try the next chunk. */
continue;
}
$count = count($dupeIds);
$markers = GalleryUtilities::makeMarkers($count);
/* Set all the dupe items in this chunk to use the new ACL */
$query = sprintf($assignAclQuery, $markers);
$ret = $storage->execute($query, array_merge(array($newAclId), $dupeIds));
if ($ret) {
return $ret;
}
/* Remove all the permission rows for the migrated items */
$query = sprintf($deleteOldPermsQuery, $markers);
$ret = $storage->execute($query, $dupeIds);
if ($ret) {
return $ret;
}
$itemsProcessed += $count;
$ret = $statusMonitor->renderStatusMessage(
$module->translate(array(
'text' => 'Upgrading permissions (%d items complete, %d remaining)',
'arg1' => $itemsProcessed,
'arg2' => $totalPermissionItems - $itemsProcessed)),
'',
$itemsProcessed / $totalPermissionItems);
if ($ret) {
return $ret;
}
}
}
if ($totalPermissionItems > 0) {
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Deleting old permission tables'),
'',
$itemsProcessed / $totalPermissionItems);
if ($ret) {
return $ret;
}
}
/* Removed GalleryPermissionMap */
case '0.9.6':
/* Added GalleryMaintenance table */
case '0.9.7':
/*
* Change GalleryMaintenance::details column to be a serialized array. The old data is
* transient so just delete it. Added FlushTemplatesTask, FlushDatabaseCacheTask.
*/
$gallery->guaranteeTimeLimit(30);
$ret = GalleryCoreApi::removeAllMapEntries('GalleryMaintenanceMap');
if ($ret) {
return $ret;
}
case '0.9.8':
/*
* Create 'plugins' and 'plugins_data' directories in g2data. Remove trailing slash for
* config paths using substr so file_exists can detect either file or dir. Update: in
* core 1.0.6 the data.gallery.plugins dir moved under gallery2 basedir, not in g2data
* anymore; we may not have permission to create a dir here. So code below is now
* updated to not require those mkdirs to succeed.
*/
$gallery->guaranteeTimeLimit(30);
foreach (array(substr($gallery->getConfig('data.gallery.plugins'), 0, -1) => false,
$gallery->getConfig('data.gallery.plugins') . 'modules' => false,
$gallery->getConfig('data.gallery.plugins') . 'layouts' => false,
substr($gallery->getConfig('data.gallery.plugins_data'), 0, -1) => true,
$gallery->getConfig('data.gallery.plugins_data') . 'modules' => true,
$gallery->getConfig('data.gallery.plugins_data') . 'layouts' => true)
as $dir => $isRequired) {
if ($platform->file_exists($dir)) {
if ($platform->is_dir($dir)) {
/* No need to do anything. Except maybe we could check permissions here. */
} else {
/* There's a file there. There shouldn't be. Move it out of the way. */
if (!@$platform->rename($newDir, "$newDir.old") ||
!@$platform->mkdir($dir)) {
return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__,
"$dir already exists; unable to replace it");
}
}
} else {
if (!@$platform->mkdir($dir) && $isRequired) {
return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__,
"Unable to create $dir");
}
}
}
case '0.9.9':
/* Beta 2 release! */
case '0.9.10':
/* Added BuildDerivativesTask */
case '0.9.11':
/* Added GalleryRecoverPasswordMap */
case '0.9.12':
/* Added ResetViewCountsTask */
case '0.9.13':
/* Added SystemInfoTask */
case '0.9.14':
/* Added SetOriginationTimestampTask */
case '0.9.15':
/* Remove lock subdirs -- this is from 1.1.8->1.1.9 upgrade */
$locksDir = $gallery->getConfig('data.gallery.locks');
if ($platform->file_exists($locksDir)) {
@$platform->recursiveRmDir($locksDir);
}
@$platform->mkdir($locksDir);
/*
* Changed 'All Users' to 'Registered Users'
* Don't change if the user modified the name already!
* Don't change if there is already a group with the new name
*/
list ($ret, $group) =
GalleryCoreApi::fetchGroupByGroupName($module->translate('Registered Users'));
if ($ret) {
if ($ret->getErrorCode() & ERROR_MISSING_OBJECT) {
/* OK, we can change the group name */
list ($ret, $allUserGroupId) = $module->getParameter('id.allUserGroup');
if ($ret) {
return $ret;
}
list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($allUserGroupId);
if ($ret) {
return $ret;
}
list ($ret, $group) = GalleryCoreApi::loadEntitiesById($allUserGroupId);
if ($ret) {
return $ret;
}
$allUserGroupName = $group->getGroupName();
/* We used to entitize data in db; expect that from orignal group name: */
$originalGroupName = GalleryUtilities::utf8ToUnicodeEntities(
$module->translate('All Users'));
if (!strcmp($allUserGroupName, $originalGroupName)) {
$group->setGroupName($module->translate('Registered Users'));
$ret = $group->save();
if ($ret) {
return $ret;
}
$ret = GalleryCoreApi::releaseLocks($lockId);
if ($ret) {
return $ret;
}
}
} else {
return $ret;
}
} /* Else a group with that name already exists, nothing to do */
case '0.9.16':
/* Beta 3 release! */
case '0.9.17':
/* Split uploadLocalServer.dirs list into one parameter per entry */
list ($ret, $dirList) = $module->getParameter('uploadLocalServer.dirs');
if ($ret) {
return $ret;
}
if (!empty($dirList)) {
$dirList = explode(',', $dirList);
for ($i = 1; $i <= count($dirList); $i++) {
$ret = $module->setParameter('uploadLocalServer.dir.' . $i, $dirList[$i - 1]);
if ($ret) {
return $ret;
}
}
}
$ret = $module->removeParameter('uploadLocalServer.dirs');
if ($ret) {
return $ret;
}
case '0.9.18':
/* Add image/x-photo-cd mime type */
list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('pcd');
if (!$ret && $mimeType == 'application/unknown') {
$ret = GalleryCoreApi::addMimeType('pcd', 'image/x-photo-cd', false);
if ($ret) {
return $ret;
}
}
case '0.9.19':
/* New multisite system and support for config.php upgrades */
case '0.9.20':
/* Change view/controller separator: core:ShowItem -> core.ShowItem */
case '0.9.21':
/* Session cookie change, requires new config.php variable */
case '0.9.22':
/* GalleryModule::getItemLinks API change (GalleryModule API bumped to 0.13) */
case '0.9.23':
/* Session cookie change, revert the last change and try something new */
foreach (array('cookie.path', 'cookie.domain') as $parameterName) {
$ret = $module->setParameter($parameterName, '');
if ($ret) {
return $ret;
}
}
case '0.9.24':
/* Add image/jpeg-cmyk mime type */
list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('jpgcmyk');
if (!$ret && $mimeType == 'application/unknown') {
$ret = GalleryCoreApi::addMimeType('jpgcmyk', 'image/jpeg-cmyk', false);
if ($ret) {
return $ret;
}
}
case '0.9.25':
/* Add image/tiff-cmyk mime type */
list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('tifcmyk');
if (!$ret && $mimeType == 'application/unknown') {
$ret = GalleryCoreApi::addMimeType('tifcmyk', 'image/tiff-cmyk', false);
if ($ret) {
return $ret;
}
}
case '0.9.26':
/* Added GalleryDerivative::isBroken; default all values to null */
$ret = $storage->configureStore($module->getId(), array('GalleryDerivative:1.0'));
if ($ret) {
return $ret;
}
case '0.9.27':
/* Remove lock subdirs -- this is from 1.1.8->1.1.9 upgrade */
$locksDir = $gallery->getConfig('data.gallery.locks');
if ($platform->file_exists($locksDir)) {
@$platform->recursiveRmDir($locksDir);
}
@$platform->mkdir($locksDir);
/* Mark old broken derivatives as such with our new isBroken flag */
/*
* This is the filesize and the crc32 checksum of the broken derivative placeholder
* image that we used in beta 3 and earlier versions. We may have replaced this image
* by the time this upgrade code is run. Thus we hardcode filesize(oldImage) and
* crc32(oldImageData) here.
*/
$referenceSize = 1589;
/* CRC is a good measure to compare files (not to detect malicous attacks though) */
$referenceCrc = 888290220;
/*
* 1. Get a list of all derivatives that are not already marked as isBroken
* (We can't count on derivativeSize being correct, so check all derivatives)
* Update: upgrade from pre-beta-1 will fail to load RandomHighlightDerivativeImage
* so restrict this query to only GalleryDerivativeImage
*/
$gallery->guaranteeTimeLimit(60);
$query = 'SELECT [GalleryDerivative::id]
FROM [GalleryDerivative], [GalleryEntity]
WHERE [GalleryDerivative::isBroken] IS NULL
AND [GalleryDerivative::id] = [GalleryEntity::id]
AND [GalleryEntity::entityType] = \'GalleryDerviativeImage\'';
list ($ret, $searchResults) = $gallery->search($query);
if ($ret) {
return $ret;
}
/* Check the derivatives that match the search criteria */
if ($searchResults->resultCount() > 0) {
$derivativeIds = array();
while ($result = $searchResults->nextResult()) {
$derivativeIds[] = $result[0];
}
$totalDerivatives = sizeof($derivativeIds);
/*
* The following process is very expensive. We have to deal with a potentially huge
* (10^6) amount of derivatives. To not exceed the memory limit we do everything in
* batches. To not exceed the PHP execution time limit and to not exceed the apache
* timeout we add a progress bar and manipulate the PHP execution time limit
* periodically.
*/
$gallery->guaranteeTimeLimit(60);
/* Show a progress bar */
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Detecting broken derivatives'), '', 0);
if ($ret) {
return $ret;
}
/*
* The outer loop is for each derivativeId and we upgrade a progress bar every
* $progressStepSize ids. We don't load entity by entity, but in batches of
* $loadBatchSize. And we don't save the items that were detected as broken
* derivatives one by one, but also in batches of $saveBatchSize, i.e. we acquire
* and release the locks in this batch size, but still have to save entity by entity
* because Gallery has no mass entity save like loadEntitiesById().
*/
$derivatives = array();
$progressStepSize = min(500, intval($totalDerivatives / 10));
$loadBatchSize = 1000;
$saveBatchSize = 1000;
$itemsProcessed = 0;
$brokenDerivatives = array();
do {
/* 2. Load the entities in batches */
if (empty($derivatives) && !empty($derivativeIds)) {
/* Prevent PHP timeout */
$gallery->guaranteeTimeLimit(60);
/* Prevent apache timeout */
$ret = $statusMonitor->renderStatusMessage(
$module->translate(
array('text' => 'Detecting broken derivatives, loading '
. '(%d derivatives checked, %d remaining)',
'arg1' => $itemsProcessed,
'arg2' => sizeof($derivativeIds))),
'', $itemsProcessed / $totalDerivatives);
if ($ret) {
return $ret;
}
$currentDerivativeIds = array_splice($derivativeIds, 0, $loadBatchSize);
list ($ret, $derivatives) =
GalleryCoreApi::loadEntitiesById($currentDerivativeIds);
if ($ret) {
return $ret;
}
}
/* Detect if the derivative is broken */
if (!empty($derivatives)) {
$itemsProcessed++;
$gallery->guaranteeTimeLimit(30);
$derivative = array_pop($derivatives);
/*
* Show the progress, but not for each derivative, this would slow down the
* process considerably
*/
if ($itemsProcessed % $progressStepSize == 0 ||
$itemsProcessed == $totalDerivatives) {
$ret = $statusMonitor->renderStatusMessage(
$module->translate(
array('text' => 'Detecting broken derivatives (%d derivatives '
. 'checked, %d remaining)',
'arg1' => $itemsProcessed,
'arg2' => $totalDerivatives - $itemsProcessed)),
'', $itemsProcessed / $totalDerivatives);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(30);
}
/*
* 3. Filter out derivatives that don't return true for isCacheCurrent
* (= don't have a cache file yet = would be rebuilt anyway)
*/
list ($ret, $current) = $derivative->isCacheCurrent();
if ($ret) {
return $ret;
}
if (!$current) {
continue;
}
/*
* 4. Filter out derivatives that don't have the same file size as the
* broken image placeholder
*/
list ($ret, $path) = $derivative->fetchPath();
if ($ret) {
return $ret;
}
if (($size = $platform->filesize($path)) === false) {
return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE);
}
if ($size != $referenceSize) {
continue;
}
/* 5. Binary compare the derivative file with the placeholder file */
if (($data = $platform->file($path)) === false) {
return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE);
}
$data = implode('', $data);
if ($referenceCrc == crc32($data)) {
/* Add the derivative to the list of broken ones */
$brokenDerivatives[$derivative->getId()] = $derivative;
}
}
/* 6. Mark the detected broken derivative as such and save it in the DB */
if (sizeof($brokenDerivatives) == $saveBatchSize ||
(!empty($brokenDerivatives) && empty($derivativeIds))) {
$gallery->guaranteeTimeLimit(30);
$saveProgressStepSize = min(200, intval(sizeof($brokenDerivatives) / 10));
$ret = $statusMonitor->renderStatusMessage(
$module->translate(
array('text' => 'Detecting broken derivatives, saving '
. '(%d derivatives checked, %d remaining)',
'arg1' => $itemsProcessed,
'arg2' => $totalDerivatives - $itemsProcessed)),
'', $itemsProcessed / $totalDerivatives);
if ($ret) {
return $ret;
}
list ($ret, $lockId) =
GalleryCoreApi::acquireWriteLock(array_keys($brokenDerivatives));
if ($ret) {
return $ret;
}
$itemsSaved = 0;
foreach ($brokenDerivatives as $brokenDerivative) {
$itemsSaved++;
if ($itemsSaved % $saveProgressStepSize == 0) {
$ret = $statusMonitor->renderStatusMessage(
$module->translate(array(
'text' => 'Detecting broken derivatives, saving item '
. '%d of %d (%d derivatives complete, %d remaining)',
'arg1' => $itemsSaved,
'arg2' => sizeof($brokenDerivatives),
'arg3' => $itemsProcessed,
'arg4' => $totalDerivatives - $itemsProcessed)),
'', $itemsProcessed / $totalDerivatives);
if ($ret) {
GalleryCoreApi::releaseLocks($lockId);
return $ret;
}
$gallery->guaranteeTimeLimit(30);
}
$brokenDerivative->setIsBroken(true);
$ret = $brokenDerivative->save(true, false);
if ($ret) {
GalleryCoreApi::releaseLocks($lockId);
return $ret;
}
}
$brokenDerivatives = array();
$ret = GalleryCoreApi::releaseLocks($lockId);
if ($ret) {
return $ret;
}
}
/*
* Continue if there are either unloaded ids, unchecked derivatives or unsaved
* derivatives
*/
} while (!empty($derivativeIds) || !empty($brokenDerivatives) ||
!empty($derivatives));
}
case '0.9.28':
/* Changed module API onLoad($entity, $duringUpgrade) definition */
case '0.9.29':
/* Ginormous layout and theme consolidation refactor */
$ret = $storage->configureStore($module->getId(),
array('GalleryPluginParameterMap:1.1'));
if ($ret) {
return $ret;
}
$query = '
UPDATE
[GalleryPluginParameterMap]
SET
[::pluginType] = \'theme\'
WHERE
[GalleryPluginParameterMap::pluginType] = \'layout\'
';
$ret = $storage->execute($query);
if ($ret) {
return $ret;
}
/* After this refactor we only support the matrix theme */
$query = '
UPDATE
[GalleryAlbumItem]
SET
[::theme] = \'matrix\'
';
$ret = $storage->execute($query);
if ($ret) {
return $ret;
}
$query = '
UPDATE
[GalleryPluginMap]
SET
[::pluginType] = \'theme\'
WHERE
[GalleryPluginMap::pluginType] = \'layout\'
';
$ret = $storage->execute($query);
if ($ret) {
return $ret;
}
/*
* Rename g2data 'layouts' directories to be 'themes', or create them if they don't
* already exist (they should exist, though)
*/
foreach (array($gallery->getConfig('data.gallery.plugins'),
$gallery->getConfig('data.gallery.plugins_data')) as $base) {
if ($platform->file_exists("$base/themes")) {
if ($platform->file_exists("$base/layouts")) {
$platform->recursiveRmDir("$base/layouts");
}
} else if (file_exists($base)) {
if ($platform->file_exists("$base/layouts")) {
$platform->rename("$base/layouts", "$base/themes");
} else {
$platform->mkdir("$base/themes");
}
}
}
/* Removed parameters */
foreach (array('language.selector', 'misc.login') as $paramName) {
$ret = $module->removeParameter($paramName);
if ($ret) {
return $ret;
}
}
/*
* If we're coming from 0.8.13 or earlier, then our themes don't have version
* information, so take care of that here by calling installOrUpgrade() on the currently
* active themes to let them update their bookkeeping. Reactivate them too for good
* measure.
*/
if (version_compare($currentVersion, '0.8.13', '<=')) {
list ($ret, $themes) = GalleryCoreApi::fetchPluginStatus('theme');
if ($ret) {
return $ret;
}
foreach ($themes as $themeId => $themeStatus) {
$gallery->guaranteeTimeLimit(30);
if (!empty($themeStatus['active'])) {
list ($ret, $theme) = GalleryCoreApi::loadPlugin('theme', $themeId);
if ($ret &&
!($ret->getErrorCode() & ERROR_PLUGIN_VERSION_MISMATCH)) {
return $ret;
}
$ret = $theme->installOrUpgrade();
if ($ret) {
return $ret;
}
list ($ret, $ignored) = $theme->activate(false);
if ($ret &&
!($ret->getErrorCode() & ERROR_PLUGIN_VERSION_MISMATCH)) {
/*
* Theme getSettings may try to load ImageFrame interface, but
* ImageFrame may need to be upgraded. Ignore version mismatch here.
*/
return $ret;
}
}
}
}
case '0.9.30':
/* Removed layout column from AlbumItem; matrix is only theme for now: set default */
$ret = $storage->configureStore($module->getId(), array('GalleryAlbumItem:1.0'));
if ($ret) {
return $ret;
}
$ret = $module->setParameter('default.theme', 'matrix');
if ($ret) {
return $ret;
}
$ret = $module->removeParameter('default.layout');
if ($ret) {
return $ret;
}
$query = '
UPDATE
[GalleryAlbumItem]
SET
[::theme] = NULL
';
$ret = $storage->execute($query);
if ($ret) {
return $ret;
}
case '0.9.31':
/* Beta 4! */
case '0.9.32':
/* Minor core API change */
case '0.9.33':
/* Release Candidate 1! */
case '0.9.34':
/* Add date/time formats */
foreach (array('format.date' => '%x', 'format.time' => '%X', 'format.datetime' => '%c')
as $key => $value) {
$ret = $module->setParameter($key, $value);
if ($ret) {
return $ret;
}
}
case '0.9.35':
/* Release Candidate 2! */
case '0.9.36':
/*
* Fixed GalleryUtilities::getPseudoFileName for derivatives. Delete fast-download
* files that may have cached incorrect filenames.
*/
$slash = $platform->getDirectorySeparator();
$baseDir = $gallery->getConfig('data.gallery.cache') . 'derivative' . $slash;
for ($i = 0; $i < 10; $i++) {
$gallery->guaranteeTimeLimit(60);
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Clearing fast-download cache'), '', $i / 10);
if ($ret) {
return $ret;
}
for ($j = 0; $j < 10; $j++) {
$dir = $baseDir . $i . $slash . $j . $slash;
if ($dh = @$platform->opendir($dir)) {
while (($file = $platform->readdir($dh)) !== false) {
if (substr($file, -9) == '-fast.inc') {
@$platform->unlink($dir . $file);
}
}
$platform->closedir($dh);
}
}
}
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Clearing fast-download cache'), '', 1);
if ($ret) {
return $ret;
}
case '0.9.37':
/* 2.0 Release! */
case '1.0.0':
case '1.0.0.x':
/* Schema only upgrade */
$ret = $storage->configureStore($module->getId(),
array('GalleryPluginParameterMap:1.2'));
if ($ret) {
return $ret;
}
case '1.0.1':
/* Add image/wmf mime type */
list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('wmf');
if (!$ret && $mimeType == 'application/unknown') {
$ret = GalleryCoreApi::addMimeType('wmf', 'image/wmf', false);
if ($ret) {
return $ret;
}
}
case '1.0.2':
/* Security fix */
case '1.0.3':
/* Consolidated .sql files into schema.tpl */
case '1.0.4':
/* Added maintenance mode */
case '1.0.5':
/* Remove plugins directory from g2data */
$pluginDirectory = $gallery->getConfig('data.gallery.base') . 'plugins';
$pluginDirectories = array($pluginDirectory . '/modules',
$pluginDirectory . '/themes',
$pluginDirectory);
foreach ($pluginDirectories as $pluginDirectory) {
if (@$platform->file_exists($pluginDirectory)) {
/* We're not interested in whether it succeeded or not */
@$platform->recursiveRmDir($pluginDirectory);
}
}
case '1.0.6':
/* Add PluginPackageMap table */
case '1.0.7':
$ret = $module->setParameter('exec.beNice', '0');
if ($ret) {
return $ret;
}
case '1.0.8':
case '1.0.9':
/* Security fix in zipcart */
case '1.0.10':
/* Rename unnamed pre-beta-3 index to named index */
if ($storage->getType() == 'mysql') {
$gallery->debug('Rename unnamed pre-beta-3 index to named index (ignore errors)');
$query = sprintf('
ALTER TABLE %sAccessMap
DROP INDEX %saccessListId_2,
ADD INDEX %sAccessMap_83732(%saccessListId);',
$storage->_tablePrefix, $storage->_columnPrefix, $storage->_tablePrefix,
$storage->_columnPrefix);
/* Ignore error, since there's nothing to do for most installations */
$storage->execute($query);
}
/*
* Combine AccessMap userId/groupId into single userOrGroupId, and remove unused
* GALLERY_PERMISSION_ITEM_ADMIN permission flag. Also increase size of
* GalleryUser::email column.
*/
$ret = $storage->configureStore($module->getId(),
array('GalleryAccessMap:1.0', 'GalleryUser:1.0'));
if ($ret) {
return $ret;
}
/* If coming from 0.9.5 or earlier then GalleryAccessMap already has userOrGroupId */
if (version_compare($currentVersion, '0.9.5', '>')) {
$query = '
UPDATE
[GalleryAccessMap]
SET
[::userOrGroupId] = [::userId] + [::groupId]
';
$ret = $storage->execute($query, array());
if ($ret) {
return $ret;
}
}
$ret = $storage->configureStore($module->getId(), array('GalleryAccessMap:1.1'));
if ($ret) {
return $ret;
}
list ($ret, $flagModifier) =
$storage->getFunctionSql('BITAND', array('[::flags]', '?'));
if ($ret) {
return $ret;
}
$query = '
UPDATE
[GalleryPermissionSetMap]
SET
[::flags] = ' . $flagModifier . '
';
$ret = $storage->execute($query, array(3));
if ($ret) {
return $ret;
}
case '1.0.11':
/* Several previous upgrades used 'modules' instead of 'module' with plugin params */
list ($ret, $coreParams) = $module->fetchParameters();
if ($ret) {
return $ret;
}
foreach (array('misc.useShortUrls', 'language.selector') as $key) {
if (isset($coreParams[$key])) {
$ret = $module->removeParameter('misc.useShortUrls');
if ($ret) {
return $ret;
}
}
}
foreach (array('cookie.path' => '', 'cookie.domain' => '',
'exec.beNice' => '0', 'repository.updateTime' => '0')
as $key => $value) {
if (!isset($coreParams[$key])) {
$ret = $module->setParameter($key, $value);
if ($ret) {
return $ret;
}
}
}
$ret = GalleryCoreApi::removeMapEntry(
'GalleryPluginParameterMap', array('pluginType' => 'modules'));
if ($ret) {
return $ret;
}
case '1.0.12':
/* Add param 'language.useBrowserPref' */
list ($ret, $langCode) = $module->getParameter('default.language');
if ($ret) {
return $ret;
}
$useBrowserPref = '0';
if (empty($langCode)) {
$useBrowserPref = '1';
$ret = $module->setParameter('default.language', 'en_US');
if ($ret) {
return $ret;
}
}
$ret = $module->setParameter('language.useBrowserPref', $useBrowserPref);
if ($ret) {
return $ret;
}
case '1.0.13':
/* Add config parameter: 'baseUri'*/
case '1.0.14':
/* GalleryCoreApi 7.0 and GalleryModule 3.0 */
case '1.0.15':
/*
* Add fast-download for GalleryDataItems too. Fast-download files are now in
* cache/entity/. Delete the old files in cache/derivative/.
*/
$gallery->guaranteeTimeLimit(60);
$query = 'SELECT [GalleryDerivativeImage::id]
FROM [GalleryDerivativeImage]';
list ($ret, $searchResults) = $gallery->search($query);
if ($ret) {
return $ret;
}
if ($searchResults->resultCount() > 0) {
$derivativeIds = array();
while ($result = $searchResults->nextResult()) {
$derivativeIds[] = $result[0];
}
$totalDerivatives = count($derivativeIds);
$base = $gallery->getConfig('data.gallery.cache');
$gallery->guaranteeTimeLimit(60);
/* Show a progress bar */
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Deleting old fast-download cache'), '', 0);
if ($ret) {
return $ret;
}
$stepSize = min(100, max(intval($totalDerivatives / 10), 5));
for ($i = 0; $i < $totalDerivatives; $i++) {
/* Delete the file if it exists */
list ($first, $second) = GalleryDataCache::getCacheTuple($derivativeIds[$i]);
$fastDownloadFilePath = sprintf('%derivative/%s/%s/%d-fast.inc',
$base, $first, $second, $derivativeIds[$i]);
if ($platform->file_exists($fastDownloadFilePath)) {
$platform->unlink($fastDownloadFilePath);
}
/* Update the progress bar / prevent timouts */
if ($i % $stepSize == 0 || $i == ($totalDerivatives - 1)) {
$gallery->guaranteeTimeLimit(60);
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Deleting old fast-download cache'),
'', ($i+1) / $totalDerivatives);
if ($ret) {
return $ret;
}
}
}
}
case '1.0.16':
/* Added 'not-null' to Entities.inc and Map.inc */
$storageExtras =& $storage->_getExtras();
$storageExtras->_clearEntityAndMapCache();
case '1.0.17':
/* Add image/tga mime type */
list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('tga');
if (!$ret && $mimeType == 'application/unknown') {
$ret = GalleryCoreApi::addMimeType('tga', 'image/tga', false);
if ($ret) {
return $ret;
}
}
case '1.0.18':
/* Add index to GalleryEntity::linkId */
$ret = $storage->configureStore($module->getId(), array('GalleryEntity:1.1'));
if ($ret) {
return $ret;
}
case '1.0.19':
/* Add page level caching and the GalleryCache map */
$acceleration = serialize(array('guest' => array('type' => 'none'),
'user' => array('type' => 'none')));
$ret = GalleryCoreApi::setPluginParameter(
'module', 'core', 'acceleration', $acceleration);
if ($ret) {
return $ret;
}
case '1.0.20':
/* Add configurable captcha security level */
$ret = GalleryCoreApi::setPluginParameter('module', 'core', 'captcha.level', 'MEDIUM');
if ($ret) {
return $ret;
}
case '1.0.21':
/* GallerySession change: Store sessions in the database and no longer on disk */
$sessionsDir = $gallery->getConfig('data.gallery.base') . 'sessions' .
$platform->getDirectorySeparator();
$stepSize = 100;
$count = 0;
$iterationSize = 5000;
$iteration = 1;
/* Show a progress bar while removing the files */
$ret = $statusMonitor->renderStatusMessage(
$module->translate(array('text' => 'Deleting old session files (iteration %d)',
'arg1' => $iteration)),
'', 0);
if ($ret) {
return $ret;
}
$dir = $platform->opendir($sessionsDir, 'r');
if (!$dir) {
return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__,
"Can't access session dir");
}
$gallery->guaranteeTimeLimit(60);
while (($filename = $platform->readdir($dir)) !== false) {
if ($filename == '.' || $filename == '..') {
continue;
}
$count++;
$platform->unlink($sessionsDir . $filename);
/* Update the progress bar / prevent timouts */
if ($count % $stepSize == 0) {
$gallery->guaranteeTimeLimit(60);
$ret = $statusMonitor->renderStatusMessage(
$module->translate(
array('text' => 'Deleting old session files (iteration %d)',
'arg1' => $iteration)),
'', $count / $iterationSize);
if ($ret) {
return $ret;
}
}
if ($count > $iterationSize) {
$iteration++;
$count = 0;
}
}
$platform->closedir($dir);
$platform->rmdir($sessionsDir);
$ret = $statusMonitor->renderStatusMessage(
$module->translate(array('text' => 'Deleting old session files (iteration %d)',
'arg1' => $iteration)),
'', 1);
if ($ret) {
return $ret;
}
case '1.0.22':
/* Rename unnamed pre-beta-3 index to named index */
$gallery->guaranteeTimeLimit(120);
if ($storage->getType() == 'mysql') {
$gallery->debug('Rename unnamed pre-beta-3 index to named index (ignore errors)');
$indexChanges = array();
$indexChanges[] = array('AccessMap', 'permission',
'AccessMap_18058', array('permission'));
$indexChanges[] = array('AccessSubscriberMap', 'accessListId',
'AccessSubscriberMap_83732', array('accessListId'));
$indexChanges[] = array('ChildEntity', 'parentId',
'ChildEntity_52718', array('parentId'));
$indexChanges[] = array('Derivative', 'derivativeSourceId',
'Derivative_85338', array('derivativeSourceId'));
$indexChanges[] = array('Derivative', 'derivativeOrder',
'Derivative_25243', array('derivativeOrder'));
$indexChanges[] = array('Derivative', 'derivativeType',
'Derivative_97216', array('derivativeType'));
$indexChanges[] = array('DerivativePrefsMap', 'itemId',
'DerivativePrefsMap_75985', array('itemId'));
$indexChanges[] = array('Entity', 'creationTimestamp',
'Entity_76255', array('creationTimestamp'));
$indexChanges[] = array('Entity', 'isLinkable',
'Entity_35978', array('isLinkable'));
$indexChanges[] = array('Entity', 'modificationTimestamp',
'Entity_63025', array('modificationTimestamp'));
$indexChanges[] = array('Entity', 'serialNumber',
'Entity_60702', array('serialNumber'));
$indexChanges[] = array('FileSystemEntity ', 'pathComponent',
'FileSystemEntity_3406', array('pathComponent'));
$indexChanges[] = array('Item', 'keywords', 'Item_99070', array('keywords'));
$indexChanges[] = array('Item', 'ownerId', 'Item_21573', array('ownerId'));
$indexChanges[] = array('Item', 'summary', 'Item_54147', array('summary'));
$indexChanges[] = array('Item', 'title', 'Item_90059', array('title'));
$indexChanges[] = array('ItemAttributesMap', 'parentSequence',
'ItemAttributesMap_95270', array('parentSequence'));
$indexChanges[] = array('MaintenanceMap', 'taskId',
'MaintenanceMap_21687', array('taskId'));
$indexChanges[] = array('PluginParameterMap', 'pluginType_2',
'PluginParameterMap_12808',
array('pluginType', 'pluginId', 'itemId'));
$indexChanges[] = array('PluginParameterMap', 'pluginType_3',
'PluginParameterMap_80596', array('pluginType'));
$indexChanges[] = array('TkOperatnMimeTypeMap', 'operationName',
'TkOperatnMimeTypeMap_2014', array('operationName'));
$indexChanges[] = array('TkOperatnMimeTypeMap', 'mimeType',
'TkOperatnMimeTypeMap_79463', array('mimeType'));
$indexChanges[] = array('TkOperatnParameterMap', 'operationName',
'TkOperatnParameterMap_2014', array('operationName'));
$indexChanges[] = array('TkPropertyMimeTypeMap', 'propertyName',
'TkPropertyMimeTypeMap_52881', array('propertyName'));
$indexChanges[] = array('TkPropertyMimeTypeMap', 'mimeType',
'TkPropertyMimeTypeMap_79463', array('mimeType'));
$indexChanges[] = array('UserGroupMap', 'userId',
'UserGroupMap_69068', array('userId'));
$indexChanges[] = array('UserGroupMap', 'groupId',
'UserGroupMap_89328', array('groupId'));
$indexChanges[] = array('Lock', 'lockId',
'Lock_11039', array('lockId'));
foreach ($indexChanges as $change) {
$indexColumns = implode('`, `' . $storage->_columnPrefix, $change[3]);
$indexColumns = $storage->_columnPrefix . $indexColumns;
$query = sprintf('
ALTER TABLE `%s%s`
DROP INDEX `%s%s`,
ADD INDEX `%s%s`(`%s`);',
$storage->_tablePrefix, $change[0], $storage->_columnPrefix, $change[1],
$storage->_tablePrefix, $change[2], $indexColumns);
/* Ignore error, since there's nothing to do for most installations */
$storage->execute($query);
}
$gallery->debug('Finished renaming unnamed pre-beta-3 indices to named indices');
}
/* Commit transactions before we execute a query that we expect to fail */
$ret = $storage->checkPoint();
if ($ret) {
return $ret;
}
/*
* Also add a single column index on AccessMap.accessListId since it was forgotten in
* the initial upgrade code. Ignore errors since some installations already have it.
*/
$gallery->debug('Adding an index to the AccessMap table, ignore errors');
$storage->configureStore($module->getId(), array('GalleryAccessMap:1.2'));
/* Postgres will abort the transaction if the index exists, so checkpoint here */
$ret = $storage->checkPoint();
if ($ret) {
return $ret;
}
$gallery->debug('Finished adding an index to the AccessMap table');
/*
* Make sure the schema update is stored, can't use updateMapEntry because schema is not
* in Maps.xml
*/
$query = sprintf('
UPDATE %sSchema
SET %smajor=1, %sminor=3
WHERE %sname=\'AccessMap\' AND %smajor=1 AND %sminor=2',
$storage->_tablePrefix, $storage->_columnPrefix,
$storage->_columnPrefix, $storage->_columnPrefix,
$storage->_columnPrefix, $storage->_columnPrefix);
$ret = $storage->execute($query);
if ($ret) {
return $ret;
}
case '1.0.23':
/* Rename GalleryCache to GalleryCacheMap, and make the value column TEXT(LARGE) */
case '1.0.24':
/* Add CoreCaptchaAdminOption, rename level parameter */
$gallery->guaranteeTimeLimit(60);
list ($ret, $level) = $module->getParameter('captcha.level');
if ($ret) {
return $ret;
}
$ret = $module->setParameter('validation.level', $level);
if ($ret) {
return $ret;
}
$ret = $module->removeParameter('captcha.level');
if ($ret) {
return $ret;
}
case '1.0.25':
case '1.0.26':
/*
* 2.1 Release Candidate 1!
*
* We used to change the character set for MySQL databases to utf8 here, but now we do
* it on every upgrade (at the beginning) to allow for the fact that the user can
* upgrade their MySQL from 3.x to 4.x at any time. We still call it here for
* historical accuracy for users upgrading from before 1.0.26.
*/
list ($ret, $converted) =
CoreModuleExtras::convertCharacterSetToUtf8($module, $statusMonitor);
if ($ret) {
return $ret;
}
/* Clear the cache data since we changed the blob encoding */
$gallery->guaranteeTimeLimit(60);
$ret = GalleryCoreApi::removeAllMapEntries('GalleryCacheMap');
if ($ret) {
return $ret;
}
case '1.0.27':
case '1.0.28':
/* Change in page cache key format */
case '1.0.29':
/* Support for transactional locking */
case '1.0.30':
/* Pull dangerous mime types */
$ret = GalleryCoreApi::removeMimeType(
array('mimeType' => array('text/html', 'application/xhtml+xml', 'text/xml')));
if ($ret) {
return $ret;
}
case '1.0.31':
list ($ret, $params) = GalleryCoreApi::fetchAllPluginParameters('module', 'core');
if ($ret) {
return $ret;
}
foreach (array('session.lifetime' => array(25 * 365 * 86400, 21 * 86400),
'session.inactivityTimeout' => array(14 * 86400, 7 * 86400)) as
$key => $oldAndNew) {
if ($params[$key] == $oldAndNew[0]) {
$ret = $module->setParameter($key, $oldAndNew[1]);
if ($ret) {
return $ret;
}
}
}
case '1.0.32':
/* 2.1 Release Candidate 2! */
case '1.0.33':
/* Security fix in installer/upgrader - RC-2a */
case '1.0.34':
/* 2.1 Release! */
case '1.1.0':
case '1.1.0.x':
/* Minimum PHP version now 4.3.0; new versions of ADODb and Smarty */
case '1.1.1':
case '1.1.2':
/* Add Flash video and Windows playlist mime types */
list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('flv');
if (!$ret && $mimeType == 'application/unknown') {
$ret = GalleryCoreApi::addMimeType('flv', 'video/x-flv', false);
if ($ret) {
return $ret;
}
}
list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('asx');
if (!$ret && $mimeType == 'application/unknown') {
$ret = GalleryCoreApi::addMimeType('asx', 'video/x-ms-asx', false);
if ($ret) {
return $ret;
}
}
case '1.1.3':
/* Add renderers to GalleryItem */
$ret = $storage->configureStore($module->getId(), array('GalleryItem:1.1'));
if ($ret) {
return $ret;
}
$ret = $storage->execute('UPDATE [GalleryItem] SET [::renderer] = NULL');
if ($ret) {
return $ret;
}
/*
* Switch PanoramaPhotoItem and PanoramaDerivativeImage entities back to their base
* classes and set the items to use the PanoramaRenderer instead
*/
$gallery->guaranteeTimeLimit(60);
$query = '
SELECT
[GalleryEntity::id], [GalleryEntity::entityType]
FROM
[GalleryEntity]
WHERE
[GalleryEntity::entityType] IN (\'PanoramaPhotoItem\', \'PanoramaDerivativeImage\')
';
list ($ret, $searchResults) = $gallery->search($query, array());
if ($ret) {
return $ret;
}
$photos = $derivatives = array();
while ($result = $searchResults->nextResult()) {
if ($result[1] == 'PanoramaPhotoItem') {
$photos[] = $result[0];
} else {
$derivatives[] = $result[0];
}
}
$total = count($photos) + count($derivatives);
/* Switch PanoramaPhotoItems back to GalleryPhotoItems */
for ($i = 0; $photos; $i += count($ids)) {
$gallery->guaranteeTimeLimit(30);
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Updating panorama items'), '', $i / $total);
if ($ret) {
return $ret;
}
$ids = array_splice($photos, 0, 500);
$markers = GalleryUtilities::makeMarkers($ids);
$query = "UPDATE [GalleryItem] SET [::renderer] = 'PanoramaRenderer' " .
"WHERE [GalleryItem::id] IN ($markers)";
$ret = $storage->execute($query, $ids);
if ($ret) {
return $ret;
}
$query = "UPDATE [GalleryEntity] SET [::entityType] = 'GalleryPhotoItem' " .
"WHERE [GalleryEntity::id] IN ($markers)";
$ret = $storage->execute($query, $ids);
if ($ret) {
return $ret;
}
}
/* Switch PanoramaDerivativeImage back to GalleryDerivativeImage */
while ($derivatives) {
$gallery->guaranteeTimeLimit(30);
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Updating panorama items'), '', $i / $total);
if ($ret) {
return $ret;
}
$ids = array_splice($derivatives, 0, 500);
$markers = GalleryUtilities::makeMarkers($ids);
$query = "UPDATE [GalleryEntity] SET [::entityType] = 'GalleryDerivativeImage' " .
"WHERE [GalleryEntity::id] IN ($markers)";
$ret = $storage->execute($query, $ids);
if ($ret) {
return $ret;
}
$i += count($ids);
}
if ($total) {
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Updating panorama items'), '', 1);
if ($ret) {
return $ret;
}
}
case '1.1.4':
/* Add mpeg-4 video mime type */
list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('mp4');
if (!$ret && $mimeType == 'application/unknown') {
$ret = GalleryCoreApi::addMimeType('mp4', 'video/mp4', false);
if ($ret) {
return $ret;
}
}
case '1.1.5':
case '1.1.6':
/* Remove useless rows in AccessSubscriberMap */
$gallery->guaranteeTimeLimit(60);
$query = '
SELECT
[GalleryAccessSubscriberMap::itemId]
FROM
[GalleryAccessSubscriberMap], [GalleryEntity]
WHERE
[GalleryAccessSubscriberMap::accessListId] = 0
AND
[GalleryAccessSubscriberMap::itemId] = [GalleryEntity::id]
AND
[GalleryEntity::entityType] IN (?,?,?,?)
';
list ($ret, $searchResults) = $gallery->search($query,
array('GalleryDerivativeImage', 'GalleryUser', 'GalleryGroup', 'GalleryComment'));
if ($ret) {
return $ret;
}
$itemIds = array();
while ($result = $searchResults->nextResult()) {
$itemIds[] = (int)$result[0];
}
$total = count($itemIds);
$query = 'DELETE FROM [GalleryAccessSubscriberMap] WHERE [::itemId] IN (';
for ($i = 0; $itemIds; $i += count($ids)) {
$gallery->guaranteeTimeLimit(30);
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Optimizing AccessSubscriberMap table'), '', $i / $total);
if ($ret) {
return $ret;
}
$ids = array_splice($itemIds, 0, 500);
$markers = GalleryUtilities::makeMarkers($ids);
$ret = $storage->execute($query . $markers . ')', $ids);
if ($ret) {
return $ret;
}
}
if ($total) {
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Optimizing AccessSubscriberMap table'), '', 1);
if ($ret) {
return $ret;
}
}
case '1.1.7':
/* ItemAddFromServer and ItemAddFromWeb moved to separate module */
/* Move uploadLocalServer.dir entries to itemadd module in case it is activated later */
list ($ret, $params) = GalleryCoreApi::fetchAllPluginParameters('module', 'core');
if ($ret) {
return $ret;
}
for ($i = 1; isset($params['uploadLocalServer.dir.' . $i]); $i++) {
$key = 'uploadLocalServer.dir.' . $i;
$ret = GalleryCoreApi::setPluginParameter('module', 'itemadd', $key, $params[$key]);
if ($ret) {
return $ret;
}
$ret = $module->removeParameter($key);
if ($ret) {
return $ret;
}
}
case '1.1.8':
/* Remove lock subdirs */
$locksDir = $gallery->getConfig('data.gallery.locks');
if ($platform->file_exists($locksDir)) {
@$platform->recursiveRmDir($locksDir);
}
@$platform->mkdir($locksDir);
case '1.1.9':
/* Graphics toolkits now support percentages for thumbnail/scale/resize */
case '1.1.10':
/* Moved ItemCreateLink[Single] to replica module */
case '1.1.11':
/* GalleryAuthPlugin: set active user from session now handled by SessionAuthPlugin */
case '1.1.12':
/* GalleryCoreApi::getMapEntry */
case '1.1.13':
/* GalleryDynamicAlbum */
case '1.1.14':
/*
* Add a .htaccess file in the storage folder to protect it against direct access
* in case it is accessible from the web.
*/
$fh = @fopen($gallery->getConfig('data.gallery.base') . '.htaccess', 'w');
if ($fh) {
$htaccessContents = "DirectoryIndex .htaccess\n" .
"SetHandler Gallery_Security_Do_Not_Remove\n" .
"Options None\n" .
"\n" .
"RewriteEngine off\n" .
"\n" .
"\n" .
"Order allow,deny\n" .
"Deny from all\n" .
"\n";
fwrite($fh, $htaccessContents);
fclose($fh);
}
case '1.1.15':
/* Locked Users */
$ret = $storage->configureStore($module->getId(), array('GalleryUser:1.1'));
if ($ret) {
return $ret;
}
case '1.1.16':
/* Initialize multiple repositories */
$ret = $module->setParameter('core.repositories', serialize(array('released' => 1)));
if ($ret) {
return $ret;
}
/* Locked plugins */
$ret = $storage->configureStore($module->getId(), array('GalleryPluginPackageMap:1.0'));
if ($ret) {
return $ret;
}
case '1.1.17':
/* Rolled SessionAuthPlugin into GallerySession.class, so force a factory update */
case '1.1.18':
/* Added PHP display_errors ini setting to config.php */
case '1.1.19':
/* Added ConvertDatabaseToUtf8Task */
case '1.1.20':
/* Add column isEmpty to CacheMap */
$ret = $storage->configureStore($module->getId(), array('GalleryCacheMap:1.0'));
if ($ret) {
return $ret;
}
case '1.1.21':
/* Added authentication token */
case '1.1.22':
/* Add FailedLoginsMap */
case '1.1.23':
/* Add JavaScriptWarning.tpl */
case '1.1.24':
/* Add page-level caching for embedded mode */
case '1.1.25':
/* 2.2 Release Candidate 1! */
case '1.1.26':
/* Prevent PHP from showing errors on direct access to config.php */
case '1.1.27':
/* Changed repository cache directory, easiest to just blow away the old one. */
$oldDir = $gallery->getConfig('data.gallery.plugins_data') . 'modules/core/repository';
if ($platform->file_exists($oldDir)) {
@$platform->recursiveRmDir($oldDir);
}
case '1.1.28':
/* Added GalleryUrlGenerator::makeAbsoluteUrl() */
case '1.1.29':
/* 2.2 Release Candidate 2! */
case '1.1.30':
/* Reposition display_errors in config.php */
case '1.1.31':
/* 2.2 Release! */
case '1.2.0':
/* 2.2.1 Bugfix Release */
case '1.2.0.1':
/*
* Add a new column to the Schema table to store the creation sql for each table. This
* change is to prepare the way for database export functionality.
*/
$gallery->guaranteeTimeLimit(30);
$ret = $storage->configureStore($module->getId(), array('Schema:1.0'));
if ($ret) {
return $ret;
}
list ($ret, $modules) = GalleryCoreApi::fetchPluginStatus('module', true);
if ($ret) {
return $ret;
}
$storageExtras =& $storage->_getExtras();
/* Load all table versions */
list ($ret, $tableVersions) = $storageExtras->_loadTableVersions();
if ($ret) {
return $ret;
}
$count = 1;
$total = count($modules);
$statusText = $module->translate('Converting Schema Table');
foreach ($modules as $moduleId => $moduleStatus) {
/* Skip uninstalled/unavailable modules */
if (!isset($moduleStatus['active']) || empty($moduleStatus['available'])) {
continue;
}
list ($ret, $sql) = $storageExtras->_getModuleSql($moduleId);
if ($ret) {
return $ret;
}
if (empty($sql['table'])){
continue;
}
foreach ($sql['table'] as $tableName => $tableSql) {
list ($safeName, $unused, $nameInSchema) =
$storage->_translateTableName($tableName);
if (!array_key_exists($nameInSchema, $tableVersions)) {
continue;
}
/*
* Check if there is a pending alter for the table and skip if there is.
* Column will be populated when/if that module is upgraded.
*/
list ($major, $minor) = $tableVersions[$nameInSchema];
if (!empty($sql['alter'][$tableName][$major][$minor])) {
continue;
}
$query = 'UPDATE [GallerySchema] SET [::createSql] = ? WHERE [::name] = ?';
$ret = $storage->execute($query, array($tableSql, $nameInSchema));
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(60);
$ret = $statusMonitor->renderStatusMessage($statusText, '', $count / $total);
if ($ret) {
return $ret;
}
}
$ret = $statusMonitor->renderStatusMessage($statusText, '', $count++ / $total);
if ($ret) {
return $ret;
}
}
/* Changed the length of the SessionMap data field for mySql & DB2. */
$ret = $storage->configureStore($module->getId(), array('GallerySessionMap:1.0'));
if ($ret) {
return $ret;
}
case '1.2.0.2':
/* 2.2.2 Bugfix Release - Not used */
case '1.2.0.3':
/* 2.2.2 Bugfix Release */
/* Store Entities.inc and Maps.inc definitions in the Schema table. */
$gallery->guaranteeTimeLimit(30);
/* Remove _maps & _entities parameters from GalleryPluginParameterMap. See r16620 */
$query = 'DELETE FROM [GalleryPluginParameterMap]
WHERE [::parameterName] in (\'_maps\', \'_entities\')
AND [::pluginType] = \'module\'';
$ret = $storage->execute($query);
if ($ret) {
return $ret;
}
$ret = $storage->configureStore($module->getId(), array('Schema:1.1'));
if ($ret) {
return $ret;
}
list ($ret, $modules) = GalleryCoreApi::fetchPluginStatus('module', true);
if ($ret) {
return $ret;
}
$count = 1;
$total = count($modules);
$statusText = $module->translate('Converting Schema Table');
foreach ($modules as $moduleId => $moduleStatus) {
/* Skip uninstalled/unavailable modules */
if (!isset($moduleStatus['active']) || empty($moduleStatus['available'])) {
continue;
}
$ret = $storage->updateTableInfo($moduleId);
if ($ret) {
return $ret;
}
$gallery->guaranteeTimeLimit(30);
$ret = $statusMonitor->renderStatusMessage($statusText, '', $count++ / $total);
if ($ret) {
return $ret;
}
}
$ret = $storage->checkPoint();
if ($ret) {
return $ret;
}
case 'end of upgrade path':
/*
* Leave this bogus case at the end of the legitimate case statements so that we always
* properly terminate our upgrade path with a break
*/
break;
default:
$gallery->debug('Error: Unknown module version');
return GalleryCoreApi::error(ERROR_BAD_PLUGIN, __FILE__, __LINE__,
sprintf('Unknown module version %s', $currentVersion));
}
$gallery->debug('Write new version to versions file');
$versionFile = $gallery->getConfig('data.gallery.base') . 'versions.dat';
$versionDatError = 0;
if ($fd = $platform->fopen($versionFile, 'wb')) {
$data = sprintf("%s\n%s",
$module->getVersion(),
$module->getGalleryVersion());
if ($platform->fwrite($fd, $data) != strlen($data)) {
$versionDatError = 1;
}
$platform->fclose($fd);
} else {
$versionDatError = 1;
}
if ($versionDatError) {
$gallery->debug('Error: Can\'t write to versions file');
return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__,
'Can\'t write to the versions file');
}
return null;
}
/**
* Determine what changes to config.php are required for this upgrade.
*
* @param string $currentVersion current core version
* @return array of array('remove' => array of string regexp removals,
* 'add' => array of string additions)
* @access private
*/
function _prepareConfigUpgrade($currentVersion) {
global $gallery;
$configChanges = array();
$currentVersion = preg_replace('/^(1\.[01]\.0)\.\d+$/', '$1.x', $currentVersion);
/**
* README: How to update the block below
*
* If you add a new feature to the core module and revise the version, you should do the
* following. Supposing the current version is 1.0.1 and you're adding 1.0.2. Go to the
* end of the switch and find the 'end of upgrade path' case. Create a new case *above*
* that one with the old version number. For our example you'd add: "case '1.0.1':" and
* then your code. Do *not* put in a break statement. (Update upgrade function too).
*/
switch ($currentVersion) {
case '0.8.4':
case '0.8.5':
case '0.8.6':
case '0.8.7':
case '0.8.8':
case '0.8.9':
case '0.8.10':
case '0.8.11':
case '0.8.12':
case '0.8.13':
case '0.8.14':
case '0.8.15':
case '0.8.16':
case '0.8.17':
case '0.9.0':
case '0.9.1':
case '0.9.2':
case '0.9.3':
case '0.9.4':
case '0.9.5':
case '0.9.6':
case '0.9.7':
case '0.9.8':
case '0.9.9':
case '0.9.10':
case '0.9.11':
case '0.9.12':
case '0.9.13':
case '0.9.14':
case '0.9.15':
case '0.9.16':
case '0.9.17':
case '0.9.18':
case '0.9.19':
$add = array();
if (!isset($gallery->_config['allowSessionAccess'])) {
/*
* This item was added to config.php before config.php upgrades were supported. Add
* it only if not already present.
*/
$add[] =
'/*
* Allow a particular IP address to access the session (it still must know the
* session id) even though it doesn\'t match the address/user agent that created
* the session. Put the address of validator.w3.org (\'128.30.52.13\') here to allow
* validation of non-public Gallery pages from the links at the bottom of the page.
*/
$gallery->setConfig(\'allowSessionAccess\', false);
';
}
$add[] =
'/*
* URL of Gallery codebase; required only for multisite install.
*/
$gallery->setConfig(\'galleryBaseUrl\', \'\');
';
$configChanges[] = array(
'remove' => array('{/\*[^/]*\*/\s*\$gallery->setConfig\(\'galleryId\',.*?;\s*}s'),
'add' => $add, 'edit' => array());
case '0.9.20':
case '0.9.21':
$add = array();
/* Generate cookieId */
list ($usec, $sec) = explode(" ", microtime());
$cookieId = substr(md5(rand()), 0, 6);
$add[] =
'
/*
* Set the name for Gallery session cookies. The name of the session cookie is
* a concatenation of \'GALLERYSID_\' and cookieId, which is randomly generated
* at Gallery installation time. You can change cookieId at any time, but if
* you change it be aware of two things:
* 1. Users have to login again after the change. They lose their old session.
* 2. If multiple Gallery installs are running on the same domain (in different paths or
* different subdomains) choose cookieId such that it is different for all Gallery
* installs on the same domain.
*/
$gallery->setConfig(\'cookieId\', \'' . $cookieId . '\');
';
$configChanges[] = array('remove' => array(), 'add' => $add, 'edit' => array());
case '0.9.22':
case '0.9.23':
/* Session cookie change, revert the last change and try something new */
$configChanges[] = array(
'remove' => array('{/\*[^/]*\*/\s*\$gallery->setConfig\(\'cookieId\',.*?;\s*}s'),
'add' => array(), 'edit' => array());
case '0.9.24':
case '0.9.25':
case '0.9.26':
case '0.9.27':
case '0.9.28':
case '0.9.29':
case '0.9.30':
case '0.9.31':
case '0.9.32':
case '0.9.33':
case '0.9.34':
case '0.9.35':
case '0.9.36':
case '0.9.37':
case '1.0.0':
case '1.0.0.x':
case '1.0.1':
case '1.0.2':
case '1.0.3':
case '1.0.4':
$configChanges[] = array('remove' => array(), 'edit' => array(), 'add' => array(
'
/*
* Maintenance mode. You can disable access to the site for anyone but
* site administrators by setting this this flag. Set value below to:
* true (without quotes) - to use a basic notification page; themed
* view with admin login link when codebase is up to date, but a
* plain unstyled page when codebase has been updated but upgrader
* has not yet been run.
* url (with quotes) - provide a URL where requests are redirected in
* either case described above. Example: \'/maintenance.html\'
*/
$gallery->setConfig(\'mode.maintenance\', false);
'));
case '1.0.5':
case '1.0.6':
case '1.0.7':
case '1.0.8':
case '1.0.9':
case '1.0.10':
case '1.0.11':
case '1.0.12':
case '1.0.13':
/* Add config parameter: 'baseUri' */
$configChanges[] = array('remove' => array(), 'edit' => array(), 'add' => array(
'
/*
* This setting can be used to override Gallery\'s auto-detection of the domain-name,
* protocol (http/https), URL path, and of the file & query string.
* Most users can leave this empty. If the server is misconfigured or for very special
* setups, this setting can be quite handy.
* Examples (the positions of the slashes (\'/\') are important):
* override the path: $gallery->setConfig(\'baseUri\', \'/another/path/\');
* override the host + path: $gallery->setConfig(\'baseUri\', \'example.com/gallery2/\');
* override the protocol + host + path + file:
* $gallery->setConfig(\'baseUri\', \'https://example.com:8080/gallery2/index.php\');
*/
$gallery->setConfig(\'baseUri\', \'\');'));
case '1.0.14':
case '1.0.15':
/*
* Normalize the config path 'data.gallery.base' (add a trailing slash if necessary).
* Escape the backslashes and quotes two times since we feed preg_replace with it.
*/
$edit = array();
$tmp = strtr($gallery->getConfig('data.gallery.base'),
array('\\' => '\\\\\\\\', "'" => "\\\\'"));
$edit['regexp'] = '{\$gallery->setConfig\(\'data\.gallery\.base\',.*?;}s';
$edit['replacement'] = '$gallery->setConfig(\'data.gallery.base\', \'' . $tmp . '\');';
$configChanges[] = array('remove' => array(), 'add' => array(), 'edit' => array($edit));
case '1.0.16':
case '1.0.17':
case '1.0.18':
case '1.0.19':
case '1.0.20':
case '1.0.21':
case '1.0.22':
case '1.0.23':
case '1.0.24':
case '1.0.25':
case '1.0.26':
case '1.0.27':
case '1.0.28':
case '1.0.29':
case '1.0.30':
case '1.0.31':
case '1.0.32':
case '1.0.33':
case '1.0.34':
case '1.1.0':
case '1.1.0.x':
case '1.1.1':
case '1.1.2':
case '1.1.3':
case '1.1.4':
case '1.1.5':
case '1.1.6':
case '1.1.7':
case '1.1.8':
case '1.1.9':
case '1.1.10':
case '1.1.11':
case '1.1.12':
case '1.1.13':
case '1.1.14':
case '1.1.15':
case '1.1.16':
case '1.1.17':
case '1.1.18':
/* Originally added PHP display_errors setting in this step, but at the end. */
case '1.1.19':
case '1.1.20':
case '1.1.21':
case '1.1.22':
case '1.1.23':
case '1.1.24':
case '1.1.25':
case '1.1.26':
/*
* Prevent PHP from showing errors on direct access to config.php by adding a check
* for the $gallery object before the first setConfig() call.
*/
$edit = array();
$edit['regexp'] = '{(<\?php\s*(?:/\*.*?\*/\s*)?)}s';
$edit['replacement'] = '\1/*
* Prevent direct access to config.php.
*/
if (!isset($gallery) || !method_exists($gallery, \'setConfig\')) {
exit;
}
';
$configChanges[] = array('remove' => array(), 'add' => array(), 'edit' => array($edit));
case '1.1.27':
case '1.1.28':
case '1.1.29':
case '1.1.30':
/* Reposition display_errors from the end to the beginning of the config file. */
$remove = array('{/\*[^/]*\*/\s*\@?ini_set\(\'display_errors\',.*?;\s*}s');
$edit = array();
$edit['regexp'] = '{(<\?php\s*(?:/\*.*?\*/\s*)?)}s';
$edit['replacement'] = '\1/*
* When display_errors is enabled, PHP errors are printed to the output.
* For production web sites, you\'re strongly encouraged to turn this feature off,
* and use error logging instead.
* During development, you should set the value to 1 to ensure that you notice PHP
* warnings and notices that are not covered in unit tests (e.g. template issues).
*/
@ini_set(\'display_errors\', 0);
';
$configChanges[] = array('remove' => $remove, 'add' => array(), 'edit' => array($edit));
case '1.1.31':
case '1.2.0':
case '1.2.0.1':
case '1.2.0.2':
case '1.2.0.3':
case 'end of upgrade path':
/*
* Leave this bogus case at the end of the legitimate case statements so that we always
* properly terminate our upgrade path with a break
*/
break;
default:
$gallery->debug("Unknown module version $currentVersion in prepareConfigUpgrade()");
}
return $configChanges;
}
/**
* Check if any changes to config.php are required for this upgrade.
*
* @param string $currentVersion current core version
* @return boolean true if change is required
*/
function isConfigUpgradeRequired($currentVersion) {
$configChanges = CoreModuleExtras::_prepareConfigUpgrade($currentVersion);
return !empty($configChanges);
}
/**
* Perform upgrade of config.php file.
*
* @param string $currentVersion current core version
* @return object GalleryStatus a status code
*/
function performConfigUpgrade($currentVersion) {
global $gallery;
$platform =& $gallery->getPlatform();
$configFilePath = GALLERY_CONFIG_DIR . '/config.php';
$configContents = implode('', $platform->file($configFilePath));
if (empty($configContents) || strlen($configContents) < 100) {
return GalleryCoreApi::error(ERROR_MISSING_VALUE, __FILE__, __LINE__,
'Unable to read current config.php contents');
}
$configChanges = CoreModuleExtras::_prepareConfigUpgrade($currentVersion);
foreach ($configChanges as $change) {
/* preg_replace $count param is only PHP 5.1.0+ */
foreach ($change['remove'] as $regexp) {
$configContents = preg_replace($regexp, '', $old = $configContents);
if ($configContents == $old) {
$gallery->debug('Warning: config.php remove pattern not matched: ' . $regexp);
}
}
foreach ($change['edit'] as $edit) {
$configContents =
preg_replace($edit['regexp'], $edit['replacement'], $old = $configContents);
if ($configContents == $old) {
$gallery->debug('Warning: config.php edit pattern not matched: ' . $regexp);
}
}
foreach ($change['add'] as $content) {
$configContents =
preg_replace('{\?>\s*\z}', $content . "\n?>\n", $old = $configContents);
if ($configContents == $old) {
$gallery->debug(
'Warning: config.php add pattern not matched, appending to file instead');
$configContents .= "\n" . $content . "\n?>\n";
}
}
}
if (!$out = $platform->fopen($configFilePath, 'w')) {
return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__,
'Unable to write to config.php');
}
if ($platform->fwrite($out, $configContents) < strlen($configContents)) {
return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__,
'Unable to write config.php contents');
}
$platform->fclose($out);
return null;
}
/**
* Create the initial all users group.
*
* @param object GalleryModule $module the core module
* @return object GalleryStatus a status code
*/
function _createAllUsersGroup($module) {
global $gallery;
list ($ret, $id) = $module->getParameter('id.allUserGroup');
if ($ret) {
return $ret;
}
if (!empty($id)) {
return null;
}
GalleryCoreApi::requireOnce('modules/core/classes/GalleryGroup.class');
$group = new GalleryGroup();
$groupName = $module->translate('Registered Users');
$ret = $group->create($groupName, GROUP_ALL_USERS);
if ($ret) {
return $ret;
}
$ret = $group->save();
if ($ret) {
return $ret;
}
$ret = $module->setParameter('id.allUserGroup', $group->getId());
if ($ret) {
return $ret;
}
return null;
}
/**
* Create the site admins group.
*
* @param object GalleryModule $module the core module
* @return object GalleryStatus a status code
*/
function _createSiteAdminsGroup($module) {
global $gallery;
list ($ret, $id) = $module->getParameter('id.adminGroup');
if ($ret) {
return $ret;
}
if (!empty($id)) {
return null;
}
GalleryCoreApi::requireOnce('modules/core/classes/GalleryGroup.class');
$group = new GalleryGroup();
$groupName = $module->translate('Site Admins');
$ret = $group->create($groupName, GROUP_SITE_ADMINS);
if ($ret) {
return $ret;
}
$ret = $group->save();
if ($ret) {
return $ret;
}
$ret = $module->setParameter('id.adminGroup', $group->getId());
if ($ret) {
return $ret;
}
return null;
}
/**
* Create the everybody group.
*
* @param object GalleryModule $module the core module
* @return object GalleryStatus a status code
*/
function _createEverybodyGroup($module) {
global $gallery;
list ($ret, $id) = $module->getParameter('id.everybodyGroup');
if ($ret) {
return $ret;
}
if (!empty($id)) {
return null;
}
GalleryCoreApi::requireOnce('modules/core/classes/GalleryGroup.class');
$group = new GalleryGroup();
$groupName = $module->translate('Everybody');
$ret = $group->create($groupName, GROUP_EVERYBODY);
if ($ret) {
return $ret;
}
$ret = $group->save();
if ($ret) {
return $ret;
}
$ret = $module->setParameter('id.everybodyGroup', $group->getId());
if ($ret) {
return $ret;
}
return null;
}
/**
* Create the initial anonymous user.
*
* @param object GalleryModule $module the core module
* @return object GalleryStatus a status code
*/
function _createAnonymousUser($module) {
global $gallery;
list ($ret, $id) = $module->getParameter('id.anonymousUser');
if ($ret) {
return $ret;
}
if (!empty($id)) {
return null;
}
GalleryCoreApi::requireOnce('modules/core/classes/GalleryUser.class');
$user = new GalleryUser();
$userName = 'guest';
$fullName = $module->translate('Guest');
$ret = $user->create($userName);
if ($ret) {
return $ret;
}
$user->setFullName($fullName);
$user->changePassword('');
$ret = $user->save();
if ($ret) {
return $ret;
}
/* Remove the anonymous user from the Everybody group */
list ($ret, $allUserGroupId) = $module->getParameter('id.allUserGroup');
if ($ret) {
return $ret;
}
$ret = GalleryCoreApi::removeUserFromGroup($user->getId(), $allUserGroupId);
if ($ret) {
return $ret;
}
$ret = $module->setParameter('id.anonymousUser', $user->getId());
if ($ret) {
return $ret;
}
return null;
}
/**
* Create the initial admin user.
*
* @param object GalleryModule $module the core module
* @return object GalleryStatus a status code
*/
function _createAdminUser($module) {
global $gallery;
/* Don't create if there is already a user in the admin group */
list ($ret, $adminGroupId) = $module->getParameter('id.adminGroup');
if ($ret) {
return $ret;
}
list ($ret, $results) = GalleryCoreApi::fetchUsersForGroup($adminGroupId);
if ($ret) {
return $ret;
}
if (sizeof($results) > 0) {
return null;
}
GalleryCoreApi::requireOnce('modules/core/classes/GalleryUser.class');
$user = new GalleryUser();
/*
* Get the admin name and data from the installer and default to 'admin' if it's not
* available for some reason
*/
$userName = $gallery->getConfig('setup.admin.userName');
$userName = !strlen($userName) ? 'admin' : $userName;
$email = $gallery->getConfig('setup.admin.email');
$fullName = $gallery->getConfig('setup.admin.fullName');
$ret = $user->create($userName);
if ($ret) {
return $ret;
}
$user->changePassword($gallery->getConfig('setup.password'));
$user->setFullName($fullName);
$user->setEmail($email);
$ret = $user->save();
if ($ret) {
return $ret;
}
/* Add her to the admin group */
$ret = GalleryCoreApi::addUserToGroup($user->getId(), $adminGroupId);
if ($ret) {
return $ret;
}
/*
* The rest of the bootstrap code won't work so well unless we're logged in, so log in as
* the admin user now
*/
$gallery->setActiveUser($user);
return null;
}
/**
* Create the root album item.
*
* @param object GalleryModule $module the core module
* @return object GalleryStatus a status code
*/
function _createRootAlbumItem($module) {
global $gallery;
/* Do we already have a root? */
list ($ret, $rootAlbumId) = $module->getParameter('id.rootAlbum');
if ($rootAlbumId) {
return null;
}
GalleryCoreApi::requireOnce('modules/core/classes/GalleryAlbumItem.class');
$album = new GalleryAlbumItem();
$ret = $album->createRoot();
if ($ret) {
return $ret;
}
$title = $module->translate('Gallery');
$description = $module->translate('This is the main page of your Gallery');
$album->setTitle($title);
$album->setDescription($description);
$ret = $album->save();
if ($ret) {
return $ret;
}
/* Give everybody some permissions */
list ($ret, $groupId) = $module->getParameter('id.everybodyGroup');
if ($ret) {
return $ret;
}
$ret = GalleryCoreApi::addGroupPermission($album->getId(), $groupId, 'core.viewAll');
if ($ret) {
return $ret;
}
/* Grant admin users everything */
list ($ret, $groupId) = $module->getParameter('id.adminGroup');
if ($ret) {
return $ret;
}
$ret = GalleryCoreApi::addGroupPermission($album->getId(), $groupId, 'core.all');
if ($ret) {
return $ret;
}
$ret = $module->setParameter('id.rootAlbum', $album->getId());
if ($ret) {
return $ret;
}
return null;
}
/**
* Create the access list compactor lock entity.
*
* @param object GalleryModule $module the core module
* @return object GalleryStatus a status code
*/
function _createAccessListCompacterLock($module) {
global $gallery;
/* Do we already have a root? */
list ($ret, $compacterLockId) = $module->getParameter('id.accessListCompacterLock');
if ($compacterLockId) {
return null;
}
GalleryCoreApi::requireOnce('modules/core/classes/GalleryEntity.class');
$lock = new GalleryEntity();
$lock->create();
$ret = $lock->save(false);
if ($ret) {
return $ret;
}
$ret = $module->setParameter('id.accessListCompacterLock', $lock->getId());
if ($ret) {
return $ret;
}
return null;
}
/**
* @see GalleryModule::performFactoryRegistrations
*/
function performFactoryRegistrations($module) {
/* Register all of our factory implementations. */
$regs[] = array('GalleryEntity', 'GalleryEntity', 'class', null);
$regs[] = array('GalleryEntity', 'GalleryChildEntity', 'class', null);
$regs[] = array('GalleryEntity', 'GalleryAlbumItem', 'class', null);
$regs[] = array('GalleryEntity', 'GalleryUser', 'class', null);
$regs[] = array('GalleryEntity', 'GalleryGroup', 'class', null);
$regs[] = array('GalleryEntity', 'GalleryDerivative', 'class', null);
$regs[] = array('GalleryEntity', 'GalleryDerivativeImage', 'class', null);
$regs[] = array('GalleryDerivative', 'GalleryDerivativeImage', 'class', array('*'));
$regs[] = array('GalleryEntity', 'GalleryMovieItem', 'class', null);
$regs[] = array('GalleryEntity', 'GalleryAnimationItem', 'class', null);
$regs[] = array('GalleryEntity', 'GalleryPhotoItem', 'class', null);
$regs[] = array('GalleryEntity', 'GalleryUnknownItem', 'class', null);
$regs[] = array('GalleryItem', 'GalleryPhotoItem', 'class',
array('image/*', 'application/photoshop'));
$regs[] = array('GalleryItem', 'GalleryMovieItem', 'class', array('video/*'));
$regs[] = array('GalleryItem', 'GalleryAnimationItem', 'class',
array('application/x-director', 'application/x-shockwave-flash'));
$regs[] = array('GalleryItem', 'GalleryUnknownItem', 'class', array('*'));
$regs[] = array('GalleryDynamicAlbum', 'GalleryDynamicAlbum', 'class', null);
$regs[] = array('GallerySearchInterface_1_0', 'GalleryCoreSearch', 'class', null);
$regs[] = array('ItemEditPlugin', 'ItemEditItem', 'inc', null, 1);
$regs[] = array('ItemEditPlugin', 'ItemEditAnimation', 'inc', null, 2);
$regs[] = array('ItemEditPlugin', 'ItemEditMovie', 'inc', null, 2);
$regs[] = array('ItemEditPlugin', 'ItemEditAlbum', 'inc', null, 2);
$regs[] = array('ItemEditPlugin', 'ItemEditTheme', 'inc', null, 3);
$regs[] = array('ItemEditPlugin', 'ItemEditPhoto', 'inc', null, 2);
$regs[] = array('ItemEditPlugin', 'ItemEditRotateAndScalePhoto', 'inc', null, 3);
$regs[] = array('ItemEditPlugin', 'ItemEditPhotoThumbnail', 'inc', null, 4);
$regs[] = array('ItemAddPlugin', 'ItemAddFromBrowser', 'inc', null, 2);
$regs[] = array('ItemAddOption', 'CreateThumbnailOption', 'inc', null);
$regs[] = array('MaintenanceTask', 'OptimizeDatabaseTask', 'class', null);
$regs[] = array('MaintenanceTask', 'FlushTemplatesTask', 'class', null);
$regs[] = array('MaintenanceTask', 'FlushDatabaseCacheTask', 'class', null);
$regs[] = array('MaintenanceTask', 'BuildDerivativesTask', 'class', null);
$regs[] = array('MaintenanceTask', 'ResetViewCountsTask', 'class', null);
$regs[] = array('MaintenanceTask', 'SystemInfoTask', 'class', null);
$regs[] = array('MaintenanceTask', 'SetOriginationTimestampTask', 'class', null);
$regs[] = array('MaintenanceTask', 'DeleteSessionsTask', 'class', null);
$regs[] = array('MaintenanceTask', 'ConvertDatabaseToUtf8Task', 'class', null);
$regs[] = array('CaptchaAdminOption', 'CoreCaptchaAdminOption', 'class', null);
/*
* Unlike other modules, the core module doesn't get deactivated so its factory
* registrations may still be around from before. Unregister them now before reregistering
* them all.
*/
/* Unregister all factory implementations */
$ret = GalleryCoreApi::unregisterFactoryImplementationsByModuleId($module->getId());
if ($ret) {
return $ret;
}
foreach ($regs as $entry) {
$ret = GalleryCoreApi::registerFactoryImplementation(
$entry[0], $entry[1], $entry[1],
$entry[2] == 'class' ?
sprintf('modules/core/classes/%s.class', $entry[1]) :
sprintf('modules/core/%s.inc', $entry[1]),
'core', $entry[3], isset($entry[4]) ? (string)$entry[4] : '4');
if ($ret) {
return $ret;
}
}
/* Special cases */
$ret = GalleryCoreApi::registerFactoryImplementation(
'GalleryAuthPlugin', 'SessionAuthPlugin', 'SessionAuthPlugin',
'modules/core/classes/GallerySession.class',
'core', null, 4);
if ($ret) {
return $ret;
}
return null;
}
/**
* Change character set encoding to utf 8 for MySQL if necessary. This is public because it
* is also used by ConvertDatabaseToUtf8Task.
*
* @return array object GalleryStatus a status code
* bool true if any conversions took place
* @access public
*/
function convertCharacterSetToUtf8($module, $statusMonitor) {
global $gallery;
$storage =& $gallery->getStorage();
$converted = false;
if ($storage->getType() == 'mysql') {
$version = $storage->getVersion();
/* MySQL < 4.1.0 does not support UTF8 */
if ($version && version_compare($version, '4.1.0', '>=')) {
/*
* Check if the database uses UTF8 already, by looking at the Schema table, which
* we convert last.
*/
list ($ret, $results) =
$storage->search('SHOW CREATE TABLE `' . $storage->_tablePrefix . 'Schema`');
if ($ret) {
return array($ret, null);
}
$row = $results->nextResult();
$result = $row[1];
if (!$result || !preg_match('/utf8/i', $result)) {
/* Convert all existing tables to UTF-8 */
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Converting MySQL data to UTF8'), null, 0);
if ($ret) {
return array($ret, null);
}
$gallery->guaranteeTimeLimit(120);
$storageExtras =& $storage->_getExtras();
list ($ret, $tableVersions) = $storageExtras->_loadTableVersions();
if ($ret) {
return array($ret, null);
}
$types = array('varchar' => 'varbinary',
'text' => 'blob',
'longtext' => 'longblob');
$i = 0;
foreach ($tableVersions as $tableName => $unused) {
$i++;
$tableName = $storage->_tablePrefix . $tableName;
/* First the table itself */
$query = "ALTER TABLE `$tableName` DEFAULT CHARACTER SET utf8";
$ret = $storage->execute($query);
if ($ret) {
return array($ret, null);
}
/*
* Then all character/string columns
* See: http://dev.mysql.com/doc/refman/4.1/en/charset-conversion.html
*
* The following code is based significantly on code from Drupal,
* For details, refer to:
* - http://api.drupal.org/api/4.7/file/update.php/source
* - http://api.drupal.org/api/4.7/file/LICENSE.txt
* - http://drupal.org/node/40515
*
* Drupal is licensed under the GPL:
*
* 1. Detect current column attributes
* 2. Convert text column to binary column
* 3. Convert them to character/text columns with UTF8 charset
*/
$query = "SHOW FULL COLUMNS FROM `$tableName`";
$originalFetchMode = $storage->_db->SetFetchMode(ADODB_FETCH_ASSOC);
list ($ret, $results) = $storage->search($query);
if ($ret) {
return array($ret, null);
}
$storage->_db->SetFetchMode($originalFetchMode);
$changeToBinary = $changeToUtf8 = array();
while ($column = $results->nextResult()) {
list ($type) = explode('(', $column['Type']);
if (!isset($types[$type])) {
continue;
}
$change =
'CHANGE `' . $column['Field'] . '` `' . $column['Field'] . '` ';
$binaryType = preg_replace('/'. $type .'/i', $types[$type],
$column['Type']);
$attributes = ' ';
if ($column['Default'] == 'NULL') {
$attributes .= 'DEFAULT NULL ';
} else if (!empty($column['Default'])) {
$attributes .= 'DEFAULT ' . $column['Default'] . ' ';
}
$attributes .= $column['Null'] == 'YES' ? 'NULL' : 'NOT NULL';
$changeToBinary[] = $change . $binaryType . $attributes;
$changeToUtf8[] =
$change . $column['Type'] . ' CHARACTER SET utf8' . $attributes;
}
if (count($changeToBinary)) {
$query =
"ALTER TABLE `$tableName` " . implode(', ', $changeToBinary);
$ret = $storage->Execute($query);
if ($ret) {
return array($ret, null);
}
$query = "ALTER TABLE `$tableName` " . implode(', ', $changeToUtf8);
$ret = $storage->Execute($query);
if ($ret) {
return array($ret, null);
}
$converted = true;
}
$ret = $statusMonitor->renderStatusMessage(
$module->translate('Converting MySQL data to UTF8'),
null, $i / count($tableVersions));
if ($ret) {
return array($ret, null);
}
$gallery->guaranteeTimeLimit(120);
} /* End for each table */
if ($converted) {
/* Clear any cache data since it may be in the wrong character set*/
$gallery->guaranteeTimeLimit(60);
$ret = GalleryCoreApi::removeAllMapEntries('GalleryCacheMap');
if ($ret) {
return array($ret, null);
}
}
} /* End if database character set not UTF-8 */
} /* End if MySql version > 4.1.0 */
} /* End if MySQL */
return array(null, $converted);
}
/**
* Sort an associative array where the key is the name of the table. Force
* the schema table to be last in line.
*/
function _sortSchemaTableLast($a, $b) {
if ($a == 'Schema') {
return -1;
} else if ($b == 'Schema') {
return 1;
} else {
return strcmp($a, $b);
}
}
}
?>