예제 #1
0
파일: View.php 프로젝트: paveli/Tweeem
 /**
  * Конструктор
  */
 function __construct()
 {
     parent::__construct();
     if (DEBUG) {
         Open_Benchmark::getInstance()->mark(__CLASS__ . '_start');
     }
     /**
      * Создаём объект Smarty
      */
     $this->smarty = new Open_Smarty();
     /**
      * Передаём Smarty ссылки на экземпляры объектов, для удобства их использования изнутри
      * Использовать функцию Smarty assign_by_ref не надо, т.к. мы и так имеем дело со ссылками на объекты, иначе получится двойная ссылка
      */
     $C = Open_Config::getInstance();
     $this->smarty->assign('config', $C);
     $this->smarty->assign('input', Open_Input::getInstance());
     $this->smarty->assign('router', Open_Router::getInstance());
     $this->smarty->assign('text', Open_Text::getInstance());
     $this->smarty->assign('view', $this);
     /**
      * Устанавливаем значения по умолчанию
      */
     $config = $C->get(array('headers', 'default_title', 'js', 'css', 'default_body'));
     $this->setHeaders($config['headers']);
     $this->setTitle($config['default_title']);
     $this->setJs($config['js']);
     $this->setCss($config['css']);
     $this->setBody($config['default_body']);
 }
예제 #2
0
 /**
  * Конструктор
  *
  * @param mixed $value Число (0xFFEEDD), массив (array(0xFF, 0xEE, 0xDD)), либо строка ('#FFEEDD' или название web-цвета)
  */
 function __construct($value)
 {
     /**
      * Если число сохраняем
      */
     if (is_int($value)) {
         $this->RGB = $value;
     } else {
         if (is_array($value) && count($value) == 3) {
             $temp = array_values($value);
             $this->RGB = ($temp[0] & 0xff) << 16 | ($temp[1] & 0xff) << 8 | $temp[2] & 0xff;
         } else {
             if (is_string($value)) {
                 if ($value[0] == '#') {
                     $this->RGB = intval(base_convert(trim($value, '# '), 16, 10)) & 0xffffff;
                 } else {
                     if (isset(self::$webColors[$temp = strtolower($value)])) {
                         $this->RGB = self::$webColors[$temp];
                     }
                 }
             }
         }
     }
     /**
      * Иначе выдаём ошибку
      */
     if ($this->RGB === FALSE) {
         triggerError(sprintf(Open_Text::getInstance()->dget('errors', 'The value "<b>%s</b>" cannot be converted to color'), $value), E_USER_WARNING);
     }
 }
예제 #3
0
 /**
  * Конструктор
  */
 protected function __construct()
 {
     parent::__construct();
     if (DEBUG) {
         Open_Benchmark::getInstance()->mark(__CLASS__ . '_start');
     }
     $this->config = Open_Config::getInstance();
     $this->input = Open_Input::getInstance();
     $this->router = Open_Router::getInstance();
     $this->text = Open_Text::getInstance();
     $this->view = Open_View::getInstance();
     $this->setArguments($this->router->getArguments());
 }
예제 #4
0
파일: Config.php 프로젝트: paveli/Tweeem
 /**
  * Получить параметр из конфига по имени и секции
  *
  * @param string $section Имя секции. Если секция не указана, берётся секция по умолчанию
  * @param string $name Имя параметра либо массив имён параметров. Если не указано, значит имя секции - это имя параметра
  * @return mixed
  */
 public function get($section, $name = NULL)
 {
     /**
      * Если второй параметр не указан при вызове, значит первый это имя, а не секция
      * Чтобы при вызове с двумя параметрами сначала была секция, а потом имя параметра, по логике вещей
      */
     if (!isset($name)) {
         $name = $section;
         $section = self::DEFAULT_CONFIG;
     }
     /**
      * Если такой секции не существует
      * То пытаемся подгрузить
      */
     if (!isset($this->config[$section])) {
         $this->load($section, FALSE);
     }
     /**
      * Если запрашивается массив значений из конфига
      * Выбираем все по очереди, если чего-то нет, выдаётся ошибка
      */
     if (is_array($name)) {
         $result = array();
         foreach ($name as $value) {
             if (isset($this->config[$section][$value])) {
                 $result[$value] = $this->config[$section][$value];
             } else {
                 trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Config item <b>%s[%s]</b> does not exist'), $section, $name), E_USER_NOTICE);
                 return FALSE;
             }
         }
         return $result;
     }
     /**
      * Если указанный пункт в секции существует, возвращаем
      */
     if (isset($this->config[$section][$name])) {
         return $this->config[$section][$name];
     }
     /**
      * Если ничего не найдено, то выдаём ошибку
      */
     trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Config item <b>%s[%s]</b> does not exist'), $section, $name), E_USER_NOTICE);
     return FALSE;
 }
예제 #5
0
/**
 * Функция для вставки постраничной навигации
 *
 * Параметры:
 *
 * 1. Обязательные
 *
 * 1.1. Для всех шаблонов
 * 1.1.1. link - ссылка для навигации, где подстрока [:nav:] заменяется на параметр навигации (e.g. страницу, номер объекта)
 * 1.1.2. amount - количество объектов по которым производится навигация
 * 1.1.3. span - количество объектов выводимых на одной странице
 * 1.1.4. current - текущий параметр навигации (e.g. текущая страница, номер объекта)
 *
 * 1.2. Шаблон first
 *
 * 2. Необязательные
 *
 * 2.1. Для всех шаблонов
 * 2.1.1. pattern - шаблон постраничной навигации. По умолчанию берётся значение 'default_pagination_pattern' из конфига
 * 2.1.2. class - имя класса для <div> навигации. По умолчанию будет присвоен класс 'pagination-'. $params['pattern']
 *
 * 2.2. Шаблон first
 * 2.2.1. around - страниц рядом с текущей
 * 2.2.2. gaps - максимальное количество промежутков
 * 2.2.3. threshold - порог промежутка
 * 2.2.4. gap - обозначение промежутка, по умолчанию строка '&#8230;', что есть многоточие
 *
 * @param array $params
 * @param object $smarty
 * @return string
 */
function smarty_function_pagination($params, &$smarty)
{
    /**
     * Проверка все ли необходимые аргументы переданы
     */
    if (!isset($params['link']) || empty($params['link'])) {
        trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Parameter <b>%s</b> for Smarty function <b>pagination</b> is not set'), 'link'), E_USER_ERROR);
    } else {
        if (!isset($params['amount']) || empty($params['amount'])) {
            trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Parameter <b>%s</b> for Smarty function <b>pagination</b> is not set'), 'amount'), E_USER_ERROR);
        } else {
            if (!isset($params['span']) || empty($params['span'])) {
                trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Parameter <b>%s</b> for Smarty function <b>pagination</b> is not set'), 'span'), E_USER_ERROR);
            } else {
                if (!isset($params['current']) || empty($params['current'])) {
                    trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Parameter <b>%s</b> for Smarty function <b>pagination</b> is not set'), 'current'), E_USER_ERROR);
                }
            }
        }
    }
    /**
     * Если шаблон не передан, берём значение по умолчанию из конфига
     */
    if (!isset($params['pattern']) || empty($params['pattern'])) {
        $params['pattern'] = Open_Config::getInstance()->get('default_pagination_pattern');
    }
    /**
     * Если класс ещё не объявлен, подключается исходный файл
     */
    if (!class_exists('Open_Pagination')) {
        require_once CORE_PATH . 'Open/Pagination' . EXT;
    }
    /**
     * Выполнение действий для выбранного шаблона
     */
    switch ($params['pattern']) {
        case Open_Pagination::FIRST:
            /**
             * Установка значений по умолчанию, если необходимо
             */
            $params['around'] = isset($params['around']) ? $params['around'] : Open_Pagination::FIRST_DEFAULT_AROUND;
            $params['gaps'] = isset($params['gaps']) ? $params['gaps'] : Open_Pagination::FIRST_DEFAULT_GAPS;
            $params['threshold'] = isset($params['threshold']) ? $params['threshold'] : Open_Pagination::FIRST_DEFAULT_THRESHOLD;
            /**
             * Получение массива с вычисленными значениями
             */
            $params['pagination'] = Open_Pagination::getInstance()->patternFirst($params['amount'], $params['span'], $params['current'], $params['around'], $params['gaps'], $params['threshold']);
            break;
        default:
            trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Pagination pattern <b>%s</b> is not available'), $params['pattern']), E_USER_ERROR);
            break;
    }
    /**
     * Получение значения переменной params из Smarty
     * Устанавливается своё значение
     */
    $paramsBackup = $smarty->get_template_vars('params');
    $smarty->assign('params', $params);
    /**
     * Отключение кеширования
     */
    $previousCaching = $smarty->caching;
    $smarty->caching = FALSE;
    /**
     * Получение шаблона
     */
    $result = $smarty->fetch('Open/Pagination/' . $params['pattern'] . TPLEXT);
    /**
     * Возврат значения кеширования
     */
    $smarty->caching = $previousCaching;
    /**
     * Восстановление значения переменной params
     */
    $smarty->assign('params', $paramsBackup);
    return $result;
}
예제 #6
0
 /**
  * Установить/получить объект идентификатор
  * Должен соответствовать Open_Auth_Identifier_Interface
  * При получении если объекта не существует, то по умолчанию будет создан объект Open_Auth_Identifier_Db
  *
  * @param object $identifier
  * @return object
  */
 public function identifier($identifier = NULL)
 {
     if (isset($identifier)) {
         if (!$identifier instanceof Open_Auth_Identifier_Interface) {
             trigger_error(Open_Text::getInstance()->dget('errors', 'Identifier passed to <b>Open_Auth</b> does not implements <b>Open_Auth_Identifier_Interface</b>'), E_USER_ERROR);
         }
         $this->identifier = $identifier;
     } else {
         if ($this->identifier === FALSE) {
             if (!class_exists('Open_Auth_Identifier_Db')) {
                 require_once CORE_PATH . 'Open/Auth/Identifier/Db' . EXT;
             }
             $this->identifier(Open_Auth_Identifier_Db::getInstance());
         }
     }
     return $this->identifier;
 }
예제 #7
0
/**
 * Показать 404-ю
 *
 * @param string $message Текст ошибки
 */
function trigger404($message = FALSE)
{
    if ($message === FALSE) {
        $message = Open_Text::getInstance()->dget('errors', Open_Config::getInstance()->get('default_404_message'));
    }
    triggerError($message, E_404);
}
예제 #8
0
 /**
  * Подключить контроллер, проверить доступность метода, и вызвать
  *
  * @param string $controller Контроллер
  * @param string $method Метод
  * @param array $arguments Аргументы
  * @return mixed Возвращённое методом контроллера значение
  */
 private function callControllerMethod($controller, $method, $arguments = array(), $trigger = self::TRIGGER_ERROR)
 {
     /**
      * Получение имени контроллера и метода
      * Заменяются псевдоразделители '_' на '/' и первая буква каждой части делается заглавной
      */
     $temp = explode('_', $controller);
     foreach ($temp as &$value) {
         $value = ucwords(strtolower($value));
     }
     $controller = implode('_', $temp);
     /**
      * Проверка объявлен ли класс с таким именем
      * Если нет, выдаётся ошибка если надо
      */
     if (!class_exists($controller)) {
         /**
          * Проверка существует ли файл с контроллером и его подключение
          */
         if (file_exists($temp = CONTROLLERS_PATH . str_replace('_', '/', $controller) . EXT)) {
             require_once $temp;
         } else {
             switch ($trigger) {
                 case self::TRIGGER_404:
                     trigger404();
                     break;
                 case self::TRIGGER_ERROR:
                     trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Controller <b>%s</b> was not found'), $controller), E_USER_ERROR);
                 default:
                 case self::TRIGGER_NONE:
                     break;
             }
         }
     }
     /**
      * Получение ссылки на объект контроллера
      */
     $C = call_user_func(array($controller, 'getInstance'), $controller);
     /**
      * Проверка возможно ли вызвать метод котроллера
      * Если нет, выдаётся ошибка если надо
      */
     if (!is_callable(array($C, $method))) {
         switch ($trigger) {
             case self::TRIGGER_404:
                 trigger404();
                 break;
             case self::TRIGGER_ERROR:
                 trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Method <b>%s</b> of controller <b>%s</b> cannot be called'), $method, $controller), E_USER_ERROR);
             default:
             case self::TRIGGER_NONE:
                 break;
         }
     }
     /**
      * Вызов метода
      */
     return call_user_func_array(array($C, $method), $arguments);
 }
예제 #9
0
 /**
  * Пресекаем войну клонов
  */
 public function __clone()
 {
     trigger_error(Open_Text::getInstance()->dget('errors', sprintf('Cannot clone %s', __CLASS__)), E_USER_ERROR);
 }
예제 #10
0
파일: Db.php 프로젝트: paveli/OpenStructPHP
 /**
  * Закрыть соединение с БД
  * Если параметр профиль не передан, то отключается подключение по умолчанию
  *
  * @param string $profile
  * @return bool Успех операции
  */
 public function disconnect($profile = FALSE)
 {
     /**
      * Если профиль не передан, то берём профиль по умолчанию
      */
     if ($profile === FALSE) {
         $profile = $this->getProfile();
     }
     /**
      * Закрываем соединение и удаляем элемент текущего профиля из массива соединений
      */
     if (in_array($profile, $this->links)) {
         mysql_close($this->links[$profile]) or triggerError("<i>" . Open_Text::getInstance()->dget('errors', 'Unable to close connection') . " - <b>" . $profile . "</b> !<br><b>#" . mysql_errno($this->links[$profile]) . "</b> - " . mysql_error($this->links[$profile]) . "</i><br />", E_DB);
         unset($this->links[$profile]);
     }
     return TRUE;
 }
예제 #11
0
 /**
  * Получить все параметры из секции
  *
  * @param string $section Имя секции. Если секция не указана, берётся секция по умолчанию
  * @return mixed
  */
 public function getAll($section = NULL)
 {
     /**
      * Если секция не указана, берём секцию по умолчанию
      */
     if (!isset($section)) {
         $section = self::DEFAULT_CONFIG;
     }
     /**
      * Если такой секции не существует
      * То пытаемся подгрузить
      */
     if (!isset($this->config[$section])) {
         $this->load($section, FALSE);
     }
     /**
      * Если секция существует после попытки загрузить, то возвращаем её целиком
      */
     if (isset($this->config[$section])) {
         return $this->config[$section];
     }
     /**
      * Если ничего не найдено, то выдаём ошибку
      */
     trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Config section <b>%s</b> does not exist'), $section), E_USER_NOTICE);
     return FALSE;
 }
예제 #12
0
 /**
  * Проверка поддерживается ли заданый формат методом
  *
  * @param int $supportedFormats Перечисленные через битовое ИЛИ поддерживаемые форматы
  * @param int $format Константа формата
  * @return bool
  */
 private function checkSupportedFormat($supportedFormats, $format)
 {
     if (($supportedFormats & $format) !== $format) {
         trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Format <b>%s</b> is not supported'), $format), E_USER_ERROR);
         return FALSE;
     }
     return TRUE;
 }
예제 #13
0
파일: Acl.php 프로젝트: paveli/Tweeem
 /**
  * Проверить доступ роли $role к ресурсу $resource по действию $action
  * По умолчанию доступ запрещён
  *
  * @param array $role
  * @param array $resource
  * @param array $action
  * @return bool
  */
 public function isAllowed($role, $resource, $action)
 {
     /**
      * Если роли, ресурса или действия не существует возвращается запрещение доступа и выдаётся ошибка
      */
     if (!in_array($role, $this->roles)) {
         trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Unknown role <b>%s</b>'), $role), E_USER_WARNING);
         return FALSE;
     } else {
         if (!in_array($resource, array_keys($this->resources))) {
             trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Unknown resource <b>%s</b>'), $resource), E_USER_WARNING);
             return FALSE;
         } else {
             if (!in_array($action, $this->resources[$resource])) {
                 trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Unknown action <b>%s</b>'), $action), E_USER_WARNING);
                 return FALSE;
             }
         }
     }
     /**
      * Даём безоговорочный доступ роли с полным доступом (админу)
      */
     if ($this->complete_access_role === $role) {
         return TRUE;
     }
     /**
      * Запрещение доступа по умолчанию
      */
     $result = FALSE;
     /**
      * Проверка разрешения в массиве допуска
      * Массив допуска формируется с учётом всех родителей роли
      */
     $allow = $this->getAllow($role);
     if (!in_array($resource, array_keys($allow))) {
     } else {
         if (!in_array($action, $allow[$resource])) {
         } else {
             $result = TRUE;
         }
     }
     return $result;
 }
예제 #14
0
파일: Sync.php 프로젝트: paveli/Tweeem
 /**
  * Заблокировать доступ к ресурсу с ключом $key на основе семафора
  * Эксклюзивная блокировка, т.е. семафор в данном случае является мьютексом
  * Желательно, чтобы ключ был целым значением от 0 до 255
  *
  * @param string $key
  * @return bool Успех операции
  */
 public function semLock($key)
 {
     /**
      * Если нет идентификатора
      */
     if (!isset($this->semaphores[$key])) {
         /**
          * Пытаемся получить ключ к файлу и получить идентификатор семафора по ключу
          * В данном случае семафор является мьютексом
          */
         if (($fkey = ftok(__FILE__, (int) $key & 0xff)) < 0 || ($this->semaphores[$key] = sem_get($fkey, 1, 0664, 1)) === FALSE) {
             /**
              * В случае ошибки при получении ключа в ftok() или при получении семафора sem_get() выдаётся стандартная ошибка
              */
             trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Unable to get semaphore with key <b>%s</b>'), $key), E_USER_ERROR);
         }
         //p(strftime('%T', time()) .' '. numberFormat(fmod(microtime(true), 1), 4) ."\t $key sem got");
     }
     /**
      * Пытаемся захватить семафор
      */
     if (!($result = sem_acquire($this->identifiers[$name]))) {
         trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Semaphore with key <b>%s</b> cannot be acquired'), $name), E_USER_WARNING);
     }
     //p(strftime('%T', time()) .' '. numberFormat(fmod(microtime(true), 1), 4) ."\t $name sem aquired");
     return $result;
 }
예제 #15
0
파일: Text.php 프로젝트: paveli/Tweeem
 /**
  * Получить или установить домен по умолчанию
  *
  * @param mixed $domain
  * @return mixed
  */
 public static function domain($domain = FALSE)
 {
     if ($domain !== FALSE) {
         self::$domain = $domain;
     }
     return self::$domain;
 }
예제 #16
0
 /**
  * Получить URL к статическим данным
  * Если URL является полным (http://www.example.com/eg.css), то так и возвращается
  * Иначе к нему добавляется префикс в соответствии с типом
  *
  * @param string $url
  * @param int $type Open_View::URL_TYPE_JS или Open_View::URL_TYPE_CSS
  * @return string
  */
 private function getStaticUrl($url, $type)
 {
     $parsedUrl = parse_url($url);
     if (isset($parsedUrl['scheme']) && isset($parsedUrl['host'])) {
         return $url;
     }
     switch ($type) {
         case self::URL_TYPE_JS:
             return '/' . JS_DIR . $url . JSEXT;
         case self::URL_TYPE_CSS:
             return '/' . CSS_DIR . $url . CSSEXT;
         default:
             trigger_error(sprintf(Open_Text::getInstance()->dget('errors', 'Type <b>%s</b> is unallowed'), $type), E_USER_WARNING);
             return $url;
     }
 }
예제 #17
0
파일: Validator.php 프로젝트: paveli/Tweeem
 /**
  * Совпадает ли поле с переданным значением
  * В случае ошибки возвращается 1-й аргумент, если он передан
  * Остальные игнорируются
  *
  * @param mixed $var
  * @param array $args
  * @return mixed
  */
 private function match($var, $args)
 {
     $result = isset($args[0]) ? $var == $args[0] : FALSE;
     if ($result) {
         return TRUE;
     } else {
         return isset($args[1]) ? $args[1] : Open_Text::getInstance()->dget('validator', 'The field data does not match a given value');
     }
 }
예제 #18
0
파일: Image.php 프로젝트: paveli/Tweeem
 /**
  * Отобразить, либо сохранить в файл изображение
  *
  * @param int $type Тип сохраняемой картинки
  * @param string $filepath Путь к файлу, в который сохранить картинку, БЕЗ расширения
  * @param int $quality Качество изображения для PNG и JPG
  * @param int $filters Фильтры для PNG изображения
  */
 public function output($type = IMAGETYPE_PNG, $filepath = NULL, $quality = NULL, $filters = NULL)
 {
     /**
      * Если не передано имя файла, то выводим картинку на экран
      */
     if (isset($filepath)) {
         $filepath .= image_type_to_extension($type);
     } else {
         header('Content-type: ' . image_type_to_mime_type($type));
     }
     switch ($type) {
         case IMAGETYPE_PNG:
             imagepng($this->resource, $filepath, $quality, $filters);
             break;
         case IMAGETYPE_JPEG:
             imagejpeg($this->resource, $filepath, $quality);
             break;
         case IMAGETYPE_GIF:
             imagegif($this->resource, $filepath);
             break;
         default:
             trigger_error(Open_Text::getInstance()->dget('errors', 'Wrong or unsupported image type specified for output image'), E_USER_ERROR);
             break;
     }
 }
예제 #19
0
 /**
  * Рисует картинку и возвращает её в виде image/png
  *
  */
 public function draw($isRedraw = false)
 {
     $C = $this->config;
     $I = $this->input;
     $V = $this->view;
     $S = Open_Session::getInstance();
     $M = getModel('CaptchaModel');
     /**
      * Получаем параметры из конфига
      */
     $config = $C->get('captcha', array('angle', 'background', 'color', 'distraction', 'font', 'height', 'length', 'size', 'sessionKey', 'width'));
     $angle =& $config['angle'];
     $background =& $config['background'];
     $color =& $config['color'];
     $distraction =& $config['distraction'];
     $font = FONTS_PATH . $config['font'];
     $height =& $config['height'];
     $length =& $config['length'];
     $size =& $config['size'];
     $sessionKey =& $config['sessionKey'];
     $width =& $config['width'];
     /**
      * Получить строку для прорисовки
      */
     $string = $M->get($isRedraw);
     /**
      * Создание картинки
      */
     if (!($img = imagecreatetruecolor($width, $height))) {
         trigger_error(Open_Text::getInstance()->dget('errors', 'New image cannot be initialized for captcha'), E_USER_ERROR);
     }
     /**
      * Формирование цвета фона
      */
     $background = $this->getColor($img, $background);
     imagefill($img, 0, 0, $background);
     /**
      * Создание надписи на картинке
      */
     for ($i = 0; $i < $length; $i++) {
         $currentSize = $size + mt_rand(-(int) ($size / 6), (int) ($size / 6));
         $x = ($width - 20) / $length * $i + mt_rand(11, 13);
         $y = ($height + $currentSize) / 2 + mt_rand(-4, 4);
         $char = mb_substr($string, $i, 1);
         /**
          * Отвлекающий символ
          */
         imagettftext($img, $currentSize + (int) ($size / 8), mt_rand(-$angle, $angle), $x + mt_rand(-4, 4), $y + mt_rand(-4, 4), $this->getColor($img, $distraction), $font, $char);
         /**
          * Основной цвет
          */
         imagettftext($img, $currentSize, mt_rand(-$angle, $angle), $x, $y, $this->getColor($img, $color), $font, $char);
         /**
          * Повторение надписи цветом фона для создания пересечений
          */
         imagettftext($img, $currentSize + (int) ($size / 12), mt_rand(-$angle, $angle), $x + mt_rand(-2, 2), $y + mt_rand(-2, 2), $background, $font, $char);
     }
     /**
      * Установка header-заголовков
      * Отменяем кеширование картинки и задаём тип содержимого
      */
     $V->setHeaders(array("Expires: Mon, 26 Jul 1997 05:00:00 GMT", "Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT", "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0", "Pragma: no-cache", "Content-type: image/png"));
     $V->sendHeaders();
     /**
      * Выдача картинки
      */
     imagepng($img);
     imagedestroy($img);
 }