<?php 
 
/** 
 * Pimcore 
 * 
 * This source file is available under two different licenses: 
 * - GNU General Public License version 3 (GPLv3) 
 * - Pimcore Commercial License (PCL) 
 * Full copyright and license information is available in 
 * LICENSE.md which is distributed with this source code. 
 * 
 *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org) 
 *  @license    http://www.pimcore.org/license     GPLv3 and PCL 
 */ 
 
namespace Pimcore; 
 
use Pimcore\Model\DataObject; 
use Pimcore\Model\Document; 
use Symfony\Component\Dotenv\Dotenv; 
use Symfony\Component\ErrorHandler\Debug; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpKernel\KernelInterface; 
 
class Bootstrap 
{ 
    public static function startup() 
    { 
        self::setProjectRoot(); 
        self::bootstrap(); 
        $kernel = self::kernel(); 
 
        return $kernel; 
    } 
 
    /** 
     * @return KernelInterface 
     */ 
    public static function startupCli() 
    { 
        // ensure the cli arguments are set 
        if (!isset($_SERVER['argv'])) { 
            $_SERVER['argv'] = []; 
        } 
 
        self::setProjectRoot(); 
 
        self::bootstrap(); 
 
        $workingDirectory = getcwd(); 
        chdir(__DIR__); 
 
        // init shell verbosity as 0 - this would normally be handled by the console application, 
        // but as we boot the kernel early the kernel initializes this to 3 (verbose) by default 
        putenv('SHELL_VERBOSITY=0'); 
        $_ENV['SHELL_VERBOSITY'] = 0; 
        $_SERVER['SHELL_VERBOSITY'] = 0; 
 
        /** @var \Pimcore\Kernel $kernel */ 
        $kernel = self::kernel(); 
 
        if (is_readable($workingDirectory)) { 
            chdir($workingDirectory); 
        } 
 
        // activate inheritance for cli-scripts 
        \Pimcore::unsetAdminMode(); 
        Document::setHideUnpublished(true); 
        DataObject::setHideUnpublished(true); 
        DataObject::setGetInheritedValues(true); 
        DataObject\Localizedfield::setGetFallbackValues(true); 
 
        // CLI has no memory/time limits 
        @ini_set('memory_limit', '-1'); 
        @ini_set('max_execution_time', '-1'); 
        @ini_set('max_input_time', '-1'); 
 
        // Error reporting is enabled in CLI 
        @ini_set('display_errors', 'On'); 
        @ini_set('display_startup_errors', 'On'); 
 
        // Pimcore\Console handles maintenance mode through the AbstractCommand 
        $pimcoreConsole = (defined('PIMCORE_CONSOLE') && true === PIMCORE_CONSOLE); 
        if (!$pimcoreConsole) { 
            // skip if maintenance mode is on and the flag is not set 
            if (\Pimcore\Tool\Admin::isInMaintenanceMode() && !in_array('--ignore-maintenance-mode', $_SERVER['argv'])) { 
                die("in maintenance mode -> skip\nset the flag --ignore-maintenance-mode to force execution\n"); 
            } 
        } 
 
        return $kernel; 
    } 
 
    public static function setProjectRoot() 
    { 
        // this should already be defined at this point, but we include a fallback for backwards compatibility here 
        if (!defined('PIMCORE_PROJECT_ROOT')) { 
            define( 
                'PIMCORE_PROJECT_ROOT', 
                $_SERVER['PIMCORE_PROJECT_ROOT'] ?? $_ENV['PIMCORE_PROJECT_ROOT'] ?? 
                $_SERVER['REDIRECT_PIMCORE_PROJECT_ROOT'] ?? $_ENV['REDIRECT_PIMCORE_PROJECT_ROOT'] ?? 
                realpath(__DIR__ . '/../../../..') 
            ); 
        } 
    } 
 
    public static function bootstrap() 
    { 
        if (defined('PIMCORE_PROJECT_ROOT') && file_exists(PIMCORE_PROJECT_ROOT . '/vendor/autoload.php')) { 
            // PIMCORE_PROJECT_ROOT is usually always set at this point (self::setProjectRoot()), so it makes sense to check this first 
            $loader = include PIMCORE_PROJECT_ROOT . '/vendor/autoload.php'; 
        } elseif (file_exists(__DIR__ . '/../vendor/autoload.php')) { 
            $loader = include __DIR__ . '/../vendor/autoload.php'; 
        } elseif (file_exists(__DIR__ . '/../../../../vendor/autoload.php')) { 
            $loader = include __DIR__ . '/../../../../vendor/autoload.php'; 
        } else { 
            throw new \Exception('Unable to locate autoloader! Pimcore project root not found or invalid, please set/check env variable PIMCORE_PROJECT_ROOT.'); 
        } 
 
        self::defineConstants(); 
 
        /** @var \Composer\Autoload\ClassLoader $loader */ 
        \Pimcore::setAutoloader($loader); 
        self::autoload(); 
 
        ini_set('error_log', PIMCORE_PHP_ERROR_LOG); 
        ini_set('log_errors', '1'); 
 
        // load a startup file if it exists - this is a good place to preconfigure the system 
        // before the kernel is loaded - e.g. to set trusted proxies on the request object 
        $startupFile = PIMCORE_PROJECT_ROOT . '/config/pimcore/startup.php'; 
        if (file_exists($startupFile)) { 
            include_once $startupFile; 
        } 
 
        if (false === in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) { 
            // see https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/4.2/public/index.php#L15 
            if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) { 
                Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO); 
            } 
            if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) { 
                Request::setTrustedHosts([$trustedHosts]); 
            } 
        } 
    } 
 
    private static function prepareEnvVariables() 
    { 
        if (!($_SERVER['PIMCORE_SKIP_DOTENV_FILE'] ?? false)) { 
            if (class_exists('Symfony\Component\Dotenv\Dotenv')) { 
                (new Dotenv())->bootEnv(PIMCORE_PROJECT_ROOT . '/.env'); 
            } else { 
                $_SERVER += $_ENV; 
            } 
        } 
    } 
 
    public static function defineConstants() 
    { 
        self::prepareEnvVariables(); 
 
        // load custom constants 
        $customConstantsFile = PIMCORE_PROJECT_ROOT . '/config/pimcore/constants.php'; 
        if (file_exists($customConstantsFile)) { 
            include_once $customConstantsFile; 
        } 
 
        $resolveConstant = function (string $name, $default, bool $define = true) { 
            // return constant if defined 
            if (defined($name)) { 
                return constant($name); 
            } 
 
            $value = $_SERVER[$name] ?? $default; 
            if ($define) { 
                define($name, $value); 
            } 
 
            return $value; 
        }; 
 
        // basic paths 
        $resolveConstant('PIMCORE_COMPOSER_PATH', PIMCORE_PROJECT_ROOT . '/vendor'); 
        $resolveConstant('PIMCORE_COMPOSER_FILE_PATH', PIMCORE_PROJECT_ROOT); 
        $resolveConstant('PIMCORE_PATH', realpath(__DIR__ . '/..')); 
        $resolveConstant('PIMCORE_WEB_ROOT', PIMCORE_PROJECT_ROOT . '/public'); 
        $resolveConstant('PIMCORE_PRIVATE_VAR', PIMCORE_PROJECT_ROOT . '/var'); 
 
        // special directories for tests 
        // test mode can bei either controlled by a constant or an env variable 
        $testMode = (bool)$resolveConstant('PIMCORE_TEST', false, false); 
        if ($testMode) { 
            // override and initialize directories 
            $resolveConstant('PIMCORE_CLASS_DIRECTORY', PIMCORE_PATH . '/tests/_output/var/classes'); 
 
            if (!defined('PIMCORE_TEST')) { 
                define('PIMCORE_TEST', true); 
            } 
        } 
 
        // paths relying on basic paths above 
        $resolveConstant('PIMCORE_CUSTOM_CONFIGURATION_DIRECTORY', PIMCORE_PROJECT_ROOT . '/config/pimcore'); 
        $resolveConstant('PIMCORE_CUSTOM_CONFIGURATION_CLASS_DEFINITION_DIRECTORY', PIMCORE_CUSTOM_CONFIGURATION_DIRECTORY . '/classes'); 
        $resolveConstant('PIMCORE_CONFIGURATION_DIRECTORY', PIMCORE_PRIVATE_VAR . '/config'); 
        $resolveConstant('PIMCORE_LOG_DIRECTORY', PIMCORE_PRIVATE_VAR . '/log'); 
        $resolveConstant('PIMCORE_CACHE_DIRECTORY', PIMCORE_PRIVATE_VAR . '/cache/pimcore'); 
        $resolveConstant('PIMCORE_LOG_FILEOBJECT_DIRECTORY', PIMCORE_PRIVATE_VAR . '/application-logger'); 
        $resolveConstant('PIMCORE_SYMFONY_CACHE_DIRECTORY', PIMCORE_PRIVATE_VAR . '/cache'); 
        $resolveConstant('PIMCORE_CLASS_DIRECTORY', PIMCORE_PRIVATE_VAR . '/classes'); 
        $resolveConstant('PIMCORE_CLASS_DEFINITION_DIRECTORY', PIMCORE_CLASS_DIRECTORY); 
        $resolveConstant('PIMCORE_CUSTOMLAYOUT_DIRECTORY', PIMCORE_CLASS_DEFINITION_DIRECTORY . '/customlayouts'); 
        $resolveConstant('PIMCORE_SYSTEM_TEMP_DIRECTORY', PIMCORE_PRIVATE_VAR . '/tmp'); 
 
        // configure PHP's error logging 
        $resolveConstant('PIMCORE_PHP_ERROR_LOG', PIMCORE_LOG_DIRECTORY . '/php.log'); 
        $resolveConstant('PIMCORE_KERNEL_CLASS', '\App\Kernel'); 
    } 
 
    private static function autoload() 
    { 
        $loader = \Pimcore::getAutoloader(); 
 
        // tell the autoloader where to find Pimcore's generated class stubs 
        // this is primarily necessary for tests and custom class directories, which are not covered in composer.json 
        $loader->addPsr4('Pimcore\\Model\\DataObject\\', PIMCORE_CLASS_DIRECTORY . '/DataObject'); 
 
        if (defined('PIMCORE_APP_BUNDLE_CLASS_FILE')) { 
            require_once PIMCORE_APP_BUNDLE_CLASS_FILE; 
        } 
    } 
 
    /** 
     * @return KernelInterface 
     */ 
    public static function kernel() 
    { 
        $environment = Config::getEnvironment(); 
 
        $debug = (bool) ($_SERVER['APP_DEBUG'] ?? false); 
        if ($debug) { 
            umask(0000); 
            Debug::enable(); 
            @ini_set('display_errors', 'On'); 
        } 
 
        if (defined('PIMCORE_KERNEL_CLASS')) { 
            $kernelClass = PIMCORE_KERNEL_CLASS; 
        } else { 
            $kernelClass = '\App\Kernel'; 
        } 
 
        if (!class_exists($kernelClass)) { 
            throw new \InvalidArgumentException(sprintf('Defined Kernel Class %s not found', $kernelClass)); 
        } 
 
        if (!is_subclass_of($kernelClass, Kernel::class)) { 
            throw new \InvalidArgumentException(sprintf('Defined Kernel Class %s needs to extend the \Pimcore\Kernel Class', $kernelClass)); 
        } 
 
        $kernel = new $kernelClass($environment, $debug); 
        \Pimcore::setKernel($kernel); 
        $kernel->boot(); 
 
        $conf = \Pimcore::getContainer()->getParameter('pimcore.config'); 
 
        if ($conf['general']['timezone']) { 
            date_default_timezone_set($conf['general']['timezone']); 
        } 
 
        return $kernel; 
    } 
}