<?php use Storage\PathPattern; use Storage\Storage; use Storage\Processing\File as FileProcessing; class COBJ_TypesFieldFile extends COBJ_TypesField implements COBJ_TypesFieldInterfaceFile { const RANDOM_LENGTH = 16; protected $processing; // Возвращает максимально допустимый размер файла. protected function getMaxAllowedSize() { return min(get_bytes_from_ini_value(ini_get('upload_max_filesize')), get_bytes_from_ini_value(ini_get('post_max_size')), $this->data['size_max'] ? $this->data['size_max'] * 1024 : INF); } protected function getDefaultData() { return array( 'description' => '', 'readonly' => false, 'limit_required' => false, 'files_site' => null, 'filename' => '', 'pattern' => '', 'size_max' => 0, ); } // Взаимодействие с базой public function getDbFieldDeclarations() { return array( 'type' => 'VARCHAR', 'length' => 255, 'notnull' => true, 'comment' => $this->getTitle(), 'drop_foreign_keys' => true, ); } // Админка public function getDescription() { $description = parent::getDescription(); if ($this->data['pattern'] !== '') { $description .= 'Допустимые форматы файла: '.$this->data['pattern'].".\n"; } $size_max = $this->getMaxAllowedSize(); if ($size_max) { $description .= 'Размер файла должен быть не больше '.ru_get_size($size_max).".\n"; } return $description; } public function getObjectFormData() { $data = parent::getObjectFormData(); $data['gui'] = 'File'; $data['filename'] = $this->data['filename']; $data['readonly'] = (bool)$this->data['readonly']; $data['limit']['required'] = (bool)$this->data['limit_required']; if ($this->data['pattern'] !== '') { $data['limit']['filename']['pattern'] = $this->data['pattern']; $data['limit']['filename']['message'] = 'Допустимые форматы файла: '.$this->data['pattern']; } // Размер файла $size_max = $this->getMaxAllowedSize(); if ($size_max) { $data['limit']['size']['max'] = round($size_max / 1024); $data['limit']['size']['message'] = 'Размер файла должен быть не больше '.ru_get_size($size_max); } // Файловое хранилище $data['storage'] = $this->getFilesStorage(); return $data; } public function getFilterFormData(COBJ_TypesTypeInterface $object_type = null, array $object_values = array()) { $data = parent::getFilterFormData($object_type, $object_values); $data['gui'] = 'Checkbox'; $data['value'] = true; $data['description'] = 'Файл закачен'; return $data; } // Отображения public function getColumnData() { return array( 'title' => $this->getTitle(), 'width' => 20, ); } public function getColumnValue(array $values) { $value = $values[$this->getName()]; if ($value === '') { return array(); } $url = $this->getFileData($values, 'url'); if ($url === null) { return array(); } return array( 'image' => GUI_Icons::icon($url), 'link' => $url, ); } protected function getFilesStorage() { $site = $this->getSite(); if (!$site) { return; } return $site->getFilesStorage(); } protected function getPathPattern() { $pattern = new PathPattern($this->data['filename']); $pattern->setRandomLength(static::RANDOM_LENGTH); return $pattern; } // Интерфейс public function getProcessing() { if ($this->processing === null) { $storage = $this->getFilesStorage(); if (!$storage) { $this->processing = false; } else { $processing = new FileProcessing($storage, $this->getPathPattern()); $data = $this->getObjectFormData(); $processing->setLimits($data['limit']); $this->processing = $processing; } } return $this->processing; } /** * Устанавливает сайт хранения файлов. * @param int $id */ public function setSiteId($id) { $this->data['files_site'] = $id; } /** * Возвращает сайт, в который хранятся файлы. * @return CSitesSite|null */ public function getSite() { if (!$this->data['files_site']) { return; } try { return CSites::getById($this->data['files_site']); } catch (UnexpectedValueException $e) { return; } } /** * Возвращает информацию о файле. * @param array $row * @param string|null $arg Если указан, то возвратится указанный параметр превьюшки * @return array|null|mixed */ public function getFileData(array $row, $arg = null) { $filename = $row[$this->getName()]; if ((string)$filename === '') { return; } $processing = $this->getProcessing(); if (!$processing) { return; } return $processing->getFileData($filename, $row, $arg); } /** * Проверяет файл. * @param string $path Путь к файлу * @param string|null $realname Настоящее название файла(basename) * @return bool|string */ public function checkFile($path, $realname = null) { if (!is_file($path)) { throw new InvalidArgumentException(sprintf('Файл "%s" не найден.', $path)); } $processing = $this->getProcessing(); if (!$processing) { return true; } return $processing->validate($path, $realname); } /** * Сохраняет файл. * @param array $row * @param string $path Путь к файлу * @param string|null $realname Настоящее название файла(basename) * @return string Путь к сохранённому файлу */ public function saveFile(array $row, $path, $realname = null) { if (!is_file($path)) { throw new InvalidArgumentException(sprintf('Файл "%s" не найден.', $path)); } $processing = $this->getProcessing(); if (!$processing) { return; } return $processing->save($row, $path, $realname); } /** * Удаляет файл. * @param array $row * @return bool */ public function deleteFile(array $row) { if ($row[$this->getName()] === '') { throw new InvalidArgumentException('Невозможно удалить файл, так как не указаны данные файла.'); } $processing = $this->getProcessing(); if (!$processing) { return; } return $processing->delete($row[$this->getName()], $row); } }
SystemBootstrap->errorToExceptionHandler(4096, 'Argument 1 passed to COBJ_TypesFieldFile::getFileData() must be ...', '/home/host1864002/admin.infomine.ru/htdocs/www/cms_adm/modules/O...', 187, array())
<?php use Storage\PathPattern; use Storage\Storage; use Storage\Processing\File as FileProcessing; class COBJ_TypesFieldFile extends COBJ_TypesField implements COBJ_TypesFieldInterfaceFile { const RANDOM_LENGTH = 16; protected $processing; // Возвращает максимально допустимый размер файла. protected function getMaxAllowedSize() { return min(get_bytes_from_ini_value(ini_get('upload_max_filesize')), get_bytes_from_ini_value(ini_get('post_max_size')), $this->data['size_max'] ? $this->data['size_max'] * 1024 : INF); } protected function getDefaultData() { return array( 'description' => '', 'readonly' => false, 'limit_required' => false, 'files_site' => null, 'filename' => '', 'pattern' => '', 'size_max' => 0, ); } // Взаимодействие с базой public function getDbFieldDeclarations() { return array( 'type' => 'VARCHAR', 'length' => 255, 'notnull' => true, 'comment' => $this->getTitle(), 'drop_foreign_keys' => true, ); } // Админка public function getDescription() { $description = parent::getDescription(); if ($this->data['pattern'] !== '') { $description .= 'Допустимые форматы файла: '.$this->data['pattern'].".\n"; } $size_max = $this->getMaxAllowedSize(); if ($size_max) { $description .= 'Размер файла должен быть не больше '.ru_get_size($size_max).".\n"; } return $description; } public function getObjectFormData() { $data = parent::getObjectFormData(); $data['gui'] = 'File'; $data['filename'] = $this->data['filename']; $data['readonly'] = (bool)$this->data['readonly']; $data['limit']['required'] = (bool)$this->data['limit_required']; if ($this->data['pattern'] !== '') { $data['limit']['filename']['pattern'] = $this->data['pattern']; $data['limit']['filename']['message'] = 'Допустимые форматы файла: '.$this->data['pattern']; } // Размер файла $size_max = $this->getMaxAllowedSize(); if ($size_max) { $data['limit']['size']['max'] = round($size_max / 1024); $data['limit']['size']['message'] = 'Размер файла должен быть не больше '.ru_get_size($size_max); } // Файловое хранилище $data['storage'] = $this->getFilesStorage(); return $data; } public function getFilterFormData(COBJ_TypesTypeInterface $object_type = null, array $object_values = array()) { $data = parent::getFilterFormData($object_type, $object_values); $data['gui'] = 'Checkbox'; $data['value'] = true; $data['description'] = 'Файл закачен'; return $data; } // Отображения public function getColumnData() { return array( 'title' => $this->getTitle(), 'width' => 20, ); } public function getColumnValue(array $values) { $value = $values[$this->getName()]; if ($value === '') { return array(); } $url = $this->getFileData($values, 'url'); if ($url === null) { return array(); } return array( 'image' => GUI_Icons::icon($url), 'link' => $url, ); } protected function getFilesStorage() { $site = $this->getSite(); if (!$site) { return; } return $site->getFilesStorage(); } protected function getPathPattern() { $pattern = new PathPattern($this->data['filename']); $pattern->setRandomLength(static::RANDOM_LENGTH); return $pattern; } // Интерфейс public function getProcessing() { if ($this->processing === null) { $storage = $this->getFilesStorage(); if (!$storage) { $this->processing = false; } else { $processing = new FileProcessing($storage, $this->getPathPattern()); $data = $this->getObjectFormData(); $processing->setLimits($data['limit']); $this->processing = $processing; } } return $this->processing; } /** * Устанавливает сайт хранения файлов. * @param int $id */ public function setSiteId($id) { $this->data['files_site'] = $id; } /** * Возвращает сайт, в который хранятся файлы. * @return CSitesSite|null */ public function getSite() { if (!$this->data['files_site']) { return; } try { return CSites::getById($this->data['files_site']); } catch (UnexpectedValueException $e) { return; } } /** * Возвращает информацию о файле. * @param array $row * @param string|null $arg Если указан, то возвратится указанный параметр превьюшки * @return array|null|mixed */ public function getFileData(array $row, $arg = null) { $filename = $row[$this->getName()]; if ((string)$filename === '') { return; } $processing = $this->getProcessing(); if (!$processing) { return; } return $processing->getFileData($filename, $row, $arg); } /** * Проверяет файл. * @param string $path Путь к файлу * @param string|null $realname Настоящее название файла(basename) * @return bool|string */ public function checkFile($path, $realname = null) { if (!is_file($path)) { throw new InvalidArgumentException(sprintf('Файл "%s" не найден.', $path)); } $processing = $this->getProcessing(); if (!$processing) { return true; } return $processing->validate($path, $realname); } /** * Сохраняет файл. * @param array $row * @param string $path Путь к файлу * @param string|null $realname Настоящее название файла(basename) * @return string Путь к сохранённому файлу */ public function saveFile(array $row, $path, $realname = null) { if (!is_file($path)) { throw new InvalidArgumentException(sprintf('Файл "%s" не найден.', $path)); } $processing = $this->getProcessing(); if (!$processing) { return; } return $processing->save($row, $path, $realname); } /** * Удаляет файл. * @param array $row * @return bool */ public function deleteFile(array $row) { if ($row[$this->getName()] === '') { throw new InvalidArgumentException('Невозможно удалить файл, так как не указаны данные файла.'); } $processing = $this->getProcessing(); if (!$processing) { return; } return $processing->delete($row[$this->getName()], $row); } }
COBJ_TypesFieldFile->getFileData(null)
<? ?><?php $prev_content = $content; $content = ""; $research = COBJ_TypesType::create("ResearchItems")->id($_GET["item"])->published()->getRow(); $demo = $ResearchItems->fields["file"]->getFileData($research); //var_dump($demo); if (!$research || !$demo["url"]) { $header = "Исследование не существует"; $content = $content_error; } Core::loadLib("form"); class FormFeedback extends Form { protected $submitted_check_field_name = "surname"; protected function validate($_obj) { $this->checkRequired("surname", "Вы не заполнили поле \"Фамилия\""); $this->checkRequired("name", "Вы не заполнили поле \"Имя\""); $this->checkRequired("phone", "Вы не заполнили поле \"Телефон\""); $this->checkRequired("mail", "Вы не ввели E-mail"); $this->checkMail("mail", "Указан несуществующий E-mail адрес."); } // Это нужно только если мы хотим выводить ошибки к каждому полю. // Если ошибки хотим выводить в одном месте, переопределение метода getHtmlErrors нужно убрать. protected function getHtmlErrors() { return; } protected function process($_obj, $research, $demo) { if (!form_check("js_enabled")) { $_obj->redirect(array("item" => $_GET["item"])); } $values = array( "surname" => $this->value("surname"), "name" => $this->value("name"), "phone" => $this->value("phone"), "mail" => $this->value("mail"), "demo" => $research["name"], ); $DemoQueries = COBJ_TypesType::create("DemoQueries"); $DemoQueries->insert($values); $mail_values = array( "Фамилия имя" => $this->value("surname"), "Имя" => $this->value("name"), "Телефон" => $this->value("phone"), "E-mail" => $this->value("mail"), ); // Клиенту: $mail = COBJ_TypesType::create("MailTypes")->getMail("demo_to_client_kz", array( "time" => Date_convert("U", "d.m.Y в H:i:s", time()), "name" => escape($this->value("name")), "order" => $research["name"], ), trim($this->value("mail"))); if ($demo["url"]) { $mail->attachFile($demo["path"], $demo["filename"]); } $mail->send(); //Менеджеру COBJ_TypesType::create("MailTypes")->send("demo_order_mail_kz", array( "time" => Date_convert("U", "d.m.Y в H:i:s", time()), "data" => COBJ_TypesType::create("MailTypes")->tableText($mail_values), "demo" => $research["name"], )); //СМС if (!empty($values["phone"])) { $response = serialize($DemoQueries->sendSms(10, $research, $values)); $DemoQueries->id($new_id)->update(array( "sms" => $response, )); } $_obj->redirect(array("item" => $_GET["item"])); } } $form = new FormFeedback(); $form->setVars($_obj, $research, $demo); ?> <div class="forms-element"> <? $form->begin() ?> <h1><?=escape($header)?></h1> <? if (!empty($content)) { ?> <?=$content?> <? } else { ?> <h4><?=escape($research["name"])?></h4> <div>Язык отчета: Русский </div> <div>Способ представления: в электронном виде</div> <div style="margin: 15px 0;"> <?=$prev_content?> </div> <table border="0"> <tr> <td> <p>Фамилия*</p> <? $form->errors("surname") ?> <div class="input" style="width: 285px; margin-right: 20px;"> <?=$form->text("surname", array("style" => "width: 270px;"))?> </div> </td> <td> <p>Имя*</p> <? $form->errors("name") ?> <div class="input" style="width: 285px;"> <?=$form->text("name", array("style" => "width: 270px;"))?> </div> </td> </tr> <tr> <td> <p>Мобильный телефон с кодом страны*</p> <? $form->errors("phone") ?> <div class="input" style="width: 285px; margin-right: 20px;"> <?=$form->text("phone", array("style" => "width: 270px;"))?> </div> </td> <td> <p>Электронная почта*</p> <? $form->errors("mail") ?> <div class="input" style="width: 285px;"> <?=$form->text("mail", array("style" => "width: 270px;"))?> </div> </td> </tr> </table> <input type="submit" class="submit-button" value="Отправить"> <? } ?> <? form_check_hidden("js_enabled") ?> <? $form->result() ?> <?=$content_ok?> <? $form->end() ?> </div>
include('template://kazahstan/forms/demo.php')
<?php class CTemplatesProcess { protected $path; protected $variables = array(); protected $extend_path; protected $extend_variable; public function __construct($path, array $variables) { $this->path = $path; $this->variables = $variables; } protected function registerStreamWrapper() { static $wrapper = false; if (!$wrapper) { $wrapper = true; CTemplatesWrapperTemplate::register(); } } /** * Устанавливает одну или несколько переменных шаблона. * @param array|string $key * @param null|mixed $value */ public function assign($key, $value = null) { if (is_array($key)) { $this->variables = array_replace($this->variables, $key); return; } $this->variables[$key] = $value; } /** * Выводит результат выполнения шаблона. * @param string $path Путь к шаблону * @param array $variables Дополнительные переменные шаблона * @return mixed */ public function display($path, array $variables = array()) { $process = new self($path, array_replace($this->variables, $variables)); echo $process->output($result); return $result; } /** * Возвращает результат выполнения шаблона. * @param string $path Путь к шаблону * @param array $variables Дополнительные переменные шаблона * @return mixed */ public function fetch($path, array $variables = array()) { $process = new self($path, array_replace($this->variables, $variables)); return $process->output(); } /** * Выводит результат выполнения шаблона. * Кеширует вывод на указанное время. * @param int $time Количество секунд закеширования * @param string $path Путь к шаблону * @param array $variables Дополнительные переменные шаблона * @return mixed */ public function cache($time, $path, array $variables = array()) { $process = new CTemplatesProcessCached($path, $variables); $process->setCacheTime($time); $process->assign(array_replace($this->variables, $variables)); echo $process->output(); } public function extend($path, $variable) { $this->extend_path = $path; $this->extend_variable = $variable; } protected function output(&$result = null) { $this->registerStreamWrapper(); extract($this->variables); ob_start(); $result = include CTemplatesWrapperTemplate::PROTOCOL.'://'.$this->path; $output = ob_get_clean(); if ($this->extend_path) { $output = $this->fetch($this->extend_path, array( $this->extend_variable => $output, )); } return $output; } // @todo remove (in CContentPage) public function fetchString($_string) { extract($this->variables, EXTR_SKIP); ob_start(); $result = eval('?>'.$_string); $output = ob_get_clean(); return $result === null ? $output : $result; } }
CTemplatesProcess->output(null)
<?php class CTemplatesProcess { protected $path; protected $variables = array(); protected $extend_path; protected $extend_variable; public function __construct($path, array $variables) { $this->path = $path; $this->variables = $variables; } protected function registerStreamWrapper() { static $wrapper = false; if (!$wrapper) { $wrapper = true; CTemplatesWrapperTemplate::register(); } } /** * Устанавливает одну или несколько переменных шаблона. * @param array|string $key * @param null|mixed $value */ public function assign($key, $value = null) { if (is_array($key)) { $this->variables = array_replace($this->variables, $key); return; } $this->variables[$key] = $value; } /** * Выводит результат выполнения шаблона. * @param string $path Путь к шаблону * @param array $variables Дополнительные переменные шаблона * @return mixed */ public function display($path, array $variables = array()) { $process = new self($path, array_replace($this->variables, $variables)); echo $process->output($result); return $result; } /** * Возвращает результат выполнения шаблона. * @param string $path Путь к шаблону * @param array $variables Дополнительные переменные шаблона * @return mixed */ public function fetch($path, array $variables = array()) { $process = new self($path, array_replace($this->variables, $variables)); return $process->output(); } /** * Выводит результат выполнения шаблона. * Кеширует вывод на указанное время. * @param int $time Количество секунд закеширования * @param string $path Путь к шаблону * @param array $variables Дополнительные переменные шаблона * @return mixed */ public function cache($time, $path, array $variables = array()) { $process = new CTemplatesProcessCached($path, $variables); $process->setCacheTime($time); $process->assign(array_replace($this->variables, $variables)); echo $process->output(); } public function extend($path, $variable) { $this->extend_path = $path; $this->extend_variable = $variable; } protected function output(&$result = null) { $this->registerStreamWrapper(); extract($this->variables); ob_start(); $result = include CTemplatesWrapperTemplate::PROTOCOL.'://'.$this->path; $output = ob_get_clean(); if ($this->extend_path) { $output = $this->fetch($this->extend_path, array( $this->extend_variable => $output, )); } return $output; } // @todo remove (in CContentPage) public function fetchString($_string) { extract($this->variables, EXTR_SKIP); ob_start(); $result = eval('?>'.$_string); $output = ob_get_clean(); return $result === null ? $output : $result; } }
CTemplatesProcess->display('kazahstan/forms/demo.php')
<?php use Storage\PathPattern; use Storage\Processing\File as FileProcessing; use Storage\Processing\Image as ImageProcessing; class CContentPage { const DEFAULT_FIELD_GUI = 'String'; const URL_PREFIX = 'page'; const TITLE_KEY = 'header'; protected $site; protected $id; protected $params; protected $variables; protected $values; protected $compiled_values = array(); protected $templater; protected $head; public function __construct($id, array $params = null) { $this->site = CSites::getCurrentSite(); if (!$this->site) { throw new LogicException('Не установлен сайт.'); } $this->id = (int)$id; if ($params !== null) { $this->params = $params; } else { $this->params = $this->site->getPagesDataProvider()->getById($this->id); } } /** * Проверяем существует ли переменная страницы. * @param string $name * @return bool */ public function __isset($name) { if ($name === 'id') { return true; } if ($name[0] === '_' && array_key_exists(mb_substr($name, 1), $this->params)) { return true; } if ($this->variables === null) { $this->loadContents(); } if (array_key_exists($name, $this->variables)) { return true; } if (array_key_exists($name, $this->values)) { return true; } return false; } /** * Возвращает значение переменной страницы. * @param string $name * @return mixed */ public function __get($name) { if ($name === 'id') { return $this->id; } if (mb_substr($name[0], 0, 1) === '_' && array_key_exists(mb_substr($name, 1), $this->params)) { return $this->params[mb_substr($name, 1)]; } if ($this->variables === null) { $this->loadContents(); } if (array_key_exists($name, $this->variables)) { return $this->variables[$name]; } if (array_key_exists($name, $this->values)) { if (is_string($this->values[$name]) && mb_strpos($this->values[$name], '<?') !== false && !in_array($name, $this->compiled_values, true)) { $this->values[$name] = $this->templater->fetchString($this->values[$name]); $this->compiled_values[] = $name; } return $this->values[$name]; } } /** * Загрузка переменных шаблона страницы. * @return type */ protected function loadContents() { if ($this->variables !== null) { return; } $this->variables = array(); $this->values = array(); $template = $this->getTemplate(); if (!$template) { return; } $storage = null; // Заполненные переменные $variables = (array)unserialize($this->params['data']); // Устанавливаем переменные $this->variables = array(); foreach ($template->getVariables() as $name => $value) { // Импортируем поля из других шаблонов if (isset($value['import'])) { try { $imported_template = $this->site->getTemplate($value['import']); } catch (UnexpectedValueException $e) { throw new RuntimeException(sprintf('Невозможно импортировать настройки поля "%s" из шаблона "%s", так как шаблон не найден.', $name, $value['import']), 0, $e); } if ($imported_template->isError()) { throw new RuntimeException(CTemplates::PARSE_ERROR_MESSAGE); } $imported_fields = $imported_template->getVariables(); if (!isset($imported_fields[$name])) { continue; } $value += $imported_fields[$name]; } // Доступно ли поле шаблона на этой странице if (isset($value['pages'])) { $result = false; foreach (array_create_numeric($value['pages']) as $selector) { if ($this->isMatchSelector($selector)) { $result = true; continue; } } if (!$result) { continue; } } if (!isset($value['gui'])) { $value['gui'] = static::DEFAULT_FIELD_GUI; } $names = isset($value['names']) ? array_get_from_string($value['names']) : array($name); foreach ($names as $name) { if (isset($value['rewrite']) && $value['rewrite'] === 'no' && empty($variables[$name])) { continue; } $this->variables[$name] = isset($variables[$name]) ? $variables[$name] : null; // Если файл или картинка if ($value['gui'] === 'File' || $value['gui'] === 'Image') { $filename = @$this->variables[$name]; $this->variables[$name] = null; if (!empty($filename)) { if ($storage === null) { $storage = $this->site->getFilesStorage(); } if (!empty($value['filename'])) { $processing = new FileProcessing($storage, new PathPattern($value['filename'])); $this->variables[$name] = $processing->getFileData($filename, array( '{EXT}' => @pathinfo($filename, PATHINFO_EXTENSION), '{ID}' => $this->id, '{$id}' => $this->id, )); } // Картинка, добавляем превьюшки if ($value['gui'] === 'Image') { if ($this->variables[$name] === null) { $this->variables[$name] = array(); } $this->variables[$name]['resize'] = array(); // Если есть превьюшки в изображении if (isset($value['resize'])) { $processing = new ImageProcessing($storage); $processing->setPreviews($value['resize']); foreach (array_keys($processing->getPreviews()) as $i) { $this->variables[$name]['resize'][] = $processing->getPreviewData($filename, array( '{EXT}' => @pathinfo($filename, PATHINFO_EXTENSION), '{ID}' => $this->id, '{$id}' => $this->id, ), $i + 1); } } } } } // Если HTML if (!empty($this->variables[$name]) && $value['gui'] === 'Html') { if (preg_match('/^(<p>)?( |&#\\d+;)?(<\\/p>)?$/u', $this->variables[$name])) { $this->variables[$name] = ''; } } } } // Устанавливаем значения $this->values = $template->getValues(); // Создаём шаблонизатор $this->templater = CTemplates::getTemplater(); $this->templater->assign('_obj', $this); } /** * Возвращает параметры страницы. * @return array */ public function getParams() { return $this->params; } /** * Возвращает массив редактируемых переменных страницы. * @return array */ public function getVariables() { if ($this->variables === null) { $this->loadContents(); } return $this->variables; } /** * Возвращает массив значений страницы. * @return array */ public function getValues() { if ($this->values === null) { $this->loadContents(); } foreach ($this->values as $name => $value) { if (is_string($value) && mb_strpos($value, '<?') !== false && !in_array($name, $this->compiled_values, true)) { $this->values[$name] = $this->templater->fetchString($value); $this->compiled_values[] = $name; } } return $this->values; } /** * Возвращает url по умолчанию (без указания собственного url). * @param int $id * @return string */ public static function getDefaultUrl($id) { return (int)$id === 1 ? '/' : '/'.static::URL_PREFIX.$id; } /** * Возвращает объект для помощи(helper) построения html-кода. * @return CContentPageHtml */ public function html() { return new CContentPageHtml($this); } /** * Возвращает объект для работы с head (мета-теги, стили, js). * @return CContentPageHead */ public function head() { if (!$this->head) { $this->head = new CContentPageHead(); } return $this->head; } public function getTitle() { return $this->__isset(static::TITLE_KEY) ? $this->__get(static::TITLE_KEY) : null; } public function getText() { $template = $this->getTemplate(); if (!$template) { return; } $variables = $this->getVariables(); $texts = array(); foreach ($template->getVariables() as $name => $value) { if (!isset($variables[$name])) { continue; } $text = $variables[$name]; if (!is_string($text)) { continue; } if (isset($value['import'])) { try { $imported_template = $this->site->getTemplate($value['import']); } catch (UnexpectedValueException $e) { continue; } if ($imported_template->isError()) { continue; } $imported_fields = $imported_template->getVariables(); if (!isset($imported_fields[$name])) { continue; } $value += $imported_fields[$name]; } if (!isset($value['gui'])) { $value['gui'] = static::DEFAULT_FIELD_GUI; } if ($value['gui'] === 'Html') { $texts[] = html_entity_decode(strip_tags($text), ENT_COMPAT, 'utf-8'); } if (in_array($value['gui'], array('String', 'Text'), true)) { $texts[] = $text; } } if (!count($texts)) { return ''; } $text = implode(' ', $texts); $text = str_replace("\n", ' ', $text); $text = str_replace("\r", ' ', $text); $text = preg_replace('/\\s{2,}/u', ' ', $text); $text = trim($text); return $text; } public function getTemplate() { if (!$this->params['template']) { return; } try { $template = $this->site->getTemplate($this->params['template']); } catch (UnexpectedValueException $e) { return; } if (!$template->isAssignable()) { return; } return $template; } /** * Перенаправляет браузер на url страницы. * @param array $args * @param mixed $flash */ public function redirect(array $args = array(), $flash = null) { if ($flash !== null) { Flash::set($flash); } http_location($this->getUrl($args)); } /** * Возвращает url страницы. * Можно передавать неименованные параметры. Кол-во должно совпадать с кол-вом параметров в ссылке. * @param array $args * @param bool $assign * @return string */ public function getUrl() { $arguments = func_get_args(); if (count($arguments) && !is_array($arguments[0])) { if ($this->params['redirect'] !== '' || $this->params['filename_regexp'] === '') { throw new InvalidArgumentException(sprintf('Url страницы не формируется динамически, поэтому нельзя передавать неименованные параметры.')); } $filename = $this->params['filename']; while (count($arguments)) { $value = str_replace('/', CContent::SLASH_IN_URL, array_shift($arguments)); $filename = preg_replace('/\\{.*?\\}/u', rawurlencode($value), $filename, 1, $replaced); if (!$replaced) { throw new InvalidArgumentException(sprintf('Передано больше параметров, чем кол-во параметров, участвующих в формировании url страницы.')); } } if (mb_strpos($filename, '{') !== false) { throw new InvalidArgumentException(sprintf('Переданное меньше параметров, чем кол-во параметров, участвующих в формировании url страницы.')); } return '/'.$filename; } $args = count($arguments) ? $arguments[0] : array(); $assign = isset($arguments[1]) ? (bool)$arguments[1] : true; if ($this->params['redirect'] !== '') { $filename = $this->params['redirect']; } else { if ($this->params['filename_regexp'] !== '') { $filename = preg_replace('/\{(\w+\|)?(\$\w+)(\|\w+)?\}/u', '{$2}', '/'.$this->params['filename']); // Переданные переменные $replace = array(); foreach (CContent::getVarsFromFilename($this->params['filename']) as $key => $value) { if (isset($args[$key])) { $value = $args[$key]; unset($args[$key]); } if ($value === null) { return; } $value = str_replace('/', CContent::SLASH_IN_URL, $value); $replace['{$'.$key.'}'] = rawurlencode($value); } $filename = str_replace(array_keys($replace), array_values($replace), $filename); } else { $filename = $this->params['url']; } } // Если остались неиспользованные параметры, то добавляем их if ($assign && count($args)) { $query = http_build_query($args, '', '&'); $delimiter = mb_strpos($filename, '?') === false ? '?' : '&'; if ($query !== '') { $filename .= $delimiter.$query; } } return $filename; } /** * Возвращает родительскую страницу. * @return CContentPage|null */ public function getParent() { if (!$this->params['parent_id']) { return; } return $this->site->getPage($this->params['parent_id']); } /** * Возвращает дочерние страницы. * @param bool $published_only Только опубликованные с непараметризованными url и с установленным шаблоном * @return array */ public function getChildren($published_only = true) { $pages = array(); foreach ($this->site->getPagesDataProvider()->getChildren($this->id) as $data) { if ($published_only) { if (!$data['active'] || ($data['url'] === '' && $data['redirect'] === '') || !$data['template']) { continue; } } $page = $this->site->getPage($data); if ($published_only) { $template = $page->getTemplate(); if (!$template) { continue; } } $pages[] = $page; } return $pages; } /** * Возвращает одну дочернюю страницу. * @param string|null $where * @return CContentPage|null */ public function getChild($where = '`active` = 1') { global $_core; if ($where !== null) { $where = ' AND '.$where; } $row = $_core->db->getRow('SELECT * FROM ?F WHERE `parent_id` = ? ?N ORDER BY `n` LIMIT 1', $this->site->getPagesDataProvider()->getDbTable(), $this->id, (string)$where); if (!$row) { return; } return $this->site->getPage($row); } /** * Возвращает всех предков. * @return array */ public function getPath() { $page = $this; $pages = array($page); while ($page = $page->getParent()) { $pages[] = $page; } return array_reverse($pages); } /** * Является ли указанная страница предком текущей странице? * @param CContentPage|int $page2 * @return bool */ public function inPath($page2) { if (!$page2 instanceof self && !is_decimal($page2)) { throw new InvalidArgumentException('Аргумент должен быть целым числом или страницей.'); } $page2_id = $page2 instanceof self ? $page2->id : (int)$page2; $page = $this; do { if ($page->id === $page2_id) { return true; } } while ($page = $page->getParent()); return false; } /** * @todo */ public function isMatchSelector($selector) { $selector = array_reverse(array_get_from_string($selector, '/')); $page = $this; $id = reset($selector); while ($id !== false) { if ($page === null) { return false; } if ($id !== '*' && $id != $page->id) { return false; } $page = $page->getParent(); $id = next($selector); } return true; } /** * Вывод страницы. * @param array $values */ public function display(array $values = array()) { $this->loadContents(); if ($this->templater === null) { throw new RuntimeException(sprintf('Не установлен шаблон страницы "%s".', $this->id)); } $this->templater->assign($this->getValues() + $this->getVariables()); if (count($values)) { $this->templater->assign($values); } $this->templater->display($this->params['template']); } /** * Создаёт дочернюю страницу. * @param array $values * @return CContentPage */ public function createChild(array $values) { $children = $this->getChildren(false); $values = array( 'create_time' => time(), 'update_time' => time(), 'n' => count($children) ? end($children)->params['n'] + 1 : 1, 'parent_id' => $this->id, ) + $values; // Создаём регулярку для url с параметрами if (isset($values['filename'])) { $values['filename_regexp'] = CContent::getRegexpFromFilename($values['filename']); } // url, по которому будет доступна страница if (isset($values['url'])) { unset($values['url']); } if (isset($values['filename']) && $values['filename'] !== '') { $values['url'] = CContent::getUrlFromFilename($values['filename']); } $id = $this->site->getPagesDataProvider()->insert($values); // Если ещё не был сгенерирован url страницы if (!isset($values['url'])) { $this->site->getPagesDataProvider()->update($id, array( 'url' => static::getDefaultUrl($id), )); } return $this->site->getPage($id); } /** * Изменяет параметры страницы. * @param array $values */ public function update(array $values) { $values['update_time'] = time(); if (isset($values['create_time'])) { unset($values['create_time']); } if (isset($values['filename'])) { $values['filename_regexp'] = CContent::getRegexpFromFilename($values['filename']); if ($values['filename'] === '') { $values['url'] = static::getDefaultUrl($this->id); } else { $values['url'] = CContent::getUrlFromFilename($values['filename']); } } if (isset($values['parent_id']) && (int)$values['parent_id'] !== (int)$this->params['parent_id']) { $children = $this->site->getPage($values['parent_id'])->getChildren(false); $values['n'] = count($children) ? end($children)->params['n'] + 1 : 1; } $this->site->getPagesDataProvider()->update($this->id, $values); } /** * Удаляет страницу. */ public function delete() { $this->site->getPagesDataProvider()->delete($this->id); } // Методы вывода html-кода public function getPathString($variable, $separator = ' / ', $max_length = null, $last_link = false) { return $this->html()->path($variable, $separator, $max_length, $last_link); } public function getPaginatorString(Paginator $paginator, $class = 'paginator', $variable = 'page', array $variables = array(), $separator_html = null) { return $this->html()->paginator($paginator, $class, $variable, $variables, $separator_html); } public function getTreeString($class = 'sitemap', $variable = 'header', self $current_page = null, $current_class = null, $callback = null) { return $this->html()->tree($class, $variable, $current_page, $current_class, $callback); } }
CContentPage->display(array('header' => 'Заказ демо-версии', 'content' => '<p>Для получения демоверсии отчета, пожалуйста, заполните следую...', 'content_ok' => '<p>Ваш заказ принят. </p> <p>Демо-версия будет направлен...', 'content_error' => '<p>К сожалению, произошла ошибка. Мы не смогли найти на сайте та...', 'path' => 'Басты', 'language' => 'kazahstan', 'top_content' => '<p>1993 ж. құрылған «Инфомайн» компаниясының өнеркәс...', 'header_block' => null, ...))
<?php class CContent { const SLASH_IN_URL = '(%2f)'; /** * @var CContentPage */ public static $page; /** * @var array */ public static $path; /** * @var mixed */ public static $flash; /** * Возвращает страницу по указанному ID. * @param int|array $id * @return CContentPage */ public static function id($id) { $site = CSites::getCurrentSite(); if (!$site) { throw new LogicException('Не установлен сайт.'); } return $site->getPage($id); } public static function getAll($where = null) { global $_core; $site = CSites::getCurrentSite(); if (!$site) { throw new LogicException('Не установлен сайт.'); } $where = (string)$where === '' ? '' : ' WHERE '.$where; return $_core->db->getAll('SELECT * FROM ?F ?N ORDER BY `n`', $site->getPagesDataProvider()->getDbTable(), $where); } public function search($string, $where = '`active` = 1 AND `filename_regexp` = ""', $operator = 'OR') { global $_core; $search = $_core->db->getSearchSql(mb_substr($string, 0, 64), 'data', $operator, 1); if (!$search) { return array(); } $where = $where === null ? $search : '('.$where.') AND '.$search; return static::getAll($where); } public static function getPageByUrl($url, array &$vars = null) { $site = CSites::getCurrentSite(); if (!$site) { throw new LogicException('Не установлен сайт.'); } // Индексная страница if ($url === '/') { return $site->getPage(1); } $data = $site->getPagesDataProvider()->getPublishedByUrl($url); if (!$data) { return; } $page = $site->getPage($data); // Переменные из url if ($page->_filename_regexp !== '' && is_array($vars)) { $filename_regexp = str_replace('[:alpha:]', '\\pL', $page->_filename_regexp); preg_match('/'.str_replace('/', '\/', $filename_regexp).'/u', mb_substr($url, 1), $matches); array_shift($matches); $variables = static::getVarsFromFilename($page->_filename); foreach (array_keys($variables) as $key) { $value = array_shift($matches); $value = str_replace(static::SLASH_IN_URL, '/', $value); $vars[$key] = $value; } } return $page; } public static function showPage(CContentPage $page, array $additional_variables = array()) { // Не опубликована if (!$page->_active) { return false; } // Перенаправление if (trim($page->_redirect) !== '') { http_location($page->_redirect, 301); } // Шаблон $template = $page->getTemplate(); if (!$template) { return false; } // Загрузка цепочки элементов от корня до текущего $path = $page->getPath(); static::$page = $page; static::$path = $path; static::$flash = Flash::get(); // Формируем массив переменных, которые пойдут на страницу $values = array(); foreach ($path as $o) { $values = $o->getValues() + $o->getVariables() + $values; } // Устанавливаем дополнительные переменные $values = $additional_variables + $values; Benchmark::s(__METHOD__.':display', $page->_template, array($page, $values)); try { $page->display($values); } catch (Exception $e) { Benchmark::e(__METHOD__.':display', $page->_template); throw $e; } Benchmark::e(__METHOD__.':display', $page->_template); return true; } public static function getRegexpFromFilename($filename) { if (mb_strpos($filename, '$') === false) { return ''; } $pattern = preg_replace('/\\{((\\w+)\|)?\\$\\w+(\\|\\w+)?\\}/u', '_VARIABLE_$2', $filename); $pattern = preg_quote($pattern); $pattern = str_replace(array( '_VARIABLE_int', '_VARIABLE_str', '_VARIABLE_', ), array( '([0-9]+)', '([0-9[:alpha:]]+)', '([^/]+)', ), $pattern); $pattern = '^'.$pattern.'$'; return $pattern; } public static function getVarsFromFilename($filename) { $vars = array(); if (preg_match_all('/\\{((\\w+)\\|)?\\$(\\w+)(\\|(\\w+))?\\}/u', $filename, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $vars[$match[3]] = isset($match[5]) ? $match[5] : null; } } return $vars; } // Возвращает url, по которому будет доступна страница public static function getUrlFromFilename($filename) { if ($filename === '') { throw new UnexpectedValueException('Не указан путь к странице.'); } // Если нет переменных $vars = static::getVarsFromFilename($filename); if (!count($vars)) { return '/'.$filename; } // Если хоть у одной переменной не указано значение по умолчанию, то невозможно создать url foreach ($vars as $value) { if ($value === null) { return ''; } } // Подставляем в url значения по умолчанию всех переменных foreach ($vars as $value) { $filename = preg_replace('/{.*?}/', $value, $filename, 1); } return '/'.$filename; } }
CContent::showPage(CContentPage)
<?php /** * Возможные настройки константами: * * SKIP_BOOTSTRAP Не выполнять инициализацию системы этим файлом. * BOOTSTRAP Суффикс названия класса, инициализирующего систему. * BOOTSTRAP_DISPLAY_ERRORS Устанавливает настройку конфигурации php 'display_errors'. Если не объявлена, то устанавливается в true. * BOOTSTRAP_CACHE_PREFIX Префикс ключей при key-value кешировании. * BOOTSTRAP_CORE_CACHE Кешировать глобальный объект $_core. * BOOTSTRAP_CORE_CACHE_FILENAME Название файла, в который будет кешироваться глобальный объект $_core. Нужно, если система запускается с разными конфигами, например dev-версия. * BOOTSTRAP_DEBUGBAR Отображать ли отладочную информацию вверху страницы. * BOOTSTRAP_SITE_ID Идентификатор сайта, который нужно установить текущим. * BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION Функция, которая должна быть вызвана для преобразования сгенерированного html-кода запрашиваемой страницы сайта. * BOOTSTRAP_FULLPAGE_CAСHE_TIME Время в секундах, на которое будет кешироваться страница. По умолчанию 60. * BOOTSTRAP_FULLPAGE_CAСHE_HEADER Отправлять заголовок, указывающий, бралась ли страница из кеша. Если не объявлена, то устанавливается в true. * BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES Переменные сессии, которые могут быть установлены для возможности кеширования страницы. По умолчанию: csrf-token */ if (!defined('SKIP_BOOTSTRAP') || !SKIP_BOOTSTRAP) { if (!defined('BOOTSTRAP')) { define('BOOTSTRAP', ''); } $classname = 'SystemBootstrap'.BOOTSTRAP; return new $classname(); } class SystemBootstrap { const CACHE_DIR = 'cache'; const CORE_CACHE_AVAILABLE = true; const CORE_CACHE_FILE = 'core.cache'; protected $dir; protected $is_cli_or_ajax = false; protected $autoload_classmap = array(); protected $config; protected $e; public function __construct() { $this->dir = __DIR__; // Настройка $this->environment(); // Ошибки переделываются в исключения set_error_handler(array($this, 'errorToExceptionHandler')); // Регистрация автозагрузчика классов spl_autoload_register(array($this, 'autoload')); // Инициализация классов из vendor $this->vendor(); // Подгрузка из lib $this->lib(); // Автозагружаемые классы из lib $this->libAutoload(); // Требуется в нескольких методах $this->is_cli_or_ajax = PHP_SAPI === 'cli' || http_is_ajax(); // Ловим непойманные исключения $this->registerUncatchableExceptionHandler(); // Действия, выполняемые после завершения выполнения скрипта register_shutdown_function(array($this, 'shutdownHandler')); $this->call('initCoreOrGetFromCache'); $this->call('modulesAutoload'); $this->call('session'); } protected function call($method) { Benchmark::s('Bootstrap::'.$method); call_user_func(array($this, $method)); Benchmark::e('Bootstrap::'.$method); } public function autoload($class) { if (isset($this->autoload_classmap[$class])) { require_once $this->dir.'/'.$this->autoload_classmap[$class]; } } protected function environment() { if (version_compare(PHP_VERSION, '5.3.8', '<')) { exit('Require PHP 5.3.8 or higher.'); } ob_start(); error_reporting(E_ALL & ~E_STRICT); if (!defined('REQUEST_TIME_FLOAT')) { define('REQUEST_TIME_FLOAT', microtime(true)); } ini_set('display_errors', defined('BOOTSTRAP_DISPLAY_ERRORS') ? BOOTSTRAP_DISPLAY_ERRORS : true); ini_set('magic_quotes_runtime', false); ini_set('default_charset', 'UTF-8'); if (version_compare(PHP_VERSION, '5.6.0', '<')) { ini_set('mbstring.internal_encoding', 'UTF-8'); } if (!ini_get('date.timezone')) { ini_set('date.timezone', 'Europe/Moscow'); } setlocale(LC_ALL, 'ru_RU.UTF-8'); setlocale(LC_NUMERIC, 'C'); if (PHP_SAPI !== 'cli') { ini_set('html_errors', true); ini_set('default_mimetype', 'text/html'); header('Expires: '.date(DATE_RFC1123)); header('Last-Modified: '.date(DATE_RFC1123)); header('Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0'); } } protected function vendor() { require $this->dir.'/../vendor/autoload.php'; if (!defined('GD_VERSION')) { define('GD_VERSION', '2.0.1'); } } protected function lib() { require_once $this->dir.'/lib/init.inc.php'; } protected function libAutoload() { $classmap_path = $this->dir.'/'.static::CACHE_DIR.'/classmap-lib.php'; try { $this->autoload_classmap = include $classmap_path; } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { $files = array(); foreach (glob($this->dir.'/lib/*/autoload.php') as $path) { $local_files = include $path; foreach (include $path as $local_path) { $files[] = 'lib/'.basename(dirname($path)).'/'.$local_path; } } $map = array(); foreach ($files as $file) { $class = $this->getClassFromFile($this->dir.'/'.$file); if ($class !== null) { $map[$class] = $file; } } $code = '<?php return '.var_export($map, true).';'; file_put_contents($classmap_path, $code); $this->autoload_classmap += $map; } else { throw $e; } } $this->autoload_classmap = include $classmap_path; } protected function getClassFromFile($path) { $tokens = token_get_all(file_get_contents($path)); $namespace = ''; foreach ($tokens as $i => $token) { if (defined('T_NAMESPACE') && $token[0] === T_NAMESPACE) { for ($namespace_token_i = $i + 2; isset($tokens[$namespace_token_i]); $namespace_token_i += 2) { $namespace .= $tokens[$namespace_token_i][1].'\\'; if (!isset($tokens[$namespace_token_i + 1]) || !is_array($tokens[$namespace_token_i + 1]) || $tokens[$namespace_token_i + 1][0] !== T_NS_SEPARATOR) { break; } } continue; } if (in_array($token[0], array(T_CLASS, T_INTERFACE), true)) { return $namespace.$tokens[$i + 2][1]; } } return null; } /* protected */ public function errorToExceptionHandler($errno, $errstr, $errfile, $errline, $errcontext) { if (error_reporting() & $errno) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } return false; } protected function registerUncatchableExceptionHandler() { if (!$this->is_cli_or_ajax) { set_exception_handler(array($this, 'uncatchableExceptionHandler')); } } /* protected */ public function uncatchableExceptionHandler(Exception $e) { $this->e = $e; error_log($e); } // Инициализация системы. protected function initCoreOrGetFromCache() { $core_cache = static::CORE_CACHE_AVAILABLE && defined('BOOTSTRAP_CORE_CACHE') && BOOTSTRAP_CORE_CACHE; if (!$core_cache || !$this->restoreCoreFromCache()) { $this->call('configuration'); $this->call('core'); $this->call('db'); $this->call('cache'); $this->call('modulesUpdate'); $this->call('modules'); if ($core_cache) { $this->call('cacheCore'); } } } // Кеширование инициализированного экземпляра системы. protected function cacheCore() { global $_core; $cache_filename = static::CORE_CACHE_FILE; if (defined('BOOTSTRAP_CORE_CACHE_FILENAME') && is_string(BOOTSTRAP_CORE_CACHE_FILENAME)) { $cache_filename = BOOTSTRAP_CORE_CACHE_FILENAME; } $path = $this->dir.'/'.static::CACHE_DIR.'/'.$cache_filename; file_put_contents($path, serialize($_core)); } // Берёт из кеша экземпляр системы. protected function restoreCoreFromCache() { global $_core; $cache_filename = static::CORE_CACHE_FILE; if (defined('BOOTSTRAP_CORE_CACHE_FILENAME') && is_string(BOOTSTRAP_CORE_CACHE_FILENAME)) { $cache_filename = BOOTSTRAP_CORE_CACHE_FILENAME; } $path = $this->dir.'/'.static::CACHE_DIR.'/'.$cache_filename; try { $serialized_core = file_get_contents($path); } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { return false; } else { throw $e; } } if (isset($_core)) { throw new RuntimeException('Global variable "$_core" already defined.'); } $_core = unserialize($serialized_core); $this->config = $_core->config; // @todo удалить Core::loadLib('db'); return true; } // Загрузка конфигурационного файла protected function configuration() { require_once $this->dir.'/config.inc.php'; require_once $this->dir.'/config.private.inc.php'; $this->config = $_cfg; } // Инициализация системы protected function core() { global $_core; if (isset($_core)) { throw new RuntimeException('Global variable "$_core" already defined.'); } $_core = new Core($this->config); } // Настройка подключения к БД protected function db() { global $_core; $_core->setDb($this->getDb()); } protected function getDb() { // @todo удалить Core::loadLib('db'); $db = new Db(array( 'host' => $this->config['DB']['Host'], 'user' => $this->config['DB']['User'], 'password' => $this->config['DB']['Password'], 'dbname' => $this->config['DB']['Database'], 'charset' => 'utf8', )); $db->setQueryCompiler(new DbQueryCompiler()); $db->setLogger(new ArrayLogger()); return $db; } // Настройка подключения к кеширующему серверу protected function cache() { global $_core; $cache = $this->getCache(); if ($cache) { $_core->setCache($cache); } } // Возвращает кеширующий объект. protected function getCache() { if (empty($this->config['Cache']['Driver'])) { return; } $class = 'Cache'.$this->config['Cache']['Driver']; $cache = new $class($this->config['Cache']); $cache->setLogger(new ArrayLogger()); if (defined('BOOTSTRAP_CACHE_PREFIX')) { $cache->setPrefix(BOOTSTRAP_CACHE_PREFIX); } return $cache; } // Настройка работы с сессиями protected function session() { if (PHP_SAPI === 'cli') { return; } if (!session_id()) { session_start(); } } // Обновление информации о модулях protected function modulesUpdate() { global $_core; $_core->modules->update($_core->db); } // Загрузка модулей системы protected function modules() { global $_core; foreach ($_core->db->getAll('SELECT * FROM `cms_core_modules` ORDER BY `mod_name`') as $data) { $_core->modules->add($data['mod_name'], unserialize($data['mod_data'])); } } // Автозагружаемые классы из модулей системы protected function modulesAutoload() { global $_core; $classmap_path = $this->dir.'/'.static::CACHE_DIR.'/classmap-modules.php'; try { $this->autoload_classmap += include $classmap_path; } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { $map = array(); foreach ($_core->modules as $module) { $map += $module->getClassMap(); } $code = '<?php return '.var_export($map, true).';'; file_put_contents($classmap_path, $code); $this->autoload_classmap += $map; } else { throw $e; } } } public function shutdownHandler() { // Ловим ошибки не переделанные в исключения $this->shutdownFatalError(); // Вывод сообщений об ошибках $this->shutdownErrorVisualization(); // Логирование времени работы $this->shutdownOverallTimeLogger(); if (defined('BOOTSTRAP_DEBUGBAR') && BOOTSTRAP_DEBUGBAR) { $this->shutdownDebugbar(); } } protected function shutdownFatalError() { if ($this->is_cli_or_ajax) { return; } $error = error_get_last(); if ($error) { if ($error['type'] & (E_ERROR | E_COMPILE_ERROR | E_PARSE)) { $this->e = new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']); } } } protected function shutdownErrorVisualization() { if ($this->is_cli_or_ajax) { return; } if (!$this->e) { return; } http_response_code(500); if (!ini_get('display_errors')) { return; } if (ini_get('html_errors')) { while (ob_get_level()) { ob_end_clean(); } ini_set('default_mimetype', 'text/html'); Diagnostic::handleException($this->e); return; } echo $this->e; } protected function getShutdownOverallTimeLogger() { if (!$this->config['Debug']['ShutdownLogger']) { return; } return new FileLogger($this->config['Log']['Root'].'requests.log'); } protected function shutdownOverallTimeLogger() { $logger = $this->getShutdownOverallTimeLogger(); if (!$logger) { return; } $time = microtime(true) - REQUEST_TIME_FLOAT; $ip = isset($_SERVER['REMOTE_ADDR']) ? "\t".$_SERVER['REMOTE_ADDR'] : "\t".'127.0.0.1'; $file = isset($_SERVER['REQUEST_URI']) ? "\t".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] : "\t".$_SERVER['SCRIPT_FILENAME']; $logger->info(number_format($time, 3).$ip.$file); } protected function shutdownDebugbar() { if ($this->is_cli_or_ajax) { return; } $bar = new DebugBar(); $bar->show(); } } class SystemBootstrapAdmin extends SystemBootstrap { const SESSION_USER_ID_KEY = 'core_user_id'; public function __construct() { parent::__construct(); $this->call('templatesUpdate'); $this->call('userInit'); } // Обновление информации о шаблонах сайтов protected function templatesUpdate() { foreach (CSites::getAll() as $site) { if (!$site->data['status'] || !$site->data['reindex_templates'] || !is_dir($site->templates_root)) { continue; } $site->updateTemplates(); } } // Инициализация и проверка авторизованности пользователя системы protected function userInit() { global $_core; if (isset($_SESSION[static::SESSION_USER_ID_KEY])) { try { $user = CUsers::getById($_SESSION[static::SESSION_USER_ID_KEY]); if ($user->getStatus()) { $_core->setUser($user); $user->updateActivity(); } } catch (UnexpectedValueException $e) { // Пользователь не найден } } if (!$_core->user) { http_location($this->config['Adm']['URL'].'index.php'); } } } class SystemBootstrapAdminModule extends SystemBootstrapAdmin { public function __construct() { parent::__construct(); $this->call('action'); } protected function environment() { parent::environment(); ob_start(array($this, 'responseOutputHandler')); } /* protected */ public function responseOutputHandler($buffer) { if (PHP_SAPI === 'cli' || (function_exists('http_is_ajax') && !http_is_ajax())) { return false; } $response_type = null; if (!empty($_GET['--type'])) { $response_type = (string)$_GET['--type']; } if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['--type'])) { $response_type = (string)$_POST['--type']; } if ($response_type === 'xml') { ini_set('default_mimetype', 'text/xml'); $buffer = '<data><![CDATA['.$buffer.']]></data>'; } return $buffer; } // Дествие protected function action() { global $_core; $module = $_core->modules->getModuleNameByFilename(realpath($_SERVER['SCRIPT_FILENAME'])); $_core->run($module, (string)@$_REQUEST['act']); if (isset($_SERVER['HTTP_HOST'])) { $style = $_core->action->_template->getStyle(); setcookie('style', $style, time() + 60 * 60 * 24 * 365 * 10, '/', $_SERVER['HTTP_HOST'], false, true); } } } class SystemBootstrapAdminLogin extends SystemBootstrapAdmin { public function __construct() { parent::__construct(); $this->call('userLogout'); $this->call('userLogin'); $this->call('userLoginPage'); } protected function templatesUpdate() { } protected function userInit() { } // Выход из системы пользователя protected function userLogout() { global $_core; if (isset($_GET['_logout'])) { unset($_SESSION[static::SESSION_USER_ID_KEY]); http_location($this->config['Adm']['URL'].'index.php'); } } // Авторизация пользователя protected function userLogin() { global $_core; if (!isset($_POST['login']) || !isset($_POST['password'])) { return; } unset($_SESSION[static::SESSION_USER_ID_KEY]); $user = CUsers::login((string)$_POST['login'], (string)$_POST['password']); if ($user) { $_SESSION[static::SESSION_USER_ID_KEY] = $user->getId(); http_location(Core::url(array($this->config['Modules']['DefaultModule'], true))); } } // Вывод страницы авторизации пользователя protected function userLoginPage() { $template = new CoreTemplate(); $template->setTemplate('login.php'); $template->setTitle('Вход в систему'); if (isset($_COOKIE['style'])) { if (preg_match('/^[A-Za-z0-9\\-]+$/', $_COOKIE['style'])) { $template->setStyle($_COOKIE['style']); } } $template->show(); } } class SystemBootstrapSite extends SystemBootstrap { public function __construct() { parent::__construct(); $this->call('site'); $this->call('auth'); $this->call('php'); } protected function modulesUpdate() { // Не требуется обновлять список модулей } // Сайт определяется по константе BOOTSTRAP_SITE_ID, а не по HTTP_HOST. protected function site() { if (!defined('BOOTSTRAP_SITE_ID')) { throw new RuntimeException('Не объявлена константа "BOOTSTRAP_SITE_ID".'); } try { CSites::setCurrentSiteById(BOOTSTRAP_SITE_ID); } catch (UnexpectedValueException $e) { throw new RuntimeException(sprintf('Не удалось установить сайт "%s".', BOOTSTRAP_SITE_ID), 0, $e); } } protected function auth() { $site = CSites::getCurrentSite(); if ($site->data['auth'] && (@$_SERVER['PHP_AUTH_USER'] !== $site->data['auth_login'] || @$_SERVER['PHP_AUTH_PW'] !== $site->data['auth_password'])) { http_authenticate(); } } protected function php() { $site = CSites::getCurrentSite(); $files = glob($site->root.'php/*.php'); if (is_array($files)) { foreach ($files as $filename) { require_once $filename; } } } // Вызывается только в классах-потомках. protected function templateVariablesToGlobalScape() { foreach (CTemplates::getAdditionalTemplateVariables() as $key => $value) { $GLOBALS[$key] = $value; } } } class SystemBootstrapSitePage extends SystemBootstrapSite { public function __construct() { parent::__construct(); $this->call('page'); } protected function page() { $url = $_SERVER['REQUEST_URI']; // Убираем параметры после ? $pos = mb_strpos($url, '?'); if ($pos !== false) { $url = mb_substr($url, 0, $pos); } // Поддержка старого page_id if (isset($_REQUEST['page_id']) && in_array($url, array('/', '/index.php'))) { $url = '/page'.(int)$_REQUEST['page_id']; } $vars = array(); $page = CContent::getPageByUrl(rawurldecode($url), $vars); if (defined('BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION')) { ob_start(BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION); } try { if (!$page) { throw new Exception404(); } foreach ($vars as $key => $value) { $_REQUEST[$key] = $value; $_GET[$key] = $value; } if (!CContent::showPage($page)) { throw new Exception404(); } } catch (HttpException $e) { $code = $e->getCode(); ob_clean(); http_response_code($code); if ($code === 404) { $site = CSites::getCurrentSite(); if (!$site) { throw new LogicException('Не установлен сайт.', 0, $e); } if (!empty($site->data['404'])) { try { $page = $site->getPage($site->data['404']); } catch (UnexpectedValueException $e) { $page = null; } if ($page) { CContent::showPage($page); } } } } if (defined('BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION')) { ob_end_flush(); } } } class SystemBootstrapSitePageCache extends SystemBootstrapSitePage { const CACHE_PREFIX = 'fullpage'; const CACHE_TIME = 60; const CSRF_TOKEN_PLACEHOLDER = 'CSRF_TOKEN_PLACEHOLDER'; const DEFAULT_FULLPAGE_CAСHE_VARIABLES = 'csrf'; protected $from_cache = true; protected function modulesAutoload() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::modulesAutoload(); } } protected function site() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::site(); } } protected function auth() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::auth(); } } protected function php() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::php(); } } protected function isPageCachable() { if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'GET' || !isset($_SERVER['REQUEST_URI'])) { return false; } if (!isset($_SESSION)) { return true; } $allowed_variables = defined('BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES') ? BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES : static::DEFAULT_FULLPAGE_CAСHE_VARIABLES; $allowed_variables = array_get_from_string($allowed_variables); foreach (array_keys($_SESSION) as $key) { if (!in_array((string)$key, $allowed_variables, true)) { return false; } } return true; } protected function page() { global $_core; if (!$this->isPageCachable()) { $this->from_cache = false; $this->call('modulesAutoload'); $this->call('site'); $this->call('auth'); $this->call('php'); parent::page(); return; } $cache = $_core->cache; if (!$cache) { throw new RuntimeException('Кеш не инициализирован.'); } $key = static::CACHE_PREFIX.BOOTSTRAP_SITE_ID.'_'.crc32($_SERVER['REQUEST_URI']); $html = $cache->get($key); if ($html) { if (!defined('BOOTSTRAP_FULLPAGE_CAСHE_HEADER') || BOOTSTRAP_FULLPAGE_CAСHE_HEADER) { header('FullpageCache: 1'); } // Подставляем персонализированный csrf-token $html = str_replace(static::CSRF_TOKEN_PLACEHOLDER, Core::csrf(), $html); echo $html; return; } $this->from_cache = false; $this->call('modulesAutoload'); $this->call('site'); $this->call('auth'); $this->call('php'); ob_start(); parent::page(); $html = ob_get_flush(); // Перепроверяем, вдруг добавились переменные в сессию (например: автологин) if ($this->isPageCachable()) { // Убираем персонализированный csrf-token. $html = str_replace('<meta name="csrf-token" value="'.Core::csrf().'">', '<meta name="csrf-token" value="'.static::CSRF_TOKEN_PLACEHOLDER.'">', $html); $cache->set($key, $html, defined('BOOTSTRAP_FULLPAGE_CAСHE_TIME') ? BOOTSTRAP_FULLPAGE_CAСHE_TIME : static::CACHE_TIME); } } } class SystemBootstrapSiteAjax extends SystemBootstrapSite { public function __construct() { parent::__construct(); $this->call('templateVariablesToGlobalScape'); } } class SystemBootstrapSiteCron extends SystemBootstrapSite { const LOCK_FILE_HANDLER_KEY = 'lock_file_handle'; public function __construct() { parent::__construct(); $this->call('lock'); $this->call('templateVariablesToGlobalScape'); } protected function auth() { } protected function lock() { $path = realpath($_SERVER['SCRIPT_FILENAME']); $handler = fopen($path.'.lock', 'a+b'); if (!flock($handler, LOCK_EX | LOCK_NB)) { exit; } $GLOBALS[static::LOCK_FILE_HANDLER_KEY] = $handler; } }
SystemBootstrapSitePage->page()
call_user_func(array(0 => SystemBootstrapSitePage, 1 => 'page'))
<?php /** * Возможные настройки константами: * * SKIP_BOOTSTRAP Не выполнять инициализацию системы этим файлом. * BOOTSTRAP Суффикс названия класса, инициализирующего систему. * BOOTSTRAP_DISPLAY_ERRORS Устанавливает настройку конфигурации php 'display_errors'. Если не объявлена, то устанавливается в true. * BOOTSTRAP_CACHE_PREFIX Префикс ключей при key-value кешировании. * BOOTSTRAP_CORE_CACHE Кешировать глобальный объект $_core. * BOOTSTRAP_CORE_CACHE_FILENAME Название файла, в который будет кешироваться глобальный объект $_core. Нужно, если система запускается с разными конфигами, например dev-версия. * BOOTSTRAP_DEBUGBAR Отображать ли отладочную информацию вверху страницы. * BOOTSTRAP_SITE_ID Идентификатор сайта, который нужно установить текущим. * BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION Функция, которая должна быть вызвана для преобразования сгенерированного html-кода запрашиваемой страницы сайта. * BOOTSTRAP_FULLPAGE_CAСHE_TIME Время в секундах, на которое будет кешироваться страница. По умолчанию 60. * BOOTSTRAP_FULLPAGE_CAСHE_HEADER Отправлять заголовок, указывающий, бралась ли страница из кеша. Если не объявлена, то устанавливается в true. * BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES Переменные сессии, которые могут быть установлены для возможности кеширования страницы. По умолчанию: csrf-token */ if (!defined('SKIP_BOOTSTRAP') || !SKIP_BOOTSTRAP) { if (!defined('BOOTSTRAP')) { define('BOOTSTRAP', ''); } $classname = 'SystemBootstrap'.BOOTSTRAP; return new $classname(); } class SystemBootstrap { const CACHE_DIR = 'cache'; const CORE_CACHE_AVAILABLE = true; const CORE_CACHE_FILE = 'core.cache'; protected $dir; protected $is_cli_or_ajax = false; protected $autoload_classmap = array(); protected $config; protected $e; public function __construct() { $this->dir = __DIR__; // Настройка $this->environment(); // Ошибки переделываются в исключения set_error_handler(array($this, 'errorToExceptionHandler')); // Регистрация автозагрузчика классов spl_autoload_register(array($this, 'autoload')); // Инициализация классов из vendor $this->vendor(); // Подгрузка из lib $this->lib(); // Автозагружаемые классы из lib $this->libAutoload(); // Требуется в нескольких методах $this->is_cli_or_ajax = PHP_SAPI === 'cli' || http_is_ajax(); // Ловим непойманные исключения $this->registerUncatchableExceptionHandler(); // Действия, выполняемые после завершения выполнения скрипта register_shutdown_function(array($this, 'shutdownHandler')); $this->call('initCoreOrGetFromCache'); $this->call('modulesAutoload'); $this->call('session'); } protected function call($method) { Benchmark::s('Bootstrap::'.$method); call_user_func(array($this, $method)); Benchmark::e('Bootstrap::'.$method); } public function autoload($class) { if (isset($this->autoload_classmap[$class])) { require_once $this->dir.'/'.$this->autoload_classmap[$class]; } } protected function environment() { if (version_compare(PHP_VERSION, '5.3.8', '<')) { exit('Require PHP 5.3.8 or higher.'); } ob_start(); error_reporting(E_ALL & ~E_STRICT); if (!defined('REQUEST_TIME_FLOAT')) { define('REQUEST_TIME_FLOAT', microtime(true)); } ini_set('display_errors', defined('BOOTSTRAP_DISPLAY_ERRORS') ? BOOTSTRAP_DISPLAY_ERRORS : true); ini_set('magic_quotes_runtime', false); ini_set('default_charset', 'UTF-8'); if (version_compare(PHP_VERSION, '5.6.0', '<')) { ini_set('mbstring.internal_encoding', 'UTF-8'); } if (!ini_get('date.timezone')) { ini_set('date.timezone', 'Europe/Moscow'); } setlocale(LC_ALL, 'ru_RU.UTF-8'); setlocale(LC_NUMERIC, 'C'); if (PHP_SAPI !== 'cli') { ini_set('html_errors', true); ini_set('default_mimetype', 'text/html'); header('Expires: '.date(DATE_RFC1123)); header('Last-Modified: '.date(DATE_RFC1123)); header('Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0'); } } protected function vendor() { require $this->dir.'/../vendor/autoload.php'; if (!defined('GD_VERSION')) { define('GD_VERSION', '2.0.1'); } } protected function lib() { require_once $this->dir.'/lib/init.inc.php'; } protected function libAutoload() { $classmap_path = $this->dir.'/'.static::CACHE_DIR.'/classmap-lib.php'; try { $this->autoload_classmap = include $classmap_path; } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { $files = array(); foreach (glob($this->dir.'/lib/*/autoload.php') as $path) { $local_files = include $path; foreach (include $path as $local_path) { $files[] = 'lib/'.basename(dirname($path)).'/'.$local_path; } } $map = array(); foreach ($files as $file) { $class = $this->getClassFromFile($this->dir.'/'.$file); if ($class !== null) { $map[$class] = $file; } } $code = '<?php return '.var_export($map, true).';'; file_put_contents($classmap_path, $code); $this->autoload_classmap += $map; } else { throw $e; } } $this->autoload_classmap = include $classmap_path; } protected function getClassFromFile($path) { $tokens = token_get_all(file_get_contents($path)); $namespace = ''; foreach ($tokens as $i => $token) { if (defined('T_NAMESPACE') && $token[0] === T_NAMESPACE) { for ($namespace_token_i = $i + 2; isset($tokens[$namespace_token_i]); $namespace_token_i += 2) { $namespace .= $tokens[$namespace_token_i][1].'\\'; if (!isset($tokens[$namespace_token_i + 1]) || !is_array($tokens[$namespace_token_i + 1]) || $tokens[$namespace_token_i + 1][0] !== T_NS_SEPARATOR) { break; } } continue; } if (in_array($token[0], array(T_CLASS, T_INTERFACE), true)) { return $namespace.$tokens[$i + 2][1]; } } return null; } /* protected */ public function errorToExceptionHandler($errno, $errstr, $errfile, $errline, $errcontext) { if (error_reporting() & $errno) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } return false; } protected function registerUncatchableExceptionHandler() { if (!$this->is_cli_or_ajax) { set_exception_handler(array($this, 'uncatchableExceptionHandler')); } } /* protected */ public function uncatchableExceptionHandler(Exception $e) { $this->e = $e; error_log($e); } // Инициализация системы. protected function initCoreOrGetFromCache() { $core_cache = static::CORE_CACHE_AVAILABLE && defined('BOOTSTRAP_CORE_CACHE') && BOOTSTRAP_CORE_CACHE; if (!$core_cache || !$this->restoreCoreFromCache()) { $this->call('configuration'); $this->call('core'); $this->call('db'); $this->call('cache'); $this->call('modulesUpdate'); $this->call('modules'); if ($core_cache) { $this->call('cacheCore'); } } } // Кеширование инициализированного экземпляра системы. protected function cacheCore() { global $_core; $cache_filename = static::CORE_CACHE_FILE; if (defined('BOOTSTRAP_CORE_CACHE_FILENAME') && is_string(BOOTSTRAP_CORE_CACHE_FILENAME)) { $cache_filename = BOOTSTRAP_CORE_CACHE_FILENAME; } $path = $this->dir.'/'.static::CACHE_DIR.'/'.$cache_filename; file_put_contents($path, serialize($_core)); } // Берёт из кеша экземпляр системы. protected function restoreCoreFromCache() { global $_core; $cache_filename = static::CORE_CACHE_FILE; if (defined('BOOTSTRAP_CORE_CACHE_FILENAME') && is_string(BOOTSTRAP_CORE_CACHE_FILENAME)) { $cache_filename = BOOTSTRAP_CORE_CACHE_FILENAME; } $path = $this->dir.'/'.static::CACHE_DIR.'/'.$cache_filename; try { $serialized_core = file_get_contents($path); } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { return false; } else { throw $e; } } if (isset($_core)) { throw new RuntimeException('Global variable "$_core" already defined.'); } $_core = unserialize($serialized_core); $this->config = $_core->config; // @todo удалить Core::loadLib('db'); return true; } // Загрузка конфигурационного файла protected function configuration() { require_once $this->dir.'/config.inc.php'; require_once $this->dir.'/config.private.inc.php'; $this->config = $_cfg; } // Инициализация системы protected function core() { global $_core; if (isset($_core)) { throw new RuntimeException('Global variable "$_core" already defined.'); } $_core = new Core($this->config); } // Настройка подключения к БД protected function db() { global $_core; $_core->setDb($this->getDb()); } protected function getDb() { // @todo удалить Core::loadLib('db'); $db = new Db(array( 'host' => $this->config['DB']['Host'], 'user' => $this->config['DB']['User'], 'password' => $this->config['DB']['Password'], 'dbname' => $this->config['DB']['Database'], 'charset' => 'utf8', )); $db->setQueryCompiler(new DbQueryCompiler()); $db->setLogger(new ArrayLogger()); return $db; } // Настройка подключения к кеширующему серверу protected function cache() { global $_core; $cache = $this->getCache(); if ($cache) { $_core->setCache($cache); } } // Возвращает кеширующий объект. protected function getCache() { if (empty($this->config['Cache']['Driver'])) { return; } $class = 'Cache'.$this->config['Cache']['Driver']; $cache = new $class($this->config['Cache']); $cache->setLogger(new ArrayLogger()); if (defined('BOOTSTRAP_CACHE_PREFIX')) { $cache->setPrefix(BOOTSTRAP_CACHE_PREFIX); } return $cache; } // Настройка работы с сессиями protected function session() { if (PHP_SAPI === 'cli') { return; } if (!session_id()) { session_start(); } } // Обновление информации о модулях protected function modulesUpdate() { global $_core; $_core->modules->update($_core->db); } // Загрузка модулей системы protected function modules() { global $_core; foreach ($_core->db->getAll('SELECT * FROM `cms_core_modules` ORDER BY `mod_name`') as $data) { $_core->modules->add($data['mod_name'], unserialize($data['mod_data'])); } } // Автозагружаемые классы из модулей системы protected function modulesAutoload() { global $_core; $classmap_path = $this->dir.'/'.static::CACHE_DIR.'/classmap-modules.php'; try { $this->autoload_classmap += include $classmap_path; } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { $map = array(); foreach ($_core->modules as $module) { $map += $module->getClassMap(); } $code = '<?php return '.var_export($map, true).';'; file_put_contents($classmap_path, $code); $this->autoload_classmap += $map; } else { throw $e; } } } public function shutdownHandler() { // Ловим ошибки не переделанные в исключения $this->shutdownFatalError(); // Вывод сообщений об ошибках $this->shutdownErrorVisualization(); // Логирование времени работы $this->shutdownOverallTimeLogger(); if (defined('BOOTSTRAP_DEBUGBAR') && BOOTSTRAP_DEBUGBAR) { $this->shutdownDebugbar(); } } protected function shutdownFatalError() { if ($this->is_cli_or_ajax) { return; } $error = error_get_last(); if ($error) { if ($error['type'] & (E_ERROR | E_COMPILE_ERROR | E_PARSE)) { $this->e = new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']); } } } protected function shutdownErrorVisualization() { if ($this->is_cli_or_ajax) { return; } if (!$this->e) { return; } http_response_code(500); if (!ini_get('display_errors')) { return; } if (ini_get('html_errors')) { while (ob_get_level()) { ob_end_clean(); } ini_set('default_mimetype', 'text/html'); Diagnostic::handleException($this->e); return; } echo $this->e; } protected function getShutdownOverallTimeLogger() { if (!$this->config['Debug']['ShutdownLogger']) { return; } return new FileLogger($this->config['Log']['Root'].'requests.log'); } protected function shutdownOverallTimeLogger() { $logger = $this->getShutdownOverallTimeLogger(); if (!$logger) { return; } $time = microtime(true) - REQUEST_TIME_FLOAT; $ip = isset($_SERVER['REMOTE_ADDR']) ? "\t".$_SERVER['REMOTE_ADDR'] : "\t".'127.0.0.1'; $file = isset($_SERVER['REQUEST_URI']) ? "\t".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] : "\t".$_SERVER['SCRIPT_FILENAME']; $logger->info(number_format($time, 3).$ip.$file); } protected function shutdownDebugbar() { if ($this->is_cli_or_ajax) { return; } $bar = new DebugBar(); $bar->show(); } } class SystemBootstrapAdmin extends SystemBootstrap { const SESSION_USER_ID_KEY = 'core_user_id'; public function __construct() { parent::__construct(); $this->call('templatesUpdate'); $this->call('userInit'); } // Обновление информации о шаблонах сайтов protected function templatesUpdate() { foreach (CSites::getAll() as $site) { if (!$site->data['status'] || !$site->data['reindex_templates'] || !is_dir($site->templates_root)) { continue; } $site->updateTemplates(); } } // Инициализация и проверка авторизованности пользователя системы protected function userInit() { global $_core; if (isset($_SESSION[static::SESSION_USER_ID_KEY])) { try { $user = CUsers::getById($_SESSION[static::SESSION_USER_ID_KEY]); if ($user->getStatus()) { $_core->setUser($user); $user->updateActivity(); } } catch (UnexpectedValueException $e) { // Пользователь не найден } } if (!$_core->user) { http_location($this->config['Adm']['URL'].'index.php'); } } } class SystemBootstrapAdminModule extends SystemBootstrapAdmin { public function __construct() { parent::__construct(); $this->call('action'); } protected function environment() { parent::environment(); ob_start(array($this, 'responseOutputHandler')); } /* protected */ public function responseOutputHandler($buffer) { if (PHP_SAPI === 'cli' || (function_exists('http_is_ajax') && !http_is_ajax())) { return false; } $response_type = null; if (!empty($_GET['--type'])) { $response_type = (string)$_GET['--type']; } if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['--type'])) { $response_type = (string)$_POST['--type']; } if ($response_type === 'xml') { ini_set('default_mimetype', 'text/xml'); $buffer = '<data><![CDATA['.$buffer.']]></data>'; } return $buffer; } // Дествие protected function action() { global $_core; $module = $_core->modules->getModuleNameByFilename(realpath($_SERVER['SCRIPT_FILENAME'])); $_core->run($module, (string)@$_REQUEST['act']); if (isset($_SERVER['HTTP_HOST'])) { $style = $_core->action->_template->getStyle(); setcookie('style', $style, time() + 60 * 60 * 24 * 365 * 10, '/', $_SERVER['HTTP_HOST'], false, true); } } } class SystemBootstrapAdminLogin extends SystemBootstrapAdmin { public function __construct() { parent::__construct(); $this->call('userLogout'); $this->call('userLogin'); $this->call('userLoginPage'); } protected function templatesUpdate() { } protected function userInit() { } // Выход из системы пользователя protected function userLogout() { global $_core; if (isset($_GET['_logout'])) { unset($_SESSION[static::SESSION_USER_ID_KEY]); http_location($this->config['Adm']['URL'].'index.php'); } } // Авторизация пользователя protected function userLogin() { global $_core; if (!isset($_POST['login']) || !isset($_POST['password'])) { return; } unset($_SESSION[static::SESSION_USER_ID_KEY]); $user = CUsers::login((string)$_POST['login'], (string)$_POST['password']); if ($user) { $_SESSION[static::SESSION_USER_ID_KEY] = $user->getId(); http_location(Core::url(array($this->config['Modules']['DefaultModule'], true))); } } // Вывод страницы авторизации пользователя protected function userLoginPage() { $template = new CoreTemplate(); $template->setTemplate('login.php'); $template->setTitle('Вход в систему'); if (isset($_COOKIE['style'])) { if (preg_match('/^[A-Za-z0-9\\-]+$/', $_COOKIE['style'])) { $template->setStyle($_COOKIE['style']); } } $template->show(); } } class SystemBootstrapSite extends SystemBootstrap { public function __construct() { parent::__construct(); $this->call('site'); $this->call('auth'); $this->call('php'); } protected function modulesUpdate() { // Не требуется обновлять список модулей } // Сайт определяется по константе BOOTSTRAP_SITE_ID, а не по HTTP_HOST. protected function site() { if (!defined('BOOTSTRAP_SITE_ID')) { throw new RuntimeException('Не объявлена константа "BOOTSTRAP_SITE_ID".'); } try { CSites::setCurrentSiteById(BOOTSTRAP_SITE_ID); } catch (UnexpectedValueException $e) { throw new RuntimeException(sprintf('Не удалось установить сайт "%s".', BOOTSTRAP_SITE_ID), 0, $e); } } protected function auth() { $site = CSites::getCurrentSite(); if ($site->data['auth'] && (@$_SERVER['PHP_AUTH_USER'] !== $site->data['auth_login'] || @$_SERVER['PHP_AUTH_PW'] !== $site->data['auth_password'])) { http_authenticate(); } } protected function php() { $site = CSites::getCurrentSite(); $files = glob($site->root.'php/*.php'); if (is_array($files)) { foreach ($files as $filename) { require_once $filename; } } } // Вызывается только в классах-потомках. protected function templateVariablesToGlobalScape() { foreach (CTemplates::getAdditionalTemplateVariables() as $key => $value) { $GLOBALS[$key] = $value; } } } class SystemBootstrapSitePage extends SystemBootstrapSite { public function __construct() { parent::__construct(); $this->call('page'); } protected function page() { $url = $_SERVER['REQUEST_URI']; // Убираем параметры после ? $pos = mb_strpos($url, '?'); if ($pos !== false) { $url = mb_substr($url, 0, $pos); } // Поддержка старого page_id if (isset($_REQUEST['page_id']) && in_array($url, array('/', '/index.php'))) { $url = '/page'.(int)$_REQUEST['page_id']; } $vars = array(); $page = CContent::getPageByUrl(rawurldecode($url), $vars); if (defined('BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION')) { ob_start(BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION); } try { if (!$page) { throw new Exception404(); } foreach ($vars as $key => $value) { $_REQUEST[$key] = $value; $_GET[$key] = $value; } if (!CContent::showPage($page)) { throw new Exception404(); } } catch (HttpException $e) { $code = $e->getCode(); ob_clean(); http_response_code($code); if ($code === 404) { $site = CSites::getCurrentSite(); if (!$site) { throw new LogicException('Не установлен сайт.', 0, $e); } if (!empty($site->data['404'])) { try { $page = $site->getPage($site->data['404']); } catch (UnexpectedValueException $e) { $page = null; } if ($page) { CContent::showPage($page); } } } } if (defined('BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION')) { ob_end_flush(); } } } class SystemBootstrapSitePageCache extends SystemBootstrapSitePage { const CACHE_PREFIX = 'fullpage'; const CACHE_TIME = 60; const CSRF_TOKEN_PLACEHOLDER = 'CSRF_TOKEN_PLACEHOLDER'; const DEFAULT_FULLPAGE_CAСHE_VARIABLES = 'csrf'; protected $from_cache = true; protected function modulesAutoload() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::modulesAutoload(); } } protected function site() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::site(); } } protected function auth() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::auth(); } } protected function php() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::php(); } } protected function isPageCachable() { if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'GET' || !isset($_SERVER['REQUEST_URI'])) { return false; } if (!isset($_SESSION)) { return true; } $allowed_variables = defined('BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES') ? BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES : static::DEFAULT_FULLPAGE_CAСHE_VARIABLES; $allowed_variables = array_get_from_string($allowed_variables); foreach (array_keys($_SESSION) as $key) { if (!in_array((string)$key, $allowed_variables, true)) { return false; } } return true; } protected function page() { global $_core; if (!$this->isPageCachable()) { $this->from_cache = false; $this->call('modulesAutoload'); $this->call('site'); $this->call('auth'); $this->call('php'); parent::page(); return; } $cache = $_core->cache; if (!$cache) { throw new RuntimeException('Кеш не инициализирован.'); } $key = static::CACHE_PREFIX.BOOTSTRAP_SITE_ID.'_'.crc32($_SERVER['REQUEST_URI']); $html = $cache->get($key); if ($html) { if (!defined('BOOTSTRAP_FULLPAGE_CAСHE_HEADER') || BOOTSTRAP_FULLPAGE_CAСHE_HEADER) { header('FullpageCache: 1'); } // Подставляем персонализированный csrf-token $html = str_replace(static::CSRF_TOKEN_PLACEHOLDER, Core::csrf(), $html); echo $html; return; } $this->from_cache = false; $this->call('modulesAutoload'); $this->call('site'); $this->call('auth'); $this->call('php'); ob_start(); parent::page(); $html = ob_get_flush(); // Перепроверяем, вдруг добавились переменные в сессию (например: автологин) if ($this->isPageCachable()) { // Убираем персонализированный csrf-token. $html = str_replace('<meta name="csrf-token" value="'.Core::csrf().'">', '<meta name="csrf-token" value="'.static::CSRF_TOKEN_PLACEHOLDER.'">', $html); $cache->set($key, $html, defined('BOOTSTRAP_FULLPAGE_CAСHE_TIME') ? BOOTSTRAP_FULLPAGE_CAСHE_TIME : static::CACHE_TIME); } } } class SystemBootstrapSiteAjax extends SystemBootstrapSite { public function __construct() { parent::__construct(); $this->call('templateVariablesToGlobalScape'); } } class SystemBootstrapSiteCron extends SystemBootstrapSite { const LOCK_FILE_HANDLER_KEY = 'lock_file_handle'; public function __construct() { parent::__construct(); $this->call('lock'); $this->call('templateVariablesToGlobalScape'); } protected function auth() { } protected function lock() { $path = realpath($_SERVER['SCRIPT_FILENAME']); $handler = fopen($path.'.lock', 'a+b'); if (!flock($handler, LOCK_EX | LOCK_NB)) { exit; } $GLOBALS[static::LOCK_FILE_HANDLER_KEY] = $handler; } }
SystemBootstrap->call('page')
<?php /** * Возможные настройки константами: * * SKIP_BOOTSTRAP Не выполнять инициализацию системы этим файлом. * BOOTSTRAP Суффикс названия класса, инициализирующего систему. * BOOTSTRAP_DISPLAY_ERRORS Устанавливает настройку конфигурации php 'display_errors'. Если не объявлена, то устанавливается в true. * BOOTSTRAP_CACHE_PREFIX Префикс ключей при key-value кешировании. * BOOTSTRAP_CORE_CACHE Кешировать глобальный объект $_core. * BOOTSTRAP_CORE_CACHE_FILENAME Название файла, в который будет кешироваться глобальный объект $_core. Нужно, если система запускается с разными конфигами, например dev-версия. * BOOTSTRAP_DEBUGBAR Отображать ли отладочную информацию вверху страницы. * BOOTSTRAP_SITE_ID Идентификатор сайта, который нужно установить текущим. * BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION Функция, которая должна быть вызвана для преобразования сгенерированного html-кода запрашиваемой страницы сайта. * BOOTSTRAP_FULLPAGE_CAСHE_TIME Время в секундах, на которое будет кешироваться страница. По умолчанию 60. * BOOTSTRAP_FULLPAGE_CAСHE_HEADER Отправлять заголовок, указывающий, бралась ли страница из кеша. Если не объявлена, то устанавливается в true. * BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES Переменные сессии, которые могут быть установлены для возможности кеширования страницы. По умолчанию: csrf-token */ if (!defined('SKIP_BOOTSTRAP') || !SKIP_BOOTSTRAP) { if (!defined('BOOTSTRAP')) { define('BOOTSTRAP', ''); } $classname = 'SystemBootstrap'.BOOTSTRAP; return new $classname(); } class SystemBootstrap { const CACHE_DIR = 'cache'; const CORE_CACHE_AVAILABLE = true; const CORE_CACHE_FILE = 'core.cache'; protected $dir; protected $is_cli_or_ajax = false; protected $autoload_classmap = array(); protected $config; protected $e; public function __construct() { $this->dir = __DIR__; // Настройка $this->environment(); // Ошибки переделываются в исключения set_error_handler(array($this, 'errorToExceptionHandler')); // Регистрация автозагрузчика классов spl_autoload_register(array($this, 'autoload')); // Инициализация классов из vendor $this->vendor(); // Подгрузка из lib $this->lib(); // Автозагружаемые классы из lib $this->libAutoload(); // Требуется в нескольких методах $this->is_cli_or_ajax = PHP_SAPI === 'cli' || http_is_ajax(); // Ловим непойманные исключения $this->registerUncatchableExceptionHandler(); // Действия, выполняемые после завершения выполнения скрипта register_shutdown_function(array($this, 'shutdownHandler')); $this->call('initCoreOrGetFromCache'); $this->call('modulesAutoload'); $this->call('session'); } protected function call($method) { Benchmark::s('Bootstrap::'.$method); call_user_func(array($this, $method)); Benchmark::e('Bootstrap::'.$method); } public function autoload($class) { if (isset($this->autoload_classmap[$class])) { require_once $this->dir.'/'.$this->autoload_classmap[$class]; } } protected function environment() { if (version_compare(PHP_VERSION, '5.3.8', '<')) { exit('Require PHP 5.3.8 or higher.'); } ob_start(); error_reporting(E_ALL & ~E_STRICT); if (!defined('REQUEST_TIME_FLOAT')) { define('REQUEST_TIME_FLOAT', microtime(true)); } ini_set('display_errors', defined('BOOTSTRAP_DISPLAY_ERRORS') ? BOOTSTRAP_DISPLAY_ERRORS : true); ini_set('magic_quotes_runtime', false); ini_set('default_charset', 'UTF-8'); if (version_compare(PHP_VERSION, '5.6.0', '<')) { ini_set('mbstring.internal_encoding', 'UTF-8'); } if (!ini_get('date.timezone')) { ini_set('date.timezone', 'Europe/Moscow'); } setlocale(LC_ALL, 'ru_RU.UTF-8'); setlocale(LC_NUMERIC, 'C'); if (PHP_SAPI !== 'cli') { ini_set('html_errors', true); ini_set('default_mimetype', 'text/html'); header('Expires: '.date(DATE_RFC1123)); header('Last-Modified: '.date(DATE_RFC1123)); header('Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0'); } } protected function vendor() { require $this->dir.'/../vendor/autoload.php'; if (!defined('GD_VERSION')) { define('GD_VERSION', '2.0.1'); } } protected function lib() { require_once $this->dir.'/lib/init.inc.php'; } protected function libAutoload() { $classmap_path = $this->dir.'/'.static::CACHE_DIR.'/classmap-lib.php'; try { $this->autoload_classmap = include $classmap_path; } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { $files = array(); foreach (glob($this->dir.'/lib/*/autoload.php') as $path) { $local_files = include $path; foreach (include $path as $local_path) { $files[] = 'lib/'.basename(dirname($path)).'/'.$local_path; } } $map = array(); foreach ($files as $file) { $class = $this->getClassFromFile($this->dir.'/'.$file); if ($class !== null) { $map[$class] = $file; } } $code = '<?php return '.var_export($map, true).';'; file_put_contents($classmap_path, $code); $this->autoload_classmap += $map; } else { throw $e; } } $this->autoload_classmap = include $classmap_path; } protected function getClassFromFile($path) { $tokens = token_get_all(file_get_contents($path)); $namespace = ''; foreach ($tokens as $i => $token) { if (defined('T_NAMESPACE') && $token[0] === T_NAMESPACE) { for ($namespace_token_i = $i + 2; isset($tokens[$namespace_token_i]); $namespace_token_i += 2) { $namespace .= $tokens[$namespace_token_i][1].'\\'; if (!isset($tokens[$namespace_token_i + 1]) || !is_array($tokens[$namespace_token_i + 1]) || $tokens[$namespace_token_i + 1][0] !== T_NS_SEPARATOR) { break; } } continue; } if (in_array($token[0], array(T_CLASS, T_INTERFACE), true)) { return $namespace.$tokens[$i + 2][1]; } } return null; } /* protected */ public function errorToExceptionHandler($errno, $errstr, $errfile, $errline, $errcontext) { if (error_reporting() & $errno) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } return false; } protected function registerUncatchableExceptionHandler() { if (!$this->is_cli_or_ajax) { set_exception_handler(array($this, 'uncatchableExceptionHandler')); } } /* protected */ public function uncatchableExceptionHandler(Exception $e) { $this->e = $e; error_log($e); } // Инициализация системы. protected function initCoreOrGetFromCache() { $core_cache = static::CORE_CACHE_AVAILABLE && defined('BOOTSTRAP_CORE_CACHE') && BOOTSTRAP_CORE_CACHE; if (!$core_cache || !$this->restoreCoreFromCache()) { $this->call('configuration'); $this->call('core'); $this->call('db'); $this->call('cache'); $this->call('modulesUpdate'); $this->call('modules'); if ($core_cache) { $this->call('cacheCore'); } } } // Кеширование инициализированного экземпляра системы. protected function cacheCore() { global $_core; $cache_filename = static::CORE_CACHE_FILE; if (defined('BOOTSTRAP_CORE_CACHE_FILENAME') && is_string(BOOTSTRAP_CORE_CACHE_FILENAME)) { $cache_filename = BOOTSTRAP_CORE_CACHE_FILENAME; } $path = $this->dir.'/'.static::CACHE_DIR.'/'.$cache_filename; file_put_contents($path, serialize($_core)); } // Берёт из кеша экземпляр системы. protected function restoreCoreFromCache() { global $_core; $cache_filename = static::CORE_CACHE_FILE; if (defined('BOOTSTRAP_CORE_CACHE_FILENAME') && is_string(BOOTSTRAP_CORE_CACHE_FILENAME)) { $cache_filename = BOOTSTRAP_CORE_CACHE_FILENAME; } $path = $this->dir.'/'.static::CACHE_DIR.'/'.$cache_filename; try { $serialized_core = file_get_contents($path); } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { return false; } else { throw $e; } } if (isset($_core)) { throw new RuntimeException('Global variable "$_core" already defined.'); } $_core = unserialize($serialized_core); $this->config = $_core->config; // @todo удалить Core::loadLib('db'); return true; } // Загрузка конфигурационного файла protected function configuration() { require_once $this->dir.'/config.inc.php'; require_once $this->dir.'/config.private.inc.php'; $this->config = $_cfg; } // Инициализация системы protected function core() { global $_core; if (isset($_core)) { throw new RuntimeException('Global variable "$_core" already defined.'); } $_core = new Core($this->config); } // Настройка подключения к БД protected function db() { global $_core; $_core->setDb($this->getDb()); } protected function getDb() { // @todo удалить Core::loadLib('db'); $db = new Db(array( 'host' => $this->config['DB']['Host'], 'user' => $this->config['DB']['User'], 'password' => $this->config['DB']['Password'], 'dbname' => $this->config['DB']['Database'], 'charset' => 'utf8', )); $db->setQueryCompiler(new DbQueryCompiler()); $db->setLogger(new ArrayLogger()); return $db; } // Настройка подключения к кеширующему серверу protected function cache() { global $_core; $cache = $this->getCache(); if ($cache) { $_core->setCache($cache); } } // Возвращает кеширующий объект. protected function getCache() { if (empty($this->config['Cache']['Driver'])) { return; } $class = 'Cache'.$this->config['Cache']['Driver']; $cache = new $class($this->config['Cache']); $cache->setLogger(new ArrayLogger()); if (defined('BOOTSTRAP_CACHE_PREFIX')) { $cache->setPrefix(BOOTSTRAP_CACHE_PREFIX); } return $cache; } // Настройка работы с сессиями protected function session() { if (PHP_SAPI === 'cli') { return; } if (!session_id()) { session_start(); } } // Обновление информации о модулях protected function modulesUpdate() { global $_core; $_core->modules->update($_core->db); } // Загрузка модулей системы protected function modules() { global $_core; foreach ($_core->db->getAll('SELECT * FROM `cms_core_modules` ORDER BY `mod_name`') as $data) { $_core->modules->add($data['mod_name'], unserialize($data['mod_data'])); } } // Автозагружаемые классы из модулей системы protected function modulesAutoload() { global $_core; $classmap_path = $this->dir.'/'.static::CACHE_DIR.'/classmap-modules.php'; try { $this->autoload_classmap += include $classmap_path; } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { $map = array(); foreach ($_core->modules as $module) { $map += $module->getClassMap(); } $code = '<?php return '.var_export($map, true).';'; file_put_contents($classmap_path, $code); $this->autoload_classmap += $map; } else { throw $e; } } } public function shutdownHandler() { // Ловим ошибки не переделанные в исключения $this->shutdownFatalError(); // Вывод сообщений об ошибках $this->shutdownErrorVisualization(); // Логирование времени работы $this->shutdownOverallTimeLogger(); if (defined('BOOTSTRAP_DEBUGBAR') && BOOTSTRAP_DEBUGBAR) { $this->shutdownDebugbar(); } } protected function shutdownFatalError() { if ($this->is_cli_or_ajax) { return; } $error = error_get_last(); if ($error) { if ($error['type'] & (E_ERROR | E_COMPILE_ERROR | E_PARSE)) { $this->e = new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']); } } } protected function shutdownErrorVisualization() { if ($this->is_cli_or_ajax) { return; } if (!$this->e) { return; } http_response_code(500); if (!ini_get('display_errors')) { return; } if (ini_get('html_errors')) { while (ob_get_level()) { ob_end_clean(); } ini_set('default_mimetype', 'text/html'); Diagnostic::handleException($this->e); return; } echo $this->e; } protected function getShutdownOverallTimeLogger() { if (!$this->config['Debug']['ShutdownLogger']) { return; } return new FileLogger($this->config['Log']['Root'].'requests.log'); } protected function shutdownOverallTimeLogger() { $logger = $this->getShutdownOverallTimeLogger(); if (!$logger) { return; } $time = microtime(true) - REQUEST_TIME_FLOAT; $ip = isset($_SERVER['REMOTE_ADDR']) ? "\t".$_SERVER['REMOTE_ADDR'] : "\t".'127.0.0.1'; $file = isset($_SERVER['REQUEST_URI']) ? "\t".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] : "\t".$_SERVER['SCRIPT_FILENAME']; $logger->info(number_format($time, 3).$ip.$file); } protected function shutdownDebugbar() { if ($this->is_cli_or_ajax) { return; } $bar = new DebugBar(); $bar->show(); } } class SystemBootstrapAdmin extends SystemBootstrap { const SESSION_USER_ID_KEY = 'core_user_id'; public function __construct() { parent::__construct(); $this->call('templatesUpdate'); $this->call('userInit'); } // Обновление информации о шаблонах сайтов protected function templatesUpdate() { foreach (CSites::getAll() as $site) { if (!$site->data['status'] || !$site->data['reindex_templates'] || !is_dir($site->templates_root)) { continue; } $site->updateTemplates(); } } // Инициализация и проверка авторизованности пользователя системы protected function userInit() { global $_core; if (isset($_SESSION[static::SESSION_USER_ID_KEY])) { try { $user = CUsers::getById($_SESSION[static::SESSION_USER_ID_KEY]); if ($user->getStatus()) { $_core->setUser($user); $user->updateActivity(); } } catch (UnexpectedValueException $e) { // Пользователь не найден } } if (!$_core->user) { http_location($this->config['Adm']['URL'].'index.php'); } } } class SystemBootstrapAdminModule extends SystemBootstrapAdmin { public function __construct() { parent::__construct(); $this->call('action'); } protected function environment() { parent::environment(); ob_start(array($this, 'responseOutputHandler')); } /* protected */ public function responseOutputHandler($buffer) { if (PHP_SAPI === 'cli' || (function_exists('http_is_ajax') && !http_is_ajax())) { return false; } $response_type = null; if (!empty($_GET['--type'])) { $response_type = (string)$_GET['--type']; } if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['--type'])) { $response_type = (string)$_POST['--type']; } if ($response_type === 'xml') { ini_set('default_mimetype', 'text/xml'); $buffer = '<data><![CDATA['.$buffer.']]></data>'; } return $buffer; } // Дествие protected function action() { global $_core; $module = $_core->modules->getModuleNameByFilename(realpath($_SERVER['SCRIPT_FILENAME'])); $_core->run($module, (string)@$_REQUEST['act']); if (isset($_SERVER['HTTP_HOST'])) { $style = $_core->action->_template->getStyle(); setcookie('style', $style, time() + 60 * 60 * 24 * 365 * 10, '/', $_SERVER['HTTP_HOST'], false, true); } } } class SystemBootstrapAdminLogin extends SystemBootstrapAdmin { public function __construct() { parent::__construct(); $this->call('userLogout'); $this->call('userLogin'); $this->call('userLoginPage'); } protected function templatesUpdate() { } protected function userInit() { } // Выход из системы пользователя protected function userLogout() { global $_core; if (isset($_GET['_logout'])) { unset($_SESSION[static::SESSION_USER_ID_KEY]); http_location($this->config['Adm']['URL'].'index.php'); } } // Авторизация пользователя protected function userLogin() { global $_core; if (!isset($_POST['login']) || !isset($_POST['password'])) { return; } unset($_SESSION[static::SESSION_USER_ID_KEY]); $user = CUsers::login((string)$_POST['login'], (string)$_POST['password']); if ($user) { $_SESSION[static::SESSION_USER_ID_KEY] = $user->getId(); http_location(Core::url(array($this->config['Modules']['DefaultModule'], true))); } } // Вывод страницы авторизации пользователя protected function userLoginPage() { $template = new CoreTemplate(); $template->setTemplate('login.php'); $template->setTitle('Вход в систему'); if (isset($_COOKIE['style'])) { if (preg_match('/^[A-Za-z0-9\\-]+$/', $_COOKIE['style'])) { $template->setStyle($_COOKIE['style']); } } $template->show(); } } class SystemBootstrapSite extends SystemBootstrap { public function __construct() { parent::__construct(); $this->call('site'); $this->call('auth'); $this->call('php'); } protected function modulesUpdate() { // Не требуется обновлять список модулей } // Сайт определяется по константе BOOTSTRAP_SITE_ID, а не по HTTP_HOST. protected function site() { if (!defined('BOOTSTRAP_SITE_ID')) { throw new RuntimeException('Не объявлена константа "BOOTSTRAP_SITE_ID".'); } try { CSites::setCurrentSiteById(BOOTSTRAP_SITE_ID); } catch (UnexpectedValueException $e) { throw new RuntimeException(sprintf('Не удалось установить сайт "%s".', BOOTSTRAP_SITE_ID), 0, $e); } } protected function auth() { $site = CSites::getCurrentSite(); if ($site->data['auth'] && (@$_SERVER['PHP_AUTH_USER'] !== $site->data['auth_login'] || @$_SERVER['PHP_AUTH_PW'] !== $site->data['auth_password'])) { http_authenticate(); } } protected function php() { $site = CSites::getCurrentSite(); $files = glob($site->root.'php/*.php'); if (is_array($files)) { foreach ($files as $filename) { require_once $filename; } } } // Вызывается только в классах-потомках. protected function templateVariablesToGlobalScape() { foreach (CTemplates::getAdditionalTemplateVariables() as $key => $value) { $GLOBALS[$key] = $value; } } } class SystemBootstrapSitePage extends SystemBootstrapSite { public function __construct() { parent::__construct(); $this->call('page'); } protected function page() { $url = $_SERVER['REQUEST_URI']; // Убираем параметры после ? $pos = mb_strpos($url, '?'); if ($pos !== false) { $url = mb_substr($url, 0, $pos); } // Поддержка старого page_id if (isset($_REQUEST['page_id']) && in_array($url, array('/', '/index.php'))) { $url = '/page'.(int)$_REQUEST['page_id']; } $vars = array(); $page = CContent::getPageByUrl(rawurldecode($url), $vars); if (defined('BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION')) { ob_start(BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION); } try { if (!$page) { throw new Exception404(); } foreach ($vars as $key => $value) { $_REQUEST[$key] = $value; $_GET[$key] = $value; } if (!CContent::showPage($page)) { throw new Exception404(); } } catch (HttpException $e) { $code = $e->getCode(); ob_clean(); http_response_code($code); if ($code === 404) { $site = CSites::getCurrentSite(); if (!$site) { throw new LogicException('Не установлен сайт.', 0, $e); } if (!empty($site->data['404'])) { try { $page = $site->getPage($site->data['404']); } catch (UnexpectedValueException $e) { $page = null; } if ($page) { CContent::showPage($page); } } } } if (defined('BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION')) { ob_end_flush(); } } } class SystemBootstrapSitePageCache extends SystemBootstrapSitePage { const CACHE_PREFIX = 'fullpage'; const CACHE_TIME = 60; const CSRF_TOKEN_PLACEHOLDER = 'CSRF_TOKEN_PLACEHOLDER'; const DEFAULT_FULLPAGE_CAСHE_VARIABLES = 'csrf'; protected $from_cache = true; protected function modulesAutoload() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::modulesAutoload(); } } protected function site() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::site(); } } protected function auth() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::auth(); } } protected function php() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::php(); } } protected function isPageCachable() { if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'GET' || !isset($_SERVER['REQUEST_URI'])) { return false; } if (!isset($_SESSION)) { return true; } $allowed_variables = defined('BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES') ? BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES : static::DEFAULT_FULLPAGE_CAСHE_VARIABLES; $allowed_variables = array_get_from_string($allowed_variables); foreach (array_keys($_SESSION) as $key) { if (!in_array((string)$key, $allowed_variables, true)) { return false; } } return true; } protected function page() { global $_core; if (!$this->isPageCachable()) { $this->from_cache = false; $this->call('modulesAutoload'); $this->call('site'); $this->call('auth'); $this->call('php'); parent::page(); return; } $cache = $_core->cache; if (!$cache) { throw new RuntimeException('Кеш не инициализирован.'); } $key = static::CACHE_PREFIX.BOOTSTRAP_SITE_ID.'_'.crc32($_SERVER['REQUEST_URI']); $html = $cache->get($key); if ($html) { if (!defined('BOOTSTRAP_FULLPAGE_CAСHE_HEADER') || BOOTSTRAP_FULLPAGE_CAСHE_HEADER) { header('FullpageCache: 1'); } // Подставляем персонализированный csrf-token $html = str_replace(static::CSRF_TOKEN_PLACEHOLDER, Core::csrf(), $html); echo $html; return; } $this->from_cache = false; $this->call('modulesAutoload'); $this->call('site'); $this->call('auth'); $this->call('php'); ob_start(); parent::page(); $html = ob_get_flush(); // Перепроверяем, вдруг добавились переменные в сессию (например: автологин) if ($this->isPageCachable()) { // Убираем персонализированный csrf-token. $html = str_replace('<meta name="csrf-token" value="'.Core::csrf().'">', '<meta name="csrf-token" value="'.static::CSRF_TOKEN_PLACEHOLDER.'">', $html); $cache->set($key, $html, defined('BOOTSTRAP_FULLPAGE_CAСHE_TIME') ? BOOTSTRAP_FULLPAGE_CAСHE_TIME : static::CACHE_TIME); } } } class SystemBootstrapSiteAjax extends SystemBootstrapSite { public function __construct() { parent::__construct(); $this->call('templateVariablesToGlobalScape'); } } class SystemBootstrapSiteCron extends SystemBootstrapSite { const LOCK_FILE_HANDLER_KEY = 'lock_file_handle'; public function __construct() { parent::__construct(); $this->call('lock'); $this->call('templateVariablesToGlobalScape'); } protected function auth() { } protected function lock() { $path = realpath($_SERVER['SCRIPT_FILENAME']); $handler = fopen($path.'.lock', 'a+b'); if (!flock($handler, LOCK_EX | LOCK_NB)) { exit; } $GLOBALS[static::LOCK_FILE_HANDLER_KEY] = $handler; } }
SystemBootstrapSitePage->__construct()
<?php /** * Возможные настройки константами: * * SKIP_BOOTSTRAP Не выполнять инициализацию системы этим файлом. * BOOTSTRAP Суффикс названия класса, инициализирующего систему. * BOOTSTRAP_DISPLAY_ERRORS Устанавливает настройку конфигурации php 'display_errors'. Если не объявлена, то устанавливается в true. * BOOTSTRAP_CACHE_PREFIX Префикс ключей при key-value кешировании. * BOOTSTRAP_CORE_CACHE Кешировать глобальный объект $_core. * BOOTSTRAP_CORE_CACHE_FILENAME Название файла, в который будет кешироваться глобальный объект $_core. Нужно, если система запускается с разными конфигами, например dev-версия. * BOOTSTRAP_DEBUGBAR Отображать ли отладочную информацию вверху страницы. * BOOTSTRAP_SITE_ID Идентификатор сайта, который нужно установить текущим. * BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION Функция, которая должна быть вызвана для преобразования сгенерированного html-кода запрашиваемой страницы сайта. * BOOTSTRAP_FULLPAGE_CAСHE_TIME Время в секундах, на которое будет кешироваться страница. По умолчанию 60. * BOOTSTRAP_FULLPAGE_CAСHE_HEADER Отправлять заголовок, указывающий, бралась ли страница из кеша. Если не объявлена, то устанавливается в true. * BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES Переменные сессии, которые могут быть установлены для возможности кеширования страницы. По умолчанию: csrf-token */ if (!defined('SKIP_BOOTSTRAP') || !SKIP_BOOTSTRAP) { if (!defined('BOOTSTRAP')) { define('BOOTSTRAP', ''); } $classname = 'SystemBootstrap'.BOOTSTRAP; return new $classname(); } class SystemBootstrap { const CACHE_DIR = 'cache'; const CORE_CACHE_AVAILABLE = true; const CORE_CACHE_FILE = 'core.cache'; protected $dir; protected $is_cli_or_ajax = false; protected $autoload_classmap = array(); protected $config; protected $e; public function __construct() { $this->dir = __DIR__; // Настройка $this->environment(); // Ошибки переделываются в исключения set_error_handler(array($this, 'errorToExceptionHandler')); // Регистрация автозагрузчика классов spl_autoload_register(array($this, 'autoload')); // Инициализация классов из vendor $this->vendor(); // Подгрузка из lib $this->lib(); // Автозагружаемые классы из lib $this->libAutoload(); // Требуется в нескольких методах $this->is_cli_or_ajax = PHP_SAPI === 'cli' || http_is_ajax(); // Ловим непойманные исключения $this->registerUncatchableExceptionHandler(); // Действия, выполняемые после завершения выполнения скрипта register_shutdown_function(array($this, 'shutdownHandler')); $this->call('initCoreOrGetFromCache'); $this->call('modulesAutoload'); $this->call('session'); } protected function call($method) { Benchmark::s('Bootstrap::'.$method); call_user_func(array($this, $method)); Benchmark::e('Bootstrap::'.$method); } public function autoload($class) { if (isset($this->autoload_classmap[$class])) { require_once $this->dir.'/'.$this->autoload_classmap[$class]; } } protected function environment() { if (version_compare(PHP_VERSION, '5.3.8', '<')) { exit('Require PHP 5.3.8 or higher.'); } ob_start(); error_reporting(E_ALL & ~E_STRICT); if (!defined('REQUEST_TIME_FLOAT')) { define('REQUEST_TIME_FLOAT', microtime(true)); } ini_set('display_errors', defined('BOOTSTRAP_DISPLAY_ERRORS') ? BOOTSTRAP_DISPLAY_ERRORS : true); ini_set('magic_quotes_runtime', false); ini_set('default_charset', 'UTF-8'); if (version_compare(PHP_VERSION, '5.6.0', '<')) { ini_set('mbstring.internal_encoding', 'UTF-8'); } if (!ini_get('date.timezone')) { ini_set('date.timezone', 'Europe/Moscow'); } setlocale(LC_ALL, 'ru_RU.UTF-8'); setlocale(LC_NUMERIC, 'C'); if (PHP_SAPI !== 'cli') { ini_set('html_errors', true); ini_set('default_mimetype', 'text/html'); header('Expires: '.date(DATE_RFC1123)); header('Last-Modified: '.date(DATE_RFC1123)); header('Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0'); } } protected function vendor() { require $this->dir.'/../vendor/autoload.php'; if (!defined('GD_VERSION')) { define('GD_VERSION', '2.0.1'); } } protected function lib() { require_once $this->dir.'/lib/init.inc.php'; } protected function libAutoload() { $classmap_path = $this->dir.'/'.static::CACHE_DIR.'/classmap-lib.php'; try { $this->autoload_classmap = include $classmap_path; } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { $files = array(); foreach (glob($this->dir.'/lib/*/autoload.php') as $path) { $local_files = include $path; foreach (include $path as $local_path) { $files[] = 'lib/'.basename(dirname($path)).'/'.$local_path; } } $map = array(); foreach ($files as $file) { $class = $this->getClassFromFile($this->dir.'/'.$file); if ($class !== null) { $map[$class] = $file; } } $code = '<?php return '.var_export($map, true).';'; file_put_contents($classmap_path, $code); $this->autoload_classmap += $map; } else { throw $e; } } $this->autoload_classmap = include $classmap_path; } protected function getClassFromFile($path) { $tokens = token_get_all(file_get_contents($path)); $namespace = ''; foreach ($tokens as $i => $token) { if (defined('T_NAMESPACE') && $token[0] === T_NAMESPACE) { for ($namespace_token_i = $i + 2; isset($tokens[$namespace_token_i]); $namespace_token_i += 2) { $namespace .= $tokens[$namespace_token_i][1].'\\'; if (!isset($tokens[$namespace_token_i + 1]) || !is_array($tokens[$namespace_token_i + 1]) || $tokens[$namespace_token_i + 1][0] !== T_NS_SEPARATOR) { break; } } continue; } if (in_array($token[0], array(T_CLASS, T_INTERFACE), true)) { return $namespace.$tokens[$i + 2][1]; } } return null; } /* protected */ public function errorToExceptionHandler($errno, $errstr, $errfile, $errline, $errcontext) { if (error_reporting() & $errno) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } return false; } protected function registerUncatchableExceptionHandler() { if (!$this->is_cli_or_ajax) { set_exception_handler(array($this, 'uncatchableExceptionHandler')); } } /* protected */ public function uncatchableExceptionHandler(Exception $e) { $this->e = $e; error_log($e); } // Инициализация системы. protected function initCoreOrGetFromCache() { $core_cache = static::CORE_CACHE_AVAILABLE && defined('BOOTSTRAP_CORE_CACHE') && BOOTSTRAP_CORE_CACHE; if (!$core_cache || !$this->restoreCoreFromCache()) { $this->call('configuration'); $this->call('core'); $this->call('db'); $this->call('cache'); $this->call('modulesUpdate'); $this->call('modules'); if ($core_cache) { $this->call('cacheCore'); } } } // Кеширование инициализированного экземпляра системы. protected function cacheCore() { global $_core; $cache_filename = static::CORE_CACHE_FILE; if (defined('BOOTSTRAP_CORE_CACHE_FILENAME') && is_string(BOOTSTRAP_CORE_CACHE_FILENAME)) { $cache_filename = BOOTSTRAP_CORE_CACHE_FILENAME; } $path = $this->dir.'/'.static::CACHE_DIR.'/'.$cache_filename; file_put_contents($path, serialize($_core)); } // Берёт из кеша экземпляр системы. protected function restoreCoreFromCache() { global $_core; $cache_filename = static::CORE_CACHE_FILE; if (defined('BOOTSTRAP_CORE_CACHE_FILENAME') && is_string(BOOTSTRAP_CORE_CACHE_FILENAME)) { $cache_filename = BOOTSTRAP_CORE_CACHE_FILENAME; } $path = $this->dir.'/'.static::CACHE_DIR.'/'.$cache_filename; try { $serialized_core = file_get_contents($path); } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { return false; } else { throw $e; } } if (isset($_core)) { throw new RuntimeException('Global variable "$_core" already defined.'); } $_core = unserialize($serialized_core); $this->config = $_core->config; // @todo удалить Core::loadLib('db'); return true; } // Загрузка конфигурационного файла protected function configuration() { require_once $this->dir.'/config.inc.php'; require_once $this->dir.'/config.private.inc.php'; $this->config = $_cfg; } // Инициализация системы protected function core() { global $_core; if (isset($_core)) { throw new RuntimeException('Global variable "$_core" already defined.'); } $_core = new Core($this->config); } // Настройка подключения к БД protected function db() { global $_core; $_core->setDb($this->getDb()); } protected function getDb() { // @todo удалить Core::loadLib('db'); $db = new Db(array( 'host' => $this->config['DB']['Host'], 'user' => $this->config['DB']['User'], 'password' => $this->config['DB']['Password'], 'dbname' => $this->config['DB']['Database'], 'charset' => 'utf8', )); $db->setQueryCompiler(new DbQueryCompiler()); $db->setLogger(new ArrayLogger()); return $db; } // Настройка подключения к кеширующему серверу protected function cache() { global $_core; $cache = $this->getCache(); if ($cache) { $_core->setCache($cache); } } // Возвращает кеширующий объект. protected function getCache() { if (empty($this->config['Cache']['Driver'])) { return; } $class = 'Cache'.$this->config['Cache']['Driver']; $cache = new $class($this->config['Cache']); $cache->setLogger(new ArrayLogger()); if (defined('BOOTSTRAP_CACHE_PREFIX')) { $cache->setPrefix(BOOTSTRAP_CACHE_PREFIX); } return $cache; } // Настройка работы с сессиями protected function session() { if (PHP_SAPI === 'cli') { return; } if (!session_id()) { session_start(); } } // Обновление информации о модулях protected function modulesUpdate() { global $_core; $_core->modules->update($_core->db); } // Загрузка модулей системы protected function modules() { global $_core; foreach ($_core->db->getAll('SELECT * FROM `cms_core_modules` ORDER BY `mod_name`') as $data) { $_core->modules->add($data['mod_name'], unserialize($data['mod_data'])); } } // Автозагружаемые классы из модулей системы protected function modulesAutoload() { global $_core; $classmap_path = $this->dir.'/'.static::CACHE_DIR.'/classmap-modules.php'; try { $this->autoload_classmap += include $classmap_path; } catch (ErrorException $e) { if (mb_strpos($e->getMessage(), 'failed to open stream') !== false) { $map = array(); foreach ($_core->modules as $module) { $map += $module->getClassMap(); } $code = '<?php return '.var_export($map, true).';'; file_put_contents($classmap_path, $code); $this->autoload_classmap += $map; } else { throw $e; } } } public function shutdownHandler() { // Ловим ошибки не переделанные в исключения $this->shutdownFatalError(); // Вывод сообщений об ошибках $this->shutdownErrorVisualization(); // Логирование времени работы $this->shutdownOverallTimeLogger(); if (defined('BOOTSTRAP_DEBUGBAR') && BOOTSTRAP_DEBUGBAR) { $this->shutdownDebugbar(); } } protected function shutdownFatalError() { if ($this->is_cli_or_ajax) { return; } $error = error_get_last(); if ($error) { if ($error['type'] & (E_ERROR | E_COMPILE_ERROR | E_PARSE)) { $this->e = new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']); } } } protected function shutdownErrorVisualization() { if ($this->is_cli_or_ajax) { return; } if (!$this->e) { return; } http_response_code(500); if (!ini_get('display_errors')) { return; } if (ini_get('html_errors')) { while (ob_get_level()) { ob_end_clean(); } ini_set('default_mimetype', 'text/html'); Diagnostic::handleException($this->e); return; } echo $this->e; } protected function getShutdownOverallTimeLogger() { if (!$this->config['Debug']['ShutdownLogger']) { return; } return new FileLogger($this->config['Log']['Root'].'requests.log'); } protected function shutdownOverallTimeLogger() { $logger = $this->getShutdownOverallTimeLogger(); if (!$logger) { return; } $time = microtime(true) - REQUEST_TIME_FLOAT; $ip = isset($_SERVER['REMOTE_ADDR']) ? "\t".$_SERVER['REMOTE_ADDR'] : "\t".'127.0.0.1'; $file = isset($_SERVER['REQUEST_URI']) ? "\t".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] : "\t".$_SERVER['SCRIPT_FILENAME']; $logger->info(number_format($time, 3).$ip.$file); } protected function shutdownDebugbar() { if ($this->is_cli_or_ajax) { return; } $bar = new DebugBar(); $bar->show(); } } class SystemBootstrapAdmin extends SystemBootstrap { const SESSION_USER_ID_KEY = 'core_user_id'; public function __construct() { parent::__construct(); $this->call('templatesUpdate'); $this->call('userInit'); } // Обновление информации о шаблонах сайтов protected function templatesUpdate() { foreach (CSites::getAll() as $site) { if (!$site->data['status'] || !$site->data['reindex_templates'] || !is_dir($site->templates_root)) { continue; } $site->updateTemplates(); } } // Инициализация и проверка авторизованности пользователя системы protected function userInit() { global $_core; if (isset($_SESSION[static::SESSION_USER_ID_KEY])) { try { $user = CUsers::getById($_SESSION[static::SESSION_USER_ID_KEY]); if ($user->getStatus()) { $_core->setUser($user); $user->updateActivity(); } } catch (UnexpectedValueException $e) { // Пользователь не найден } } if (!$_core->user) { http_location($this->config['Adm']['URL'].'index.php'); } } } class SystemBootstrapAdminModule extends SystemBootstrapAdmin { public function __construct() { parent::__construct(); $this->call('action'); } protected function environment() { parent::environment(); ob_start(array($this, 'responseOutputHandler')); } /* protected */ public function responseOutputHandler($buffer) { if (PHP_SAPI === 'cli' || (function_exists('http_is_ajax') && !http_is_ajax())) { return false; } $response_type = null; if (!empty($_GET['--type'])) { $response_type = (string)$_GET['--type']; } if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['--type'])) { $response_type = (string)$_POST['--type']; } if ($response_type === 'xml') { ini_set('default_mimetype', 'text/xml'); $buffer = '<data><![CDATA['.$buffer.']]></data>'; } return $buffer; } // Дествие protected function action() { global $_core; $module = $_core->modules->getModuleNameByFilename(realpath($_SERVER['SCRIPT_FILENAME'])); $_core->run($module, (string)@$_REQUEST['act']); if (isset($_SERVER['HTTP_HOST'])) { $style = $_core->action->_template->getStyle(); setcookie('style', $style, time() + 60 * 60 * 24 * 365 * 10, '/', $_SERVER['HTTP_HOST'], false, true); } } } class SystemBootstrapAdminLogin extends SystemBootstrapAdmin { public function __construct() { parent::__construct(); $this->call('userLogout'); $this->call('userLogin'); $this->call('userLoginPage'); } protected function templatesUpdate() { } protected function userInit() { } // Выход из системы пользователя protected function userLogout() { global $_core; if (isset($_GET['_logout'])) { unset($_SESSION[static::SESSION_USER_ID_KEY]); http_location($this->config['Adm']['URL'].'index.php'); } } // Авторизация пользователя protected function userLogin() { global $_core; if (!isset($_POST['login']) || !isset($_POST['password'])) { return; } unset($_SESSION[static::SESSION_USER_ID_KEY]); $user = CUsers::login((string)$_POST['login'], (string)$_POST['password']); if ($user) { $_SESSION[static::SESSION_USER_ID_KEY] = $user->getId(); http_location(Core::url(array($this->config['Modules']['DefaultModule'], true))); } } // Вывод страницы авторизации пользователя protected function userLoginPage() { $template = new CoreTemplate(); $template->setTemplate('login.php'); $template->setTitle('Вход в систему'); if (isset($_COOKIE['style'])) { if (preg_match('/^[A-Za-z0-9\\-]+$/', $_COOKIE['style'])) { $template->setStyle($_COOKIE['style']); } } $template->show(); } } class SystemBootstrapSite extends SystemBootstrap { public function __construct() { parent::__construct(); $this->call('site'); $this->call('auth'); $this->call('php'); } protected function modulesUpdate() { // Не требуется обновлять список модулей } // Сайт определяется по константе BOOTSTRAP_SITE_ID, а не по HTTP_HOST. protected function site() { if (!defined('BOOTSTRAP_SITE_ID')) { throw new RuntimeException('Не объявлена константа "BOOTSTRAP_SITE_ID".'); } try { CSites::setCurrentSiteById(BOOTSTRAP_SITE_ID); } catch (UnexpectedValueException $e) { throw new RuntimeException(sprintf('Не удалось установить сайт "%s".', BOOTSTRAP_SITE_ID), 0, $e); } } protected function auth() { $site = CSites::getCurrentSite(); if ($site->data['auth'] && (@$_SERVER['PHP_AUTH_USER'] !== $site->data['auth_login'] || @$_SERVER['PHP_AUTH_PW'] !== $site->data['auth_password'])) { http_authenticate(); } } protected function php() { $site = CSites::getCurrentSite(); $files = glob($site->root.'php/*.php'); if (is_array($files)) { foreach ($files as $filename) { require_once $filename; } } } // Вызывается только в классах-потомках. protected function templateVariablesToGlobalScape() { foreach (CTemplates::getAdditionalTemplateVariables() as $key => $value) { $GLOBALS[$key] = $value; } } } class SystemBootstrapSitePage extends SystemBootstrapSite { public function __construct() { parent::__construct(); $this->call('page'); } protected function page() { $url = $_SERVER['REQUEST_URI']; // Убираем параметры после ? $pos = mb_strpos($url, '?'); if ($pos !== false) { $url = mb_substr($url, 0, $pos); } // Поддержка старого page_id if (isset($_REQUEST['page_id']) && in_array($url, array('/', '/index.php'))) { $url = '/page'.(int)$_REQUEST['page_id']; } $vars = array(); $page = CContent::getPageByUrl(rawurldecode($url), $vars); if (defined('BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION')) { ob_start(BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION); } try { if (!$page) { throw new Exception404(); } foreach ($vars as $key => $value) { $_REQUEST[$key] = $value; $_GET[$key] = $value; } if (!CContent::showPage($page)) { throw new Exception404(); } } catch (HttpException $e) { $code = $e->getCode(); ob_clean(); http_response_code($code); if ($code === 404) { $site = CSites::getCurrentSite(); if (!$site) { throw new LogicException('Не установлен сайт.', 0, $e); } if (!empty($site->data['404'])) { try { $page = $site->getPage($site->data['404']); } catch (UnexpectedValueException $e) { $page = null; } if ($page) { CContent::showPage($page); } } } } if (defined('BOOTSTRAP_PAGE_POST_PROCESS_FUNCTION')) { ob_end_flush(); } } } class SystemBootstrapSitePageCache extends SystemBootstrapSitePage { const CACHE_PREFIX = 'fullpage'; const CACHE_TIME = 60; const CSRF_TOKEN_PLACEHOLDER = 'CSRF_TOKEN_PLACEHOLDER'; const DEFAULT_FULLPAGE_CAСHE_VARIABLES = 'csrf'; protected $from_cache = true; protected function modulesAutoload() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::modulesAutoload(); } } protected function site() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::site(); } } protected function auth() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::auth(); } } protected function php() { // Вызывается только, если страница не взята из кеша. if (!$this->from_cache) { return parent::php(); } } protected function isPageCachable() { if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'GET' || !isset($_SERVER['REQUEST_URI'])) { return false; } if (!isset($_SESSION)) { return true; } $allowed_variables = defined('BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES') ? BOOTSTRAP_FULLPAGE_CAСHE_VARIABLES : static::DEFAULT_FULLPAGE_CAСHE_VARIABLES; $allowed_variables = array_get_from_string($allowed_variables); foreach (array_keys($_SESSION) as $key) { if (!in_array((string)$key, $allowed_variables, true)) { return false; } } return true; } protected function page() { global $_core; if (!$this->isPageCachable()) { $this->from_cache = false; $this->call('modulesAutoload'); $this->call('site'); $this->call('auth'); $this->call('php'); parent::page(); return; } $cache = $_core->cache; if (!$cache) { throw new RuntimeException('Кеш не инициализирован.'); } $key = static::CACHE_PREFIX.BOOTSTRAP_SITE_ID.'_'.crc32($_SERVER['REQUEST_URI']); $html = $cache->get($key); if ($html) { if (!defined('BOOTSTRAP_FULLPAGE_CAСHE_HEADER') || BOOTSTRAP_FULLPAGE_CAСHE_HEADER) { header('FullpageCache: 1'); } // Подставляем персонализированный csrf-token $html = str_replace(static::CSRF_TOKEN_PLACEHOLDER, Core::csrf(), $html); echo $html; return; } $this->from_cache = false; $this->call('modulesAutoload'); $this->call('site'); $this->call('auth'); $this->call('php'); ob_start(); parent::page(); $html = ob_get_flush(); // Перепроверяем, вдруг добавились переменные в сессию (например: автологин) if ($this->isPageCachable()) { // Убираем персонализированный csrf-token. $html = str_replace('<meta name="csrf-token" value="'.Core::csrf().'">', '<meta name="csrf-token" value="'.static::CSRF_TOKEN_PLACEHOLDER.'">', $html); $cache->set($key, $html, defined('BOOTSTRAP_FULLPAGE_CAСHE_TIME') ? BOOTSTRAP_FULLPAGE_CAСHE_TIME : static::CACHE_TIME); } } } class SystemBootstrapSiteAjax extends SystemBootstrapSite { public function __construct() { parent::__construct(); $this->call('templateVariablesToGlobalScape'); } } class SystemBootstrapSiteCron extends SystemBootstrapSite { const LOCK_FILE_HANDLER_KEY = 'lock_file_handle'; public function __construct() { parent::__construct(); $this->call('lock'); $this->call('templateVariablesToGlobalScape'); } protected function auth() { } protected function lock() { $path = realpath($_SERVER['SCRIPT_FILENAME']); $handler = fopen($path.'.lock', 'a+b'); if (!flock($handler, LOCK_EX | LOCK_NB)) { exit; } $GLOBALS[static::LOCK_FILE_HANDLER_KEY] = $handler; } }
require_once('/home/host1864002/admin.infomine.ru/htdocs/www/cms_adm/init.inc....')
<?php if (!defined('BOOTSTRAP')) { define('BOOTSTRAP', 'SitePage'); // SitePageCache, если нужно кешировать страницу полностью. // Время кеширования страницы. define('BOOTSTRAP_FULLPAGE_CAСHE_TIME', 10); } // Идентификатор сайта. define('BOOTSTRAP_SITE_ID', 6); // Отображать ли ошибки на сайте. if (!defined('BOOTSTRAP_DISPLAY_ERRORS')) { define('BOOTSTRAP_DISPLAY_ERRORS', true); } // Отображать ли отладочную информацию сверху страницы. if (!defined('BOOTSTRAP_DEBUGBAR')) { define('BOOTSTRAP_DEBUGBAR', isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] === '77.50.238.108'); } // Включить ли кеширование инициализации core. if (!defined('BOOTSTRAP_CORE_CACHE')) { define('BOOTSTRAP_CORE_CACHE', true); } require_once __DIR__.'/../../../admin.infomine.ru/htdocs/www/cms_adm/init.inc.php';