mirror of
				https://github.com/Icinga/icingaweb2.git
				synced 2025-11-03 20:54:27 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			673 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			673 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
 | 
						|
 | 
						|
namespace Icinga\Application;
 | 
						|
 | 
						|
use ErrorException;
 | 
						|
use Exception;
 | 
						|
use LogicException;
 | 
						|
use Icinga\Application\Modules\Manager as ModuleManager;
 | 
						|
use Icinga\Authentication\User\UserBackend;
 | 
						|
use Icinga\Data\ConfigObject;
 | 
						|
use Icinga\Data\ResourceFactory;
 | 
						|
use Icinga\Exception\ConfigurationError;
 | 
						|
use Icinga\Exception\NotReadableError;
 | 
						|
use Icinga\Application\Logger;
 | 
						|
use Icinga\Util\Translator;
 | 
						|
use Icinga\Exception\IcingaException;
 | 
						|
 | 
						|
/**
 | 
						|
 * This class bootstraps a thin Icinga application layer
 | 
						|
 *
 | 
						|
 * Usage example for CLI:
 | 
						|
 * <code>
 | 
						|
 * use Icinga\Application\Cli;
 | 
						|
 | 
						|
 * Cli::start();
 | 
						|
 * </code>
 | 
						|
 *
 | 
						|
 * Usage example for Icinga Web application:
 | 
						|
 * <code>
 | 
						|
 * use Icinga\Application\Web;
 | 
						|
 * Web::start()->dispatch();
 | 
						|
 * </code>
 | 
						|
 *
 | 
						|
 * Usage example for Icinga-Web 1.x compatibility mode:
 | 
						|
 * <code>
 | 
						|
 * use Icinga\Application\LegacyWeb;
 | 
						|
 * LegacyWeb::start()->setIcingaWebBasedir(ICINGAWEB_BASEDIR)->dispatch();
 | 
						|
 * </code>
 | 
						|
 */
 | 
						|
abstract class ApplicationBootstrap
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * Base directory
 | 
						|
     *
 | 
						|
     * Parent folder for at least application, bin, modules, library/vendor and public
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    protected $baseDir;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Application directory
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    protected $appDir;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Vendor library directory
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    protected $vendorDir;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Library directory
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    protected $libDir;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Configuration directory
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    protected $configDir;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Icinga class loader
 | 
						|
     *
 | 
						|
     * @var ClassLoader
 | 
						|
     */
 | 
						|
    private $loader;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Config object
 | 
						|
     *
 | 
						|
     * @var Config
 | 
						|
     */
 | 
						|
    protected $config;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Module manager
 | 
						|
     *
 | 
						|
     * @var ModuleManager
 | 
						|
     */
 | 
						|
    private $moduleManager;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Flag indicates we're on cli environment
 | 
						|
     *
 | 
						|
     * @var bool
 | 
						|
     */
 | 
						|
    protected $isCli = false;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Flag indicates we're on web environment
 | 
						|
     *
 | 
						|
     * @var bool
 | 
						|
     */
 | 
						|
    protected $isWeb = false;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Whether Icinga Web 2 requires setup
 | 
						|
     *
 | 
						|
     * @var bool
 | 
						|
     */
 | 
						|
    protected $requiresSetup = false;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructor
 | 
						|
     *
 | 
						|
     * @param string $baseDir   Icinga Web 2 base directory
 | 
						|
     * @param string $configDir Path to Icinga Web 2's configuration files
 | 
						|
     */
 | 
						|
    protected function __construct($baseDir = null, $configDir = null)
 | 
						|
    {
 | 
						|
        if ($baseDir === null) {
 | 
						|
            $baseDir = dirname($this->getBootstrapDirectory());
 | 
						|
        }
 | 
						|
        $this->baseDir = $baseDir;
 | 
						|
        $this->appDir = $baseDir . '/application';
 | 
						|
        $this->vendorDir = $baseDir . '/library/vendor';
 | 
						|
        $this->libDir = realpath(__DIR__ . '/../..');
 | 
						|
 | 
						|
        $this->setupAutoloader();
 | 
						|
 | 
						|
        if ($configDir === null) {
 | 
						|
            if (array_key_exists('ICINGAWEB_CONFIGDIR', $_SERVER)) {
 | 
						|
                $configDir = $_SERVER['ICINGAWEB_CONFIGDIR'];
 | 
						|
            } else {
 | 
						|
                $configDir = Platform::isWindows()
 | 
						|
                    ? $baseDir . '/config'
 | 
						|
                    : '/etc/icingaweb2';
 | 
						|
            }
 | 
						|
        }
 | 
						|
        $canonical = realpath($configDir);
 | 
						|
        $this->configDir = $canonical ? $canonical : $configDir;
 | 
						|
 | 
						|
        set_include_path(
 | 
						|
            implode(
 | 
						|
                PATH_SEPARATOR,
 | 
						|
                array($this->vendorDir, get_include_path())
 | 
						|
            )
 | 
						|
        );
 | 
						|
 | 
						|
        Benchmark::measure('Bootstrap, autoloader registered');
 | 
						|
 | 
						|
        Icinga::setApp($this);
 | 
						|
 | 
						|
        require_once dirname(__FILE__) . '/functions.php';
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Bootstrap interface method for concrete bootstrap objects
 | 
						|
     *
 | 
						|
     * @return mixed
 | 
						|
     */
 | 
						|
    abstract protected function bootstrap();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Getter for module manager
 | 
						|
     *
 | 
						|
     * @return ModuleManager
 | 
						|
     */
 | 
						|
    public function getModuleManager()
 | 
						|
    {
 | 
						|
        return $this->moduleManager;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Getter for class loader
 | 
						|
     *
 | 
						|
     * @return ClassLoader
 | 
						|
     */
 | 
						|
    public function getLoader()
 | 
						|
    {
 | 
						|
        return $this->loader;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Getter for configuration object
 | 
						|
     *
 | 
						|
     * @return Config
 | 
						|
     */
 | 
						|
    public function getConfig()
 | 
						|
    {
 | 
						|
        return $this->config;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Flag indicates we're on cli environment
 | 
						|
     *
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function isCli()
 | 
						|
    {
 | 
						|
        return $this->isCli;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Flag indicates we're on web environment
 | 
						|
     *
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function isWeb()
 | 
						|
    {
 | 
						|
        return $this->isWeb;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Helper to glue directories together
 | 
						|
     *
 | 
						|
     * @param   string $dir
 | 
						|
     * @param   string $subdir
 | 
						|
     *
 | 
						|
     * @return  string
 | 
						|
     */
 | 
						|
    private function getDirWithSubDir($dir, $subdir = null)
 | 
						|
    {
 | 
						|
        if ($subdir !== null) {
 | 
						|
            $dir .= '/' . ltrim($subdir, '/');
 | 
						|
        }
 | 
						|
 | 
						|
        return $dir;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the base directory
 | 
						|
     *
 | 
						|
     * @param   string $subDir Optional sub directory to get
 | 
						|
     *
 | 
						|
     * @return  string
 | 
						|
     */
 | 
						|
    public function getBaseDir($subDir = null)
 | 
						|
    {
 | 
						|
        return $this->getDirWithSubDir($this->baseDir, $subDir);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the application directory
 | 
						|
     *
 | 
						|
     * @param   string $subDir Optional sub directory to get
 | 
						|
     *
 | 
						|
     * @return  string
 | 
						|
     */
 | 
						|
    public function getApplicationDir($subDir = null)
 | 
						|
    {
 | 
						|
        return $this->getDirWithSubDir($this->appDir, $subDir);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the vendor library directory
 | 
						|
     *
 | 
						|
     * @param   string $subDir Optional sub directory to get
 | 
						|
     *
 | 
						|
     * @return  string
 | 
						|
     */
 | 
						|
    public function getVendorDir($subDir = null)
 | 
						|
    {
 | 
						|
        return $this->getDirWithSubDir($this->vendorDir, $subDir);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the configuration directory
 | 
						|
     *
 | 
						|
     * @param   string $subDir Optional sub directory to get
 | 
						|
     *
 | 
						|
     * @return  string
 | 
						|
     */
 | 
						|
    public function getConfigDir($subDir = null)
 | 
						|
    {
 | 
						|
        return $this->getDirWithSubDir($this->configDir, $subDir);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the Icinga library directory
 | 
						|
     *
 | 
						|
     * @param   string $subDir Optional sub directory to get
 | 
						|
     *
 | 
						|
     * @return  string
 | 
						|
     */
 | 
						|
    public function getLibraryDir($subDir = null)
 | 
						|
    {
 | 
						|
        return $this->getDirWithSubDir($this->libDir, $subDir);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the path to the bootstrapping directory
 | 
						|
     *
 | 
						|
     * This is usually /public for Web and EmbeddedWeb and /bin for the CLI
 | 
						|
     *
 | 
						|
     * @return  string
 | 
						|
     *
 | 
						|
     * @throws  LogicException If the base directory can not be detected
 | 
						|
     */
 | 
						|
    public function getBootstrapDirectory()
 | 
						|
    {
 | 
						|
        $script = $_SERVER['SCRIPT_FILENAME'];
 | 
						|
        $canonical = realpath($script);
 | 
						|
        if ($canonical !== false) {
 | 
						|
            $dir = dirname($canonical);
 | 
						|
        } elseif (substr($script, -14) === '/webrouter.php') {
 | 
						|
            // If Icinga Web 2 is served using PHP's built-in webserver with our webrouter.php script, the $_SERVER
 | 
						|
            // variable SCRIPT_FILENAME is set to DOCUMENT_ROOT/webrouter.php which is not a valid path to
 | 
						|
            // realpath but DOCUMENT_ROOT here still is the bootstrapping directory
 | 
						|
            $dir = dirname($script);
 | 
						|
        } else {
 | 
						|
            throw new LogicException('Can\'t detected base directory');
 | 
						|
        }
 | 
						|
        return $dir;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Start the bootstrap
 | 
						|
     *
 | 
						|
     * @param   string $baseDir     Icinga Web 2 base directory
 | 
						|
     * @param   string $configDir   Path to Icinga Web 2's configuration files
 | 
						|
     *
 | 
						|
     * @return  static
 | 
						|
     */
 | 
						|
    public static function start($baseDir = null, $configDir = null)
 | 
						|
    {
 | 
						|
        $application = new static($baseDir, $configDir);
 | 
						|
        $application->bootstrap();
 | 
						|
        return $application;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Setup Icinga class loader
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    public function setupAutoloader()
 | 
						|
    {
 | 
						|
        require $this->libDir . '/Icinga/Application/ClassLoader.php';
 | 
						|
 | 
						|
        $this->loader = new ClassLoader();
 | 
						|
        $this->loader->registerNamespace('Icinga', $this->libDir. '/Icinga');
 | 
						|
        $this->loader->register();
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Register the Zend Autoloader
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    public function setupZendAutoloader()
 | 
						|
    {
 | 
						|
        require_once 'Zend/Loader/Autoloader.php';
 | 
						|
 | 
						|
        \Zend_Loader_Autoloader::getInstance();
 | 
						|
 | 
						|
        \Zend_Paginator::addScrollingStylePrefixPath(
 | 
						|
            'Icinga_Web_Paginator_ScrollingStyle_', $this->libDir . '/Icinga/Web/Paginator/ScrollingStyle'
 | 
						|
        );
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     * Setup module manager
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected function setupModuleManager()
 | 
						|
    {
 | 
						|
        $this->moduleManager = new ModuleManager(
 | 
						|
            $this,
 | 
						|
            $this->configDir . '/enabledModules',
 | 
						|
            explode(':', $this->config->get('global', 'module_path', $this->baseDir . '/modules'))
 | 
						|
        );
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Load all enabled modules
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected function loadEnabledModules()
 | 
						|
    {
 | 
						|
        try {
 | 
						|
            $this->moduleManager->loadEnabledModules();
 | 
						|
        } catch (NotReadableError $e) {
 | 
						|
            Logger::error(new IcingaException('Cannot load enabled modules. An exception was thrown:', $e));
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Load the setup module if Icinga Web 2 requires setup or the setup token exists
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected function loadSetupModuleIfNecessary()
 | 
						|
    {
 | 
						|
        if (! @file_exists($this->config->resolvePath('authentication.ini'))) {
 | 
						|
            $this->requiresSetup = true;
 | 
						|
            $this->moduleManager->loadModule('setup');
 | 
						|
        } elseif ($this->setupTokenExists()) {
 | 
						|
            // Load setup module but do not require setup
 | 
						|
            $this->moduleManager->loadModule('setup');
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get whether Icinga Web 2 requires setup
 | 
						|
     *
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function requiresSetup()
 | 
						|
    {
 | 
						|
        return $this->requiresSetup;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get whether the setup token exists
 | 
						|
     *
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function setupTokenExists()
 | 
						|
    {
 | 
						|
        return @file_exists($this->config->resolvePath('setup.token'));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Setup default logging
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected function setupLogging()
 | 
						|
    {
 | 
						|
        Logger::create(
 | 
						|
            new ConfigObject(
 | 
						|
                array(
 | 
						|
                    'log' => 'syslog'
 | 
						|
                )
 | 
						|
            )
 | 
						|
        );
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Load Configuration
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected function loadConfig()
 | 
						|
    {
 | 
						|
        Config::$configDir = $this->configDir;
 | 
						|
 | 
						|
        try {
 | 
						|
            $this->config = Config::app();
 | 
						|
        } catch (NotReadableError $e) {
 | 
						|
            Logger::error(new IcingaException('Cannot load application configuration. An exception was thrown:', $e));
 | 
						|
            $this->config = new Config();
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Error handling configuration
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected function setupErrorHandling()
 | 
						|
    {
 | 
						|
        error_reporting(E_ALL | E_STRICT);
 | 
						|
        ini_set('display_startup_errors', 1);
 | 
						|
        ini_set('display_errors', 1);
 | 
						|
        set_error_handler(function ($errno, $errstr, $errfile, $errline) {
 | 
						|
            if (error_reporting() === 0) {
 | 
						|
                // Error was suppressed with the @-operator
 | 
						|
                return false; // Continue with the normal error handler
 | 
						|
            }
 | 
						|
            switch($errno) {
 | 
						|
                case E_NOTICE:
 | 
						|
                case E_WARNING:
 | 
						|
                case E_STRICT:
 | 
						|
                    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
 | 
						|
            }
 | 
						|
            return false; // Continue with the normal error handler
 | 
						|
        });
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set up logger
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected function setupLogger()
 | 
						|
    {
 | 
						|
        if ($this->config->hasSection('logging')) {
 | 
						|
            $loggingConfig = $this->config->getSection('logging');
 | 
						|
 | 
						|
            try {
 | 
						|
                Logger::create($loggingConfig);
 | 
						|
            } catch (ConfigurationError $e) {
 | 
						|
                Logger::getInstance()->registerConfigError($e->getMessage());
 | 
						|
 | 
						|
                try {
 | 
						|
                    Logger::getInstance()->setLevel($loggingConfig->get('level', Logger::ERROR));
 | 
						|
                } catch (ConfigurationError $e) {
 | 
						|
                    Logger::getInstance()->registerConfigError($e->getMessage());
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set up the resource factory
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected function setupResourceFactory()
 | 
						|
    {
 | 
						|
        try {
 | 
						|
            $config = Config::app('resources');
 | 
						|
            ResourceFactory::setConfig($config);
 | 
						|
        } catch (NotReadableError $e) {
 | 
						|
            Logger::error(
 | 
						|
                new IcingaException('Cannot load resource configuration. An exception was thrown:', $e)
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set up the user backend factory
 | 
						|
     *
 | 
						|
     * @return  $this
 | 
						|
     */
 | 
						|
    protected function setupUserBackendFactory()
 | 
						|
    {
 | 
						|
        try {
 | 
						|
            UserBackend::setConfig(Config::app('authentication'));
 | 
						|
        } catch (NotReadableError $e) {
 | 
						|
            Logger::error(
 | 
						|
                new IcingaException('Cannot load user backend configuration. An exception was thrown:', $e)
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Detect the timezone
 | 
						|
     *
 | 
						|
     * @return null|string
 | 
						|
     */
 | 
						|
    protected function detectTimezone()
 | 
						|
    {
 | 
						|
        return null;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set up the timezone
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected final function setupTimezone()
 | 
						|
    {
 | 
						|
        $timezone = $this->detectTimeZone();
 | 
						|
        if ($timezone === null || @date_default_timezone_set($timezone) === false) {
 | 
						|
            $timezone = @date_default_timezone_get();
 | 
						|
            if ($timezone === false) {
 | 
						|
                $timezone = 'UTC';
 | 
						|
                date_default_timezone_set($timezone);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Detect the locale
 | 
						|
     *
 | 
						|
     * @return null|string
 | 
						|
     */
 | 
						|
    protected function detectLocale()
 | 
						|
    {
 | 
						|
        return null;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set up internationalization using gettext
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    protected final function setupInternationalization()
 | 
						|
    {
 | 
						|
        if ($this->hasLocales()) {
 | 
						|
            Translator::registerDomain(Translator::DEFAULT_DOMAIN, $this->getLocaleDir());
 | 
						|
        }
 | 
						|
 | 
						|
        $locale = $this->detectLocale();
 | 
						|
        if ($locale === null) {
 | 
						|
            $locale = Translator::DEFAULT_LOCALE;
 | 
						|
        }
 | 
						|
 | 
						|
        try {
 | 
						|
            Translator::setupLocale($locale);
 | 
						|
        } catch (Exception $error) {
 | 
						|
            Logger::error($error);
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return string Our locale directory
 | 
						|
     */
 | 
						|
    public function getLocaleDir()
 | 
						|
    {
 | 
						|
        return $this->getApplicationDir('locale');
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * return bool Whether Icinga Web has translations
 | 
						|
     */
 | 
						|
    public function hasLocales()
 | 
						|
    {
 | 
						|
        $localedir = $this->getLocaleDir();
 | 
						|
        return file_exists($localedir) && is_dir($localedir);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * List all available locales
 | 
						|
     *
 | 
						|
     * NOTE: Might be a candidate for a static function in Translator
 | 
						|
     *
 | 
						|
     * return array Locale list
 | 
						|
     */
 | 
						|
    public function listLocales()
 | 
						|
    {
 | 
						|
        $locales = array();
 | 
						|
        if (! $this->hasLocales()) {
 | 
						|
            return $locales;
 | 
						|
        }
 | 
						|
        $localedir = $this->getLocaleDir();
 | 
						|
 | 
						|
        $dh = opendir($localedir);
 | 
						|
        while (false !== ($file = readdir($dh))) {
 | 
						|
            $filename = $localedir . DIRECTORY_SEPARATOR . $file;
 | 
						|
            if (preg_match('/^[a-z]{2}_[A-Z]{2}$/', $file) && is_dir($filename)) {
 | 
						|
                $locales[] = $file;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        closedir($dh);
 | 
						|
        sort($locales);
 | 
						|
        return $locales;
 | 
						|
    }
 | 
						|
}
 |