PageRenderTime 6ms CodeModel.GetById 2ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/core/PKPApplication.inc.php

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