Sindbad~EG File Manager
<?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;
}
}
?>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists