Merge branch 'master' into noglob

This commit is contained in:
origami11@yandex.ru 2022-11-18 16:07:32 +03:00
commit 7d35a8f3f0
27 changed files with 430 additions and 288 deletions

View file

@ -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()

View file

@ -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, '');
}
}

View file

@ -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();

View file

@ -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)) {

View file

@ -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();
}
}

View file

@ -18,7 +18,7 @@ use PDO,
/**
* Класс оболочка для PDO для замены Creole
*/
class Database extends PDO
class Database/*<Database_PDOStatement>*/ 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;
}

View file

@ -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;
}
}

View file

@ -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}";
}

View file

@ -8,7 +8,7 @@ class Number
function __construct($value)
{
$this->value = (int)$value;
$this->value = (int)($value);
}
function getString()

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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;
}
}
/**
* Добавляет одно поле ввода на форму
*/

View file

@ -0,0 +1,87 @@
<?php
class Form_OptionFactory {
public $db;
public $registry;
function __construct($db, $registry = null) {
$this->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;
}
}

View file

@ -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) {

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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]);
}
}

View file

@ -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']]
);
}
}

View file

@ -1,5 +1,9 @@
<?php
namespace ctiso;
use ctiso\File,
Exception;
/**
* Класс реестра
* Реестр организован как ассоциативный многомерный массив
@ -9,19 +13,18 @@
* parameters1, parameters1 - Массивы с параметрами модуля
* Имя необходимо чтобы потом легко было удалить ненужные ветки дерева
*/
namespace ctiso;
use ctiso\File,
Exception;
class Settings
{
public $data = [];
protected $file;
protected $format = 'php';
public function __construct ($file = null)
public function __construct ($file = null, $format = false)
{
$this->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)

View file

@ -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;
}
}
}
}

View file

@ -146,7 +146,7 @@ class SQLStatementExtractor {
trigger_error("substring(), Endindex out of bounds must be $startpos<n<".($len-1), E_USER_ERROR);
}
if ($startpos === $endpos) {
return (string) $string{$startpos};
return (string) $string[$startpos];
} else {
$len = $endpos-$startpos;
}

View file

@ -6,55 +6,55 @@ class StringUtil {
// from creole
static function strToArray($str) {
$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[] = 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);
}
}
}

View file

@ -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
}
}
}

View file

@ -1,9 +1,4 @@
<?php
/**
* UserMessageException.php
*
*/
/**
* Исключение с понятным пользователю сообщением, которое имеет смысл ему показать.
* @see Controller_Front

View file

@ -1,77 +0,0 @@
<?php
namespace ctiso\View;
use ctiso\View\View,
ctiso\Controller\SiteInterface,
ctiso\Controller\Component,
ctiso\HttpRequest;
class Page extends View
{
private $counter;
public $text;
public $site/*: SiteInterface*/;
function __construct($data, $site)
{
$this->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' =>"<p>Добавьте текст<p>", '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;
}
}

View file

@ -1,14 +1,16 @@
<?php
namespace ctiso\View;
use ctiso\View\Composite;
class Top extends Composite {
class Top extends Composite
{
/**
* Общая строка заголовка
*/
public $mid = 0;
public $require = array();
public $mid = 0;
public $require = array();
public $deps = array();
public function getTitle()
@ -18,8 +20,8 @@ class Top extends Composite {
private function findGroup($groups, $file)
{
foreach($groups as $key => $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');
}
}
}

View file

@ -33,4 +33,3 @@ function tableTreeWalk($level, $table, $fn) {
}
return $data;
}