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