Task #10198 - Prevent infinite login loading message when no database configuration...
[expresso_livre:fgsl-expressolivre3.git] / tine20 / Tinebase / Core.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Tinebase
6  * @subpackage  Server
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @copyright   Copyright (c) 2007-2013 Metaways Infosystems GmbH (http://www.metaways.de)
9  * @author      Philipp Schüle <p.schuele@metaways.de>
10  *
11  */
12
13 /**
14  * php helpers
15  */
16 require_once 'Helper.php';
17
18 /**
19  * dispatcher and initialisation class (functions are static)
20  * - dispatchRequest() function
21  * - initXYZ() functions
22  * - has registry and config
23  *
24  * @package     Tinebase
25  * @subpackage  Server
26  */
27 class Tinebase_Core
28 {
29     /**************** registry indexes *************************/
30
31     /**
32      * constant for config registry index
33      */
34     const CONFIG = 'configFile';
35
36     /**
37      * constant for locale registry index
38      */
39     const LOCALE = 'locale';
40
41     /**
42      * constant for logger registry index
43      */
44     const LOGGER = 'logger';
45
46     /**
47      * constant for loglevel registry index
48      *
49      */
50     const LOGLEVEL = 'loglevel';
51
52     /**
53      * constant for cache registry index
54      */
55     const CACHE = 'cache';
56
57     /**
58      * constant for shared cache registry index
59      */
60     const SHAREDCACHE = 'sharedCache';
61
62     /**
63      * constant for custom expirable cache registry index
64      */
65     const CUSTOMEXPIRABLECACHE = 'customexpirablecache';
66
67     /**
68      * constant for current account/user
69      */
70     const USER = 'currentAccount';
71
72     /**
73      * const for current users credentialcache
74      */
75     const USERCREDENTIALCACHE = 'usercredentialcache';
76
77     /**
78      * constant for database adapter
79      */
80     const DB = 'dbAdapter';
81
82     /**
83      * constant for database adapter
84      */
85     const USERTIMEZONE = 'userTimeZone';
86
87     /**
88      * constant for preferences registry
89      */
90     const PREFERENCES = 'preferences';
91
92     /**
93      * constant for preferences registry
94      */
95     const SCHEDULER = 'scheduler';
96
97     /**
98      * constant temp dir registry
99      */
100     const TMPDIR = 'tmpdir';
101
102     /**
103      * constant temp dir registry
104      */
105     const FILESDIR = 'filesdir';
106
107     /**
108      * constant for request method registry
109      */
110     const METHOD = 'method';
111
112     /**************** other consts *************************/
113
114     /**
115      * const PDO_MYSQL
116      *
117      */
118     const PDO_MYSQL = 'Pdo_Mysql';
119
120     /**
121      * minimal version of MySQL supported
122      */
123     const MYSQL_MINIMAL_VERSION = '5.0.0';
124
125     /**
126      * const PDO_PGSQL
127      *
128      */
129     const PDO_PGSQL = 'Pdo_Pgsql';
130
131     /**
132      * minimal version of PostgreSQL supported
133      */
134     const PGSQL_MINIMAL_VERSION = '8.4.8';
135
136     /**
137      * const PDO_OCI
138      *
139      */
140     const PDO_OCI = 'Pdo_Oci';
141
142     /**
143      * const ORACLE
144      * Zend_Db adapter name for the oci8 driver.
145      *
146      */
147     const ORACLE = 'Oracle';
148
149     /**
150      * minimal version of Oracle supported
151      */
152     const ORACLE_MINIMAL_VERSION = '9.0.0';
153
154     /**
155      * Application Instance Cache
156      * @var array
157      */
158     protected static $appInstanceCache = array();
159
160     /**
161      * current cache status, maybe NULL / uninitialized, true / enabled, false / disabled
162      * @var boolean
163     */
164     protected static $cacheStatus = NULL;
165
166     /******************************* DISPATCH *********************************/
167
168     /**
169      * dispatch request
170      */
171     public static function dispatchRequest()
172     {
173         // check transaction header
174         if (isset($_SERVER['HTTP_X_TINE20_TRANSACTIONID'])) {
175             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Client transaction {$_SERVER['HTTP_X_TINE20_TRANSACTIONID']}");
176             Tinebase_Log_Formatter::setPrefix(substr($_SERVER['HTTP_X_TINE20_TRANSACTIONID'], 0, 5));
177         }
178
179         $server = NULL;
180
181         /**************************** JSON API *****************************/
182         if ((isset($_SERVER['HTTP_X_TINE20_REQUEST_TYPE']) && $_SERVER['HTTP_X_TINE20_REQUEST_TYPE'] == 'JSON')  ||
183             (isset($_SERVER['CONTENT_TYPE']) && substr($_SERVER['CONTENT_TYPE'],0,16) == 'application/json')  ||
184             (isset($_POST['requestType']) && $_POST['requestType'] == 'JSON') ||
185             (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
186         ) {
187             $server = new Tinebase_Server_Json();
188
189         /**************************** SNOM API *****************************/
190         } elseif(
191             isset($_SERVER['HTTP_USER_AGENT']) &&
192             preg_match('/^Mozilla\/4\.0 \(compatible; (snom...)\-SIP (\d+\.\d+\.\d+)/i', $_SERVER['HTTP_USER_AGENT'])
193         ) {
194             $server = new Voipmanager_Server_Snom();
195
196         /**************************** ASTERISK API *****************************/
197         } elseif(isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] == 'asterisk-libcurl-agent/1.0') {
198             $server = new Voipmanager_Server_Asterisk();
199
200         /**************************** ActiveSync API ****************************
201          * RewriteRule ^/Microsoft-Server-ActiveSync /index.php?frontend=activesync [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
202          */
203         } elseif((isset($_SERVER['REDIRECT_ACTIVESYNC']) && $_SERVER['REDIRECT_ACTIVESYNC'] == 'true') ||
204                  (isset($_GET['frontend']) && $_GET['frontend'] == 'activesync')) {
205             $server = new ActiveSync_Server_Http();
206             self::set('serverclassname', get_class($server));
207
208         /**************************** WebDAV / CardDAV / CalDAV API **********************************
209          * RewriteCond %{REQUEST_METHOD} !^(GET|POST)$
210          * RewriteRule ^/$            /index.php?frontend=webdav [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
211          *
212          * RewriteRule ^/addressbooks /index.php?frontend=webdav [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
213          * RewriteRule ^/calendars    /index.php?frontend=webdav [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
214          * RewriteRule ^/principals   /index.php?frontend=webdav [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
215          * RewriteRule ^/webdav       /index.php?frontend=webdav [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
216          */
217         } elseif(isset($_GET['frontend']) && $_GET['frontend'] == 'webdav') {
218             $server = new Tinebase_Server_WebDAV();
219
220         /**************************** CLI API *****************************/
221         } elseif (php_sapi_name() == 'cli') {
222             $server = new Tinebase_Server_Cli();
223
224         /**************************** HTTP API ****************************/
225         } else {
226
227             /**************************** OpenID ****************************
228              * RewriteRule ^/users/(.*)                      /index.php?frontend=openid&username=$1 [L,QSA]
229              */
230             if (isset($_SERVER['HTTP_ACCEPT']) && stripos($_SERVER['HTTP_ACCEPT'], 'application/xrds+xml') !== FALSE) {
231                 $_REQUEST['method'] = 'Tinebase.getXRDS';
232             } elseif ((isset($_SERVER['REDIRECT_USERINFOPAGE']) && $_SERVER['REDIRECT_USERINFOPAGE'] == 'true') ||
233                       (isset($_REQUEST['frontend']) && $_REQUEST['frontend'] == 'openid')) {
234                 $_REQUEST['method'] = 'Tinebase.userInfoPage';
235             }
236
237             if (!isset($_REQUEST['method']) && (isset($_REQUEST['openid_action']) || isset($_REQUEST['openid_assoc_handle'])) ) {
238                 $_REQUEST['method'] = 'Tinebase.openId';
239             }
240
241             $server = new Tinebase_Server_Http();
242         }
243
244         $server->handle();
245         $method = get_class($server) . '::' . $server->getRequestMethod();
246         self::set(self::METHOD, $method);
247
248         self::finishProfiling();
249         self::getDbProfiling();
250     }
251
252     /**
253      * enable profiling
254      * - supports xhprof
255      */
256     public static function enableProfiling()
257     {
258         if (! self::getConfig() || ! self::getConfig()->profiler) {
259             return;
260         }
261
262         if (self::getConfig()->profiler->xhprof) {
263             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Enabling xhprof');
264
265             xhprof_enable(XHPROF_FLAGS_MEMORY);
266         }
267     }
268
269     /**
270      * finish profiling / save profiling data to a file
271      * - supports xhprof
272      */
273     public static function finishProfiling()
274     {
275     if (! self::getConfig() || ! self::getConfig()->profiler) {
276             return;
277         }
278
279         $config = self::getConfig()->profiler;
280         $method = self::get(self::METHOD);
281
282         if ($config->xhprof) {
283             $xhprof_data = xhprof_disable();
284
285             if ($config->method) {
286                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Filtering xhprof profiling method: ' . $config->method);
287                 if (! preg_match($config->method, $method)) {
288                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Method mismatch, do not save profiling info.');
289                     return;
290                 }
291             }
292
293             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Saving xhprof profiling run for method ' . $method);
294
295             $XHPROF_ROOT = '/usr/share/php5-xhprof';
296             if (file_exists($XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php")) {
297                 include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";
298                 include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";
299                 $xhprof_runs = new XHProfRuns_Default();
300                 $run_id = $xhprof_runs->save_run($xhprof_data, "tine");
301             } else {
302                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  ' . print_r($xhprof_data, TRUE));
303             }
304         }
305     }
306
307     /******************************* APPLICATION ************************************/
308
309     /**
310      * returns an instance of the controller of an application
311      *
312      * @param   string $_applicationName appname / modelname
313      * @param   string $_modelName
314      * @return  Tinebase_Controller_Abstract|Tinebase_Controller_Record_Abstract the controller of the application
315      * @throws  Tinebase_Exception_NotFound
316      */
317     public static function getApplicationInstance($_applicationName, $_modelName = '', $_ignoreACL = FALSE)
318     {
319         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
320                 . ' Params: application: ' . $_applicationName . ' / model: ' . $_modelName);
321
322         $cacheKey = $_applicationName . '_' . $_modelName . '_' . ($_ignoreACL?1:0);
323         if (isset(self::$appInstanceCache[$cacheKey])) {
324             return self::$appInstanceCache[$cacheKey];
325         }
326
327         // modified (some model names can have both . and _ in their names and we should treat them as JS model name
328         if (strpos($_applicationName, '_') && ! strpos($_applicationName, '.')) {
329             // got (complete) model name name as first param
330             list($appName, $i, $modelName) = explode('_', $_applicationName, 3);
331         }
332         else if (strpos($_applicationName, '.')) {
333             // got (complete) model name name as first param (JS style)
334             list($j, $appName, $i, $modelName) = explode('.', $_applicationName, 4);
335         }
336         else {
337             $appName = $_applicationName;
338             $modelName = $_modelName;
339         }
340
341         $controllerName = ucfirst((string) $appName);
342         if ($appName !== 'Tinebase' || ($appName === 'Tinebase' && !$modelName)) {
343             // only app controllers are called "App_Controller_Model"
344             $controllerName .= '_Controller';
345         }
346
347         // check for model controller
348         if (!empty($modelName)) {
349             $modelName = preg_replace('/^' . $appName . '_' . 'Model_/', '', $modelName);
350             $controllerNameModel = $controllerName . '_' . $modelName;
351             if (! class_exists($controllerNameModel)) {
352                 throw new Tinebase_Exception_NotFound('No Application Controller found (checked class ' . $controllerNameModel . ')!');
353                 // check for generic app controller
354                 if (! class_exists($controllerName)) {
355                     throw new Tinebase_Exception_NotFound('No Controller found (checked classes '. $controllerName . ' and ' . $controllerNameModel . ')!');
356                 }
357             } else {
358                 $controllerName = $controllerNameModel;
359             }
360         } else if (!@class_exists($controllerName)) {
361             throw new Tinebase_Exception_NotFound('No Application Controller found (checked class ' . $controllerName . ')!');
362         }
363
364         if (! $_ignoreACL && is_object(Tinebase_Core::getUser()) && ! Tinebase_Core::getUser()->hasRight($appName, Tinebase_Acl_Rights_Abstract::RUN)) {
365             throw new Tinebase_Exception_AccessDenied('No right to access application ' . $appName);
366         }
367
368         $controller = call_user_func(array($controllerName, 'getInstance'));
369         self::$appInstanceCache[$cacheKey] = $controller;
370
371         return $controller;
372     }
373
374     /******************************* SETUP ************************************/
375
376     /**
377      * init tine framework
378      */
379     public static function initFramework()
380     {
381         Tinebase_Core::setupCache();
382
383         Tinebase_Core::setupTempDir();
384         Tinebase_Core::setupStreamWrapper();
385
386         //Cache must be setup before User Locale because otherwise Zend_Locale tries to setup
387         //its own cache handler which might result in a open_basedir restriction depending on the php.ini settings
388         Tinebase_Core::setupBuildConstants();
389
390         Tinebase_Session::setupSession();
391         if (Tinebase_Session::sessionExists()) {
392                         Tinebase_Core::startCoreSession();
393         }
394
395         // setup a temporary user locale/timezone. This will be overwritten later but we
396         // need to handle exceptions during initialisation process such as session timeout
397         // @todo add fallback locale to config file
398         Tinebase_Core::set('locale', new Zend_Locale('en_US'));
399         Tinebase_Core::set('userTimeZone', 'UTC');
400
401         Tinebase_Core::setupUserCredentialCache();
402
403         Tinebase_Core::setupUserTimezone();
404
405         Tinebase_Core::setupUserLocale();
406
407         Tinebase_Core::enableProfiling();
408
409         if (PHP_SAPI !== 'cli') {
410             header('X-API: http://www.tine20.org/apidocs/tine20/');
411             if (isset($_SERVER['HTTP_X_TRANSACTIONID'])) {
412                 header('X-TransactionID: ' . substr($_SERVER['HTTP_X_TRANSACTIONID'], 1, -1) . ';' . $_SERVER['SERVER_NAME'] . ';16.4.5009.816;' . date('Y-m-d H:i:s') . ' UTC;265.1558 ms');
413             }
414         }
415     }
416
417     /**
418      * start session helper function
419      *
420      * @param array $_options
421      * @throws Exception
422      */
423     public static function startCoreSession($namespace = null)
424     {
425         try {
426                 $coreSession = Tinebase_Session::getSessionNamespace();
427             $userSession = Tinebase_User_Session::getSessionNamespace();
428         } catch(Exception $e) {
429                 throw $e;
430         }
431
432         if(isset($userSession->currentAccount)) {
433             self::set(self::USER, $userSession->currentAccount);
434         }
435
436         if(!isset($coreSession->jsonKey)){
437                 $coreSession->jsonKey = Tinebase_Record_Abstract::generateUID();
438         }
439
440         Tinebase_Core::set('jsonKey', $coreSession->jsonKey);
441         if (Zend_Auth::getInstance()->hasIdentity()) {
442             Tinebase_Core::set(Tinebase_Session::SESSIONID, session_id());
443             Tinebase_Core::setDbCapabilitiesInSession($coreSession);
444         }
445     }
446
447     /**
448      * initializes the build constants like buildtype, package information, ...
449      */
450     public static function setupBuildConstants()
451     {
452         $config = self::getConfig();
453         define('TINE20_BUILDTYPE',     strtoupper($config->get('buildtype', 'DEVELOPMENT')));
454         define('TINE20_CODENAME',      getDevelopmentRevision());
455         define('TINE20_PACKAGESTRING', 'none');
456         define('TINE20_RELEASETIME',   'none');
457     }
458
459     /**
460      * tines error exception handler for catchable fatal errors
461      *
462      * NOTE: PHP < 5.3 don't throws exceptions for Catchable fatal errors per default,
463      * so we convert them into exceptions manually
464      *
465      * @param integer $severity
466      * @param string $errstr
467      * @param string $errfile
468      * @param integer $errline
469      * @throws ErrorException
470      */
471     public static function errorHandler($severity, $errstr, $errfile, $errline)
472     {
473         if (error_reporting() == 0) {
474             return;
475         }
476
477         $logLine = " $errstr in {$errfile}::{$errline} ($severity)";
478         $e = new Exception('just to get trace');
479         $trace = $e->getTraceAsString();
480
481         switch ($severity) {
482             case E_COMPILE_ERROR:
483             case E_CORE_ERROR:
484             case E_ERROR:
485             case E_PARSE:
486             case E_RECOVERABLE_ERROR:
487             case E_USER_ERROR:
488                 throw new ErrorException($errstr, 0, $severity, $errfile, $errline);
489                 break;
490
491             case E_COMPILE_WARNING:
492             case E_CORE_WARNING:
493             case E_USER_WARNING:
494             case E_WARNING:
495                 if (Tinebase_Core::isRegistered(Tinebase_Core::LOGGER)) {
496                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . $logLine);
497                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . $trace);
498                 } else {
499                     error_log(__METHOD__ . '::' . __LINE__ . $logLine);
500                     error_log(__METHOD__ . '::' . __LINE__ . ' ' . $trace);
501                 }
502                 break;
503
504             case E_NOTICE:
505             case E_STRICT:
506             case E_USER_NOTICE:
507             default:
508                 if (Tinebase_Core::isRegistered(Tinebase_Core::LOGGER)) {
509                     Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . $logLine);
510                     Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' ' . $trace);
511                 } else {
512                     error_log(__METHOD__ . '::' . __LINE__ . $logLine);
513                     error_log(__METHOD__ . '::' . __LINE__ . ' ' . $trace);
514                 }
515                 break;
516         }
517     }
518
519     /**
520      * initializes the config
521      */
522     public static function setupConfig()
523     {
524         self::set(self::CONFIG, Tinebase_Config::getInstance());
525     }
526
527     /**
528      * setup temp dir registry setting retrieved by {@see _getTempDir()}
529      *
530      * @return void
531      */
532     public static function setupTempDir()
533     {
534         self::set(self::TMPDIR, self::guessTempDir());
535     }
536
537     /**
538      * figure out temp directory:
539      * config.inc.php > sys_get_temp_dir > session_save_path > /tmp
540      *
541      * @return String
542      */
543     public static function guessTempDir()
544     {
545         $config = self::getConfig();
546
547         $tmpdir = $config->tmpdir;
548         if ($tmpdir == Tinebase_Model_Config::NOTSET || !@is_writable($tmpdir)) {
549             $tmpdir = sys_get_temp_dir();
550             if (empty($tmpdir) || !@is_writable($tmpdir)) {
551                 $tmpdir = session_save_path();
552                 if (empty($tmpdir) || !@is_writable($tmpdir)) {
553                     $tmpdir = '/tmp';
554                 }
555             }
556         }
557
558         return $tmpdir;
559     }
560
561     /**
562      * initializes the logger
563      *
564      * @param $_defaultWriter Zend_Log_Writer_Abstract default log writer
565      */
566     public static function setupLogger(Zend_Log_Writer_Abstract $_defaultWriter = NULL)
567     {
568         $config = self::getConfig();
569         $logger = new Tinebase_Log();
570
571         if (isset($config->logger) && $config->logger->active) {
572             try {
573                 $logger->addWriterByConfig($config->logger);
574                 if ($config->logger->additionalWriters) {
575                     foreach ($config->logger->additionalWriters as $writerConfig) {
576                         $logger->addWriterByConfig($writerConfig);
577                     }
578                 }
579                 if ((bool)($config->logger->syslog)) {
580                     $writer = new Zend_Log_Writer_Syslog(
581                             array(
582                                     'application' => 'Tine 2.0'
583                             ));
584                     $prio = ($config->logger->priority) ? (int) $config->logger->priority : 3;
585                     $filter = new Zend_Log_Filter_Priority(
586                             $config->logger->priority);
587                     $writer->addFilter($filter);
588                     $logger->addWriter($writer);
589                 }
590             } catch (Exception $e) {
591                 error_log("Tine 2.0 can't setup the configured logger! The Server responded: $e");
592                 $writer = ($_defaultWriter === NULL) ? new Zend_Log_Writer_Null() : $_defaultWriter;
593                 $logger->addWriter($writer);
594             }
595         } else {
596             $writer = new Zend_Log_Writer_Syslog(array(
597                 'application'   => 'Tine 2.0'
598             ));
599
600             $filter = new Zend_Log_Filter_Priority(Zend_Log::WARN);
601             $writer->addFilter($filter);
602             $logger->addWriter($writer);
603         }
604
605         self::set(self::LOGGER, $logger);
606
607         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) $logger->info(__METHOD__ . '::' . __LINE__ .' Logger initialized');
608         if (isset($loggerConfig) && Tinebase_Core::isLogLevel(Zend_Log::TRACE)) $logger->trace(__METHOD__ . '::' . __LINE__
609             .' Logger settings: ' . print_r($loggerConfig->toArray(), TRUE));
610     }
611
612     /**
613      * setup the cache and add it to zend registry
614      *
615      * @param bool $_enabled disabled cache regardless what's configured in config.inc.php
616      *
617      * @todo use the same config keys as Zend_Cache (backend + frontend) to simplify this
618      */
619     public static function setupCache($_enabled = true)
620     {
621         if ( self::$cacheStatus !== NULL && self::$cacheStatus === $_enabled ) {
622             return;
623         }
624
625         $config = self::getConfig();
626
627         if ($config->caching && $config->caching->active) {
628             if (isset($config->caching->shared) && ($config->caching->shared === true)) {
629                 self::set(self::SHAREDCACHE, true);
630             } else {
631                 self::set(self::SHAREDCACHE, false);
632             }
633             if (isset($config->caching->customexpirable) && ($config->caching->customexpirable === true)) {
634                 self::set(self::CUSTOMEXPIRABLECACHE, true);
635             } else {
636                 self::set(self::CUSTOMEXPIRABLECACHE, false);
637             }
638         }
639
640         // create zend cache
641         if ($_enabled === true && $config->caching && $config->caching->active) {
642             $frontendOptions = array(
643                 'lifetime'                  => ($config->caching->lifetime) ? $config->caching->lifetime : 7200,
644                 'automatic_serialization'   => true, // turn that off for more speed
645                 'caching'                   => true,
646                 'automatic_cleaning_factor' => 0,    // no garbage collection as this is done by a scheduler task
647                 'write_control'             => false, // don't read cache entry after it got written
648 //                'logging'                   => (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)),
649 //                'logger'                    => self::getLogger(),
650             );
651
652             $backendType = ($config->caching->backend) ? ucfirst($config->caching->backend) : 'File';
653             $backendOptions = ($config->caching->backendOptions) ? $config->caching->backendOptions->toArray() : false;
654
655             if (! $backendOptions) {
656                 switch ($backendType) {
657                     case 'File':
658                         $backendOptions = array(
659                             'cache_dir'              => ($config->caching->path)     ? $config->caching->path     : Tinebase_Core::getTempDir(),
660                             'hashed_directory_level' => ($config->caching->dirlevel) ? $config->caching->dirlevel : 4,
661 //                            'logging'                => (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)),
662 //                            'logger'                 => self::getLogger(),
663                         );
664                         break;
665
666                     case 'Memcached':
667                         $host = $config->caching->host ? $config->caching->host : ($config->caching->memcached->host ? $config->caching->memcached->host : 'localhost');
668                         $port = $config->caching->port ? $config->caching->port : ($config->caching->memcached->port ? $config->caching->memcached->port : 11211);
669                         $backendOptions = array(
670                             'servers' => array(
671                                 'host' => $host,
672                                 'port' => $port,
673                                 'persistent' => TRUE
674                         ));
675                         break;
676
677                     case 'Redis':
678                         $host = $config->caching->host ? $config->caching->host : ($config->caching->redis->host ? $config->caching->redis->host : 'localhost');
679                         $port = $config->caching->port ? $config->caching->port : ($config->caching->redis->port ? $config->caching->redis->port : 6379);
680                         $prefix = (Setup_Controller::getInstance()->isInstalled('Tinebase')) ? Tinebase_Application::getInstance()->getApplicationByName('Tinebase')->getId() : 'TINESETUP';
681                         $prefix .= '_CACHE_';
682                         $backendOptions = array(
683                             'servers' => array(
684                                 'host'   => $host,
685                                 'port'   => $port,
686                                 'prefix' => $prefix
687                         ));
688                         break;
689
690                     default:
691                         $backendOptions = array();
692                         break;
693                 }
694             }
695
696            // Tinebase_Core::getLogger()->INFO(__METHOD__ . '::' . __LINE__ . " cache of backend type '{$backendType}' enabled");
697
698             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
699                 // logger is an object, that makes ugly traces :)
700                 $backendOptionsWithoutLogger = $backendOptions;
701                 if (isset($backendOptionsWithoutLogger['logger'])) {
702                     unset($backendOptionsWithoutLogger['logger']);
703                 }
704              //   Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " backend options: " . print_r($backendOptionsWithoutLogger, TRUE));
705             }
706
707         } else {
708             //Tinebase_Core::getLogger()->INFO(__METHOD__ . '::' . __LINE__ . ' cache disabled');
709             $backendType = 'Test';
710             $frontendOptions = array(
711                 'caching' => false
712             );
713             $backendOptions = array(
714             );
715         }
716
717         // getting a Zend_Cache_Core object
718         try {
719             $cache = Zend_Cache::factory('Core', $backendType, $frontendOptions, $backendOptions);
720
721         } catch (Zend_Cache_Exception $e) {
722             $enabled = FALSE;
723             if ('File' === $backendType && !is_dir($backendOptions['cache_dir'])) {
724                 // create cache directory and re-try
725                 if (mkdir($backendOptions['cache_dir'], 0770, true)) {
726                     $enabled = $_enabled;
727                 }
728             }
729
730             //Tinebase_Core::getLogger()->WARN(__METHOD__ . '::' . __LINE__ . ' Cache error: ' . $e->getMessage());
731
732             self::setupCache($enabled);
733             return;
734         }
735
736
737         // some important caches
738         Zend_Locale::setCache($cache);
739         Zend_Translate::setCache($cache);
740
741         Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);
742         self::set(self::CACHE, $cache);
743         self::$cacheStatus = $_enabled;
744     }
745
746     /**
747      * creates a hash of the cacheId; allows to use any character,
748      * not only [a-zA-Z0-9_]
749      *
750      * @param Array $params
751      *
752      * @return string $cacheId
753      */
754     public static function createCacheId($params)
755     {
756         $cacheId = implode($params);
757
758         $result = md5($cacheId);
759
760         return $result;
761     }
762
763     /**
764      * places user credential cache id from cache adapter (if present) into registry
765      */
766     public static function setupUserCredentialCache()
767     {
768         $cache = NULL;
769         try {
770             if (Zend_Session::isStarted() && Zend_Auth::getInstance()->hasIdentity()) {
771                 $cache = Tinebase_Auth_CredentialCache::getInstance()->getCacheAdapter()->getCache();
772             }
773         } catch (Zend_Db_Statement_Exception $zdse) {
774             // could not get credential cache adapter, perhaps Tine 2.0 is not installed yet
775             $cache = NULL;
776         }
777         if ($cache !== NULL) {
778             self::set(self::USERCREDENTIALCACHE, $cache);
779         }
780     }
781
782     /**
783      * setup stream wrapper for tine20:// prefix
784      *
785      */
786     public static function setupStreamWrapper()
787     {
788         if (empty(Tinebase_Core::getConfig()->filesdir)) {
789             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__
790                 . " Filesdir config value not set. tine20:// streamwrapper not registered, virtual filesystem not available.");
791             return;
792         }
793
794         stream_wrapper_register('tine20', 'Tinebase_FileSystem_StreamWrapper');
795     }
796
797
798
799     /**
800      * set database capabilities in session
801      *
802      * @param Zend_Session_Namespace $session
803      */
804     public static function setDbCapabilitiesInSession($coreSession)
805     {
806         if (! isset($coreSession->dbcapabilities)) {
807             $db = Tinebase_Core::getDb();
808             $capabilities = array();
809             if ($db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
810                 $capabilities['unaccent'] = Tinebase_Core::checkUnaccentExtension($db);
811             }
812             $coreSession->dbcapabilities = $capabilities;
813         }
814     }
815
816     /**
817      * initializes the database connection
818      *
819      * @throws  Tinebase_Exception_UnexpectedValue
820      * @throws  Tinebase_Exception_Backend_Database
821      */
822     public static function setupDatabaseConnection()
823     {
824         $config = self::getConfig();
825
826         if (isset($config->database)) {
827             $dbConfig = $config->database;
828
829             if (! defined('SQL_TABLE_PREFIX')) {
830                 define('SQL_TABLE_PREFIX', $dbConfig->get('tableprefix') ? $dbConfig->get('tableprefix') : 'tine20_');
831             }
832
833             $dbConfigArray = $dbConfig->toArray();
834             $constName = __CLASS__  . '::' . strtoupper($dbConfigArray['adapter']);
835             if (empty($dbConfigArray['adapter']) || ! defined($constName)) {
836                 self::getLogger()->warn('Wrong db adapter configured (' . $dbConfigArray['adapter'] . '). Using default: ' . self::PDO_MYSQL);
837                 $dbBackend = self::PDO_MYSQL;
838                 $dbConfigArray['adapter'] = self::PDO_MYSQL;
839             } else {
840                 $dbBackend = constant($constName);
841             }
842
843             self::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Creating ' . $dbBackend . ' DB adapter');
844
845             switch ($dbBackend) {
846                 case self::PDO_MYSQL:
847                     foreach (array('PDO::MYSQL_ATTR_USE_BUFFERED_QUERY', 'PDO::MYSQL_ATTR_INIT_COMMAND') as $pdoConstant) {
848                         if (! defined($pdoConstant)) {
849                             throw new Tinebase_Exception_Backend_Database($pdoConstant . ' is not defined. Please check PDO extension.');
850                         }
851                     }
852
853                     // force some driver options
854                     $dbConfigArray['driver_options'] = array(
855                         PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => FALSE,
856                         // set utf8 charset
857                         PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8;",
858                     );
859                     $db = Zend_Db::factory('Pdo_Mysql', $dbConfigArray);
860                     try {
861                         // set mysql timezone to utc and activate strict mode
862                         $db->query("SET time_zone ='+0:00';");
863                         $db->query("SET SQL_MODE = 'STRICT_ALL_TABLES'");
864                         $db->query("SET SESSION group_concat_max_len = 81920");
865                     } catch (Exception $e) {
866                         self::getLogger()->warn('Failed to set "SET SQL_MODE to STRICT_ALL_TABLES or timezone: ' . $e->getMessage());
867                     }
868
869                     break;
870
871                 case self::PDO_OCI:
872                     $db = Zend_Db::factory('Pdo_Oci', $dbConfigArray);
873                     break;
874
875                 case self::ORACLE:
876                     $db = Zend_Db::factory(self::ORACLE, $dbConfigArray);
877                     $db->supportPositionalParameters(true);
878                     $db->setLobAsString(true);
879                     break;
880
881                 case self::PDO_PGSQL:
882                     unset($dbConfigArray['adapter']);
883                     unset($dbConfigArray['tableprefix']);
884                     $db = Zend_Db::factory('Pdo_Pgsql', $dbConfigArray);
885                     try {
886                         // set mysql timezone to utc and activate strict mode
887                         $db->query("SET timezone ='+0:00';");
888                         // PostgreSQL has always been strict about making sure data is valid before allowing it into the database
889                     } catch (Exception $e) {
890                         self::getLogger()->warn('Failed to set "SET timezone: ' . $e->getMessage());
891                     }
892                     break;
893
894                 default:
895                     throw new Tinebase_Exception_UnexpectedValue('Invalid database adapter defined. Please set adapter to ' . self::PDO_MYSQL . ' or ' . self::PDO_OCI . ' in config.inc.php.');
896                     break;
897             }
898
899             Zend_Db_Table_Abstract::setDefaultAdapter($db);
900
901             // place table prefix into the concrete adapter
902             $db->table_prefix = SQL_TABLE_PREFIX;
903
904             self::set(self::DB, $db);
905
906         } else {
907             Tinebase_Session::destroyAndRemoveCookie();
908             if(MULTIDOMAIN && $config->getDomain() === 'default'){
909                 throw new Tinebase_Exception_ConfigNotFound('No database configuration found', Tinebase_Auth::FAILURE_IDENTITY_NOT_FOUND);
910             } else {
911                 throw new Tinebase_Exception_ConfigNotFound('No database configuration found');
912             }
913         }
914     }
915
916     /**
917      * get value of session variable "unaccent"
918      *
919      * @param Zend_Db_Adapter_Abstract $db
920      * @return boolean $valueUnaccent
921      *
922      * @todo should be moved to pgsql adapter / helper functions
923      */
924     public static function checkUnaccentExtension($db)
925     {
926         $tableName = 'pg_extension';
927         $cols = 'COUNT(*)';
928
929         $select = $db->select()
930             ->from($tableName, $cols)
931             ->where("extname = 'unaccent'");
932
933         // if there is no table pg_extension, returns 0 (false)
934         try {
935             // checks if unaccent extension is installed or not
936             // (1 - yes; unaccent found)
937             $result = (bool) $db->fetchOne($select);
938         } catch (Zend_Db_Statement_Exception $zdse) {
939             // (0 - no; unaccent not found)
940             self::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Unaccent extension disabled (' . $zdse->getMessage() . ')');
941             $result = FALSE;
942         }
943
944         return $result;
945     }
946
947     /**
948      * get db profiling
949      *
950      * Enable db profiling like this (in config.inc.php):
951      *
952      *   'database' =>
953      *      array(
954      *         [...] // db connection params
955      *         'profiler' => TRUE
956      *      ),
957      *   'profiler' =>
958      *      array(
959      *         'queryProfiles' => TRUE,
960      *         'queryProfilesDetails' => TRUE,
961      *         //'profilerFilterElapsedSecs' => 1,
962      *      )
963      *    ),
964      *
965      */
966     public static function getDbProfiling()
967     {
968         if (! self::getConfig() || ! self::getConfig()->database || ! (bool) self::getConfig()->database->profiler) {
969             return;
970         }
971
972         $config = self::getConfig()->profiler;
973
974         $profiler = Zend_Db_Table::getDefaultAdapter()->getProfiler();
975
976         if (! empty($config->profilerFilterElapsedSecs)) {
977             $profiler->setFilterElapsedSecs($config->profilerFilterElapsedSecs);
978         }
979
980         $data = array(
981             'totalNumQueries' => $profiler->getTotalNumQueries(),
982             'totalElapsedSec' => $profiler->getTotalElapsedSecs(),
983             'longestTime'        => 0,
984             'longestQuery'       => ''
985         );
986
987         if ($config && (bool) $config->queryProfiles) {
988             $queryProfiles = $profiler->getQueryProfiles();
989             if (is_array($queryProfiles)) {
990                 $data['queryProfiles'] = array();
991                 foreach ($queryProfiles as $profile) {
992                     if ((bool) $config->queryProfilesDetails) {
993                         $data['queryProfiles'][] = array(
994                             'query'       => $profile->getQuery(),
995                             'elapsedSecs' => $profile->getElapsedSecs(),
996                         );
997                     }
998
999                     if ($profile->getElapsedSecs() > $data['longestTime']) {
1000                         $data['longestTime']  = $profile->getElapsedSecs();
1001                         $data['longestQuery'] = $profile->getQuery();
1002                     }
1003                 }
1004             }
1005         }
1006
1007         self::getLogger()->debug(__METHOD__ . ' (' . __LINE__ . ') value: ' . print_r($data, true));
1008     }
1009
1010     /**
1011      * sets the user locale
1012      *
1013      * @param  string $localeString
1014      * @param  bool   $saveaspreference
1015      */
1016     public static function setupUserLocale($localeString = 'auto', $saveaspreference = FALSE)
1017     {
1018         $userSession = Tinebase_User_Session::getSessionNamespace();
1019
1020         if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " given localeString '$localeString'");
1021
1022         // get locale object from session or ...
1023         if ($userSession !== NULL
1024                 && isset($userSession->userLocale)
1025                 && is_object($userSession->userLocale)
1026                 && ($userSession->userLocale->toString() === $localeString || $localeString === 'auto')) {
1027
1028             $locale = $userSession->userLocale;
1029             if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__
1030                 . " Got locale from session : " . (string)$locale);
1031
1032         // ... create new locale object
1033         } else {
1034             if ($localeString === 'auto') {
1035                 // check if cookie or pref with language is available
1036                 if (isset($_COOKIE['TINE20LOCALE'])) {
1037                     $localeString = $_COOKIE['TINE20LOCALE'];
1038                     if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__
1039                         . " Got locale from cookie: '$localeString'");
1040
1041                 } elseif (isset($userSession->currentAccount)) {
1042                     $localeString = self::getPreference()->getValue(Tinebase_Preference::LOCALE, 'auto');
1043                     if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__
1044                         . " Got locale from preference: '$localeString'");
1045                 } else {
1046                     if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__
1047                         . " Try to detect the locale of the user (browser, environment, default)");
1048                 }
1049             }
1050
1051             $locale = Tinebase_Translation::getLocale($localeString);
1052
1053             // save in session
1054             if ($userSession !== NULL) {
1055                 $userSession->userLocale = $locale;
1056             }
1057         }
1058
1059         // save in registry
1060         self::set('locale', $locale);
1061
1062         $localeString = (string)$locale;
1063         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) self::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Setting user locale: " . $localeString);
1064
1065         // save locale as preference
1066         if (is_object(Tinebase_Core::getUser()) && ($saveaspreference || self::getPreference()->{Tinebase_Preference::LOCALE} === 'auto')) {
1067             self::getPreference()->{Tinebase_Preference::LOCALE} = $localeString;
1068         }
1069
1070         // set correct ctype locale, to make sure that the filesystem functions like basename() are working correctly with utf8 chars
1071         $ctypeLocale = setlocale(LC_CTYPE, 0);
1072         if (! preg_match('/utf-?8/i', $ctypeLocale)) {
1073             // use en_US as fallback locale if region string is missing
1074             $newCTypeLocale = ((strpos($localeString, '_') !== FALSE) ? $localeString : 'en_US') . '.UTF8';
1075             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
1076                 . ' Setting CTYPE locale from "' . $ctypeLocale . '" to "' . $newCTypeLocale . '".');
1077             setlocale(LC_CTYPE, $newCTypeLocale);
1078         }
1079     }
1080
1081     /**
1082      * intializes the timezone handling
1083      *
1084      * @param  string $_timezone
1085      * @param  bool   $_saveaspreference
1086      * @return string
1087      */
1088     public static function setupUserTimezone($_timezone = NULL, $_saveaspreference = FALSE)
1089     {
1090         $userSession = Tinebase_User_Session::getSessionNamespace();
1091         if ($_timezone === NULL) {
1092
1093             if ($userSession instanceof Zend_Session_Namespace && isset($userSession->timezone)) {
1094                 $timezone = $userSession->timezone;
1095             } else {
1096                 // get timezone from preferences
1097                 $timezone = date_default_timezone_get();
1098                 if(Tinebase_Session::isStarted() && Zend_Auth::getInstance()->hasIdentity()) {
1099                     $timezone = self::getPreference()->getValue(Tinebase_Preference::TIMEZONE);
1100                 }
1101                 if ($userSession instanceof Zend_Session_Namespace) {
1102                     $userSession->timezone = $timezone;
1103                 }
1104             }
1105         } else {
1106             $timezone = $_timezone;
1107             if ($userSession instanceof Zend_Session_Namespace) {
1108                 $userSession->timezone = $timezone;
1109             }
1110
1111             // saves into database only user is logged
1112             if ($_saveaspreference && Zend_Session::isStarted() && Zend_Auth::getInstance()->hasIdentity()) {
1113                 // save as user preference
1114                 self::getPreference()->setValue(Tinebase_Preference::TIMEZONE, $timezone);
1115             }
1116         }
1117
1118         self::set(self::USERTIMEZONE, $timezone);
1119
1120         return $timezone;
1121     }
1122
1123     /**
1124      * set php execution life (max) time
1125      *
1126      * @param int $_seconds
1127      * @return int old max exexcution time in seconds
1128      */
1129     public static function setExecutionLifeTime($_seconds)
1130     {
1131         $oldMaxExcecutionTime = ini_get('max_execution_time');
1132
1133         if ($oldMaxExcecutionTime > 0) {
1134             if ((bool)ini_get('safe_mode') === true) {
1135                 if (Tinebase_Core::isRegistered(self::LOGGER) && Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
1136                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__
1137                         . ' max_execution_time(' . $oldMaxExcecutionTime . ') is too low. Can\'t set limit to '
1138                         . $_seconds . ' because of safe mode restrictions.');
1139                 }
1140             } else {
1141                 if (Tinebase_Core::isRegistered(self::LOGGER) && Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
1142                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' setting execution life time to: ' . $_seconds);
1143                 }
1144                 set_time_limit($_seconds);
1145             }
1146         }
1147
1148         return $oldMaxExcecutionTime;
1149     }
1150
1151     /**
1152      * set php memory (max) limit
1153      *
1154      * @param string $_limit
1155      * @return string old max memory limit
1156      */
1157     public static function setMemoryLimit($_limit)
1158     {
1159         $oldMaxMemoryLimit = ini_get('memory_limit');
1160
1161         if (! empty($oldMaxMemoryLimit)) {
1162             if ((bool)ini_get('safe_mode') === true) {
1163                 if (Tinebase_Core::isRegistered(self::LOGGER) && Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
1164                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__
1165                         . ' memory_limit(' . $oldMaxMemoryLimit . ') is too low. Can\'t set limit to '
1166                         . $_limit . ' because of safe mode restrictions.');
1167                 }
1168             } else {
1169                 if (Tinebase_Core::isRegistered(self::LOGGER) && Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
1170                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' setting memory limit to: ' . $_limit);
1171                 }
1172                 ini_set('memory_limit', $_limit);
1173             }
1174         }
1175
1176         return $oldMaxMemoryLimit;
1177     }
1178
1179     /**
1180      * log memory usage
1181      *
1182      */
1183     public static function logMemoryUsage()
1184     {
1185         if (function_exists('memory_get_peak_usage')) {
1186             $memory = memory_get_peak_usage(true);
1187         } else {
1188             $memory = memory_get_usage(true);
1189         }
1190
1191         return  ' Memory usage: ' . ($memory / 1024 / 1024) . ' MB';
1192     }
1193
1194     public static function logCacheSize()
1195     {
1196         if(function_exists('realpath_cache_size')) {
1197             $realPathCacheSize = realpath_cache_size();
1198         } else {
1199             $realPathCacheSize = 'unknown';
1200         }
1201
1202         return ' Real patch cache size: ' . $realPathCacheSize;
1203     }
1204
1205     /******************************* REGISTRY ************************************/
1206
1207     /**
1208      * get a value from the registry
1209      *
1210      */
1211     public static function get($index)
1212     {
1213         return (Zend_Registry::isRegistered($index)) ? Zend_Registry::get($index) : NULL;
1214     }
1215
1216     /**
1217      * set a registry value
1218      *
1219      * @return mixed value
1220      */
1221     public static function set($index, $value)
1222     {
1223         Zend_Registry::set($index, $value);
1224     }
1225
1226     /**
1227      * checks a registry value
1228      *
1229      * @return boolean
1230      */
1231     public static function isRegistered($index)
1232     {
1233         return Zend_Registry::isRegistered($index);
1234     }
1235
1236     /**
1237      * Returns the auth typ from config or default value
1238      *
1239      * @return String
1240      */
1241     public static function getAuthType()
1242     {
1243         if (isset(Tinebase_Core::getConfig()->authentication)) {
1244             $authType = Tinebase_Core::getConfig()->authentication->get('backend', Tinebase_Auth::SQL);
1245         } else {
1246             $authType = Tinebase_Auth::SQL;
1247         }
1248
1249         return ucfirst($authType);
1250     }
1251
1252     /**
1253      * get config from the registry
1254      *
1255      * @return Zend_Config|Zend_Config_Ini|Tinebase_Config
1256      */
1257     public static function getConfig()
1258     {
1259         if (! self::get(self::CONFIG)) {
1260             self::setupConfig();
1261         }
1262         return self::get(self::CONFIG);
1263     }
1264
1265     /**
1266      * get max configured loglevel
1267      *
1268      * @return integer
1269      */
1270     public static function getLogLevel()
1271     {
1272         if (! ($logLevel = self::get(self::LOGLEVEL))) {
1273             $config = self::getConfig();
1274             $logLevel = Tinebase_Log::getMaxLogLevel($config->logger);
1275             self::set(self::LOGLEVEL, $logLevel);
1276         }
1277         return $logLevel;
1278     }
1279
1280     /**
1281      * check if given loglevel should be logged
1282      *
1283      * @param  integer $_prio
1284      * @return boolean
1285      */
1286     public static function isLogLevel($_prio)
1287     {
1288         return self::getLogLevel() >= $_prio;
1289     }
1290
1291     /**
1292      * get config from the registry
1293      *
1294      * @return Tinebase_Log the logger
1295      */
1296     public static function getLogger()
1297     {
1298         if (! self::get(self::LOGGER) instanceof Tinebase_Log) {
1299             Tinebase_Core::setupLogger();
1300         }
1301
1302         return self::get(self::LOGGER);
1303     }
1304
1305     /**
1306      * get cache from the registry
1307      *
1308      * @return Zend_Cache_Core the cache
1309      */
1310     public static function getCache()
1311     {
1312         return self::get(self::CACHE);
1313     }
1314
1315     /**
1316      * get session namespace from the registry
1317      *
1318      * @return Zend_Session_Namespace tinebase session namespace
1319      */
1320     /*public static function getSession()
1321     {
1322         return self::get(Tinebase_Session::SESSION);
1323     }*/
1324
1325     /**
1326      * get locale from the registry
1327      *
1328      * @return Zend_Locale
1329      */
1330     public static function getLocale()
1331     {
1332         return self::get(self::LOCALE);
1333     }
1334
1335     /**
1336      * get current user account
1337      *
1338      * @return Tinebase_Model_FullUser the user account record
1339      */
1340     public static function getUser()
1341     {
1342         $result = (self::isRegistered(self::USER)) ? self::get(self::USER) : NULL;
1343         return $result;
1344     }
1345
1346     /**
1347      * get preferences instance by application name (create+save it to registry if it doesn't exist)
1348      *
1349      * @param string $_application
1350      * @param boolean $_throwException throws exception if class does not exist
1351      * @return Tinebase_Preference_Abstract
1352      */
1353     public static function getPreference($_application = 'Tinebase', $_throwException = FALSE)
1354     {
1355         $result = NULL;
1356
1357         if (self::isRegistered(self::PREFERENCES)) {
1358             $prefs = self::get(self::PREFERENCES);
1359             if (isset($prefs[$_application])) {
1360                 $result = $prefs[$_application];
1361             }
1362         } else {
1363             $prefs = array();
1364         }
1365
1366         if ($result === NULL) {
1367             $prefClassName = $_application . '_Preference';
1368             if (@class_exists($prefClassName)) {
1369                 $result = new $prefClassName();
1370                 $prefs[$_application] = $result;
1371                 self::set(self::PREFERENCES, $prefs);
1372             } else if ($_throwException) {
1373                 throw new Tinebase_Exception_NotFound('No preference class found for app ' . $_application);
1374             }
1375         }
1376
1377         return $result;
1378     }
1379
1380     /**
1381      * get db adapter
1382      *
1383      * @return Zend_Db_Adapter_Abstract
1384      */
1385     public static function getDb()
1386     {
1387         if (! self::get(self::DB) instanceof Zend_Db_Adapter_Abstract) {
1388             Tinebase_Core::setupDatabaseConnection();
1389         }
1390
1391         return self::get(self::DB);
1392     }
1393
1394     /**
1395      * get temp dir string (without PATH_SEP at the end)
1396      *
1397      * @return string
1398      */
1399     public static function getTempDir()
1400     {
1401         return self::get(self::TMPDIR);
1402     }
1403
1404     /**
1405      * Singleton instance
1406      *
1407      * @return Zend_Scheduler
1408      */
1409     public static function getScheduler()
1410     {
1411         if (! self::get(self::SCHEDULER) instanceof Zend_Scheduler) {
1412             $scheduler =  new Zend_Scheduler();
1413             $scheduler->setBackend(new Zend_Scheduler_Backend_Db(array(
1414                 'DbAdapter' => self::getDb(),
1415                 'tableName' => SQL_TABLE_PREFIX . 'scheduler',
1416                 'taskClass' => 'Tinebase_Scheduler_Task'
1417             )));
1418
1419             self::set(self::SCHEDULER, $scheduler);
1420         }
1421         return self::get(self::SCHEDULER);
1422     }
1423 }