]> git.mxchange.org Git - core.git/blob - framework/bootstrap/class_FrameworkBootstrap.php
Continued:
[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 - 2023 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                 //* NOISY-DEBUG: */ printf('[%s:%d]: fileInstance=%s - CALLED!' . PHP_EOL, __METHOD__, __LINE__, get_class($fileInstance));
191                 $isReachable = false;
192
193                 // Get open_basedir parameter
194                 $openBaseDir = trim(ini_get('open_basedir'));
195
196                 // Is it set?
197                 //* NOISY-DEBUG: */ printf('[%s:%d]: openBaseDir=%s' . PHP_EOL, __METHOD__, __LINE__, $openBaseDir);
198                 if (!empty($openBaseDir)) {
199                         // Check all entries
200                         foreach (explode(PATH_SEPARATOR, $openBaseDir) as $dir) {
201                                 // Check on existence
202                                 //* NOISY-DEBUG: */ printf('[%s:%d]: dir=%s' . PHP_EOL, __METHOD__, __LINE__, $dir);
203                                 if (substr($fileInstance->getPathname(), 0, strlen($dir)) == $dir) {
204                                         // Is reachable
205                                         $isReachable = true;
206
207                                         // Abort lookup as it has been found in open_basedir
208                                         //* NOISY-DEBUG: */ printf('[%s:%d]: BREAK!' . PHP_EOL, __METHOD__, __LINE__);
209                                         break;
210                                 }
211                         }
212                 } else {
213                         // If open_basedir is not set, all is allowed
214                         //* NOISY-DEBUG: */ printf('[%s:%d]: All is allowed - BREAK!' . PHP_EOL, __METHOD__, __LINE__);
215                         $isReachable = true;
216                 }
217
218                 // Return status
219                 //* NOISY-DEBUG: */ printf('[%s:%d]: isReachable=%d - EXIT' . PHP_EOL, __METHOD__, __LINE__, intval($isReachable));
220                 return $isReachable;
221         }
222
223         /**
224          * Checks whether the give file is within open_basedir() (done by
225          * isReachableFilePath()), is actually a file and is readable.
226          *
227          * @param       $fileInstance   An instance of a SplFileInfo class
228          * @return      $isReadable             Whether the file is readable (and therefor exists)
229          */
230         public static function isReadableFile (SplFileInfo $fileInstance) {
231                 // Default is not readable
232                 $isReadable = false;
233
234                 // Check if it is a file and readable
235                 $isReadable = (
236                         (
237                                 self::isReachableFilePath($fileInstance)
238                         ) && (
239                                 $fileInstance->isFile()
240                         ) && (
241                                 $fileInstance->isReadable()
242                         )
243                 );
244
245                 // Return status
246                 return $isReadable;
247         }
248
249         /**
250          * Loads given include file
251          *
252          * @param       $fileInstance   An instance of a SplFileInfo class
253          * @return      void
254          * @throws      InvalidArgumentException        If file was not found or not readable or deprecated
255          */
256         public static function loadInclude (SplFileInfo $fileInstance) {
257                 // Should be there ...
258                 //* NOISY-DEBUG: */ printf('[%s:%d]: fileInstance=%s - CALLED!' . PHP_EOL, __METHOD__, __LINE__, $fileInstance->__toString());
259                 if (!self::isReadableFile($fileInstance)) {
260                         // Abort here
261                         throw new InvalidArgumentException(sprintf('Cannot find fileInstance.pathname=%s.', $fileInstance->getPathname()));
262                 } elseif (!$fileInstance->isFile()) {
263                         // Not a file
264                         throw new InvalidArgumentException(sprintf('fileInstance.pathname=%s is not a file', $fileInstance->getPathname()));
265                 } elseif (substr($fileInstance->__toString(), -4, 4) != '.php') {
266                         // Not PHP script
267                         throw new InvalidArgumentException(sprintf('fileInstance.pathname=%s is not a PHP script', $fileInstance->getPathname()));
268                 }
269
270                 // Load it
271                 require_once $fileInstance->getPathname();
272
273                 // Trace message
274                 //* NOISY-DEBUG: */ printf('[%s:%d]: EXIT!' . PHP_EOL, __METHOD__, __LINE__);
275         }
276
277         /**
278          * Does the actual bootstrap. I think the amount of statically loaded
279          * include files cannot be reduced here as those files are need to early
280          * in the bootstrap phase. If you can find an other solution than this, with
281          * lesser "static includes" (means not loaded by the class loader), please
282          * let me know.
283          *
284          * @return      void
285          */
286         public static function doBootstrap () {
287                 // Load basic include files to continue bootstrapping
288                 //* NOISY-DEBUG: */ printf('[%s:%d]: CALLED!' . PHP_EOL, __METHOD__, __LINE__);
289                 self::loadInclude(new SplFileInfo(sprintf('%smain%sinterfaces%sclass_FrameworkInterface.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
290                 self::loadInclude(new SplFileInfo(sprintf('%smain%sclasses%sclass_BaseFrameworkSystem.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
291                 self::loadInclude(new SplFileInfo(sprintf('%smain%sclasses%sutils%sstrings%sclass_StringUtils.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
292                 self::loadInclude(new SplFileInfo(sprintf('%smain%sinterfaces%sregistry%sclass_Registerable.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
293                 self::loadInclude(new SplFileInfo(sprintf('%sconfig%sclass_FrameworkConfiguration.php', ApplicationEntryPoint::detectFrameworkPath(), DIRECTORY_SEPARATOR)));
294
295                 // Load global configuration
296                 self::loadInclude(new SplFileInfo(sprintf('%s%s', ApplicationEntryPoint::detectFrameworkPath(), 'config-global.php')));
297
298                 // Trace message
299                 //* NOISY-DEBUG: */ printf('[%s:%d]: EXIT!' . PHP_EOL, __METHOD__, __LINE__);
300         }
301
302         /**
303          * Initializes the framework by scanning for all framework-relevant
304          * classes, interfaces and exception. Then determine the request type and
305          * initialize a Requestable instance which will then contain all request
306          * parameter, also from CLI. Next step is to validate the application
307          * (very basic).
308          *
309          * @return      void
310          */
311         public static function initFramework () {
312                 /**
313                  * 1) Load class loader and scan framework classes, interfaces and
314                  *    exceptions.
315                  */
316                 self::scanFrameworkClasses();
317
318                 /*
319                  * 2) Determine the request type, console or web and store request and
320                  *    response here. This also initializes the request instance with
321                  *    all given parameters (see doc-tag for possible sources of
322                  *    parameters).
323                  */
324                 self::determineRequestType();
325
326                 /*
327                  * 3) Now, that there are all request parameters being available, check
328                  *    if 'application' is supplied. If it is not found, abort execution, if
329                  *    found, continue below with next step.
330                  */
331                 self::validateApplicationParameter();
332         }
333
334         /**
335          * Initializes the detected application. This may fail if required files
336          * are not found in the application's base path (not to be confused with
337          * 'application_base_path' which only points to /some/foo/application/.
338          *
339          * @return      void
340          */
341         public static function prepareApplication () {
342                 /*
343                  * Now check and load all files, found deprecated files will throw a
344                  * warning at the user.
345                  */
346                 /* NOISY-DEBUG: */ printf('[%s:%d]: self::configAppIncludes()=%d' . PHP_EOL, __METHOD__, __LINE__, count(self::$configAppIncludes));
347                 foreach (self::$configAppIncludes as $fileName => $status) {
348                         // Construct file instance
349                         //* NOISY-DEBUG: */ printf('[%s:%d]: fileName=%s,status=%s' . PHP_EOL, __METHOD__, __LINE__, $fileName, $status);
350                         $fileInstance = new SplFileInfo(sprintf('%s%s.php', self::getDetectedApplicationPath(), $fileName));
351
352                         // Determine if this file is wanted/readable/deprecated
353                         if (($status == 'required') && (!self::isReadableFile($fileInstance))) {
354                                 // Nope, required file cannot be found/read from
355                                 ApplicationEntryPoint::exitApplication(sprintf('Application "%s" does not have required file "%s.php". Please add it.', self::getDetectedApplicationName(), $fileInstance->getBasename()));
356                         } elseif (($fileInstance->isFile()) && (!$fileInstance->isReadable())) {
357                                 // Found, not readable file
358                                 ApplicationEntryPoint::exitApplication(sprintf('File "%s.php" from application "%s" cannot be read. Please fix CHMOD.', $fileInstance->getBasename(), self::getDetectedApplicationName()));
359                         } elseif (($status != 'required') && (!self::isReadableFile($fileInstance))) {
360                                 // Not found but optional/deprecated file, skip it
361                                 //* NOISY-DEBUG: */ printf('[%s:%d]: fileName=%s,status=%s - SKIPPED!' . PHP_EOL, __METHOD__, __LINE__, $fileName, $status);
362                                 continue;
363                         }
364
365                         // Is the file deprecated?
366                         if ($status == 'deprecated') {
367                                 // Issue warning
368                                 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);
369
370                                 // Skip loading deprecated file
371                                 continue;
372                         }
373
374                         // Load it
375                         //* NOISY-DEBUG: */ printf('[%s:%d]: Invoking self::loadInclude(%s) ...' . PHP_EOL, __METHOD__, __LINE__, $fileInstance->__toString());
376                         self::loadInclude($fileInstance);
377                 }
378
379                 // After this, sort the configuration array
380                 self::getConfigurationInstance()->sortConfigurationArray();
381
382                 // Scan for application's classes, exceptions and interfaces
383                 ClassLoader::scanApplicationClasses();
384         }
385
386         /**
387          * Starts a fully initialized application, the class ApplicationHelper must
388          * be loaded at this point.
389          *
390          * @return      void
391          */
392         public static function startApplication () {
393                 // Is there an application helper instance?
394                 //* NOISY-DEBUG: */ printf('[%s:%d]: CALLED!' . PHP_EOL, __METHOD__, __LINE__);
395                 $applicationInstance = call_user_func_array(
396                         [
397                                 'Org\Mxchange\CoreFramework\Helper\Application\ApplicationHelper', 'getSelfInstance'
398                         ], []
399                 );
400
401                 // Some sanity checks
402                 //* NOISY-DEBUG: */ printf('[%s:%d]: applicationInstance=%s' . PHP_EOL, __METHOD__, __LINE__, $applicationInstance->__toString());
403                 if ((empty($applicationInstance)) || (is_null($applicationInstance))) {
404                         // Something went wrong!
405                         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.',
406                                 self::getDetectedApplicationName(),
407                                 'Org\Mxchange\CoreFramework\Helper\Application\ApplicationHelper'
408                         ));
409                 } elseif (!is_object($applicationInstance)) {
410                         // No object!
411                         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).',
412                                 self::getDetectedApplicationName(),
413                                 gettype($applicationInstance)
414                         ));
415                 } elseif (!($applicationInstance instanceof ManageableApplication)) {
416                         // Missing interface
417                         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.',
418                                 self::getDetectedApplicationName()
419                         ));
420                 }
421
422                 // Now call all methods in one go
423                 //* NOISY-DEBUG: */ printf('[%s:%d]: Initializing application ...' . PHP_EOL, __METHOD__, __LINE__);
424                 foreach (['setupApplicationData', 'initApplication', 'launchApplication'] as $methodName) {
425                         // Call method
426                         //*NOISY-DEBUG: */ printf('[%s:%d]: Invoking methodName=%s ...' . PHP_EOL, __METHOD__, __LINE__, $methodName);
427                         call_user_func([$applicationInstance, $methodName]);
428                 }
429
430                 // Trace message
431                 //* NOISY-DEBUG: */ printf('[%s:%d]: EXIT!' . PHP_EOL, __METHOD__, __LINE__);
432         }
433
434         /**
435          * Initializes database instance, no need to double-call this method
436          *
437          * @return      void
438          */
439         public static function initDatabaseInstance () {
440                 // Get application instance
441                 $applicationInstance = ApplicationHelper::getSelfInstance();
442
443                 // Is the database instance already set?
444                 if (self::getDatabaseInstance() instanceof DatabaseConnector) {
445                         // Yes, then abort here
446                         throw new BadMethodCallException('Method called twice.');
447                 }
448
449                 // Initialize database layer
450                 $databaseInstance = ObjectFactory::createObjectByConfiguredName(self::getConfigurationInstance()->getConfigEntry('database_type') . '_class');
451
452                 // Prepare database instance
453                 $connectionInstance = DatabaseConnection::createDatabaseConnection(DebugMiddleware::getSelfInstance(), $databaseInstance);
454
455                 // Set it in application helper
456                 self::setDatabaseInstance($connectionInstance);
457         }
458
459         /**
460          * Detects the server address (SERVER_ADDR) and set it in configuration
461          *
462          * @return      $serverAddress  The detected server address
463          * @throws      UnknownHostnameException        If SERVER_NAME cannot be resolved to an IP address
464          * @todo        Have to check some more entries from $_SERVER here
465          */
466         public static function detectServerAddress () {
467                 // Is the entry set?
468                 if (!isset(self::$serverAddress)) {
469                         // Is it set in $_SERVER?
470                         if (!empty($_SERVER['SERVER_ADDR'])) {
471                                 // Set it from $_SERVER
472                                 self::$serverAddress = $_SERVER['SERVER_ADDR'];
473                         } elseif (isset($_SERVER['SERVER_NAME'])) {
474                                 // Resolve IP address
475                                 $serverIp = ConsoleTools::resolveIpAddress($_SERVER['SERVER_NAME']);
476
477                                 // Is it valid?
478                                 if ($serverIp === false) {
479                                         /*
480                                          * Why is gethostbyname() returning the host name and not
481                                          * false as many other PHP functions are doing? ;-(
482                                          */
483                                         throw new UnknownHostnameException(sprintf('Cannot resolve "%s" to an IP address. Please fix your setup.', $_SERVER['SERVER_NAME']));
484                                 }
485
486                                 // Al fine, set it
487                                 self::$serverAddress = $serverIp;
488                         } else {
489                                 // Run auto-detecting through console tools lib
490                                 self::$serverAddress = ConsoleTools::acquireSelfIpAddress();
491                         }
492                 }
493
494                 // Return it
495                 return self::$serverAddress;
496         }
497
498         /**
499          * Setter for default time zone (must be correct!)
500          *
501          * @param       $timezone       The timezone string (e.g. Europe/Berlin)
502          * @return      $success        If timezone was accepted
503          * @throws      InvalidArgumentException        If $timezone is empty
504          */
505         public static function setDefaultTimezone (string $timezone) {
506                 // Is it set?
507                 if (empty($timezone)) {
508                         // Entry is empty
509                         throw new InvalidArgumentException('Parameter "timezone" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
510                 }
511
512                 // Default success
513                 $success = FALSE;
514
515                 /*
516                  * Set desired time zone to prevent date() and related functions to
517                  * issue an E_WARNING.
518                  */
519                 $success = date_default_timezone_set($timezone);
520
521                 // Return status
522                 return $success;
523         }
524
525         /**
526          * Checks whether HTTPS is set in $_SERVER
527          *
528          * @return      $isset  Whether HTTPS is set
529          * @todo        Test more fields
530          */
531         public static function isHttpSecured () {
532                 return (
533                         (
534                                 (
535                                         isset($_SERVER['HTTPS'])
536                                 ) && (
537                                         strtolower($_SERVER['HTTPS']) == 'on'
538                                 )
539                         ) || (
540                                 (
541                                         isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
542                                 ) && (
543                                         strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'
544                                 )
545                         )
546                 );
547         }
548
549         /**
550          * Dectect and return the base URL for all URLs and forms
551          *
552          * @return      $baseUrl        Detected base URL
553          */
554         public static function detectBaseUrl () {
555                 // Initialize the URL
556                 $protocol = 'http';
557
558                 // Do we have HTTPS?
559                 if (self::isHttpSecured()) {
560                         // Add the >s< for HTTPS
561                         $protocol = 'https';
562                 }
563
564                 // Construct the full URL and secure it against CSRF attacks
565                 $baseUrl = sprintf('%s://%s%s', $protocol, self::detectDomain(), self::detectScriptPath());
566
567                 // Return the URL
568                 return $baseUrl;
569         }
570
571         /**
572          * Detect safely and return the full domain where this script is installed
573          *
574          * @return      $fullDomain             The detected full domain
575          */
576         public static function detectDomain () {
577                 // Full domain is localnet.invalid by default
578                 $fullDomain = 'localnet.invalid';
579
580                 // Is the server name there?
581                 if (isset($_SERVER['SERVER_NAME'])) {
582                         // Detect the full domain
583                         $fullDomain = htmlentities(strip_tags($_SERVER['SERVER_NAME']), ENT_QUOTES);
584                 }
585
586                 // Return it
587                 return $fullDomain;
588         }
589
590         /**
591          * Detect safely the script path without trailing slash which is the glue
592          * between "http://your-domain.invalid/" and "script-name.php"
593          *
594          * @return      $scriptPath             The script path extracted from $_SERVER['SCRIPT_NAME']
595          */
596         public static function detectScriptPath () {
597                 // Default is empty
598                 $scriptPath = '';
599
600                 // Is the scriptname set?
601                 if (isset($_SERVER['SCRIPT_NAME'])) {
602                         // Get dirname from it and replace back-slashes with slashes for lame OSes...
603                         $scriptPath = str_replace("\\", '/', dirname($_SERVER['SCRIPT_NAME']));
604                 }
605
606                 // Return it
607                 return $scriptPath;
608         }
609
610         /**
611          * 1) Loads class scanner and scans all framework's classes and interfaces.
612          * This method also registers the class loader's method autoLoad() for the
613          * SPL auto-load feature. Remember that you can register additional methods
614          * (not functions, please) for other libraries.
615          *
616          * Yes, I know about Composer, but I like to keep my class loader around.
617          * You can always use mine as long as your classes have a namespace
618          * according naming-convention: Vendor\Project\Group[\SubGroup]
619          *
620          * @return      void
621          */
622         private static function scanFrameworkClasses () {
623                 // Include class loader
624                 require self::getConfigurationInstance()->getConfigEntry('framework_base_path') . 'loader/class_ClassLoader.php';
625
626                 // Register auto-load function with the SPL
627                 spl_autoload_register('Org\Mxchange\CoreFramework\Loader\ClassLoader::autoLoad');
628
629                 // Scan for all framework classes, exceptions and interfaces
630                 ClassLoader::scanFrameworkClasses();
631         }
632
633         /**
634          * 2) Determines request/response type and stores the created
635          * request/response instances in this object for later usage.
636          *
637          * @return      void
638          */
639         private static function determineRequestType () {
640                 // Determine request type
641                 $request = self::getRequestTypeFromSystem();
642                 $requestType = self::getRequestTypeFromSystem();
643
644                 // Create a new request object
645                 $requestInstance = ObjectFactory::createObjectByName(sprintf('Org\Mxchange\CoreFramework\Request\%sRequest', StringUtils::convertToClassName($request)));
646
647                 // Remember request instance here
648                 self::setRequestInstance($requestInstance);
649
650                 // Do we have another response?
651                 if ($requestInstance->isRequestElementSet('request')) {
652                         // Then use it
653                         $request = strtolower($requestInstance->getRequestElement('request'));
654                         $requestType = $request;
655                 }
656
657                 // ... and a new response object
658                 $responseInstance = ObjectFactory::createObjectByName(sprintf('Org\Mxchange\CoreFramework\Response\%sResponse', StringUtils::convertToClassName($request)));
659
660                 // Remember response instance here
661                 self::setResponseInstance($responseInstance);
662         }
663
664         /**
665          * 3) Validate parameter 'application' if it is set and the application is there.
666          *
667          * @return      void
668          */
669         private static function validateApplicationParameter () {
670                 // Is the parameter set?
671                 if (!self::getRequestInstance()->isRequestElementSet('app')) {
672                         /*
673                          * Don't continue here, the application 'selector' is no longer
674                          * supported and only existed as an idea to select the proper
675                          * application (by user).
676                          */
677                         ApplicationEntryPoint::exitApplication('No application specified. Please provide a parameter "app" and retry.');
678                 }
679
680                 // Get it for local usage
681                 $applicationName = self::getRequestInstance()->getRequestElement('app');
682
683                 // Secure it, by keeping out tags
684                 $applicationName = htmlentities(strip_tags($applicationName), ENT_QUOTES);
685
686                 // Secure it a little more with a reg.exp.
687                 $applicationName = preg_replace('/([^a-z0-9_-])+/i', '', $applicationName);
688
689                 // Construct FQPN (Full-Qualified Path Name) for ApplicationHelper class
690                 $applicationPath = sprintf(
691                         '%s%s%s',
692                         self::getConfigurationInstance()->getConfigEntry('application_base_path'),
693                         $applicationName,
694                         DIRECTORY_SEPARATOR
695                 );
696
697                 // Full path for application
698                 // Is the path there? This secures a bit the parameter (from untrusted source).
699                 if ((!is_dir($applicationPath)) || (!is_readable($applicationPath))) {
700                         // Not found or not readable
701                         ApplicationEntryPoint::exitApplication(sprintf('Application "%s" not found.', $applicationName));
702                 }
703
704                 // Set the detected application's name and full path for later usage
705                 self::$detectedApplicationPath = $applicationPath;
706                 self::$detectedApplicationName = $applicationName;
707         }
708
709         /**
710          * Getter for request instance
711          *
712          * @return      $requestInstance        An instance of a Requestable class
713          */
714         public static function getRequestInstance () {
715                 return self::$requestInstance;
716         }
717
718         /**
719          * Getter for response instance
720          *
721          * @return      $responseInstance       An instance of a Responseable class
722          */
723         public static function getResponseInstance () {
724                 return self::$responseInstance;
725         }
726
727         /**
728          * Setter for request instance
729          *
730          * @param       $requestInstance        An instance of a Requestable class
731          * @return      void
732          */
733         private static function setRequestInstance (Requestable $requestInstance) {
734                 self::$requestInstance = $requestInstance;
735         }
736
737         /**
738          * Setter for response instance
739          *
740          * @param       $responseInstance       An instance of a Responseable class
741          * @return      void
742          */
743         private static function setResponseInstance (Responseable $responseInstance) {
744                 self::$responseInstance = $responseInstance;
745         }
746
747         /**
748          * Setter for database instance
749          *
750          * @param       $databaseInstance       An instance of a DatabaseConnection class
751          * @return      void
752          */
753         public static function setDatabaseInstance (DatabaseConnection $databaseInstance) {
754                 self::$databaseInstance = $databaseInstance;
755         }
756
757         /**
758          * Getter for database instance
759          *
760          * @return      $databaseInstance       An instance of a DatabaseConnection class
761          */
762         public static function getDatabaseInstance () {
763                 // Return instance
764                 return self::$databaseInstance;
765         }
766
767         /**
768          * Private getter for language instance
769          *
770          * @return      $languageInstance       An instance of a ManageableLanguage class
771          */
772         public static function getLanguageInstance () {
773                 return self::$languageInstance;
774         }
775
776         /**
777          * Setter for language instance
778          *
779          * @param       $languageInstance       An instance of a ManageableLanguage class
780          * @return      void
781          */
782         public static function setLanguageInstance (ManageableLanguage $languageInstance) {
783                 self::$languageInstance = $languageInstance;
784         }
785
786 }