<?php
/**
 * Installation
 *
 * @author christian.k
 */
class Us_installation extends CI_Model
{
    const MODE_INSTALL = 172615907;
    const MODE_UPDATE = 286345884;

    protected $configpath;
    protected $dbpath;
    protected $proceed;
    protected $positive_feedback;

    protected $sysinfo;
    protected $security_upload;

    protected $sys_config;
    protected $sys_db;
    
    protected $new_path;
    protected $new_db_settings;
    protected $new_mode;
    protected $new_license;
    
    protected $portlet_update_key;
    protected $up_inst_mode;
    protected $db_update;

    /**
     * Constructor
     */
    public function  __construct()
    {
        $this->configpath = APPPATHLIVE.'config/config.php'; # To gain access to the config.php
        $this->dbpath = APPPATHLIVE.'config/database.php'; # To gain access to the database.php
        $this->proceed = true;
        $this->positive_feedback = false;
        $this->sys_config = false;
        $this->sys_db = false;

        $this->new_db_settings = false;
        $this->new_path = false;
        $this->new_mode = false;
        $this->new_license = false;
        
        $this->up_inst_mode = false;

        require_once(APPPATHLIVE.'helpers/us_html_helper.php');
        require_once(APPPATHLIVE.'libraries/US_Sysinfo.php');
        $this->sysinfo = new US_Sysinfo();
    }

    /**
     * Check for files not exits
     *
     * @return  string
     */
    public function file_exists_errors()
    {
        if (!$this->proceed) return '';
        $msg = '';
        $msg .= $this->_file_not_exits($this->configpath);
        $msg .= $this->_file_not_exits($this->dbpath);
        return $msg;
    }
    
    /**
     * Check for file not exits
     *
     * @param   string  $filename   File name
     * @return  void
     */
    private function _file_not_exits($filename)
    {
        if (is_readable($filename)) {
            $this->proceed = false;
            return '<code>'.$filename.'</code>';
        }
    }

    /**
     * Check for dirs writeable
     *
     * @return  string
     */
    public function dirs_not_writeable()
    {
        if (!$this->proceed) return '';
        $msg = '';
        $msg .= $this->_dir_not_writeable(dirname($this->configpath));
        $msg .= $this->_dir_not_writeable(WRITEABLEPATH.'applications');
        $msg .= $this->_dir_not_writeable(WRITEABLEPATH.'cache');
        $msg .= $this->_dir_not_writeable(WRITEABLEPATH.'logs');
        $msg .= $this->_dir_not_writeable(WRITEABLEPATH.'temp');
        $msg .= $this->_dir_not_writeable(WRITEABLEPATH.'updates');
        return $msg;
    }

    /**
     * Check for dir writeable
     *
     * @param   string  $path_name   Directory name
     * @return  void
     */
    private function _dir_not_writeable($path_name)
    {
        if (!is_dir($path_name)) {
            $this->proceed = false;
            return '<code>Missing: '.$path_name.'</code>';
        }
        if (!is_writable($path_name)) {
            $this->proceed = false;
            return '<code>'.$path_name.'</code>';
        }
    }

    /**
     * Check for file exits
     *
     * @return  string
     */
    public function file_load()
    {
        if (!$this->proceed) return '';
        $msg = '';
        $msg .= $this->_file_exits($this->configpath);
        $msg .= $this->_file_exits($this->dbpath);

        if (!$this->proceed) return $msg;
        require_once $this->configpath;
        require_once $this->dbpath;
        $this->sys_config = $config;
        $this->sys_db = $db;

        return $msg;
    }

    /**
     * Check for file exits
     *
     * @param   string  $filename   File name
     * @return  void
     */
    private function _file_exits($filename)
    {
        if (!is_readable($filename)) {
            $this->proceed = false;
            return '<code>'.$filename.'</code>';
        }
    }

    /**
     * Process version errors
     *
     * @return string
     */
    public function version_errors()
    {
        if (!$this->proceed) return '';
        $msg = $this->sysinfo->create_version_to_do();
        if (!$this->sysinfo->was_all_ok()) {
            $this->proceed = false;
            return $msg;
        }
        if($this->positive_feedback) return $msg; else return '';
    }

    /**
     * Process apache errors
     *
     * @return string
     */
    public function apache_errors()
    {
        if (!$this->proceed) return '';
        $msg = $msg = $this->sysinfo->create_apache_to_do();
        if (!$this->sysinfo->was_all_ok()) {
            $this->proceed = false;
            return $msg;
        }
        if($this->positive_feedback) return $msg; else return '';
    }

    /**
     * Process PHP errors
     *
     * @return string
     */
    public function php_errors()
    {
        if (!$this->proceed) return '';
        $msg = $msg = $this->sysinfo->create_php_to_do();
        if (!$this->sysinfo->was_all_ok()) {
            $this->proceed = false;
            return $msg;
        }
        if($this->positive_feedback) return $msg; else return '';
    }

    /**
     * Process DB errors
     *
     * @return string
     */
    public function db_errors()
    {
        if (!$this->proceed) return '';
        
        $msg = $msg = $this->sysinfo->create_mysql_to_do($this->sys_db);
        if (!$this->sysinfo->was_all_ok()) {
            $this->proceed = false;
            return $msg;
        }
        if($this->positive_feedback) return $msg; else return '';
    }

    /**
     * Process directoy errors
     *
     * @return string
     */
    public function dir_errors()
    {
        if (!$this->proceed) return '';

        $msg = $msg = $this->sysinfo->create_dir_do($this->sys_config);
        if (!$this->sysinfo->was_all_ok()) {
            $this->proceed = false;
            return $msg;
        }
        if($this->positive_feedback) return $msg; else return '';
    }

    /**
     * Process the path and stores the information if they are working
     *
     * @param   string  $path   Path
     * @return  string
     */
    public function process_datapath($path)
    {
        //Helper
        require_once(APPPATHLIVE.'helpers/env_helper.php');

        $path = trim($path);
        if (is_file($path)) {
            //The user entered a path to the usystem.ini
            $path_dir = dirname($path);
            $path_full = realpath($path);
        } else {
            //The user entered a folder path
            $path_dir = $path;
            $path_full = realpath($path).'/usystem.ini';
        }
        
        if (strtoupper(substr(PHP_OS, 0, 3))!=='WIN') {
            //Linux or Mac mode
            if (preg_match('/^[a-zA-Z]:[\/\\\\].+/', $path_dir)) {
                $this->proceed = false;
                return 'Data path on '.PHP_OS.' cannot start with a Windows drive letter: '.$path_dir;
            }
        }
        
        #echo $path_dir.': '.is_really_writable($path_dir); die();

        $msg = $this->sysinfo->create_dir_check_write($path_dir);
        if (!$this->sysinfo->was_all_ok()) {
            $this->proceed = false;
            return $msg;
        }
        
        $this->new_path = array(
            'dir' => $path_dir,
            'full' => $path_full
        );

        //Do we have a valid full path = Update mode
        if (empty($path_full) || !is_file($path_full)) {
            //INSTALLATION mode
            
            //Check dir empty
            $path_map = directory_map($path_dir, 1, false); //Ignore hidden = system files
            foreach ($path_map as $path_key => $path_item) {
                if (is_array($path_item)) {
                    $this->proceed = false;
                    return 'Data path is not empty. Holds folder: "'.$path_key.'"';
                }
                if ($path_item!='.' && $path_item!='..') {
                    $this->proceed = false;
                    return 'Data path is not empty. Holds file: "'.$path_item.'"';
                }
            }
            
            return '';
        }
        
        $msg = $this->sysinfo->create_dir_check_read($path_full);
        if (!$this->sysinfo->was_all_ok()) {
            $this->proceed = false;
            return $msg;
        }

        //Read
        $usystem_ini = @parse_ini_file($path_full, true);
        #var_dump($usystem_ini); die();
        if (!is_array($usystem_ini)) {
            $this->proceed = false;
            return 'Cannot read ini file '.$path_full;
        }

        //Validate DB-Type
        if (!key_exists('Database-Type', $usystem_ini)) {
            $this->proceed = false;
            return 'Cannot read ini file '.$path_full.' - Database-Type missing';
        }
        if (!key_exists('DB-Type', $usystem_ini['Database-Type'])) {
            $this->proceed = false;
            return 'Cannot read ini file '.$path_full.' - Database-Type > DB-Type missing';
        }

        //Check for type MySQL
        $usystem_ini_dbtype = $usystem_ini['Database-Type']['DB-Type'];
        if ($usystem_ini_dbtype!=='MySQL') {
            $this->proceed = false;
            return 'The database type of your existing installation is not MySQL. <br />'.$this->sysinfo->create_howto_migrate();
        }

        //Validate MySQL Server
        if (!key_exists('MySQL', $usystem_ini)) {
            $this->proceed = false;
            return 'Cannot read ini file '.$path_full.' - MySQL missing';
        }
        if (!key_exists('Server', $usystem_ini['MySQL'])) {
            $this->proceed = false;
            return 'Cannot read ini file '.$path_full.' - MySQL > Server missing';
        }
        if (!key_exists('Port', $usystem_ini['MySQL'])) {
            $usystem_ini['MySQL']['Port'] = 3306;
        }
        if (!key_exists('Database', $usystem_ini['MySQL'])) {
            $this->proceed = false;
            return 'Cannot read ini file '.$path_full.' - MySQL > Database missing';
        }

        //Test the mysql settings
        $ok = $this->process_database_settings(
                $usystem_ini['MySQL']['Server'],
                null,//'####',
                null,//'####',
                $usystem_ini['MySQL']['Port'],
                $usystem_ini['MySQL']['Database'],
                true,
                false
        );

        //Keep the settings
        if ($this->proceed) {
            $this->new_mode = self::MODE_UPDATE;
        }

        return $ok;
    }

    /**
     * Process the mysql settings and stores the information if they are working
     *
     * @param   string  $hostname           Server
     * @param   string  $username           Username (Might be '' or '####' as well)
     * @param   string  $password           Password (Might be '' or '####' as well)
     * @param   integer $port               Server port (Might be '')
     * @param   string  $database           Database name
     * @param   boolean $existing           Test for existing tables and database (true) or non (false)
     * @param   string  $check_language     Optional Language for check against existing
     * @return  string
     */
    public function process_database_settings($hostname, $username, $password, $port, $database, $existing, $try_connect=true, $check_language=null)
    {
        if (!is_numeric($port)) {
            $port = 3306;
        }
        
        //Try to connect to the MySQL server
        $db_conf = array(
            'hostname'          => $hostname,
            'username'          => $username,
            'password'          => $password,
            'port'              => $port,
            'database'          => $database,
            'existing'          => $existing,
            'check_language'    => $existing ? $check_language : null,
        );
        $db = array(
            'default' => $db_conf,
            'temp' => $db_conf,
        );

        
        //Are the settings working?
        if ($try_connect) {
            $msg = $this->sysinfo->create_mysql_to_do($db, false);
            if (!$this->sysinfo->was_all_ok()) {
                $this->proceed = false;
                return $msg;
            }
        }

        //Keep the settings
        $this->new_db_settings = $db_conf;
        return '';
    }

    /**
     * Test the license key
     *
     * @param   string  $license    License key
     * @return  string
     */
    public function test_license($license)
    {
        if (!$this->new_db_settings) {
            $this->proceed = false;
            return 'Cannot proceed without MySQL settings';
        }

        require_once(APPPATHLIVE.'models/security_upload_model.php');
        $this->security_upload = new Security_upload_model();
        
        $ok = $this->security_upload->valid_test($license);
        if ($ok!==true) {
            $this->proceed = false;
            return $ok;
        }
        
        //Keep the settings
        $this->new_license = $license;
        $this->new_mode = self::MODE_INSTALL;

        return '';
    }

    /**
     * Run the setup
     *
     * @param   string  $create_db_username     The DB user to create
     * @param   string  $language               Language
     * @param   string  $datelocale             Date locale
     * @param   string  $numberlocale           Number locale
     * @return  string
     */
    public function run_setup($create_db_username, $language, $datelocale, $numberlocale)
    {
        //Helper
        require_once(APPPATHLIVE.'helpers/env_helper.php');

        if (!$this->proceed) {
            return 'Cannot proceed setup while there are still errors';
        }
        
        if (!$this->new_mode) {
            $this->proceed = false;
            return 'Cannot proceed while there are variables missing (mode)';
        }
        
        if ($this->new_mode==self::MODE_INSTALL) {
            //Validate installation
            if (!$this->new_db_settings || !$this->new_license || !$this->new_path) {
                $this->proceed = false;
                return 'Cannot proceed while there are variables missing (db, license, path)';
            }
        } else {
            //Validate update
            if (!$this->new_db_settings || !$this->new_path) {
                $this->proceed = false;
                return 'Cannot proceed while there are variables missing (db, path)';
            }
        }
        
        //Prevent from memory / timeout errors
        ignore_user_abort(true);
        @ini_set('memory_limit', '200M');
        @set_time_limit(36000);

        $serial = null;
        $ok = $this->_init_database($create_db_username, $serial);
        if (!$this->proceed) {
            return $ok;
        }
        
        if ($this->new_mode==self::MODE_INSTALL) {
            //Setup datapath for installation
            $ok = $this->_create_datapath();
            if (!$this->proceed) {
                return $ok;
            }
        }
        
        $ok = $this->_write_config($language, $datelocale, $numberlocale);
        if (!$this->proceed) {
            return $ok;
        }

        $suffix = get_max_dotenv_suffix() + 1;
        $p = null;
        $ok = $this->_write_dabase_config($suffix, $p);
        if (!$this->proceed) {
            return $ok;
        }

        $ok = $this->_write_dotenv_config($suffix, $p);
        if (!$this->proceed) {
            return $ok;
        }

        $ok = $this->_write_portlet_update_file($serial);
        if (!$this->proceed) {
            return $ok;
        }

        return 'Successful / Erfolgreich';
    }
    
    /**
     * Setup the db and the login
     *
     * @return  string 
     */
    public function setup_db_login()
    {
        require_once(APPPATHLIVE.'libraries/US_Db_update.php');
        $this->db_update = new US_Db_update();
        
        $ok = $this->db_update->setup_db_login($this->new_db_settings);
        if ($ok!==true) {
            $this->proceed = false;
            return $ok;
        }
    }

    /**
     * Init the database
     *
     * @param   string      $u          The DB user to create
     * @param   string      $serial     Reference Serial in use
     * @return  string
     */
    protected function _init_database($u, &$serial=null)
    {
        require_once(APPPATHLIVE.'libraries/US_Db_update.php');
        require_once(APPPATHLIVE.'models/security_upload_model.php');
        $this->db_update = new US_Db_update();
        $this->security_upload = new Security_upload_model();
        
        #if (!$this->new_db_settings['existing']) {
            //Setup the db and the login
            $p = null;
            $ok = $this->db_update->setup_db_login($this->new_db_settings, $u, $p);
            if ($ok!==true) {
                $this->proceed = false;
                return $ok;
            }

            //Drop all views, functions, procedures and triggers from DB using mysql root user
            $ok = $this->db_update->cleanup_all_except_tables($this->new_db_settings);
            if ($ok!==true) {
                $this->proceed = false;
                return $ok;
            }            
            
            //Set db settings, to untermStrich user - For MySQL 8.0.16+
            $ok = $this->process_database_settings(
                $this->new_db_settings['hostname'],
                $u,
                $p,
                $this->new_db_settings['port'],
                $this->new_db_settings['database'],
                true
            );
            if (!$this->proceed) {
                return $ok;
            }
        #}

        //Lic test
        if ($this->new_mode == self::MODE_INSTALL) {
            $license = $this->new_license;
        } else {
            $result_info = $this->db_update->run_query($this->new_db_settings, 'SELECT instinfo FROM installation');
            if ($result_info===false) {
                $this->proceed = false;
                return 'Failed to get license from database 31';
            }
            if (!isset($result_info->instinfo)) {
                $this->proceed = false;
                return 'Failed to get license details from database 32';
            }
            $license = trim($result_info->instinfo);
        }
        
        //Decode lic
        $ok = $this->security_upload->valid_test($license, false, $this->db_update, $this->new_db_settings, $dec);
        if ($ok!==true) {
            $this->proceed = false;
            $this->proceed = false;
            return $ok.' - 33';
        }
        if (!isset($dec[1])) {
            $this->proceed = false;
            return 'Invalid serial 34';
        }
        
        $us_version = (US_MAIN_VERSION==='15.0.5.52897') ? '13.0.0.1' : US_MAIN_VERSION;
        $ok = $this->db_update->testit($us_version, $dec[1]);
        if ($ok!==true) {
            $this->proceed = false;
            $this->proceed = false;
            return $ok.' Serial: '.$dec[1];
        }
        $serial = $dec[1];
        
        if ($this->new_mode == self::MODE_INSTALL) {
            //Install basic
            $ok = $this->db_update->update(APPPATH.'data/install_current.sql', $this->new_db_settings);
            if ($ok!==true) {
                $this->proceed = false;
                return $ok;
            }

            //Install data
            $ok = $this->db_update->update(APPPATH.'data/data_current.sql', $this->new_db_settings);
            if ($ok!==true) {
                $this->proceed = false;
                return $ok;
            }
        }
        
        //Update to web
        $ok = $this->db_update->update(APPPATH.'data/from_current.sql', $this->new_db_settings);
        if ($ok!==true) {
            $this->proceed = false;
            return $ok;
        }
        
        if ($this->new_mode == self::MODE_INSTALL) {
            //Add license
            $ok = $this->_add_license($this->db_update);
            if (!$this->proceed) {
                return $ok;
            }
        }
        
        return '';
    }
    
    /**
     * Add the license key
     *
     * @return  string
     */
    protected function _add_license()
    {
        if ($this->new_mode != self::MODE_INSTALL) {
            $this->proceed = false;
            return 'Can only add license on new installation';
        }
        
        require_once(APPPATHLIVE.'models/security_upload_model.php');
        $this->security_upload = new Security_upload_model();
        
        $ok = $this->security_upload->upload($this->new_license, $this->db_update, $this->new_db_settings);
        if ($ok!==true) {
            $this->proceed = false;
            return $ok;
        }
        
        return '';
    }
    
    /**
     * Create the datapath for install
     * 
     * @return  string
     */
    protected function _create_datapath()
    {
        //Get data path
        $data_path = $this->new_path['dir'];
        $last = substr($data_path, -1);
        if ($last!='/' && $last!='\\') {
            $data_path .= '/';
        }
        
        //Get config file name
        $full_path = $this->new_path['full'];
        
        try {
            //Create dirs
            $this->_create_dir($data_path.'doku');
            $this->_create_dir($data_path.'postaus');
            $this->_create_dir($data_path.'postein');
            $this->_create_dir($data_path.'rechnungen');
            $this->_create_dir($data_path.'reports');
            $this->_create_dir($data_path.'reports/CustDefined');
            $this->_create_dir($data_path.'scan');
            $this->_create_dir($data_path.'vorlage');
        } catch (Exception $exc) {
            $this->proceed = false;
            return 'Cannot add directories. Error:'.$exc->getMessage();
        }
        
        try {
            //Create Ismasdb.udt
            file_put_contents($data_path.'Ismasdb.udt', 'master-database');
            @chmod($data_path.'Ismasdb.udt', FILE_WRITE_MODE);

            //Create usystem.ini
            $usystem_ini = '[Database-Type]'."\r\n";
            $usystem_ini .= 'DB-Type=MySQL'."\r\n";
            $usystem_ini .= '[MySQL]'."\r\n";
            $usystem_ini .= 'Server='.$this->new_db_settings['hostname']."\r\n";
            $port = $this->new_db_settings['port'];
            if ($port!=3306) {
                $usystem_ini .= 'Port='.$port."\r\n";
            }
            $usystem_ini .= 'Database='.$this->new_db_settings['database']."\r\n";
            $usystem_ini .= '[System]'."\r\n";
            $usystem_ini .= 'BaseName='.$this->new_db_settings['database']."\r\n";
            file_put_contents($data_path.'usystem.ini', $usystem_ini);
            @chmod($data_path.'usystem.ini', FILE_WRITE_MODE);
        } catch (Exception $exc) {
            $this->proceed = false;
            return 'Cannot create files. Error:'.$exc->getMessage();
        }
        
        return '';
    }
    
    /**
     * Create a directory
     *
     * @param   string  $dir_path   Path
     * @return  void
     */
    private function _create_dir($dir_path)
    {
        mkdir($dir_path);
        @chmod($dir_path, DIR_WRITE_MODE);
    }
    
    /**
     * Write portlet update key file
     * 
     * @param   string      $serial         Serial in use
     * @return  string
     */
    private function _write_portlet_update_file($serial)
    {
        $this->portlet_update_key = $this->security->get_token();
        
        //Write
        $ok = file_put_contents(WRITEABLEPATH.'applications/update.php', $this->portlet_update_key.';'.$serial);
        if ($ok===false) {
            $this->proceed = false;
            return 'Cannot write '.$this->configpath;
        }
        
        
        return '';
    }

    /**
     * Write database.php
     *
     * @return  string
     */
    private function _write_dabase_config($suffix, &$p)
    {
        $config_from_name = APPPATHLIVE.'config/database-default.php'; # To gain access to the database-default.php
        $config_data = file_get_contents($config_from_name);
        if ($config_data===false) {
            $this->proceed = false;
            return 'Cannot read '.$config_from_name;
        }
        
        if (!extension_loaded('mysqli')) {
            $msg = 'mysqli extension missing';
            header('Location: install.php/install/'.rawurlencode($msg));
            die($msg);
        }
        
        //Set values
        $p = bin2hex(openssl_random_pseudo_bytes(14));
        $config_data = str_replace('##hostname##', $this->new_db_settings['hostname'], $config_data);
        $config_data = str_replace('##username##', "##env:USER_$suffix"."##", $config_data);//'##env:X2_USER##'
        $config_data = str_replace('##password##', "##env:PASS_$suffix".":$p##", $config_data);//'##env:X2_PASS:A_nice_password##'
        $config_data = str_replace('##database##', $this->new_db_settings['database'], $config_data);
        $config_data = str_replace('##dbdriver##', 'mysqli', $config_data);
        $config_data = str_replace('##port##', $this->new_db_settings['port'], $config_data);
        
        //Write
        $ok = file_put_contents($this->dbpath, $config_data);
        if ($ok===false) {
            $this->proceed = false;
            return 'Cannot write '.$this->configpath;
        }
        return '';
    }

    /**
     * Write .env
     *
     * @return  string
     */
    private function _write_dotenv_config($suffix, $p)
    {
        //Helper
        require_once(APPPATHLIVE.'helpers/env_helper.php');

        $key = 'USER_'.$suffix;
        $value = $this->new_db_settings['username'];
        $stat = write_to_dotenv($key, $value);
        if ($stat !== false) {
            $this->proceed = false;
            return 'Cannot write username to .env file.';
        }

        $key = 'PASS_'.$suffix;
        $value = $this->new_db_settings['password'];
        $stat = write_to_dotenv($key, $value, $p);
        if ($stat !== false) {
            $this->proceed = false;
            return 'Cannot write password to .env file.';
        }      
        
        return '';
    }

    /**
     * Create config.php
     *
     * @param  string   $language       Language
     * @param  string   $datelocale     Date locale
     * @param  string   $numberlocale   Number locale
     * @return  string
     */
    private function _write_config($language, $datelocale, $numberlocale)
    {
        //Helper
        require_once(APPPATHLIVE.'helpers/write_config_helper.php');

        //Prepare values
        $data_path = str_replace('\\', '/', $this->new_path['dir']);
        if (!substr($data_path, -1)!='/') {
            $data_path .= '/';
        }

        //Write config
        $specific = array();
        if ($this->new_mode==self::MODE_INSTALL) {
            $specific['us_write_config'] = '"init"';
        } else {
            $specific['us_write_config'] = '"write"';
        }
        
        $ok = write_config_file($data_path, $language, $datelocale, $numberlocale, $specific);
        if ($ok!==true) {
            $this->proceed = false;
            return $ok;
        }
        return '';
    }

    /**
     * Get path to PHP ini file
     *
     * @return  string
     */
    public function ini_file()
    {
        return $this->sysinfo->ini_file();
    }

    /**
     * Set positive feedback
     *
     * @param   boolean $to     Active?
     * @return  void
     */
    public function activate_positive_feedback($to)
    {
        $this->positive_feedback = $to;
    }

    /**
     * Proceed
     *
     * @return  boolean
     */
    public function get_proceed($reset=false)
    {
        $reply = $this->proceed;
        if ($reset) {
            $this->sysinfo->was_all_ok(true);
            $this->proceed = true;

            $this->new_db_settings = false;
            $this->new_path = false;
            $this->new_mode = false;
            $this->new_license = false;
        }
        return $reply;
    }

    /**
     * Get new database settings
     *
     * @return  mixed
     */
    public function get_new_db_settings()
    {
        return $this->new_db_settings;
    }
    
    /**
     * Try to find the server name
     *
     * @return  mixed   Either a string or false
     */
    public function get_server_ip()
    {
        //Try to get from SERVER_ADDR
        try {
            if (isset($_SERVER['SERVER_ADDR'])) {
                $server_name = $_SERVER['SERVER_ADDR'];
                if ($server_name!=='127.0.0.1' && $server_name!=='localhost' ) {
                    $server_name = (!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : $server_name;
                    
                    //Do not like hostname - try to get IP
                    $hosts = gethostbynamel($server_name);
                    if (is_array($hosts)) {
                        if (count($hosts)>1) {
                            foreach ($hosts as $host) {
                                if ($host!=='127.0.0.1') {
                                    return $host;
                                }
                            }
                        } elseif (count($hosts)==1) {
                            return $hosts[0];
                        }
                    }
                    
                    //Nothing found - Take hostname
                    return $server_name;
                }
            }
        } catch (Exception $exc) {
        }
        
        //Try to get via gethostbynamel (Returns IP)
        try {
            $hosts = gethostbynamel('localhost');
            if (is_array($hosts)) {
                foreach ($hosts as $host) {
                    if ($host!=='127.0.0.1') {
                        return $host;
                    }
                }
            }
        } catch (Exception $exc) {
        }
        
        //Try to get via gethostname
        try {
            if (function_exists('gethostname')) {
                $hostname = gethostname();
                if ($hostname!=='127.0.0.1' && $hostname!=='localhost') {
                    //Do not like hostname - try to get IP
                    $hosts = gethostbynamel($hostname);
                    if (is_array($hosts)) {
                        foreach ($hosts as $host) {
                            if ($host!=='127.0.0.1') {
                                return $host;
                            }
                        }
                    }
                    
                    //Nothing found - Take hostname
                    return $hostname;
                }
            }
        } catch (Exception $exc) {
        }
        
        //Try to get via php_uname('n')
        try {
            if (function_exists('php_uname')) {
                $hostname = php_uname('n');
                if ($hostname!=='127.0.0.1' && $hostname!=='localhost') {
                    //Do not like hostname - try to get IP
                    $hosts = gethostbynamel($hostname);
                    if (is_array($hosts)) {
                        foreach ($hosts as $host) {
                            if ($host!=='127.0.0.1') {
                                return $host;
                            }
                        }
                    }
                    
                    //Nothing found - Take hostname
                    return $hostname;
                }
            }
        } catch (Exception $exc) {
        }
        
        return false;
    }
    
    /**
     * Get portlet_update_key
     * 
     * @return string
     */
    public function get_portlet_update_key()
    {
        return $this->portlet_update_key;
    }

}
