piotrpolak/pepiscms

View on GitHub
pepiscms/application/models/Siteconfig_model.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

/**
 * PepisCMS
 *
 * Simple content management system
 *
 * @package             PepisCMS
 * @author              Piotr Polak
 * @copyright           Copyright (c) 2007-2018, Piotr Polak
 * @license             See license.txt
 * @link                http://www.polak.ro/
 */

defined('BASEPATH') or exit('No direct script access allowed');

/**
 * Site config model
 *
 * @since 0.1.5
 */
class Siteconfig_model extends Generic_model
{
    const MODULE_FIELD_NAME = 'module';
    const IS_BOOLEAN_FIELD_NAME = 'is_boolean';
    const NAME_FIELD_NAME = 'name';
    const UPDATED_DATETIME_FIELD_NAME = 'updated_datetime';
    const CREATED_DATETIME_FIELD_NAME = 'created_datetime';
    const VALUE_FIELD_NAME = 'value';
    const IS_SERIALIZED_FIELD_NAME = 'is_serialized';

    private $cache_ttl;
    private $cache_collection = 'siteconfig';
    private $cache_variable_name = 'all_pairs';


    public function __construct()
    {
        parent::__construct();
        $this->setTable('cms_siteconfig');
        $this->setIdFieldName('id');
        $this->enableJournaling();

        $this->cache_ttl = 600;
        $this->cache_collection = 'siteconfig';
        $this->cache_variable_name = 'all_pairs';

        // Required by saveById method
        $this->setAcceptedPostFields(array(
                self::MODULE_FIELD_NAME,
                self::IS_BOOLEAN_FIELD_NAME,
                self::NAME_FIELD_NAME,
                self::UPDATED_DATETIME_FIELD_NAME,
                self::CREATED_DATETIME_FIELD_NAME,
                self::VALUE_FIELD_NAME,
                self::IS_SERIALIZED_FIELD_NAME
            )
        );

        // Clone database to avoid query clash
        $this->setDatabase('default');

        $this->load->library('Cachedobjectmanager');
    }

    /**
     * Saves by id, $data must be an associative array
     *
     * @param array $data
     * @return bool
     * @local
     * @throws Exception
     */
    public function saveAllConfigurationVariables($data)
    {
        $known_config_data = (array)$this->getAllConfigurationVariables();

        $data = array_merge($known_config_data, $data);

        if (isset($data['cms_customization_logo_predefined']) && !empty($data['cms_customization_logo_predefined'])) {
            $customization_logo_path = APPPATH . '/../theme/img/customization_icons/' . $data['cms_customization_logo_predefined'];

            if (file_exists($customization_logo_path) || is_file($customization_logo_path)) {
                $customization_logo_path_new_name = 'customization_' . time() . '.png';

                $customization_logo_path_new_location = INSTALLATIONPATH . $this->config->item('theme_path') . $customization_logo_path_new_name;

                if (@copy($customization_logo_path, $customization_logo_path_new_location)) {
                    $data['cms_customization_logo'] = $customization_logo_path_new_name;
                } else {
                    throw new \Exception('Unable to copy predefined logo to ' . $customization_logo_path_new_location);
                }
            }
        } else {
            unset($data['cms_customization_logo_predefined']);
        }

        if (!isset($data['cms_customization_logo']) && $data['cms_customization_logo']) {
            $data['cms_customization_logo_predefined'] = null;
        }

        foreach ($data as $key => $value) {
            if (isset($known_config_data[$key]) && $this->is_equal($known_config_data[$key], $value)) {
                continue;
            }

            $this->saveConfigByName($key, $value);
        }

        return true;
    }

    /**
     * @return object
     */
    public function getAllConfigurationVariables()
    {
        @include(APPPATH . 'config/_pepiscms.php');
        @include(APPPATH . 'config/debug.php');
        @include(APPPATH . 'config/email.php');
        @include(INSTALLATIONPATH . 'application/config/_pepiscms.php');
        @include(INSTALLATIONPATH . 'application/config/debug.php');
        @include(INSTALLATIONPATH . 'application/config/email.php');

        if (isset($config['cms_customization_logo'])) {
            $config['cms_customization_logo'] = str_replace($this->config->item('theme_path'), '', $config['cms_customization_logo']);
        }

        $all = $this->getPairsForAll();

        $config = array_merge($config, $all);

        return (object)$config;
    }

    /**
     * Returns a raw entry by name.
     *
     * @param $name
     * @return mixed
     */
    public function getByName($name)
    {
        return $this->db->select('*')->from($this->getTable())->where('name', $name)->get()->row();
    }

    /**
     * Returns config pairs for all all entries.
     *
     * @return array
     */
    public function getPairsForAll()
    {
        $output = array();
        $result = $this->getAll();
        foreach ($result as $line) {
            $output[$line->name] = $this->toValue($line);
        }

        return $output;
    }

    /**
     * Returns config pairs for all all entries.
     *
     * @return array
     */
    public function getPairsForModule($module_name)
    {
        $output = array();
        $result = $this->getAll(array('module' => $module_name));
        foreach ($result as $line) {
            $output[$line->name] = $this->toValue($line);
        }

        return $output;
    }

    /**
     * Returns config value. The method is cached for extra performance.
     *
     * @param $name
     * @return mixed|null
     */
    public function getValueByNameCached($name)
    {
        $output = $this->cachedobjectmanager->get($this->cache_variable_name, $this->cache_collection, $this->cache_ttl,
            function () {
                // This protection is required for cases when installer is run to clean up database
                if (php_sapi_name() == 'cli') {
                    if (!$this->db->table_exists($this->getTable())) {
                        return null;
                    }
                }

                return $this->getPairsForAll();
            }
        );

        if (isset($output[$name])) {
            return $output[$name];
        }

        return null;
    }

    /**
     * Saves config entry by name.
     *
     * @param $name
     * @param $value
     * @param null $module
     * @return bool
     */
    public function saveConfigByName($name, $value, $module = null)
    {
        $entry = $this->getByName($name);

        $id = false;
        $updated_datetime = utc_timestamp();
        if ($entry) {
            $id = $entry->id;
        } else {
            $created_datetime = $updated_datetime;
        }

        $is_boolean = is_bool($value);

        if ($is_boolean) {
            $value_mapped = $value ? 'true' : 'false';
        } else {
            $value_mapped = $value;
        }

        $is_serialized = false;
        if (is_array($value) || is_object($value)) {
            $is_serialized = true;
            $value_mapped = json_encode($value);
        }

        if ($entry && $entry->value == $value_mapped) {
            return true;
        }

        $data = array(
            self::MODULE_FIELD_NAME => $module,
            self::IS_BOOLEAN_FIELD_NAME => $is_boolean,
            self::NAME_FIELD_NAME => $name,
            self::UPDATED_DATETIME_FIELD_NAME => $updated_datetime,
            self::VALUE_FIELD_NAME => $value_mapped,
            self::IS_SERIALIZED_FIELD_NAME => $is_serialized,
        );

        if (isset($created_datetime)) {
            $data[self::CREATED_DATETIME_FIELD_NAME] = $created_datetime;
        }

        return $this->saveById($id, $data);
    }

    /**
     * @inheritdoc
     */
    public function saveById($id, $data)
    {
        $this->load->library('Cachedobjectmanager');
        $this->cachedobjectmanager->cleanup($this->cache_collection);

        return parent::saveById($id, $data);
    }

    /**
     * @inheritdoc
     */
    public function deleteById($id)
    {
        $this->load->library('Cachedobjectmanager');
        $this->cachedobjectmanager->cleanup($this->cache_collection);

        return parent::deleteById($id);
    }

    /**
     * Returns the list of available themes
     *
     * @return array
     */
    public function getAvailableThemes()
    {
        $theme_path = $this->config->item('theme_path');
        $dir = opendir($theme_path);

        $themes = array();

        while ($file = readdir($dir)) {
            if ($file[0] == '.') {
                continue;
            }

            if (is_dir($theme_path . $file)) {
                $themes[$file] = $file;
            }
        }
        closedir($dir);

        return $themes;
    }

    /**
     * Returns a list of customization icons
     *
     * @return array
     */
    public function getPredefinedIconsNames()
    {
        $output = array();
        $customization_icons = glob(APPPATH . '/../theme/img/customization_icons/*.png');

        foreach ($customization_icons as $customization_icon) {
            $customization_icon = basename($customization_icon);
            $output[$customization_icon] = $customization_icon;
        }

        return $output;
    }

    /**
     * Returns a list of available timezone
     *
     * @return array
     */
    public function getAvailableTimezones()
    {
        $tz = array(
            'Europe/Amsterdam',
            'Europe/Andorra',
            'Europe/Athens',
            'Europe/Belfast',
            'Europe/Belgrade',
            'Europe/Berlin',
            'Europe/Bratislava',
            'Europe/Brussels',
            'Europe/Bucharest',
            'Europe/Budapest',
            'Europe/Chisinau',
            'Europe/Copenhagen',
            'Europe/Dublin',
            'Europe/Gibraltar',
            'Europe/Guernsey',
            'Europe/Helsinki',
            'Europe/Isle_of_Man',
            'Europe/Istanbul',
            'Europe/Jersey',
            'Europe/Kaliningrad',
            'Europe/Kiev',
            'Europe/Lisbon',
            'Europe/Ljubljana',
            'Europe/London',
            'Europe/Luxembourg',
            'Europe/Madrid',
            'Europe/Malta',
            'Europe/Mariehamn',
            'Europe/Minsk',
            'Europe/Monaco',
            'Europe/Moscow',
            'Europe/Nicosia',
            'Europe/Oslo',
            'Europe/Paris',
            'Europe/Podgorica',
            'Europe/Prague',
            'Europe/Riga',
            'Europe/Rome',
            'Europe/Samara',
            'Europe/San_Marino',
            'Europe/Sarajevo',
            'Europe/Simferopol',
            'Europe/Skopje',
            'Europe/Sofia',
            'Europe/Stockholm',
            'Europe/Tallinn',
            'Europe/Tirane',
            'Europe/Tiraspol',
            'Europe/Uzhgorod',
            'Europe/Vaduz',
            'Europe/Vatican',
            'Europe/Vienna',
            'Europe/Vilnius',
            'Europe/Volgograd',
            'Europe/Warsaw',
            'Europe/Zagreb',
            'Europe/Zaporozhye',
            'Europe/Zurich');

        $timezones = array();
        foreach ($tz as $k) {
            $timezones[$k] = $k;
        }

        return $timezones;
    }

    /**
     * Returns a list of available admin languages
     *
     * @return array
     */
    public function getAvailableAdminLanguages()
    {
        $lng = $this->config->item('enabled_languages');
        $languages = array();
        foreach ($lng as $k) {
            $languages[$k] = ucfirst($k);
        }

        return $languages;
    }

    /**
     * Returns default admin language
     *
     * @return string
     */
    public function getDefaultAdminLanguage()
    {
        $obj = $this->getByName('language');
        if ($obj) {
            return $obj->value;
        }

        include(INSTALLATIONPATH . 'application/config/_pepiscms.php');

        return $config['language'];
    }

    /**
     * Does configuration test and tells whenever it has errors
     *
     * @return bool
     */
    public function hasConfigurationAnyErrors()
    {
        $errors = $this->makeConfigurationTestsAngGetErrors();
        foreach ($errors as $error) {
            if ($error) {
                return true;
            }
        }
        return false;
    }

    /**
     * Does configuration tests and returns an array of errors
     *
     * @return array
     */
    public function makeConfigurationTestsAngGetErrors()
    {
        $cache_path = $this->config->item('cache_path');
        $cache_path = ($cache_path === '') ? 'application/cache/' : $cache_path;
        if ($cache_path[0] !== '/') {
            $cache_path = INSTALLATIONPATH . $cache_path;
        }

        $logs_path = INSTALLATIONPATH . 'application/logs/';

        $configuration_tests = array();
        $configuration_tests['error_php_reporting_enabled'] = ENVIRONMENT !== 'production' && PEPISCMS_PRODUCTION_RELEASE;
        $configuration_tests['error_development_release'] = !PEPISCMS_PRODUCTION_RELEASE;
        $configuration_tests['error_wrong_uri_protocol'] = $this->config->item('uri_protocol') != 'QUERY_STRING';
        $configuration_tests['error_cache_not_writeable'] = false;
        $configuration_tests['error_logs_not_writeable'] = false;

        // Extended cache test
        if (!is_writeable($cache_path)) {
            $configuration_tests['error_cache_not_writeable'] = true;
        } else {
            $tmp_cache_path = $cache_path . '/_test_' . rand(9999, 10000) . '/';
            if (!@mkdir($tmp_cache_path)) {
                $configuration_tests['error_cache_not_writeable'] = true;
            } else {
                if (!@rmdir($tmp_cache_path)) {
                    $configuration_tests['error_cache_not_writeable'] = true;
                }
            }
        }

        // Extended logs test
        if (!is_writeable($logs_path)) {
            $configuration_tests['error_logs_not_writeable'] = true;
        } else {
            $tmp_logs_path = $logs_path . '/_test_' . rand(9999, 10000) . '.php';
            if (!touch($tmp_logs_path)) {
                $configuration_tests['error_logs_not_writeable'] = true;
            } else {
                if (!unlink($tmp_logs_path)) {
                    $configuration_tests['error_logs_not_writeable'] = true;
                }
            }
        }


        $configuration_tests['error_wrong_file_owner'] = false;
        if (function_exists('posix_getpwuid')) {
            $owner = posix_getpwuid(fileowner(INSTALLATIONPATH));
            $whoaim = exec('whoami');
            $configuration_tests['error_wrong_file_owner'] = ($whoaim != $owner['name'] && $whoaim != $owner['uid']);
        }

        return $configuration_tests;
    }

    /**
     * Returns an array containing the names of failed tests
     *
     * @return array
     */
    public function makeConfigurationTestsAngGetFailedTests()
    {
        $tests = $this->makeConfigurationTestsAngGetErrors();
        $failed_tests = array();

        foreach ($tests as $test_name => $is_error) {
            if ($is_error) {
                $failed_tests[] = $test_name;
            }
        }

        return $failed_tests;
    }

    /**
     * @param $obj
     * @return mixed
     */
    private function toValue($obj)
    {
        if ($obj->is_serialized) {
            return json_decode($obj->value);
        } elseif ($obj->is_boolean) {
            if (strtolower($obj->value) === 'true') {
                return true;
            }

            return false;
        } elseif (is_numeric($obj->value)) {
            return 0 + $obj->value;
        } else {
            return $obj->value;
        }
    }

    /**
     * @param $value1
     * @param $value2
     * @return bool
     */
    private function is_equal($value1, $value2)
    {
        if (is_numeric($value1) && is_numeric($value2)) {
            return 0 + $value1 === 0 + $value2;
        }

        return $value1 === $value2;
    }
}