Commit | Line | Data |
---|---|---|
e9f721ac TD |
1 | <?php |
2 | namespace wcf\system; | |
3 | use wcf\data\application\Application; | |
8f3fc897 | 4 | use wcf\data\option\OptionEditor; |
e9cb0be0 | 5 | use wcf\data\package\Package; |
e9f721ac | 6 | use wcf\data\package\PackageCache; |
e9cb0be0 | 7 | use wcf\data\package\PackageEditor; |
e9f721ac | 8 | use wcf\system\application\ApplicationHandler; |
b401cd0d | 9 | use wcf\system\cache\builder\CoreObjectCacheBuilder; |
5592cc27 | 10 | use wcf\system\cache\builder\PackageUpdateCacheBuilder; |
e9f721ac | 11 | use wcf\system\cronjob\CronjobScheduler; |
ef4f8d9f | 12 | use wcf\system\event\EventHandler; |
b1356a27 | 13 | use wcf\system\exception\AJAXException; |
b8e1429f | 14 | use wcf\system\exception\IPrintableException; |
b1356a27 | 15 | use wcf\system\exception\NamedUserException; |
b8e1429f AE |
16 | use wcf\system\exception\PermissionDeniedException; |
17 | use wcf\system\exception\SystemException; | |
e9f721ac TD |
18 | use wcf\system\language\LanguageFactory; |
19 | use wcf\system\package\PackageInstallationDispatcher; | |
b42a1cd9 | 20 | use wcf\system\request\RouteHandler; |
e9f721ac TD |
21 | use wcf\system\session\SessionFactory; |
22 | use wcf\system\session\SessionHandler; | |
ae054dfc | 23 | use wcf\system\style\StyleHandler; |
e9f721ac TD |
24 | use wcf\system\template\TemplateEngine; |
25 | use wcf\system\user\storage\UserStorageHandler; | |
a17de04e MS |
26 | use wcf\util\ArrayUtil; |
27 | use wcf\util\ClassUtil; | |
28 | use wcf\util\FileUtil; | |
29 | use wcf\util\StringUtil; | |
e9f721ac | 30 | |
460dc24e AE |
31 | // try to set a time-limit to infinite |
32 | @set_time_limit(0); | |
e9f721ac | 33 | |
102fb489 MW |
34 | // fix timezone warning issue |
35 | if (!@ini_get('date.timezone')) { | |
36 | @date_default_timezone_set('Europe/London'); | |
37 | } | |
38 | ||
e9f721ac | 39 | // define current wcf version |
4c5b87fc | 40 | define('WCF_VERSION', '2.1.0 Alpha 1 (Typhoon)'); |
e9f721ac TD |
41 | |
42 | // define current unix timestamp | |
43 | define('TIME_NOW', time()); | |
44 | ||
45 | // wcf imports | |
46 | if (!defined('NO_IMPORTS')) { | |
47 | require_once(WCF_DIR.'lib/core.functions.php'); | |
48 | } | |
49 | ||
50 | /** | |
51 | * WCF is the central class for the community framework. | |
52 | * It holds the database connection, access to template and language engine. | |
9f959ced MS |
53 | * |
54 | * @author Marcel Werk | |
ca4ba303 | 55 | * @copyright 2001-2014 WoltLab GmbH |
e9f721ac TD |
56 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
57 | * @package com.woltlab.wcf | |
58 | * @subpackage system | |
9f959ced | 59 | * @category Community Framework |
e9f721ac TD |
60 | */ |
61 | class WCF { | |
62 | /** | |
63 | * list of currently loaded applications | |
e7bfc881 | 64 | * @var array<\wcf\data\application\Application> |
e9f721ac TD |
65 | */ |
66 | protected static $applications = array(); | |
67 | ||
e7bfc881 AE |
68 | /** |
69 | * list of currently loaded application objects | |
70 | * @var array<\wcf\system\application\IApplication> | |
71 | */ | |
72 | protected static $applicationObjects = array(); | |
73 | ||
e9f721ac TD |
74 | /** |
75 | * list of autoload directories | |
9f959ced | 76 | * @var array |
e9f721ac TD |
77 | */ |
78 | protected static $autoloadDirectories = array(); | |
79 | ||
80 | /** | |
81 | * list of unique instances of each core object | |
0ad90fc3 | 82 | * @var array<\wcf\system\SingletonFactory> |
e9f721ac TD |
83 | */ |
84 | protected static $coreObject = array(); | |
85 | ||
86 | /** | |
87 | * list of cached core objects | |
88 | * @var array<array> | |
89 | */ | |
90 | protected static $coreObjectCache = array(); | |
91 | ||
e9f721ac TD |
92 | /** |
93 | * database object | |
0ad90fc3 | 94 | * @var \wcf\system\database\Database |
e9f721ac TD |
95 | */ |
96 | protected static $dbObj = null; | |
97 | ||
98 | /** | |
99 | * language object | |
0ad90fc3 | 100 | * @var \wcf\system\language\Language |
e9f721ac TD |
101 | */ |
102 | protected static $languageObj = null; | |
103 | ||
b98e7f33 AE |
104 | /** |
105 | * overrides disabled debug mode | |
106 | * @var boolean | |
107 | */ | |
108 | protected static $overrideDebugMode = false; | |
109 | ||
e9f721ac TD |
110 | /** |
111 | * session object | |
0ad90fc3 | 112 | * @var \wcf\system\session\SessionHandler |
e9f721ac TD |
113 | */ |
114 | protected static $sessionObj = null; | |
115 | ||
116 | /** | |
117 | * template object | |
0ad90fc3 | 118 | * @var \wcf\system\template\TemplateEngine |
e9f721ac TD |
119 | */ |
120 | protected static $tplObj = null; | |
121 | ||
f6619df8 AE |
122 | /** |
123 | * true if Zend Opcache is loaded and enabled | |
124 | * @var boolean | |
125 | */ | |
126 | protected static $zendOpcacheEnabled = null; | |
127 | ||
e9f721ac TD |
128 | /** |
129 | * Calls all init functions of the WCF class. | |
130 | */ | |
131 | public function __construct() { | |
132 | // add autoload directory | |
133 | self::$autoloadDirectories['wcf'] = WCF_DIR . 'lib/'; | |
134 | ||
135 | // define tmp directory | |
a17de04e | 136 | if (!defined('TMP_DIR')) define('TMP_DIR', FileUtil::getTempFolder()); |
e9f721ac TD |
137 | |
138 | // start initialization | |
139 | $this->initMagicQuotes(); | |
140 | $this->initDB(); | |
141 | $this->loadOptions(); | |
e9f721ac TD |
142 | $this->initSession(); |
143 | $this->initLanguage(); | |
144 | $this->initTPL(); | |
145 | $this->initCronjobs(); | |
e9f721ac TD |
146 | $this->initCoreObjects(); |
147 | $this->initApplications(); | |
bf63d51d | 148 | $this->initBlacklist(); |
ef4f8d9f MW |
149 | |
150 | EventHandler::getInstance()->fireAction($this, 'initialized'); | |
e9f721ac TD |
151 | } |
152 | ||
153 | /** | |
154 | * Replacement of the "__destruct()" method. | |
155 | * Seems that under specific conditions (windows) the destructor is not called automatically. | |
156 | * So we use the php register_shutdown_function to register an own destructor method. | |
96e82a73 | 157 | * Flushs the output, closes caches and updates the session. |
e9f721ac TD |
158 | */ |
159 | public static function destruct() { | |
49ab25e3 AE |
160 | try { |
161 | // database has to be initialized | |
162 | if (!is_object(self::$dbObj)) return; | |
163 | ||
164 | // flush output | |
165 | if (ob_get_level() && ini_get('output_handler')) { | |
166 | ob_flush(); | |
167 | } | |
168 | else { | |
169 | flush(); | |
170 | } | |
171 | ||
172 | // update session | |
173 | if (is_object(self::getSession())) { | |
174 | self::getSession()->update(); | |
175 | } | |
176 | ||
49ab25e3 AE |
177 | // execute shutdown actions of user storage handler |
178 | UserStorageHandler::getInstance()->shutdown(); | |
e9f721ac | 179 | } |
49ab25e3 | 180 | catch (\Exception $exception) { |
30413de4 | 181 | die("<pre>WCF::destruct() Unhandled exception: ".$exception->getMessage()."\n\n".$exception->getTraceAsString()); |
e9f721ac | 182 | } |
e9f721ac TD |
183 | } |
184 | ||
185 | /** | |
186 | * Removes slashes in superglobal gpc data arrays if 'magic quotes gpc' is enabled. | |
187 | */ | |
188 | protected function initMagicQuotes() { | |
189 | if (function_exists('get_magic_quotes_gpc')) { | |
190 | if (@get_magic_quotes_gpc()) { | |
15fa2802 | 191 | if (!empty($_REQUEST)) { |
a17de04e | 192 | $_REQUEST = ArrayUtil::stripslashes($_REQUEST); |
e9f721ac | 193 | } |
15fa2802 | 194 | if (!empty($_POST)) { |
a17de04e | 195 | $_POST = ArrayUtil::stripslashes($_POST); |
e9f721ac | 196 | } |
15fa2802 | 197 | if (!empty($_GET)) { |
a17de04e | 198 | $_GET = ArrayUtil::stripslashes($_GET); |
e9f721ac | 199 | } |
15fa2802 | 200 | if (!empty($_COOKIE)) { |
a17de04e | 201 | $_COOKIE = ArrayUtil::stripslashes($_COOKIE); |
e9f721ac | 202 | } |
15fa2802 | 203 | if (!empty($_FILES)) { |
e9f721ac TD |
204 | foreach ($_FILES as $name => $attributes) { |
205 | foreach ($attributes as $key => $value) { | |
206 | if ($key != 'tmp_name') { | |
a17de04e | 207 | $_FILES[$name][$key] = ArrayUtil::stripslashes($value); |
e9f721ac TD |
208 | } |
209 | } | |
210 | } | |
211 | } | |
212 | } | |
213 | } | |
9f959ced | 214 | |
e9f721ac TD |
215 | if (function_exists('set_magic_quotes_runtime')) { |
216 | @set_magic_quotes_runtime(0); | |
217 | } | |
218 | } | |
219 | ||
220 | /** | |
221 | * Returns the database object. | |
9f959ced | 222 | * |
0ad90fc3 | 223 | * @return \wcf\system\database\Database |
e9f721ac TD |
224 | */ |
225 | public static final function getDB() { | |
226 | return self::$dbObj; | |
227 | } | |
228 | ||
229 | /** | |
230 | * Returns the session object. | |
9f959ced | 231 | * |
0ad90fc3 | 232 | * @return \wcf\system\session\SessionHandler |
e9f721ac TD |
233 | */ |
234 | public static final function getSession() { | |
235 | return self::$sessionObj; | |
236 | } | |
237 | ||
238 | /** | |
239 | * Returns the user object. | |
9f959ced | 240 | * |
0ad90fc3 | 241 | * @return \wcf\data\user\User |
e9f721ac TD |
242 | */ |
243 | public static final function getUser() { | |
244 | return self::getSession()->getUser(); | |
245 | } | |
246 | ||
247 | /** | |
248 | * Returns the language object. | |
9f959ced | 249 | * |
0ad90fc3 | 250 | * @return \wcf\data\language\Language |
e9f721ac TD |
251 | */ |
252 | public static final function getLanguage() { | |
253 | return self::$languageObj; | |
254 | } | |
255 | ||
256 | /** | |
257 | * Returns the template object. | |
9f959ced | 258 | * |
0ad90fc3 | 259 | * @return \wcf\system\template\TemplateEngine |
e9f721ac TD |
260 | */ |
261 | public static final function getTPL() { | |
262 | return self::$tplObj; | |
263 | } | |
264 | ||
265 | /** | |
266 | * Calls the show method on the given exception. | |
9f959ced | 267 | * |
e9f721ac TD |
268 | * @param \Exception $e |
269 | */ | |
270 | public static final function handleException(\Exception $e) { | |
49ab25e3 | 271 | try { |
b8e1429f | 272 | if ($e instanceof IPrintableException) { |
49ab25e3 AE |
273 | $e->show(); |
274 | exit; | |
275 | } | |
276 | ||
277 | // repack Exception | |
b8e1429f | 278 | self::handleException(new SystemException($e->getMessage(), $e->getCode(), '', $e)); |
49ab25e3 AE |
279 | } |
280 | catch (\Exception $exception) { | |
30413de4 | 281 | die("<pre>WCF::handleException() Unhandled exception: ".$exception->getMessage()."\n\n".$exception->getTraceAsString()); |
e9f721ac | 282 | } |
e9f721ac TD |
283 | } |
284 | ||
285 | /** | |
286 | * Catches php errors and throws instead a system exception. | |
9f959ced | 287 | * |
e9f721ac TD |
288 | * @param integer $errorNo |
289 | * @param string $message | |
290 | * @param string $filename | |
291 | * @param integer $lineNo | |
292 | */ | |
293 | public static final function handleError($errorNo, $message, $filename, $lineNo) { | |
294 | if (error_reporting() != 0) { | |
295 | $type = 'error'; | |
296 | switch ($errorNo) { | |
297 | case 2: $type = 'warning'; | |
298 | break; | |
299 | case 8: $type = 'notice'; | |
300 | break; | |
301 | } | |
302 | ||
b8e1429f | 303 | throw new SystemException('PHP '.$type.' in file '.$filename.' ('.$lineNo.'): '.$message, 0); |
e9f721ac TD |
304 | } |
305 | } | |
306 | ||
307 | /** | |
308 | * Loads the database configuration and creates a new connection to the database. | |
309 | */ | |
310 | protected function initDB() { | |
311 | // get configuration | |
312 | $dbHost = $dbUser = $dbPassword = $dbName = ''; | |
313 | $dbPort = 0; | |
314 | $dbClass = 'wcf\system\database\MySQLDatabase'; | |
315 | require(WCF_DIR.'config.inc.php'); | |
316 | ||
317 | // create database connection | |
318 | self::$dbObj = new $dbClass($dbHost, $dbUser, $dbPassword, $dbName, $dbPort); | |
319 | } | |
320 | ||
e9f721ac | 321 | /** |
b07d3301 | 322 | * Loads the options file, automatically created if not exists. |
e9f721ac | 323 | */ |
b07d3301 AE |
324 | protected function loadOptions() { |
325 | $filename = WCF_DIR.'options.inc.php'; | |
e9f721ac TD |
326 | |
327 | // create options file if doesn't exist | |
328 | if (!file_exists($filename) || filemtime($filename) <= 1) { | |
8f3fc897 | 329 | OptionEditor::rebuild(); |
e9f721ac TD |
330 | } |
331 | require_once($filename); | |
332 | } | |
333 | ||
334 | /** | |
335 | * Starts the session system. | |
336 | */ | |
337 | protected function initSession() { | |
338 | $factory = new SessionFactory(); | |
339 | $factory->load(); | |
340 | ||
341 | self::$sessionObj = SessionHandler::getInstance(); | |
342 | } | |
343 | ||
344 | /** | |
345 | * Initialises the language engine. | |
346 | */ | |
347 | protected function initLanguage() { | |
348 | if (isset($_GET['l']) && !self::getUser()->userID) { | |
349 | self::getSession()->setLanguageID(intval($_GET['l'])); | |
350 | } | |
351 | ||
352 | // set mb settings | |
353 | mb_internal_encoding('UTF-8'); | |
354 | if (function_exists('mb_regex_encoding')) mb_regex_encoding('UTF-8'); | |
355 | mb_language('uni'); | |
356 | ||
357 | // get language | |
358 | self::$languageObj = LanguageFactory::getInstance()->getUserLanguage(self::getSession()->getLanguageID()); | |
e9f721ac TD |
359 | } |
360 | ||
361 | /** | |
362 | * Initialises the template engine. | |
363 | */ | |
364 | protected function initTPL() { | |
365 | self::$tplObj = TemplateEngine::getInstance(); | |
366 | self::getTPL()->setLanguageID(self::getLanguage()->languageID); | |
367 | $this->assignDefaultTemplateVariables(); | |
83736ee3 AE |
368 | |
369 | $this->initStyle(); | |
370 | } | |
371 | ||
372 | /** | |
373 | * Initializes the user's style. | |
374 | */ | |
375 | protected function initStyle() { | |
376 | if (isset($_REQUEST['styleID'])) { | |
e421b813 | 377 | self::getSession()->setStyleID(intval($_REQUEST['styleID'])); |
83736ee3 AE |
378 | } |
379 | ||
e421b813 | 380 | StyleHandler::getInstance()->changeStyle(self::getSession()->getStyleID()); |
e9f721ac TD |
381 | } |
382 | ||
383 | /** | |
384 | * Executes the blacklist. | |
385 | */ | |
386 | protected function initBlacklist() { | |
387 | if (defined('BLACKLIST_IP_ADDRESSES') && BLACKLIST_IP_ADDRESSES != '') { | |
e421b813 | 388 | if (!StringUtil::executeWordFilter(self::getSession()->ipAddress, BLACKLIST_IP_ADDRESSES)) { |
b8e1429f | 389 | throw new PermissionDeniedException(); |
e9f721ac TD |
390 | } |
391 | } | |
392 | if (defined('BLACKLIST_USER_AGENTS') && BLACKLIST_USER_AGENTS != '') { | |
e421b813 | 393 | if (!StringUtil::executeWordFilter(self::getSession()->userAgent, BLACKLIST_USER_AGENTS)) { |
b8e1429f | 394 | throw new PermissionDeniedException(); |
e9f721ac TD |
395 | } |
396 | } | |
397 | if (defined('BLACKLIST_HOSTNAMES') && BLACKLIST_HOSTNAMES != '') { | |
e421b813 | 398 | if (!StringUtil::executeWordFilter(@gethostbyaddr(self::getSession()->ipAddress), BLACKLIST_HOSTNAMES)) { |
b8e1429f | 399 | throw new PermissionDeniedException(); |
e9f721ac TD |
400 | } |
401 | } | |
b1356a27 MW |
402 | |
403 | // handle banned users | |
8797f7be | 404 | if (self::getUser()->userID && self::getUser()->banned) { |
b1356a27 | 405 | if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')) { |
8797f7be | 406 | throw new AJAXException(self::getLanguage()->getDynamicVariable('wcf.user.error.isBanned'), AJAXException::INSUFFICIENT_PERMISSIONS); |
b1356a27 MW |
407 | } |
408 | else { | |
8797f7be | 409 | throw new NamedUserException(self::getLanguage()->getDynamicVariable('wcf.user.error.isBanned')); |
b1356a27 MW |
410 | } |
411 | } | |
e9f721ac TD |
412 | } |
413 | ||
414 | /** | |
415 | * Initializes applications. | |
416 | */ | |
417 | protected function initApplications() { | |
eeffb188 AE |
418 | // step 1) load all applications |
419 | $loadedApplications = array(); | |
420 | ||
6ddd24ef AE |
421 | // register WCF as application |
422 | self::$applications['wcf'] = ApplicationHandler::getInstance()->getWCF(); | |
423 | ||
2dc89c0a AE |
424 | if (PACKAGE_ID == 1) { |
425 | return; | |
426 | } | |
427 | ||
e9f721ac TD |
428 | // start main application |
429 | $application = ApplicationHandler::getInstance()->getActiveApplication(); | |
eeffb188 | 430 | $loadedApplications[] = $this->loadApplication($application); |
e9f721ac TD |
431 | |
432 | // register primary application | |
433 | $abbreviation = ApplicationHandler::getInstance()->getAbbreviation($application->packageID); | |
434 | self::$applications[$abbreviation] = $application; | |
435 | ||
436 | // start dependent applications | |
437 | $applications = ApplicationHandler::getInstance()->getDependentApplications(); | |
438 | foreach ($applications as $application) { | |
eeffb188 AE |
439 | $loadedApplications[] = $this->loadApplication($application, true); |
440 | } | |
441 | ||
442 | // step 2) run each application | |
c4575796 AE |
443 | if (!class_exists('wcf\system\WCFACP', false)) { |
444 | foreach ($loadedApplications as $application) { | |
445 | $application->__run(); | |
446 | } | |
dd932bc6 AE |
447 | |
448 | // refresh the session 1 minute before it expires | |
449 | self::getTPL()->assign('__sessionKeepAlive', (SESSION_TIMEOUT - 60)); | |
e9f721ac TD |
450 | } |
451 | } | |
452 | ||
453 | /** | |
454 | * Loads an application. | |
9f959ced | 455 | * |
0ad90fc3 | 456 | * @param \wcf\data\application\Application $application |
e9f721ac | 457 | * @param boolean $isDependentApplication |
0ad90fc3 | 458 | * @return \wcf\system\application\IApplication |
9f959ced | 459 | */ |
e9f721ac | 460 | protected function loadApplication(Application $application, $isDependentApplication = false) { |
eeffb188 | 461 | $applicationObject = null; |
e9f721ac | 462 | $package = PackageCache::getInstance()->getPackage($application->packageID); |
e9cb0be0 AE |
463 | // package cache might be outdated |
464 | if ($package === null) { | |
465 | $package = new Package($application->packageID); | |
466 | ||
467 | // package cache is outdated, discard cache | |
468 | if ($package->packageID) { | |
469 | PackageEditor::resetCache(); | |
470 | } | |
471 | else { | |
472 | // package id is invalid | |
473 | throw new SystemException("application identified by package id '".$application->packageID."' is unknown"); | |
474 | } | |
475 | } | |
476 | ||
e9f721ac | 477 | $abbreviation = ApplicationHandler::getInstance()->getAbbreviation($application->packageID); |
a17de04e | 478 | $packageDir = FileUtil::getRealPath(WCF_DIR.$package->packageDir); |
e9f721ac TD |
479 | self::$autoloadDirectories[$abbreviation] = $packageDir . 'lib/'; |
480 | ||
481 | $className = $abbreviation.'\system\\'.strtoupper($abbreviation).'Core'; | |
a17de04e | 482 | if (class_exists($className) && ClassUtil::isInstanceOf($className, 'wcf\system\application\IApplication')) { |
e9f721ac TD |
483 | // include config file |
484 | $configPath = $packageDir . PackageInstallationDispatcher::CONFIG_FILE; | |
485 | if (file_exists($configPath)) { | |
486 | require_once($configPath); | |
487 | } | |
488 | else { | |
b8e1429f | 489 | throw new SystemException('Unable to load configuration for '.$package->package); |
e9f721ac TD |
490 | } |
491 | ||
db5bb050 | 492 | // register template path if not within ACP |
e9f721ac | 493 | if (!class_exists('wcf\system\WCFACP', false)) { |
e9a062f9 | 494 | // add template path and abbreviation |
58fda665 | 495 | $this->getTPL()->addApplication($abbreviation, $packageDir . 'templates/'); |
e9f721ac | 496 | } |
db5bb050 MW |
497 | |
498 | // init application and assign it as template variable | |
e7bfc881 AE |
499 | self::$applicationObjects[$application->packageID] = call_user_func(array($className, 'getInstance')); |
500 | $this->getTPL()->assign('__'.$abbreviation, self::$applicationObjects[$application->packageID]); | |
e9f721ac TD |
501 | } |
502 | else { | |
503 | unset(self::$autoloadDirectories[$abbreviation]); | |
b8e1429f | 504 | throw new SystemException("Unable to run '".$package->package."', '".$className."' is missing or does not implement 'wcf\system\application\IApplication'."); |
e9f721ac TD |
505 | } |
506 | ||
e9f721ac TD |
507 | // register template path in ACP |
508 | if (class_exists('wcf\system\WCFACP', false)) { | |
58fda665 | 509 | $this->getTPL()->addApplication($abbreviation, $packageDir . 'acp/templates/'); |
e9f721ac TD |
510 | } |
511 | else if (!$isDependentApplication) { | |
512 | // assign base tag | |
6f296cdf | 513 | $this->getTPL()->assign('baseHref', $application->getPageURL()); |
e9f721ac TD |
514 | } |
515 | ||
516 | // register application | |
517 | self::$applications[$abbreviation] = $application; | |
eeffb188 | 518 | |
e7bfc881 AE |
519 | return self::$applicationObjects[$application->packageID]; |
520 | } | |
521 | ||
522 | /** | |
523 | * Returns the corresponding application object. Does not support the 'wcf' pseudo application. | |
524 | * | |
525 | * @param wcf\data\application\Application $application | |
526 | * @return \wcf\system\application\IApplication | |
527 | */ | |
528 | public static function getApplicationObject(Application $application) { | |
529 | if (isset(self::$applicationObjects[$application->packageID])) { | |
530 | return self::$applicationObjects[$application->packageID]; | |
531 | } | |
532 | ||
533 | return null; | |
e9f721ac TD |
534 | } |
535 | ||
8f8d8a38 AE |
536 | /** |
537 | * Loads an application on runtime, do not use this outside the package installation. | |
538 | * | |
539 | * @param integer $packageID | |
540 | */ | |
541 | public static function loadRuntimeApplication($packageID) { | |
542 | $package = new Package($packageID); | |
543 | $application = new Application($packageID); | |
544 | ||
545 | $abbreviation = Package::getAbbreviation($package->package); | |
546 | $packageDir = FileUtil::getRealPath(WCF_DIR.$package->packageDir); | |
547 | self::$autoloadDirectories[$abbreviation] = $packageDir . 'lib/'; | |
548 | self::$applications[$abbreviation] = $application; | |
549 | self::getTPL()->addApplication($abbreviation, $packageDir . 'acp/templates/'); | |
550 | } | |
551 | ||
e9f721ac TD |
552 | /** |
553 | * Initializes core object cache. | |
554 | */ | |
555 | protected function initCoreObjects() { | |
556 | // ignore core objects if installing WCF | |
557 | if (PACKAGE_ID == 0) { | |
558 | return; | |
559 | } | |
560 | ||
b401cd0d | 561 | self::$coreObjectCache = CoreObjectCacheBuilder::getInstance()->getData(); |
e9f721ac TD |
562 | } |
563 | ||
564 | /** | |
565 | * Assigns some default variables to the template engine. | |
566 | */ | |
567 | protected function assignDefaultTemplateVariables() { | |
3d963f30 | 568 | self::getTPL()->registerPrefilter(array('event', 'hascontent', 'lang')); |
484312bd AE |
569 | self::getTPL()->assign(array( |
570 | '__wcf' => $this, | |
838e315b | 571 | '__wcfVersion' => mb_substr(sha1(WCF_VERSION), 0, 8) |
484312bd | 572 | )); |
e9f721ac TD |
573 | } |
574 | ||
575 | /** | |
576 | * Wrapper for the getter methods of this class. | |
9f959ced | 577 | * |
e9f721ac TD |
578 | * @param string $name |
579 | * @return mixed value | |
580 | */ | |
581 | public function __get($name) { | |
582 | $method = 'get'.ucfirst($name); | |
583 | if (method_exists($this, $method)) { | |
584 | return $this->$method(); | |
585 | } | |
586 | ||
b8e1429f | 587 | throw new SystemException("method '".$method."' does not exist in class WCF"); |
e9f721ac TD |
588 | } |
589 | ||
590 | /** | |
591 | * Changes the active language. | |
9f959ced | 592 | * |
e9f721ac TD |
593 | * @param integer $languageID |
594 | */ | |
595 | public static final function setLanguage($languageID) { | |
596 | self::$languageObj = LanguageFactory::getInstance()->getLanguage($languageID); | |
597 | self::getTPL()->setLanguageID(self::getLanguage()->languageID); | |
598 | } | |
599 | ||
600 | /** | |
601 | * Includes the required util or exception classes automatically. | |
59dc0db6 | 602 | * |
39bea7dd | 603 | * @param string $className |
e9f721ac TD |
604 | * @see spl_autoload_register() |
605 | */ | |
606 | public static final function autoload($className) { | |
607 | $namespaces = explode('\\', $className); | |
608 | if (count($namespaces) > 1) { | |
609 | $applicationPrefix = array_shift($namespaces); | |
9d5ada2f | 610 | if ($applicationPrefix === '') { |
9cc6345f | 611 | $applicationPrefix = array_shift($namespaces); |
98c74d79 | 612 | } |
e9f721ac TD |
613 | if (isset(self::$autoloadDirectories[$applicationPrefix])) { |
614 | $classPath = self::$autoloadDirectories[$applicationPrefix] . implode('/', $namespaces) . '.class.php'; | |
615 | if (file_exists($classPath)) { | |
616 | require_once($classPath); | |
617 | } | |
618 | } | |
619 | } | |
620 | } | |
621 | ||
622 | /** | |
0ad90fc3 | 623 | * @see \wcf\system\WCF::__callStatic() |
e9f721ac TD |
624 | */ |
625 | public final function __call($name, array $arguments) { | |
626 | // bug fix to avoid php crash, see http://bugs.php.net/bug.php?id=55020 | |
627 | if (!method_exists($this, $name)) { | |
628 | return self::__callStatic($name, $arguments); | |
629 | } | |
630 | ||
631 | return $this->$name($arguments); | |
632 | } | |
633 | ||
634 | /** | |
635 | * Returns dynamically loaded core objects. | |
9f959ced | 636 | * |
e9f721ac TD |
637 | * @param string $name |
638 | * @param array $arguments | |
639 | */ | |
640 | public static final function __callStatic($name, array $arguments) { | |
641 | $className = preg_replace('~^get~', '', $name); | |
642 | ||
643 | if (isset(self::$coreObject[$className])) { | |
644 | return self::$coreObject[$className]; | |
645 | } | |
646 | ||
647 | $objectName = self::getCoreObject($className); | |
648 | if ($objectName === null) { | |
b8e1429f | 649 | throw new SystemException("Core object '".$className."' is unknown."); |
e9f721ac TD |
650 | } |
651 | ||
652 | if (class_exists($objectName)) { | |
a17de04e | 653 | if (!(ClassUtil::isInstanceOf($objectName, 'wcf\system\SingletonFactory'))) { |
b8e1429f | 654 | throw new SystemException("class '".$objectName."' does not implement the interface 'SingletonFactory'"); |
e9f721ac TD |
655 | } |
656 | ||
657 | self::$coreObject[$className] = call_user_func(array($objectName, 'getInstance')); | |
658 | return self::$coreObject[$className]; | |
659 | } | |
660 | } | |
661 | ||
662 | /** | |
663 | * Searches for cached core object definition. | |
9f959ced | 664 | * |
e9f721ac TD |
665 | * @param string $className |
666 | * @return string | |
667 | */ | |
668 | protected static final function getCoreObject($className) { | |
f1c1fc65 AE |
669 | if (isset(self::$coreObjectCache[$className])) { |
670 | return self::$coreObjectCache[$className]; | |
e9f721ac TD |
671 | } |
672 | ||
673 | return null; | |
674 | } | |
675 | ||
676 | /** | |
677 | * Returns true if the debug mode is enabled, otherwise false. | |
678 | * | |
9f959ced | 679 | * @return boolean |
e9f721ac TD |
680 | */ |
681 | public static function debugModeIsEnabled() { | |
b98e7f33 AE |
682 | // ACP override |
683 | if (self::$overrideDebugMode) { | |
684 | return true; | |
685 | } | |
686 | else if (defined('ENABLE_DEBUG_MODE') && ENABLE_DEBUG_MODE) { | |
687 | return true; | |
688 | } | |
689 | ||
e9f721ac TD |
690 | return false; |
691 | } | |
692 | ||
693 | /** | |
694 | * Returns true if benchmarking is enabled, otherwise false. | |
695 | * | |
9f959ced | 696 | * @return boolean |
e9f721ac TD |
697 | */ |
698 | public static function benchmarkIsEnabled() { | |
699 | // benchmarking is enabled by default | |
700 | if (!defined('ENABLE_BENCHMARK') || ENABLE_BENCHMARK) return true; | |
701 | return false; | |
702 | } | |
703 | ||
704 | /** | |
705 | * Returns domain path for given application. | |
706 | * | |
707 | * @param string $abbreviation | |
708 | * @return string | |
709 | */ | |
710 | public static function getPath($abbreviation = 'wcf') { | |
711 | // workaround during WCFSetup | |
712 | if (!PACKAGE_ID) { | |
713 | return '../'; | |
714 | } | |
715 | ||
716 | if (!isset(self::$applications[$abbreviation])) { | |
717 | $abbreviation = 'wcf'; | |
718 | } | |
719 | ||
6670a9b6 | 720 | return self::$applications[$abbreviation]->getPageURL(); |
e9f721ac TD |
721 | } |
722 | ||
723 | /** | |
724 | * Returns a fully qualified anchor for current page. | |
725 | * | |
726 | * @param string $fragment | |
727 | * @return string | |
728 | */ | |
729 | public function getAnchor($fragment) { | |
85dfad13 | 730 | return self::getRequestURI() . '#' . $fragment; |
761fa7f0 MW |
731 | } |
732 | ||
733 | /** | |
734 | * Returns the URI of the current page. | |
59dc0db6 | 735 | * |
761fa7f0 MW |
736 | * @return string |
737 | */ | |
85dfad13 | 738 | public static function getRequestURI() { |
e9f721ac TD |
739 | // resolve path and query components |
740 | $scriptName = $_SERVER['SCRIPT_NAME']; | |
b42a1cd9 AE |
741 | $pathInfo = RouteHandler::getPathInfo(); |
742 | if (empty($pathInfo)) { | |
e9f721ac TD |
743 | // bug fix if URL omits script name and path |
744 | $scriptName = substr($scriptName, 0, strrpos($scriptName, '/')); | |
745 | } | |
746 | ||
747 | $path = str_replace('/index.php', '', str_replace($scriptName, '', $_SERVER['REQUEST_URI'])); | |
6a74a874 MW |
748 | if (!StringUtil::isASCII($path) && !StringUtil::isUTF8($path)) { |
749 | $path = StringUtil::convertEncoding('ISO-8859-1', 'UTF-8', $path); | |
da0f0e8e | 750 | } |
6b2f5a59 | 751 | $path = FileUtil::removeLeadingSlash($path); |
e9f721ac TD |
752 | $baseHref = self::getTPL()->get('baseHref'); |
753 | ||
838e315b | 754 | if (!empty($path) && mb_strpos($path, '?') !== 0) { |
6b2f5a59 AE |
755 | $baseHref .= 'index.php/'; |
756 | } | |
757 | ||
761fa7f0 | 758 | return $baseHref . $path; |
e9f721ac TD |
759 | } |
760 | ||
f6619df8 AE |
761 | /** |
762 | * Resets Zend Opcache cache if installed and enabled. | |
763 | * | |
764 | * @param string $script | |
765 | */ | |
766 | public static function resetZendOpcache($script = '') { | |
767 | if (self::$zendOpcacheEnabled === null) { | |
f456bbdb AE |
768 | self::$zendOpcacheEnabled = false; |
769 | ||
f6619df8 AE |
770 | if (extension_loaded('Zend Opcache') && @ini_get('opcache.enable')) { |
771 | self::$zendOpcacheEnabled = true; | |
772 | } | |
773 | ||
f6619df8 AE |
774 | } |
775 | ||
776 | if (self::$zendOpcacheEnabled) { | |
777 | if (empty($script)) { | |
778 | opcache_reset(); | |
779 | } | |
780 | else { | |
781 | opcache_invalidate($script, true); | |
782 | } | |
783 | } | |
784 | } | |
785 | ||
ae054dfc AE |
786 | /** |
787 | * Returns style handler. | |
788 | * | |
0ad90fc3 | 789 | * @return \wcf\system\style\StyleHandler |
ae054dfc AE |
790 | */ |
791 | public function getStyleHandler() { | |
792 | return StyleHandler::getInstance(); | |
793 | } | |
794 | ||
839b49f1 AE |
795 | /** |
796 | * Returns number of available updates. | |
797 | * | |
798 | * @return integer | |
799 | */ | |
800 | public function getAvailableUpdates() { | |
801 | $data = PackageUpdateCacheBuilder::getInstance()->getData(); | |
802 | return $data['updates']; | |
803 | } | |
804 | ||
b9f4bd69 MS |
805 | /** |
806 | * @see \wcf\system\request\RouteHandler::secureConnection() | |
807 | */ | |
808 | public function secureConnection() { | |
809 | return RouteHandler::secureConnection(); | |
810 | } | |
811 | ||
e9f721ac TD |
812 | /** |
813 | * Initialises the cronjobs. | |
814 | */ | |
815 | protected function initCronjobs() { | |
816 | if (PACKAGE_ID) { | |
817 | self::getTPL()->assign('executeCronjobs', CronjobScheduler::getInstance()->getNextExec() < TIME_NOW); | |
818 | } | |
819 | } | |
820 | } |