0011960: print with 300 dpi by default
[tine20] / 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  * dispatcher and initialisation class (functions are static)
15  * - dispatchRequest() function
16  * - initXYZ() functions
17  * - has registry and config
18  *
19  * @package     Tinebase
20  * @subpackage  Server
21  */
22 class Tinebase_Core
23 {
24     /**************** registry indexes *************************/
25
26     /**
27      * constant for config registry index
28      */
29     const CONFIG = 'configFile';
30
31     /**
32      * constant for locale registry index
33      */
34     const LOCALE = 'locale';
35
36     /**
37      * constant for logger registry index
38      */
39     const LOGGER = 'logger';
40     
41     /**
42      * constant for loglevel registry index
43      *
44      */
45     const LOGLEVEL = 'loglevel';
46
47     /**
48      * constant for cache registry index
49      */
50     const CACHE = 'cache';
51     
52      /**
53      * constant for shared cache registry index
54      */
55     const SHAREDCACHE = 'sharedCache';
56
57     /**
58      * constant for session namespace (tinebase) registry index
59      */
60     const SESSION = 'session';
61     
62     /**
63      * session id constant
64      */
65     const SESSIONID = 'sessionId';
66
67     /**
68      * constant for application start time in ms registry index
69      */
70     const STARTTIME = 'starttime';
71     
72     const REQUEST = 'request';
73
74     /**
75      * constant for current account/user
76      */
77     const USER = 'currentAccount';
78
79     /**
80      * const for current users credentialcache
81      */
82     const USERCREDENTIALCACHE = 'usercredentialcache';
83
84     /**
85      * const for current users access log
86      */
87     const USERACCESSLOG = 'useraccesslog';
88
89     /**
90      * constant for database adapter
91      */
92     const DB = 'dbAdapter';
93     
94     /**
95      * constant for database adapter name
96      * 
97      */
98     const DBNAME = 'dbAdapterName';
99
100     /**
101      * constant for database adapter
102      */
103     const USERTIMEZONE = 'userTimeZone';
104
105     /**
106      * constant for preferences registry
107      */
108     const PREFERENCES = 'preferences';
109     
110     /**
111      * constant for preferences registry
112      */
113     const SCHEDULER = 'scheduler';
114     
115     /**
116      * constant temp dir registry
117      */
118     const TMPDIR = 'tmpdir';
119     
120     /**
121      * constant temp dir registry
122      */
123     const FILESDIR = 'filesdir';
124     
125     /**
126      * constant for request method registry
127      */
128     const METHOD = 'method';
129     
130     /**
131      * const PDO_MYSQL
132      *
133      */
134     const PDO_MYSQL = 'Pdo_Mysql';
135     
136     /**
137      * minimal version of MySQL supported
138      */
139     const MYSQL_MINIMAL_VERSION = '5.0.0';
140     
141     /**
142      * const PDO_PGSQL
143      *
144      */
145     const PDO_PGSQL = 'Pdo_Pgsql';
146     
147     /**
148      * minimal version of PostgreSQL supported
149      */
150     const PGSQL_MINIMAL_VERSION = '8.4.8';
151
152     /**
153      * const PDO_OCI
154      *
155      */
156     const PDO_OCI = 'Pdo_Oci';
157     
158     /**
159      * const ORACLE
160      * Zend_Db adapter name for the oci8 driver.
161      *
162      */
163     const ORACLE = 'Oracle';
164     
165     /**
166      * minimal version of Oracle supported
167      */
168     const ORACLE_MINIMAL_VERSION = '9.0.0';
169
170     /**
171      * Key for storing server plugins into cache
172      *
173      * @var string
174      */
175     const TINEBASE_SERVER_PLUGINS = 'Tinebase_Server_Plugins';
176
177     /**
178      * name of frontend server class
179      *
180      * @var string
181      */
182     const SERVER_CLASS_NAME = 'serverclassname';
183
184     /**
185      * Application Instance Cache
186      * @var array
187      */
188     protected static $appInstanceCache = array();
189     
190     /**
191      * current cache status, maybe NULL / uninitialized, true / enabled, false / disabled
192      * @var boolean
193      */
194     protected static $cacheStatus = NULL;
195     
196     /**
197      * variable to cache value of logLevel during request
198      * 
199      * @var int
200      */
201     protected static $logLevel = null;
202
203     /**
204      * Server classes provided by applications
205      *
206      * @var array
207      */
208     protected static $_serverPlugins = array();
209
210     /******************************* DISPATCH *********************************/
211     
212     /**
213      * dispatch request
214      */
215     public static function dispatchRequest()
216     {
217         $request = new \Zend\Http\PhpEnvironment\Request();
218         self::set(self::REQUEST, $request);
219         
220         // check transaction header
221         if ($request->getHeaders()->has('X-TINE20-TRANSACTIONID')) {
222             $transactionId = $request->getHeaders()->get('X-TINE20-TRANSACTIONID')->getFieldValue();
223             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Client transaction $transactionId");
224             Tinebase_Log_Formatter::setPrefix(substr($transactionId, 0, 5));
225         }
226         
227         $server = self::getDispatchServer($request);
228         
229         $server->handle($request);
230         $method = get_class($server) . '::' . $server->getRequestMethod();
231         self::set(self::METHOD, $method);
232         
233         self::finishProfiling();
234         self::getDbProfiling();
235     }
236     
237     /**
238      * dispatch request
239      * 
240      * @param \Zend\Http\Request $request
241      * @return Tinebase_Server_Interface|null
242      */
243     public static function getDispatchServer(\Zend\Http\Request $request)
244     {
245         // Test server conditions from server plugins
246         foreach (self::_getServerPlugins() as $serverPlugin){
247             $server = call_user_func_array(array($serverPlugin,'getServer'), array($request));
248             
249             if ($server instanceof Tinebase_Server_Interface) {
250                 Tinebase_Core::set('serverclassname', get_class($server));
251                 
252                 return $server;
253             }
254         }
255
256         if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
257              Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . " Request: " . $request->toString());
258         }
259         throw new Tinebase_Exception('No valid server found for request');
260     }
261     
262     /**
263      * returns TRUE if request is HTTPS
264      * 
265      * @return boolean
266      */
267     public static function isHttpsRequest()
268     {
269         return (! empty($_SERVER['HTTPS']) && strtoupper($_SERVER['HTTPS']) != 'OFF');
270     }
271     
272     /**
273      * enable profiling
274      * - supports xhprof
275      */
276     public static function enableProfiling()
277     {
278         if (! self::getConfig() || ! self::getConfig()->profiler) {
279             return;
280         }
281         
282         $config = self::getConfig()->profiler;
283         
284         if ($config && $config->xhprof) {
285             $XHPROF_ROOT = $config->path ? $config->path : '/usr/share/php5-xhprof';
286             if (file_exists($XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php")) {
287                 define('XHPROF_LIB_ROOT', $XHPROF_ROOT . '/xhprof_lib');
288                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Enabling xhprof');
289                 xhprof_enable(XHPROF_FLAGS_MEMORY);
290             } else {
291                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Could not find xhprof lib root');
292             }
293         } 
294     }
295
296     /**
297      * finish profiling / save profiling data to a file
298      * - supports xhprof
299      */
300     public static function finishProfiling()
301     {
302         if (! self::getConfig() || ! self::getConfig()->profiler) {
303             return;
304         }
305         
306         $config = self::getConfig()->profiler;
307         $method = self::get(self::METHOD);
308     
309         if ($config->xhprof) {
310             $xhprof_data = xhprof_disable();
311             
312             if ($config->method) {
313                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Filtering xhprof profiling method: ' . $config->method);
314                 if (! preg_match($config->method, $method)) {
315                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Method mismatch, do not save profiling info.');
316                     return;
317                 }
318             }
319             
320             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Saving xhprof profiling run for method ' . $method);
321             
322             if (! defined('XHPROF_LIB_ROOT')) {
323                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  ' . print_r($xhprof_data, TRUE));
324             } else {
325                 include_once XHPROF_LIB_ROOT . "/utils/xhprof_lib.php";
326                 include_once XHPROF_LIB_ROOT . "/utils/xhprof_runs.php";
327                 $xhprof_runs = new XHProfRuns_Default();
328                 $run_id = $xhprof_runs->save_run($xhprof_data, "tine");
329             }
330         }
331     }
332     
333     /******************************* APPLICATION ************************************/
334
335     /**
336      * returns an instance of the controller of an application
337      *
338      * @param   string $_applicationName appname / modelname
339      * @param   string $_modelName
340      * @return  Tinebase_Controller_Abstract|Tinebase_Controller_Record_Abstract the controller of the application
341      * @throws  Tinebase_Exception_NotFound
342      */
343     public static function getApplicationInstance($_applicationName, $_modelName = '', $_ignoreACL = FALSE)
344     {
345         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
346             . ' Params: application: ' . $_applicationName . ' / model: ' . $_modelName);
347         
348         $cacheKey = $_applicationName . '_' . $_modelName . '_' . ($_ignoreACL?1:0);
349         if (isset(self::$appInstanceCache[$cacheKey])) {
350             return self::$appInstanceCache[$cacheKey];
351         }
352         
353         // modified (some model names can have both . and _ in their names and we should treat them as JS model name
354         if (strpos($_applicationName, '_') && ! strpos($_applicationName, '.')) {
355             // got (complete) model name name as first param
356             list($appName, $i, $modelName) = explode('_', $_applicationName, 3);
357         } else if (strpos($_applicationName, '.')) {
358             // got (complete) model name name as first param (JS style)
359             list($j, $appName, $i, $modelName) = explode('.', $_applicationName, 4);
360         } else {
361             $appName = $_applicationName;
362             $modelName = $_modelName;
363         }
364         
365         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
366             . ' Extracted appName: ' . $appName . ' modelName: ' . $modelName);
367         
368         $controllerName = ucfirst((string) $appName);
369         if ($appName !== 'Tinebase' || ($appName === 'Tinebase' && ! $modelName)) {
370             // only app controllers are called "App_Controller_Model"
371             $controllerName .= '_Controller';
372         }
373         
374         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
375             . ' controllerName: ' . $controllerName);
376
377         if (! empty($modelName)) {
378             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
379                 . ' Checking for model controller ...');
380             
381             $modelName = preg_replace('/^' . $appName . '_' . 'Model_/', '', $modelName);
382             $controllerNameModel = $controllerName . '_' . $modelName;
383             if (! class_exists($controllerNameModel)) {
384                 throw new Tinebase_Exception_NotFound('No Application Controller found (checked class ' . $controllerNameModel . ')!');
385             } else {
386                 $controllerName = $controllerNameModel;
387             }
388         } else if (! class_exists($controllerName)) {
389             throw new Tinebase_Exception_NotFound('No Application Controller found (checked class ' . $controllerName . ')!');
390         }
391         
392         if (! $_ignoreACL && is_object(Tinebase_Core::getUser()) && ! Tinebase_Core::getUser()->hasRight($appName, Tinebase_Acl_Rights_Abstract::RUN)) {
393             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ 
394                 . ' User ' . Tinebase_Core::getUser()->accountDisplayName . '/' . Tinebase_Core::getUser()->getId() . ' has no right to access ' . $appName);
395             throw new Tinebase_Exception_AccessDenied('No right to access application ' . $appName);
396         }
397         
398         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
399             . ' Getting instance of ' . $controllerName);
400         
401         $controller = call_user_func(array($controllerName, 'getInstance'));
402         self::$appInstanceCache[$cacheKey] = $controller;
403         
404         return $controller;
405     }
406     
407     /******************************* SETUP ************************************/
408
409     /**
410      * init tine framework
411      */
412     public static function initFramework()
413     {
414         // avoid autostart of sessions
415         Zend_Session::setOptions(array(
416             'strict' => true
417         ));
418         
419         Tinebase_Core::setupTempDir();
420         
421         Tinebase_Core::setupStreamWrapper();
422         
423         //Cache must be setup before User Locale because otherwise Zend_Locale tries to setup 
424         //its own cache handler which might result in a open_basedir restriction depending on the php.ini settings
425         Tinebase_Core::setupCache();
426         
427         Tinebase_Core::setupBuildConstants();
428         
429         // setup a temporary user locale. This will be overwritten later but we 
430         // need to handle exceptions during initialisation process such as session timeout
431         // @todo add fallback locale to config file
432         Tinebase_Core::set('locale', new Zend_Locale('en_US'));
433         
434         Tinebase_Core::setupUserLocale();
435         
436         Tinebase_Core::enableProfiling();
437         
438         if (PHP_SAPI !== 'cli') {
439             header('X-API: http://www.tine20.org/apidocs/tine20/');
440             if (isset($_SERVER['HTTP_X_TRANSACTIONID'])) {
441                 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');
442             }
443         }
444     }
445     
446     /**
447      * start core session
448      *
449      * @throws Exception
450      */
451     public static function startCoreSession()
452     {
453         Tinebase_Session::setSessionBackend();
454         
455         Zend_Session::start();
456         
457         $coreSession = Tinebase_Session::getSessionNamespace();
458         
459         if (isset($coreSession->currentAccount)) {
460             self::set(self::USER, $coreSession->currentAccount);
461         }
462         
463         if (!isset($coreSession->jsonKey)) {
464             $coreSession->jsonKey = Tinebase_Record_Abstract::generateUID();
465         }
466         self::set('jsonKey', $coreSession->jsonKey);
467     }
468
469     /**
470      * return current session id
471      *
472      * @param boolean $generateUid
473      * @return mixed|null
474      */
475     public static function getSessionId($generateUid = true)
476     {
477         if (! self::isRegistered(self::SESSIONID)) {
478             $sessionId = null;
479             // TODO allow to access Tinebase/Core methods with Setup session and remove this workaround
480             if (Tinebase_Session::isStarted() && ! Tinebase_Session::isSetupSession()) {
481                 $sessionId = Tinebase_Session::getId();
482             }
483             if (empty($sessionId)) {
484                 $sessionId = 'NOSESSION';
485                 if ($generateUid) {
486                     $sessionId .= Tinebase_Record_Abstract::generateUID(31);
487                 }
488             }
489             self::set(self::SESSIONID, $sessionId);
490         }
491
492         return self::get(self::SESSIONID);
493     }
494     
495     /**
496      * initializes the build constants like buildtype, package information, ...
497      */
498     public static function setupBuildConstants()
499     {
500         $config = self::getConfig();
501         define('TINE20_BUILDTYPE',     strtoupper($config->get('buildtype', 'DEVELOPMENT')));
502         define('TINE20_CODENAME',      Tinebase_Helper::getDevelopmentRevision());
503         define('TINE20_PACKAGESTRING', 'none');
504         define('TINE20_RELEASETIME',   'none');
505     }
506     
507     /**
508      * tines error exception handler for catchable fatal errors
509      *
510      * NOTE: PHP < 5.3 don't throws exceptions for Catchable fatal errors per default,
511      * so we convert them into exceptions manually
512      *
513      * @param integer $severity
514      * @param string $errstr
515      * @param string $errfile
516      * @param integer $errline
517      * @throws ErrorException
518      */
519     public static function errorHandler($severity, $errstr, $errfile, $errline)
520     {
521         if (error_reporting() == 0) {
522             return;
523         }
524         
525         $logLine = " $errstr in {$errfile}::{$errline} ($severity)";
526         $e = new Exception('just to get trace');
527         $trace = $e->getTraceAsString();
528         
529         switch ($severity) {
530             case E_COMPILE_ERROR:
531             case E_CORE_ERROR:
532             case E_ERROR:
533             case E_PARSE:
534             case E_RECOVERABLE_ERROR:
535             case E_USER_ERROR:
536                 throw new ErrorException($errstr, 0, $severity, $errfile, $errline);
537                 break;
538                 
539             case E_COMPILE_WARNING:
540             case E_CORE_WARNING:
541             case E_USER_WARNING:
542             case E_WARNING:
543                 if (Tinebase_Core::isRegistered(Tinebase_Core::LOGGER)) {
544                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . $logLine);
545                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . $trace);
546                 } else {
547                     error_log(__METHOD__ . '::' . __LINE__ . $logLine);
548                     error_log(__METHOD__ . '::' . __LINE__ . ' ' . $trace);
549                 }
550                 break;
551                 
552             case E_NOTICE:
553             case E_STRICT:
554             case E_USER_NOTICE:
555             default:
556                 if (Tinebase_Core::isRegistered(Tinebase_Core::LOGGER)) {
557                     Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . $logLine);
558                     Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' ' . $trace);
559                 } else {
560                     error_log(__METHOD__ . '::' . __LINE__ . $logLine);
561                     error_log(__METHOD__ . '::' . __LINE__ . ' ' . $trace);
562                 }
563                 break;
564         }
565     }
566
567     /**
568      * initializes the config
569      */
570     public static function setupConfig()
571     {
572         self::set(self::CONFIG, Tinebase_Config::getInstance());
573     }
574
575     /**
576      * setup temp dir registry setting retrieved by {@see _getTempDir()}
577      *
578      * @return void
579      */
580     public static function setupTempDir()
581     {
582         self::set(self::TMPDIR, self::guessTempDir());
583     }
584
585     /**
586      * figure out temp directory:
587      * config.inc.php > sys_get_temp_dir > session_save_path > /tmp
588      *
589      * @param array $config
590      * @return String
591      */
592     public static function guessTempDir($config = null)
593     {
594         if ($config === null) {
595             $config = self::getConfig();
596             $tmpdir = $config->tmpdir !== Tinebase_Model_Config::NOTSET ? $config->tmpdir : null;
597         } else {
598             $tmpdir = isset($config['tmpdir']) ? $config['tmpdir'] : null;
599         }
600
601         if (! $tmpdir || !@is_writable($tmpdir)) {
602             $tmpdir = sys_get_temp_dir();
603             if (empty($tmpdir) || !@is_writable($tmpdir)) {
604                 $tmpdir = session_save_path();
605                 if (empty($tmpdir) || !@is_writable($tmpdir)) {
606                     $tmpdir = '/tmp';
607                 }
608             }
609         }
610         
611         return $tmpdir;
612     }
613     
614     /**
615      * initializes the logger
616      *
617      * @param $_defaultWriter Zend_Log_Writer_Abstract default log writer
618      */
619     public static function setupLogger(Zend_Log_Writer_Abstract $_defaultWriter = NULL)
620     {
621         $config = self::getConfig();
622         $logger = new Tinebase_Log();
623         
624         if (isset($config->logger) && $config->logger->active) {
625             try {
626                 $logger->addWriterByConfig($config->logger);
627                 if ($config->logger->additionalWriters) {
628                     foreach ($config->logger->additionalWriters as $writerConfig) {
629                         $logger->addWriterByConfig($writerConfig);
630                     }
631                 }
632             } catch (Exception $e) {
633                 error_log("Tine 2.0 can't setup the configured logger! The Server responded: $e");
634                 $writer = ($_defaultWriter === NULL) ? new Zend_Log_Writer_Null() : $_defaultWriter;
635                 $logger->addWriter($writer);
636             }
637             
638             // For saving log into syslog too, create a key syslog into logger (value does not matter)
639             if ((bool) $config->logger->syslog){
640                 $writer = new Zend_Log_Writer_Syslog(array(
641                         'application'   => 'Tine 2.0'
642                 ));
643                 $prio = ($config->logger->priority) ? (int) $config->logger->priority : 3;
644                 $filter = new Zend_Log_Filter_Priority($prio);
645                 $writer->addFilter($filter);
646                 $logger->addWriter($writer);
647             }
648         } else {
649             $writer = new Zend_Log_Writer_Syslog(array(
650                 'application'   => 'Tine 2.0'
651             ));
652             
653             $filter = new Zend_Log_Filter_Priority(Zend_Log::WARN);
654             $writer->addFilter($filter);
655             $logger->addWriter($writer);
656         }
657         
658         self::set(self::LOGGER, $logger);
659         
660         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) $logger->info(__METHOD__ . '::' . __LINE__ .' Logger initialized');
661         if (isset($config->logger) && Tinebase_Core::isLogLevel(Zend_Log::TRACE)) $logger->trace(__METHOD__ . '::' . __LINE__ 
662             .' Logger settings: ' . print_r($config->logger->toArray(), TRUE));
663     }
664     
665     /**
666      * setup the cache and add it to zend registry
667      *
668      * @param bool $_enabled disabled cache regardless what's configured in config.inc.php
669      * 
670      * @todo use the same config keys as Zend_Cache (backend + frontend) to simplify this
671      */
672     public static function setupCache($_enabled = true)
673     {
674         if ( self::$cacheStatus !== NULL && self::$cacheStatus === $_enabled ) {
675             return;
676         }
677         
678         $config = self::getConfig();
679         if ($config->caching && $config->caching->active) {
680             if (isset($config->caching->shared) && ($config->caching->shared === true)) {
681                 self::set(self::SHAREDCACHE, true);
682             } else {
683                 self::set(self::SHAREDCACHE, false);
684             }
685         }
686
687         // create zend cache
688         if ($_enabled === true && $config->caching && $config->caching->active) {
689             $logging = ($config->caching->logging) ? $config->caching->logging : false;
690             $logger = self::getLogger();
691
692             $frontendOptions = array(
693                 'lifetime'                  => ($config->caching->lifetime) ? $config->caching->lifetime : 7200,
694                 'automatic_serialization'   => true, // turn that off for more speed
695                 'caching'                   => true,
696                 'automatic_cleaning_factor' => 0,    // no garbage collection as this is done by a scheduler task
697                 'write_control'             => false, // don't read cache entry after it got written
698                 'logging'                   => $logging,
699                 'logger'                    => $logger,
700             );
701             
702             $backendType = ($config->caching->backend) ? ucfirst($config->caching->backend) : 'File';
703             $backendOptions = ($config->caching->backendOptions) ? $config->caching->backendOptions->toArray() : false;
704             
705             if (! $backendOptions) {
706                 switch ($backendType) {
707                     case 'File':
708                         $backendOptions = array(
709                             'cache_dir'              => ($config->caching->path)     ? $config->caching->path     : Tinebase_Core::getTempDir(),
710                             'hashed_directory_level' => ($config->caching->dirlevel) ? $config->caching->dirlevel : 4, 
711                             'logging'                => $logging,
712                             'logger'                 => $logger,
713                         );
714                         break;
715                         
716                     case 'Memcached':
717                         $host = $config->caching->host ? $config->caching->host : (isset($config->caching->memcached->host)
718                             ? $config->caching->memcached->host : 'localhost');
719                         $port = $config->caching->port ? $config->caching->port : (isset($config->caching->memcached->port)
720                             ? $config->caching->memcached->port : 11211);
721                         $backendOptions = array(
722                             'servers' => array(
723                                 'host' => $host,
724                                 'port' => $port,
725                                 'persistent' => TRUE
726                         ));
727                         break;
728                         
729                     case 'Redis':
730                         $host = $config->caching->host ? $config->caching->host : ($config->caching->redis->host ? $config->caching->redis->host : 'localhost');
731                         $port = $config->caching->port ? $config->caching->port : ($config->caching->redis->port ? $config->caching->redis->port : 6379);
732                         if ($config->caching && $config->caching->prefix) {
733                             $prefix = $config->caching->prefix;
734                         } else if ($config->caching && $config->caching->redis && $config->caching->redis->prefix) {
735                             $prefix = $config->caching->redis->prefix;
736                         } else {
737                             $prefix = ($config->database && $config->database->tableprefix) ? $config->database->tableprefix : 'tine20';
738                         }
739                         $prefix .= '_CACHE_';
740                         $backendOptions = array(
741                             'servers' => array(
742                                 'host'   => $host,
743                                 'port'   => $port,
744                                 'prefix' => $prefix
745                         ));
746                         break;
747                         
748                     default:
749                         $backendOptions = array();
750                         break;
751                 }
752             }
753             
754             Tinebase_Core::getLogger()->INFO(__METHOD__ . '::' . __LINE__ . " cache of backend type '{$backendType}' enabled");
755             
756             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
757                 // logger is an object, that makes ugly traces :)
758                 $backendOptionsWithoutLogger = $backendOptions;
759                 if (isset($backendOptionsWithoutLogger['logger'])) {
760                     unset($backendOptionsWithoutLogger['logger']);
761                 }
762                 Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " backend options: " . print_r($backendOptionsWithoutLogger, TRUE));
763             }
764             
765         } else {
766             Tinebase_Core::getLogger()->INFO(__METHOD__ . '::' . __LINE__ . ' Cache disabled');
767             $backendType = 'Test';
768             $frontendOptions = array(
769                 'caching' => false
770             );
771             $backendOptions = array(
772             );
773         }
774         
775         // getting a Zend_Cache_Core object
776         try {
777             $cache = Zend_Cache::factory('Core', $backendType, $frontendOptions, $backendOptions);
778             
779         } catch (Exception $e) {
780             Tinebase_Exception::log($e);
781
782             $enabled = false;
783             if ('File' === $backendType && !is_dir($backendOptions['cache_dir'])) {
784                 Tinebase_Core::getLogger()->INFO(__METHOD__ . '::' . __LINE__ . ' Create cache directory and re-try');
785                 if (mkdir($backendOptions['cache_dir'], 0770, true)) {
786                     $enabled = $_enabled;
787                 }
788             }
789
790             self::setupCache($enabled);
791             return;
792         }
793         
794         // some important caches
795         Zend_Locale::setCache($cache);
796         Zend_Translate::setCache($cache);
797         
798         Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);
799         self::set(self::CACHE, $cache);
800         self::$cacheStatus = $_enabled;
801     }
802     
803     /**
804      * setup stream wrapper for tine20:// prefix
805      * 
806      */
807     public static function setupStreamWrapper()
808     {
809         if (empty(Tinebase_Core::getConfig()->filesdir)) {
810             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ 
811                 . " Filesdir config value not set. tine20:// streamwrapper not registered, virtual filesystem not available.");
812             return;
813         }
814         
815         stream_wrapper_register('tine20', 'Tinebase_FileSystem_StreamWrapper');
816     }
817     
818     /**
819      * initializes the database connection
820      */
821     public static function setupDatabaseConnection()
822     {
823         // check if database connection is setup already 
824         if (self::get(self::DB) instanceof Zend_Db_Adapter_Abstract) {
825             return self::get(self::DB);
826         }
827         
828         $config = self::getConfig();
829         
830         if (!isset($config->database)) {
831             die ("Database section not found in central configuration file.\n");
832         }
833         
834         $dbConfig = $config->database;
835         
836         if (!empty($dbConfig->password)) {
837             self::getLogger()->getFormatter()->addReplacement($dbConfig->password);
838         }
839         
840         if (! defined('SQL_TABLE_PREFIX')) {
841             define('SQL_TABLE_PREFIX', $dbConfig->get('tableprefix') ? $dbConfig->get('tableprefix') : 'tine20_');
842         }
843         
844         $db = self::createAndConfigureDbAdapter($dbConfig->toArray());
845         Zend_Db_Table_Abstract::setDefaultAdapter($db);
846         
847         // place table prefix into the concrete adapter
848         $db->table_prefix = SQL_TABLE_PREFIX;
849         
850         self::set(self::DB, $db);
851         
852         return $db;
853     }
854     
855     /**
856      * create db adapter and configure it for Tine 2.0
857      * 
858      * @param array $dbConfigArray
859      * @param string $dbBackend
860      * @return Zend_Db_Adapter_Abstract
861      * @throws Tinebase_Exception_Backend_Database
862      * @throws Tinebase_Exception_UnexpectedValue
863      */
864     public static function createAndConfigureDbAdapter($dbConfigArray, $dbBackend = NULL)
865     {
866         if ($dbBackend === NULL) {
867             $constName = 'self::' . strtoupper($dbConfigArray['adapter']);
868             if (empty($dbConfigArray['adapter']) || ! defined($constName)) {
869                 self::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Wrong/no db adapter configured (' . $dbConfigArray['adapter'] . '). Using default: ' . self::PDO_MYSQL);
870                 $dbBackend = self::PDO_MYSQL;
871                 $dbConfigArray['adapter'] = self::PDO_MYSQL;
872             } else {
873                 $dbBackend = constant($constName);
874             }
875         }
876         
877         self::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Creating ' . $dbBackend . ' DB adapter');
878         
879         // set utf8 charset
880         $dbConfigArray['charset'] = 'UTF8';
881         $dbConfigArray['adapterNamespace'] = 'Tinebase_Backend_Sql_Adapter';
882         
883         switch ($dbBackend) {
884             case self::PDO_MYSQL:
885                 foreach (array('PDO::MYSQL_ATTR_USE_BUFFERED_QUERY', 'PDO::MYSQL_ATTR_INIT_COMMAND') as $pdoConstant) {
886                     if (! defined($pdoConstant)) {
887                         throw new Tinebase_Exception_Backend_Database($pdoConstant . ' is not defined. Please check PDO extension.');
888                     }
889                 }
890                 
891                 // @todo set charset to utf8mb4 / @see 0008708: switch to mysql utf8mb4
892                 
893                 // force some driver options
894                 $dbConfigArray['driver_options'] = array(
895                     PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => FALSE,
896                 );
897                 $dbConfigArray['options']['init_commands'] = array(
898                     "SET time_zone = '+0:00'",
899                     "SET SQL_MODE = 'STRICT_ALL_TABLES'",
900                     "SET SESSION group_concat_max_len = 4294967295"
901                 );
902                 $db = Zend_Db::factory('Pdo_Mysql', $dbConfigArray);
903                 break;
904                 
905             case self::PDO_OCI:
906                 $db = Zend_Db::factory('Pdo_Oci', $dbConfigArray);
907                 break;
908                 
909             case self::ORACLE:
910                 $db = Zend_Db::factory(self::ORACLE, $dbConfigArray);
911                 $db->supportPositionalParameters(true);
912                 $db->setLobAsString(true);
913                 break;
914                 
915             case self::PDO_PGSQL:
916                 unset($dbConfigArray['adapter']);
917                 unset($dbConfigArray['tableprefix']);
918                 if (empty($dbConfigArray['port'])) {
919                     $dbConfigArray['port'] = 5432;
920                 }
921                 $dbConfigArray['options']['init_commands'] = array(
922                     "SET timezone = '+0:00'"
923                 );
924                 $db = Zend_Db::factory('Pdo_Pgsql', $dbConfigArray);
925                 
926                 break;
927                 
928             default:
929                 throw new Tinebase_Exception_UnexpectedValue('Invalid database adapter defined. Please set adapter to ' . self::PDO_MYSQL . ' or ' . self::PDO_OCI . ' in config.inc.php.');
930                 break;
931         }
932         
933         return $db;
934     }
935     
936     /**
937      * get db profiling
938      * 
939      * Enable db profiling like this (in config.inc.php):
940      * 
941      *   'database' => 
942      *      array(
943      *         [...] // db connection params  
944      *         'profiler' => TRUE
945      *      ),
946      *   'profiler' =>
947      *      array(
948      *         'queryProfiles' => TRUE,
949      *         'queryProfilesDetails' => TRUE,
950      *         'user' => 'loginname',             // only profile this user 
951      *         'profilerFilterElapsedSecs' => 1,  // only show queries whose elapsed time is equal or greater than this
952      *      )
953      *    ),
954      * 
955      */
956     public static function getDbProfiling()
957     {
958         if (! self::getConfig() || ! self::getConfig()->database || ! (bool) self::getConfig()->database->profiler) {
959             return;
960         }
961         
962         $config = self::getConfig()->profiler;
963         
964         if ($config->user && is_object(self::getUser()) && $config->user !== self::getUser()->accountLoginName) {
965             return;
966         }
967         
968         $profiler = Zend_Db_Table::getDefaultAdapter()->getProfiler();
969         
970         if (! empty($config->profilerFilterElapsedSecs)) {
971             $profiler->setFilterElapsedSecs($config->profilerFilterElapsedSecs);
972         }
973         
974         $data = array(
975             'totalNumQueries' => $profiler->getTotalNumQueries(),
976             'totalElapsedSec' => $profiler->getTotalElapsedSecs(),
977             'longestTime'        => 0,
978             'longestQuery'       => ''
979         );
980         
981         if ($config && (bool) $config->queryProfiles) {
982             $queryProfiles = $profiler->getQueryProfiles();
983             if (is_array($queryProfiles)) {
984                 $data['queryProfiles'] = array();
985                 foreach ($queryProfiles as $profile) {
986                     if ((bool) $config->queryProfilesDetails) {
987                         $data['queryProfiles'][] = array(
988                             'query'       => $profile->getQuery(),
989                             'elapsedSecs' => $profile->getElapsedSecs(),
990                         );
991                     }
992                     
993                     if ($profile->getElapsedSecs() > $data['longestTime']) {
994                         $data['longestTime']  = $profile->getElapsedSecs();
995                         $data['longestQuery'] = $profile->getQuery();
996                     }
997                 }
998                 $profiler->clear();
999             }
1000         }
1001         
1002         self::getLogger()->debug(__METHOD__ . ' (' . __LINE__ . ') value: ' . print_r($data, true));
1003     }
1004
1005     /**
1006      * sets the user locale
1007      *
1008      * @param  string $localeString
1009      */
1010     public static function setupUserLocale($localeString = 'auto')
1011     {
1012         try {
1013             $session = Tinebase_Session::getSessionNamespace();
1014         } catch (Zend_Session_Exception $zse) {
1015             $session = null;
1016         }
1017         
1018         if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " given localeString '$localeString'");
1019         
1020         // get locale object from session or ...
1021         if (   $session !== NULL
1022             && isset($session->userLocale)
1023             && is_object($session->userLocale)
1024             && ($session->userLocale->toString() === $localeString || $localeString === 'auto')
1025         ) {
1026             $locale = $session->userLocale;
1027
1028             if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__
1029                 . " Got locale from session : " . (string)$locale);
1030             
1031         // ... create new locale object
1032         } else {
1033             if ($localeString === 'auto') {
1034                 // check if cookie or pref with language is available
1035                 if (isset($_COOKIE['TINE20LOCALE'])) {
1036                     $localeString = $_COOKIE['TINE20LOCALE'];
1037                     if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__
1038                         . " Got locale from cookie: '$localeString'");
1039                     
1040                 } elseif (isset($session->currentAccount)) {
1041                     $localeString = self::getPreference()->getValue(Tinebase_Preference::LOCALE, 'auto');
1042                     if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
1043                         . " Got locale from preference: '$localeString'");
1044                 } else {
1045                     if (self::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
1046                         . " Try to detect the locale of the user (browser, environment, default)");
1047                 }
1048             }
1049             
1050             $locale = Tinebase_Translation::getLocale($localeString);
1051             
1052             // save in session
1053             if ($session !== NULL) {
1054                 $session->userLocale = $locale;
1055             }
1056             
1057             // check if the detected locale should be saved in preferences
1058             if ($localeString === 'auto' && is_object(Tinebase_Core::getUser()) && (string)$locale !== 'en') {
1059                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) self::getLogger()->debug(__METHOD__ . '::' . __LINE__
1060                     . " Saving locale: " . (string)$locale);
1061                 self::getPreference()->{Tinebase_Preference::LOCALE} = (string)$locale;
1062             }
1063         }
1064         
1065         // save in registry
1066         self::set('locale', $locale);
1067         
1068         $localeString = (string)$locale;
1069         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) self::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Setting user locale: " . $localeString);
1070         
1071         // set correct ctype locale, to make sure that the filesystem functions like basename() are working correctly with utf8 chars
1072         $ctypeLocale = setlocale(LC_CTYPE, 0);
1073         if (! preg_match('/utf-?8/i', $ctypeLocale)) {
1074             // use en_US as fallback locale if region string is missing
1075             $newCTypeLocale = ((strpos($localeString, '_') !== FALSE) ? $localeString : 'en_US') . '.UTF8';
1076             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
1077                 . ' Setting CTYPE locale from "' . $ctypeLocale . '" to "' . $newCTypeLocale . '".');
1078             setlocale(LC_CTYPE, $newCTypeLocale);
1079         }
1080     }
1081
1082     /**
1083      * intializes the timezone handling
1084      *
1085      * @param  string $_timezone
1086      * @param  bool   $_saveaspreference
1087      * @return string
1088      */
1089     public static function setupUserTimezone($_timezone = null, $_saveaspreference = FALSE)
1090     {
1091         try {
1092             $session = Tinebase_Session::getSessionNamespace();
1093         } catch (Zend_Session_Exception $zse) {
1094             $session = null;
1095         }
1096         
1097         // get timezone from session, parameter or preference
1098         if ($_timezone === null && $session instanceof Zend_Session_Namespace && isset($session->timezone)) {
1099             $timezone = $session->timezone;
1100         } else {
1101             $timezone = $_timezone;
1102         }
1103         if ($timezone === null) {
1104             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
1105                 . ' get timezone from preferences');
1106             $timezone = self::getPreference()->getValue(Tinebase_Preference::TIMEZONE);
1107         }
1108         
1109         // set timezone in registry, session and preference
1110         self::set(self::USERTIMEZONE, $timezone);
1111         if ($session instanceof Zend_Session_Namespace && Tinebase_Session::isWritable()) {
1112             $session->timezone = $timezone;
1113         }
1114         if ($_saveaspreference) {
1115             self::getPreference()->setValue(Tinebase_Preference::TIMEZONE, $timezone);
1116         }
1117         
1118         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
1119                 . ' User timezone: ' . $timezone);
1120         
1121         return $timezone;
1122     }
1123
1124     /**
1125      * set php execution life (max) time
1126      *
1127      * @param int $_seconds
1128      * @return int old max execution time in seconds
1129      */
1130     public static function setExecutionLifeTime($_seconds)
1131     {
1132         $oldMaxExcecutionTime = ini_get('max_execution_time');
1133         
1134         if ($oldMaxExcecutionTime > 0) {
1135             $safeModeSetting = ini_get('safe_mode');
1136             if ($safeModeSetting !== 'off' && (bool) $safeModeSetting === true) {
1137                 if (Tinebase_Core::isRegistered(self::LOGGER) && Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
1138                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ 
1139                         . ' max_execution_time(' . $oldMaxExcecutionTime . ') is too low. Can\'t set limit to ' 
1140                         . $_seconds . ' because of safe mode restrictions. safe_mode = ' . $safeModeSetting);
1141                 }
1142             } else {
1143                 if (Tinebase_Core::isRegistered(self::LOGGER) && Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
1144                     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' setting execution life time to: ' . $_seconds);
1145                 }
1146                 set_time_limit($_seconds);
1147             }
1148         }
1149         
1150         return $oldMaxExcecutionTime;
1151     }
1152     
1153     /**
1154      * set php memory (max) limit
1155      *
1156      * @param string $_limit
1157      * @return string old max memory limit
1158      */
1159     public static function setMemoryLimit($_limit)
1160     {
1161         $oldMaxMemoryLimit = ini_get('memory_limit');
1162         
1163         if (! empty($oldMaxMemoryLimit)) {
1164             if ((bool)ini_get('safe_mode') === true) {
1165                 if (Tinebase_Core::isRegistered(self::LOGGER) && Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
1166                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ 
1167                         . ' memory_limit(' . $oldMaxMemoryLimit . ') is too low. Can\'t set limit to ' 
1168                         . $_limit . ' because of safe mode restrictions.');
1169                 }
1170             } else {
1171                 if (Tinebase_Core::isRegistered(self::LOGGER) && Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
1172                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' setting memory limit to: ' . $_limit);
1173                 }
1174                 ini_set('memory_limit', $_limit);
1175             }
1176         }
1177         
1178         return $oldMaxMemoryLimit;
1179     }
1180     
1181     /**
1182      * log memory usage
1183      *
1184      */
1185     public static function logMemoryUsage()
1186     {
1187         if (function_exists('memory_get_peak_usage')) {
1188             $memory = memory_get_peak_usage(true);
1189         } else {
1190             $memory = memory_get_usage(true);
1191         }
1192         
1193         return  ' Memory usage: ' . ($memory / 1024 / 1024) . ' MB';
1194     }
1195     
1196     public static function logCacheSize()
1197     {
1198         if(function_exists('realpath_cache_size')) {
1199             $realPathCacheSize = realpath_cache_size();
1200         } else {
1201             $realPathCacheSize = 'unknown';
1202         }
1203         
1204         return ' Real patch cache size: ' . $realPathCacheSize;
1205     }
1206     
1207     /******************************* REGISTRY ************************************/
1208     
1209     /**
1210      * get a value from the registry
1211      *
1212      */
1213     public static function get($index)
1214     {
1215         try {
1216             return Zend_Registry::get($index);
1217         } catch (Zend_Exception $ze) {
1218             return null;
1219         }
1220     }
1221     
1222     /**
1223      * set a registry value
1224      * 
1225      * @throws Tinebase_Exception_InvalidArgument
1226      * @return mixed value
1227      */
1228     public static function set($index, $value)
1229     {
1230         if ($index === self::USER) {
1231             if ($value === null) {
1232                 throw new Tinebase_Exception_InvalidArgument('Invalid user object!');
1233             }
1234             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
1235                 if ($value instanceof Tinebase_Model_FullUser) {
1236                     $userString =  $value->accountLoginName;
1237                 } else if ($value instanceof Tinebase_Model_User) {
1238                     $userString = $value->accountDisplayName;
1239                 } else {
1240                     $userString = var_export($value, true);
1241                 }
1242                 
1243                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Setting user ' . $userString);
1244             }
1245         }
1246         
1247         Zend_Registry::set($index, $value);
1248     }
1249     
1250     /**
1251      * checks a registry value
1252      *
1253      * @return boolean
1254      */
1255     public static function isRegistered($index)
1256     {
1257         return Zend_Registry::isRegistered($index);
1258     }
1259
1260     /**
1261      * Returns the auth typ from config or default value
1262      *
1263      * @return String
1264      */
1265     public static function getAuthType()
1266     {
1267         if (isset(Tinebase_Core::getConfig()->authentication)) {
1268             $authType = Tinebase_Core::getConfig()->authentication->get('backend', Tinebase_Auth::SQL);
1269         } else {
1270             $authType = Tinebase_Auth::SQL;
1271         }
1272
1273         return ucfirst($authType);
1274     }
1275     
1276     /**
1277      * get config from the registry
1278      *
1279      * @return Zend_Config|Zend_Config_Ini|Tinebase_Config
1280      */
1281     public static function getConfig()
1282     {
1283         if (! self::get(self::CONFIG)) {
1284             self::setupConfig();
1285         }
1286         return self::get(self::CONFIG);
1287     }
1288     
1289     /**
1290      * get max configured loglevel
1291      * 
1292      * @return integer
1293      */
1294     public static function getLogLevel()
1295     {
1296         if (! ($logLevel = self::get(self::LOGLEVEL))) {
1297             $config = self::getConfig();
1298             $logLevel = Tinebase_Log::getMaxLogLevel(isset($config->logger) ? $config->logger : NULL);
1299             self::set(self::LOGLEVEL, $logLevel);
1300         }
1301         
1302         return $logLevel;
1303     }
1304     
1305     /**
1306      * check if given loglevel should be logged
1307      * 
1308      * @param  integer $_prio
1309      * @return boolean
1310      */
1311     public static function isLogLevel($_prio)
1312     {
1313         if (! isset(self::$logLevel) || self::$logLevel === 0 ) {
1314             self::$logLevel = self::getLogLevel();
1315         }
1316
1317         return self::$logLevel >= $_prio;
1318     }
1319     
1320     /**
1321      * get config from the registry
1322      *
1323      * @return Tinebase_Log the logger
1324      */
1325     public static function getLogger()
1326     {
1327         if (! self::get(self::LOGGER) instanceof Tinebase_Log) {
1328             Tinebase_Core::setupLogger();
1329         }
1330         
1331         return self::get(self::LOGGER);
1332     }
1333     
1334     /**
1335      * get cache from the registry
1336      *
1337      * @return Zend_Cache_Core the cache
1338      */
1339     public static function getCache()
1340     {
1341         return self::get(self::CACHE);
1342     }
1343     
1344     /**
1345      * get credentials cache from the registry or initialize it
1346      *
1347      * @return  Tinebase_Model_CredentialCache
1348      */
1349     public static function getUserCredentialCache()
1350     {
1351         if (! self::get(self::USERCREDENTIALCACHE) instanceof Tinebase_Model_CredentialCache && self::getUser()) {
1352             try {
1353                 $cache = Tinebase_Auth_CredentialCache::getInstance()->getCacheAdapter()->getCache();
1354             } catch (Zend_Db_Statement_Exception $zdse) {
1355                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
1356                     . " Could not get credential cache adapter, perhaps Tine 2.0 is not installed yet");
1357                 $cache = NULL;
1358             }
1359         
1360             if ($cache !== NULL) {
1361                 self::set(self::USERCREDENTIALCACHE, $cache);
1362             }
1363         }
1364         
1365         return self::get(self::USERCREDENTIALCACHE);
1366     }
1367     
1368     /**
1369      * get locale from the registry
1370      *
1371      * @return Zend_Locale
1372      */
1373     public static function getLocale()
1374     {
1375         return self::get(self::LOCALE);
1376     }
1377         
1378     /**
1379      * get current user account
1380      *
1381      * @return Tinebase_Model_FullUser the user account record
1382      */
1383     public static function getUser()
1384     {
1385         return self::get(self::USER);
1386     }
1387
1388     /**
1389      * get current users timezone
1390      *
1391      * @return string the current users timezone string
1392      */
1393     public static function getUserTimezone()
1394     {
1395         if (!self::isRegistered(self::USERTIMEZONE) || ($return = self::get(self::USERTIMEZONE)) === NULL) {
1396             return Tinebase_Core::setupUserTimezone();
1397         }
1398         
1399         return $return;
1400     }
1401
1402     /**
1403      * get preferences instance by application name (create+save it to registry if it doesn't exist)
1404      *
1405      * @param string $_application
1406      * @param boolean $_throwException throws exception if class does not exist
1407      * @return Tinebase_Preference_Abstract
1408      */
1409     public static function getPreference($_application = 'Tinebase', $_throwException = FALSE)
1410     {
1411         $result = NULL;
1412
1413         if (self::isRegistered(self::PREFERENCES)) {
1414             $prefs = self::get(self::PREFERENCES);
1415             if (isset($prefs[$_application])) {
1416                 $result = $prefs[$_application];
1417             }
1418         } else {
1419             $prefs = array();
1420         }
1421
1422         if ($result === NULL) {
1423             $prefClassName = $_application . '_Preference';
1424             if (@class_exists($prefClassName)) {
1425                 $result = new $prefClassName();
1426                 $prefs[$_application] = $result;
1427                 self::set(self::PREFERENCES, $prefs);
1428             } else if ($_throwException) {
1429                 throw new Tinebase_Exception_NotFound('No preference class found for app ' . $_application);
1430             }
1431         }
1432
1433         return $result;
1434     }
1435     
1436     /**
1437      * get db adapter
1438      *
1439      * @return Zend_Db_Adapter_Abstract
1440      */
1441     public static function getDb()
1442     {
1443         if (! self::get(self::DB) instanceof Zend_Db_Adapter_Abstract) {
1444             Tinebase_Core::setupDatabaseConnection();
1445         }
1446         
1447         return self::get(self::DB);
1448     }
1449     
1450     /**
1451      * get db name
1452      * 
1453      * @return string
1454      */
1455     public static function getDbName()
1456     {
1457         if (! self::get(self::DBNAME)) {
1458             $db = self::getDb();
1459             $adapterName = get_class($db);
1460     
1461             if (empty($adapterName) || strpos($adapterName, '_') === FALSE) {
1462                 throw new Tinebase_Exception('Could not get DB adapter name.');
1463             }
1464     
1465             $adapterNameParts = explode('_', $adapterName);
1466             $type = array_pop($adapterNameParts);
1467     
1468             // special handling for Oracle
1469             $type = str_replace('Oci', self::ORACLE, $type);
1470             self::set(self::DBNAME, $type);
1471         }
1472         
1473         return self::get(self::DBNAME);
1474     }
1475     
1476     /**
1477      * get temp dir string (without PATH_SEP at the end)
1478      *
1479      * @return string
1480      */
1481     public static function getTempDir()
1482     {
1483         return self::get(self::TMPDIR);
1484     }
1485     
1486     /**
1487      * returns protocol + hostname
1488      * 
1489      * @return string
1490      */
1491     public static function getHostname()
1492     {
1493         $hostname = self::get('HOSTNAME');
1494         if (! $hostname) {
1495             $request = new Sabre\HTTP\Request();
1496             $hostname = strlen($request->getUri()) > 1 ?
1497                 str_replace($request->getUri(), '', $request->getAbsoluteUri()) :
1498                 $request->getAbsoluteUri();
1499
1500             self::set('HOSTNAME', $hostname);
1501         }
1502         
1503         return $hostname;
1504     }
1505
1506     /**
1507      * returns requested url part
1508      *
1509      * @param string $part
1510      * @return string
1511      */
1512     public static function getUrl($part = 'full')
1513     {
1514         $request = new Zend_Controller_Request_Http();
1515         $pathname = $request->getBasePath();
1516         $hostname = $request->getHttpHost();
1517         $protocol = $request->getScheme();
1518
1519         switch ($part) {
1520             case 'path':
1521                 $url = $pathname;
1522                 break;
1523             case 'host':
1524                 $url = $hostname;
1525                 break;
1526             case 'protocol':
1527                 $url = $protocol;
1528                 break;
1529             case 'full':
1530             default:
1531                 $url = $protocol . '://' . $hostname . $pathname;
1532                 break;
1533         }
1534
1535         return $url;
1536     }
1537
1538     /**
1539      * Singleton instance
1540      *
1541      * @return Zend_Scheduler
1542      */
1543     public static function getScheduler()
1544     {
1545         if (! self::get(self::SCHEDULER) instanceof Zend_Scheduler) {
1546             $scheduler =  new Zend_Scheduler();
1547             $scheduler->setBackend(new Zend_Scheduler_Backend_Db(array(
1548                 'DbAdapter' => self::getDb(),
1549                 'tableName' => SQL_TABLE_PREFIX . 'scheduler',
1550                 'taskClass' => 'Tinebase_Scheduler_Task'
1551             )));
1552             
1553             self::set(self::SCHEDULER, $scheduler);
1554         }
1555         return self::get(self::SCHEDULER);
1556     }
1557     
1558     /**
1559      * filter input string for database as some databases (looking at you, MySQL) can't cope with some chars
1560      * 
1561      * @param string $string
1562      * @return string
1563      *
1564      * @see 0008644: error when sending mail with note (wrong charset)
1565      * @see http://stackoverflow.com/questions/1401317/remove-non-utf8-characters-from-string/8215387#8215387
1566      * @see http://stackoverflow.com/questions/8491431/remove-4-byte-characters-from-a-utf-8-string
1567      */
1568     public static function filterInputForDatabase($string)
1569     {
1570         if (self::getDb() instanceof Zend_Db_Adapter_Pdo_Mysql) {
1571             $string = Tinebase_Helper::mbConvertTo($string);
1572             
1573             // remove 4 byte utf8
1574             $result = preg_replace('/[\xF0-\xF7].../s', '?', $string);
1575         } else {
1576             $result = $string;
1577         }
1578         
1579         return $result;
1580     }
1581     
1582     /**
1583      * checks if a system command exists. Works on POSIX systems.
1584      * 
1585      * @param string $name
1586      * @return bool
1587      */
1588     public static function systemCommandExists($name)
1589     {
1590         $ret = shell_exec('which ' . $name);
1591         return ! empty($ret);
1592     }
1593     
1594     /**
1595      * calls a system command with escapeshellcmd
1596      * 
1597      * @param string $cmd
1598      * @return bool
1599      */
1600     public static function callSystemCommand($cmd)
1601     {
1602         return shell_exec(escapeshellcmd($cmd));
1603     }
1604
1605     /**
1606      * Search server plugins from applications configuration
1607      *
1608      */
1609     protected static function _searchServerPlugins()
1610     {
1611         $cache = Tinebase_Core::getCache();
1612         
1613         if ($cache &&
1614             $plugins = $cache->load(self::TINEBASE_SERVER_PLUGINS)
1615         ) {
1616             return $plugins;
1617         }
1618         
1619         // get list of available applications
1620         $applications = array();
1621         
1622         $d = dir(realpath(__DIR__ . '/../'));
1623         
1624         while (false !== ($entry = $d->read())) {
1625            if ($entry[0] == '.') {
1626                continue;
1627            }
1628            
1629            if (ctype_upper($entry[0]) && is_dir($d->path . DIRECTORY_SEPARATOR . $entry)) {
1630                 $applications[] = $entry;
1631            }
1632         }
1633         
1634         $d->close();
1635         
1636         // get list of plugins
1637         $plugins = array();
1638         
1639         foreach ($applications as $application) {
1640             $config = $application . '_Config';
1641             
1642             try {
1643                 if (class_exists($config)) {
1644                     $reflectedClass = new ReflectionClass($config);
1645                     
1646                     if ($reflectedClass->isSubclassOf('Tinebase_Config_Abstract')) {
1647                         $plugins = array_merge(
1648                             $plugins,
1649                             call_user_func(array($config,'getServerPlugins'))
1650                         );
1651                     }
1652                 }
1653             } catch (Exception $e) {
1654                 Tinebase_Exception::log($e);
1655             }
1656         }
1657         
1658         // sort plugins by priority
1659         asort($plugins);
1660         
1661         $plugins = array_keys($plugins);
1662         
1663         if ($cache) {
1664             $cache->save($plugins, self::TINEBASE_SERVER_PLUGINS);
1665         }
1666         
1667         return $plugins;
1668     }
1669
1670     /**
1671      * Return server plugins ensuring that they were found
1672      *
1673      * @return array
1674      */
1675     protected static function _getServerPlugins()
1676     {
1677         if (empty(self::$_serverPlugins)) {
1678             self::$_serverPlugins = self::_searchServerPlugins();
1679         }
1680
1681         return self::$_serverPlugins;
1682     }
1683
1684     /**
1685      * returns TRUE if filesystem is available
1686      *
1687      *  - value is stored in session and registry for caching
1688      *
1689      * @return boolean
1690      */
1691     public static function isFilesystemAvailable()
1692     {
1693         $isFileSystemAvailable = self::get('FILESYSTEM');
1694         if ($isFileSystemAvailable === null) {
1695             try {
1696                 $session = Tinebase_Session::getSessionNamespace();
1697
1698                 if (isset($session->filesystemAvailable)) {
1699                     $isFileSystemAvailable = $session->filesystemAvailable;
1700
1701                     self::set('FILESYSTEM', $isFileSystemAvailable);
1702                     return $isFileSystemAvailable;
1703                 }
1704             } catch (Zend_Session_Exception $zse) {
1705                 $session = null;
1706             }
1707
1708             $isFileSystemAvailable = (!empty(Tinebase_Core::getConfig()->filesdir) && is_writeable(Tinebase_Core::getConfig()->filesdir));
1709
1710             if ($session instanceof Zend_Session_Namespace) {
1711                 if (Tinebase_Session::isWritable()) {
1712                     $session->filesystemAvailable = $isFileSystemAvailable;
1713                 }
1714             }
1715
1716             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
1717                 . ' Filesystem available: ' . ($isFileSystemAvailable ? 'yes' : 'no'));
1718
1719             self::set('FILESYSTEM', $isFileSystemAvailable);
1720         }
1721
1722         return $isFileSystemAvailable;
1723     }
1724
1725     /**
1726      * returns true if installation is in maintenance mode
1727      *
1728      * @return bool
1729      */
1730     public static function inMaintenanceMode()
1731     {
1732         $config = self::getConfig();
1733         return !! $config->maintenanceMode;
1734     }
1735
1736     /**
1737      * returns Tine 2.0 user agent string
1738      *
1739      * @param string $submodule
1740      * @return string
1741      */
1742     public static function getTineUserAgent($submodule = '')
1743     {
1744         return 'Tine 2.0 ' . $submodule . '(version ' . TINE20_CODENAME . ' - ' . TINE20_PACKAGESTRING . ')';
1745     }
1746 }