Расширение библиотеки Config, работа с БД

Каждый топик здесь посвящен конкретной библиотеке или наработкам конкретного проекта

Расширение библиотеки Config, работа с БД

Сообщение aser » 22 янв 2010, 15:55

Добавляет возможность хранить дополнительные параметры конфигурации в базе данных и изменять их.
Требуется автозагрузка базы данных, префикса расширений классов MY.

item если не находит элемент конфигурации в загруженном массиве обращается в БД и ищет там значение данного элемента, если не находит возвращает FALSE.
get_item возвращает элемент с базы в виде массива
get_list возвращает полный список констант со всеми их параметрами
save_item сохраняет параметр в базу данных

Код: Выделить всё

class MY_Config extends CI_Config 
{

    var $db = null;

        function MY_Config()
    {
            parent::CI_Config();
            log_message('debug', "Extends Config Class Initialized");
    }
      
        
/**
         * Obtaining a database object and run a autoload
         *
         *
         * @access   private
         * @param string $item Vernet value of the item if it will be processed in autoload
         * @return <type>
         */
        function init_db($item=null) {
            $return = null;
            if($this->db !== null)
                return $return;

            $CI =& get_instance();
            $this->db = $CI->db;

            /* При вызове контроллера еще не запущено ядро CI,
             * потому автолоадер запускаем при первой попытке получить данные из базы
             */
            if(!$this->item('autoload_db_config')) {
                log_message('debug', "Autoload Config OFF");
                return $return;
            }

            $this->init_db();
            $this->db->select('config_name, config_value');
            $this->db->where('autoload', 'yes');
            $r = $this->db->get('config');

            if($r->num_rows == 0)
                  return $return;

            $datatable = $r->result_array();

            foreach ($datatable as $row)
            {
                $this->set_item($row['config_name'], unserialize($row['config_value']));

                if($item !== null && $item==$row['config_name'])
                    $return = unserialize($row['config_value']);
            }

            return $return;
        }

        /**
         * Fetch a config file item
         *
         *
         * @access public
         * @param string the config item name
         * @param string the index name
         * @param bool used database
         * @return string
         */
    function item($item, $index = '', $use_db=true)
    {
            if(($pref = parent::item($item, $index)) !== FALSE || $index != '' || $use_db != true)
                return $pref;

            if ( isset($this->config[$item]))
                return FALSE;

            /**
             * Если значение будет найденно при автозагрузке то мы
             * его сразуже вернем
             */
            if(($pref = $this->init_db($item)) !== null )
                return $pref;

            $this->db->where('config_name', $item);
            $r = $this->db->get('config', 1);
            if($r->num_rows == 0)
                return false;
            
            $data 
= $r->row_array();
            $pref = unserialize($data['config_value']);
            $this->set_item($item, $pref);

            return $pref;
    }

        /**
         * Get config item
         *
         * Gets the item from the database as an array
         *
         * @access public
         * @param string $item
         * @return array
         */
        function get_item($item)
    {
            $this->init_db();

            $this->db->where('config_name', $item);
            $r = $this->db->get('config', 1);
            if($r->num_rows == 0)
                return false;

            $datarow = $r->row_array();
            $datarow['config_value'] = unserialize($datarow['config_value']);
            
            return $datarow
;
    }

        /**
         * Get list const items
         *
         *
         * @access public
         * @return array
         */
        function get_list() {
            $this->init_db();

            $r = $this->db->get('config');

            if($r->num_rows == 0)
                  return false;

            $datatable = $r->result_array();
            $func = create_function('$v', '$v[\'config_value\'] = unserialize($v[\'config_value\']); return $v;');
            $datatable = array_map($func, $datatable);

            return $datatable;
        }

               /**
         * Save to db config
         * 
         *
         * @param string $item
         * @param string $value
         * @param string $title
         * @param string $description
         * @param string $autoload yes/no
         */
        function save_item($item, $value, $title='', $description='', $autoload = 'no')
        {
            $this->init_db();
            
            $this
->db->where('config_name', $item);
            $r = $this->db->get('config', 1);

            if($autoload != 'yes' && $autoload != 'no')
                $autoload = 'no';

            if($r->num_rows == 0)
                $this->db->insert('config', array('config_name'=>$item, 'config_value'=>serialize($value), 'config_title'=>$title, 'config_description'=>$description, 'autoload'=>$autoload));
            else
            
{
                $this->db->where('config_name', $item);
                $this->db->update('config', array('config_value'=>serialize($value), 'config_title'=>$title, 'config_description'=>$description, 'autoload'=>$autoload));
            }

            $this->set_item($item, $value);
        }
}
 


Код: Выделить всё

CREATE TABLE 
`config` (
  `config_title` varchar(255) default NULL,
  `config_name` varchar(255) NOT NULL default '',
  `config_value` blob,
  `config_description` text,
  `autoload` varchar(20) NOT NULL default 'no',
  PRIMARY KEY  (`config_name`)
)
 ENGINE=MyISAM DEFAULT CHARSET=utf8;
 


По большей части интересует критика :). С CI знаком поверхностно, так что сильно не пинайте :).

Код: Выделить всё

changelog
1. Добавлена возможность хранить любые данные которые можно  сериализовать 
Последний раз редактировалось aser 25 янв 2010, 10:49, всего редактировалось 7 раз(а).
aser
 
Сообщения: 36
Зарегистрирован: 26 дек 2008, 21:09
Откуда: Киев

Re: Расширение библиотеки Config, работа с БД

Сообщение michail1982 » 22 янв 2010, 18:39

мне иногда бывает нужно хранить массив в конфиге... можно бы сариализацию прикрутить...
Аватара пользователя
michail1982
 
Сообщения: 533
Зарегистрирован: 25 ноя 2008, 15:36

Re: Расширение библиотеки Config, работа с БД

Сообщение aser » 22 янв 2010, 19:43

отредактировал, теперь работает и с массивами!
Все функции возвращают данные готовые к работе, ничего больше десериализировать не нужно
aser
 
Сообщения: 36
Зарегистрирован: 26 дек 2008, 21:09
Откуда: Киев

Re: Расширение библиотеки Config, работа с БД

Сообщение michail1982 » 22 янв 2010, 23:22

я имел ввиду не то, что нужно сериализовать всё :))
Код: Выделить всё
function get_item ()
{
...
if(
$item !== null && $item==$row['config_name']){
if(
substr($item,0,2)=='a:'){
return 
unserialize($item);
}
else
{
return 
$item;
}
...
Аватара пользователя
michail1982
 
Сообщения: 533
Зарегистрирован: 25 ноя 2008, 15:36

Re: Расширение библиотеки Config, работа с БД

Сообщение Tovit » 23 янв 2010, 09:40

Вероятно, следует разработчикам CI предложить добавить поддержку сохранения параметров.

Похоже, это проблема актуальна для всех, кто впервые сталкивается с CI и первая мысль -- хранить в БД. Я не был исключением :) .
Только потом Вам станет ясна ошибочность данного подхода.

В Вашем случае, для каждого нестандартного параметра, вы лезете снова и снова в БД. Как считаете, это нормально? Представим себе случай, когда задача требует оперировать кол-вом параметров примерно под сотню или даже больше. И что получается? Каждый цикл работы приложения будет производить под сотню запросов на выборку, а потом еще и на запись, если они изменяться.

Вам бы помог метод items запрашивающий ряд данных за один запрос. Поле хранящее имя параметра в обязательном порядке должно индексироваться.

Я же остановил пока свой выбор на хранении динамических параметров в формате YAML.
P.S. чтоб не повторяться, вот здесь, в своем блоге я рассуждаю о хранении параметров в масштабах целой CMS.
Фантазия! Фантазия! Она поможет... не форум!
Аватара пользователя
Tovit
Модератор
 
Сообщения: 1230
Зарегистрирован: 15 фев 2009, 17:18

Re: Расширение библиотеки Config, работа с БД

Сообщение aser » 25 янв 2010, 10:40

Tovit писал(а):Вероятно, следует разработчикам CI предложить добавить поддержку сохранения параметров.


Для этого служит параметр "autoload", если выставлен в true, то при первом обращении к БД выбираются и записываются в массив $config все параметры с БД у которых autoload = true. То есть дальше система не будет повторно обращаться к БД, а будет выбирать параметр с массива $config. Единственное втыканул добавить параметр в save_item.

В моем частном случаи система без нагрузки работает, и это первый и последний мой проект на CI. А класс выложил как основу. В идеальном случаи нужно дописать кеш выборок, обновляемый событием на метод save_item и конфиг для отдельной модели.

а над методом items я подумаю, он явно должен работать на основе отложенной загрузки, так как есть параметры которые нужны здесь и сейчас.

За ссылку спасибо! Почитаю.
aser
 
Сообщения: 36
Зарегистрирован: 26 дек 2008, 21:09
Откуда: Киев

Re: Расширение библиотеки Config, работа с БД

Сообщение radist2s » 25 янв 2010, 12:47

Tovit писал(а):Я же остановил пока свой выбор на хранении динамических параметров в формате YAML.
P.S. чтоб не повторяться, вот здесь, в своем блоге я рассуждаю о хранении параметров в масштабах целой CMS.

По-моему - хранить конфиги вне *.php и <?php ?> - небезопасно. Понятное дело, что настройки сервера, chmod и все такое позволяют запретить доступ к файлу простым пользователям, однако это не меняет факта возможной ошибки конечного администратора.
Я тоже решил хранить не жизненно важные конфиги в БД, ну и конечно включаем кеширование.
radist2s
 
Сообщения: 8
Зарегистрирован: 02 окт 2009, 12:11

Re: Расширение библиотеки Config, работа с БД

Сообщение Tovit » 25 янв 2010, 13:33

по-моему, решение 2/3 проблемы лежит в выносе всего критически важно за пределы папки www (видимой извне).
А если Вам в конфиг, записываемом в формате php, вольют инъекцию из опасного кода? Только не нужно рассказывать про фильтрацию данных, всегда найдется умник, который найдет лазейку или в Ваших фильтрациях или в самом интерпретаторе php.
А если хранить параметры, в изначально не известном для злоумышленника формате, и парсить такой формат, это и будет защита от исполнения данных.

Да, кто-то возразит, что и это не идеальная защита -- согласен. Но абсолютно защищенная система не юзабельна.
Фантазия! Фантазия! Она поможет... не форум!
Аватара пользователя
Tovit
Модератор
 
Сообщения: 1230
Зарегистрирован: 15 фев 2009, 17:18


Вернуться в Решения, авторский код и библиотеки

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 0