]> git.mxchange.org Git - core.git/blob - framework/bootstrap/class_FrameworkBootstrap.php
de4aac3ddb6fc10d6c560ee84871a8d95c1de497
[core.git] / framework / bootstrap / class_FrameworkBootstrap.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Bootstrap;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Configuration\FrameworkConfiguration;
7 use Org\Mxchange\CoreFramework\Connection\Database\DatabaseConnection;
8 use Org\Mxchange\CoreFramework\Connector\Database\DatabaseConnector;
9 use Org\Mxchange\CoreFramework\Console\Tools\ConsoleTools;
10 use Org\Mxchange\CoreFramework\EntryPoint\ApplicationEntryPoint;
11 use Org\Mxchange\CoreFramework\Factory\Object\ObjectFactory;
12 use Org\Mxchange\CoreFramework\Generic\FrameworkInterface;
13 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
14 use Org\Mxchange\CoreFramework\Helper\Application\ApplicationHelper;
15 use Org\Mxchange\CoreFramework\Localization\ManageableLanguage;
16 use Org\Mxchange\CoreFramework\Loader\ClassLoader;
17 use Org\Mxchange\CoreFramework\Manager\ManageableApplication;
18 use Org\Mxchange\CoreFramework\Middleware\Debug\DebugMiddleware;
19 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
20 use Org\Mxchange\CoreFramework\Registry\GenericRegistry;
21 use Org\Mxchange\CoreFramework\Request\Requestable;
22 use Org\Mxchange\CoreFramework\Response\Responseable;
23 use Org\Mxchange\CoreFramework\Utils\Strings\StringUtils;
24
25 // Import SPL stuff
26 use \BadMethodCallException;
27 use \InvalidArgumentException;
28 use \SplFileInfo;
29
30 /**
31  * A framework-bootstrap class which helps the frameworks to bootstrap ... ;-)
32  *
33  * @author              Roland Haeder <webmaster@ship-simu.org>
34  * @version             0.0.0
35  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2022 Core Developer Team
36  * @license             GNU GPL 3.0 or any newer version
37  * @link                http://www.ship-simu.org
38  *
39  * This program is free software: you can redistribute it and/or modify
40  * it under the terms of the GNU General Public License as published by
41  * the Free Software Foundation, either version 3 of the License, or
42  * (at your option) any later version.
43  *
44  * This program is distributed in the hope that it will be useful,
45  * but WITHOUT ANY WARRANTY; without even the implied warranty of
46  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
47  * GNU General Public License for more details.
48  *
49  * You should have received a copy of the GNU General Public License
50  * along with this program. If not, see <http://www.gnu.org/licenses/>.
51  */
52 final class FrameworkBootstrap {
53
54         /**
55          * Detected server address
56          */
57         private static $serverAddress = NULL;
58
59         /**
60          * Instance of a Requestable class
61          */
62         private static $requestInstance = NULL;
63
64         /**
65          * Instance of a Responseable class
66          */
67         private static $responseInstance = NULL;
68
69         /**
70          * Instance of a FrameworkConfiguration class
71          */
72         private static $configurationInstance = NULL;
73
74         /**
75          * Database instance
76          */
77         private static $databaseInstance = NULL;
78
79         /**
80          * Language system instance
81          */
82         private static $languageInstance = NULL;
83
84         /*
85          * Includes applications may have. They will be tried in the given order,
86          * some will become soon deprecated.
87          */
88         private static $configAppIncludes = [
89                 // The ApplicationHelper class (required)
90                 'class_ApplicationHelper' => 'required',
91                 // Some debugging stuff (optional but can be committed)
92                 'debug'                   => 'optional',
93                 // Application's exception handler (optional but can be committed)
94                 'exceptions'              => 'optional',
95                 // Application's configuration file (committed, non-local specific)
96                 'config'                  => 'required',
97                 // Local configuration file (optional, not committed, listed in .gitignore)
98                 'config-local'            => 'optional',
99                 // Application data (deprecated)
100                 'data'                    => 'deprecated',
101                 // Application loader (deprecated)
102                 'loader'                  => 'deprecated',
103                 // Application initializer (deprecated)
104                 'init'                    => 'deprecated',
105                 // Application starter (deprecated)
106                 'starter'                 => 'deprecated',
107         ];
108
109         /**
110          * Detected application's name
111          */
112         private static $detectedApplicationName;
113
114         /**
115          * Detected application's full path
116          */
117         private static $detectedApplicationPath;
118
119         /**
120          * Private constructor, no instance is needed from this class as only
121          * static methods exist.
122          */
123         private function __construct () {
124                 // Prevent making instances from this "utilities" class
125         }
126
127         /**
128          * Some "getter" for a configuration instance, making sure, it is unique
129          *
130          * @return      $configurationInstance  An instance of a FrameworkConfiguration class
131          */
132         public static function getConfigurationInstance () {
133                 // Is the instance there?
134                 if (is_null(self::$configurationInstance)) {
135                         // Init new instance
136                         self::$configurationInstance = new FrameworkConfiguration();
137                 }
138
139                 // Return it
140                 return self::$configurationInstance;
141         }
142
143         /**
144          * Getter for detected application name
145          *
146          * @return      $detectedApplicationName        Detected name of application
147          */
148         public static function getDetectedApplicationName () {
149                 return self::$detectedApplicationName;
150         }
151
152         /**
153          * Getter for detected application's full path
154          *
155          * @return      $detectedApplicationPath        Detected full path of application
156          */
157         public static function getDetectedApplicationPath () {
158                 return self::$detectedApplicationPath;
159         }
160
161         /**
162          * "Getter" to get response/request type from analysis of the system.
163          *
164          * @return      $requestType    Analyzed request type
165          */
166         public static function getRequestTypeFromSystem () {
167                 // Default is console
168                 $requestType = 'console';
169
170                 // Is 'HTTP_HOST' set?
171                 if (isset($_SERVER['HTTP_HOST'])) {
172                         // Then it is a HTML response/request.
173                         $requestType = 'html';
174                 }
175
176                 // Return it
177                 return $requestType;
178         }
179
180         /**
181          * Checks whether the given file/path is in open_basedir(). This does not
182          * gurantee that the file is actually readable and/or writeable. If you need
183          * such gurantee then please use isReadableFile() instead.
184          *
185          * @param       $fileInstance   An instance of a SplFileInfo class
186          * @return      $isReachable    Whether it is within open_basedir()
187          */
188         public static function isReachableFilePath (SplFileInfo $fileInstance) {
189                 // Is not reachable by default
190                 $isReachable = false;
191
192                 // Get open_basedir parameter
193                 $openBaseDir = trim(ini_get('open_basedir'));
194
195                 // Is it set?
196                 if (!empty($openBaseDir)) {
197                         // Check all entries
198                         foreach (explode(PATH_SEPARATOR, $openBaseDir) as $dir) {
199                                 // Check on existence
200                                 if (substr($fileInstance->getPathname(), 0, strlen($dir)) == $dir) {
201                                         // Is reachable
202                                         $isReachable = true;
203
204                                         // Abort lookup as it has been found in open_basedir
205                                         break;
206                                 }
207                         }
208                 } else {
209                         // If open_basedir is not set, all is allowed
210                         $isReachable = true;
211                 }
212
213                 // Return status
214                 return $isReachable;
215         }
216
217         /**
218          * Checks whether the give file is within open_basedir() (done by
219          * isReachableFilePath()), is actually a file and is readable.
220          *
221          * @param       $fileInstance   An instance of a SplFileInfo class
222          * @return      $isReadable             Whether the file is readable (and therefor exists)
223          */
224         public static function isReadableFile (SplFileInfo $fileInstance) {
225                 // Default is not readable
226                 $isReadable = false;
227
228                 // Check if it is a file and readable
229                 $isReadable = (
230                         (
231                                 self::isReachableFilePath($fileInstance)
232                         ) && (
233                                 $fileInstance->isFile()
234                         ) && (
235                                 $fileInstance->isReadable()
236                         )
237                 );
238
239                 // Return status
240                 return $isReadable;
241         }
242
243         /**
244          * Loads given include file
245          *
246          * @param       $fileInstance   An instance of a SplFileInfo class
247          * @return      void
248          * @throws      InvalidArgumentException        If file was not found or not readable or deprecated
249          */
250         public static function loadInclude (SplFileInfo $fileInstance) {
251                 // Should be there ...
252                 //* NOISY-DEBUG: */ printf('[%s:%d]: fileInstance=%s - CALLED!' . PHP_EOL, __METHOD__, __LINE__, $fileInstance);
253                 if (!self::isReadableFile($fileInstance)) {
254                         // Abort here
255                         throw new InvalidArgumentException(sprintf('Cannot find fileInstance.pathname=%s.', $fileInstance->getPathname()));
256                 }
257
258                 // Load it
259                 require_once $fileInstance->getPathname();
260
261                 // Trace message
262                 //* NOISY-DEBUG: */ printf('[%s:%d]: EXIT!' . PHP_EOL, __METHOD__, __LINE__);
263         }
264
265         /**
266          * Does the actual bootstrap. I think the amount of statically loaded
267          * include files cannot be reduced here as those files are need to early
268          * in the bootstrap phase. If you can find an other solution than this, with
269          * lesser "static includes" (means not loaded by the class loader), please
270          * let me know.
271          *
272          * @return      void
273          */
274         public static function doBootstrap () {
275                 // Load basic include files to continue bootstrapping
276                 //* NOISY-DEBUG: */ printf('[%s:%d]: CALLED!' . PHP_EOL, __METHOD__, __LINE__);
277                 self::loadInclude(new SplFileInfo(sprintf('%smain%sinterfaces%sclass_FrameworkInterface.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
278                 self::loadInclude(new SplFileInfo(sprintf('%smain%sclasses%sclass_BaseFrameworkSystem.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
279                 self::loadInclude(new SplFileInfo(sprintf('%smain%sclasses%sutils%sstrings%sclass_StringUtils.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
280                 self::loadInclude(new SplFileInfo(sprintf('%smain%sinterfaces%sregistry%sclass_Registerable.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
281                 self::loadInclude(new SplFileInfo(sprintf('%sconfig%sclass_FrameworkConfiguration.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR)));
282
283                 // Load global configuration
284                 self::loadInclude(new SplFileInfo(sprintf('%s%s', ApplicationEntryPoint::detectFrameworkPath(), 'config-global.php')));
285
286                 // Trace message
287                 //* NOISY-DEBUG: */ printf('[%s:%d]: EXIT!' . PHP_EOL, __METHOD__, __LINE__);
288         }
289
290         /**
291          * Initializes the framework by scanning for all framework-relevant
292          * classes, interfaces and exception. Then determine the request type and
293          * initialize a Requestable instance which will then contain all request
294          * parameter, also from CLI. Next step is to validate the application
295          * (very basic).
296          *
297          * @return      void
298          */
299         public static function initFramework () {
300                 /**
301                  * 1) Load class loader and scan framework classes, interfaces and
302                  *    exceptions.
303                  */
304                 self::scanFrameworkClasses();
305
306                 /*
307                  * 2) Determine the request type, console or web and store request and
308                  *    response here. This also initializes the request instance with
309                  *    all given parameters (see doc-tag for possible sources of
310                  *    parameters).
311                  */
312                 self::determineRequestType();
313
314                 /*
315                  * 3) Now, that there are all request parameters being available, check
316                  *    if 'application' is supplied. If it is not found, abort execution, if
317                  *    found, continue below with next step.
318                  */
319                 self::validateApplicationParameter();
320         }
321
322         /**
323          * Initializes the detected application. This may fail if required files
324          * are not found in the application's base path (not to be confused with
325          * 'application_base_path' which only points to /some/foo/application/.
326          *
327          * @return      void
328          */
329         public static function prepareApplication () {
330                 /*
331                  * Now check and load all files, found deprecated files will throw a
332                  * warning at the user.
333                  */
334                 foreach (self::$configAppIncludes as $fileName => $status) {
335                         // Construct file instance
336                         $fileInstance = new SplFileInfo(sprintf('%s%s.php', self::getDetectedApplicationPath(), $fileName));
337
338                         // Determine if this file is wanted/readable/deprecated
339                         if (($status == 'required') && (!self::isReadableFile($fileInstance))) {
340                                 // Nope, required file cannot be found/read from
341                                 ApplicationEntryPoint::exitApplication(sprintf('Application "%s" does not have required file "%s.php". Please add it.', self::getDetectedApplicationName(), $fileInstance->getBasename()));
342                         } elseif (($fileInstance->isFile()) && (!$fileInstance->isReadable())) {
343                                 // Found, not readable file
344                                 ApplicationEntryPoint::exitApplication(sprintf('File "%s.php" from application "%s" cannot be read. Please fix CHMOD.', $fileInstance->getBasename(), self::getDetectedApplicationName()));
345                         } elseif (($status != 'required') && (!self::isReadableFile($fileInstance))) {
346                                 // Not found but optional/deprecated file, skip it
347                                 continue;
348                         }
349
350                         // Is the file deprecated?
351                         if ($status == 'deprecated') {
352                                 // Issue warning
353                                 trigger_error(sprintf('Deprecated file "%s.php" found, will not load it to avoid problems. Please remove it from your application "%s" to avoid this warning.', $fileName, self::getDetectedApplicationName()), E_USER_WARNING);
354
355                                 // Skip loading deprecated file
356                                 continue;
357                         }
358
359                         // Load it
360                         self::loadInclude($fileInstance);
361                 }
362
363                 // After this, sort the configuration array
364                 self::getConfigurationInstance()->sortConfigurationArray();
365
366                 // Scan for application's classes, exceptions and interfaces
367                 ClassLoader::scanApplicationClasses();
368         }
369
370         /**
371          * Starts a fully initialized application, the class ApplicationHelper must
372          * be loaded at this point.
373          *
374          * @return      void
375          */
376         public static function startApplication () {
377                 // Is there an application helper instance?
378                 $applicationInstance = call_user_func_array(
379                         array(
380                                 'Org\Mxchange\CoreFramework\Helper\Application\ApplicationHelper', 'getSelfInstance'
381                         ), []
382                 );
383
384                 // Some sanity checks
385                 if ((empty($applicationInstance)) || (is_null($applicationInstance))) {
386                         // Something went wrong!
387                         ApplicationEntryPoint::exitApplication(sprintf('[Main:] The application <span class="app_name">%s</span> could not be launched because the helper class <span class="class_name">%s</span> is not loaded.',
388                                 self::getDetectedApplicationName(),
389                                 'Org\Mxchange\CoreFramework\Helper\Application\ApplicationHelper'
390                         ));
391                 } elseif (!is_object($applicationInstance)) {
392                         // No object!
393                         ApplicationEntryPoint::exitApplication(sprintf('[Main:] The application <span class="app_name">%s</span> could not be launched because &#39;app&#39; is not an object (%s).',
394                                 self::getDetectedApplicationName(),
395                                 gettype($applicationInstance)
396                         ));
397                 } elseif (!($applicationInstance instanceof ManageableApplication)) {
398                         // Missing interface
399                         ApplicationEntryPoint::exitApplication(sprintf('[Main:] The application <span class="app_name">%s</span> could not be launched because &#39;app&#39; is lacking required interface ManageableApplication.',
400                                 self::getDetectedApplicationName()
401                         ));
402                 }
403
404                 // Now call all methods in one go
405                 foreach (['setupApplicationData', 'initApplication', 'launchApplication'] as $methodName) {
406                         // Call method
407                         //*NOISY-DEBUG: */ printf('[%s:%d]: Calling methodName=%s ...' . PHP_EOL, __METHOD__, __LINE__, $methodName);
408                         call_user_func([$applicationInstance, $methodName]);
409                 }
410         }
411
412         /**
413          * Initializes database instance, no need to double-call this method
414          *
415          * @return      void
416          */
417         public static function initDatabaseInstance () {
418                 // Get application instance
419                 $applicationInstance = ApplicationHelper::getSelfInstance();
420
421                 // Is the database instance already set?
422                 if (self::getDatabaseInstance() instanceof DatabaseConnector) {
423                         // Yes, then abort here
424                         throw new BadMethodCallException('Method called twice.');
425                 }
426
427                 // Initialize database layer
428                 $databaseInstance = ObjectFactory::createObjectByConfiguredName(self::getConfigurationInstance()->getConfigEntry('database_type') . '_class');
429
430                 // Prepare database instance
431                 $connectionInstance = DatabaseConnection::createDatabaseConnection(DebugMiddleware::getSelfInstance(), $databaseInstance);
432
433                 // Set it in application helper
434                 self::setDatabaseInstance($connectionInstance);
435         }
436
437         /**
438          * Detects the server address (SERVER_ADDR) and set it in configuration
439          *
440          * @return      $serverAddress  The detected server address
441          * @throws      UnknownHostnameException        If SERVER_NAME cannot be resolved to an IP address
442          * @todo        Have to check some more entries from $_SERVER here
443          */
444         public static function detectServerAddress () {
445                 // Is the entry set?
446                 if (!isset(self::$serverAddress)) {
447                         // Is it set in $_SERVER?
448                         if (!empty($_SERVER['SERVER_ADDR'])) {
449                                 // Set it from $_SERVER
450                                 self::$serverAddress = $_SERVER['SERVER_ADDR'];
451                         } elseif (isset($_SERVER['SERVER_NAME'])) {
452                                 // Resolve IP address
453                                 $serverIp = ConsoleTools::resolveIpAddress($_SERVER['SERVER_NAME']);
454
455                                 // Is it valid?
456                                 if ($serverIp === false) {
457                                         /*
458                                          * Why is gethostbyname() returning the host name and not
459                                          * false as many other PHP functions are doing? ;-(
460                                          */
461                                         throw new UnknownHostnameException(sprintf('Cannot resolve "%s" to an IP address. Please fix your setup.', $_SERVER['SERVER_NAME']));
462                                 }
463
464                                 // Al fine, set it
465                                 self::$serverAddress = $serverIp;
466                         } else {
467                                 // Run auto-detecting through console tools lib
468                                 self::$serverAddress = ConsoleTools::acquireSelfIpAddress();
469                         }
470                 }
471
472                 // Return it
473                 return self::$serverAddress;
474         }
475
476         /**
477          * Setter for default time zone (must be correct!)
478          *
479          * @param       $timezone       The timezone string (e.g. Europe/Berlin)
480          * @return      $success        If timezone was accepted
481          * @throws      InvalidArgumentException        If $timezone is empty
482          */
483         public static function setDefaultTimezone (string $timezone) {
484                 // Is it set?
485                 if (empty($timezone)) {
486                         // Entry is empty
487                         throw new InvalidArgumentException('Parameter "timezone" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
488                 }
489
490                 // Default success
491                 $success = FALSE;
492
493                 /*
494                  * Set desired time zone to prevent date() and related functions to
495                  * issue an E_WARNING.
496                  */
497                 $success = date_default_timezone_set($timezone);
498
499                 // Return status
500                 return $success;
501         }
502
503         /**
504          * Checks whether HTTPS is set in $_SERVER
505          *
506          * @return      $isset  Whether HTTPS is set
507          * @todo        Test more fields
508          */
509         public static function isHttpSecured () {
510                 return (
511                         (
512                                 (
513                                         isset($_SERVER['HTTPS'])
514                                 ) && (
515                                         strtolower($_SERVER['HTTPS']) == 'on'
516                                 )
517                         ) || (
518                                 (
519                                         isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
520                                 ) && (
521                                         strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'
522                                 )
523                         )
524                 );
525         }
526
527         /**
528          * Dectect and return the base URL for all URLs and forms
529          *
530          * @return      $baseUrl        Detected base URL
531          */
532         public static function detectBaseUrl () {
533                 // Initialize the URL
534                 $protocol = 'http';
535
536                 // Do we have HTTPS?
537                 if (self::isHttpSecured()) {
538                         // Add the >s< for HTTPS
539                         $protocol = 'https';
540                 }
541
542                 // Construct the full URL and secure it against CSRF attacks
543                 $baseUrl = sprintf('%s://%s%s', $protocol, self::detectDomain(), self::detectScriptPath());
544
545                 // Return the URL
546                 return $baseUrl;
547         }
548
549         /**
550          * Detect safely and return the full domain where this script is installed
551          *
552          * @return      $fullDomain             The detected full domain
553          */
554         public static function detectDomain () {
555                 // Full domain is localnet.invalid by default
556                 $fullDomain = 'localnet.invalid';
557
558                 // Is the server name there?
559                 if (isset($_SERVER['SERVER_NAME'])) {
560                         // Detect the full domain
561                         $fullDomain = htmlentities(strip_tags($_SERVER['SERVER_NAME']), ENT_QUOTES);
562                 }
563
564                 // Return it
565                 return $fullDomain;
566         }
567
568         /**
569          * Detect safely the script path without trailing slash which is the glue
570          * between "http://your-domain.invalid/" and "script-name.php"
571          *
572          * @return      $scriptPath             The script path extracted from $_SERVER['SCRIPT_NAME']
573          */
574         public static function detectScriptPath () {
575                 // Default is empty
576                 $scriptPath = '';
577
578                 // Is the scriptname set?
579                 if (isset($_SERVER['SCRIPT_NAME'])) {
580                         // Get dirname from it and replace back-slashes with slashes for lame OSes...
581                         $scriptPath = str_replace("\\", '/', dirname($_SERVER['SCRIPT_NAME']));
582                 }
583
584                 // Return it
585                 return $scriptPath;
586         }
587
588         /**
589          * 1) Loads class scanner and scans all framework's classes and interfaces.
590          * This method also registers the class loader's method autoLoad() for the
591          * SPL auto-load feature. Remember that you can register additional methods
592          * (not functions, please) for other libraries.
593          *
594          * Yes, I know about Composer, but I like to keep my class loader around.
595          * You can always use mine as long as your classes have a namespace
596          * according naming-convention: Vendor\Project\Group[\SubGroup]
597          *
598          * @return      void
599          */
600         private static function scanFrameworkClasses () {
601                 // Include class loader
602                 require self::getConfigurationInstance()->getConfigEntry('framework_base_path') . 'loader/class_ClassLoader.php';
603
604                 // Register auto-load function with the SPL
605                 spl_autoload_register('Org\Mxchange\CoreFramework\Loader\ClassLoader::autoLoad');
606
607                 // Scan for all framework classes, exceptions and interfaces
608                 ClassLoader::scanFrameworkClasses();
609         }
610
611         /**
612          * 2) Determines request/response type and stores the created
613          * request/response instances in this object for later usage.
614          *
615          * @return      void
616          */
617         private static function determineRequestType () {
618                 // Determine request type
619                 $request = self::getRequestTypeFromSystem();
620                 $requestType = self::getRequestTypeFromSystem();
621
622                 // Create a new request object
623                 $requestInstance = ObjectFactory::createObjectByName(sprintf('Org\Mxchange\CoreFramework\Request\%sRequest', StringUtils::convertToClassName($request)));
624
625                 // Remember request instance here
626                 self::setRequestInstance($requestInstance);
627
628                 // Do we have another response?
629                 if ($requestInstance->isRequestElementSet('request')) {
630                         // Then use it
631                         $request = strtolower($requestInstance->getRequestElement('request'));
632                         $requestType = $request;
633                 }
634
635                 // ... and a new response object
636                 $responseInstance = ObjectFactory::createObjectByName(sprintf('Org\Mxchange\CoreFramework\Response\%sResponse', StringUtils::convertToClassName($request)));
637
638                 // Remember response instance here
639                 self::setResponseInstance($responseInstance);
640         }
641
642         /**
643          * 3) Validate parameter 'application' if it is set and the application is there.
644          *
645          * @return      void
646          */
647         private static function validateApplicationParameter () {
648                 // Is the parameter set?
649                 if (!self::getRequestInstance()->isRequestElementSet('app')) {
650                         /*
651                          * Don't continue here, the application 'selector' is no longer
652                          * supported and only existed as an idea to select the proper
653                          * application (by user).
654                          */
655                         ApplicationEntryPoint::exitApplication('No application specified. Please provide a parameter "app" and retry.');
656                 }
657
658                 // Get it for local usage
659                 $applicationName = self::getRequestInstance()->getRequestElement('app');
660
661                 // Secure it, by keeping out tags
662                 $applicationName = htmlentities(strip_tags($applicationName), ENT_QUOTES);
663
664                 // Secure it a little more with a reg.exp.
665                 $applicationName = preg_replace('/([^a-z0-9_-])+/i', '', $applicationName);
666
667                 // Construct FQPN (Full-Qualified Path Name) for ApplicationHelper class
668                 $applicationPath = sprintf(
669                         '%s%s%s',
670                         self::getConfigurationInstance()->getConfigEntry('application_base_path'),
671                         $applicationName,
672                         DIRECTORY_SEPARATOR
673                 );
674
675                 // Full path for application
676                 // Is the path there? This secures a bit the parameter (from untrusted source).
677                 if ((!is_dir($applicationPath)) || (!is_readable($applicationPath))) {
678                         // Not found or not readable
679                         ApplicationEntryPoint::exitApplication(sprintf('Application "%s" not found.', $applicationName));
680                 }
681
682                 // Set the detected application's name and full path for later usage
683                 self::$detectedApplicationPath = $applicationPath;
684                 self::$detectedApplicationName = $applicationName;
685         }
686
687         /**
688          * Getter for request instance
689          *
690          * @return      $requestInstance        An instance of a Requestable class
691          */
692         public static function getRequestInstance () {
693                 return self::$requestInstance;
694         }
695
696         /**
697          * Getter for response instance
698          *
699          * @return      $responseInstance       An instance of a Responseable class
700          */
701         public static function getResponseInstance () {
702                 return self::$responseInstance;
703         }
704
705         /**
706          * Setter for request instance
707          *
708          * @param       $requestInstance        An instance of a Requestable class
709          * @return      void
710          */
711         private static function setRequestInstance (Requestable $requestInstance) {
712                 self::$requestInstance = $requestInstance;
713         }
714
715         /**
716          * Setter for response instance
717          *
718          * @param       $responseInstance       An instance of a Responseable class
719          * @return      void
720          */
721         private static function setResponseInstance (Responseable $responseInstance) {
722                 self::$responseInstance = $responseInstance;
723         }
724
725         /**
726          * Setter for database instance
727          *
728          * @param       $databaseInstance       An instance of a DatabaseConnection class
729          * @return      void
730          */
731         public static function setDatabaseInstance (DatabaseConnection $databaseInstance) {
732                 self::$databaseInstance = $databaseInstance;
733         }
734
735         /**
736          * Getter for database instance
737          *
738          * @return      $databaseInstance       An instance of a DatabaseConnection class
739          */
740         public static function getDatabaseInstance () {
741                 // Return instance
742                 return self::$databaseInstance;
743         }
744
745         /**
746          * Private getter for language instance
747          *
748          * @return      $languageInstance       An instance of a ManageableLanguage class
749          */
750         public static function getLanguageInstance () {
751                 return self::$languageInstance;
752         }
753
754         /**
755          * Setter for language instance
756          *
757          * @param       $languageInstance       An instance of a ManageableLanguage class
758          * @return      void
759          */
760         public static function setLanguageInstance (ManageableLanguage $languageInstance) {
761                 self::$languageInstance = $languageInstance;
762         }
763
764 }