0byt3m1n1
Path:
/
data
/
applications
/
aps
/
gallery
/
2.2-08
/
htdocs
/
modules
/
core
/
classes
/
[
Home
]
File: Gallery.class
<?php /* * Gallery - a web based photo album viewer and editor * Copyright (C) 2000-2007 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /** * Global storage container and utility class for Gallery. * This is a container for global information required for Gallery operation, such as configuration, * session, user, etc. * * @package GalleryCore * @subpackage Classes * @author Bharat Mediratta <bharat@menalto.com> * @version $Revision: 15519 $ */ class Gallery { /** * The active GalleryUser instance * @var object GalleryUser * @access private */ var $_activeUser; /** * Storage for all configuration variables, set in config.php. The values contained here can't * be modified. Well, they can be modified but they can't be saved so it's not a good idea. * @var array * @access private */ var $_config; /** * The current debugging mode. One of 'buffered', 'logged', 'immediate' or false. * @var string * @access private */ var $_debug; /** * Where to send debug output (when the debugging mode is set to 'logged') * @var string * @access private */ var $_debugLogFile; /** * A place to temporarily store debug output when the debugging mode is set to 'buffered' * @var string * @access private */ var $_debugBuffer; /** * A secondary debug buffer used to record debug output even if regular debug mode is disabled. * @var string * @access private */ var $_debugSnippet = null; /** * Are we currently recording a debug snippet? * @var boolean * @access private */ var $_debugSnippetActive = false; /** * The active GalleryLockSystem implementation * @var object GalleryLockSystem * @access private */ var $_lockSystem; /** * An instance of the GalleryPlatform class * @var object GalleryPlatform * @access private */ var $_platform; /** * The current profiling mode. * @var string * @access private */ var $_profile; /** * Storage for all session variables. * @var object GallerySession * @access private */ var $_session; /** * The backend persistent store for the Gallery class * @var object GalleryStorage * @access private */ var $_storage; /** * The adapter between the template system and any Gallery callbacks that want to use in the * template process. * @var object GalleryTemplateAdapter * @access private */ var $_templateAdapter; /** * Instance of the GalleryTranslator class * @var object GalleryTranslator * @access private */ var $_translator; /** * Instance of the GalleryUrlGenerator class * @var object GalleryUrlGenerator * @access private */ var $_urlGenerator; /** * The name of the current view * @var string * @access private */ var $_currentView = ''; /** * The time at which we should cease whatever operation we're doing * @var int * @access private */ var $_timeLimit; /** * Actions to perform at the end of the request * @var array * @access private */ var $_shutdownActions; /** * A facade in front of the PHP virtual machine. We use this as an abstraction layer to let us * interpose mock objects between our code and the VM for testing purposes. When we're not in a * test environment, this is always an instance of GalleryPhpVm. * @var object GalleryPhpVm * @access private */ var $_phpVm = null; function Gallery() { $this->_activeUser = null; /* Set up a shutdown function to release any hanging locks */ register_shutdown_function(array(&$this, '_shutdown')); /* Default config settings (can be overridden via config.php or embedded environment) */ $this->_config = array( 'login' => true, /* Offer UserAdmin links (Login/Logout/Your Account) */ /* UrlGenerator parameters for redirect URL to login page. Can be overridden. */ 'loginRedirect' => array('view' => 'core.UserAdmin', 'subView' => 'core.UserLogin', 'return' => true), 'link' => true, /* @deprecated - Allow item linking */ /* (now unused, there is a separate replica module */ 'showSidebarBlocks' => true, /* Can we allow themes to show the sidebar? */ 'systemCharset' => null, /* Specify system character set, skip autodetect */ 'defaultAlbumId' => null, /* Initial album to display instead of root album */ 'breadcrumbRootId' => null, /* Can omit parents above this id in fetchParentSequence */ 'anonymousUserId' => null, /* Alternate user account for guest sessions */ ); } /** * @see GalleryStorage::search */ function search($query, $data=array(), $options=array()) { $storage =& $this->getStorage(); list ($ret, $results) = $storage->search($query, $data, $options); if ($ret) { return array($ret, null); } return array(null, $results); } /** * Set the id of the active user. The active user is the user who is logged on in this session. * * @param object GalleryUser $user the current user */ function setActiveUser($user) { $this->_activeUser = $user; /* It's possible for the session not to exist during bootstrap time */ $session =& $this->getSession(); if (isset($session)) { $activeUserId = $session->getUserId(); if ($activeUserId != $user->getId()) { $session->setUserId($user->getId()); $language = $user->getLanguage(); if (!empty($language)) { $session->put('core.language', $language); } } } } /** * Get the Id of the active user. * The active user is the user who is logged on in this session. * * @return int the id of the current user */ function getActiveUserId() { if (isset($this->_activeUser)) { return (int) $this->_activeUser->getId(); } else { $session =& $this->getSession(); return (int) $session->getUserId(); } } /** * Get the active user. * Cache the results of the first call and return that same value each time. * * @return object GalleryUser the active user */ function getActiveUser() { return $this->_activeUser; } /** * Store a value in the Gallery config table * * @param string $key * @param mixed $value */ function setConfig($key, $value) { assert('!empty($key)'); $this->_config[$key] = $value; } /** * Get a value from the Gallery configuration settings * * @return mixed an arbitrary value */ function getConfig($key) { assert('!empty($key)'); return $this->_config[$key]; } /** * Initialize session. * * @return object GalleryStatus a status code */ function initSession() { GalleryCoreApi::requireOnce('modules/core/classes/GallerySession.class'); if (empty($this->_session)) { $this->_session = new GallerySession(); $ret = $this->_session->init(); if ($ret) { return $ret; } } return null; } /** * Initialize an empty session. */ function initEmptySession() { GalleryCoreApi::requireOnce('modules/core/classes/GallerySession.class'); $this->_session = new GallerySession(); } /** * Get the Gallery session object. * Return a reference to the unique Gallery session object. Any changes made to this object * will be saved in the session. * * @return object GallerySession a session instance */ function &getSession() { return $this->_session; } /** * Set the Gallery platform object. * * @param object GalleryPlatform $platform the Gallery platform object */ function setPlatform(&$platform) { unset($this->_platform); $this->_platform =& $platform; } /** * Get the Gallery platform object. * Return a reference to the unique Gallery platform object. * * @return object GalleryPlatform the Gallery platform object */ function &getPlatform() { return $this->_platform; } /** * Return the active lock system. * * @param boolean $canInit (optional) if false and lockSystem isn't yet initialized, return null * @return array object GalleryStatus a status code * object GalleryLockSystem the lock implementation (reference) */ function &getLockSystem($canInit=true) { if (!isset($this->_lockSystem)) { if ($canInit) { list ($ret, $which) = GalleryCoreApi::getPluginParameter('module', 'core', 'lock.system'); if ($ret) { $ret = array($ret, null); return $ret; } } else { $which = 'null'; } switch($which) { case 'flock': GalleryCoreApi::requireOnce('modules/core/classes/FlockLockSystem.class'); $this->_lockSystem = new FlockLockSystem(); break; case 'database': GalleryCoreApi::requireOnce('modules/core/classes/DatabaseLockSystem.class'); $this->_lockSystem = new DatabaseLockSystem(); break; case 'null': $this->_lockSystem = null; break; default: $ret = array(GalleryCoreApi::error(ERROR_BAD_PARAMETER), null); return $ret; } } $ret = array(null, &$this->_lockSystem); return $ret; } /** * Perform any necessary shutdown tasks. * This should only be invoked as a register_shutdown callback. * * @access private */ function _shutdown() { if (isset($this->_lockSystem)) { /* Bitch about open locks */ $lockIds = $this->_lockSystem->getLockIds(); foreach ($lockIds as $lockId) { if ($this->getDebug()) { $this->debug(sprintf('Lock id %d was left hanging!', $lockId)); } } /* Release all locks and ignore any errors */ $this->_lockSystem->releaseAllLocks(); $this->_lockSystem->releaseQueue(); } /* Roll back any transactions */ if (isset($this->_storage)) { $this->_storage->rollbackTransaction(); } } /** * Return an instance of the GalleryStorage class * * @return object GalleryStorage a storage instance */ function &getStorage() { if (!isset($this->_storage)) { $config = $this->getConfig('storage.config'); switch ($config['type']) { case 'mysql': case 'mysqlt': case 'mysqli': GalleryCoreApi::requireOnce('modules/core/classes/GalleryStorage.class'); $this->_storage = new MySqlStorage($config); break; case 'postgres': case 'postgres7': GalleryCoreApi::requireOnce( 'modules/core/classes/GalleryStorage/PostgreSqlStorage.class'); $this->_storage = new PostgreSqlStorage($config); break; case 'db2': GalleryCoreApi::requireOnce('modules/core/classes/GalleryStorage/Db2Storage.class'); $this->_storage = new Db2Storage($config); break; case 'oci8': case 'oci805': case 'oci8po': case 'oracle': GalleryCoreApi::requireOnce( 'modules/core/classes/GalleryStorage/OracleStorage.class'); $this->_storage = new OracleStorage($config); break; case 'ado_mssql': GalleryCoreApi::requireOnce( 'modules/core/classes/GalleryStorage/MSSqlStorage.class'); $this->_storage = new MSSqlStorage($config); break; default: $this->debug('Unknown storage type'); $this->debug_r($config); GalleryCoreApi::requireOnce('modules/core/classes/GalleryStorage.class', true); $this->_storage = new GalleryStorage($config); } } return $this->_storage; } /** * Check if GalleryStorage has been instantiated * * @return boolean */ function isStorageInitialized() { return isset($this->_storage); } /** * Set the URL generator * * @param object GalleryUrlGenerator $urlGenerator */ function setUrlGenerator(&$urlGenerator) { unset($this->_urlGenerator); $this->_urlGenerator =& $urlGenerator; } /** * Get the URL generator * * @return object GalleryUrlGenerator */ function &getUrlGenerator() { return $this->_urlGenerator; } /** * Set the current view * * @param string $view the view name */ function setCurrentView($view) { $this->_currentView = $view; } /** * Get the current view * * @return string the current view name */ function getCurrentView() { return $this->_currentView; } /** * Return a reference to our GalleryTranslator instance * * @return object GalleryTranslator */ function &getTranslator() { return $this->_translator; } /** * Initialize our GalleryTranslator * * @param boolean $dontUseDatabase (optional) true if we should not use the database * @return object GalleryStatus a status code */ function initTranslator($dontUseDatabase=false) { if (empty($this->_translator)) { /* Load the translator class */ GalleryCoreApi::requireOnce('modules/core/classes/GalleryTranslator.class'); /* Do we already have an activeLanguage for this session? */ list ($ret, $language) = $this->getActiveLanguageCode(); if ($ret) { return $ret; } $this->_translator = new GalleryTranslator(); list ($ret, $languageCode) = $this->_translator->init($language, $dontUseDatabase); if ($ret) { return $ret; } $ret = $this->setActiveLanguageCode($languageCode); if ($ret) { return $ret; } } return null; } /** * Get the active language code. * * @return array object GalleryStatus a status code * string language code */ function getActiveLanguageCode() { $session =& $this->getSession(); /* During installation, we don't have a session yet */ if (!empty($session)) { $language = $session->get('core.language'); } else { $language = ''; } return array(null, $language); } /** * Set the active language code for this session. * * @param string $language language code * @return object GalleryStatus a status code */ function setActiveLanguageCode($language) { $session =& $this->getSession(); /* During installation, we don't have a session yet */ if (!empty($session)) { $session->put('core.language', $language); } return null; } /** * Guarantee that we have at least this many more seconds to work * * After this function completes, we will be guaranteed of at least this much more time to work. * * @param int $limit a time interval in seconds, must be greater than 0 */ function guaranteeTimeLimit($limit) { if ($limit <= 0) { $limit = 30; } $now = time(); if (empty($this->_timeLimit) || ($this->_timeLimit - $now < $limit)) { $this->debug("[$now] can't guarantee $limit -- extending!"); /* Make sure that we extend at least a minimum of 30 seconds */ $this->_timeLimit = $now + max($limit, 30); set_time_limit($this->_timeLimit - $now); /* * Then make sure our locks stick around. Even though this returns a status code, we * really don't want to make guaranteeTimeLimit() return a status code since we want to * keep it lightweight. So swallow the return code and don't sweat it for now. */ if (isset($this->_lockSystem)) { $this->_lockSystem->refreshLocks($this->_timeLimit); } } } /** * Set the profiling state. Pass in an array containing the different kinds of things that you * want to profile. Right now, we only do sql profiling so the only valid values are: * * false <-- no profiling * array() <-- no profiling * array('sql') <-- SQL profiling * * @param mixed $profile array of profiling modes or boolean false */ function setProfile($profile=array()) { if ($profile === false) { $this->_profile = array(); } else { $this->_profile = $profile; } } /** * Get the profiling state * * @param string $type profiling type * @return boolean */ function isProfiling($type) { return in_array($type, $this->_profile); } /** * Change the debugging state * * @param mixed $debug one of 'buffered', 'logged', 'immediate' or false */ function setDebug($debug=false) { /* Try to do the right thing in the face of bogus input */ if ($debug === true) { $debug = 'buffered'; } $this->_debug = $debug; if (!isset($this->_debugBuffer)) { $this->clearDebugBuffer(); } if (!empty($this->_debug)) { /* PHP 6 includes E_STRICT in E_ALL. Hardcode since PHP 4 does not know that constant */ error_reporting(E_ALL &~ 2048); ini_set('display_errors', 1); ini_set('log_errors', 1); ini_set('short_open_tag', false); ini_set('allow_call_time_pass_reference', false); } if (isset($this->_storage)) { $this->_storage->setDebug((bool)$debug); } } /** * Set the location of debugging output * @param string $debugLogFile a filename */ function setDebugLogFile($debugLogFile) { $this->_debugLogFile = $debugLogFile; } /** * Get the debug state * @return mixed the debug state */ function getDebug() { if ($this->_debug) { return $this->_debug; } if ($this->_debugSnippetActive) { return 'snippet'; } return false; } /** * Get any buffered debug output * @return string the debug state */ function getDebugBuffer() { return $this->_debugBuffer; } /** * Clear any buffered debug output */ function clearDebugBuffer() { $this->_debugBuffer = ''; } /** * Start recording a debug snippet */ function startRecordingDebugSnippet() { $this->_debugSnippetActive = true; $this->_debugSnippet = ''; if (isset($this->_storage) && !$this->_debug) { $this->_storage->setDebug(true); } } /** * Stop recording the debug snippet and return whatever got recorded. * @return string the snippet */ function stopRecordingDebugSnippet() { $this->_debugSnippetActive = false; $tmp = $this->_debugSnippet; $this->_debugSnippet = ''; if (isset($this->_storage) && !$this->_debug) { $this->_storage->setDebug(false); } return $tmp; } /** * Output a debug message * @param string $msg a message */ function debug($msg) { if (empty($msg)) { return; } if (!empty($this->_debug)) { if (!strcmp($this->_debug, 'buffered')) { $this->_debugBuffer .= wordwrap($msg) . "\n"; } else if (!strcmp($this->_debug, 'logged')) { /* Don't use platform calls for these as they call debug internally! */ if ($fd = fopen($this->_debugLogFile, 'a')) { $date = date('Y-m-d H:i:s'); $session =& $this->getSession(); if (!empty($session)) { $id = $session->getId(); } else { $id = '<no session id>'; } fwrite($fd, "$date [" . $id . "] $msg\n"); fclose($fd); } } else if (!strcmp($this->_debug, 'immediate')) { print "$msg\n"; } } if ($this->_debugSnippetActive) { $this->_debugSnippet .= wordwrap($msg) . "\n"; } } /** * Output a print_r style debug message * * @param mixed $object any object or value * @param boolean $escapeHtmlEntities true if the output should be run through htmlentities() */ function debug_r($object, $escapeHtmlEntities=false) { if (!empty($this->_debug)) { $buf = print_r($object, true); if ($escapeHtmlEntities) { $buf = htmlentities($buf); } $this->debug($buf); } } /** * Return the template adapter. There is only ever one in the system. * * @return object GalleryTemplateAdapter */ function &getTemplateAdapter() { if (!isset($this->_templateAdapter)) { GalleryCoreApi::requireOnce('modules/core/classes/GalleryTemplateAdapter.class'); $this->_templateAdapter = new GalleryTemplateAdapter(); } return $this->_templateAdapter; } /** * Mark a string as being internationalized. This is a semaphore method; it does nothing but it * allows us to easily identify strings that require translation. Generally this is used to * mark strings that will be stored in the database (like descriptions of permissions). * * Gallery uses GNU gettext for internationalization (i18n) and localization (l10n) of text * presented to the user. Gettext needs to know about all places involving strings, that must * be translated. Mark any place, where localization at runtime shall take place by using the * function GalleryPlugin::translate(). * * eg. instead of: * print 'TEST to be displayed in different languages'; * use (in any modules subclass of GalleryPlugin): * print $this->translate('TEST to be displayed in different languages'); * and you are all set for pure literals. The translation teams will receive that literal * string as a job to translate and will translate it (when the message is clear enough). * At runtime the message is then localized when printed. * The input string can contain a hint to assist translators: * print $this->translate('TT <!-- abbreviation for Translation Test -->'); * The hint portion of the string will not be printed. * * But consider this case: * $message_to_be_localized = 'TEST to be displayed in different languages'; * print $this->translate($message_to_be_localized); * * The translate() method is called in the right place for runtime handling, but there is no * message at gettext preprocessing time to be given to the translation teams, just a variable * name. Translation of the variable name would break the code! So all places potentially * feeding this variable have to be marked to be given to translation teams, but not translated * at runtime! * * This method resolves all such cases. Simply mark the candidates: * $message_to_be_localized = $gallery->i18n('TEST to be displayed in different languages'); * print $this->translate($message_to_be_localized); * * @param string $value * @param boolean $cFormat (optional) hint for gettext whether to use c-format * @return string the same value */ function i18n($value, $cFormat=null) { return $value; /* Just pass the value through */ } /** * Send a data file out to the browser as quickly as possible. * * @param string $relativePath the relative path to the file from the g2data/ directory * @param string $filename logical name of the file (used for the Content-Disposition header) * @param string $lastModified the last modified date string (used for the Last-Modified header) * @param string $mimeType the mime type (used for the Content-type header) * @param int $contentLength the size of the file (used for the Content-length header) * @return boolean true if we transferred the file successfully */ function fastDownload($relativePath, $filename, $lastModified, $mimeType, $contentLength) { /* * Note: don't use GalleryPlatform or GalleryUtilities here because this code is * a shortcut that is used before we load those classes. */ $fileNameParam = GALLERY_FORM_VARIABLE_PREFIX . 'fileName'; $requestFileName = isset($_GET[$fileNameParam]) ? $_GET[$fileNameParam] : null; if (!empty($requestFileName) && $requestFileName != $filename) { return false; } $base = $this->getConfig('data.gallery.base'); $path = $base . $relativePath; if (file_exists($path) && $fd = fopen($path, 'rb')) { header('Content-Disposition: inline; filename="' . $filename . '"'); header('Last-Modified: ' . $lastModified); header('Content-type: ' . $mimeType); header('Content-length: ' . $contentLength); header('Expires: ' . $this->getHttpDate(time() + 31536000)); set_magic_quotes_runtime(0); set_time_limit(0); while (!feof($fd)) { print fread($fd, 4096); } fclose($fd); return true; } return false; } /** * Return a date and time string that is conformant to RFC 2616 * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 * * @param int $time the unix timestamp of the date we want to return, * empty if we want the current time * @return string a date-string conformant to the RFC 2616 */ function getHttpDate($time='') { if ($time == '') { $time = time(); } /* Use fixed list of weekdays and months, so we don't have to fiddle with locale stuff */ $months = array('01' => 'Jan', '02' => 'Feb', '03' => 'Mar', '04' => 'Apr', '05' => 'May', '06' => 'Jun', '07' => 'Jul', '08' => 'Aug', '09' => 'Sep', '10' => 'Oct', '11' => 'Nov', '12' => 'Dec'); $weekdays = array('1' => 'Mon', '2' => 'Tue', '3' => 'Wed', '4' => 'Thu', '5' => 'Fri', '6' => 'Sat', '0' => 'Sun'); $dow = $weekdays[gmstrftime('%w', $time)]; $month = $months[gmstrftime('%m', $time)]; $out = gmstrftime('%%s, %d %%s %Y %H:%M:%S GMT', $time); return sprintf($out, $dow, $month); } /** * Check if Gallery is in embedded mode * * @return boolean true if Gallery is in embedded mode, false otherwise */ function isEmbedded() { return GalleryDataCache::containsKey('G2_EMBED') && GalleryDataCache::get('G2_EMBED'); } /** * Add an action to be performed at the end of the request. * * @param callback $callback * @param array $parameters */ function addShutdownAction($callback, $parameters) { if (!isset($this->_shutdownActions)) { $this->_shutdownActions = array(); } $action = array($callback, $parameters); /* Skip duplicate actions */ foreach ($this->_shutdownActions as $item) { if ($item == $action) { $duplicate = true; break; } } if (!isset($duplicate)) { $this->_shutdownActions[] = $action; } } /** * Process registered shutdown actions. */ function performShutdownActions() { if (isset($this->_shutdownActions)) { foreach ($this->_shutdownActions as $action) { $ret = @call_user_func_array($action[0], $action[1]); if ($this->getDebug() || class_exists('GalleryTestCase')) { /* Ignore errors unless debug is on */ if (is_array($ret) && GalleryUtilities::isA($ret[0], 'GalleryStatus')) { $ret = $ret[0]; } else if (!GalleryUtilities::isA($ret, 'GalleryStatus')) { $ret = null; } if (isset($ret) && $ret) { $this->debug('Error from shutdown action:'); $this->debug_r($action); $this->debug_r($ret); } } } } } /** * Return our PHP virtual machine abstraction * * @return object GalleryPhpVm */ function getPhpVm() { if (!isset($this->_phpVm)) { GalleryCoreApi::requireOnce('modules/core/classes/GalleryPhpVm.class'); $this->_phpVm = new GalleryPhpVm(); } return $this->_phpVm; } } ?>