diff --git a/src/Collection.php b/src/Collection.php index ccc60cf..d2f662d 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -4,7 +4,7 @@ namespace ctiso; /** * Коллекция - * + * */ class Collection implements \ArrayAccess { @@ -59,7 +59,7 @@ class Collection implements \ArrayAccess return isset($this->data[$key]) && $this->data[$key] != '' ? $this->data[$key] : $default; } - public function getInt($key, $default = 0) + public function getInt($key, $default = 0) { return (int)$this->get($key, $default); } @@ -72,7 +72,7 @@ class Collection implements \ArrayAccess public function getNat($key, $default = 1) { $result = (int)$this->get($key, $default); - return (($result > 0) ? $result : $default); + return (($result > 0) ? $result : $default); } public function clear() diff --git a/src/Controller/Component.php b/src/Controller/Component.php index 655fbd5..ed19057 100644 --- a/src/Controller/Component.php +++ b/src/Controller/Component.php @@ -88,6 +88,11 @@ class Component } } + public function getTemplateName($_registry/*: Settings*/) { + return (isset($_COOKIE['with_template']) && preg_match('/^[\w\d-]{3,20}$/', $_COOKIE['with_template'])) + ? $_COOKIE['with_template'] : ($_registry ? $_registry->get('site', 'template') : 'modern'); + } + public function getView($name) { if ($this->output == 'json') { @@ -96,12 +101,13 @@ class Component $config/*: Registry*/ = $this->config; $default = $config->get('site', 'template'); - $template = ($this->template) ? $this->template : $default; + $template = ($this->template) ? $this->template : $this->getTemplateName($config); $selected = null; foreach ($this->viewPath as $index => $viewPath) { // Загружать шаблон по умолчанию если не найден текущий - if(is_dir(Path::join($this->viewPath[$index], 'templates', $template))) { + $dir = Path::join($this->viewPath[$index], 'templates', $template); + if(is_dir($dir)) { $tpl = new PHPTAL(Path::join($this->viewPath[$index], 'templates', $template, $name)); $tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION); $selected = $index; @@ -110,10 +116,11 @@ class Component } if ($selected === null) { - $tpl = new PHPTAL(Path::join($this->viewPath[0], 'templates', 'modern', $name)); + // Последний вариант viewPath, путь к папке компонента + $selected = count($this->viewPath) - 1; + $tpl = new PHPTAL(Path::join($this->viewPath[$selected], 'templates', 'modern', $name)); $tpl->setPhpCodeDestination(PHPTAL_PHP_CODE_DESTINATION); $template = 'modern'; - $selected = 0; } $tpl->stripComments(true); @@ -135,13 +142,26 @@ class Component return $tpl; } + function _getDefaultPath() { + return $this->viewPath[count($this->viewPath) - 1]; + } + public function getTemplatePath($name) { - return Path::join($this->viewPath[0], 'templates', 'modern', $name); + $registry/*: Settings*/ = $this->config; + // Брать настройки из куков если есть + $template = ($this->template) ? $this->template : $this->getTemplateName($registry); + foreach ($this->viewPath as $index => $viewPath) { + if(is_dir(Path::join($this->viewPath[$index], 'templates', $template))) { + return Path::join($this->viewPath[$index], 'templates', $template, $name); + } + } + + return Path::join($this->viewPath[count($this->viewPath) - 1], 'templates', 'modern', $name); } public function getTemplateWebPath() { - return Path::join($this->webPath[0], 'templates', 'modern'); + return Path::join($this->webPath[count($this->webPath) - 1], 'templates', 'modern'); } /** @@ -184,7 +204,7 @@ class Component } function getInfo() { - $filename = $this->findFile($this->viewPath, 'install.json'); + $filename = Path::join($this->viewPath[count($this->viewPath) - 1], 'install.json'); if (file_exists($filename)) { $settings = json_decode(File::getContents($filename), true); return $settings; @@ -197,10 +217,10 @@ class Component */ public function setParameters($view/*: Composite*/, $options = null) { - $form = new Form(); + $form = new Form(); $settings = $this->getInfo(); - $form->addFieldList($settings['parameter'], $options); + $form->addFieldList($settings['parameter'], $options); $view->form = $form; $view->component = $settings['component']; @@ -224,7 +244,7 @@ class Component } $name = $path; - $path = Path::join ($this->config->get('site', 'path'), 'components', $name, $name . '.php'); + $path = Path::join ($site->config->get('site', 'path'), 'components', $name, $name . '.php'); $className = 'Component_' . $name; $component/*: Component*/ = null; @@ -233,19 +253,37 @@ class Component require_once ($path); $component = new $className(); - $component->viewPath = array($this->config->get('site', 'path') . '/components/' . $name . '/'); - $component->webPath = array($this->config->get('site', 'web') . '/components/' . $name); - $component->COMPONENTS_WEB = $this->config->get('site', 'web') . '/components/'; + $component->viewPath = array($site->config->get('site', 'path') . '/components/' . $name . '/'); + $component->webPath = array($site->config->get('site', 'web') . '/components/' . $name); + $component->COMPONENTS_WEB = $site->config->get('site', 'web') . '/components/'; } else { - $path = Path::join ($this->config->get('system', 'components'), $name, $name . '.php'); + $path = Path::join ($site->config->get('system', 'components'), $name, $name . '.php'); require_once ($path); $component = new $className(); - $component->viewPath = array($this->config->get('system', 'components') . '/' . $name . '/', $this->config->get('site', 'path') . '/components/' . $name . '/'); + $template = $component->getTemplateName($registry); + + $component->viewPath = array( + // Сначало ищем локально + $site->config->get('site', 'path') . '/templates/' . $template . '/_components/' . $name . '/', + $site->config->get('site', 'path') . '/components/' . $name . '/', + // Потом в общем хранилище + CMS_PATH . '/../templates/' . $template . '/_components/' . $name . '/', + $site->config->get('system', 'components') . '/' . $name . '/', + ); if (defined('COMPONENTS_WEB')) { - $component->webPath = array($this->config->get('system', 'components_web') . '/' . $name, $this->config->get('site', 'web') . '/components/' . $name); - $component->COMPONENTS_WEB = $this->config->get('system', 'components_web'); + $component->webPath = array( + // Сначало локально + $site->config->get('site', 'web') . '/templates/' . $template . '/_components/' . $name, + $site->config->get('site', 'web') . '/components/' . $name, + // Потом в общем хранилище + TEMPLATE_WEB . '/' . $template . '/_components/' . $name, + COMPONENTS_WEB . '/' . $name, + ); + $component->COMPONENTS_WEB = COMPONENTS_WEB; + } else { + $component->webPath = array('', $site->config->get('site', 'web') . '/components/' . $name, ''); } } diff --git a/src/Controller/Front.php b/src/Controller/Front.php index bc4096c..b8c3bae 100644 --- a/src/Controller/Front.php +++ b/src/Controller/Front.php @@ -41,7 +41,7 @@ class Front extends Action /** * Создает экземпляр модуля и выполняет действия для него * @param string $name Имя модуля - * @param request $request Имя модуля + * @param Request $request Имя модуля * @return string */ public function loadModule($name, Collection $request, $controller = null) @@ -55,8 +55,6 @@ class Front extends Action $moulesPath = Path::join($config->get('system', 'path'), 'modules'); $logPath = Path::join($config->get('site', 'path'), $config->get('system', 'access.log')); - $moduleFile = Path::join($moulesPath, $name, 'classes', $controller ? $controller : $name); - $ucname = ucfirst($name); $moduleClass = "Modules\\$ucname\\$ucname"; $module = new $moduleClass(); diff --git a/src/Controller/Request.php b/src/Controller/Request.php index b9e77e9..81fbc46 100644 --- a/src/Controller/Request.php +++ b/src/Controller/Request.php @@ -12,7 +12,7 @@ class Request { $this->id = $id; } - function get($name, $def) { + function get($name, $def = null) { $v = $this->r->get($name); $id = $this->id; if ($id && is_array($v)) { diff --git a/src/Controller/Service.php b/src/Controller/Service.php index 4992e50..cccecdf 100644 --- a/src/Controller/Service.php +++ b/src/Controller/Service.php @@ -5,6 +5,7 @@ */ namespace ctiso\Controller; use ctiso\Path, + ctiso\File, ctiso\Registry, ctiso\Database\PDOStatement; @@ -16,7 +17,7 @@ class Service public $template; public $templatePath; public $COMPONENTS_WEB; - + public $db; public function getTemplatePath($name) @@ -30,7 +31,7 @@ class Service } /** - * @param $name Имя модели + * @param string $name Имя модели */ private function getModelPath($name) { @@ -40,7 +41,7 @@ class Service /** * Создает модель * @param string $name - * @return model + * @return Model */ public function getModel($name) { @@ -66,5 +67,14 @@ class Service } return $result; } + + function getInfo() { + $filename = Path::join($this->viewPath[0], 'install.json'); + if (file_exists($filename)) { + $settings = json_decode(File::getContents($filename), true); + return $settings; + } + return array(); + } } diff --git a/src/Database.php b/src/Database.php index ebf717c..3cb15b6 100644 --- a/src/Database.php +++ b/src/Database.php @@ -18,7 +18,7 @@ use PDO, /** * Класс оболочка для PDO для замены Creole */ -class Database extends PDO +class Database/**/ extends PDO { public $dsn; @@ -26,8 +26,14 @@ class Database extends PDO { parent::__construct($dsn, $username, $password); $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('ctiso\\Database\\PDOStatement', array())); } + + function prepare($sql, $args = []) { + $result/*: PDOStatement*/ = parent::prepare($sql, $args); + return $result; + } public function getDSN() { @@ -48,6 +54,10 @@ class Database extends PDO if ($dsn['phptype'] == 'pgsql') { $connection->query('SET client_encoding="UTF-8"'); } + + if (isset($dsn['schema'])) { + $connection->query('SET search_path TO ' . $dsn['schema']); + } } if ($dsn['phptype'] == 'sqlite') { $connection/*: Database*/ = new static("{$dsn['phptype']}:{$dsn['database']}"); @@ -133,7 +143,6 @@ class Database extends PDO $sql = "INSERT INTO $table (" . implode(",", array_keys($values)) . ") VALUES (" . implode(",", array_keys($prep)). ")"; - if ($return_id) { if ($this->isPostgres()){ $sql = $sql." RETURNING $index"; @@ -181,11 +190,6 @@ class Database extends PDO return $result['nextval']; } - function prepare($query, $options = NULL) { - $result/*: PDOStatement*/ = parent::prepare($query); - return $result; - } - function close() { return null; } diff --git a/src/Database/PDOStatement.php b/src/Database/PDOStatement.php index 7d5b3fe..d837669 100644 --- a/src/Database/PDOStatement.php +++ b/src/Database/PDOStatement.php @@ -12,7 +12,7 @@ class PDOStatement extends \PDOStatement implements \IteratorAggregate public $cache = array(); public $fields; - function getIterator() { + function getIterator(): Iterator { return new StatementIterator($this); } @@ -72,6 +72,9 @@ class PDOStatement extends \PDOStatement implements \IteratorAggregate } function getInt($name) { + if (!$this->fields) { + throw new Error('no fields'); + } return (int)$this->fields[$name]; } @@ -80,7 +83,7 @@ class PDOStatement extends \PDOStatement implements \IteratorAggregate } function getString($name) { - return $this->fields[$name]; + return isset($this->fields[$name]) ? $this->fields[$name]: null; } function getBoolean($name) { @@ -98,4 +101,10 @@ class PDOStatement extends \PDOStatement implements \IteratorAggregate function getRecordCount() { return count($this->cache); } + + function execute($args = null) { + $result = parent::execute($args); + return $result; + } + } diff --git a/src/Database/Statement.php b/src/Database/Statement.php index b25b008..38652e5 100644 --- a/src/Database/Statement.php +++ b/src/Database/Statement.php @@ -21,33 +21,27 @@ class Statement $this->conn = $conn; } - function setInt($n, $value) - { + function setInt($n, $value) { $this->binds [] = array($n, $value, PDO::PARAM_INT); } - function setString($n, $value) - { + function setString($n, $value) { $this->binds [] = array($n, $value, PDO::PARAM_STR); } - function setBlob($n, $value) - { + function setBlob($n, $value) { $this->binds [] = array($n, $value, PDO::PARAM_LOB); } - function setLimit($limit) - { + function setLimit($limit) { $this->limit = $limit; } - function setOffset($offset) - { + function setOffset($offset) { $this->offset = $offset; } - function executeQuery() - { + function executeQuery() { if ($this->limit) { $this->query .= " LIMIT {$this->limit} OFFSET {$this->offset}"; } diff --git a/src/Excel/Number.php b/src/Excel/Number.php index be5fba2..8ed12b4 100644 --- a/src/Excel/Number.php +++ b/src/Excel/Number.php @@ -8,7 +8,7 @@ class Number function __construct($value) { - $this->value = (int)$value; + $this->value = (int)($value); } function getString() diff --git a/src/Filter/ActionLogger.php b/src/Filter/ActionLogger.php index 09f497c..b2b02ff 100644 --- a/src/Filter/ActionLogger.php +++ b/src/Filter/ActionLogger.php @@ -28,8 +28,8 @@ class ActionLogger function execute(HttpRequest $request) { $action = $request->getAction(); if(in_array($action, $this->before)) { - $message = ["time" => date("r", time()), "query" => array_merge($_POST, $_GET), "user" => $this->user->getName()]; - fwrite($this->file, json_encode($message) . "\n"); + $line = ['time' => time(), 'user' => $this->user->getName(), 'sid' => session_id(), 'query' => array_merge($_POST, $_GET)]; + fwrite($this->file, json_encode($line) . "\n"); } return $this->processor->execute($request); } diff --git a/src/Filter/Login.php b/src/Filter/Login.php index 4362bc7..e17205b 100644 --- a/src/Filter/Login.php +++ b/src/Filter/Login.php @@ -3,36 +3,41 @@ /** * Фильтр для проверки авторизации * - * action: login(password, login) + * action: login(password, login) * action: logout() */ -// В класс авторизации передавать обьект для управления пользователем +// В класс авторизации передавать обьект для управления пользователем // Вынести в отдельный файл namespace ctiso\Filter; use ctiso\Filter\Filter, ctiso\HttpRequest, ctiso\Settings, + ctiso\Registry, ctiso\Database, ctiso\Role\User, - ctiso\Collection; + ctiso\Collection, + ctiso\Path; class Login extends Filter { const SESSION_BROWSER_SIGN_SECRET = '@w3dsju45Msk#'; const SESSION_BROWSER_SIGN_KEYNAME = 'session.app.browser.sign'; - + const AUTH_MAX_ATTEMPT = 10; + const AUTH_LAST_ATTEMPT_TIMER = 600; public $mode = 'ajax'; public $user; - public $role/*: User*/; - public $whitelist; + public $role; + public $config; - function __construct($processor, $role, $whitelist = []) { + function __construct($processor, User $role, Registry $config) { parent::__construct($processor); $this->role = $role; - $this->whitelist = $whitelist; + $this->config = $config; } + /** * Проверка авторизации + * @param HttpRequest $request * @return Boolean Авторизовани пользователь или нет */ public function isLoggin(HttpRequest $request) @@ -41,27 +46,56 @@ class Login extends Filter session_start(); switch ($request->getAction()) { // Авторизация по постоянному паролю - case 'login': - $login = $request->get('login'); + case 'login': + $login = $request->get('login'); $password = $request->get('password'); $result = $this->role->getUserByLogin($login); // Поиск по логину if ($result) { $userPassword = $this->role->getUserPassword($result); + if ($this->role->access == 'site_root' && defined('PARENT_PATH')) { + $s = new Settings(PARENT_PATH . '/settings.json'); + $s->read(); + $dsn = $s->readKey(array('system', 'dsn')); + + $db = Database::getConnection($dsn); + $user = $db->fetchOneArray("SELECT * FROM users WHERE login = :login", ['login' => $login]); + $userPassword = $user['password']; + } /*else if (time() - $result->getInt('lastupdate') > 60*60*24*60) { + // Проверить давность пароля, 60 дней + $request->set('error', true); + $request->set('lastupdate', true); + return false; + }*/ + // Проверка на количества попыток авторизации + $lastAttempt = $result; + + if ($lastAttempt->get('trie_count') >= self::AUTH_MAX_ATTEMPT /*&& time() - $lastAttempt['trie_time'] < self::AUTH_LAST_ATTEMPT_TIMER*/) { + if (time() - $lastAttempt->get('trie_time') < self::AUTH_LAST_ATTEMPT_TIMER) { + $request->set('timeout_error', true); + break; + } else { + $this->role->resetTries($request->get('login')); + } + } // Извлечнеие пользователя из родительской CMS, для проверки пароля if (md5($password) == $userPassword) { // password $this->enter($result); return true; - } + } else { + // Обновление количества неудачных попыток входа + $this->role->updateTries($login); + } } $request->set('error', true); break; case 'logout': // Выход session_destroy(); break; - // Вход по временному паролю + // Вход по временному паролю, не используется + /* case 'enter': - $login = $request->get('login'); + $login = $request->get('login'); $password = $request->get('sid'); $result = $this->role->getUserByLogin($login); // Поиск по логину if ($result) { @@ -69,9 +103,10 @@ class Login extends Filter if ($password == $temp) { $this->enter($result); return true; - } + } } break; + */ default: $hash = $this->getBrowserSign(); // Если $hash не совпадает $_SESSION['hash'] то удаляем сессию @@ -107,9 +142,9 @@ class Login extends Filter $random = rand(0, 1024 * 1024); $this->role->setSID($random, $result); - // $_SESSION["group"] = $result->getInt('access'); - $_SESSION["access"] = $result->getInt('id_user'); - $_SESSION["random"] = $random; + $_SESSION["group"] = $result->getInt('access'); + $_SESSION["access"] = $result->getInt('id_user'); // id_user + $_SESSION["random"] = $random; // id_user $_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME] = $this->getBrowserSign(); $_SESSION["time"] = time(); } @@ -133,15 +168,15 @@ class Login extends Filter if ($logged) { return json_encode(array('result' => 'ok', 'message' => "Авторизация успешна")); } else { - return json_encode(array('result' => 'fail', 'message' => "Неправильное имя пользователя или пароль")); + return json_encode(array('result' => 'fail', 'message' => "Неправильное имя пользователя или пароль")); } } if (!$logged) { // Параметры при неправильной авторизации - // Действия по умолчанию !! Возможно переход на форму регистрации + // Действия по умолчанию !! Возможно переход на форму регистрации if ($request->get('mode') == 'ajax') { - if (!$this->requestIsWhite($request, $this->whitelist)) { + if (!$this->requestIsWhite($request)) { return json_encode(array('result' => 'fail', 'message' =>"NOT_AUTHORIZED")); } } else { @@ -159,15 +194,20 @@ class Login extends Filter $text = $this->processor->execute($request); return $text; } - + /* --------------------- * Проверка на попадание реквеста в белый список */ - public function requestIsWhite(HttpRequest $request, $whiteRequestList){ + public function requestIsWhite(Collection $request) { $module = $request->get('module'); $action = $request->get('action'); - foreach ($whiteRequestList as $whiteRequest) { - if ($module == $whiteRequest['module'] && $action == $whiteRequest['action']) { + + $moduleDir = explode('_',$module)[0]; + $file = Path::join($this->config->get('system', 'path'), 'modules', $moduleDir, 'filters', 'white.json'); + if (file_exists($file)) { + $whiteList = json_decode(file_get_contents($file), true); + + if (in_array($action, $whiteList)) { return true; } } @@ -175,4 +215,3 @@ class Login extends Filter return false; } } - diff --git a/src/Form/Form.php b/src/Form/Form.php index 200d7ad..3a1e5f0 100644 --- a/src/Form/Form.php +++ b/src/Form/Form.php @@ -98,6 +98,8 @@ class Form extends View { 'radio' => 'ctiso\\Form\\SelectOne', 'filebrowser' => 'ctiso\\Form\\BrowserInput', 'documents' => 'ctiso\\Form\\BrowserInput', + 'chooser' => 'ctiso\\Form\\Input', + 'select_chooser' => 'ctiso\\Form\\SelectOne' ); } @@ -110,8 +112,8 @@ class Form extends View { public function addFieldClass($name, $class) { $this->constructor [$name] = $class; - } - + } + /** * Добавляет одно поле ввода на форму */ diff --git a/src/Form/OptionFactory.php b/src/Form/OptionFactory.php new file mode 100644 index 0000000..724b3e6 --- /dev/null +++ b/src/Form/OptionFactory.php @@ -0,0 +1,87 @@ +db = $db; + $this->registry = $registry; + } + + function create(Form_Select $field, $input) { + if (isset($input['options.resid'])) { + $type = $input['options.resid']; + + $res = new Model_Resources($this->db); + $field->options = $this->optionsArray('id_section', 'title', $res->getSubsections('', $type)); + + } else if (isset($input['options.res'])) { + $type = $input['options.res']; + + $res = new Model_Resources($this->db); + $field->options = $this->optionsArray('path', 'title', $res->getSubsections('', $type)); + + } else if (isset($input['options.all_res'])) { + $type = $input['options.all_res']; + + $res = new Model_Resources($this->db); + $field->options = $this->optionsArray('id_resource', 'subtitle', $res->getAllResource($type)); + + } else if (isset($input['options.db'])) { + list($table, $keyvalue) = explode(":", $input['options.db']); + list($key, $value) = explode(",", $keyvalue); + try { + $query_result = $this->db->executeQuery("SELECT * FROM $table"); + $field->options = $this->optionsDB($key, $value, $query_result); + } catch(Exception $ex) { + $field->options = []; + } + } elseif (isset($input['options.pair'])) { + $field->options = $this->optionsPair($input['options.pair']); + } elseif (isset($input['options.model'])) { + $factory = new Model_Factory($this->db, $this->registry); + $model = $factory->getModel($input['options.model']); + $field->options = $model->getAllAsOptions(); + } else { + $field->options = $input['options']; + } + if (isset($input['default'])) { + array_unshift($field->options, ['value' => 0, 'name' => $input['default']]); + } + + // Ставим корневой каталог в начало списка (скорее всего он будет в конце массива) + if ($field->options) + { + $root_elem = array_pop($field->options); + if ($root_elem['value'] == '/') + array_unshift($field->options, $root_elem); + else + array_push($field->options, $root_elem); + } + } + + public function optionsDB($key, $val, $res) { + $result = array(); + while($res->next()) { + $result[] = array('value' => $res->getInt($key), 'name' => $res->getString($val)); + } + return $result; + } + + public function optionsArray($key, $val, $res) { + $result = array(); + foreach($res as $item) { + $result[] = array('value' => $item->{$key}, 'name' => $item->{$val}); + } + return $result; + } + + public function optionsPair($list, $selected = false) { + $result = array(); + foreach ($list as $key => $value) { + $result [] = array('value' => $key, 'name' => $value, 'selected' => $key == $selected); + } + return $result; + } +} diff --git a/src/HttpRequest.php b/src/HttpRequest.php index 05c435e..0a65a4c 100644 --- a/src/HttpRequest.php +++ b/src/HttpRequest.php @@ -20,11 +20,12 @@ class HttpRequest extends Collection implements ArrayAccess */ public function __construct() { - $list = array ( + $list = [ 'data' => $_REQUEST, 'get' => $_GET, 'post' => $_POST, - 'cookie' => $_COOKIE); + 'cookie' => $_COOKIE + ]; $ajax = $this->isAjax(); foreach ($list as $key => $value) { diff --git a/src/Model/Factory.php b/src/Model/Factory.php index 577b826..6fbc4a4 100644 --- a/src/Model/Factory.php +++ b/src/Model/Factory.php @@ -6,7 +6,6 @@ use ctiso\Registry, class Factory { - static $shortcut = "model"; public $db; public $config; @@ -19,7 +18,7 @@ class Factory /** * Создает модель * @param string $name - * @return model + * @return Model */ public function getModel ($name) { diff --git a/src/Path.php b/src/Path.php index 1918571..bafed76 100644 --- a/src/Path.php +++ b/src/Path.php @@ -176,11 +176,14 @@ class Path public static function makeUrl($path) { + $slash = (isset($path['host']) && (strlen($path['path']) > 0) && ($path['path'][0] != '/')) ? '/' : ''; + return (isset($path['scheme']) ? $path['scheme'] . ':/' : '') . (isset($path['host']) ? ('/' . (isset($path['user']) ? $path['user'] . (isset($path['pass']) ? ':' . $path['pass'] : '') . '@' : '') . $path['host'] . (isset($path['port']) ? ':' . $path['port'] : '')) : '') + . $slash . $path['path'] . (isset($path['query']) ? '?' . $path['query'] : '') . (isset($path['fragment']) ? '#' . $path['fragment'] : ''); @@ -293,8 +296,9 @@ class Path $parts = new Path($file); $result [] = $parts->getParts(); } + // При обьединении ссылок можно обьеденить path, query, fragment - $path = implode(self::SEPARATOR, self::optimize(call_user_func_array('array_merge', $result))); + $path = implode(self::SEPARATOR, self::optimize(call_user_func_array('array_merge', $result))); $parts0->url['path'] = ($parts0->isAbsolute()) ? '/' . $path : $path; return $parts0; } diff --git a/src/Registry.php b/src/Registry.php index 19f0681..e5eedba 100644 --- a/src/Registry.php +++ b/src/Registry.php @@ -6,6 +6,7 @@ use ctiso\File, class Registry { public $namespace = []; + public $data; function importFile($namespace, $filePath = null) { $data = json_decode(File::getContents($filePath), true); @@ -40,4 +41,20 @@ class Registry { function set($ns, $key, $value) { $this->namespace[$ns]['data'][$key] = $value; } + + /** + * Список модулей + */ + public function getModules() + { + return array_keys($this->data); + } + + /** + * Проверка наличия модуля + */ + public function hasModule($name) + { + return isset($this->data[$name]); + } } diff --git a/src/Role/User.php b/src/Role/User.php index 8d3e892..d6b6671 100644 --- a/src/Role/User.php +++ b/src/Role/User.php @@ -74,11 +74,26 @@ class User implements UserInterface $time = time(); if ($time - $lasttime > self::LIFE_TIME) return null; // Вышло время сессии $id = $this->id; - $this->db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время последнего обращения входа } return $result; } - function setSID() { + function setSID($random, $result) { + return $this->db->executeQuery("UPDATE users SET sid = '$random', trie_count = 0 WHERE id_user = " . $result->getInt('id_user')); + } + + function resetTries($login) { + $this->db->executeQuery( + "UPDATE users SET trie_count = :count WHERE login = :login", + ['count' => 0, 'login' => $login] + ); + } + + function updateTries($login) { + $user = $this->db->fetchOneArray("SELECT id_user, trie_count FROM users WHERE login = :login", ['login' => $login]); + $this->db->executeQuery( + "UPDATE users SET trie_time = :cur_time, trie_count = :count WHERE id_user = :id_user", + ['cur_time' => time(), 'count' => $user['trie_count']+1, 'id_user' => $user['id_user']] + ); } } diff --git a/src/Settings.php b/src/Settings.php index 4bd7ee5..c7c96b1 100644 --- a/src/Settings.php +++ b/src/Settings.php @@ -1,5 +1,9 @@ format = pathinfo($file, PATHINFO_EXTENSION); + $fileFormat = ['theme' => 'json']; + $extname = pathinfo($file, PATHINFO_EXTENSION); + + $this->format = $format ? $format : Arr::get($fileFormat, $extname, $extname); $this->file = $file; } @@ -47,6 +50,7 @@ class Settings } $this->data = $settings; + return true; } /** @@ -91,7 +95,7 @@ class Settings /** * Чтение ключа из реестра - * @param $args Путь к значению ключа + * @param mixed $args Путь к значению ключа */ public function readKey(array $key) { @@ -121,7 +125,7 @@ class Settings /** * Чтение ключа из реестра (Собирает все ключи с определенным значением во всех модулях) - * @param $key Путь к значению ключа внутри модуля + * @param mixed $key Путь к значению ключа внутри модуля */ public function readKeyList($_rest) { @@ -162,7 +166,6 @@ class Settings * Запись настроек в файл (Может переименовать в store) * * @param File $file - * * @return void */ public function write($file = null) diff --git a/src/Tools/Image.php b/src/Tools/Image.php index 3e56df7..a59642f 100644 --- a/src/Tools/Image.php +++ b/src/Tools/Image.php @@ -12,17 +12,17 @@ class Image case 'jpeg': case 'jpg': return imagecreatefromjpeg($uri); case 'gif': return imagecreatefromgif($uri); } - } + } static function fit($image, $prewidth, $preheight, $force = true) { $width = imagesx($image); - $height = imagesy($image); + $height = imagesy($image); $percent = min($prewidth / $width, $preheight / $height); if ($percent > 1 && !$force) $percent = 1; $new_width = $width * $percent; $new_height = $height * $percent; - + $image_p = imagecreatetruecolor($new_width, $new_height); imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); @@ -38,4 +38,4 @@ class Image case 'gif': imagegif($image, $uri); break; } } -} +} \ No newline at end of file diff --git a/src/Tools/SQLStatementExtractor.php b/src/Tools/SQLStatementExtractor.php index d6acd15..a084113 100644 --- a/src/Tools/SQLStatementExtractor.php +++ b/src/Tools/SQLStatementExtractor.php @@ -146,7 +146,7 @@ class SQLStatementExtractor { trigger_error("substring(), Endindex out of bounds must be $startpos 0) { // already in sub-array? - $subarr[$in_subarr][] = $tok; - if ('}' === substr($tok, -1, 1)) { // check to see if we just added last component - $res[] = self::strToArray(implode(',', $subarr[$in_subarr])); - $in_subarr--; - } - } elseif ($tok{0} === '{') { // we're inside a new sub-array - if ('}' !== substr($tok, -1, 1)) { - $in_subarr++; - // if sub-array has more than one element - $subarr[$in_subarr] = array(); - $subarr[$in_subarr][] = $tok; - } else { - $res[] = self::strToArray($tok); - } - } else { // not sub-array - $val = trim($tok, '"'); // remove " (surrounding strings) - // perform type castng here? - $res[] = $val; - } - } - - return $res; + $str = substr($str, 1, -1); // remove { } + $res = array(); + + $subarr = array(); + $in_subarr = 0; + + $toks = explode(',', $str); + foreach($toks as $tok) { + if ($in_subarr > 0) { // already in sub-array? + $subarr[$in_subarr][] = $tok; + if ('}' === substr($tok, -1, 1)) { // check to see if we just added last component + $res[] = static::strToArray(implode(',', $subarr[$in_subarr])); + $in_subarr--; + } + } elseif ($tok[0] === '{') { // we're inside a new sub-array + if ('}' !== substr($tok, -1, 1)) { + $in_subarr++; + // if sub-array has more than one element + $subarr[$in_subarr] = array(); + $subarr[$in_subarr][] = $tok; + } else { + $res[] = static::strToArray($tok); + } + } else { // not sub-array + $val = trim($tok, '"'); // remove " (surrounding strings) + // perform type castng here? + $res[] = $val; + } + } + + return $res; } //Нормализация строк на русском static function normalizeRussian($str) { $result = preg_replace('/\s+/',' ', $str); if (is_string($result)) { - $result = trim($result); //Замена длинных пробелов на одинарные, пробелы по краям - $result = mb_strtolower($result); - $result = preg_replace('/ё/','е', $str); //е на ё + $result = trim($result); //Замена длинных пробелов на одинарные, пробелы по краям + $result = mb_strtolower($result); + $result = preg_replace('/ё/','е', $str); //е на ё } - return $result; + return $result; } - + //Проверка равенства двух строк на русском языке. static function equalRussianCheck($str1,$str2) { - return self::normalizeRussian($str1) == self::normalizeRussian($str2); + return self::normalizeRussian($str1) == self::normalizeRussian($str2); } - + /** * Попадает ли строка в список вариантов @@ -62,7 +62,7 @@ class StringUtil { * output: true * input: $str="foo" $variants="foo1|foo2|foo3" * output: false -*/ +*/ static function compare_string_to_variants($str, $variants){ $variants_array = explode('|', $variants); $founded = false; @@ -71,17 +71,17 @@ class StringUtil { } return $founded; } - + static function mb_str_split($str) { return preg_split('~~u', $str, null, PREG_SPLIT_NO_EMPTY); } - + static function mb_strtr($str, $from, $to) { return str_replace(self::mb_str_split($from), self::mb_str_split($to), $str); - } - + } + static function encodestring($st) { - $st = self::mb_strtr($st,"абвгдеёзийклмнопрстуфхъыэ !+-()", "abvgdeeziyklmnoprstufh_ie______"); + $st = self::mb_strtr($st,"абвгдеёзийклмнопрстуфхъыэ !+()", "abvgdeeziyklmnoprstufh_ie_____"); $st = self::mb_strtr($st,"АБВГДЕЁЗИЙКЛМНОПРСТУФХЪЫЭ", "ABVGDEEZIYKLMNOPRSTUFH_IE"); $st = strtr($st, array( " " => '_', @@ -96,8 +96,8 @@ class StringUtil { "#" => '_', "*" => '_', "ж"=>"zh", "ц"=>"ts", "ч"=>"ch", "ш"=>"sh", - "щ"=>"shch","ь"=>"", "ю"=>"yu", "я"=>"ya", - "Ж"=>"ZH", "Ц"=>"TS", "Ч"=>"CH", "Ш"=>"SH", + "щ"=>"shch","ь"=>"", "ю"=>"yu", "я"=>"ya", + "Ж"=>"ZH", "Ц"=>"TS", "Ч"=>"CH", "Ш"=>"SH", "Щ"=>"SHCH","Ь"=>"", "Ю"=>"YU", "Я"=>"YA", "Й"=>"i", "й"=>"ie", "ё"=>"Ye", "№"=>"N" @@ -109,4 +109,4 @@ class StringUtil { $enc_st = self::encodestring($st); return preg_match('/^[\w_-]+(\.[\w_-]+)?$/', $enc_st); } -} +} \ No newline at end of file diff --git a/src/Tools/TemplateImage.php b/src/Tools/TemplateImage.php index 8dbb21e..478b3df 100644 --- a/src/Tools/TemplateImage.php +++ b/src/Tools/TemplateImage.php @@ -10,14 +10,14 @@ class TemplateImage { static $listfiles = array('jpg' => 'jpeg', 'gif' => 'gif', 'png' => 'png', 'bmp' => 'wbmp'); static $listfonts = array( - 'georgia' => 'georgia.ttf', - 'georgiabd' => 'georgiab.ttf', - 'georgiaz' => 'georgiaz.ttf', - 'times' => 'times.ttf', - 'timesbd' => 'timesbd.ttf', - 'arial' => 'arial.ttf', - 'arialbd' => 'arialbd.ttf', - 'tahoma' => 'tahoma.ttf', + 'georgia' => 'georgia.ttf', + 'georgiabd' => 'georgiab.ttf', + 'georgiaz' => 'georgiaz.ttf', + 'times' => 'times.ttf', + 'timesbd' => 'timesbd.ttf', + 'arial' => 'arial.ttf', + 'arialbd' => 'arialbd.ttf', + 'tahoma' => 'tahoma.ttf', 'calibri' => 'calibri.ttf', 'calibribd' => 'calibrib.ttf', 'calibrii' => 'calibrii.ttf', @@ -29,7 +29,7 @@ class TemplateImage 'miriad' => 'MyriadPro-Cond.ttf', 'miriadbd' => 'MyriadPro-BoldCond.ttf' -); + ); protected $src; protected $context = array(); @@ -38,6 +38,8 @@ class TemplateImage protected $image; protected $_prepare = true; public $debug = false; + public $filename; + public $resource; public $resource; public $filename; @@ -63,14 +65,14 @@ class TemplateImage /** * Путь у шрифтам */ - function fontPath($path) + function fontPath($path) { assert(is_string($path)); $this->base = $path; } - - function set($name, $value) + + function set($name, $value) { assert(is_string($name)); @@ -91,11 +93,11 @@ class TemplateImage /** * Создает изображение из файла */ - function imagefromfile($file) + function imagefromfile($file) { assert(is_string($file)); - $suffix = pathinfo($file, PATHINFO_EXTENSION); + $suffix = pathinfo($file, PATHINFO_EXTENSION); if (array_key_exists($suffix, self::$listfiles)) { return call_user_func('imagecreatefrom' . self::$listfiles[$suffix], $file); } @@ -103,12 +105,12 @@ class TemplateImage } function getFontFile($name) - { + { assert(is_string($name)); if(array_key_exists(strtolower($name), self::$listfonts)) { return $this->base . self::$listfonts[$name]; - } + } return $this->base . 'arial.ttf'; } @@ -162,8 +164,8 @@ class TemplateImage } function setSize($new_width, $new_height) - { - $width = imagesx($this->image); + { + $width = imagesx($this->image); $height = imagesy($this->image); if ($new_height == null) { $new_height = ceil($height * $new_width / $width); @@ -174,7 +176,7 @@ class TemplateImage imagecopyresampled($image_p, $this->image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); // imagecopyresized($image_p, $this->image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); $this->image = $image_p; - } + } function prepare() { if($this->_prepare) { @@ -205,4 +207,3 @@ class TemplateImage } } } - diff --git a/src/UserMessageException.php b/src/UserMessageException.php index 032c0b8..1049dc9 100644 --- a/src/UserMessageException.php +++ b/src/UserMessageException.php @@ -1,9 +1,4 @@ site = $site; - // Вставка компонентов на странице - $pattern = '/<(\w+)(\s+[a-zA-Z\-]+=\"[^\"]*\")*\s+tal:replace="structure\s+component:([^\"]*)"[^>]*>/u'; - $matches = array(); - preg_match_all($pattern, $data, $matches, PREG_OFFSET_CAPTURE, 0); - - $split = array(); - $offset = 0; - foreach ($matches[0] as $key => $match) { - $text = $this->fixHTML(substr($data, $offset, $match[1] - $offset)); - if (trim($text)) { - $split[] = array('type' => 'page-text', 'content' => $text, 'component' => '', 'module' => ''); - } - $offset = $match[1] + strlen($match[0]); - $split[] = $this->replaceContent($matches[3][$key][0], $matches[3][$key][1]); - } - $text = $this->fixHTML(substr($data, $offset)); - if (trim($text)) { - $split[] = array('type' => 'page-text', 'content' => $text, 'component' => '', 'module' => ''); - } - - $this->text = $this->merge($split); - } - - function fixHTML($fragment) { - return $fragment; - } - - function merge($data) { - if (count($data) == 0) { - $data[] = array('type' => 'page-text', 'content' =>"

Добавьте текст

", 'component' => '', 'module' => ''); - } - $result = array(); - foreach($data as $key => $part) { - $result[] = $part['content']; - } - return implode("", $result); - } - - function replaceContent($match, $offset) - { - $component/*: Component*/ = $this->site->loadComponent($match); - - $req = new HttpRequest(); - unset($req['active_page']); - - $info = $component->getInfo(); - $result = $component->execute($req); - - if (is_string($result)) { - return array('type' => 'page-component', 'content' => $result, 'component' => $match); - } else { - $this->setView('view' . $this->counter++, $result); - return array('type' => 'page-component', 'content' => $result->execute(), 'component' => $match); - } - } - - function execute() { - return $this->text; - } -} diff --git a/src/View/Top.php b/src/View/Top.php index b3fd768..f27e44e 100644 --- a/src/View/Top.php +++ b/src/View/Top.php @@ -1,14 +1,16 @@ $group) { - if(in_array($file, $group)) { + foreach ($groups as $key => $group) { + if (in_array($file, $group)) { return $key; } } @@ -28,7 +30,7 @@ class Top extends Composite { private function groupFiles(array $list, $debugMode = true) { - $debug = ($debugMode) ? 'debug=1' : ''; + $debug = ($debugMode) ? 'debug=1' : ''; $path = parse_url($this->config->get('system', 'web'), PHP_URL_PATH); $groups = array(); @@ -37,7 +39,7 @@ class Top extends Composite { $result = array(); foreach ($list as $file) { $name = $this->findGroup($groups, $file); - if($name) { + if ($name) { $use[$name] = 1; } else { $result[] = $file; @@ -52,17 +54,18 @@ class Top extends Composite { } - function getId($pref) { - $this->mid++; - return $pref.$this->mid; - } + function getId($pref) + { + $this->mid++; + return $pref . $this->mid; + } /** * Обработка шаблона * * @return string */ - public function render() + public function render() { $alias = $this->doTree('alias'); @@ -72,51 +75,52 @@ class Top extends Composite { $this->set('scripts', array_unique($this->groupFiles($this->getScripts(), false))); $this->set('stylesheet', array_unique($this->groupFiles($this->getStyleSheet(), false))); - $this->require = array('admin' => 'ma'); - $this->deps = array(); + $this->require = array('admin' => 'ma'); + $this->deps = array(); - $startup = array(); - foreach($this->_section as $s) { + $startup = array(); + foreach ($this->_section as $s) { if (is_string($s)) { continue; } - $moduleName = explode('_', $s->active_module, 2); + $moduleName = explode('_', $s->active_module, 2); if (count($moduleName) < 2) { continue; } $module = $moduleName[1]; - $name = mb_strtolower($module); - $fname = $name . '/' . $name; + $name = mb_strtolower($module); + $fname = $name . '/' . $name; - $current = $this->getId('m'); - $this->require[$fname] = $current; + $current = $this->getId('m'); + $this->require[$fname] = $current; - $value = $this->getId('v'); + $value = $this->getId('v'); - $script = "var " . $value . " = new " . $current . '.' . $module . "();\n"; - foreach($s->_values as $key => $v) { - $script .= $value . "." . $key . " = " . json_encode($v/*, JSON_PRETTY_PRINT*/) . ";\n"; - } + $script = "var " . $value . " = new " . $current . '.' . $module . "();\n"; + foreach ($s->_values as $key => $v) { + $script .= $value . "." . $key . " = " . json_encode($v /*, JSON_PRETTY_PRINT*/) . ";\n"; + } - $init = array(); - foreach($s->_section as $key => $item) { - $ss/*: View*/ = $item; + $init = array(); + foreach ($s->_section as $key => $item) { + $ss /*: View*/= $item; if ($ss->codeGenerator !== null) { - // функцию которая вычисляет а не результат - $part = call_user_func($ss->codeGenerator, $this, $key, $value); - $init [] = $part; - } - } + // функцию которая вычисляет а не результат + $part = call_user_func($ss->codeGenerator, $this, $key, $value); + $init[] = $part; + } + } - $script .= $value . ".execute('" . $s->module_action . "', " . json_encode($init) .");\n"; - $startup[] = $script; - } + $script .= $value . ".execute('" . $s->module_action . "', " . json_encode($init) . ");\n"; + $startup[] = $script; + } $this->set('startup', implode("", $startup) . $this->getScriptStartup()); - $this->set('require', implode(",", array_map(function ($x) { return "'$x'";}, array_keys($this->require)))); + $this->set('require', implode(",", array_map(function ($x) { + return "'$x'"; }, array_keys($this->require)))); $this->set('deps', implode(",", array_values($this->require))); $this->set('title', $this->getTitle()); @@ -160,4 +164,4 @@ class Top extends Composite { return $this->doTree('_stylesheet'); } -} +} \ No newline at end of file diff --git a/src/tabletree.php b/src/tabletree.php index 3cfa321..0d9203a 100644 --- a/src/tabletree.php +++ b/src/tabletree.php @@ -33,4 +33,3 @@ function tableTreeWalk($level, $table, $fn) { } return $data; } -