*/ /** * Extra, rarely used core module code. Most modules will not need to push * their extra code into a separate class, but the core module has a lot of * install code that is very rarely used so we tuck it out of the way. * * @package GalleryCore * @static */ class CoreModuleExtras { /** * @see GalleryModule::upgrade() * @param object GalleryModule the core module * @param string the current installed version * @static */ 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 get to the final release. It's * only useful in the alpha -> beta transition. */ list ($ret, $paramValue) = $module->getParameter('permissions.directory'); if (isset($paramValue)) { $currentVersion = '0.8'; } else { $currentVersion = '0'; } } if (substr($currentVersion, 0, 6) == '1.0.0.') { /* Enable upgrade from any Gallery 2.0.x version */ $currentVersion = '1.0.0.x'; } /** * 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 configurStore 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 g2 bug id: 1235284. */ $ret = $storage->checkPoint(); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $ret = $statusMonitor->renderStatusMessage( $module->translate('Installing the core module'), '', 0.15); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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', ) 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->wrap(__FILE__, __LINE__); } } } $ret = $statusMonitor->renderStatusMessage( $module->translate('Installing the core module'), '', 0.2); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $gallery->guaranteeTimeLimit(180); /* Activate the Matrix theme */ $gallery->debug('Load Matrix theme'); list ($ret, $theme) = GalleryCoreApi::loadPlugin('theme', 'matrix'); if ($ret) { $gallery->debug(sprintf('Error: Failed to load matrix theme, this is the error ' . 'stack trace; %s', $ret->getAsText())); return $ret->wrap(__FILE__, __LINE__); } $ret = $statusMonitor->renderStatusMessage( $module->translate('Installing the core module'), '', 0.25); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $gallery->guaranteeTimeLimit(180); $gallery->debug('InstallOrUpgrade Matrix theme'); $ret = $theme->installOrUpgrade(); if ($ret) { $gallery->debug(sprintf('Error: Failed to installOrUpgrade matrix theme, this is ' . 'the error stack trace; %s', $ret->getAsText())); return $ret->wrap(__FILE__, __LINE__); } $ret = $statusMonitor->renderStatusMessage( $module->translate('Installing the core module'), '', 0.3); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $gallery->guaranteeTimeLimit(180); $gallery->debug('Activate Matrix theme'); list ($ret, $ignored) = $theme->activate(false); if ($ret) { $gallery->debug(sprintf('Error: Failed to activate matrix theme, this is ' . 'the error stack trace; %s', $ret->getAsText())); return $ret->wrap(__FILE__, __LINE__); } $ret = $statusMonitor->renderStatusMessage( $module->translate('Installing the core module'), '', 0.4); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } } $ret = $statusMonitor->renderStatusMessage( $module->translate('Installing the core module'), '', 0.5); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } } $ret = $statusMonitor->renderStatusMessage( $module->translate('Installing the core module'), '', 0.6); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } $gallery->debug('CoreModulesExtra::upgrade: successfully installed core'); $ret = $statusMonitor->renderStatusMessage( $module->translate('Installing the core module'), '', 0.7); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } $ret = $storage->execute($query, array('_callbacks', 'callbacks')); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } /* Added a new parameter */ $ret = $module->setParameter('misc.login', 'both'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } /* Copy viewedSinceTimestamp to originationTimestamp as both default to time() */ $query = ' UPDATE [GalleryItem] SET [::originationTimestamp] = [::viewedSinceTimestamp] '; $ret = $storage->execute($query, array()); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } case '0.8.6': case '0.8.7': $ret = $module->setParameter('default.newAlbumsUseDefaults', 'false'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } case '0.8.10': case '0.8.11': case '0.8.12': $ret = $module->setParameter('lock.system', 'flock'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } case '0.8.17': /* Beta 1! */ case '0.9.0': $ret = $module->removeParameter('misc.useShortUrls'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } case '0.9.1': /* Set g2 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->wrap(__FILE__, __LINE__); } case '0.9.5': $gallery->guaranteeTimeLimit(30); $ret = CoreModuleExtras::_createAccessListCompacterLock($module); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } /* * 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } } 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $ret = $storage->execute($createAclQuery, array($newAclId, $targetItemId)); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } /* * 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->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } /* Remove all the permission rows for the migrated items */ $query = sprintf($deleteOldPermsQuery, $markers); $ret = $storage->execute($query, $dupeIds); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } } } if ($totalPermissionItems > 0) { $ret = $statusMonitor->renderStatusMessage( $module->translate('Deleting old permission tables'), '', $itemsProcessed / $totalPermissionItems); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } } /* 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->wrap(__FILE__, __LINE__); } 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': /* * 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->wrap(__FILE__, __LINE__); } list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($allUserGroupId); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } list ($ret, $group) = GalleryCoreApi::loadEntitiesById($allUserGroupId); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } $ret = GalleryCoreApi::releaseLocks($lockId); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } } } else { return $ret->wrap(__FILE__, __LINE__); } } /* 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } } } $ret = $module->removeParameter('uploadLocalServer.dirs'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } } 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->wrap(__FILE__, __LINE__); } } 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->wrap(__FILE__, __LINE__); } } case '0.9.25': /* And 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->wrap(__FILE__, __LINE__); } } 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->wrap(__FILE__, __LINE__); } case '0.9.27': /* 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->wrap(__FILE__, __LINE__); } /* 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->wrap(__FILE__, __LINE__); } /* * 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 G2 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->wrap(__FILE__, __LINE__); } $currentDerivativeIds = array_splice($derivativeIds, 0, $loadBatchSize); list ($ret, $derivatives) = GalleryCoreApi::loadEntitiesById($currentDerivativeIds); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } } /* 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->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } if (($size = $platform->filesize($path)) === false) { return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__); } 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, __FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock(array_keys($brokenDerivatives)); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } $gallery->guaranteeTimeLimit(30); } $brokenDerivative->setIsBroken(true); $ret = $brokenDerivative->save(true, false); if ($ret) { GalleryCoreApi::releaseLocks($lockId); return $ret->wrap(__FILE__, __LINE__); } } $brokenDerivatives = array(); $ret = GalleryCoreApi::releaseLocks($lockId); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } } /* * 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->wrap(__FILE__, __LINE__); } $query = ' UPDATE [GalleryPluginParameterMap] SET [::pluginType] = \'theme\' WHERE [GalleryPluginParameterMap::pluginType] = \'layout\' '; $ret = $storage->execute($query); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } /* After this refactor we only support the matrix theme */ $query = ' UPDATE [GalleryAlbumItem] SET [::theme] = \'matrix\' '; $ret = $storage->execute($query); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $query = ' UPDATE [GalleryPluginMap] SET [::pluginType] = \'theme\' WHERE [GalleryPluginMap::pluginType] = \'layout\' '; $ret = $storage->execute($query); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } /* * 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->wrap(__FILE__, __LINE__); } } /* * 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $ret = $theme->installOrUpgrade(); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } } } } 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->wrap(__FILE__, __LINE__); } $ret = $module->setParameter('default.theme', 'matrix'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $ret = $module->removeParameter('default.layout'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $query = ' UPDATE [GalleryAlbumItem] SET [::theme] = NULL '; $ret = $storage->execute($query); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } } 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } case '1.0.1': /* And 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->wrap(__FILE__, __LINE__); } } 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } /* 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->wrap(__FILE__, __LINE__); } } $ret = $storage->configureStore($module->getId(), array('GalleryAccessMap:1.1')); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } list ($ret, $flagModifier) = $storage->getFunctionSql('BITAND', array('[::flags]', '?')); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $query = ' UPDATE [GalleryPermissionSetMap] SET [::flags] = ' . $flagModifier . ' '; $ret = $storage->execute($query, array(3)); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } case '1.0.11': /* Several previous upgrades used 'modules' instead of 'module' with plugin params */ list ($ret, $coreParams) = $module->fetchParameters(); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } foreach (array('misc.useShortUrls', 'language.selector') as $key) { if (isset($coreParams[$key])) { $ret = $module->removeParameter('misc.useShortUrls'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } } } 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->wrap(__FILE__, __LINE__); } } } $ret = GalleryCoreApi::removeMapEntry( 'GalleryPluginParameterMap', array('pluginType' => 'modules')); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } case '1.0.12': /* Add param 'language.useBrowserPref' */ list ($ret, $langCode) = $module->getParameter('default.language'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $useBrowserPref = '0'; if (empty($langCode)) { $useBrowserPref = '1'; $ret = $module->setParameter('default.language', 'en_US'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } } $ret = $module->setParameter('language.useBrowserPref', $useBrowserPref); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $stepSize = min(100, intval($totalDerivatives / 10)); 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->wrap(__FILE__, __LINE__); } } } } case '1.0.16': /* Added 'not-null' to Entities.inc and Map.inc */ $storageExtras =& $storage->_getExtras(); $storageExtras->_clearEntityAndMapCache(); case '1.0.17': /* And 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->wrap(__FILE__, __LINE__); } } case '1.0.18': /* Add index to GalleryEntity::linkId */ $ret = $storage->configureStore($module->getId(), array('GalleryEntity:1.1')); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } case '1.0.20': /* Add configurable captcha security level */ $ret = GalleryCoreApi::setPluginParameter('module', 'core', 'captcha.level', 'MEDIUM'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } } 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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } /* * 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->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $ret = $module->setParameter('validation.level', $level); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $ret = $module->removeParameter('captcha.level'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } case '1.0.25': case '1.0.26': /* 2.1 Release Candidate 1! */ /* Change character set encoding to utf 8 for MySQL if necessary */ if ($storage->getType() == 'mysql') { $version = mysql_get_server_info(); /* MySQL < 4.1.0 does not support UTF8 */ if ($version && version_compare($version, '4.1.0', '>=')) { /* Check if the database uses UTF8 already */ list ($ret, $results) = $storage->search('SHOW CREATE DATABASE `' . $storage->_database . '`'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $row = $results->nextResult(); $result = $row[1]; if (!$result || !preg_match('/utf8/i', $result)) { /* Convert all existing tables to UTF8 */ $ret = $statusMonitor->renderStatusMessage( $module->translate('Converting MySQL data to UTF8'), null, 0); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $gallery->guaranteeTimeLimit(120); $storageExtras =& $storage->_getExtras(); list ($ret, $tableVersions) = $storageExtras->_loadTableVersions(); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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 $ret->wrap(__FILE__, __LINE__); } /* * Then all character / string columns * See: http://dev.mysql.com/doc/refman/4.1/en/charset-conversion.html * and http://drupal.org/node/40515 * 1. Detect current column attributes * 2. Convert text column to binary column * 3. Convert them to character/text columns with UTF8 charset */ /* 1. Detect current column attributes */ $query = "SHOW FULL COLUMNS FROM `$tableName`"; $originalFetchMode = $storage->_db->SetFetchMode(ADODB_FETCH_ASSOC); list ($ret, $results) = $storage->search($query); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $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 $ret->wrap(__FILE__, __LINE__); } $query = "ALTER TABLE `$tableName` " . implode(', ', $changeToUtf8); $ret = $storage->Execute($query); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } } $ret = $statusMonitor->renderStatusMessage( $module->translate('Converting MySQL data to UTF8'), null, $i / count($tableVersions)); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $gallery->guaranteeTimeLimit(120); } /* end for each table */ } /* end if database character set not utf8 */ } /* end if MySql version > 4.1.0 */ } /* end if MySQL */ /* Clear the cache data since we changed the blob encoding */ $gallery->guaranteeTimeLimit(60); $ret = GalleryCoreApi::removeAllMapEntries('GalleryCacheMap'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } case '1.0.31': list ($ret, $params) = GalleryCoreApi::fetchAllPluginParameters('module', 'core'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } } } 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': /* 2.1.1 Bugfix Release */ case '1.1.0.1': /* * 2.1.2 Security Release * 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 '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 current core version * @return array of array('remove' => array of string regexp removals, * 'add' => array of string additions) * @access private * @static */ function _prepareConfigUpgrade($currentVersion) { global $gallery; $configChanges = array(); if (substr($currentVersion, 0, 6) == '1.0.0.') { $currentVersion = '1.0.0.x'; } /** * 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()); /* Note: srand() is required for php versions < 4.2 */ srand(100000 * ((float)$usec + (float)$sec)); $cookieId = substr(md5(rand()), 0, 6); $add[] = ' /* * Set the name for G2 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 G2 installs are running on the same domain (in different paths or * different subdomains) choose cookieId such that it is different for all G2 * 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'*/ $add[] = ' /* * 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\', \'\');'; $configChanges[] = array('remove' => array(), 'add' => $add, 'edit' => array()); 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 */ $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.1': 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 current core version * @return boolean true if change is required * @static */ function isConfigUpgradeRequired($currentVersion) { $configChanges = CoreModuleExtras::_prepareConfigUpgrade($currentVersion); return !empty($configChanges); } /** * Perform upgrade of config.php file. * @param string current core version * @return object GalleryStatus a status code * @static */ 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) { foreach ($change['remove'] as $regexp) { $configContents = preg_replace($regexp, '', $configContents); } foreach ($change['edit'] as $edit) { $configContents = preg_replace($edit['regexp'], $edit['replacement'], $configContents); } foreach ($change['add'] as $content) { $configContents = preg_replace('{\?>\s*\z}', $content . "\n?>\n", $configContents); } } 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 the core module * @return object GalleryStatus a status code * @static */ function _createAllUsersGroup($module) { global $gallery; list ($ret, $id) = $module->getParameter('id.allUserGroup'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $ret = $group->save(); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $ret = $module->setParameter('id.allUserGroup', $group->getId()); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } return null; } /** * Create the Site Admins group * * @param object GalleryModule the core module * @return object GalleryStatus a status code * @static */ function _createSiteAdminsGroup($module) { global $gallery; list ($ret, $id) = $module->getParameter('id.adminGroup'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $ret = $group->save(); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $ret = $module->setParameter('id.adminGroup', $group->getId()); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } return null; } /** * Create the Site Admins group * * @param object GalleryModule the core module * @return object GalleryStatus a status code * @static */ function _createEverybodyGroup($module) { global $gallery; list ($ret, $id) = $module->getParameter('id.everybodyGroup'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $ret = $group->save(); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $ret = $module->setParameter('id.everybodyGroup', $group->getId()); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } return null; } /** * Create the initial Anonymous User * * @param object GalleryModule the core module * @return object GalleryStatus a status code * @static */ function _createAnonymousUser($module) { global $gallery; list ($ret, $id) = $module->getParameter('id.anonymousUser'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $user->setFullName($fullName); $user->changePassword(''); $ret = $user->save(); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } /* Remove the anonymous user from the "all users" group */ list ($ret, $allUserGroupId) = $module->getParameter('id.allUserGroup'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } GalleryCoreApi::removeUserFromGroup($user->getId(), $allUserGroupId); $ret = $module->setParameter('id.anonymousUser', $user->getId()); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } return null; } /** * Create the initial admin user * * @param object GalleryModule the core module * @return object GalleryStatus a status code * @static */ 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->wrap(__FILE__, __LINE__); } list ($ret, $results) = GalleryCoreApi::fetchUsersForGroup($adminGroupId); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } $user->changePassword($gallery->getConfig('setup.password')); $user->setFullName($fullName); $user->setEmail($email); $ret = $user->save(); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } /* Add her to the admin group */ $ret = GalleryCoreApi::addUserToGroup($user->getId(), $adminGroupId); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } /* * 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 the core module * @return object GalleryStatus a status code * @static */ 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->wrap(__FILE__, __LINE__); } $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->wrap(__FILE__, __LINE__); } /* Give everybody some permissions */ list ($ret, $groupId) = $module->getParameter('id.everybodyGroup'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $ret = GalleryCoreApi::addGroupPermission($album->getId(), $groupId, 'core.viewAll'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } /* Grant admin users everything */ list ($ret, $groupId) = $module->getParameter('id.adminGroup'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $ret = GalleryCoreApi::addGroupPermission($album->getId(), $groupId, 'core.all'); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } $ret = $module->setParameter('id.rootAlbum', $album->getId()); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } return null; } /** * Create the access list compactor lock entity * * @param object GalleryModule the core module * @return object GalleryStatus a status code * @static */ 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->wrap(__FILE__, __LINE__); } $ret = $module->setParameter('id.accessListCompacterLock', $lock->getId()); if ($ret) { return $ret->wrap(__FILE__, __LINE__); } 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/*')); $regs[] = array('GalleryItem', 'GalleryMovieItem', 'class', array('video/x-msvideo', 'video/quicktime', 'video/mpeg', 'video/x-ms-asf', 'video/x-ms-wmv')); $regs[] = array('GalleryItem', 'GalleryAnimationItem', 'class', array('application/x-director', 'application/x-shockwave-flash')); $regs[] = array('GalleryItem', 'GalleryUnknownItem', 'class', array('*')); $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('ItemAddPlugin', 'ItemAddFromServer', 'inc', null, 3); $regs[] = array('ItemAddPlugin', 'ItemAddFromWeb', 'inc', null, 4); $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('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->wrap(__FILE__, __LINE__); } 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->wrap(__FILE__, __LINE__); } } return null; } } ?>