PageRenderTime 56ms CodeModel.GetById 16ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/pkp/classes/core/PKPApplication.inc.php

https://gitlab.com/si77/RCS
PHP | 493 lines | 275 code | 70 blank | 148 comment | 30 complexity | dc30b946027ac7fa6850a94765aa2a60 MD5 | raw file
  1<?php
  2
  3/**
  4 * @file classes/core/PKPApplication.inc.php
  5 *
  6 * Copyright (c) 2000-2011 John Willinsky
  7 * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
  8 *
  9 * @class PKPApplication
 10 * @ingroup core
 11 *
 12 * @brief Class describing this application.
 13 *
 14 */
 15
 16
 17define('REALLY_BIG_NUMBER', 10000);
 18
 19define('ROUTE_COMPONENT', 'component');
 20define('ROUTE_PAGE', 'page');
 21
 22define('ASSOC_TYPE_USER',	0x00001000); // This value used because of bug #6068
 23define('ASSOC_TYPE_USER_GROUP', 0x0100002);
 24
 25define('ASSOC_TYPE_CITATION', 0x0100003);
 26
 27define('ASSOC_TYPE_AUTHOR', 0x0100004);
 28define('ASSOC_TYPE_EDITOR', 0x0100005);
 29
 30class PKPApplication {
 31	var $enabledProducts;
 32	var $allProducts;
 33
 34	function PKPApplication() {
 35		// Configure error reporting
 36		// FIXME: Error logging needs to be suppressed for strict
 37		// and deprecation errors in PHP5 as long as we support PHP 4.
 38		// This is primarily for static method warnings and warnings
 39		// about use of ... =& new ... Static class members cannot be
 40		// declared in PHP4 and ... =& new ... is deprecated since PHP 5.
 41		$errorReportingLevel = E_ALL;
 42		if (defined('E_STRICT')) $errorReportingLevel &= ~E_STRICT;
 43		if (defined('E_DEPRECATED')) $errorReportingLevel &= ~E_DEPRECATED;
 44		@error_reporting($errorReportingLevel);
 45
 46		// Instantiate the profiler
 47		import('lib.pkp.classes.core.PKPProfiler');
 48		$pkpProfiler = new PKPProfiler();
 49
 50		// Begin debug logging
 51		Console::logMemory('', 'PKPApplication::construct');
 52		Console::logSpeed('PKPApplication::construct');
 53
 54		// Seed random number generator
 55		mt_srand(((double) microtime()) * 1000000);
 56
 57		import('lib.pkp.classes.core.Core');
 58		import('lib.pkp.classes.core.String');
 59		import('lib.pkp.classes.core.Registry');
 60
 61		import('lib.pkp.classes.config.Config');
 62
 63		if (Config::getVar('debug', 'display_errors')) {
 64			// Try to switch off normal error display when error display
 65			// is being managed by OJS.
 66			@ini_set('display_errors', false);
 67		}
 68
 69		if (Config::getVar('debug', 'deprecation_warnings')) {
 70			// Switch deprecation warnings back on. This can only be done
 71			// after declaring the Config class as we need access to the
 72			// configuration and we cannot declare the Config class before
 73			// we've switched of deprecation warnings as its declaration
 74			// causes warnings itself.
 75			// FIXME: When we drop PHP4 support and can declare static methods
 76			// as such then we can also include E_STRICT/E_DEPRECATED here as
 77			// nearly all strict/deprecated warnings concern PHP4 support.
 78			@error_reporting($errorReportingLevel);
 79		}
 80
 81		Registry::set('application', $this);
 82
 83		import('lib.pkp.classes.db.DAORegistry');
 84		import('lib.pkp.classes.db.XMLDAO');
 85
 86		import('lib.pkp.classes.cache.CacheManager');
 87
 88		import('classes.security.Validation');
 89		import('lib.pkp.classes.session.SessionManager');
 90		import('classes.template.TemplateManager');
 91
 92		import('lib.pkp.classes.plugins.PluginRegistry');
 93		import('lib.pkp.classes.plugins.HookRegistry');
 94
 95		import('classes.i18n.Locale');
 96
 97		String::init();
 98		set_error_handler(array($this, 'errorHandler'));
 99
100		$microTime = Core::microtime();
101		Registry::set('system.debug.startTime', $microTime);
102
103		$notes = array();
104		Registry::set('system.debug.notes', $notes);
105
106		Registry::set('system.debug.profiler', $pkpProfiler);
107
108		if (Config::getVar('general', 'installed')) {
109			// Initialize database connection
110			$conn =& DBConnection::getInstance();
111
112			if (!$conn->isConnected()) {
113				if (Config::getVar('database', 'debug')) {
114					$dbconn =& $conn->getDBConn();
115					fatalError('Database connection failed: ' . $dbconn->errorMsg());
116				} else {
117					fatalError('Database connection failed!');
118				}
119			}
120		}
121	}
122
123	/**
124	 * Get the current application object
125	 * @return Application
126	 */
127	function &getApplication() {
128		$application =& Registry::get('application');
129		return $application;
130	}
131
132	/**
133	 * Get the request implementation singleton
134	 * @return Request
135	 */
136	function &getRequest() {
137		$request =& Registry::get('request', true, null);
138
139		if (is_null($request)) {
140			import('classes.core.Request');
141
142			// Implicitly set request by ref in the registry
143			$request = new Request();
144		}
145
146		return $request;
147	}
148
149	/**
150	 * Get the dispatcher implementation singleton
151	 * @return Dispatcher
152	 */
153	function &getDispatcher() {
154		$dispatcher =& Registry::get('dispatcher', true, null);
155
156		if (is_null($dispatcher)) {
157			import('lib.pkp.classes.core.Dispatcher');
158
159			// Implicitly set dispatcher by ref in the registry
160			$dispatcher = new Dispatcher();
161
162			// Inject dependency
163			$dispatcher->setApplication($this->getApplication());
164
165			// Inject router configuration
166			$dispatcher->addRouterName('lib.pkp.classes.core.PKPComponentRouter', ROUTE_COMPONENT);
167			$dispatcher->addRouterName('classes.core.PageRouter', ROUTE_PAGE);
168		}
169
170		return $dispatcher;
171	}
172
173	/**
174	 * This executes the application by delegating the
175	 * request to the dispatcher.
176	 */
177	function execute() {
178		// Dispatch the request to the correct handler
179		$dispatcher =& $this->getDispatcher();
180		$dispatcher->dispatch($this->getRequest());
181	}
182
183	/**
184	 * Get the symbolic name of this application
185	 * @return string
186	 */
187	function getName() {
188		return 'pkp-lib';
189	}
190
191	/**
192	 * Get the locale key for the name of this application.
193	 * @return string
194	 */
195	function getNameKey() {
196		// must be implemented by sub-classes
197		assert(false);
198	}
199
200	/**
201	 * Get the "context depth" of this application, i.e. the number of
202	 * parts of the URL after index.php that represent the context of
203	 * the current request (e.g. Journal [1], or Conference and
204	 * Scheduled Conference [2]).
205	 * @return int
206	 */
207	function getContextDepth() {
208		// must be implemented by sub-classes
209		assert(false);
210	}
211
212	/**
213	 * Get the list of the contexts available for this application
214	 * i.e. the various parameters that are needed to represent the
215	 * (e.g. array('journal') or array('conference', 'schedConf'))
216	 * @return Array
217	 */
218	function getContextList() {
219		// must be implemented by sub-classes
220		assert(false);
221	}
222
223	/**
224	 * Get the URL to the XML descriptor for the current version of this
225	 * application.
226	 * @return string
227	 */
228	function getVersionDescriptorUrl() {
229		// must be implemented by sub-classes
230		assert(false);
231	}
232
233	/**
234	 * This function retrieves all enabled product versions once
235	 * from the database and caches the result for further
236	 * access.
237	 *
238	 * @param $category string
239	 * @return array
240	 */
241	function &getEnabledProducts($category = null) {
242		if (is_null($this->enabledProducts)) {
243			$contextDepth = $this->getContextDepth();
244
245			$settingContext = array();
246			if ($contextDepth > 0) {
247				$request =& $this->getRequest();
248				$router =& $request->getRouter();
249
250				// Try to identify the main context (e.g. journal, conference, press),
251				// will be null if none found.
252				$mainContext =& $router->getContext($request, 1);
253
254				// Create the context for the setting if found
255				if ($mainContext) $settingContext[] = $mainContext->getId();
256				$settingContext = array_pad($settingContext, $contextDepth, 0);
257				$settingContext = array_combine($this->getContextList(), $settingContext);
258			}
259
260			$versionDAO =& DAORegistry::getDAO('VersionDAO');
261			$this->enabledProducts =& $versionDAO->getCurrentProducts($settingContext);
262		}
263
264		if (is_null($category)) {
265			return $this->enabledProducts;
266		} elseif (isset($this->enabledProducts[$category])) {
267			return $this->enabledProducts[$category];
268		} else {
269			$returner = array();
270			return $returner;
271		}
272	}
273
274	/**
275	 * Get the list of plugin categories for this application.
276	 */
277	function getPluginCategories() {
278		// To be implemented by sub-classes
279		assert(false);
280	}
281
282	/**
283	 * Return the current version of the application.
284	 * @return Version
285	 */
286	function &getCurrentVersion() {
287		$currentVersion =& $this->getEnabledProducts('core');
288		assert(count($currentVersion)) == 1;
289		return $currentVersion[$this->getName()];
290	}
291
292	/**
293	 * Get the map of DAOName => full.class.Path for this application.
294	 * @return array
295	 */
296	function getDAOMap() {
297		return array(
298			'AccessKeyDAO' => 'lib.pkp.classes.security.AccessKeyDAO',
299			'AuthSourceDAO' => 'lib.pkp.classes.security.AuthSourceDAO',
300			'CaptchaDAO' => 'lib.pkp.classes.captcha.CaptchaDAO',
301			'ControlledVocabDAO' => 'lib.pkp.classes.controlledVocab.ControlledVocabDAO',
302			'ControlledVocabEntryDAO' => 'lib.pkp.classes.controlledVocab.ControlledVocabEntryDAO',
303			'CountryDAO' => 'lib.pkp.classes.i18n.CountryDAO',
304			'CurrencyDAO' => 'lib.pkp.classes.currency.CurrencyDAO',
305			'GroupDAO' => 'lib.pkp.classes.group.GroupDAO',
306			'GroupMembershipDAO' => 'lib.pkp.classes.group.GroupMembershipDAO',
307			'HelpTocDAO' => 'lib.pkp.classes.help.HelpTocDAO',
308			'HelpTopicDAO' => 'lib.pkp.classes.help.HelpTopicDAO',
309			'InterestDAO' => 'lib.pkp.classes.user.InterestDAO',
310			'InterestEntryDAO' => 'lib.pkp.classes.user.InterestEntryDAO',
311			'LanguageDAO' => 'lib.pkp.classes.language.LanguageDAO',
312			'NotificationDAO' => 'lib.pkp.classes.notification.NotificationDAO',
313			'NotificationSettingsDAO' => 'lib.pkp.classes.notification.NotificationSettingsDAO',
314			'ProcessDAO' => 'lib.pkp.classes.process.ProcessDAO',
315			'ScheduledTaskDAO' => 'lib.pkp.classes.scheduledTask.ScheduledTaskDAO',
316			'SessionDAO' => 'lib.pkp.classes.session.SessionDAO',
317			'SignoffDAO' => 'lib.pkp.classes.signoff.SignoffDAO',
318			'SiteDAO' => 'lib.pkp.classes.site.SiteDAO',
319			'SiteSettingsDAO' => 'lib.pkp.classes.site.SiteSettingsDAO',
320			'TimeZoneDAO' => 'lib.pkp.classes.i18n.TimeZoneDAO',
321			'TemporaryFileDAO' => 'lib.pkp.classes.file.TemporaryFileDAO',
322			'VersionDAO' => 'lib.pkp.classes.site.VersionDAO',
323			'XMLDAO' => 'lib.pkp.classes.db.XMLDAO'
324		);
325	}
326
327	/**
328	 * Return the fully-qualified (e.g. page.name.ClassNameDAO) name of the
329	 * given DAO.
330	 * @param $name string
331	 * @return string
332	 */
333	function getQualifiedDAOName($name) {
334		$map =& Registry::get('daoMap', true, $this->getDAOMap());
335		if (isset($map[$name])) return $map[$name];
336		return null;
337	}
338
339	/**
340	 * Instantiate the help object for this application.
341	 * @return object
342	 */
343	function &instantiateHelp() {
344		// must be implemented by sub-classes
345		assert(false);
346	}
347
348	/**
349	 * Custom error handler
350	 *
351	 * NB: Custom error handlers are called for all error levels
352	 * independent of the error_reporting parameter.
353	 * @param $errorno string
354	 * @param $errstr string
355	 * @param $errfile string
356	 * @param $errline string
357	 */
358	function errorHandler($errorno, $errstr, $errfile, $errline) {
359		// We only report/log errors if their corresponding
360		// error level bit is set in error_reporting.
361		// We have to check error_reporting() each time as
362		// some application parts change the setting (e.g.
363		// smarty, adodb, certain plugins).
364		if(error_reporting() & $errorno) {
365			if ($errorno == E_ERROR) {
366				echo 'An error has occurred.  Please check your PHP log file.';
367			} elseif (Config::getVar('debug', 'display_errors')) {
368				echo $this->buildErrorMessage($errorno, $errstr, $errfile, $errline) . "<br/>\n";
369			}
370
371			error_log($this->buildErrorMessage($errorno, $errstr, $errfile, $errline), 0);
372		}
373	}
374
375	/**
376	 * Auxiliary function to errorHandler that returns a formatted error message.
377	 * Error type formatting code adapted from ash, http://ca3.php.net/manual/en/function.set-error-handler.php
378	 * @param $errorno string
379	 * @param $errstr string
380	 * @param $errfile string
381	 * @param $errline string
382 	 * @return $message string
383	 */
384	function buildErrorMessage($errorno, $errstr, $errfile, $errline) {
385		$message = array();
386		$errorType = array (
387			E_ERROR			=> 'ERROR',
388			E_WARNING		=> 'WARNING',
389			E_PARSE			=> 'PARSING ERROR',
390			E_NOTICE		=> 'NOTICE',
391			E_CORE_ERROR		=> 'CORE ERROR',
392			E_CORE_WARNING		=> 'CORE WARNING',
393			E_COMPILE_ERROR		=> 'COMPILE ERROR',
394			E_COMPILE_WARNING	=> 'COMPILE WARNING',
395			E_USER_ERROR		=> 'USER ERROR',
396			E_USER_WARNING		=> 'USER WARNING',
397			E_USER_NOTICE		=> 'USER NOTICE',
398		);
399
400		if (array_key_exists($errorno, $errorType)) {
401			$type = $errorType[$errorno];
402		} else {
403			$type = 'CAUGHT EXCEPTION';
404		}
405
406		// Return abridged message if strict error or notice (since they are more common)
407		// This also avoids infinite loops when E_STRICT (=deprecation level) error
408		// reporting is switched on.
409		$shortErrors = E_NOTICE;
410		if (defined('E_STRICT')) $shortErrors |= E_STRICT;
411		if (defined('E_DEPRECATED')) $shortErrors |= E_DEPRECATED;
412		if ($errorno & $shortErrors) {
413			return $type . ': ' . $errstr . ' (' . $errfile . ':' . $errline . ')';
414		}
415
416		$message[] = $this->getName() . ' has produced an error';
417		$message[] = '  Message: ' . $type . ': ' . $errstr;
418		$message[] = '  In file: ' . $errfile;
419		$message[] = '  At line: ' . $errline;
420		$message[] = '  Stacktrace: ';
421
422		if(Config::getVar('debug', 'show_stacktrace')) {
423			$trace = debug_backtrace();
424			// Remove the call to fatalError from the call trace.
425			array_shift($trace);
426
427			// Back-trace pretty-printer adapted from the following URL:
428			// http://ca3.php.net/manual/en/function.debug-backtrace.php
429			// Thanks to diz at ysagoon dot com
430
431			foreach ($trace as $bt) {
432				$args = '';
433				if (isset($bt['args'])) foreach ($bt['args'] as $a) {
434					if (!empty($args)) {
435						$args .= ', ';
436					}
437					switch (gettype($a)) {
438						case 'integer':
439						case 'double':
440							$args .= $a;
441							break;
442						case 'string':
443							$a = htmlspecialchars($a);
444							$args .= "\"$a\"";
445							break;
446						case 'array':
447							$args .= 'Array('.count($a).')';
448							break;
449						case 'object':
450							$args .= 'Object('.get_class($a).')';
451							break;
452						case 'resource':
453							$args .= 'Resource('.strstr($a, '#').')';
454							break;
455						case 'boolean':
456							$args .= $a ? 'True' : 'False';
457							break;
458						case 'NULL':
459							$args .= 'Null';
460							break;
461						default:
462							$args .= 'Unknown';
463					}
464				}
465				$class = isset($bt['class'])?$bt['class']:'';
466				$type = isset($bt['type'])?$bt['type']:'';
467				$function = isset($bt['function'])?$bt['function']:'';
468				$file = isset($bt['file'])?$bt['file']:'(unknown)';
469				$line = isset($bt['line'])?$bt['line']:'(unknown)';
470
471				$message[] = "   File: {$file} line {$line}";
472				$message[] = "     Function: {$class}{$type}{$function}($args)";
473			}
474		}
475
476		static $dbServerInfo;
477		if (!isset($dbServerInfo)) {
478			$dbconn =& DBConnection::getConn();
479			$dbServerInfo = $dbconn->ServerInfo();
480		}
481
482		$message[] = "  Server info:";
483		$message[] = "   OS: " . Core::serverPHPOS();
484		$message[] = "   PHP Version: " . Core::serverPHPVersion();
485		$message[] = "   Apache Version: " . (function_exists('apache_get_version') ? apache_get_version() : 'N/A');
486		$message[] = "   DB Driver: " . Config::getVar('database', 'driver');
487		$message[] = "   DB server version: " . (empty($dbServerInfo['description']) ? $dbServerInfo['version'] : $dbServerInfo['description']);
488
489		return implode("\n", $message);
490	}
491}
492
493?>