1<?php 2/* 3 * Gallery - a web based photo album viewer and editor 4 * Copyright (C) 2000-2008 Bharat Mediratta 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or (at 9 * your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 21/** 22 * Extra, rarely used core module code. Most modules will not need to push their extra code into a 23 * separate class, but the core module has a lot of install code that is very rarely used so we tuck 24 * it out of the way. 25 * 26 * @package GalleryCore 27 * @author Bharat Mediratta <bharat@menalto.com> 28 * @version $Revision: 20996 $ 29 * @static 30 */ 31class CoreModuleExtras { 32 33 /** 34 * @see GalleryModule::upgrade 35 * @param GalleryModule $module the core module 36 * @param string $currentVersion the current installed version 37 */ 38 function upgrade($module, $currentVersion, $statusMonitor) { 39 global $gallery; 40 $storage =& $gallery->getStorage(); 41 $platform =& $gallery->getPlatform(); 42 $gallery->debug('Entering CoreModuleExtras::upgrade'); 43 44 /* 45 * We store our version outside of the database so that we can upgrade even if the database 46 * is in an undependable state 47 */ 48 $versions = $module->getInstalledVersions(); 49 $currentVersion = $versions['core']; 50 if (!isset($currentVersion)) { 51 $gallery->debug('Current version not set'); 52 /* 53 * This is either an initial install or an upgrade from version 0.8 (which didn't have 54 * the core versions.dat file). Use a module parameter as our acid test. 55 * 56 * @todo Get rid of this when we stop supporting upgrades from alphas 57 */ 58 list ($ret, $paramValue) = $module->getParameter('permissions.directory'); 59 if (isset($paramValue)) { 60 $currentVersion = '0.8'; 61 } else { 62 $currentVersion = '0'; 63 } 64 } 65 $gallery->debug('Old version: ' . $currentVersion 66 . ' New version: ' . $module->getVersion()); 67 $currentExactVersion = $currentVersion; 68 /* Enable upgrade from any patch release of earlier versions */ 69 $currentVersion = preg_replace('/^(1\.[0-3]\.0)\.\d+$/', '$1.x', $currentVersion); 70 71 /* 72 * We converted the character set for MySQL to UTF8 in version 1.0.27, but this only 73 * applies if you are running MySQL 4. If you install MySQL 4 after upgrading past 1.0.27 74 * then you'd get stuck with the non-UTF8 character set and you'd get scrambled output. 75 * To remedy this, we check here to see if you're using a version more recent than 1.0.26 76 * and if so, we perform the conversion now. Otherwise, we perform the conversion in-line 77 * in the 1.0.26 upgrade block below. 78 */ 79 if (version_compare($currentVersion, '1.0.26', '>')) { 80 list ($ret, $converted) = 81 CoreModuleExtras::convertCharacterSetToUtf8($module, $statusMonitor); 82 if ($ret) { 83 return $ret; 84 } 85 } 86 87 /* 88 * Store Entities.inc and Maps.inc definitions in the Schema table. Do this upgrade before 89 * the general upgrade code to ensure that all map methods work for the other upgrade code. 90 * (but skip if upgrading from 1.2.0.4 or newer 1.2.0.x, as this upgrade was done in 2.2.2) 91 */ 92 if (version_compare($currentVersion, '1.2.18', '<') && !($currentVersion == '1.2.0.x' 93 && version_compare($currentExactVersion, '1.2.0.4', '>='))) { 94 $ret = $storage->configureStore($module->getId(), array('Schema:1.0', 'Schema:1.1')); 95 if ($ret) { 96 return $ret; 97 } 98 99 list ($ret, $modules) = GalleryCoreApi::fetchPluginStatus('module', true); 100 if ($ret) { 101 return $ret; 102 } 103 104 $count = 1; 105 $total = count($modules); 106 $statusText = $module->translate('Converting Schema Table'); 107 $gallery->guaranteeTimeLimit(30); 108 foreach ($modules as $moduleId => $moduleStatus) { 109 /* Skip uninstalled/unavailable modules */ 110 if (!isset($moduleStatus['active']) || empty($moduleStatus['available'])) { 111 continue; 112 } 113 114 $ret = $storage->updateTableInfo($moduleId); 115 if ($ret) { 116 return $ret; 117 } 118 119 $gallery->guaranteeTimeLimit(30); 120 $ret = $statusMonitor->renderStatusMessage($statusText, '', $count++ / $total); 121 if ($ret) { 122 return $ret; 123 } 124 } 125 $ret = $storage->checkPoint(); 126 if ($ret) { 127 return $ret; 128 } 129 } 130 131 if (version_compare($currentVersion, '1.2.5', '<')) { 132 $ret = $storage->configureStore($module->getId(), array('GalleryMimeTypeMap:1.0')); 133 if ($ret) { 134 return $ret; 135 } 136 } 137 138 /** 139 * README: How to update the block below 140 * 141 * If you add a new feature to the core module and revise the version, you should do the 142 * following. Supposing the current version is 1.0.1 and you're adding 1.0.2. Go to the 143 * end of the switch and find the 'end of upgrade path' case. Create a new case *above* 144 * that one with the old version number. For our example you'd add: "case '1.0.1':" and 145 * then your code. Do *not* put in a break statement. (Update _prepareConfigUpgrade too). 146 */ 147 $gallery->debug(sprintf('The current version is %s', $currentVersion)); 148 $progressText = $module->translate('Installing the core module'); 149 switch ($currentVersion) { 150 case '0': 151 $gallery->debug('Install core module'); 152 /* 153 * Checkpoint (commit configureStore transaction) 154 * Later in the installation code, we create the root album and therefore need locking. 155 * Locks are acquired with a non-transactional db connection. So before we can query 156 * the db with a second connection, the INSERT id into SequenceLock needs to be 157 * committed. Related bug 1235284. 158 */ 159 $ret = $storage->checkPoint(); 160 if ($ret) { 161 return $ret; 162 } 163 164 $ret = $statusMonitor->renderStatusMessage($progressText, '', 0.15); 165 if ($ret) { 166 return $ret; 167 } 168 $gallery->guaranteeTimeLimit(180); 169 170 if (GalleryUtilities::isA($platform, 'WinNtPlatform')) { 171 $flockType = 'database'; 172 } else { 173 $fileToLock = $platform->fopen(__FILE__, 'r'); 174 $wouldBlock = false; 175 if ($platform->flock($fileToLock, LOCK_SH, $wouldBlock) || $wouldBlock) { 176 $flockType = 'flock'; 177 } else { 178 $flockType = 'database'; 179 } 180 $platform->fclose($fileToLock); 181 } 182 $gallery->debug(sprintf('Locktype %s selected', $flockType)); 183 /* Initial install. Make sure all our module parameters are set. */ 184 $gallery->debug('Set core module parameters'); 185 186 GalleryCoreApi::requireOnce('modules/core/classes/GalleryTranslator.class'); 187 list ($ret, $defaultLanguage) = $gallery->getActiveLanguageCode(); 188 if ($ret) { 189 $defaultLanguage = GalleryTranslator::getLanguageCodeFromRequest(); 190 } 191 foreach (array('permissions.directory' => '0755', 192 'permissions.file' => '0644', 193 'exec.expectedStatus' => '0', 194 'exec.beNice' => '0', 195 'default.orderBy' => 'orderWeight', 196 'default.orderDirection' => '1', 197 'default.theme' => 'matrix', 198 'default.language' => $defaultLanguage, 199 'language.useBrowserPref' => '0', 200 'default.newAlbumsUseDefaults' => 'false', 201 'session.lifetime' => 21 * 86400, /* Three weeks */ 202 'session.inactivityTimeout' => 7 * 86400, /* One week */ 203 'session.siteAdministrationTimeout' => 30 * 60, /* 30 minutes */ 204 'misc.markup' => 'bbcode', 205 'lock.system' => $flockType, 206 'format.date' => '%x', 207 'format.time' => '%X', 208 'format.datetime' => '%c', 209 'repository.updateTime' => '0', 210 'acceleration' => serialize(array('guest' => array('type' => 'none'), 211 'user' => array('type' => 'none'))), 212 'smarty.compile_check' => '0', 213 'validation.level' => 'MEDIUM', 214 'core.repositories' => serialize(array('released' => 1)), 215 ) as $key => $value) { 216 if (!isset($param[$key])) { 217 $ret = $module->setParameter($key, (string)$value); 218 if ($ret) { 219 $gallery->debug(sprintf('Error: Failed to set core module parameter %s, ' . 220 'this is the error stack trace: %s', $key, 221 $ret->getAsText())); 222 return $ret; 223 } 224 } 225 } 226 227 $ret = $statusMonitor->renderStatusMessage($progressText, '', 0.2); 228 if ($ret) { 229 return $ret; 230 } 231 $gallery->guaranteeTimeLimit(180); 232 233 /* Activate the default theme */ 234 $gallery->debug('Load default theme'); 235 list ($ret, $themeList) = GalleryCoreApi::fetchPluginStatus('theme'); 236 if ($ret) { 237 return $ret; 238 } 239 $defaultThemeId = 'matrix'; 240 if (empty($themeList[$defaultThemeId]['available'])) { 241 $gallery->debug(sprintf('Warning: %s theme is not available. Trying to fall ' . 242 'back to another theme.', $defaultThemeId)); 243 $defaultThemeId = null; 244 foreach ($themeList as $themeId => $themeInfo) { 245 if (!empty($themeInfo['available'])) { 246 $defaultThemeId = $themeId; 247 break; 248 } 249 } 250 if (empty($defaultThemeId)) { 251 return GalleryCoreApi::error(ERROR_UNKNOWN, __FILE__, __LINE__, 252 'There is no theme available!'); 253 } 254 $ret = $module->setParameter('default.theme', $defaultThemeId); 255 if ($ret) { 256 return $ret; 257 } 258 } 259 $gallery->debug(sprintf('Using %s as default theme', $defaultThemeId)); 260 261 list ($ret, $theme) = GalleryCoreApi::loadPlugin('theme', $defaultThemeId); 262 if ($ret) { 263 $gallery->debug(sprintf('Error: Failed to load %s theme, this is the error ' . 264 'stack trace; %s', $defaultThemeId, $ret->getAsText())); 265 return $ret; 266 } 267 268 $ret = $statusMonitor->renderStatusMessage($progressText, '', 0.25); 269 if ($ret) { 270 return $ret; 271 } 272 $gallery->guaranteeTimeLimit(180); 273 274 $gallery->debug('InstallOrUpgrade default theme'); 275 $ret = $theme->installOrUpgrade(); 276 if ($ret) { 277 $gallery->debug(sprintf('Error: Failed to installOrUpgrade %s theme, this is ' . 278 'the error stack trace; %s', $defaultThemeId, $ret->getAsText())); 279 return $ret; 280 } 281 282 $ret = $statusMonitor->renderStatusMessage($progressText, '', 0.3); 283 if ($ret) { 284 return $ret; 285 } 286 $gallery->guaranteeTimeLimit(180); 287 288 $gallery->debug('Activate default theme'); 289 list ($ret, $ignored) = $theme->activate(false); 290 if ($ret) { 291 $gallery->debug(sprintf('Error: Failed to activate %s theme, this is ' . 292 'the error stack trace; %s', $defaultThemeId, $ret->getAsText())); 293 return $ret; 294 } 295 296 $ret = $statusMonitor->renderStatusMessage($progressText, '', 0.4); 297 if ($ret) { 298 return $ret; 299 } 300 $gallery->guaranteeTimeLimit(180); 301 302 /* 303 * Register our permissions. Since we're storing internationalized strings in the 304 * database, we have to give our internationalized string extractor a clue that these 305 * strings get translated. So put a line like this translate('key') in for each 306 * description so that our extractor can find it. 307 */ 308 $gallery->debug('Register core module permissions'); 309 $permissions[] = array('all', $gallery->i18n('All access'), 310 GALLERY_PERMISSION_ALL_ACCESS, array()); 311 $permissions[] = array('view', $gallery->i18n('[core] View item'), 0, array()); 312 $permissions[] = array('viewResizes', $gallery->i18n('[core] View resized version(s)'), 313 0, array()); 314 $permissions[] = array('viewSource', $gallery->i18n('[core] View original version'), 315 0, array()); 316 $permissions[] = array('viewAll', $gallery->i18n('[core] View all versions'), 317 GALLERY_PERMISSION_COMPOSITE, 318 array('core.view', 'core.viewResizes', 'core.viewSource')); 319 $permissions[] = array('addAlbumItem', $gallery->i18n('[core] Add sub-album'), 320 0, array()); 321 $permissions[] = array('addDataItem', $gallery->i18n('[core] Add sub-item'), 322 0, array()); 323 $permissions[] = array('edit', $gallery->i18n('[core] Edit item'), 0, array()); 324 $permissions[] = array('changePermissions', 325 $gallery->i18n('[core] Change item permissions'), 0, array()); 326 $permissions[] = array('delete', $gallery->i18n('[core] Delete item'), 0, array()); 327 foreach ($permissions as $p) { 328 $ret = GalleryCoreApi::registerPermission( 329 $module->getId(), 'core.' . $p[0], $p[1], $p[2], $p[3]); 330 if ($ret) { 331 $gallery->debug(sprintf('Error: Failed to register a permission, ' . 332 'this is the error stack trace: %s', 333 $ret->getAsText())); 334 return $ret; 335 } 336 } 337 338 $ret = $statusMonitor->renderStatusMessage($progressText, '', 0.5); 339 if ($ret) { 340 return $ret; 341 } 342 $gallery->guaranteeTimeLimit(180); 343 344 foreach (array('_createAccessListCompacterLock', 345 '_createAllUsersGroup', 346 '_createSiteAdminsGroup', 347 '_createEverybodyGroup', 348 '_createAnonymousUser', 349 '_createAdminUser', 350 '_createRootAlbumItem') as $func) { 351 352 $gallery->debug(sprintf('Call user func %s', $func)); 353 $ret = call_user_func(array('CoreModuleExtras', $func), $module); 354 if ($ret) { 355 $gallery->debug(sprintf('Error: %s returned an error, ' . 356 'this is the error stack trace: %s', $func, 357 $ret->getAsText())); 358 return $ret; 359 } 360 } 361 362 $ret = $statusMonitor->renderStatusMessage($progressText, '', 0.6); 363 if ($ret) { 364 return $ret; 365 } 366 $gallery->guaranteeTimeLimit(180); 367 368 $gallery->debug('Initialize MIME types'); 369 GalleryCoreApi::requireOnce( 370 'modules/core/classes/helpers/GalleryMimeTypeHelper_advanced.class'); 371 $ret = GalleryMimeTypeHelper_advanced::initializeMimeTypes(); 372 if ($ret) { 373 $gallery->debug(sprintf('Error: Failed to initialize MIME types, this is ' . 374 'the error stack trace: %s', $ret->getAsText())); 375 return $ret; 376 } 377 $gallery->debug('CoreModulesExtra::upgrade: successfully installed core'); 378 379 $ret = $statusMonitor->renderStatusMessage($progressText, '', 0.7); 380 if ($ret) { 381 return $ret; 382 } 383 $gallery->guaranteeTimeLimit(180); 384 break; 385 386 case '0.8': 387 $gallery->debug('Warning: Upgrading from version 0.8 (not supported)'); 388 case '0.8.1': 389 case '0.8.2': 390 /* 391 * Update our framework module parameters to have a leading underscore so that we have 392 * our own separate namespace 393 */ 394 $query = ' 395 UPDATE 396 [GalleryPluginParameterMap] 397 SET 398 [::parameterName] = ? 399 WHERE 400 [GalleryPluginParameterMap::parameterName] = ? 401 AND 402 [GalleryPluginParameterMap::pluginType] = \'module\' 403 AND 404 [GalleryPluginParameterMap::itemId] = 0 405 '; 406 $ret = $storage->execute($query, array('_version', 'version')); 407 if ($ret) { 408 return $ret; 409 } 410 411 $ret = $storage->execute($query, array('_callbacks', 'callbacks')); 412 if ($ret) { 413 return $ret; 414 } 415 416 /* Added a new parameter */ 417 $ret = $module->setParameter('misc.login', 'both'); 418 if ($ret) { 419 return $ret; 420 } 421 422 case '0.8.3': 423 case '0.8.4': 424 case '0.8.5': 425 /* Added GalleryItem::originationTimestamp */ 426 $ret = $storage->configureStore($module->getId(), array('GalleryItem:1.0')); 427 if ($ret) { 428 return $ret; 429 } 430 431 /* Copy viewedSinceTimestamp to originationTimestamp as both default to time() */ 432 $query = ' 433 UPDATE 434 [GalleryItem] 435 SET 436 [::originationTimestamp] = [::viewedSinceTimestamp] 437 '; 438 $ret = $storage->execute($query, array()); 439 if ($ret) { 440 return $ret; 441 } 442 443 case '0.8.6': 444 case '0.8.7': 445 $ret = $module->setParameter('default.newAlbumsUseDefaults', 'false'); 446 if ($ret) { 447 return $ret; 448 } 449 450 case '0.8.8': 451 /* 452 * This was not originally part of the 0.8.9 upgrade, but added much later. Upgrade 453 * code after this will need valid factory registrations so we can't wait until 454 * upgrade() completes to register during reactivate(). 455 */ 456 $ret = CoreModuleExtras::performFactoryRegistrations($module); 457 if ($ret) { 458 return $ret; 459 } 460 461 case '0.8.9': 462 /* 463 * Set all factory implementation weights to 5. We'll re-register all core 464 * implementations with a weight of 4 so that they get precedence. 465 */ 466 $query = 'UPDATE [GalleryFactoryMap] SET [::orderWeight] = 5'; 467 $ret = $storage->execute($query, array()); 468 if ($ret) { 469 return $ret; 470 } 471 472 case '0.8.10': 473 case '0.8.11': 474 case '0.8.12': 475 $ret = $module->setParameter('lock.system', 'flock'); 476 if ($ret) { 477 return $ret; 478 } 479 480 case '0.8.13': 481 /* We used to add layout versioning here. Now that's been moved to the 0.9.29 block. */ 482 483 case '0.8.14': 484 /* Added Entity::onLoadHandlers; default all values to null */ 485 $ret = $storage->configureStore($module->getId(), array('GalleryEntity:1.0')); 486 if ($ret) { 487 return $ret; 488 } 489 490 case '0.8.15': 491 /* Removed GalleryItemPropertiesMap */ 492 493 case '0.8.16': 494 /* Schema updates: GalleryPluginMap, GalleryPluginParameterMap, GalleryGroup */ 495 $ret = $storage->configureStore($module->getId(), 496 array('GalleryPluginMap:1.0', 'GalleryPluginParameterMap:1.0', 'GalleryGroup:1.0')); 497 if ($ret) { 498 return $ret; 499 } 500 501 case '0.8.17': 502 /* Beta 1! */ 503 504 case '0.9.0': 505 $ret = $module->removeParameter('misc.useShortUrls'); 506 if ($ret) { 507 return $ret; 508 } 509 510 case '0.9.1': 511 /* Set Gallery version to 2.0-beta-1+ */ 512 513 case '0.9.2': 514 /* Changed the data cache format */ 515 516 case '0.9.3': 517 /* CSS refactor across entire app */ 518 519 case '0.9.4': 520 $gallery->guaranteeTimeLimit(30); 521 GalleryCoreApi::requireOnce( 522 'modules/core/classes/helpers/GalleryMimeTypeHelper_advanced.class'); 523 $ret = GalleryMimeTypeHelper_advanced::initializeMimeTypes(); 524 if ($ret) { 525 return $ret; 526 } 527 528 case '0.9.5': 529 $gallery->guaranteeTimeLimit(30); 530 $ret = CoreModuleExtras::_createAccessListCompacterLock($module); 531 if ($ret) { 532 return $ret; 533 } 534 535 /* 536 * Choose an item that has permission rows. Find all other items with the same exact 537 * permissions. Create a new ACL, assign all those items to the ACL, delete those rows 538 * from the permissions table. Repeat. 539 */ 540 $totalRowsQuery = ' 541 SELECT 542 COUNT(DISTINCT [GalleryPermissionMap::itemId]) 543 FROM 544 [GalleryPermissionMap] 545 '; 546 547 $findItemIdQuery = ' 548 SELECT 549 [GalleryPermissionMap::itemId], COUNT(*) AS C 550 FROM 551 [GalleryPermissionMap] 552 GROUP BY 553 [GalleryPermissionMap::itemId] 554 ORDER BY 555 C DESC 556 '; 557 558 $permissionRowCountQuery = ' 559 SELECT 560 COUNT(*) 561 FROM 562 [GalleryPermissionMap] 563 WHERE 564 [GalleryPermissionMap::itemId] = ? 565 '; 566 567 /* Updated this query for core 1.0.11 to write to userOrGroupId column */ 568 $createAclQuery = ' 569 INSERT INTO 570 [GalleryAccessMap] ([::accessListId], [::userOrGroupId], [::permission]) 571 SELECT 572 ?, 573 [GalleryPermissionMap::userId] + [GalleryPermissionMap::groupId], 574 [GalleryPermissionMap::permission] 575 FROM 576 [GalleryPermissionMap] 577 WHERE 578 [GalleryPermissionMap::itemId] = ? 579 '; 580 581 $findPossibleDupesQuery = ' 582 SELECT 583 [GalleryPermissionMap=2::itemId], COUNT(*) 584 FROM 585 [GalleryPermissionMap=1], [GalleryPermissionMap=2] 586 WHERE 587 [GalleryPermissionMap=1::itemId] = ? 588 AND 589 [GalleryPermissionMap=1::userId] = [GalleryPermissionMap=2::userId] 590 AND 591 [GalleryPermissionMap=1::groupId] = [GalleryPermissionMap=2::groupId] 592 AND 593 [GalleryPermissionMap=1::permission] = [GalleryPermissionMap=2::permission] 594 GROUP BY 595 [GalleryPermissionMap=2::itemId] 596 HAVING 597 COUNT(*) = ? 598 '; 599 600 $refineDupesQuery = ' 601 SELECT 602 [GalleryPermissionMap::itemId], COUNT(*) 603 FROM 604 [GalleryPermissionMap] 605 WHERE 606 [GalleryPermissionMap::itemId] IN (%s) 607 GROUP BY 608 [GalleryPermissionMap::itemId] 609 HAVING 610 COUNT(*) = ? 611 '; 612 613 $assignAclQuery = ' 614 INSERT INTO 615 [GalleryAccessSubscriberMap] ([::itemId], [::accessListId]) 616 SELECT DISTINCT 617 [GalleryPermissionMap::itemId], ? 618 FROM 619 [GalleryPermissionMap] 620 WHERE 621 [GalleryPermissionMap::itemId] IN (%s) 622 '; 623 624 $deleteOldPermsQuery = ' 625 DELETE FROM 626 [GalleryPermissionMap] 627 WHERE 628 [GalleryPermissionMap::itemId] IN (%s) 629 '; 630 631 /* Determine how many items we are going to process for our status message */ 632 list ($ret, $results) = 633 $gallery->search($totalRowsQuery, array(), array('limit' => array('count' => 1))); 634 if ($ret) { 635 return $ret; 636 } 637 if ($results->resultCount() == 0) { 638 break; 639 } 640 $result = $results->nextResult(); 641 $totalPermissionItems = $result[0]; 642 643 $itemsProcessed = 0; 644 if ($totalPermissionItems > 0) { 645 $ret = $statusMonitor->renderStatusMessage( 646 $module->translate('Upgrading permissions'), 647 null, 648 $itemsProcessed / $totalPermissionItems); 649 if ($ret) { 650 return $ret; 651 } 652 } 653 654 while ($totalPermissionItems > 0 && true) { 655 $gallery->guaranteeTimeLimit(60); 656 657 /* Find the next item in the permissions table */ 658 list ($ret, $results) = $storage->search($findItemIdQuery); 659 if ($ret) { 660 return $ret; 661 } 662 if ($results->resultCount() == 0) { 663 break; 664 } 665 $result = $results->nextResult(); 666 list ($targetItemId, $permissionRowCount) = array((int)$result[0], (int)$result[1]); 667 668 /* Create a new ACL */ 669 list ($ret, $newAclId) = $storage->getUniqueId(); 670 if ($ret) { 671 return $ret; 672 } 673 674 $ret = $storage->execute($createAclQuery, array($newAclId, $targetItemId)); 675 if ($ret) { 676 return $ret; 677 } 678 679 /* 680 * Find all items that share the same permissions as the target. I haven't figured 681 * out a good way to do aggregation without using temporary tables, which I'd like 682 * to avoid for portability. So, figure out how many rows have at least as many 683 * matching permissions as our target item. These are potentially dupes. We'll 684 * refine them later on. 685 */ 686 list ($ret, $results) = $gallery->search( 687 $findPossibleDupesQuery, array($targetItemId, $permissionRowCount)); 688 if ($ret) { 689 return $ret; 690 } 691 $possibleDupeIds = array(); 692 while ($result = $results->nextResult()) { 693 $possibleDupeIds[] = (int)$result[0]; 694 } 695 696 /* 697 * Process these queries in chunks since we may have thousands of items with the 698 * same permissions and we don't want to give the database a heart attack 699 */ 700 $chunkSize = 200; 701 while (!empty($possibleDupeIds)) { 702 $chunk = array_splice($possibleDupeIds, 0, $chunkSize); 703 $count = count($chunk); 704 705 /* 706 * Refine our dupes by eliminating ones that don't have exactly the same number 707 * of permission rows as our target. Our target item is included in the dupes, 708 * so this will always return at least 1 row. 709 */ 710 $markers = GalleryUtilities::makeMarkers($count); 711 $query = sprintf($refineDupesQuery, $markers); 712 list ($ret, $results) = $gallery->search( 713 $query, array_merge($chunk, array($permissionRowCount))); 714 $possibleDupeIds = array(); 715 716 $dupeIds = array(); 717 while ($result = $results->nextResult()) { 718 $dupeIds[] = (int)$result[0]; 719 } 720 721 if (empty($dupeIds)) { 722 /* No actual dupes? Try the next chunk. */ 723 continue; 724 } 725 726 $count = count($dupeIds); 727 $markers = GalleryUtilities::makeMarkers($count); 728 729 /* Set all the dupe items in this chunk to use the new ACL */ 730 $query = sprintf($assignAclQuery, $markers); 731 $ret = $storage->execute($query, array_merge(array($newAclId), $dupeIds)); 732 if ($ret) { 733 return $ret; 734 } 735 736 /* Remove all the permission rows for the migrated items */ 737 $query = sprintf($deleteOldPermsQuery, $markers); 738 $ret = $storage->execute($query, $dupeIds); 739 if ($ret) { 740 return $ret; 741 } 742 743 $itemsProcessed += $count; 744 745 $ret = $statusMonitor->renderStatusMessage( 746 $module->translate(array( 747 'text' => 'Upgrading permissions (%d items complete, %d remaining)', 748 'arg1' => $itemsProcessed, 749 'arg2' => $totalPermissionItems - $itemsProcessed)), 750 '', 751 $itemsProcessed / $totalPermissionItems); 752 if ($ret) { 753 return $ret; 754 } 755 } 756 } 757 758 if ($totalPermissionItems > 0) { 759 $ret = $statusMonitor->renderStatusMessage( 760 $module->translate('Deleting old permission tables'), 761 '', 762 $itemsProcessed / $totalPermissionItems); 763 if ($ret) { 764 return $ret; 765 } 766 } 767 768 /* Removed GalleryPermissionMap */ 769 770 case '0.9.6': 771 /* Added GalleryMaintenance table */ 772 773 case '0.9.7': 774 /* 775 * Change GalleryMaintenance::details column to be a serialized array. The old data is 776 * transient so just delete it. Added FlushTemplatesTask, FlushDatabaseCacheTask. 777 */ 778 $gallery->guaranteeTimeLimit(30); 779 $ret = GalleryCoreApi::removeAllMapEntries('GalleryMaintenanceMap'); 780 if ($ret) { 781 return $ret; 782 } 783 784 case '0.9.8': 785 /* 786 * Create 'plugins' and 'plugins_data' directories in g2data. Remove trailing slash for 787 * config paths using substr so file_exists can detect either file or dir. Update: in 788 * core 1.0.6 the data.gallery.plugins dir moved under gallery2 basedir, not in g2data 789 * anymore; we may not have permission to create a dir here. So code below is now 790 * updated to not require those mkdirs to succeed. 791 */ 792 $gallery->guaranteeTimeLimit(30); 793 foreach (array(substr($gallery->getConfig('data.gallery.plugins'), 0, -1) => false, 794 $gallery->getConfig('data.gallery.plugins') . 'modules' => false, 795 $gallery->getConfig('data.gallery.plugins') . 'layouts' => false, 796 substr($gallery->getConfig('data.gallery.plugins_data'), 0, -1) => true, 797 $gallery->getConfig('data.gallery.plugins_data') . 'modules' => true, 798 $gallery->getConfig('data.gallery.plugins_data') . 'layouts' => true) 799 as $dir => $isRequired) { 800 if ($platform->file_exists($dir)) { 801 if ($platform->is_dir($dir)) { 802 /* No need to do anything. Except maybe we could check permissions here. */ 803 } else { 804 /* There's a file there. There shouldn't be. Move it out of the way. */ 805 if (!@$platform->rename($newDir, "$newDir.old") || 806 !@$platform->mkdir($dir)) { 807 return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__, 808 "$dir already exists; unable to replace it"); 809 } 810 } 811 } else { 812 if (!@$platform->mkdir($dir) && $isRequired) { 813 return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__, 814 "Unable to create $dir"); 815 } 816 } 817 } 818 819 case '0.9.9': 820 /* Beta 2 release! */ 821 822 case '0.9.10': 823 /* Added BuildDerivativesTask */ 824 825 case '0.9.11': 826 /* Added GalleryRecoverPasswordMap */ 827 828 case '0.9.12': 829 /* Added ResetViewCountsTask */ 830 831 case '0.9.13': 832 /* Added SystemInfoTask */ 833 834 case '0.9.14': 835 /* Added SetOriginationTimestampTask */ 836 837 case '0.9.15': 838 /* Remove lock subdirs -- this is from 1.1.8->1.1.9 upgrade */ 839 $locksDir = $gallery->getConfig('data.gallery.locks'); 840 if ($platform->file_exists($locksDir)) { 841 @$platform->recursiveRmDir($locksDir); 842 } 843 @$platform->mkdir($locksDir); 844 845 /* 846 * Changed 'All Users' to 'Registered Users' 847 * Don't change if the user modified the name already! 848 * Don't change if there is already a group with the new name 849 */ 850 list ($ret, $group) = 851 GalleryCoreApi::fetchGroupByGroupName($module->translate('Registered Users')); 852 if ($ret) { 853 if ($ret->getErrorCode() & ERROR_MISSING_OBJECT) { 854 /* OK, we can change the group name */ 855 856 list ($ret, $allUserGroupId) = $module->getParameter('id.allUserGroup'); 857 if ($ret) { 858 return $ret; 859 } 860 list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($allUserGroupId); 861 if ($ret) { 862 return $ret; 863 } 864 list ($ret, $group) = 865 GalleryCoreApi::loadEntitiesById($allUserGroupId, 'GalleryGroup'); 866 if ($ret) { 867 return $ret; 868 } 869 $allUserGroupName = $group->getGroupName(); 870 /* We used to entitize data in db; expect that from orignal group name: */ 871 $originalGroupName = GalleryUtilities::utf8ToUnicodeEntities( 872 $module->translate('All Users')); 873 if (!strcmp($allUserGroupName, $originalGroupName)) { 874 $group->setGroupName($module->translate('Registered Users')); 875 $ret = $group->save(); 876 if ($ret) { 877 return $ret; 878 } 879 880 $ret = GalleryCoreApi::releaseLocks($lockId); 881 if ($ret) { 882 return $ret; 883 } 884 } 885 } else { 886 return $ret; 887 } 888 } /* Else a group with that name already exists, nothing to do */ 889 890 case '0.9.16': 891 /* Beta 3 release! */ 892 893 case '0.9.17': 894 /* Split uploadLocalServer.dirs list into one parameter per entry */ 895 list ($ret, $dirList) = $module->getParameter('uploadLocalServer.dirs'); 896 if ($ret) { 897 return $ret; 898 } 899 if (!empty($dirList)) { 900 $dirList = explode(',', $dirList); 901 for ($i = 1; $i <= count($dirList); $i++) { 902 $ret = $module->setParameter('uploadLocalServer.dir.' . $i, $dirList[$i - 1]); 903 if ($ret) { 904 return $ret; 905 } 906 } 907 } 908 $ret = $module->removeParameter('uploadLocalServer.dirs'); 909 if ($ret) { 910 return $ret; 911 } 912 913 case '0.9.18': 914 /* Add image/x-photo-cd mime type */ 915 list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('pcd'); 916 if (!$ret && $mimeType == 'application/unknown') { 917 $ret = GalleryCoreApi::addMimeType('pcd', 'image/x-photo-cd', false); 918 if ($ret) { 919 return $ret; 920 } 921 } 922 923 case '0.9.19': 924 /* New multisite system and support for config.php upgrades */ 925 926 case '0.9.20': 927 /* Change view/controller separator: core:ShowItem -> core.ShowItem */ 928 case '0.9.21': 929 /* Session cookie change, requires new config.php variable */ 930 931 case '0.9.22': 932 /* GalleryModule::getItemLinks API change (GalleryModule API bumped to 0.13) */ 933 934 case '0.9.23': 935 /* Session cookie change, revert the last change and try something new */ 936 foreach (array('cookie.path', 'cookie.domain') as $parameterName) { 937 $ret = $module->setParameter($parameterName, ''); 938 if ($ret) { 939 return $ret; 940 } 941 } 942 943 case '0.9.24': 944 /* Add image/jpeg-cmyk mime type */ 945 list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('jpgcmyk'); 946 if (!$ret && $mimeType == 'application/unknown') { 947 $ret = GalleryCoreApi::addMimeType('jpgcmyk', 'image/jpeg-cmyk', false); 948 if ($ret) { 949 return $ret; 950 } 951 } 952 case '0.9.25': 953 /* Add image/tiff-cmyk mime type */ 954 list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('tifcmyk'); 955 if (!$ret && $mimeType == 'application/unknown') { 956 $ret = GalleryCoreApi::addMimeType('tifcmyk', 'image/tiff-cmyk', false); 957 if ($ret) { 958 return $ret; 959 } 960 } 961 case '0.9.26': 962 /* Added GalleryDerivative::isBroken; default all values to null */ 963 $ret = $storage->configureStore($module->getId(), array('GalleryDerivative:1.0')); 964 if ($ret) { 965 return $ret; 966 } 967 968 case '0.9.27': 969 /* Remove lock subdirs -- this is from 1.1.8->1.1.9 upgrade */ 970 $locksDir = $gallery->getConfig('data.gallery.locks'); 971 if ($platform->file_exists($locksDir)) { 972 @$platform->recursiveRmDir($locksDir); 973 } 974 @$platform->mkdir($locksDir); 975 976 /* Mark old broken derivatives as such with our new isBroken flag */ 977 /* 978 * This is the filesize and the crc32 checksum of the broken derivative placeholder 979 * image that we used in beta 3 and earlier versions. We may have replaced this image 980 * by the time this upgrade code is run. Thus we hardcode filesize(oldImage) and 981 * crc32(oldImageData) here. 982 */ 983 $referenceSize = 1589; 984 /* CRC is a good measure to compare files (not to detect malicous attacks though) */ 985 $referenceCrc = 888290220; 986 987 /* 988 * 1. Get a list of all derivatives that are not already marked as isBroken 989 * (We can't count on derivativeSize being correct, so check all derivatives) 990 * Update: upgrade from pre-beta-1 will fail to load RandomHighlightDerivativeImage 991 * so restrict this query to only GalleryDerivativeImage 992 */ 993 $gallery->guaranteeTimeLimit(60); 994 $query = 'SELECT [GalleryDerivative::id] 995 FROM [GalleryDerivative], [GalleryEntity] 996 WHERE [GalleryDerivative::isBroken] IS NULL 997 AND [GalleryDerivative::id] = [GalleryEntity::id] 998 AND [GalleryEntity::entityType] = \'GalleryDerviativeImage\''; 999 list ($ret, $searchResults) = $gallery->search($query); 1000 if ($ret) { 1001 return $ret; 1002 } 1003 1004 /* Check the derivatives that match the search criteria */ 1005 if ($searchResults->resultCount() > 0) { 1006 $derivativeIds = array(); 1007 while ($result = $searchResults->nextResult()) { 1008 $derivativeIds[] = $result[0]; 1009 } 1010 $totalDerivatives = sizeof($derivativeIds); 1011 1012 /* 1013 * The following process is very expensive. We have to deal with a potentially huge 1014 * (10^6) amount of derivatives. To not exceed the memory limit we do everything in 1015 * batches. To not exceed the PHP execution time limit and to not exceed the apache 1016 * timeout we add a progress bar and manipulate the PHP execution time limit 1017 * periodically. 1018 */ 1019 $gallery->guaranteeTimeLimit(60); 1020 1021 /* Show a progress bar */ 1022 $ret = $statusMonitor->renderStatusMessage( 1023 $module->translate('Detecting broken derivatives'), '', 0); 1024 if ($ret) { 1025 return $ret; 1026 } 1027 1028 /* 1029 * The outer loop is for each derivativeId and we upgrade a progress bar every 1030 * $progressStepSize ids. We don't load entity by entity, but in batches of 1031 * $loadBatchSize. And we don't save the items that were detected as broken 1032 * derivatives one by one, but also in batches of $saveBatchSize, i.e. we acquire 1033 * and release the locks in this batch size, but still have to save entity by entity 1034 * because Gallery has no mass entity save like loadEntitiesById(). 1035 */ 1036 $derivatives = array(); 1037 $progressStepSize = min(500, intval($totalDerivatives / 10)); 1038 $loadBatchSize = 1000; 1039 $saveBatchSize = 1000; 1040 $itemsProcessed = 0; 1041 $brokenDerivatives = array(); 1042 do { 1043 /* 2. Load the entities in batches */ 1044 if (empty($derivatives) && !empty($derivativeIds)) { 1045 /* Prevent PHP timeout */ 1046 $gallery->guaranteeTimeLimit(60); 1047 /* Prevent apache timeout */ 1048 $ret = $statusMonitor->renderStatusMessage( 1049 $module->translate( 1050 array('text' => 'Detecting broken derivatives, loading ' 1051 . '(%d derivatives checked, %d remaining)', 1052 'arg1' => $itemsProcessed, 1053 'arg2' => sizeof($derivativeIds))), 1054 '', $itemsProcessed / $totalDerivatives); 1055 if ($ret) { 1056 return $ret; 1057 } 1058 1059 $currentDerivativeIds = array_splice($derivativeIds, 0, $loadBatchSize); 1060 list ($ret, $derivatives) = 1061 GalleryCoreApi::loadEntitiesById($currentDerivativeIds, 1062 'GalleryDerivative'); 1063 if ($ret) { 1064 return $ret; 1065 } 1066 } 1067 1068 /* Detect if the derivative is broken */ 1069 if (!empty($derivatives)) { 1070 $itemsProcessed++; 1071 $gallery->guaranteeTimeLimit(30); 1072 $derivative = array_pop($derivatives); 1073 1074 /* 1075 * Show the progress, but not for each derivative, this would slow down the 1076 * process considerably 1077 */ 1078 if ($itemsProcessed % $progressStepSize == 0 || 1079 $itemsProcessed == $totalDerivatives) { 1080 $ret = $statusMonitor->renderStatusMessage( 1081 $module->translate( 1082 array('text' => 'Detecting broken derivatives (%d derivatives ' 1083 . 'checked, %d remaining)', 1084 'arg1' => $itemsProcessed, 1085 'arg2' => $totalDerivatives - $itemsProcessed)), 1086 '', $itemsProcessed / $totalDerivatives); 1087 if ($ret) { 1088 return $ret; 1089 } 1090 $gallery->guaranteeTimeLimit(30); 1091 } 1092 1093 /* 1094 * 3. Filter out derivatives that don't return true for isCacheCurrent 1095 * (= don't have a cache file yet = would be rebuilt anyway) 1096 */ 1097 list ($ret, $current) = $derivative->isCacheCurrent(); 1098 if ($ret) { 1099 return $ret; 1100 } 1101 if (!$current) { 1102 continue; 1103 } 1104 1105 /* 1106 * 4. Filter out derivatives that don't have the same file size as the 1107 * broken image placeholder 1108 */ 1109 list ($ret, $path) = $derivative->fetchPath(); 1110 if ($ret) { 1111 return $ret; 1112 } 1113 if (($size = $platform->filesize($path)) === false) { 1114 return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE); 1115 } 1116 if ($size != $referenceSize) { 1117 continue; 1118 } 1119 1120 /* 5. Binary compare the derivative file with the placeholder file */ 1121 if (($data = $platform->file($path)) === false) { 1122 return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE); 1123 } 1124 $data = implode('', $data); 1125 if ($referenceCrc == crc32($data)) { 1126 /* Add the derivative to the list of broken ones */ 1127 $brokenDerivatives[$derivative->getId()] = $derivative; 1128 } 1129 } 1130 1131 /* 6. Mark the detected broken derivative as such and save it in the DB */ 1132 if (sizeof($brokenDerivatives) == $saveBatchSize || 1133 (!empty($brokenDerivatives) && empty($derivativeIds))) { 1134 $gallery->guaranteeTimeLimit(30); 1135 $saveProgressStepSize = min(200, intval(sizeof($brokenDerivatives) / 10)); 1136 1137 $ret = $statusMonitor->renderStatusMessage( 1138 $module->translate( 1139 array('text' => 'Detecting broken derivatives, saving ' 1140 . '(%d derivatives checked, %d remaining)', 1141 'arg1' => $itemsProcessed, 1142 'arg2' => $totalDerivatives - $itemsProcessed)), 1143 '', $itemsProcessed / $totalDerivatives); 1144 if ($ret) { 1145 return $ret; 1146 } 1147 1148 list ($ret, $lockId) = 1149 GalleryCoreApi::acquireWriteLock(array_keys($brokenDerivatives)); 1150 if ($ret) { 1151 return $ret; 1152 } 1153 1154 $itemsSaved = 0; 1155 foreach ($brokenDerivatives as $brokenDerivative) { 1156 $itemsSaved++; 1157 if ($itemsSaved % $saveProgressStepSize == 0) { 1158 $ret = $statusMonitor->renderStatusMessage( 1159 $module->translate(array( 1160 'text' => 'Detecting broken derivatives, saving item ' 1161 . '%d of %d (%d derivatives complete, %d remaining)', 1162 'arg1' => $itemsSaved, 1163 'arg2' => sizeof($brokenDerivatives), 1164 'arg3' => $itemsProcessed, 1165 'arg4' => $totalDerivatives - $itemsProcessed)), 1166 '', $itemsProcessed / $totalDerivatives); 1167 if ($ret) { 1168 GalleryCoreApi::releaseLocks($lockId); 1169 return $ret; 1170 } 1171 $gallery->guaranteeTimeLimit(30); 1172 } 1173 1174 $brokenDerivative->setIsBroken(true); 1175 $ret = $brokenDerivative->save(true, false); 1176 if ($ret) { 1177 GalleryCoreApi::releaseLocks($lockId); 1178 return $ret; 1179 } 1180 } 1181 $brokenDerivatives = array(); 1182 1183 $ret = GalleryCoreApi::releaseLocks($lockId); 1184 if ($ret) { 1185 return $ret; 1186 } 1187 } 1188 /* 1189 * Continue if there are either unloaded ids, unchecked derivatives or unsaved 1190 * derivatives 1191 */ 1192 } while (!empty($derivativeIds) || !empty($brokenDerivatives) || 1193 !empty($derivatives)); 1194 } 1195 1196 case '0.9.28': 1197 /* Changed module API onLoad($entity, $duringUpgrade) definition */ 1198 1199 case '0.9.29': 1200 /* Ginormous layout and theme consolidation refactor */ 1201 $ret = $storage->configureStore($module->getId(), 1202 array('GalleryPluginParameterMap:1.1')); 1203 if ($ret) { 1204 return $ret; 1205 } 1206 1207 $query = ' 1208 UPDATE 1209 [GalleryPluginParameterMap] 1210 SET 1211 [::pluginType] = \'theme\' 1212 WHERE 1213 [GalleryPluginParameterMap::pluginType] = \'layout\' 1214 '; 1215 $ret = $storage->execute($query); 1216 if ($ret) { 1217 return $ret; 1218 } 1219 1220 /* After this refactor we only support the matrix theme */ 1221 $query = ' 1222 UPDATE 1223 [GalleryAlbumItem] 1224 SET 1225 [::theme] = \'matrix\' 1226 '; 1227 $ret = $storage->execute($query); 1228 if ($ret) { 1229 return $ret; 1230 } 1231 1232 $query = ' 1233 UPDATE 1234 [GalleryPluginMap] 1235 SET 1236 [::pluginType] = \'theme\' 1237 WHERE 1238 [GalleryPluginMap::pluginType] = \'layout\' 1239 '; 1240 $ret = $storage->execute($query); 1241 if ($ret) { 1242 return $ret; 1243 } 1244 1245 /* 1246 * Rename g2data 'layouts' directories to be 'themes', or create them if they don't 1247 * already exist (they should exist, though) 1248 */ 1249 foreach (array($gallery->getConfig('data.gallery.plugins'), 1250 $gallery->getConfig('data.gallery.plugins_data')) as $base) { 1251 if ($platform->file_exists("$base/themes")) { 1252 if ($platform->file_exists("$base/layouts")) { 1253 $platform->recursiveRmDir("$base/layouts"); 1254 } 1255 } else if (file_exists($base)) { 1256 if ($platform->file_exists("$base/layouts")) { 1257 $platform->rename("$base/layouts", "$base/themes"); 1258 } else { 1259 $platform->mkdir("$base/themes"); 1260 } 1261 } 1262 } 1263 1264 /* Removed parameters */ 1265 foreach (array('language.selector', 'misc.login') as $paramName) { 1266 $ret = $module->removeParameter($paramName); 1267 if ($ret) { 1268 return $ret; 1269 } 1270 } 1271 1272 /* 1273 * If we're coming from 0.8.13 or earlier, then our themes don't have version 1274 * information, so take care of that here by calling installOrUpgrade() on the currently 1275 * active themes to let them update their bookkeeping. Reactivate them too for good 1276 * measure. 1277 */ 1278 if (version_compare($currentVersion, '0.8.13', '<=')) { 1279 list ($ret, $themes) = GalleryCoreApi::fetchPluginStatus('theme'); 1280 if ($ret) { 1281 return $ret; 1282 } 1283 1284 foreach ($themes as $themeId => $themeStatus) { 1285 $gallery->guaranteeTimeLimit(30); 1286 if (!empty($themeStatus['active'])) { 1287 list ($ret, $theme) = GalleryCoreApi::loadPlugin('theme', $themeId); 1288 if ($ret && 1289 !($ret->getErrorCode() & ERROR_PLUGIN_VERSION_MISMATCH)) { 1290 return $ret; 1291 } 1292 1293 $ret = $theme->installOrUpgrade(); 1294 if ($ret) { 1295 return $ret; 1296 } 1297 1298 list ($ret, $ignored) = $theme->activate(false); 1299 if ($ret && 1300 !($ret->getErrorCode() & ERROR_PLUGIN_VERSION_MISMATCH)) { 1301 /* 1302 * Theme getSettings may try to load ImageFrame interface, but 1303 * ImageFrame may need to be upgraded. Ignore version mismatch here. 1304 */ 1305 return $ret; 1306 } 1307 } 1308 } 1309 } 1310 1311 case '0.9.30': 1312 /* Removed layout column from AlbumItem; matrix is only theme for now: set default */ 1313 $ret = $storage->configureStore($module->getId(), array('GalleryAlbumItem:1.0')); 1314 if ($ret) { 1315 return $ret; 1316 } 1317 1318 $ret = $module->setParameter('default.theme', 'matrix'); 1319 if ($ret) { 1320 return $ret; 1321 } 1322 $ret = $module->removeParameter('default.layout'); 1323 if ($ret) { 1324 return $ret; 1325 } 1326 $query = ' 1327 UPDATE 1328 [GalleryAlbumItem] 1329 SET 1330 [::theme] = NULL 1331 '; 1332 $ret = $storage->execute($query); 1333 if ($ret) { 1334 return $ret; 1335 } 1336 1337 case '0.9.31': 1338 /* Beta 4! */ 1339 case '0.9.32': 1340 /* Minor core API change */ 1341 case '0.9.33': 1342 /* Release Candidate 1! */ 1343 1344 case '0.9.34': 1345 /* Add date/time formats */ 1346 foreach (array('format.date' => '%x', 'format.time' => '%X', 'format.datetime' => '%c') 1347 as $key => $value) { 1348 $ret = $module->setParameter($key, $value); 1349 if ($ret) { 1350 return $ret; 1351 } 1352 } 1353 1354 case '0.9.35': 1355 /* Release Candidate 2! */ 1356 1357 case '0.9.36': 1358 /* 1359 * Fixed GalleryUtilities::getPseudoFileName for derivatives. Delete fast-download 1360 * files that may have cached incorrect filenames. 1361 */ 1362 $slash = $platform->getDirectorySeparator(); 1363 $baseDir = $gallery->getConfig('data.gallery.cache') . 'derivative' . $slash; 1364 for ($i = 0; $i < 10; $i++) { 1365 $gallery->guaranteeTimeLimit(60); 1366 $ret = $statusMonitor->renderStatusMessage( 1367 $module->translate('Clearing fast-download cache'), '', $i / 10); 1368 if ($ret) { 1369 return $ret; 1370 } 1371 for ($j = 0; $j < 10; $j++) { 1372 $dir = $baseDir . $i . $slash . $j . $slash; 1373 if ($dh = @$platform->opendir($dir)) { 1374 while (($file = $platform->readdir($dh)) !== false) { 1375 if (substr($file, -9) == '-fast.inc') { 1376 @$platform->unlink($dir . $file); 1377 } 1378 } 1379 $platform->closedir($dh); 1380 } 1381 } 1382 } 1383 $ret = $statusMonitor->renderStatusMessage( 1384 $module->translate('Clearing fast-download cache'), '', 1); 1385 if ($ret) { 1386 return $ret; 1387 } 1388 1389 case '0.9.37': 1390 /* 2.0 Release! */ 1391 1392 case '1.0.0': 1393 case '1.0.0.x': 1394 /* Schema only upgrade */ 1395 $ret = $storage->configureStore($module->getId(), 1396 array('GalleryPluginParameterMap:1.2')); 1397 if ($ret) { 1398 return $ret; 1399 } 1400 1401 case '1.0.1': 1402 /* Add image/wmf mime type */ 1403 list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('wmf'); 1404 if (!$ret && $mimeType == 'application/unknown') { 1405 $ret = GalleryCoreApi::addMimeType('wmf', 'image/wmf', false); 1406 if ($ret) { 1407 return $ret; 1408 } 1409 } 1410 1411 case '1.0.2': 1412 /* Security fix */ 1413 1414 case '1.0.3': 1415 /* Consolidated .sql files into schema.tpl */ 1416 1417 case '1.0.4': 1418 /* Added maintenance mode */ 1419 1420 case '1.0.5': 1421 /* Remove plugins directory from g2data */ 1422 $pluginDirectory = $gallery->getConfig('data.gallery.base') . 'plugins'; 1423 $pluginDirectories = array($pluginDirectory . '/modules', 1424 $pluginDirectory . '/themes', 1425 $pluginDirectory); 1426 1427 foreach ($pluginDirectories as $pluginDirectory) { 1428 if (@$platform->file_exists($pluginDirectory)) { 1429 /* We're not interested in whether it succeeded or not */ 1430 @$platform->recursiveRmDir($pluginDirectory); 1431 } 1432 } 1433 1434 case '1.0.6': 1435 /* Add PluginPackageMap table */ 1436 1437 case '1.0.7': 1438 $ret = $module->setParameter('exec.beNice', '0'); 1439 if ($ret) { 1440 return $ret; 1441 } 1442 1443 case '1.0.8': 1444 case '1.0.9': 1445 /* Security fix in zipcart */ 1446 1447 case '1.0.10': 1448 /* Rename unnamed pre-beta-3 index to named index */ 1449 if ($storage->getType() == 'mysql') { 1450 $gallery->debug('Rename unnamed pre-beta-3 index to named index (ignore errors)'); 1451 $query = sprintf(' 1452 ALTER TABLE %sAccessMap 1453 DROP INDEX %saccessListId_2, 1454 ADD INDEX %sAccessMap_83732(%saccessListId);', 1455 $storage->_tablePrefix, $storage->_columnPrefix, $storage->_tablePrefix, 1456 $storage->_columnPrefix); 1457 /* Ignore error, since there's nothing to do for most installations */ 1458 $storage->execute($query); 1459 } 1460 1461 /* 1462 * Combine AccessMap userId/groupId into single userOrGroupId, and remove unused 1463 * GALLERY_PERMISSION_ITEM_ADMIN permission flag. Also increase size of 1464 * GalleryUser::email column. 1465 */ 1466 $ret = $storage->configureStore($module->getId(), 1467 array('GalleryAccessMap:1.0', 'GalleryUser:1.0')); 1468 if ($ret) { 1469 return $ret; 1470 } 1471 1472 /* If coming from 0.9.5 or earlier then GalleryAccessMap already has userOrGroupId */ 1473 if (version_compare($currentVersion, '0.9.5', '>')) { 1474 $query = ' 1475 UPDATE 1476 [GalleryAccessMap] 1477 SET 1478 [::userOrGroupId] = [::userId] + [::groupId] 1479 '; 1480 $ret = $storage->execute($query, array()); 1481 if ($ret) { 1482 return $ret; 1483 } 1484 } 1485 1486 $ret = $storage->configureStore($module->getId(), array('GalleryAccessMap:1.1')); 1487 if ($ret) { 1488 return $ret; 1489 } 1490 1491 list ($ret, $flagModifier) = 1492 $storage->getFunctionSql('BITAND', array('[::flags]', '?')); 1493 if ($ret) { 1494 return $ret; 1495 } 1496 $query = ' 1497 UPDATE 1498 [GalleryPermissionSetMap] 1499 SET 1500 [::flags] = ' . $flagModifier . ' 1501 '; 1502 $ret = $storage->execute($query, array(3)); 1503 if ($ret) { 1504 return $ret; 1505 } 1506 1507 case '1.0.11': 1508 /* Several previous upgrades used 'modules' instead of 'module' with plugin params */ 1509 list ($ret, $coreParams) = $module->fetchParameters(); 1510 if ($ret) { 1511 return $ret; 1512 } 1513 foreach (array('misc.useShortUrls', 'language.selector') as $key) { 1514 if (isset($coreParams[$key])) { 1515 $ret = $module->removeParameter('misc.useShortUrls'); 1516 if ($ret) { 1517 return $ret; 1518 } 1519 } 1520 } 1521 foreach (array('cookie.path' => '', 'cookie.domain' => '', 1522 'exec.beNice' => '0', 'repository.updateTime' => '0') 1523 as $key => $value) { 1524 if (!isset($coreParams[$key])) { 1525 $ret = $module->setParameter($key, $value); 1526 if ($ret) { 1527 return $ret; 1528 } 1529 } 1530 } 1531 $ret = GalleryCoreApi::removeMapEntry( 1532 'GalleryPluginParameterMap', array('pluginType' => 'modules')); 1533 if ($ret) { 1534 return $ret; 1535 } 1536 1537 case '1.0.12': 1538 /* Add param 'language.useBrowserPref' */ 1539 list ($ret, $langCode) = $module->getParameter('default.language'); 1540 if ($ret) { 1541 return $ret; 1542 } 1543 $useBrowserPref = '0'; 1544 if (empty($langCode)) { 1545 $useBrowserPref = '1'; 1546 $ret = $module->setParameter('default.language', 'en_US'); 1547 if ($ret) { 1548 return $ret; 1549 } 1550 } 1551 $ret = $module->setParameter('language.useBrowserPref', $useBrowserPref); 1552 if ($ret) { 1553 return $ret; 1554 } 1555 1556 case '1.0.13': 1557 /* Add config parameter: 'baseUri'*/ 1558 case '1.0.14': 1559 /* GalleryCoreApi 7.0 and GalleryModule 3.0 */ 1560 case '1.0.15': 1561 /* 1562 * Add fast-download for GalleryDataItems too. Fast-download files are now in 1563 * cache/entity/. Delete the old files in cache/derivative/. 1564 */ 1565 $gallery->guaranteeTimeLimit(60); 1566 $query = 'SELECT [GalleryDerivativeImage::id] 1567 FROM [GalleryDerivativeImage]'; 1568 list ($ret, $searchResults) = $gallery->search($query); 1569 if ($ret) { 1570 return $ret; 1571 } 1572 1573 /* Checkpoint before starting a long filesystem-only task */ 1574 $ret = $storage->checkPoint(); 1575 if ($ret) { 1576 return $ret; 1577 } 1578 1579 if ($searchResults->resultCount() > 0) { 1580 $derivativeIds = array(); 1581 while ($result = $searchResults->nextResult()) { 1582 $derivativeIds[] = $result[0]; 1583 } 1584 $totalDerivatives = count($derivativeIds); 1585 $base = $gallery->getConfig('data.gallery.cache'); 1586 $gallery->guaranteeTimeLimit(60); 1587 1588 /* Show a progress bar */ 1589 $ret = $statusMonitor->renderStatusMessage( 1590 $module->translate('Deleting old fast-download cache'), '', 0); 1591 if ($ret) { 1592 return $ret; 1593 } 1594 1595 $stepSize = min(100, max(intval($totalDerivatives / 10), 5)); 1596 for ($i = 0; $i < $totalDerivatives; $i++) { 1597 /* Delete the file if it exists */ 1598 list ($first, $second) = GalleryDataCache::getCacheTuple($derivativeIds[$i]); 1599 $fastDownloadFilePath = sprintf('%derivative/%s/%s/%d-fast.inc', 1600 $base, $first, $second, $derivativeIds[$i]); 1601 if ($platform->file_exists($fastDownloadFilePath)) { 1602 $platform->unlink($fastDownloadFilePath); 1603 } 1604 1605 /* Update the progress bar / prevent timouts */ 1606 if ($i % $stepSize == 0 || $i == ($totalDerivatives - 1)) { 1607 $gallery->guaranteeTimeLimit(60); 1608 $ret = $statusMonitor->renderStatusMessage( 1609 $module->translate('Deleting old fast-download cache'), 1610 '', ($i+1) / $totalDerivatives); 1611 if ($ret) { 1612 return $ret; 1613 } 1614 } 1615 } 1616 } 1617 1618 /* We might have lost our database connection so check and reconnect */ 1619 $ret = $storage->validateConnection(); 1620 if ($ret) { 1621 return $ret; 1622 } 1623 1624 case '1.0.16': 1625 /* Added 'not-null' to Entities.inc and Map.inc */ 1626 $storageExtras =& $storage->_getExtras(); 1627 $storageExtras->_clearEntityAndMapCache(); 1628 case '1.0.17': 1629 /* Add image/tga mime type */ 1630 list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('tga'); 1631 if (!$ret && $mimeType == 'application/unknown') { 1632 $ret = GalleryCoreApi::addMimeType('tga', 'image/tga', false); 1633 if ($ret) { 1634 return $ret; 1635 } 1636 } 1637 1638 case '1.0.18': 1639 /* Add index to GalleryEntity::linkId */ 1640 $ret = $storage->configureStore($module->getId(), array('GalleryEntity:1.1')); 1641 if ($ret) { 1642 return $ret; 1643 } 1644 1645 case '1.0.19': 1646 /* Add page level caching and the GalleryCache map */ 1647 $acceleration = serialize(array('guest' => array('type' => 'none'), 1648 'user' => array('type' => 'none'))); 1649 $ret = GalleryCoreApi::setPluginParameter( 1650 'module', 'core', 'acceleration', $acceleration); 1651 if ($ret) { 1652 return $ret; 1653 } 1654 1655 case '1.0.20': 1656 /* Add configurable captcha security level */ 1657 $ret = GalleryCoreApi::setPluginParameter('module', 'core', 'captcha.level', 'MEDIUM'); 1658 if ($ret) { 1659 return $ret; 1660 } 1661 1662 case '1.0.21': 1663 /* GallerySession change: Store sessions in the database and no longer on disk */ 1664 $sessionsDir = $gallery->getConfig('data.gallery.base') . 'sessions' . 1665 $platform->getDirectorySeparator(); 1666 if ($platform->file_exists($sessionsDir)) { 1667 $stepSize = 100; 1668 $count = 0; 1669 $iterationSize = 5000; 1670 $iteration = 1; 1671 /* Show a progress bar while removing the files */ 1672 $ret = $statusMonitor->renderStatusMessage( 1673 $module->translate(array('text' => 'Deleting old session files (iteration %d)', 1674 'arg1' => $iteration)), 1675 '', 0); 1676 if ($ret) { 1677 return $ret; 1678 } 1679 $dir = $platform->opendir($sessionsDir, 'r'); 1680 if (!$dir) { 1681 return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__, 1682 "Can't access session dir"); 1683 } 1684 $gallery->guaranteeTimeLimit(60); 1685 while (($filename = $platform->readdir($dir)) !== false) { 1686 if ($filename == '.' || $filename == '..') { 1687 continue; 1688 } 1689 $count++; 1690 $platform->unlink($sessionsDir . $filename); 1691 1692 /* Update the progress bar / prevent timouts */ 1693 if ($count % $stepSize == 0) { 1694 $gallery->guaranteeTimeLimit(60); 1695 $ret = $statusMonitor->renderStatusMessage( 1696 $module->translate( 1697 array('text' => 'Deleting old session files (iteration %d)', 1698 'arg1' => $iteration)), 1699 '', $count / $iterationSize); 1700 if ($ret) { 1701 return $ret; 1702 } 1703 } 1704 1705 if ($count > $iterationSize) { 1706 $iteration++; 1707 $count = 0; 1708 } 1709 } 1710 $platform->closedir($dir); 1711 $platform->rmdir($sessionsDir); 1712 $ret = $statusMonitor->renderStatusMessage( 1713 $module->translate(array('text' => 'Deleting old session files (iteration %d)', 1714 'arg1' => $iteration)), 1715 '', 1); 1716 if ($ret) { 1717 return $ret; 1718 } 1719 } 1720 1721 case '1.0.22': 1722 /* Rename unnamed pre-beta-3 index to named index */ 1723 $gallery->guaranteeTimeLimit(120); 1724 if ($storage->getType() == 'mysql') { 1725 $gallery->debug('Rename unnamed pre-beta-3 index to named index (ignore errors)'); 1726 $indexChanges = array(); 1727 $indexChanges[] = array('AccessMap', 'permission', 1728 'AccessMap_18058', array('permission')); 1729 $indexChanges[] = array('AccessSubscriberMap', 'accessListId', 1730 'AccessSubscriberMap_83732', array('accessListId')); 1731 $indexChanges[] = array('ChildEntity', 'parentId', 1732 'ChildEntity_52718', array('parentId')); 1733 $indexChanges[] = array('Derivative', 'derivativeSourceId', 1734 'Derivative_85338', array('derivativeSourceId')); 1735 $indexChanges[] = array('Derivative', 'derivativeOrder', 1736 'Derivative_25243', array('derivativeOrder')); 1737 $indexChanges[] = array('Derivative', 'derivativeType', 1738 'Derivative_97216', array('derivativeType')); 1739 $indexChanges[] = array('DerivativePrefsMap', 'itemId', 1740 'DerivativePrefsMap_75985', array('itemId')); 1741 $indexChanges[] = array('Entity', 'creationTimestamp', 1742 'Entity_76255', array('creationTimestamp')); 1743 $indexChanges[] = array('Entity', 'isLinkable', 1744 'Entity_35978', array('isLinkable')); 1745 $indexChanges[] = array('Entity', 'modificationTimestamp', 1746 'Entity_63025', array('modificationTimestamp')); 1747 $indexChanges[] = array('Entity', 'serialNumber', 1748 'Entity_60702', array('serialNumber')); 1749 $indexChanges[] = array('FileSystemEntity ', 'pathComponent', 1750 'FileSystemEntity_3406', array('pathComponent')); 1751 $indexChanges[] = array('Item', 'keywords', 'Item_99070', array('keywords')); 1752 $indexChanges[] = array('Item', 'ownerId', 'Item_21573', array('ownerId')); 1753 $indexChanges[] = array('Item', 'summary', 'Item_54147', array('summary')); 1754 $indexChanges[] = array('Item', 'title', 'Item_90059', array('title')); 1755 $indexChanges[] = array('ItemAttributesMap', 'parentSequence', 1756 'ItemAttributesMap_95270', array('parentSequence')); 1757 $indexChanges[] = array('MaintenanceMap', 'taskId', 1758 'MaintenanceMap_21687', array('taskId')); 1759 $indexChanges[] = array('PluginParameterMap', 'pluginType_2', 1760 'PluginParameterMap_12808', 1761 array('pluginType', 'pluginId', 'itemId')); 1762 $indexChanges[] = array('PluginParameterMap', 'pluginType_3', 1763 'PluginParameterMap_80596', array('pluginType')); 1764 $indexChanges[] = array('TkOperatnMimeTypeMap', 'operationName', 1765 'TkOperatnMimeTypeMap_2014', array('operationName')); 1766 $indexChanges[] = array('TkOperatnMimeTypeMap', 'mimeType', 1767 'TkOperatnMimeTypeMap_79463', array('mimeType')); 1768 $indexChanges[] = array('TkOperatnParameterMap', 'operationName', 1769 'TkOperatnParameterMap_2014', array('operationName')); 1770 $indexChanges[] = array('TkPropertyMimeTypeMap', 'propertyName', 1771 'TkPropertyMimeTypeMap_52881', array('propertyName')); 1772 $indexChanges[] = array('TkPropertyMimeTypeMap', 'mimeType', 1773 'TkPropertyMimeTypeMap_79463', array('mimeType')); 1774 $indexChanges[] = array('UserGroupMap', 'userId', 1775 'UserGroupMap_69068', array('userId')); 1776 $indexChanges[] = array('UserGroupMap', 'groupId', 1777 'UserGroupMap_89328', array('groupId')); 1778 $indexChanges[] = array('Lock', 'lockId', 1779 'Lock_11039', array('lockId')); 1780 foreach ($indexChanges as $change) { 1781 $indexColumns = implode('`, `' . $storage->_columnPrefix, $change[3]); 1782 $indexColumns = $storage->_columnPrefix . $indexColumns; 1783 $query = sprintf(' 1784 ALTER TABLE `%s%s` 1785 DROP INDEX `%s%s`, 1786 ADD INDEX `%s%s`(`%s`);', 1787 $storage->_tablePrefix, $change[0], $storage->_columnPrefix, $change[1], 1788 $storage->_tablePrefix, $change[2], $indexColumns); 1789 /* Ignore error, since there's nothing to do for most installations */ 1790 $storage->execute($query); 1791 } 1792 $gallery->debug('Finished renaming unnamed pre-beta-3 indices to named indices'); 1793 } 1794 1795 /* Commit transactions before we execute a query that we expect to fail */ 1796 $ret = $storage->checkPoint(); 1797 if ($ret) { 1798 return $ret; 1799 } 1800 1801 /* 1802 * Also add a single column index on AccessMap.accessListId since it was forgotten in 1803 * the initial upgrade code. Ignore errors since some installations already have it. 1804 */ 1805 $gallery->debug('Adding an index to the AccessMap table, ignore errors'); 1806 $storage->configureStore($module->getId(), array('GalleryAccessMap:1.2')); 1807 1808 /* Postgres will abort the transaction if the index exists, so checkpoint here */ 1809 $ret = $storage->checkPoint(); 1810 if ($ret) { 1811 return $ret; 1812 } 1813 1814 $gallery->debug('Finished adding an index to the AccessMap table'); 1815 /* 1816 * Make sure the schema update is stored, can't use updateMapEntry because schema is not 1817 * in Maps.xml 1818 */ 1819 $query = sprintf(' 1820 UPDATE %sSchema 1821 SET %smajor=1, %sminor=3 1822 WHERE %sname=\'AccessMap\' AND %smajor=1 AND %sminor=2', 1823 $storage->_tablePrefix, $storage->_columnPrefix, 1824 $storage->_columnPrefix, $storage->_columnPrefix, 1825 $storage->_columnPrefix, $storage->_columnPrefix); 1826 $ret = $storage->execute($query); 1827 if ($ret) { 1828 return $ret; 1829 } 1830 1831 case '1.0.23': 1832 /* Rename GalleryCache to GalleryCacheMap, and make the value column TEXT(LARGE) */ 1833 1834 case '1.0.24': 1835 /* Add CoreCaptchaAdminOption, rename level parameter */ 1836 $gallery->guaranteeTimeLimit(60); 1837 list ($ret, $level) = $module->getParameter('captcha.level'); 1838 if ($ret) { 1839 return $ret; 1840 } 1841 $ret = $module->setParameter('validation.level', $level); 1842 if ($ret) { 1843 return $ret; 1844 } 1845 $ret = $module->removeParameter('captcha.level'); 1846 if ($ret) { 1847 return $ret; 1848 } 1849 1850 case '1.0.25': 1851 case '1.0.26': 1852 /* 1853 * 2.1 Release Candidate 1! 1854 * 1855 * We used to change the character set for MySQL databases to utf8 here, but now we do 1856 * it on every upgrade (at the beginning) to allow for the fact that the user can 1857 * upgrade their MySQL from 3.x to 4.x at any time. We still call it here for 1858 * historical accuracy for users upgrading from before 1.0.26. 1859 */ 1860 list ($ret, $converted) = 1861 CoreModuleExtras::convertCharacterSetToUtf8($module, $statusMonitor); 1862 if ($ret) { 1863 return $ret; 1864 } 1865 1866 /* Clear the cache data since we changed the blob encoding */ 1867 $gallery->guaranteeTimeLimit(60); 1868 $ret = GalleryCoreApi::removeAllMapEntries('GalleryCacheMap', true); 1869 if ($ret) { 1870 return $ret; 1871 } 1872 1873 case '1.0.27': 1874 case '1.0.28': 1875 /* Change in page cache key format */ 1876 case '1.0.29': 1877 /* Support for transactional locking */ 1878 1879 case '1.0.30': 1880 /* Pull dangerous mime types */ 1881 $ret = GalleryCoreApi::removeMimeType( 1882 array('mimeType' => array('text/html', 'application/xhtml+xml', 'text/xml'))); 1883 if ($ret) { 1884 return $ret; 1885 } 1886 1887 case '1.0.31': 1888 list ($ret, $params) = GalleryCoreApi::fetchAllPluginParameters('module', 'core'); 1889 if ($ret) { 1890 return $ret; 1891 } 1892 foreach (array('session.lifetime' => array(25 * 365 * 86400, 21 * 86400), 1893 'session.inactivityTimeout' => array(14 * 86400, 7 * 86400)) as 1894 $key => $oldAndNew) { 1895 if ($params[$key] == $oldAndNew[0]) { 1896 $ret = $module->setParameter($key, $oldAndNew[1]); 1897 if ($ret) { 1898 return $ret; 1899 } 1900 } 1901 } 1902 1903 case '1.0.32': 1904 /* 2.1 Release Candidate 2! */ 1905 case '1.0.33': 1906 /* Security fix in installer/upgrader - RC-2a */ 1907 case '1.0.34': 1908 /* 2.1 Release! */ 1909 1910 case '1.1.0': 1911 case '1.1.0.x': 1912 /* Minimum PHP version now 4.3.0; new versions of ADODb and Smarty */ 1913 case '1.1.1': 1914 1915 case '1.1.2': 1916 /* Add Flash video and Windows playlist mime types */ 1917 list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('flv'); 1918 if (!$ret && $mimeType == 'application/unknown') { 1919 $ret = GalleryCoreApi::addMimeType('flv', 'video/x-flv', false); 1920 if ($ret) { 1921 return $ret; 1922 } 1923 } 1924 list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('asx'); 1925 if (!$ret && $mimeType == 'application/unknown') { 1926 $ret = GalleryCoreApi::addMimeType('asx', 'video/x-ms-asx', false); 1927 if ($ret) { 1928 return $ret; 1929 } 1930 } 1931 1932 case '1.1.3': 1933 /* Add renderers to GalleryItem */ 1934 $ret = $storage->configureStore($module->getId(), array('GalleryItem:1.1')); 1935 if ($ret) { 1936 return $ret; 1937 } 1938 $ret = $storage->execute('UPDATE [GalleryItem] SET [::renderer] = NULL'); 1939 if ($ret) { 1940 return $ret; 1941 } 1942 1943 /* 1944 * Switch PanoramaPhotoItem and PanoramaDerivativeImage entities back to their base 1945 * classes and set the items to use the PanoramaRenderer instead 1946 */ 1947 $gallery->guaranteeTimeLimit(60); 1948 $query = ' 1949 SELECT 1950 [GalleryEntity::id], [GalleryEntity::entityType] 1951 FROM 1952 [GalleryEntity] 1953 WHERE 1954 [GalleryEntity::entityType] IN (\'PanoramaPhotoItem\', \'PanoramaDerivativeImage\') 1955 '; 1956 list ($ret, $searchResults) = $gallery->search($query, array()); 1957 if ($ret) { 1958 return $ret; 1959 } 1960 $photos = $derivatives = array(); 1961 while ($result = $searchResults->nextResult()) { 1962 if ($result[1] == 'PanoramaPhotoItem') { 1963 $photos[] = $result[0]; 1964 } else { 1965 $derivatives[] = $result[0]; 1966 } 1967 } 1968 $total = count($photos) + count($derivatives); 1969 1970 /* Switch PanoramaPhotoItems back to GalleryPhotoItems */ 1971 for ($i = 0; $photos; $i += count($ids)) { 1972 $gallery->guaranteeTimeLimit(30); 1973 $ret = $statusMonitor->renderStatusMessage( 1974 $module->translate('Updating panorama items'), '', $i / $total); 1975 if ($ret) { 1976 return $ret; 1977 } 1978 $ids = array_splice($photos, 0, 500); 1979 $markers = GalleryUtilities::makeMarkers($ids); 1980 $query = "UPDATE [GalleryItem] SET [::renderer] = 'PanoramaRenderer' " . 1981 "WHERE [GalleryItem::id] IN ($markers)"; 1982 $ret = $storage->execute($query, $ids); 1983 if ($ret) { 1984 return $ret; 1985 } 1986 1987 $query = "UPDATE [GalleryEntity] SET [::entityType] = 'GalleryPhotoItem' " . 1988 "WHERE [GalleryEntity::id] IN ($markers)"; 1989 $ret = $storage->execute($query, $ids); 1990 if ($ret) { 1991 return $ret; 1992 } 1993 } 1994 1995 /* Switch PanoramaDerivativeImage back to GalleryDerivativeImage */ 1996 while ($derivatives) { 1997 $gallery->guaranteeTimeLimit(30); 1998 $ret = $statusMonitor->renderStatusMessage( 1999 $module->translate('Updating panorama items'), '', $i / $total); 2000 if ($ret) { 2001 return $ret; 2002 } 2003 $ids = array_splice($derivatives, 0, 500); 2004 $markers = GalleryUtilities::makeMarkers($ids); 2005 $query = "UPDATE [GalleryEntity] SET [::entityType] = 'GalleryDerivativeImage' " . 2006 "WHERE [GalleryEntity::id] IN ($markers)"; 2007 $ret = $storage->execute($query, $ids); 2008 if ($ret) { 2009 return $ret; 2010 } 2011 $i += count($ids); 2012 } 2013 if ($total) { 2014 $ret = $statusMonitor->renderStatusMessage( 2015 $module->translate('Updating panorama items'), '', 1); 2016 if ($ret) { 2017 return $ret; 2018 } 2019 } 2020 2021 case '1.1.4': 2022 /* Add mpeg-4 video mime type */ 2023 list ($ret, $mimeType) = GalleryCoreApi::convertExtensionToMime('mp4'); 2024 if (!$ret && $mimeType == 'application/unknown') { 2025 $ret = GalleryCoreApi::addMimeType('mp4', 'video/mp4', false); 2026 if ($ret) { 2027 return $ret; 2028 } 2029 } 2030 2031 case '1.1.5': 2032 case '1.1.6': 2033 /* Remove useless rows in AccessSubscriberMap */ 2034 $gallery->guaranteeTimeLimit(60); 2035 $query = ' 2036 SELECT 2037 [GalleryAccessSubscriberMap::itemId] 2038 FROM 2039 [GalleryAccessSubscriberMap], [GalleryEntity] 2040 WHERE 2041 [GalleryAccessSubscriberMap::accessListId] = 0 2042 AND 2043 [GalleryAccessSubscriberMap::itemId] = [GalleryEntity::id] 2044 AND 2045 [GalleryEntity::entityType] IN (?,?,?,?) 2046 '; 2047 list ($ret, $searchResults) = $gallery->search($query, 2048 array('GalleryDerivativeImage', 'GalleryUser', 'GalleryGroup', 'GalleryComment')); 2049 if ($ret) { 2050 return $ret; 2051 } 2052 $itemIds = array(); 2053 while ($result = $searchResults->nextResult()) { 2054 $itemIds[] = (int)$result[0]; 2055 } 2056 $total = count($itemIds); 2057 $query = 'DELETE FROM [GalleryAccessSubscriberMap] WHERE [::itemId] IN ('; 2058 2059 for ($i = 0; $itemIds; $i += count($ids)) { 2060 $gallery->guaranteeTimeLimit(30); 2061 $ret = $statusMonitor->renderStatusMessage( 2062 $module->translate('Optimizing AccessSubscriberMap table'), '', $i / $total); 2063 if ($ret) { 2064 return $ret; 2065 } 2066 $ids = array_splice($itemIds, 0, 500); 2067 $markers = GalleryUtilities::makeMarkers($ids); 2068 $ret = $storage->execute($query . $markers . ')', $ids); 2069 if ($ret) { 2070 return $ret; 2071 } 2072 } 2073 if ($total) { 2074 $ret = $statusMonitor->renderStatusMessage( 2075 $module->translate('Optimizing AccessSubscriberMap table'), '', 1); 2076 if ($ret) { 2077 return $ret; 2078 } 2079 } 2080 2081 case '1.1.7': 2082 /* ItemAddFromServer and ItemAddFromWeb moved to separate module */ 2083 /* Move uploadLocalServer.dir entries to itemadd module in case it is activated later */ 2084 list ($ret, $params) = GalleryCoreApi::fetchAllPluginParameters('module', 'core'); 2085 if ($ret) { 2086 return $ret; 2087 } 2088 for ($i = 1; isset($params['uploadLocalServer.dir.' . $i]); $i++) { 2089 $key = 'uploadLocalServer.dir.' . $i; 2090 $ret = GalleryCoreApi::setPluginParameter('module', 'itemadd', $key, $params[$key]); 2091 if ($ret) { 2092 return $ret; 2093 } 2094 $ret = $module->removeParameter($key); 2095 if ($ret) { 2096 return $ret; 2097 } 2098 } 2099 2100 case '1.1.8': 2101 /* Remove lock subdirs */ 2102 $locksDir = $gallery->getConfig('data.gallery.locks'); 2103 if ($platform->file_exists($locksDir)) { 2104 @$platform->recursiveRmDir($locksDir); 2105 } 2106 @$platform->mkdir($locksDir); 2107 2108 case '1.1.9': 2109 /* Graphics toolkits now support percentages for thumbnail/scale/resize */ 2110 case '1.1.10': 2111 /* Moved ItemCreateLink[Single] to replica module */ 2112 case '1.1.11': 2113 /* GalleryAuthPlugin: set active user from session now handled by SessionAuthPlugin */ 2114 case '1.1.12': 2115 /* GalleryCoreApi::getMapEntry */ 2116 case '1.1.13': 2117 /* GalleryDynamicAlbum */ 2118 case '1.1.14': 2119 /* 2120 * Add a .htaccess file in the storage folder to protect it against direct access 2121 * in case it is accessible from the web. 2122 * Moved to case 1.2.23 to make a small change. 2123 */ 2124 case '1.1.15': 2125 /* Locked Users */ 2126 $ret = $storage->configureStore($module->getId(), array('GalleryUser:1.1')); 2127 if ($ret) { 2128 return $ret; 2129 } 2130 2131 case '1.1.16': 2132 /* Initialize multiple repositories */ 2133 $ret = $module->setParameter('core.repositories', serialize(array('released' => 1))); 2134 if ($ret) { 2135 return $ret; 2136 } 2137 2138 /* Locked plugins */ 2139 $ret = $storage->configureStore($module->getId(), array('GalleryPluginPackageMap:1.0')); 2140 if ($ret) { 2141 return $ret; 2142 } 2143 2144 case '1.1.17': 2145 /* Rolled SessionAuthPlugin into GallerySession.class, so force a factory update */ 2146 case '1.1.18': 2147 /* Added PHP display_errors ini setting to config.php */ 2148 case '1.1.19': 2149 /* Added ConvertDatabaseToUtf8Task */ 2150 case '1.1.20': 2151 /* Add column isEmpty to CacheMap */ 2152 $ret = GalleryCoreApi::removeAllMapEntries('GalleryCacheMap', true); 2153 if ($ret) { 2154 return $ret; 2155 } 2156 $ret = $storage->configureStore($module->getId(), array('GalleryCacheMap:1.0')); 2157 if ($ret) { 2158 return $ret; 2159 } 2160 case '1.1.21': 2161 /* Added authentication token */ 2162 case '1.1.22': 2163 /* Add FailedLoginsMap */ 2164 case '1.1.23': 2165 /* Add JavaScriptWarning.tpl */ 2166 case '1.1.24': 2167 /* Add page-level caching for embedded mode */ 2168 case '1.1.25': 2169 /* 2.2 Release Candidate 1! */ 2170 case '1.1.26': 2171 /* Prevent PHP from showing errors on direct access to config.php */ 2172 case '1.1.27': 2173 /* Changed repository cache directory, easiest to just blow away the old one. */ 2174 $oldDir = $gallery->getConfig('data.gallery.plugins_data') . 'modules/core/repository'; 2175 if ($platform->file_exists($oldDir)) { 2176 @$platform->recursiveRmDir($oldDir); 2177 } 2178 case '1.1.28': 2179 /* Added GalleryUrlGenerator::makeAbsoluteUrl() */ 2180 case '1.1.29': 2181 /* 2.2 Release Candidate 2! */ 2182 case '1.1.30': 2183 /* Reposition display_errors in config.php */ 2184 case '1.1.31': 2185 /* 2.2 Release! */ 2186 2187 case '1.2.0': 2188 case '1.2.0.x': 2189 /* Added GalleryCoreApi::getCodeBasePath */ 2190 2191 case '1.2.1': 2192 /* Add support for g2data/locale hierarchy */ 2193 $ret = $storage->checkPoint(); 2194 if ($ret) { 2195 return $ret; 2196 } 2197 foreach (array('module', 'theme') as $pluginType) { 2198 list ($ret, $pluginList[$pluginType]) = 2199 GalleryCoreApi::fetchPluginList($pluginType); 2200 if ($ret) { 2201 return $ret; 2202 } 2203 } 2204 2205 $totalOperations = count($pluginList['module']) + count($pluginList['theme']); 2206 $currentOperation = 0; 2207 $upgradingMessageText = $module->translate('Upgrading Plugin Translations'); 2208 foreach (array('module', 'theme') as $pluginType) { 2209 foreach ($pluginList[$pluginType] as $pluginId => $ignored) { 2210 $gallery->guaranteeTimeLimit(30); 2211 2212 $ret = $statusMonitor->renderStatusMessage( 2213 $upgradingMessageText, $pluginId, 2214 ++$currentOperation / $totalOperations); 2215 if ($ret) { 2216 return $ret; 2217 } 2218 2219 $ret = GalleryCoreApi::installTranslationsForPlugin($pluginType, $pluginId); 2220 if ($ret) { 2221 return $ret; 2222 } 2223 } 2224 } 2225 2226 $ret = $statusMonitor->renderStatusMessage($upgradingMessageText, '', 1); 2227 if ($ret) { 2228 return $ret; 2229 } 2230 2231 /* We might have lost our database connection so check and reconnect */ 2232 $ret = $storage->validateConnection(); 2233 if ($ret) { 2234 return $ret; 2235 } 2236 2237 case '1.2.2': 2238 /* Move modules/core/locale/ hierarchy into po/ */ 2239 case '1.2.3': 2240 /* Added template version number */ 2241 case '1.2.4': 2242 /* Increase allowed length of mime-type strings (mime type map) */ 2243 case '1.2.5': 2244 /* Expose smarty.compile_check flag as a new option and set the default to false */ 2245 $ret = $module->setParameter('smarty.compile_check', '0'); 2246 if ($ret) { 2247 return $ret; 2248 } 2249 case '1.2.6': 2250 /* Remove GalleryDataCache template-map */ 2251 $mapFile = $gallery->getConfig('data.gallery.cache') . 'theme/_all/templateMap.txt'; 2252 if ($platform->file_exists($mapFile)) { 2253 @$platform->unlink($mapFile); 2254 } 2255 case '1.2.7': 2256 /* Added the ability to set the maintenance mode programmatically. */ 2257 case '1.2.8': 2258 /* Changed the length of the SessionMap data field for mySql & DB2. */ 2259 $ret = $storage->configureStore($module->getId(), array('GallerySessionMap:1.0')); 2260 if ($ret) { 2261 return $ret; 2262 } 2263 case '1.2.9': 2264 /** 2265 * Added EventLogMap. A new G2 install will create this sequence in 2266 * GalleryStorage::configureStore. Here in an upgrade we call getUniqueId which will 2267 * create the sequence if it doesn't exist. Checkpoint first because the error that 2268 * leads to sequence creation may invalidate a pending transaction (postgres). 2269 */ 2270 $ret = $storage->checkPoint(); 2271 if ($ret) { 2272 return $ret; 2273 } 2274 list ($ret, $sequenceValue) = $storage->getUniqueId(DATABASE_SEQUENCE_EVENT_LOG); 2275 if ($ret) { 2276 return $ret; 2277 } 2278 case '1.2.10': 2279 /* Adding new $requiredEntityType parameter to all loadEntitiesById calls */ 2280 case '1.2.11': 2281 case '1.2.12': 2282 /* Remove database backup task from the admin maintenance screen */ 2283 case '1.2.13': 2284 /* 2285 * Adding PluginMap entries for all installed plugins. Until now, a plugin was said to 2286 * be installed (vs uninstalled) if the _version parameter is set. And PluginMap had a 2287 * rather undefined list of entries (at least all active plugins). 2288 */ 2289 list ($ret, $installedResults) = GalleryCoreApi::getMapEntry( 2290 'GalleryPluginParameterMap', 2291 array('pluginType', 'pluginId', 'parameterValue'), 2292 array('parameterName' => '_version', 'itemId' => 0)); 2293 if ($ret) { 2294 return $ret; 2295 } 2296 2297 list ($ret, $pluginResults) = GalleryCoreApi::getMapEntry('GalleryPluginMap', 2298 array('pluginType', 'pluginId')); 2299 if ($ret) { 2300 return $ret; 2301 } 2302 2303 $installedPlugins = $existingEntries = array(); 2304 while (($row = $pluginResults->nextResult()) !== false) { 2305 $existingEntries[$row[0]][$row[1]] = 1; 2306 } 2307 while (($row = $installedResults->nextResult()) !== false) { 2308 list ($pluginType, $pluginId, $installedVersion) = $row; 2309 if (empty($installedVersion) && isset($existingEntries[$pluginType][$pluginId])) { 2310 /* Remove entries of formerly installed but now uninstalled plugins */ 2311 $ret = GalleryCoreApi::removeMapEntry('GalleryPluginMap', 2312 array('pluginType' => $pluginType, 'pluginId' => $pluginId)); 2313 } else if (!empty($installedVersion) 2314 && !isset($existingEntries[$pluginType][$pluginId])) { 2315 $ret = GalleryCoreApi::addMapEntry('GalleryPluginMap', 2316 array('pluginType' => $pluginType, 'pluginId' => $pluginId, 'active' => 0)); 2317 } 2318 if ($ret) { 2319 return $ret; 2320 } 2321 } 2322 case '1.2.14': 2323 /* 2324 * Add a new column to the Schema table to store the creation sql for each table. This 2325 * change is to prepare the way for database export functionality. 2326 */ 2327 $gallery->guaranteeTimeLimit(30); 2328 2329 /* configureStore for Schema:1.0 removed; see code above switch ($currentVersion) */ 2330 2331 if ($currentVersion == '1.2.0.x' 2332 && version_compare($currentExactVersion, '1.2.0.2', '>=')) { 2333 /* Skip this for 1.2.0.2 or newer 1.2.0.x, as this upgrade was done in 2.2.2 */ 2334 $modules = array(); 2335 } else { 2336 list ($ret, $modules) = GalleryCoreApi::fetchPluginStatus('module', true); 2337 if ($ret) { 2338 return $ret; 2339 } 2340 2341 $storageExtras =& $storage->_getExtras(); 2342 2343 /* Load all table versions */ 2344 list ($ret, $tableVersions) = $storageExtras->_loadTableVersions(); 2345 if ($ret) { 2346 return $ret; 2347 } 2348 } 2349 2350 $count = 1; 2351 $total = count($modules); 2352 $statusText = $module->translate('Converting Schema Table'); 2353 2354 foreach ($modules as $moduleId => $moduleStatus) { 2355 /* Skip uninstalled/unavailable modules */ 2356 if (!isset($moduleStatus['active']) || empty($moduleStatus['available'])) { 2357 continue; 2358 } 2359 2360 $sql = $storageExtras->getModuleSql($moduleId); 2361 2362 if (empty($sql['table'])){ 2363 continue; 2364 } 2365 2366 foreach ($sql['table'] as $tableName => $tableSql) { 2367 list ($safeName, $unused, $nameInSchema) = 2368 $storage->_translateTableName($tableName); 2369 2370 if (!array_key_exists($nameInSchema, $tableVersions)) { 2371 continue; 2372 } 2373 2374 /* 2375 * Check if there is a pending alter for the table and skip if there is. 2376 * Column will be populated when/if that module is upgraded. 2377 */ 2378 list ($major, $minor) = $tableVersions[$nameInSchema]; 2379 if (!empty($sql['alter'][$tableName][$major][$minor])) { 2380 continue; 2381 } 2382 2383 $query = 'UPDATE [GallerySchema] SET [::createSql] = ? WHERE [::name] = ?'; 2384 $ret = $storage->execute($query, array($tableSql, $nameInSchema)); 2385 if ($ret) { 2386 return $ret; 2387 } 2388 $gallery->guaranteeTimeLimit(60); 2389 $ret = $statusMonitor->renderStatusMessage($statusText, '', $count / $total); 2390 if ($ret) { 2391 return $ret; 2392 } 2393 } 2394 2395 $ret = $statusMonitor->renderStatusMessage($statusText, '', $count++ / $total); 2396 if ($ret) { 2397 return $ret; 2398 } 2399 } 2400 case '1.2.15': 2401 /* Not used. */ 2402 case '1.2.16': 2403 /* Add database export task from the admin maintenance screen */ 2404 case '1.2.17': 2405 /* Store Entities.inc and Maps.inc definitions in the Schema table. */ 2406 $gallery->guaranteeTimeLimit(30); 2407 /* Remove _maps & _entities parameters from GalleryPluginParameterMap. See r16620 */ 2408 $query = 'DELETE FROM [GalleryPluginParameterMap] 2409 WHERE [::parameterName] in (\'_maps\', \'_entities\') 2410 AND [::pluginType] = \'module\''; 2411 $ret = $storage->execute($query); 2412 if ($ret) { 2413 return $ret; 2414 } 2415 /* This upgrade is done before the general upgrade code */ 2416 case '1.2.18': 2417 /* Remove unused derivative-meta cache files */ 2418 $statusText = $module->translate('Deleting old fast-download cache'); 2419 $basePath = $gallery->getConfig('data.gallery.cache') . 'derivative'; 2420 for ($i = 0; $i <= 9; $i++) { 2421 $ret = $statusMonitor->renderStatusMessage($statusText, '', $i / 10); 2422 if ($ret) { 2423 return $ret; 2424 } 2425 for ($j = 0; $j <= 9; $j++) { 2426 $gallery->guaranteeTimeLimit(120); 2427 $fileList = @$platform->glob("$basePath/$i/$j/*-meta.inc"); 2428 if ($fileList) { 2429 $gallery->guaranteeTimeLimit(120); 2430 $count = 0; 2431 foreach ($fileList as $file) { 2432 if (++$count % 100 == 0) { 2433 $gallery->guaranteeTimeLimit(120); 2434 $ret = $statusMonitor->renderStatusMessage($statusText, '', 2435 $i / 10 + $j / 100); 2436 if ($ret) { 2437 return $ret; 2438 } 2439 } 2440 @$platform->unlink($file); 2441 } 2442 } 2443 } 2444 } 2445 $ret = $statusMonitor->renderStatusMessage($statusText, '', 1); 2446 if ($ret) { 2447 return $ret; 2448 } 2449 2450 case '1.2.19': 2451 /* Use lightweight event system */ 2452 case '1.2.20': 2453 case '1.2.21': 2454 /* Added GalleryStorage::validateConnection */ 2455 case '1.2.22': 2456 /* Added GalleryCoreApi::registerFactoryImplementationForRequest */ 2457 case '1.2.23': 2458 /* Prevent web-access to files in the storage folder */ 2459 $fh = @fopen($gallery->getConfig('data.gallery.base') . '.htaccess', 'w'); 2460 if ($fh) { 2461 $htaccessContents = "DirectoryIndex .htaccess\n" . 2462 "SetHandler Gallery_Security_Do_Not_Remove\n" . 2463 "Options None\n" . 2464 "<IfModule mod_rewrite.c>\n" . 2465 "RewriteEngine off\n" . 2466 "</IfModule>\n" . 2467 "Order allow,deny\n" . 2468 "Deny from all\n"; 2469 fwrite($fh, $htaccessContents); 2470 fclose($fh); 2471 } 2472 case '1.2.24': 2473 /* Combined YUI libraries into a single file */ 2474 case '1.2.25': 2475 /* Added GalleryCoreApi::determineMimeType */ 2476 case '1.2.26': 2477 /* Combined javascript fix. Changed version number to force clearing of the cache */ 2478 case '1.2.27': 2479 /* Populate Plugin Map when a module is installed */ 2480 $ret = $storage->checkPoint(); 2481 if ($ret) { 2482 return $ret; 2483 } 2484 foreach (array('module', 'theme') as $pluginType) { 2485 list ($ret, $pluginList[$pluginType]) = 2486 GalleryCoreApi::fetchPluginList($pluginType); 2487 if ($ret) { 2488 return $ret; 2489 } 2490 } 2491 2492 $supportedLanguages = GalleryCoreApi::getSupportedLanguages(); 2493 $totalOperations = count($pluginList['module']) + count($pluginList['theme']); 2494 $currentOperation = 0; 2495 $upgradingMessageText = $module->translate('Creating Package Map'); 2496 2497 GalleryCoreApi::requireOnce('modules/core/classes/GalleryRepository.class'); 2498 if (!empty($repositories)) { 2499 $repository = array_pop($repositories); 2500 } else { 2501 $repository = new GalleryRepository(); 2502 $repository->init('bogus'); 2503 } 2504 2505 foreach (array('module', 'theme') as $pluginType) { 2506 foreach (array_keys($pluginList[$pluginType]) as $pluginId) { 2507 $gallery->guaranteeTimeLimit(30); 2508 2509 $ret = $statusMonitor->renderStatusMessage( 2510 $upgradingMessageText, $pluginId, ++$currentOperation / $totalOperations); 2511 if ($ret) { 2512 return $ret; 2513 } 2514 2515 $ret = $repository->scanPlugin($pluginType, $pluginId); 2516 if ($ret && !($ret->getErrorCode() & ERROR_STORAGE_FAILURE)) { 2517 if ($gallery->getDebug()) { 2518 $gallery->debug_r($ret); 2519 } 2520 } else if ($ret) { 2521 return $ret; 2522 } 2523 } 2524 } 2525 2526 $ret = $statusMonitor->renderStatusMessage($upgradingMessageText, '', 1); 2527 if ($ret) { 2528 return $ret; 2529 } 2530 2531 /* We might have lost our database connection so check and reconnect */ 2532 $ret = $storage->validateConnection(); 2533 if ($ret) { 2534 return $ret; 2535 } 2536 case '1.2.28': 2537 /* Language Manager Implementation */ 2538 case '1.2.29': 2539 /* GalleryCoreApi::fetchWebFile accepts post data and can use the POST method */ 2540 case '1.2.30': 2541 /* Implement Multipart request downloads for Language Manager */ 2542 case '1.2.31': 2543 /* Implement re-authentication for Site Admin Access */ 2544 $ret = $module->setParameter('session.siteAdministrationTimeout', 30 * 60); 2545 if ($ret) { 2546 return $ret; 2547 } 2548 case '1.2.32': 2549 /* Set the default baseUri in config.php */ 2550 case '1.2.33': 2551 case '1.2.34': 2552 /* Change the template compile directory to include the themeId */ 2553 case '1.2.35': 2554 /* R2.3 RC-1 */ 2555 case '1.2.36': 2556 /* R2.3 RC-2 */ 2557 case '1.2.37': 2558 /* R2.3 */ 2559 case '1.3.0': 2560 /* R2.3.1 R2.3.2*/ 2561 case '1.3.0.x': 2562 2563 case 'end of upgrade path': 2564 /* 2565 * Leave this bogus case at the end of the legitimate case statements so that we always 2566 * properly terminate our upgrade path with a break 2567 */ 2568 break; 2569 2570 default: 2571 $gallery->debug('Error: Unknown module version'); 2572 return GalleryCoreApi::error(ERROR_BAD_PLUGIN, __FILE__, __LINE__, 2573 sprintf('Unknown module version %s', $currentVersion)); 2574 } 2575 2576 $gallery->debug('Write new version to versions file'); 2577 $versionFile = $gallery->getConfig('data.gallery.version'); 2578 $versionDatError = 0; 2579 if ($fd = $platform->fopen($versionFile, 'wb')) { 2580 $data = sprintf("%s\n%s", 2581 $module->getVersion(), 2582 $module->getGalleryVersion()); 2583 if ($platform->fwrite($fd, $data) != strlen($data)) { 2584 $versionDatError = 1; 2585 } 2586 $platform->fclose($fd); 2587 } else { 2588 $versionDatError = 1; 2589 } 2590 2591 if ($versionDatError) { 2592 $gallery->debug('Error: Can\'t write to versions file'); 2593 return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__, 2594 'Can\'t write to the versions file'); 2595 } 2596 2597 return null; 2598 } 2599 2600 /** 2601 * Determine what changes to config.php are required for this upgrade. 2602 * 2603 * @param string $currentVersion current core version 2604 * @return array of array('remove' => array of string regexp removals, 2605 * 'add' => array of string additions) 2606 * @access private 2607 */ 2608 function _prepareConfigUpgrade($currentVersion) { 2609 global $gallery; 2610 $configChanges = array(); 2611 2612 /* Enable upgrade from any patch release of earlier versions */ 2613 $currentVersion = preg_replace('/^(1\.[0-3]\.0)\.\d+$/', '$1.x', $currentVersion); 2614 2615 /** 2616 * README: How to update the block below 2617 * 2618 * If you add a new feature to the core module and revise the version, you should do the 2619 * following. Supposing the current version is 1.0.1 and you're adding 1.0.2. Go to the 2620 * end of the switch and find the 'end of upgrade path' case. Create a new case *above* 2621 * that one with the old version number. For our example you'd add: "case '1.0.1':" and 2622 * then your code. Do *not* put in a break statement. (Update upgrade function too). 2623 */ 2624 switch ($currentVersion) { 2625 case '0.8.4': 2626 case '0.8.5': 2627 case '0.8.6': 2628 case '0.8.7': 2629 case '0.8.8': 2630 case '0.8.9': 2631 case '0.8.10': 2632 case '0.8.11': 2633 case '0.8.12': 2634 case '0.8.13': 2635 case '0.8.14': 2636 case '0.8.15': 2637 case '0.8.16': 2638 case '0.8.17': 2639 case '0.9.0': 2640 case '0.9.1': 2641 case '0.9.2': 2642 case '0.9.3': 2643 case '0.9.4': 2644 case '0.9.5': 2645 case '0.9.6': 2646 case '0.9.7': 2647 case '0.9.8': 2648 case '0.9.9': 2649 case '0.9.10': 2650 case '0.9.11': 2651 case '0.9.12': 2652 case '0.9.13': 2653 case '0.9.14': 2654 case '0.9.15': 2655 case '0.9.16': 2656 case '0.9.17': 2657 case '0.9.18': 2658 case '0.9.19': 2659 $add = array(); 2660 if (!isset($gallery->_config['allowSessionAccess'])) { 2661 /* 2662 * This item was added to config.php before config.php upgrades were supported. Add 2663 * it only if not already present. 2664 */ 2665 $add[] = 2666'/* 2667 * Allow a particular IP address to access the session (it still must know the 2668 * session id) even though it doesn\'t match the address/user agent that created 2669 * the session. Put the address of validator.w3.org (\'128.30.52.13\') here to allow 2670 * validation of non-public Gallery pages from the links at the bottom of the page. 2671 */ 2672$gallery->setConfig(\'allowSessionAccess\', false); 2673'; 2674 } 2675 2676 $add[] = 2677'/* 2678 * URL of Gallery codebase; required only for multisite install. 2679 */ 2680$gallery->setConfig(\'galleryBaseUrl\', \'\'); 2681'; 2682 2683 $configChanges[] = array( 2684 'remove' => array('{/\*[^/]*\*/\s*\$gallery->setConfig\(\'galleryId\',.*?;\s*}s'), 2685 'add' => $add, 'edit' => array()); 2686 2687 case '0.9.20': 2688 case '0.9.21': 2689 $add = array(); 2690 2691 /* Generate cookieId */ 2692 list ($usec, $sec) = explode(" ", microtime()); 2693 $cookieId = substr(md5(rand()), 0, 6); 2694 2695 $add[] = 2696' 2697/* 2698 * Set the name for Gallery session cookies. The name of the session cookie is 2699 * a concatenation of \'GALLERYSID_\' and cookieId, which is randomly generated 2700 * at Gallery installation time. You can change cookieId at any time, but if 2701 * you change it be aware of two things: 2702 * 1. Users have to login again after the change. They lose their old session. 2703 * 2. If multiple Gallery installs are running on the same domain (in different paths or 2704 * different subdomains) choose cookieId such that it is different for all Gallery 2705 * installs on the same domain. 2706 */ 2707$gallery->setConfig(\'cookieId\', \'' . $cookieId . '\'); 2708'; 2709 $configChanges[] = array('remove' => array(), 'add' => $add, 'edit' => array()); 2710 2711 case '0.9.22': 2712 case '0.9.23': 2713 /* Session cookie change, revert the last change and try something new */ 2714 $configChanges[] = array( 2715 'remove' => array('{/\*[^/]*\*/\s*\$gallery->setConfig\(\'cookieId\',.*?;\s*}s'), 2716 'add' => array(), 'edit' => array()); 2717 2718 case '0.9.24': 2719 case '0.9.25': 2720 case '0.9.26': 2721 case '0.9.27': 2722 case '0.9.28': 2723 case '0.9.29': 2724 case '0.9.30': 2725 case '0.9.31': 2726 case '0.9.32': 2727 case '0.9.33': 2728 case '0.9.34': 2729 case '0.9.35': 2730 case '0.9.36': 2731 case '0.9.37': 2732 case '1.0.0': 2733 case '1.0.0.x': 2734 case '1.0.1': 2735 case '1.0.2': 2736 case '1.0.3': 2737 2738 case '1.0.4': 2739 $configChanges[] = array('remove' => array(), 'edit' => array(), 'add' => array( 2740' 2741/* 2742 * Maintenance mode. You can disable access to the site for anyone but 2743 * site administrators by setting this this flag. Set value below to: 2744 * true (without quotes) - to use a basic notification page; themed 2745 * view with admin login link when codebase is up to date, but a 2746 * plain unstyled page when codebase has been updated but upgrader 2747 * has not yet been run. 2748 * url (with quotes) - provide a URL where requests are redirected in 2749 * either case described above. Example: \'/maintenance.html\' 2750 */ 2751$gallery->setConfig(\'mode.maintenance\', false); 2752')); 2753 2754 case '1.0.5': 2755 case '1.0.6': 2756 case '1.0.7': 2757 case '1.0.8': 2758 case '1.0.9': 2759 case '1.0.10': 2760 case '1.0.11': 2761 case '1.0.12': 2762 case '1.0.13': 2763 /* Add config parameter: 'baseUri' */ 2764 $configChanges[] = array('remove' => array(), 'edit' => array(), 'add' => array( 2765' 2766/* 2767 * This setting can be used to override Gallery\'s auto-detection of the domain-name, 2768 * protocol (http/https), URL path, and of the file & query string. 2769 * Most users can leave this empty. If the server is misconfigured or for very special 2770 * setups, this setting can be quite handy. 2771 * Examples (the positions of the slashes (\'/\') are important): 2772 * override the path: $gallery->setConfig(\'baseUri\', \'/another/path/\'); 2773 * override the host + path: $gallery->setConfig(\'baseUri\', \'example.com/gallery2/\'); 2774 * override the protocol + host + path + file: 2775 * $gallery->setConfig(\'baseUri\', \'https://example.com:8080/gallery2/index.php\'); 2776 */ 2777$gallery->setConfig(\'baseUri\', \'\');')); 2778 2779 case '1.0.14': 2780 case '1.0.15': 2781 /* 2782 * Normalize the config path 'data.gallery.base' (add a trailing slash if necessary). 2783 * Escape the backslashes and quotes two times since we feed preg_replace with it. 2784 */ 2785 $edit = array(); 2786 $tmp = strtr($gallery->getConfig('data.gallery.base'), 2787 array('\\' => '\\\\\\\\', "'" => "\\\\'")); 2788 $edit['regexp'] = '{\$gallery->setConfig\(\'data\.gallery\.base\',.*?;}s'; 2789 $edit['replacement'] = '$gallery->setConfig(\'data.gallery.base\', \'' . $tmp . '\');'; 2790 $configChanges[] = array('remove' => array(), 'add' => array(), 'edit' => array($edit)); 2791 case '1.0.16': 2792 case '1.0.17': 2793 case '1.0.18': 2794 case '1.0.19': 2795 case '1.0.20': 2796 case '1.0.21': 2797 case '1.0.22': 2798 case '1.0.23': 2799 case '1.0.24': 2800 case '1.0.25': 2801 case '1.0.26': 2802 case '1.0.27': 2803 case '1.0.28': 2804 case '1.0.29': 2805 case '1.0.30': 2806 case '1.0.31': 2807 case '1.0.32': 2808 case '1.0.33': 2809 case '1.0.34': 2810 case '1.1.0': 2811 case '1.1.0.x': 2812 case '1.1.1': 2813 case '1.1.2': 2814 case '1.1.3': 2815 case '1.1.4': 2816 case '1.1.5': 2817 case '1.1.6': 2818 case '1.1.7': 2819 case '1.1.8': 2820 case '1.1.9': 2821 case '1.1.10': 2822 case '1.1.11': 2823 case '1.1.12': 2824 case '1.1.13': 2825 case '1.1.14': 2826 case '1.1.15': 2827 case '1.1.16': 2828 case '1.1.17': 2829 case '1.1.18': 2830 /* Originally added PHP display_errors setting in this step, but at the end. */ 2831 case '1.1.19': 2832 case '1.1.20': 2833 case '1.1.21': 2834 case '1.1.22': 2835 case '1.1.23': 2836 case '1.1.24': 2837 case '1.1.25': 2838 case '1.1.26': 2839 /* 2840 * Prevent PHP from showing errors on direct access to config.php by adding a check 2841 * for the $gallery object before the first setConfig() call. 2842 */ 2843 $edit = array(); 2844 $edit['regexp'] = '{(<\?php\s*(?:/\*.*?\*/\s*)?)}s'; 2845 $edit['replacement'] = '\1/* 2846 * Prevent direct access to config.php. 2847 */ 2848if (!isset($gallery) || !method_exists($gallery, \'setConfig\')) { 2849 exit; 2850} 2851 2852'; 2853 $configChanges[] = array('remove' => array(), 'add' => array(), 'edit' => array($edit)); 2854 case '1.1.27': 2855 case '1.1.28': 2856 case '1.1.29': 2857 case '1.1.30': 2858 /* Reposition display_errors from the end to the beginning of the config file. */ 2859 $remove = array('{/\*[^/]*\*/\s*\@?ini_set\(\'display_errors\',.*?;\s*}s'); 2860 $edit = array(); 2861 $edit['regexp'] = '{(<\?php\s*(?:/\*.*?\*/\s*)?)}s'; 2862 $edit['replacement'] = '\1/* 2863 * When display_errors is enabled, PHP errors are printed to the output. 2864 * For production web sites, you\'re strongly encouraged to turn this feature off, 2865 * and use error logging instead. 2866 * During development, you should set the value to 1 to ensure that you notice PHP 2867 * warnings and notices that are not covered in unit tests (e.g. template issues). 2868 */ 2869@ini_set(\'display_errors\', 0); 2870 2871'; 2872 $configChanges[] = array('remove' => $remove, 'add' => array(), 'edit' => array($edit)); 2873 case '1.1.31': 2874 case '1.2.0': 2875 case '1.2.0.x': 2876 case '1.2.1': 2877 case '1.2.2': 2878 case '1.2.3': 2879 case '1.2.4': 2880 case '1.2.5': 2881 case '1.2.6': 2882 case '1.2.7': 2883 case '1.2.8': 2884 case '1.2.9': 2885 case '1.2.10': 2886 case '1.2.11': 2887 case '1.2.12': 2888 case '1.2.13': 2889 case '1.2.14': 2890 case '1.2.15': 2891 case '1.2.16': 2892 case '1.2.17': 2893 case '1.2.18': 2894 case '1.2.19': 2895 case '1.2.20': 2896 case '1.2.21': 2897 case '1.2.22': 2898 case '1.2.23': 2899 case '1.2.24': 2900 case '1.2.25': 2901 case '1.2.26': 2902 case '1.2.27': 2903 case '1.2.28': 2904 case '1.2.29': 2905 case '1.2.30': 2906 case '1.2.31': 2907 case '1.2.32': 2908 /* Change the baseUri if it's not set. */ 2909 $urlGenerator =& $gallery->getUrlGenerator(); 2910 $urlPath = preg_replace('|^(.*/)upgrade/index.php.*$|s', '$1', 2911 $urlGenerator->getCurrentUrl()) . GALLERY_MAIN_PHP; 2912 $edit = array(); 2913 $edit['regexp'] = '{\$gallery->setConfig\(\'baseUri\', \'\'\);}s'; 2914 $edit['replacement'] = '$gallery->setConfig(\'baseUri\', \'' . $urlPath . '\');'; 2915 $configChanges[] = array('remove' => array(), 'add' => array(), 'edit' => array($edit)); 2916 case '1.2.33': 2917 case '1.2.34': 2918 case '1.2.35': 2919 case '1.2.36': 2920 case '1.2.37': 2921 case '1.3.0': 2922 case '1.3.0.x': 2923 2924 case 'end of upgrade path': 2925 /* 2926 * Leave this bogus case at the end of the legitimate case statements so that we always 2927 * properly terminate our upgrade path with a break 2928 */ 2929 break; 2930 2931 default: 2932 $gallery->debug("Unknown module version $currentVersion in prepareConfigUpgrade()"); 2933 } 2934 2935 return $configChanges; 2936 } 2937 2938 /** 2939 * Check if any changes to config.php are required for this upgrade. 2940 * 2941 * @param string $currentVersion current core version 2942 * @return boolean true if change is required 2943 */ 2944 function isConfigUpgradeRequired($currentVersion) { 2945 $configChanges = CoreModuleExtras::_prepareConfigUpgrade($currentVersion); 2946 return !empty($configChanges); 2947 } 2948 2949 /** 2950 * Perform upgrade of config.php file. 2951 * 2952 * @param string $currentVersion current core version 2953 * @return GalleryStatus a status code 2954 */ 2955 function performConfigUpgrade($currentVersion) { 2956 global $gallery; 2957 $platform =& $gallery->getPlatform(); 2958 2959 $configFilePath = GALLERY_CONFIG_DIR . '/config.php'; 2960 $configContents = implode('', $platform->file($configFilePath)); 2961 if (empty($configContents) || strlen($configContents) < 100) { 2962 return GalleryCoreApi::error(ERROR_MISSING_VALUE, __FILE__, __LINE__, 2963 'Unable to read current config.php contents'); 2964 } 2965 2966 $configChanges = CoreModuleExtras::_prepareConfigUpgrade($currentVersion); 2967 foreach ($configChanges as $change) { 2968 /* preg_replace $count param is only PHP 5.1.0+ */ 2969 foreach ($change['remove'] as $regexp) { 2970 $configContents = preg_replace($regexp, '', $old = $configContents); 2971 if ($configContents == $old) { 2972 $gallery->debug('Warning: config.php remove pattern not matched: ' . $regexp); 2973 } 2974 } 2975 foreach ($change['edit'] as $edit) { 2976 $configContents = 2977 preg_replace($edit['regexp'], $edit['replacement'], $old = $configContents); 2978 if ($configContents == $old) { 2979 $gallery->debug( 2980 'Warning: config.php edit pattern not matched: ' . $edit['regexp']); 2981 } 2982 } 2983 foreach ($change['add'] as $content) { 2984 $configContents = 2985 preg_replace('{\?>\s*\z}', $content . "\n?>\n", $old = $configContents); 2986 if ($configContents == $old) { 2987 $gallery->debug( 2988 'Warning: config.php add pattern not matched, appending to file instead'); 2989 $configContents .= "\n" . $content . "\n?>\n"; 2990 } 2991 } 2992 } 2993 2994 if (!$out = $platform->fopen($configFilePath, 'w')) { 2995 return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__, 2996 'Unable to write to config.php'); 2997 } 2998 if ($platform->fwrite($out, $configContents) < strlen($configContents)) { 2999 return GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__, 3000 'Unable to write config.php contents'); 3001 } 3002 $platform->fclose($out); 3003 3004 return null; 3005 } 3006 3007 /** 3008 * Create the initial all users group. 3009 * 3010 * @param GalleryModule $module the core module 3011 * @return GalleryStatus a status code 3012 */ 3013 function _createAllUsersGroup($module) { 3014 global $gallery; 3015 3016 list ($ret, $id) = $module->getParameter('id.allUserGroup'); 3017 if ($ret) { 3018 return $ret; 3019 } 3020 3021 if (!empty($id)) { 3022 return null; 3023 } 3024 3025 GalleryCoreApi::requireOnce('modules/core/classes/GalleryGroup.class'); 3026 $group = new GalleryGroup(); 3027 3028 $groupName = $module->translate('Registered Users'); 3029 $ret = $group->create($groupName, GROUP_ALL_USERS); 3030 if ($ret) { 3031 return $ret; 3032 } 3033 3034 $ret = $group->save(); 3035 if ($ret) { 3036 return $ret; 3037 } 3038 3039 $ret = $module->setParameter('id.allUserGroup', $group->getId()); 3040 if ($ret) { 3041 return $ret; 3042 } 3043 3044 return null; 3045 } 3046 3047 /** 3048 * Create the site admins group. 3049 * 3050 * @param GalleryModule $module the core module 3051 * @return GalleryStatus a status code 3052 */ 3053 function _createSiteAdminsGroup($module) { 3054 global $gallery; 3055 3056 list ($ret, $id) = $module->getParameter('id.adminGroup'); 3057 if ($ret) { 3058 return $ret; 3059 } 3060 3061 if (!empty($id)) { 3062 return null; 3063 } 3064 3065 GalleryCoreApi::requireOnce('modules/core/classes/GalleryGroup.class'); 3066 $group = new GalleryGroup(); 3067 3068 $groupName = $module->translate('Site Admins'); 3069 $ret = $group->create($groupName, GROUP_SITE_ADMINS); 3070 if ($ret) { 3071 return $ret; 3072 } 3073 3074 $ret = $group->save(); 3075 if ($ret) { 3076 return $ret; 3077 } 3078 3079 $ret = $module->setParameter('id.adminGroup', $group->getId()); 3080 if ($ret) { 3081 return $ret; 3082 } 3083 3084 return null; 3085 } 3086 3087 /** 3088 * Create the everybody group. 3089 * 3090 * @param GalleryModule $module the core module 3091 * @return GalleryStatus a status code 3092 */ 3093 function _createEverybodyGroup($module) { 3094 global $gallery; 3095 3096 list ($ret, $id) = $module->getParameter('id.everybodyGroup'); 3097 if ($ret) { 3098 return $ret; 3099 } 3100 3101 if (!empty($id)) { 3102 return null; 3103 } 3104 3105 GalleryCoreApi::requireOnce('modules/core/classes/GalleryGroup.class'); 3106 $group = new GalleryGroup(); 3107 3108 $groupName = $module->translate('Everybody'); 3109 $ret = $group->create($groupName, GROUP_EVERYBODY); 3110 if ($ret) { 3111 return $ret; 3112 } 3113 3114 $ret = $group->save(); 3115 if ($ret) { 3116 return $ret; 3117 } 3118 3119 $ret = $module->setParameter('id.everybodyGroup', $group->getId()); 3120 if ($ret) { 3121 return $ret; 3122 } 3123 3124 return null; 3125 } 3126 3127 /** 3128 * Create the initial anonymous user. 3129 * 3130 * @param GalleryModule $module the core module 3131 * @return GalleryStatus a status code 3132 */ 3133 function _createAnonymousUser($module) { 3134 global $gallery; 3135 3136 list ($ret, $id) = $module->getParameter('id.anonymousUser'); 3137 if ($ret) { 3138 return $ret; 3139 } 3140 3141 if (!empty($id)) { 3142 return null; 3143 } 3144 3145 GalleryCoreApi::requireOnce('modules/core/classes/GalleryUser.class'); 3146 $user = new GalleryUser(); 3147 3148 $userName = 'guest'; 3149 $fullName = $module->translate('Guest'); 3150 $ret = $user->create($userName); 3151 if ($ret) { 3152 return $ret; 3153 } 3154 $user->setFullName($fullName); 3155 $user->changePassword(''); 3156 3157 $ret = $user->save(); 3158 if ($ret) { 3159 return $ret; 3160 } 3161 3162 /* Remove the anonymous user from the Everybody group */ 3163 list ($ret, $allUserGroupId) = $module->getParameter('id.allUserGroup'); 3164 if ($ret) { 3165 return $ret; 3166 } 3167 $ret = GalleryCoreApi::removeUserFromGroup($user->getId(), $allUserGroupId); 3168 if ($ret) { 3169 return $ret; 3170 } 3171 3172 $ret = $module->setParameter('id.anonymousUser', $user->getId()); 3173 if ($ret) { 3174 return $ret; 3175 } 3176 3177 return null; 3178 } 3179 3180 /** 3181 * Create the initial admin user. 3182 * 3183 * @param GalleryModule $module the core module 3184 * @return GalleryStatus a status code 3185 */ 3186 function _createAdminUser($module) { 3187 global $gallery; 3188 3189 /* Don't create if there is already a user in the admin group */ 3190 list ($ret, $adminGroupId) = $module->getParameter('id.adminGroup'); 3191 if ($ret) { 3192 return $ret; 3193 } 3194 3195 list ($ret, $results) = GalleryCoreApi::fetchUsersForGroup($adminGroupId); 3196 if ($ret) { 3197 return $ret; 3198 } 3199 3200 if (sizeof($results) > 0) { 3201 return null; 3202 } 3203 3204 GalleryCoreApi::requireOnce('modules/core/classes/GalleryUser.class'); 3205 $user = new GalleryUser(); 3206 3207 /* 3208 * Get the admin name and data from the installer and default to 'admin' if it's not 3209 * available for some reason 3210 */ 3211 $userName = $gallery->getConfig('setup.admin.userName'); 3212 $userName = !strlen($userName) ? 'admin' : $userName; 3213 $email = $gallery->getConfig('setup.admin.email'); 3214 $fullName = $gallery->getConfig('setup.admin.fullName'); 3215 $ret = $user->create($userName); 3216 if ($ret) { 3217 return $ret; 3218 } 3219 $user->changePassword($gallery->getConfig('setup.password')); 3220 $user->setFullName($fullName); 3221 $user->setEmail($email); 3222 3223 $ret = $user->save(); 3224 if ($ret) { 3225 return $ret; 3226 } 3227 3228 /* Add her to the admin group */ 3229 $ret = GalleryCoreApi::addUserToGroup($user->getId(), $adminGroupId); 3230 if ($ret) { 3231 return $ret; 3232 } 3233 3234 /* 3235 * The rest of the bootstrap code won't work so well unless we're logged in, so log in as 3236 * the admin user now 3237 */ 3238 $gallery->setActiveUser($user); 3239 3240 return null; 3241 } 3242 3243 /** 3244 * Create the root album item. 3245 * 3246 * @param GalleryModule $module the core module 3247 * @return GalleryStatus a status code 3248 */ 3249 function _createRootAlbumItem($module) { 3250 global $gallery; 3251 3252 /* Do we already have a root? */ 3253 list ($ret, $rootAlbumId) = $module->getParameter('id.rootAlbum'); 3254 if ($rootAlbumId) { 3255 return null; 3256 } 3257 3258 GalleryCoreApi::requireOnce('modules/core/classes/GalleryAlbumItem.class'); 3259 $album = new GalleryAlbumItem(); 3260 3261 $ret = $album->createRoot(); 3262 if ($ret) { 3263 return $ret; 3264 } 3265 $title = $module->translate('Gallery'); 3266 $description = $module->translate('This is the main page of your Gallery'); 3267 $album->setTitle($title); 3268 $album->setDescription($description); 3269 3270 $ret = $album->save(); 3271 if ($ret) { 3272 return $ret; 3273 } 3274 3275 /* Give everybody some permissions */ 3276 list ($ret, $groupId) = $module->getParameter('id.everybodyGroup'); 3277 if ($ret) { 3278 return $ret; 3279 } 3280 3281 $ret = GalleryCoreApi::addGroupPermission($album->getId(), $groupId, 'core.viewAll'); 3282 if ($ret) { 3283 return $ret; 3284 } 3285 3286 /* Grant admin users everything */ 3287 list ($ret, $groupId) = $module->getParameter('id.adminGroup'); 3288 if ($ret) { 3289 return $ret; 3290 } 3291 3292 $ret = GalleryCoreApi::addGroupPermission($album->getId(), $groupId, 'core.all'); 3293 if ($ret) { 3294 return $ret; 3295 } 3296 3297 $ret = $module->setParameter('id.rootAlbum', $album->getId()); 3298 if ($ret) { 3299 return $ret; 3300 } 3301 3302 return null; 3303 } 3304 3305 /** 3306 * Create the access list compactor lock entity. 3307 * 3308 * @param GalleryModule $module the core module 3309 * @return GalleryStatus a status code 3310 */ 3311 function _createAccessListCompacterLock($module) { 3312 global $gallery; 3313 3314 /* Do we already have a root? */ 3315 list ($ret, $compacterLockId) = $module->getParameter('id.accessListCompacterLock'); 3316 if ($compacterLockId) { 3317 return null; 3318 } 3319 3320 GalleryCoreApi::requireOnce('modules/core/classes/GalleryEntity.class'); 3321 $lock = new GalleryEntity(); 3322 $lock->create(); 3323 $ret = $lock->save(false); 3324 if ($ret) { 3325 return $ret; 3326 } 3327 3328 $ret = $module->setParameter('id.accessListCompacterLock', $lock->getId()); 3329 if ($ret) { 3330 return $ret; 3331 } 3332 3333 return null; 3334 } 3335 3336 /** 3337 * @see GalleryModule::performFactoryRegistrations 3338 */ 3339 function performFactoryRegistrations($module) { 3340 /* Register all our factory implementations */ 3341 $regs[] = array('GalleryEntity', 'GalleryEntity', 'class', null); 3342 $regs[] = array('GalleryEntity', 'GalleryChildEntity', 'class', null); 3343 $regs[] = array('GalleryEntity', 'GalleryAlbumItem', 'class', null); 3344 $regs[] = array('GalleryEntity', 'GalleryUser', 'class', null); 3345 $regs[] = array('GalleryEntity', 'GalleryGroup', 'class', null); 3346 $regs[] = array('GalleryEntity', 'GalleryDerivative', 'class', null); 3347 $regs[] = array('GalleryEntity', 'GalleryDerivativeImage', 'class', null); 3348 $regs[] = array('GalleryDerivative', 'GalleryDerivativeImage', 'class', array('*')); 3349 $regs[] = array('GalleryEntity', 'GalleryMovieItem', 'class', null); 3350 $regs[] = array('GalleryEntity', 'GalleryAnimationItem', 'class', null); 3351 $regs[] = array('GalleryEntity', 'GalleryPhotoItem', 'class', null); 3352 $regs[] = array('GalleryEntity', 'GalleryUnknownItem', 'class', null); 3353 $regs[] = array('GalleryItem', 'GalleryPhotoItem', 'class', 3354 array('image/*', 'application/photoshop')); 3355 $regs[] = array('GalleryItem', 'GalleryMovieItem', 'class', array('video/*')); 3356 $regs[] = array('GalleryItem', 'GalleryAnimationItem', 'class', 3357 array('application/x-director', 'application/x-shockwave-flash')); 3358 $regs[] = array('GalleryItem', 'GalleryUnknownItem', 'class', array('*')); 3359 $regs[] = array('GalleryDynamicAlbum', 'GalleryDynamicAlbum', 'class', null); 3360 $regs[] = array('GallerySearchInterface_1_0', 'GalleryCoreSearch', 'class', null); 3361 $regs[] = array('ItemEditPlugin', 'ItemEditItem', 'inc', null, 1); 3362 $regs[] = array('ItemEditPlugin', 'ItemEditAnimation', 'inc', null, 2); 3363 $regs[] = array('ItemEditPlugin', 'ItemEditMovie', 'inc', null, 2); 3364 $regs[] = array('ItemEditPlugin', 'ItemEditAlbum', 'inc', null, 2); 3365 $regs[] = array('ItemEditPlugin', 'ItemEditTheme', 'inc', null, 3); 3366 $regs[] = array('ItemEditPlugin', 'ItemEditPhoto', 'inc', null, 2); 3367 $regs[] = array('ItemEditPlugin', 'ItemEditRotateAndScalePhoto', 'inc', null, 3); 3368 $regs[] = array('ItemEditPlugin', 'ItemEditPhotoThumbnail', 'inc', null, 4); 3369 $regs[] = array('ItemAddPlugin', 'ItemAddFromBrowser', 'inc', null, 2); 3370 $regs[] = array('ItemAddOption', 'CreateThumbnailOption', 'inc', null, 8); 3371 $regs[] = array('MaintenanceTask', 'OptimizeDatabaseTask', 'class', null); 3372 $regs[] = array('MaintenanceTask', 'DatabaseBackupTask', 'class', null); 3373 $regs[] = array('MaintenanceTask', 'FlushTemplatesTask', 'class', null); 3374 $regs[] = array('MaintenanceTask', 'FlushDatabaseCacheTask', 'class', null); 3375 $regs[] = array('MaintenanceTask', 'BuildDerivativesTask', 'class', null); 3376 $regs[] = array('MaintenanceTask', 'ResetViewCountsTask', 'class', null); 3377 $regs[] = array('MaintenanceTask', 'SystemInfoTask', 'class', null); 3378 $regs[] = array('MaintenanceTask', 'SetOriginationTimestampTask', 'class', null); 3379 $regs[] = array('MaintenanceTask', 'DeleteSessionsTask', 'class', null); 3380 $regs[] = array('MaintenanceTask', 'ConvertDatabaseToUtf8Task', 'class', null); 3381 $regs[] = array('CaptchaAdminOption', 'CoreCaptchaAdminOption', 'class', null); 3382 3383 /* 3384 * Unlike other modules, the core module doesn't get deactivated so its factory 3385 * registrations may still be around from before. Unregister them now before reregistering 3386 * them all. 3387 */ 3388 $ret = GalleryCoreApi::unregisterFactoryImplementationsByModuleId($module->getId()); 3389 if ($ret) { 3390 return $ret; 3391 } 3392 3393 foreach ($regs as $entry) { 3394 $ret = GalleryCoreApi::registerFactoryImplementation($entry[0], 3395 $entry[1], $entry[1], $entry[2] == 'class' 3396 ? 'modules/core/classes/' . $entry[1] . '.class' 3397 : 'modules/core/' . $entry[1] . '.inc', 3398 'core', $entry[3], isset($entry[4]) ? $entry[4] : 4); 3399 if ($ret) { 3400 return $ret; 3401 } 3402 } 3403 3404 /* Special cases */ 3405 $ret = GalleryCoreApi::registerFactoryImplementation('GalleryAuthPlugin', 3406 'SessionAuthPlugin', 'SessionAuthPlugin', 3407 'modules/core/classes/GallerySession.class', 'core', null, 4); 3408 if ($ret) { 3409 return $ret; 3410 } 3411 3412 $ret = GalleryCoreApi::registerFactoryImplementation('GalleryEventListener', 3413 'GalleryItemHelper_medium', 'GalleryItemHelper_medium', 3414 'modules/core/classes/helpers/GalleryItemHelper_medium.class', 'core', 3415 array('Gallery::ViewableTreeChange', 3416 'Gallery::RemovePermission', 3417 'GalleryEntity::save', 3418 'GalleryEntity::delete'), 4); 3419 if ($ret) { 3420 return $ret; 3421 } 3422 3423 $ret = GalleryCoreApi::registerFactoryImplementation('GalleryEventListener', 3424 'GalleryUserHelper_medium', 'GalleryUserHelper_medium', 3425 'modules/core/classes/helpers/GalleryUserHelper_medium.class', 'core', 3426 array('Gallery::FailedLogin', 3427 'Gallery::Login'), 4); 3428 if ($ret) { 3429 return $ret; 3430 } 3431 3432 return null; 3433 } 3434 3435 /** 3436 * Change character set encoding to utf 8 for MySQL if necessary. This is public because it 3437 * is also used by ConvertDatabaseToUtf8Task. 3438 * 3439 * @return array GalleryStatus a status code 3440 * bool true if any conversions took place 3441 * @access public 3442 */ 3443 function convertCharacterSetToUtf8($module, $statusMonitor) { 3444 global $gallery; 3445 $storage =& $gallery->getStorage(); 3446 $converted = false; 3447 3448 if ($storage->getType() == 'mysql') { 3449 $version = $storage->getVersion(); 3450 /* MySQL < 4.1.0 does not support UTF8 */ 3451 if ($version && version_compare($version, '4.1.0', '>=')) { 3452 /* 3453 * Check if the database uses UTF8 already, by looking at the Schema table, which 3454 * we convert last. 3455 */ 3456 list ($ret, $results) = 3457 $storage->search('SHOW CREATE TABLE `' . $storage->_tablePrefix . 'Schema`'); 3458 if ($ret) { 3459 return array($ret, null); 3460 } 3461 $row = $results->nextResult(); 3462 $result = $row[1]; 3463 if (!$result || !preg_match('/utf8/i', $result)) { 3464 /* Convert all existing tables to UTF-8 */ 3465 $ret = $statusMonitor->renderStatusMessage( 3466 $module->translate('Converting MySQL data to UTF8'), null, 0); 3467 if ($ret) { 3468 return array($ret, null); 3469 } 3470 $gallery->guaranteeTimeLimit(120); 3471 $storageExtras =& $storage->_getExtras(); 3472 list ($ret, $tableVersions) = $storageExtras->_loadTableVersions(); 3473 if ($ret) { 3474 return array($ret, null); 3475 } 3476 $types = array('varchar' => 'varbinary', 3477 'text' => 'blob', 3478 'longtext' => 'longblob'); 3479 $i = 0; 3480 3481 foreach ($tableVersions as $tableName => $unused) { 3482 $i++; 3483 $tableName = $storage->_tablePrefix . $tableName; 3484 /* First the table itself */ 3485 $query = "ALTER TABLE `$tableName` DEFAULT CHARACTER SET utf8"; 3486 $ret = $storage->execute($query); 3487 if ($ret) { 3488 return array($ret, null); 3489 } 3490 /* 3491 * Then all character/string columns 3492 * See: http://dev.mysql.com/doc/refman/4.1/en/charset-conversion.html 3493 * 3494 * The following code is based significantly on code from Drupal, 3495 * For details, refer to: 3496 * - http://api.drupal.org/api/4.7/file/update.php/source 3497 * - http://api.drupal.org/api/4.7/file/LICENSE.txt 3498 * - http://drupal.org/node/40515 3499 * 3500 * Drupal is licensed under the GPL: 3501 * 3502 * 1. Detect current column attributes 3503 * 2. Convert text column to binary column 3504 * 3. Convert them to character/text columns with UTF8 charset 3505 */ 3506 $query = "SHOW FULL COLUMNS FROM `$tableName`"; 3507 $originalFetchMode = $storage->_db->SetFetchMode(ADODB_FETCH_ASSOC); 3508 list ($ret, $results) = $storage->search($query); 3509 if ($ret) { 3510 return array($ret, null); 3511 } 3512 $storage->_db->SetFetchMode($originalFetchMode); 3513 $changeToBinary = $changeToUtf8 = array(); 3514 while ($column = $results->nextResult()) { 3515 list ($type) = explode('(', $column['Type']); 3516 if (!isset($types[$type])) { 3517 continue; 3518 } 3519 $change = 3520 'CHANGE `' . $column['Field'] . '` `' . $column['Field'] . '` '; 3521 $binaryType = preg_replace('/'. $type .'/i', $types[$type], 3522 $column['Type']); 3523 $attributes = ' '; 3524 if ($column['Default'] == 'NULL') { 3525 $attributes .= 'DEFAULT NULL '; 3526 } else if (!empty($column['Default'])) { 3527 $attributes .= 'DEFAULT ' . $column['Default'] . ' '; 3528 } 3529 $attributes .= $column['Null'] == 'YES' ? 'NULL' : 'NOT NULL'; 3530 $changeToBinary[] = $change . $binaryType . $attributes; 3531 $changeToUtf8[] = 3532 $change . $column['Type'] . ' CHARACTER SET utf8' . $attributes; 3533 } 3534 if (count($changeToBinary)) { 3535 $query = 3536 "ALTER TABLE `$tableName` " . implode(', ', $changeToBinary); 3537 $ret = $storage->Execute($query); 3538 if ($ret) { 3539 return array($ret, null); 3540 } 3541 $query = "ALTER TABLE `$tableName` " . implode(', ', $changeToUtf8); 3542 $ret = $storage->Execute($query); 3543 if ($ret) { 3544 return array($ret, null); 3545 } 3546 $converted = true; 3547 } 3548 3549 $ret = $statusMonitor->renderStatusMessage( 3550 $module->translate('Converting MySQL data to UTF8'), 3551 null, $i / count($tableVersions)); 3552 if ($ret) { 3553 return array($ret, null); 3554 } 3555 $gallery->guaranteeTimeLimit(120); 3556 } /* End for each table */ 3557 3558 if ($converted) { 3559 /* Clear any cache data since it may be in the wrong character set*/ 3560 $gallery->guaranteeTimeLimit(60); 3561 $ret = GalleryCoreApi::removeAllMapEntries('GalleryCacheMap', true); 3562 if ($ret) { 3563 return array($ret, null); 3564 } 3565 } 3566 } /* End if database character set not UTF-8 */ 3567 } /* End if MySql version > 4.1.0 */ 3568 } /* End if MySQL */ 3569 3570 return array(null, $converted); 3571 } 3572 3573 /** 3574 * Sort an associative array where the key is the name of the table. Force 3575 * the schema table to be last in line. 3576 */ 3577 function _sortSchemaTableLast($a, $b) { 3578 if ($a == 'Schema') { 3579 return -1; 3580 } else if ($b == 'Schema') { 3581 return 1; 3582 } else { 3583 return strcmp($a, $b); 3584 } 3585 } 3586} 3587?> 3588