This commit is contained in:
Visman 2017-03-08 22:52:45 +07:00
parent 35c9d5583c
commit dc51f88896
25 changed files with 1322 additions and 722 deletions

View file

@ -146,10 +146,10 @@ class FileCache implements ProviderCacheInterface
*/
protected function file($key)
{
if (is_string($key) && preg_match('%^[\w-]+$%D', $key)) {
if (is_string($key) && preg_match('%^[a-z0-9_-]+$%Di', $key)) {
return $this->cacheDir . '/cache_' . $key . '.php';
}
throw new InvalidArgumentException("`$key`: Key contains invalid characters");
throw new InvalidArgumentException("Key '$key' contains invalid characters.");
}
/**

View file

@ -173,11 +173,11 @@ class Container
if (is_string($value)) {
if (strpos($value, '%') !== false) {
// whole string substitution can return any type of value
if (preg_match('~^%(\w+(?:\.\w+)*)%$~', $value, $matches)) {
if (preg_match('~^%([a-z0-9_]+(?:\.[a-z0-9_]+)*)%$~i', $value, $matches)) {
$value = $this->__get($matches[1]);
} else {
// partial string substitution casts value to string
$value = preg_replace_callback('~%(\w+(?:\.\w+)*)%~',
$value = preg_replace_callback('~%([a-z0-9_]+(?:\.[a-z0-9_]+)*)%~i',
function ($matches) {
return $this->__get($matches[1]);
}, $value);

293
app/Core/DB.php Normal file
View file

@ -0,0 +1,293 @@
<?php
namespace ForkBB\Core;
use PDO;
use PDOStatement;
use PDOException;
class DB extends PDO
{
/**
* Префикс для таблиц базы
* @var string
*/
protected $dbPrefix;
/**
* Тип базы данных
* @var string
*/
protected $dbType;
/**
* Драйвер текущей базы
* @var //????
*/
protected $dbDrv;
/**
* Конструктор
*
* @param string $dsn
* @param string $username
* @param string $password
* @param array $options
* @param string $prefix
*
* @throws PDOException
*/
public function __construct($dsn, $username = null, $password = null, array $options = [], $prefix = '')
{
$type = strstr($dsn, ':', true);
if (! $type || ! file_exists(__DIR__ . '/DB/' . ucfirst($type) . '.php')) {
throw new PDOException("For '$type' the driver isn't found.");
}
$this->dbType = $type;
$this->dbPrefix = $prefix;
$options += [
self::ATTR_DEFAULT_FETCH_MODE => self::FETCH_ASSOC,
self::ATTR_EMULATE_PREPARES => false,
self::ATTR_ERRMODE => self::ERRMODE_EXCEPTION,
];
parent::__construct($dsn, $username, $password, $options);
}
/**
* Передает вызовы методов в драйвер текущей базы
*
* @param string $name
* @param array $args
*
* @return mixed
*/
public function __call($name, array $args)
{
if (empty($this->dbDrv)) {
$drv = 'ForkBB\\Core\\DB\\' . ucfirst($this->dbType);
$this->dbDrv = new $drv($this, $this->dbPrefix);
}
return $this->dbDrv->$name(...$args);
}
/**
* Метод определяет массив ли опций подан на вход
*
* @param array $options
*
* @return bool
*/
protected function isOptions(array $arr)
{
$verify = [self::ATTR_CURSOR => [self::CURSOR_FWDONLY, self::CURSOR_SCROLL]];
foreach ($arr as $key => $value) {
if (! isset($verify[$key]) || ! in_array($value, $verify[$key])) {
return false;
}
}
return true;
}
/**
* Метод приводит запрос с типизированными плейсхолдерами к понятному для PDO виду
*
* @param string $query
* @param array $params
*
* @throws PDOException
*
* @return array
*/
protected function parse($query, array $params)
{
$parts = preg_split('%(?=[?:])(?<![a-z0-9_])(\?[a-z0-9_]+|\?(?!=:))?(::?[a-z0-9_]+)?%i', $query, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$idxIn = 0;
$idxOut = 1;
$query = '';
$total = count($parts);
$map = [];
$bind = [];
for ($i = 0; $i < $total; ++$i) {
switch ($parts[$i][0]) {
case '?':
$type = isset($parts[$i][1]) ? substr($parts[$i], 1) : 's';
$key = isset($parts[$i + 1]) && $parts[$i + 1][0] === ':'
? $parts[++$i]
: $idxIn++;
break;
case ':':
if ($parts[$i][1] === ':') {
$query .= $this->dbPrefix . substr($parts[$i], 2);
continue 2;
}
$type = 's';
$key = $parts[$i];
break;
default:
$query .= $parts[$i];
continue 2;
}
if (! isset($params[$key])) {
throw new PDOException("'$key': No parameter for (?$type) placeholder");
}
switch ($type) {
case 'p':
$query .= (string) $params[$key];
continue 2;
case 'as':
case 'ai':
case 'a':
$bindType = $type === 'ai' ? self::PARAM_INT : self::PARAM_STR;
$comma = '';
foreach ($params[$key] as $val) {
$name = ':' . $idxOut++;
$query .= $comma . $name;
$bind[$name] = [$val, $bindType];
$comma = ',';
if (empty($map[$key])) {
$map[$key] = [$type, $name];
} else {
$map[$key][] = $name;
}
}
continue 2;
case '':
break;
case 'i':
$bindType = self::PARAM_INT;
break;
case 'b':
$bindType = self::PARAM_BOOL;
break;
case 's':
default:
$bindType = self::PARAM_STR;
$type = 's';
break;
}
$name = ':' . $idxOut++;
$query .= $name;
$bind[$name] = [$params[$key], $bindType];
if (empty($map[$key])) {
$map[$key] = [$type, $name];
} else {
$map[$key][] = $name;
}
}
return [$query, $bind, $map];
}
/**
* Метод связывает параметры запроса с соответвтующими значениями
*
* @param PDOStatement $stmt
* @param array $bind
*/
protected function bind(PDOStatement $stmt, array $bind)
{
foreach ($bind as $key => $val) {
$stmt->bindValue($key, $val[0], $val[1]);
}
}
/**
* Метод расширяет PDO::exec()
*
* @param string $query
* @param array $params
*
* @return int|false
*/
public function exec($query, array $params = [])
{
list($query, $bind, ) = $this->parse($query, $params);
if (empty($bind)) {
return parent::exec($query);
}
$stmt = parent::prepare($query);
$this->bind($stmt, $bind);
if ($stmt->execute()) {
return $stmt->rowCount(); //??? Для запроса SELECT... не ясно поведение!
}
return false;
}
/**
* Метод расширяет PDO::prepare()
*
* @param string $query
* @param array $arg1
* @param array $arg2
*
* @return PDOStatement
*/
public function prepare($query, $arg1 = null, $arg2 = null)
{
if (empty($arg1) === empty($arg2) || ! empty($arg2)) {
$params = $arg1;
$options = $arg2;
} elseif ($this->isOptions($arg1)) {
$params = [];
$options = $arg1;
} else {
$params = $arg1;
$options = [];
}
list($query, $bind, $map) = $this->parse($query, $params);
$stmt = parent::prepare($query, $options);
$this->bind($stmt, $bind);
return $stmt;
}
/**
* Метод расширяет PDO::query()
*
* @param string $query
* @param mixed ...$args
*
* @return PDOStatement|false
*/
public function query($query, ...$args)
{
if (isset($args[0]) && is_array($args[0])) {
$params = array_shift($args);
} else {
$params = [];
}
list($query, $bind, ) = $this->parse($query, $params);
if (empty($bind)) {
return parent::query($query, ...$args);
}
$stmt = parent::prepare($query);
$this->bind($stmt, $bind);
if ($stmt->execute()) {
if (! empty($args)) {
$stmt->setFetchMode(...$args);
}
return $stmt;
}
return false;
}
}

View file

@ -1,374 +1,524 @@
<?php
/**
* Copyright (C) 2008-2012 FluxBB
* based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
*/
namespace ForkBB\Core\DB;
// Make sure we have built in support for MySQL
if (!function_exists('mysql_connect'))
exit('This PHP environment doesn\'t have MySQL support built in. MySQL support is required if you want to use a MySQL database to run this forum. Consult the PHP documentation for further assistance.');
use ForkBB\Core\DB;
use PDO;
use PDOStatement;
use PDOException;
class DBLayer
class Mysql
{
var $prefix;
var $link_id;
var $query_result;
/**
* @var DB
*/
protected $db;
var $saved_queries = array();
var $num_queries = 0;
/**
* Префикс для таблиц базы
* @var string
*/
protected $dbPrefix;
var $error_no = false;
var $error_msg = 'Unknown';
/**
* Набор символов БД
* @var string
*/
protected $dbCharSet;
var $datatype_transformations = array(
'%^SERIAL$%' => 'INT(10) UNSIGNED AUTO_INCREMENT'
);
/**
* Массив замены типов полей таблицы
* @var array
*/
protected $dbTypeRepl = [
'%^SERIAL$%i' => 'INT(10) UNSIGNED AUTO_INCREMENT',
];
/**
* Конструктор
*
* @param DB $db
* @param string $prefix
*/
public function __construct(DB $db, $prefix)
{
$this->db = $db;
$this->dbPrefix = $prefix;
}
function __construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
/**
* Перехват неизвестных методов
*
* @param string $name
* @param array $args
*
* @throws PDOException
*/
public function __call($name, array $args)
{
throw new PDOException("Method '{$name}' not found in DB driver.");
}
/**
* Проверяет строку на допустимые символы
*
* @param string $str
*
* @throws PDOException
*/
protected function testStr($str)
{
if (! is_string($str) || preg_match('%[^a-zA-Z0-9_]%', $str)) {
throw new PDOException("Name '{$str}' have bad characters.");
}
}
/**
* Операции над полями индексов: проверка, замена
*
* @param array $arr
*
* @return string
*/
protected function replIdxs(array $arr)
{
foreach ($arr as &$value) {
if (preg_match('%^(.*)\s*(\(\d+\))$%', $value, $matches)) {
$this->testStr($matches[1]);
$value = "`{$matches[1]}`{$matches[2]}";
} else {
$this->testStr($value);
$value = "`{$value}`";
}
unset($value);
}
return implode(',', $arr);
}
/**
* Замена типа поля в соответствии с dbTypeRepl
*
* @param string $type
*
* @return string
*/
protected function replType($type)
{
return preg_replace(array_keys($this->dbTypeRepl), array_values($this->dbTypeRepl), $type);
}
/**
* Конвертирует данные в строку для DEFAULT
*
* @param mixed $data
*
* @throws PDOException
*
* @return string
*/
protected function convToStr($data) {
if (is_string($data)) {
return $this->db->quote($data);
} elseif (is_numeric($data)) {
return (string) $data;
} elseif (is_bool($data)) {
return $data ? 'true' : 'false';
} else {
throw new PDOException('Invalid data type for DEFAULT.');
}
}
/**
* Вовзращает набор символов БД
*
* @return string
*/
protected function getCharSet()
{
if (! $this->dbCharSet) {
$stmt = $this->db->query("SHOW VARIABLES LIKE 'character\_set\_database'");
$this->dbCharSet = $stmt->fetchColumn(1);
$stmt->closeCursor();
}
return $this->dbCharSet;
}
/**
* Проверяет наличие таблицы в базе
*
* @param string $table
* @param bool $noPrefix
*
* @return bool
*/
public function tableExists($table, $noPrefix = false)
{
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
try {
$stmt = $this->db->query('SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?s:table', [':table' => $table]);
$result = $stmt->fetch();
$stmt->closeCursor();
} catch (PDOException $e) {
return false;
}
return ! empty($result);
}
/**
* Проверяет наличие поля в таблице
*
* @param string $table
* @param string $field
* @param bool $noPrefix
*
* @return bool
*/
public function fieldExists($table, $field, $noPrefix = false)
{
$this->prefix = $db_prefix;
if ($p_connect)
$this->link_id = @mysql_pconnect($db_host, $db_username, $db_password);
else
$this->link_id = @mysql_connect($db_host, $db_username, $db_password);
if ($this->link_id)
{
if (!@mysql_select_db($db_name, $this->link_id))
error('Unable to select database. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
}
else
error('Unable to connect to MySQL server. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
// Setup the client-server character set (UTF-8)
if (!defined('FORUM_NO_SET_NAMES'))
$this->set_names('utf8');
return $this->link_id;
}
function start_transaction()
{
return;
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
try {
$stmt = $this->db->query('SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?s:table AND COLUMN_NAME = ?s:field', [':table' => $table, ':field' => $field]);
$result = $stmt->fetch();
$stmt->closeCursor();
} catch (PDOException $e) {
return false;
}
return ! empty($result);
}
/**
* Проверяет наличие индекса в таблице
*
* @param string $table
* @param string $index
* @param bool $noPrefix
*
* @return bool
*/
public function indexExists($table, $index, $noPrefix = false)
{
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
$index = $index == 'PRIMARY' ? $index : $table . '_' . $index;
try {
$stmt = $this->db->query('SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?s:table AND INDEX_NAME = ?s:index', [':table' => $table, ':index' => $index]);
$result = $stmt->fetch();
$stmt->closeCursor();
} catch (PDOException $e) {
return false;
}
return ! empty($result);
}
function end_transaction()
/**
* Создает таблицу
*
* @param string $table
* @param array $schema
* @param bool $noPrefix
*
* @return bool
*/
public function createTable($table, array $schema, $noPrefix = false)
{
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
$this->testStr($table);
$charSet = $this->getCharSet();
$query = "CREATE TABLE IF NOT EXISTS `{$table}` (";
foreach ($schema['FIELDS'] as $field => $data) {
$this->testStr($field);
// имя и тип
$query .= "`{$field}` " . $this->replType($data[0]);
// не NULL
if (empty($data[1])) {
$query .= ' NOT NULL';
}
// значение по умолчанию
if (isset($data[2])) {
$query .= ' DEFAULT ' . $this->convToStr($data[2]);
}
// сравнение
if (isset($data[3]) && is_string($data[3])) {
$this->testStr($data[3]);
$query .= " CHARACTER SET {$charSet} COLLATE {$charSet}_{$data[3]}";
}
$query .= ', ';
}
if (isset($schema['PRIMARY KEY'])) {
$query .= 'PRIMARY KEY (' . $this->replIdxs($schema['PRIMARY KEY']) . '), ';
}
if (isset($schema['UNIQUE KEYS'])) {
foreach ($schema['UNIQUE KEYS'] as $key => $fields) {
$this->testStr($key);
$query .= "UNIQUE `{$table}_{$key}` (" . $this->replIdxs($fields) . '), ';
}
}
if (isset($schema['INDEXES'])) {
foreach ($schema['INDEXES'] as $index => $fields) {
$this->testStr($index);
$query .= "INDEX `{$table}_{$index}` (" . $this->replIdxs($fields) . '), ';
}
}
if (isset($schema['ENGINE'])) {
$engine = $schema['ENGINE'];
} else {
// при отсутствии типа таблицы он определяется на основании типов других таблиц в базе
$stmt = $this->db->query("SHOW TABLE STATUS LIKE '{$this->dbPrefix}%'");
$engine = [];
while ($row = $stmt->fetch()) {
if (isset($engine[$row['Engine']])) {
++$engine[$row['Engine']];
} else {
$engine[$row['Engine']] = 1;
}
}
// в базе нет таблиц
if (empty($engine)) {
$engine = 'MyISAM';
} else {
arsort($engine);
// берем тип наиболее часто встречаемый у имеющихся таблиц
$engine = array_shift(array_keys($engine));
}
}
$this->testStr($engine);
$query = rtrim($query, ', ') . ") ENGINE = {$engine} CHARACTER SET {$charSet}";
return $this->db->exec($query) !== false;
}
/**
* Удаляет таблицу
*
* @param string $table
* @param bool $noPrefix
*
* @return bool
*/
public function dropTable($table, $noPrefix = false)
{
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
$this->testStr($table);
return $this->db->exec("DROP TABLE IF EXISTS `{$table}`") !== false;
}
/**
* Переименовывает таблицу
*
* @param string $old
* @param string $new
* @param bool $noPrefix
*
* @return bool
*/
public function renameTable($old, $new, $noPrefix = false)
{
if ($this->tableExists($new, $noPrefix) && ! $this->tableExists($old, $noPrefix)) {
return true;
}
$old = ($noPrefix ? '' : $this->dbPrefix) . $old;
$this->testStr($old);
$new = ($noPrefix ? '' : $this->dbPrefix) . $new;
$this->testStr($new);
return $this->db->exec("ALTER TABLE `{$old}` RENAME TO `{$new}`") !== false;
}
/**
* Добавляет поле в таблицу
*
* @param string $table
* @param string $field
* @param bool $allowNull
* @param mixed $default
* @param string $after
* @param bool $noPrefix
*
* @return bool
*/
public function addField($table, $field, $type, $allowNull, $default = null, $after = null, $noPrefix = false)
{
if ($this->fieldExists($table, $field, $noPrefix)) {
return true;
}
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
$this->testStr($table);
$this->testStr($field);
$query = "ALTER TABLE `{$table}` ADD `{$field}` " . $this->replType($type);
if ($allowNull) {
$query .= ' NOT NULL';
}
if (null !== $default) {
$query .= ' DEFAULT ' . $this->convToStr($default);
}
if (null !== $after) {
$this->testStr($after);
$query .= " AFTER `{$after}`";
}
return $this->db->exec($query) !== false;
}
/**
* Модифицирует поле в таблице
*
* @param string $table
* @param string $field
* @param bool $allowNull
* @param mixed $default
* @param string $after
* @param bool $noPrefix
*
* @return bool
*/
public function alterField($table, $field, $type, $allowNull, $default = null, $after = null, $noPrefix = false)
{
return;
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
$this->testStr($table);
$this->testStr($field);
$query = "ALTER TABLE `{$table}` MODIFY `{$field}` " . $this->replType($type);
if ($allowNull) {
$query .= ' NOT NULL';
}
if (null !== $default) {
$query .= ' DEFAULT ' . $this->convToStr($default);
}
if (null !== $after) {
$this->testStr($after);
$query .= " AFTER `{$after}`";
}
return $this->db->exec($query) !== false;
}
function query($sql, $unbuffered = false)
{
if (defined('PUN_SHOW_QUERIES'))
$q_start = microtime(true);
if ($unbuffered)
$this->query_result = @mysql_unbuffered_query($sql, $this->link_id);
else
$this->query_result = @mysql_query($sql, $this->link_id);
if ($this->query_result)
{
if (defined('PUN_SHOW_QUERIES'))
$this->saved_queries[] = array($sql, sprintf('%.5f', microtime(true) - $q_start));
++$this->num_queries;
return $this->query_result;
}
else
{
if (defined('PUN_SHOW_QUERIES'))
$this->saved_queries[] = array($sql, 0);
$this->error_no = @mysql_errno($this->link_id);
$this->error_msg = @mysql_error($this->link_id);
return false;
}
}
function result($query_id = 0, $row = 0, $col = 0)
{
return ($query_id) ? @mysql_result($query_id, $row, $col) : false;
}
function fetch_assoc($query_id = 0)
{
return ($query_id) ? @mysql_fetch_assoc($query_id) : false;
}
function fetch_row($query_id = 0)
{
return ($query_id) ? @mysql_fetch_row($query_id) : false;
}
function num_rows($query_id = 0)
{
return ($query_id) ? @mysql_num_rows($query_id) : false;
}
function affected_rows()
{
return ($this->link_id) ? @mysql_affected_rows($this->link_id) : false;
}
function insert_id()
{
return ($this->link_id) ? @mysql_insert_id($this->link_id) : false;
}
function get_num_queries()
{
return $this->num_queries;
}
function get_saved_queries()
{
return $this->saved_queries;
}
function free_result($query_id = false)
{
return ($query_id) ? @mysql_free_result($query_id) : false;
}
function escape($str)
{
if (is_array($str))
return '';
else if (function_exists('mysql_real_escape_string'))
return mysql_real_escape_string($str, $this->link_id);
else
return mysql_escape_string($str);
}
function error()
{
$result['error_sql'] = @current(@end($this->saved_queries));
$result['error_no'] = $this->error_no;
$result['error_msg'] = $this->error_msg;
return $result;
}
function close()
{
if ($this->link_id)
{
if (is_resource($this->query_result))
@mysql_free_result($this->query_result);
return @mysql_close($this->link_id);
}
else
return false;
}
function get_names()
{
$result = $this->query('SHOW VARIABLES LIKE \'character_set_connection\'');
return $this->result($result, 0, 1);
}
function set_names($names)
{
return $this->query('SET NAMES \''.$this->escape($names).'\'');
}
function get_version()
{
$result = $this->query('SELECT VERSION()');
return array(
'name' => 'MySQL Standard',
'version' => preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
);
}
function table_exists($table_name, $no_prefix = false)
{
$result = $this->query('SHOW TABLES LIKE \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\'');
return $this->num_rows($result) > 0;
}
function field_exists($table_name, $field_name, $no_prefix = false)
{
$result = $this->query('SHOW COLUMNS FROM '.($no_prefix ? '' : $this->prefix).$table_name.' LIKE \''.$this->escape($field_name).'\'');
return $this->num_rows($result) > 0;
}
function index_exists($table_name, $index_name, $no_prefix = false)
{
$exists = false;
$result = $this->query('SHOW INDEX FROM '.($no_prefix ? '' : $this->prefix).$table_name);
while ($cur_index = $this->fetch_assoc($result))
{
if (strtolower($cur_index['Key_name']) == strtolower(($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name))
{
$exists = true;
break;
}
}
return $exists;
}
function create_table($table_name, $schema, $no_prefix = false)
{
if ($this->table_exists($table_name, $no_prefix))
return true;
$query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
// Go through every schema element and add it to the query
foreach ($schema['FIELDS'] as $field_name => $field_data)
{
$field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
$query .= $field_name.' '.$field_data['datatype'];
if (isset($field_data['collation']))
$query .= 'CHARACTER SET utf8 COLLATE utf8_'.$field_data['collation'];
if (!$field_data['allow_null'])
$query .= ' NOT NULL';
if (isset($field_data['default']))
$query .= ' DEFAULT '.$field_data['default'];
$query .= ",\n";
}
// If we have a primary key, add it
if (isset($schema['PRIMARY KEY']))
$query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
// Add unique keys
if (isset($schema['UNIQUE KEYS']))
{
foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
$query .= 'UNIQUE KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$key_name.'('.implode(',', $key_fields).'),'."\n";
}
// Add indexes
if (isset($schema['INDEXES']))
{
foreach ($schema['INDEXES'] as $index_name => $index_fields)
$query .= 'KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.'('.implode(',', $index_fields).'),'."\n";
}
// We remove the last two characters (a newline and a comma) and add on the ending
$query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'MyISAM').' CHARACTER SET utf8';
return $this->query($query) ? true : false;
}
function drop_table($table_name, $no_prefix = false)
{
if (!$this->table_exists($table_name, $no_prefix))
return true;
return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
}
function rename_table($old_table, $new_table, $no_prefix = false)
{
// If the new table exists and the old one doesn't, then we're happy
if ($this->table_exists($new_table, $no_prefix) && !$this->table_exists($old_table, $no_prefix))
return true;
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$old_table.' RENAME TO '.($no_prefix ? '' : $this->prefix).$new_table) ? true : false;
}
function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
{
if ($this->field_exists($table_name, $field_name, $no_prefix))
return true;
$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
$default_value = '\''.$this->escape($default_value).'\'';
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
}
function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
{
if (!$this->field_exists($table_name, $field_name, $no_prefix))
return true;
$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
$default_value = '\''.$this->escape($default_value).'\'';
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
}
function drop_field($table_name, $field_name, $no_prefix = false)
{
if (!$this->field_exists($table_name, $field_name, $no_prefix))
return true;
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
}
function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
{
if ($this->index_exists($table_name, $index_name, $no_prefix))
return true;
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
}
function drop_index($table_name, $index_name, $no_prefix = false)
{
if (!$this->index_exists($table_name, $index_name, $no_prefix))
return true;
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
}
function truncate_table($table_name, $no_prefix = false)
{
return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
}
/**
* Удаляет поле из таблицы
*
* @param string $table
* @param string $field
* @param bool $noPrefix
*
* @return bool
*/
public function dropField($table, $field, $noPrefix = false)
{
if (! $this->fieldExists($table, $field, $noPrefix)) {
return true;
}
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
$this->testStr($table);
$this->testStr($field);
return $this->db->exec("ALTER TABLE `{$table}` DROP COLUMN `{$field}`") !== false;
}
/**
* Добавляет индекс в таблицу
*
* @param string $table
* @param string $index
* @param array $fields
* @param bool $unique
* @param bool $noPrefix
*
* @return bool
*/
public function addIndex($table, $index, array $fields, $unique = false, $noPrefix = false)
{
if ($this->indexExists($table, $index, $noPrefix)) {
return true;
}
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
$this->testStr($table);
$query = "ALTER TABLE `{$table}` ADD ";
if ($index == 'PRIMARY') {
$query .= 'PRIMARY KEY';
} else {
$index = $table . '_' . $index;
$this->testStr($index);
if ($unique) {
$query .= "UNIQUE `{$index}`";
} else {
$query .= "INDEX `{$index}`";
}
}
$query .= ' (' . $this->replIdxs($fields) . ')';
return $this->db->exec($query) !== false;
}
/**
* Удаляет индекс из таблицы
*
* @param string $table
* @param string $index
* @param bool $noPrefix
*
* @return bool
*/
public function dropIndex($table, $index, $noPrefix = false)
{
if (! $this->indexExists($table, $index, $noPrefix)) {
return true;
}
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
$this->testStr($table);
$query = "ALTER TABLE `{$table}` ";
if ($index == 'PRIMARY') {
$query .= "DROP PRIMARY KEY";
} else {
$index = $table . '_' . $index;
$this->testStr($index);
$query .= "DROP INDEX `{$index}`";
}
return $this->db->exec($query) !== false;
}
/**
* Очищает таблицу
*
* @param string $table
* @param bool $noPrefix
*
* @return bool
*/
public function truncateTable($table, $noPrefix = false)
{
$table = ($noPrefix ? '' : $this->dbPrefix) . $table;
$this->testStr($table);
return $this->db->exec("TRUNCATE TABLE `{$table}`") !== false;
}
/**
* Статистика
*
* @return array|string
*/
public function statistics()
{
$this->testStr($this->dbPrefix);
$stmt = $this->db->query("SHOW TABLE STATUS LIKE '{$this->dbPrefix}%'");
$records = $size = 0;
$engine = [];
while ($row = $stmt->fetch()) {
$records += $row['Rows'];
$size += $row['Data_length'] + $row['Index_length'];
if (isset($engine[$row['Engine']])) {
++$engine[$row['Engine']];
} else {
$engine[$row['Engine']] = 1;
}
}
arsort($engine);
$tmp = [];
foreach ($engine as $key => $val) {
$tmp[] = "{$key}({$val})";
}
$other = [];
$stmt = $this->db->query("SHOW VARIABLES LIKE 'character\_set\_%'");
while ($row = $stmt->fetch(\PDO::FETCH_NUM)) {
$other[$row[0]] = $row[1];
}
return [
'db' => 'MySQL (PDO) ' . $this->db->getAttribute(\PDO::ATTR_SERVER_VERSION) . ' : ' . implode(', ', $tmp),
'records' => $records,
'size' => $size,
'server info' => $this->db->getAttribute(\PDO::ATTR_SERVER_INFO),
] + $other;
}
}

374
app/Core/DBold/mysql.php Normal file
View file

@ -0,0 +1,374 @@
<?php
/**
* Copyright (C) 2008-2012 FluxBB
* based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
*/
namespace ForkBB\Core\DB;
// Make sure we have built in support for MySQL
if (!function_exists('mysql_connect'))
exit('This PHP environment doesn\'t have MySQL support built in. MySQL support is required if you want to use a MySQL database to run this forum. Consult the PHP documentation for further assistance.');
class DBLayer
{
var $prefix;
var $link_id;
var $query_result;
var $saved_queries = array();
var $num_queries = 0;
var $error_no = false;
var $error_msg = 'Unknown';
var $datatype_transformations = array(
'%^SERIAL$%' => 'INT(10) UNSIGNED AUTO_INCREMENT'
);
function __construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
{
$this->prefix = $db_prefix;
if ($p_connect)
$this->link_id = @mysql_pconnect($db_host, $db_username, $db_password);
else
$this->link_id = @mysql_connect($db_host, $db_username, $db_password);
if ($this->link_id)
{
if (!@mysql_select_db($db_name, $this->link_id))
error('Unable to select database. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
}
else
error('Unable to connect to MySQL server. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
// Setup the client-server character set (UTF-8)
if (!defined('FORUM_NO_SET_NAMES'))
$this->set_names('utf8');
return $this->link_id;
}
function start_transaction()
{
return;
}
function end_transaction()
{
return;
}
function query($sql, $unbuffered = false)
{
if (defined('PUN_SHOW_QUERIES'))
$q_start = microtime(true);
if ($unbuffered)
$this->query_result = @mysql_unbuffered_query($sql, $this->link_id);
else
$this->query_result = @mysql_query($sql, $this->link_id);
if ($this->query_result)
{
if (defined('PUN_SHOW_QUERIES'))
$this->saved_queries[] = array($sql, sprintf('%.5f', microtime(true) - $q_start));
++$this->num_queries;
return $this->query_result;
}
else
{
if (defined('PUN_SHOW_QUERIES'))
$this->saved_queries[] = array($sql, 0);
$this->error_no = @mysql_errno($this->link_id);
$this->error_msg = @mysql_error($this->link_id);
return false;
}
}
function result($query_id = 0, $row = 0, $col = 0)
{
return ($query_id) ? @mysql_result($query_id, $row, $col) : false;
}
function fetch_assoc($query_id = 0)
{
return ($query_id) ? @mysql_fetch_assoc($query_id) : false;
}
function fetch_row($query_id = 0)
{
return ($query_id) ? @mysql_fetch_row($query_id) : false;
}
function num_rows($query_id = 0)
{
return ($query_id) ? @mysql_num_rows($query_id) : false;
}
function affected_rows()
{
return ($this->link_id) ? @mysql_affected_rows($this->link_id) : false;
}
function insert_id()
{
return ($this->link_id) ? @mysql_insert_id($this->link_id) : false;
}
function get_num_queries()
{
return $this->num_queries;
}
function get_saved_queries()
{
return $this->saved_queries;
}
function free_result($query_id = false)
{
return ($query_id) ? @mysql_free_result($query_id) : false;
}
function escape($str)
{
if (is_array($str))
return '';
else if (function_exists('mysql_real_escape_string'))
return mysql_real_escape_string($str, $this->link_id);
else
return mysql_escape_string($str);
}
function error()
{
$result['error_sql'] = @current(@end($this->saved_queries));
$result['error_no'] = $this->error_no;
$result['error_msg'] = $this->error_msg;
return $result;
}
function close()
{
if ($this->link_id)
{
if (is_resource($this->query_result))
@mysql_free_result($this->query_result);
return @mysql_close($this->link_id);
}
else
return false;
}
function get_names()
{
$result = $this->query('SHOW VARIABLES LIKE \'character_set_connection\'');
return $this->result($result, 0, 1);
}
function set_names($names)
{
return $this->query('SET NAMES \''.$this->escape($names).'\'');
}
function get_version()
{
$result = $this->query('SELECT VERSION()');
return array(
'name' => 'MySQL Standard',
'version' => preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
);
}
function table_exists($table_name, $no_prefix = false)
{
$result = $this->query('SHOW TABLES LIKE \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\'');
return $this->num_rows($result) > 0;
}
function field_exists($table_name, $field_name, $no_prefix = false)
{
$result = $this->query('SHOW COLUMNS FROM '.($no_prefix ? '' : $this->prefix).$table_name.' LIKE \''.$this->escape($field_name).'\'');
return $this->num_rows($result) > 0;
}
function index_exists($table_name, $index_name, $no_prefix = false)
{
$exists = false;
$result = $this->query('SHOW INDEX FROM '.($no_prefix ? '' : $this->prefix).$table_name);
while ($cur_index = $this->fetch_assoc($result))
{
if (strtolower($cur_index['Key_name']) == strtolower(($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name))
{
$exists = true;
break;
}
}
return $exists;
}
function create_table($table_name, $schema, $no_prefix = false)
{
if ($this->table_exists($table_name, $no_prefix))
return true;
$query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
// Go through every schema element and add it to the query
foreach ($schema['FIELDS'] as $field_name => $field_data)
{
$field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
$query .= $field_name.' '.$field_data['datatype'];
if (isset($field_data['collation']))
$query .= 'CHARACTER SET utf8 COLLATE utf8_'.$field_data['collation'];
if (!$field_data['allow_null'])
$query .= ' NOT NULL';
if (isset($field_data['default']))
$query .= ' DEFAULT '.$field_data['default'];
$query .= ",\n";
}
// If we have a primary key, add it
if (isset($schema['PRIMARY KEY']))
$query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
// Add unique keys
if (isset($schema['UNIQUE KEYS']))
{
foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
$query .= 'UNIQUE KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$key_name.'('.implode(',', $key_fields).'),'."\n";
}
// Add indexes
if (isset($schema['INDEXES']))
{
foreach ($schema['INDEXES'] as $index_name => $index_fields)
$query .= 'KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.'('.implode(',', $index_fields).'),'."\n";
}
// We remove the last two characters (a newline and a comma) and add on the ending
$query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'MyISAM').' CHARACTER SET utf8';
return $this->query($query) ? true : false;
}
function drop_table($table_name, $no_prefix = false)
{
if (!$this->table_exists($table_name, $no_prefix))
return true;
return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
}
function rename_table($old_table, $new_table, $no_prefix = false)
{
// If the new table exists and the old one doesn't, then we're happy
if ($this->table_exists($new_table, $no_prefix) && !$this->table_exists($old_table, $no_prefix))
return true;
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$old_table.' RENAME TO '.($no_prefix ? '' : $this->prefix).$new_table) ? true : false;
}
function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
{
if ($this->field_exists($table_name, $field_name, $no_prefix))
return true;
$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
$default_value = '\''.$this->escape($default_value).'\'';
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
}
function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
{
if (!$this->field_exists($table_name, $field_name, $no_prefix))
return true;
$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
$default_value = '\''.$this->escape($default_value).'\'';
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
}
function drop_field($table_name, $field_name, $no_prefix = false)
{
if (!$this->field_exists($table_name, $field_name, $no_prefix))
return true;
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
}
function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
{
if ($this->index_exists($table_name, $index_name, $no_prefix))
return true;
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
}
function drop_index($table_name, $index_name, $no_prefix = false)
{
if (!$this->index_exists($table_name, $index_name, $no_prefix))
return true;
return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
}
function truncate_table($table_name, $no_prefix = false)
{
return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
}
}

View file

@ -476,7 +476,7 @@ foreach ($styles as $temp)
else
{
// Validate prefix
if (strlen($db_prefix) > 0 && (! preg_match('%^[a-zA-Z]\w*$%', $db_prefix) || strlen($db_prefix) > 40))
if (strlen($db_prefix) > 0 && (! preg_match('%^[a-z][a-z0-9_]*$%i', $db_prefix) || strlen($db_prefix) > 40))
error(sprintf($lang_install['Table prefix error'], $db->prefix));
$this->c->DB_TYPE = $db_type;

View file

@ -90,7 +90,7 @@ class Mail
{
if (! is_string($email)
|| mb_strlen($email, 'UTF-8') > 80
|| ! preg_match('%^([\w!#$\%&\'*+-/=?^`{|}~]+(?:\.[\w!#$\%&\'*+-/=?^`{|}~]+)*)@([^\x00-\x20]+)$%D', $email, $matches)
|| ! preg_match('%^([a-z0-9_!#$\%&\'*+-/=?^`{|}~]+(?:\.[a-z0-9_!#$\%&\'*+-/=?^`{|}~]+)*)@([^\x00-\x20]+)$%Di', $email, $matches)
) {
return false;
}

View file

@ -2,23 +2,24 @@
namespace ForkBB\Models\Actions;
//use ForkBB\Core\DB;
use ForkBB\Core\Container;
use ForkBB\Models\User;
class CacheGenerator
{
/**
* @var ForkBB\Core\DB
* Контейнер
* @var Container
*/
protected $db;
protected $c;
/**
* Конструктор
* @param ForkBB\Core\DB $db
* @param Container $container
*/
public function __construct($db)
public function __construct(Container $container)
{
$this->db = $db;
$this->c = $container;
}
/**
@ -27,14 +28,7 @@ class CacheGenerator
*/
public function config()
{
// Get the forum config from the DB
$result = $this->db->query('SELECT * FROM '.$this->db->prefix.'config', true) or error('Unable to fetch forum config', __FILE__, __LINE__, $this->db->error());
$arr = [];
while ($cur = $this->db->fetch_row($result)) {
$arr[$cur[0]] = $cur[1];
}
$this->db->free_result($result);
return $arr;
return $this->c->DB->query('SELECT conf_name, conf_value FROM ::config')->fetchAll(\PDO::FETCH_KEY_PAIR);
}
/**
@ -43,14 +37,7 @@ class CacheGenerator
*/
public function bans()
{
// Get the ban list from the DB
$result = $this->db->query('SELECT * FROM '.$this->db->prefix.'bans', true) or error('Unable to fetch ban list', __FILE__, __LINE__, $this->db->error());
$arr = [];
while ($cur = $this->db->fetch_assoc($result)) {
$arr[] = $cur;
}
$this->db->free_result($result);
return $arr;
return $this->c->DB->query('SELECT id, username, ip, email, message, expire FROM ::bans')->fetchAll();
}
/**
@ -59,17 +46,13 @@ class CacheGenerator
*/
public function censoring()
{
$result = $this->db->query('SELECT search_for, replace_with FROM '.$this->db->prefix.'censoring') or error('Unable to fetch censoring list', __FILE__, __LINE__, $this->db->error());
$num_words = $this->db->num_rows($result);
$search_for = $replace_with = [];
for ($i = 0; $i < $num_words; $i++) {
list($search_for[$i], $replace_with[$i]) = $this->db->fetch_row($result);
$search_for[$i] = '%(?<![\p{L}\p{N}])('.str_replace('\*', '[\p{L}\p{N}]*?', preg_quote($search_for[$i], '%')).')(?![\p{L}\p{N}])%iu';
$stmt = $this->c->DB->query('SELECT search_for, replace_with FROM ::censoring');
$search = $replace = [];
while ($row = $stmt->fetch()) {
$replace[] = $row['replace_with'];
$search[] = '%(?<![\p{L}\p{N}])('.str_replace('\*', '[\p{L}\p{N}]*?', preg_quote($row['search_for'], '%')).')(?![\p{L}\p{N}])%iu';
}
$this->db->free_result($result);
return [$search_for, $replace_with];
return [$search, $replace];
}
/**
@ -80,13 +63,8 @@ class CacheGenerator
public function usersInfo()
{
$stats = [];
$result = $this->db->query('SELECT COUNT(id)-1 FROM '.$this->db->prefix.'users WHERE group_id!='.PUN_UNVERIFIED) or error('Unable to fetch total user count', __FILE__, __LINE__, $this->db->error());
$stats['total_users'] = $this->db->result($result);
$result = $this->db->query('SELECT id, username FROM '.$this->db->prefix.'users WHERE group_id!='.PUN_UNVERIFIED.' ORDER BY registered DESC LIMIT 1') or error('Unable to fetch newest registered user', __FILE__, __LINE__, $this->db->error());
$stats['last_user'] = $this->db->fetch_assoc($result);
$stats['total_users'] = $this->c->DB->query('SELECT COUNT(id)-1 FROM ::users WHERE group_id!='.PUN_UNVERIFIED)->fetchColumn();
$stats['last_user'] = $this->c->DB->query('SELECT id, username FROM ::users WHERE group_id!='.PUN_UNVERIFIED.' ORDER BY registered DESC LIMIT 1')->fetch();
return $stats;
}
@ -96,15 +74,7 @@ class CacheGenerator
*/
public function admins()
{
// Get admins from the DB
$result = $this->db->query('SELECT id FROM '.$this->db->prefix.'users WHERE group_id='.PUN_ADMIN) or error('Unable to fetch users info', __FILE__, __LINE__, $this->db->error());
$arr = [];
while ($row = $this->db->fetch_row($result)) {
$arr[] = $row[0];
}
$this->db->free_result($result);
return $arr;
return $this->c->DB->query('SELECT id FROM ::users WHERE group_id='.PUN_ADMIN)->fetchAll(\PDO::FETCH_COLUMN);
}
/**
@ -113,14 +83,7 @@ class CacheGenerator
*/
public function smilies()
{
$arr = [];
$result = $this->db->query('SELECT text, image FROM '.$this->db->prefix.'smilies ORDER BY disp_position') or error('Unable to retrieve smilies', __FILE__, __LINE__, $this->db->error());
while ($cur = $this->db->fetch_assoc($result)) {
$arr[$cur['text']] = $cur['image'];
}
$this->db->free_result($result);
return $arr;
return $this->c->DB->query('SELECT text, image FROM ::smilies ORDER BY disp_position')->fetchAll(\PDO::FETCH_KEY_PAIR); //???? text уникальное?
}
/**
@ -129,22 +92,20 @@ class CacheGenerator
*/
public function forums(User $user)
{
$groupId = $user->gId;
$result = $this->db->query('SELECT g_read_board FROM '.$this->db->prefix.'groups WHERE g_id='.$groupId) or error('Unable to fetch user group read permission', __FILE__, __LINE__, $this->db->error());
$read = $this->db->result($result);
$stmt = $this->c->DB->query('SELECT g_read_board FROM ::groups WHERE g_id=?i:id', [':id' => $user->gId]);
$read = $stmt->fetchColumn();
$stmt->closeCursor();
$tree = $desc = $asc = [];
if ($read) {
$result = $this->db->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url, f.parent_forum_id, f.disp_position FROM '.$this->db->prefix.'categories AS c INNER JOIN '.$this->db->prefix.'forums AS f ON c.id=f.cat_id LEFT JOIN '.$this->db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$groupId.') WHERE fp.read_forum IS NULL OR fp.read_forum=1 ORDER BY c.disp_position, c.id, f.disp_position', true) or error('Unable to fetch category/forum list', __FILE__, __LINE__, $this->db->error());
while ($f = $this->db->fetch_assoc($result)) {
$stmt = $this->c->DB->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url, f.parent_forum_id, f.disp_position FROM ::categories AS c INNER JOIN ::forums AS f ON c.id=f.cat_id LEFT JOIN ::forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id=?i:id) WHERE fp.read_forum IS NULL OR fp.read_forum=1 ORDER BY c.disp_position, c.id, f.disp_position', [':id' => $user->gId]);
while ($f = $stmt->fetch()) {
$tree[$f['parent_forum_id']][$f['fid']] = $f;
}
$this->forumsDesc($desc, $tree);
$this->forumsAsc($asc, $tree);
}
return [$tree, $desc, $asc];
}

View file

@ -34,7 +34,6 @@ class CheckBans
{
$user = $this->c->user;
// Для админов и при отсутствии банов прекращаем проверку
if ($user->isAdmin) {
return null;
} elseif ($user->isGuest) {
@ -46,9 +45,9 @@ class CheckBans
if ($banned) {
$this->c->Online->delete($user); //???? а зачем это надо?
return $this->ban;
} else {
return null;
}
return null;
}
/**
@ -102,12 +101,9 @@ class CheckBans
}
}
}
// If we removed any expired bans during our run-through, we need to regenerate the bans cache
if (! empty($remove))
{
$db = $this->c->DB;
$db->query('DELETE FROM '.$db->prefix.'bans WHERE id IN (' . implode(',', $remove) . ')') or error('Unable to delete expired ban', __FILE__, __LINE__, $db->error());
$this->c->DB->exec('DELETE FROM ::bans WHERE id IN (?ai:remove)', [':remove' => $remove]);
$this->c->{'bans update'};
}
return $banned;

View file

@ -62,7 +62,7 @@ class LoadUserFromCookie
// быстрое переключение языка - Visman
$language = $this->cookie->get('glang');
if (null !== $language) {
$language = preg_replace('%[^\w]%', '', $language);
$language = preg_replace('%[^a-zA-Z0-9_]%', '', $language);
$languages = forum_list_langs();
if (in_array($language, $languages)) {
$user->language = $language;
@ -138,7 +138,7 @@ class LoadUserFromCookie
$agent = preg_replace('%(?:https?://|www\.)[^\)]*(\)[^/]+$)?%i', ' ', $agent);
}
if (strpos($agent, '@') !== false) {
$agent = preg_replace('%\b[\w\.-]+@[^\)]+%', ' ', $agent);
$agent = preg_replace('%\b[a-z0-9_\.-]+@[^\)]+%i', ' ', $agent);
}
$agentL = strtolower($agent);

View file

@ -5,7 +5,6 @@ namespace ForkBB\Models;
use ForkBB\Core\Container;
use ForkBB\Models\User;
use ForkBB\Models\Pages\Page;
use RuntimeException;
class Online
{
@ -26,29 +25,15 @@ class Online
*/
protected $config;
/**
* @var DB
*/
protected $db;
/**
* @var User
*/
protected $user;
/**
* Конструктор
* @param array $config
* @param DB $db
* @param User $user
* @param Container $container
*/
public function __construct(array $config, $db, User $user, Container $container)
public function __construct(Container $container)
{
$this->config = $config;
$this->db = $db;
$this->user = $user;
$this->c = $container;
$this->config = $container->config;
}
/**
@ -83,13 +68,13 @@ class Online
$setIdle = false;
if ($this->config['o_users_online'] == '1' && $type) {
$result = $this->db->query('SELECT user_id, ident, logged, idle, o_position, o_name FROM '.$this->db->prefix.'online ORDER BY logged') or error('Unable to fetch users from online list', __FILE__, __LINE__, $this->db->error());
$stmt = $this->c->DB->query('SELECT user_id, ident, logged, idle, o_position, o_name FROM ::online ORDER BY logged');
} elseif ($type) {
$result = $this->db->query('SELECT user_id, ident, logged, idle FROM '.$this->db->prefix.'online ORDER BY logged') or error('Unable to fetch users from online list', __FILE__, __LINE__, $this->db->error());
$stmt = $this->c->DB->query('SELECT user_id, ident, logged, idle FROM ::online ORDER BY logged');
} else {
$result = $this->db->query('SELECT user_id, ident, logged, idle FROM '.$this->db->prefix.'online WHERE logged<'.$tOnline) or error('Unable to fetch users from online list', __FILE__, __LINE__, $this->db->error());
$stmt = $this->c->DB->query('SELECT user_id, ident, logged, idle FROM ::online WHERE logged<?i:online', [':online' => $tOnline]);
}
while ($cur = $this->db->fetch_assoc($result)) {
while ($cur = $stmt->fetch()) {
// посетитель уже не онлайн (или почти не онлайн)
if ($cur['logged'] < $tOnline) {
@ -97,7 +82,7 @@ class Online
if ($cur['user_id'] > 1) {
if ($cur['logged'] < $tVisit) {
$deleteU = true;
$this->db->query('UPDATE '.$this->db->prefix.'users SET last_visit='.$cur['logged'].' WHERE id='.$cur['user_id']) or error('Unable to update user visit data', __FILE__, __LINE__, $this->db->error());
$this->c->DB->exec('UPDATE ::users SET last_visit=?i:last WHERE id=?i:id', [':last' => $cur['logged'], ':id' => $cur['user_id']]);
} elseif ($cur['idle'] == '0') {
$setIdle = true;
}
@ -140,36 +125,28 @@ class Online
++$all;
}
}
$this->db->free_result($result);
// удаление просроченных пользователей
if ($deleteU) {
$this->db->query('DELETE FROM '.$this->db->prefix.'online WHERE logged<'.$tVisit) or error('Unable to delete from online list', __FILE__, __LINE__, $this->db->error());
$this->c->DB->exec('DELETE FROM ::online WHERE logged<?i:visit', [':visit' => $tVisit]);
}
// удаление просроченных гостей
if ($deleteG) {
$this->db->query('DELETE FROM '.$this->db->prefix.'online WHERE user_id=1 AND logged<'.$tOnline) or error('Unable to delete from online list', __FILE__, __LINE__, $this->db->error());
$this->c->DB->exec('DELETE FROM ::online WHERE user_id=1 AND logged<?i:online', [':online' => $tOnline]);
}
// обновление idle
if ($setIdle) {
$this->db->query('UPDATE '.$this->db->prefix.'online SET idle=1 WHERE logged<'.$tOnline) or error('Unable to update into online list', __FILE__, __LINE__, $this->db->error());
$this->c->DB->exec('UPDATE ::online SET idle=1 WHERE logged<?i:online', [':online' => $tOnline]);
}
// обновление максимального значение пользоватеелй онлайн
if ($this->config['st_max_users'] < $all) {
$this->db->query('UPDATE '.$this->db->prefix.'config SET conf_value=\''.$all.'\' WHERE conf_name=\'st_max_users\'') or error('Unable to update config value \'st_max_users\'', __FILE__, __LINE__, $this->db->error());
$this->db->query('UPDATE '.$this->db->prefix.'config SET conf_value=\''.$now.'\' WHERE conf_name=\'st_max_users_time\'') or error('Unable to update config value \'st_max_users_time\'', __FILE__, __LINE__, $this->db->error());
$this->c->DB->exec('UPDATE ::config SET conf_value=?s:value WHERE conf_name=?s:name', [':value' => $all, ':name' => 'st_max_users']);
$this->c->DB->exec('UPDATE ::config SET conf_value=?s:value WHERE conf_name=?s:name', [':value' => $now, ':name' => 'st_max_users_time']);
$this->c->{'config update'};
}
/*
@set_time_limit(0);
for ($i=0;$i<100;++$i) {
$this->db->query('REPLACE INTO '.$this->db->prefix.'online (user_id, ident, logged, o_position, o_name) VALUES(1, \''.$this->db->escape($i).'\', '.time().', \''.$this->db->escape($position).'\', \'Super Puper '.$this->db->escape($i).'\')') or error('Unable to insert into online list', __FILE__, __LINE__, $this->db->error());
}
*/
return [$users, $guests, $bots];
}
@ -181,52 +158,30 @@ for ($i=0;$i<100;++$i) {
{
$now = time();
// гость
if ($this->user->isGuest) {
$oname = (string) $this->user->isBot;
if ($this->user->isLogged) {
$this->db->query('UPDATE '.$this->db->prefix.'online SET logged='.$now.', o_position=\''.$this->db->escape($position).'\', o_name=\''.$this->db->escape($oname).'\' WHERE user_id=1 AND ident=\''.$this->db->escape($this->user->ip).'\'') or error('Unable to update online list', __FILE__, __LINE__, $this->db->error());
if ($this->c->user->isGuest) {
$vars = [
':logged' => time(),
':pos' => $position,
':name' => (string) $this->c->user->isBot,
':ip' => $this->c->user->ip
];
if ($this->c->user->isLogged) {
$this->c->DB->exec('UPDATE ::online SET logged=?i:logged, o_position=?s:pos, o_name=?s:name WHERE user_id=1 AND ident=?s:ip', $vars);
} else {
$this->db->query('INSERT INTO '.$this->db->prefix.'online (user_id, ident, logged, o_position, o_name) SELECT 1, \''.$this->db->escape($this->user->ip).'\', '.$now.', \''.$this->db->escape($position).'\', \''.$this->db->escape($oname).'\' FROM '.$this->db->prefix.'groups WHERE NOT EXISTS (SELECT 1 FROM '.$this->db->prefix.'online WHERE user_id=1 AND ident=\''.$this->db->escape($this->user->ip).'\') LIMIT 1') or error('Unable to insert into online list', __FILE__, __LINE__, $this->db->error());
// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
/* switch ($this->c->DB_TYPE) {
case 'mysql':
case 'mysqli':
case 'mysql_innodb':
case 'mysqli_innodb':
case 'sqlite':
$this->db->query('REPLACE INTO '.$this->db->prefix.'online (user_id, ident, logged, o_position, o_name) VALUES(1, \''.$this->db->escape($this->user->ip).'\', '.$now.', \''.$this->db->escape($position).'\', \''.$this->db->escape($oname).'\')') or error('Unable to insert into online list', __FILE__, __LINE__, $this->db->error());
break;
default:
$this->db->query('INSERT INTO '.$this->db->prefix.'online (user_id, ident, logged, o_position, o_name) SELECT 1, \''.$this->db->escape($this->user->ip).'\', '.$now.', \''.$this->db->escape($position).'\', \''.$this->db->escape($oname).'\' WHERE NOT EXISTS (SELECT 1 FROM '.$this->db->prefix.'online WHERE user_id=1 AND ident=\''.$this->db->escape($this->user->ip).'\')') or error('Unable to insert into online list', __FILE__, __LINE__, $this->db->error());
break;
}
*/
$this->c->DB->exec('INSERT INTO ::online (user_id, ident, logged, o_position, o_name) SELECT 1, ?s:ip, ?i:logged, ?s:pos, ?s:name FROM ::groups WHERE NOT EXISTS (SELECT 1 FROM ::online WHERE user_id=1 AND ident=?s:ip) LIMIT 1', $vars);
}
} else {
// пользователь
if ($this->user->isLogged) {
$idle_sql = ($this->user->idle == '1') ? ', idle=0' : '';
$this->db->query('UPDATE '.$this->db->prefix.'online SET logged='.$now.$idle_sql.', o_position=\''.$this->db->escape($position).'\' WHERE user_id='.$this->user->id) or error('Unable to update online list', __FILE__, __LINE__, $this->db->error());
$vars = [
':logged' => time(),
':pos' => $position,
':id' => $this->c->user->id,
':name' => $this->c->user->username,
];
if ($this->c->user->isLogged) {
$this->c->DB->exec('UPDATE ::online SET logged=?i:logged, idle=0, o_position=?s:pos WHERE user_id=?i:id', $vars);
} else {
$this->db->query('INSERT INTO '.$this->db->prefix.'online (user_id, ident, logged, o_position) SELECT '.$this->user->id.', \''.$this->db->escape($this->user->username).'\', '.$now.', \''.$this->db->escape($position).'\' FROM '.$this->db->prefix.'groups WHERE NOT EXISTS (SELECT 1 FROM '.$this->db->prefix.'online WHERE user_id='.$this->user->id.') LIMIT 1') or error('Unable to insert into online list', __FILE__, __LINE__, $this->db->error());
// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
/* switch ($this->c->DB_TYPE) {
case 'mysql':
case 'mysqli':
case 'mysql_innodb':
case 'mysqli_innodb':
case 'sqlite':
$this->db->query('REPLACE INTO '.$this->db->prefix.'online (user_id, ident, logged, o_position) VALUES('.$this->user->id.', \''.$this->db->escape($this->user->username).'\', '.$now.', \''.$this->db->escape($position).'\')') or error('Unable to insert into online list', __FILE__, __LINE__, $this->db->error());
break;
default:
$this->db->query('INSERT INTO '.$this->db->prefix.'online (user_id, ident, logged, o_position) SELECT '.$this->user->id.', \''.$this->db->escape($this->user->username).'\', '.$now.', \''.$this->db->escape($position).'\' WHERE NOT EXISTS (SELECT 1 FROM '.$this->db->prefix.'online WHERE user_id='.$this->user->id.')') or error('Unable to insert into online list', __FILE__, __LINE__, $this->db->error());
break;
}
*/
$this->c->DB->exec('INSERT INTO ::online (user_id, ident, logged, o_position) SELECT ?i:id, ?s:name, ?i:logged, ?s:pos FROM ::groups WHERE NOT EXISTS (SELECT 1 FROM ::online WHERE user_id=?i:id) LIMIT 1', $vars);
}
}
}
@ -237,9 +192,9 @@ for ($i=0;$i<100;++$i) {
public function delete(User $user)
{
if ($user->isGuest) {
$this->db->query('DELETE FROM '.$this->db->prefix.'online WHERE user_id=1 AND ident=\''.$this->db->escape($user->ip).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $this->db->error());
$this->c->DB->exec('DELETE FROM ::online WHERE user_id=1 AND ident=?s:ip', [':ip' => $user->ip]);
} else {
$this->db->query('DELETE FROM '.$this->db->prefix.'online WHERE user_id='.$user->id) or error('Unable to delete from online list', __FILE__, __LINE__, $this->db->error());
$this->c->DB->exec('DELETE FROM ::online WHERE user_id=?i:id', [':id' => $user->id]);
}
}
}

View file

@ -66,27 +66,14 @@ class Statistics extends Admin
}
// Get number of current visitors
$db = $this->c->DB;
$result = $db->query('SELECT COUNT(user_id) FROM '.$db->prefix.'online WHERE idle=0') or error('Unable to fetch online count', __FILE__, __LINE__, $db->error());
$this->data['numOnline'] = $db->result($result);
$this->data['numOnline'] = $this->c->DB->query('SELECT COUNT(user_id) FROM ::online WHERE idle=0')->fetchColumn();
// Collect some additional info about MySQL
if (in_array($this->c->DB_TYPE, ['mysql', 'mysqli', 'mysql_innodb', 'mysqli_innodb'])) {
// Calculate total db size/row count
$result = $db->query('SHOW TABLE STATUS LIKE \''.$db->prefix.'%\'') or error('Unable to fetch table status', __FILE__, __LINE__, $db->error());
$tRecords = $tSize = 0;
while ($status = $db->fetch_assoc($result)) {
$tRecords += $status['Rows'];
$tSize += $status['Data_length'] + $status['Index_length'];
}
$this->data['tSize'] = $this->size($tSize);
$this->data['tRecords'] = $this->number($tRecords);
} else {
$this->data['tSize'] = 0;
$this->data['tRecords'] = 0;
}
$stat = $this->c->DB->statistics();
$this->data['dbVersion'] = $stat['db'];
$this->data['tSize'] = $this->size($stat['size']);
$this->data['tRecords'] = $this->number($stat['records']);
unset($stat['db'], $stat['size'], $stat['records']);
$this->data['tOther'] = $stat;
// Check for the existence of various PHP opcode caches/optimizers
if (function_exists('mmcache')) {
@ -105,8 +92,6 @@ class Statistics extends Admin
$this->data['accelerator'] = __('NA');
}
$this->data['dbVersion'] = implode(' ', $db->get_version());
return $this;
}
}

View file

@ -24,12 +24,12 @@ class Debug extends Page
{
$this->data = [
'time' => $this->number(microtime(true) - (empty($_SERVER['REQUEST_TIME_FLOAT']) ? $this->c->START : $_SERVER['REQUEST_TIME_FLOAT']), 3),
'numQueries' => $this->c->DB->get_num_queries(),
'numQueries' => 0, //$this->c->DB->get_num_queries(),
'memory' => $this->size(memory_get_usage()),
'peak' => $this->size(memory_get_peak_usage()),
];
if (defined('PUN_SHOW_QUERIES')) {
if (defined('PUN_SHOW_QUERIES') && 0) {
$this->data['queries'] = $this->c->DB->get_saved_queries();
} else {
$this->data['queries'] = null;

View file

@ -39,14 +39,13 @@ class Index extends Page
$this->c->Lang->load('index');
$this->c->Lang->load('subforums');
$db = $this->c->DB;
$user = $this->c->user;
$r = $this->c->Router;
$stats = $this->c->users_info;
$result = $db->query('SELECT SUM(num_topics), SUM(num_posts) FROM '.$db->prefix.'forums') or error('Unable to fetch topic/post count', __FILE__, __LINE__, $db->error());
list($stats['total_topics'], $stats['total_posts']) = array_map([$this, 'number'], array_map('intval', $db->fetch_row($result)));
$stmt = $this->c->DB->query('SELECT SUM(num_topics), SUM(num_posts) FROM ::forums');
list($stats['total_topics'], $stats['total_posts']) = array_map([$this, 'number'], array_map('intval', $stmt->fetch(\PDO::FETCH_NUM)));
$stats['total_users'] = $this->number($stats['total_users']);
@ -126,22 +125,22 @@ class Index extends Page
return [];
}
$db = $this->c->DB;
$user = $this->c->user;
// текущие данные по подразделам
$forums = array_slice($fAsc[$root], 1);
$vars = [
':id' => $user->id,
':forums' => array_slice($fAsc[$root], 1),
];
if ($user->isGuest) {
$result = $db->query('SELECT id, forum_desc, moderators, num_topics, num_posts, last_post, last_post_id, last_poster, last_topic FROM '.$db->prefix.'forums WHERE id IN ('.implode(',', $forums).')', true) or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error());
$stmt = $this->c->DB->query('SELECT id, forum_desc, moderators, num_topics, num_posts, last_post, last_post_id, last_poster, last_topic FROM ::forums WHERE id IN (?ai:forums)', $vars);
} else {
$result = $db->query('SELECT f.id, f.forum_desc, f.moderators, f.num_topics, f.num_posts, f.last_post, f.last_post_id, f.last_poster, f.last_topic, mof.mf_upper FROM '.$db->prefix.'forums AS f LEFT JOIN '.$db->prefix.'mark_of_forum AS mof ON (mof.uid='.$user->id.' AND f.id=mof.fid) WHERE f.id IN ('.implode(',', $forums).')', true) or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error());
$stmt = $this->c->DB->query('SELECT f.id, f.forum_desc, f.moderators, f.num_topics, f.num_posts, f.last_post, f.last_post_id, f.last_poster, f.last_topic, mof.mf_upper FROM ::forums AS f LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:id AND f.id=mof.fid) WHERE f.id IN (?ai:forums)', $vars);
}
$forums = [];
while ($cur = $db->fetch_assoc($result)) {
while ($cur = $stmt->fetch()) {
$forums[$cur['id']] = $cur;
}
$db->free_result($result);
// поиск новых
$new = [];
@ -156,15 +155,19 @@ class Index extends Page
}
// проверка по темам
if (! empty($new)) {
$result = $db->query('SELECT t.forum_id, t.id, t.last_post FROM '.$db->prefix.'topics AS t LEFT JOIN '.$db->prefix.'mark_of_topic AS mot ON (mot.uid='.$user->id.' AND mot.tid=t.id) WHERE t.forum_id IN('.implode(',', array_keys($new)).') AND t.last_post>'.$max.' AND t.moved_to IS NULL AND (mot.mt_upper IS NULL OR t.last_post>mot.mt_upper)') or error('Unable to fetch new topics', __FILE__, __LINE__, $db->error());
$vars = [
':id' => $user->id,
':forums' => $new,
':max' => $max,
];
$stmt = $this->c->DB->query('SELECT t.forum_id, t.id, t.last_post FROM ::topics AS t LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:id AND mot.tid=t.id) WHERE t.forum_id IN(?ai:forums) AND t.last_post>?i:max AND t.moved_to IS NULL AND (mot.mt_upper IS NULL OR t.last_post>mot.mt_upper)', $vars);
$tmp = [];
while ($cur = $db->fetch_assoc($result)) {
while ($cur = $stmt->fetch()) {
if ($cur['last_post']>$new[$cur['forum_id']]) {
$tmp[$cur['forum_id']] = true;
}
}
$new = $tmp;
$db->free_result($result);
}
}

View file

@ -1,127 +0,0 @@
<?php
namespace ForkBB\Models;
use ForkBB\Core\Model; //????
use R2\DependencyInjection\ContainerInterface;
use RuntimeException;
class User extends Model
{
/**
* Контейнер
* @var ContainerInterface
*/
protected $c;
/**
* @var array
*/
protected $config;
/**
* @var UserCookie
*/
protected $userCookie;
/**
* @var DB
*/
protected $db;
/**
* Конструктор
*/
public function __construct(array $config, $cookie, $db, ContainerInterface $container)
{
$this->config = $config;
$this->userCookie = $cookie;
$this->db = $db;
$this->c = $container;
}
/**
* @return User
*/
public function init()
{
$this->current = $this->c->get('LoadCurrentUser')->load();
return $this;
}
/**
* Выход
*/
public function logout()
{
if ($this->current['is_guest']) {
return;
}
$this->userCookie->deleteUserCookie();
$this->c->get('Online')->delete($this);
// Update last_visit (make sure there's something to update it with)
if (isset($this->current['logged'])) {
$this->db->query('UPDATE '.$this->db->prefix.'users SET last_visit='.$this->current['logged'].' WHERE id='.$this->current['id']) or error('Unable to update user visit data', __FILE__, __LINE__, $this->db->error());
}
}
/**
* Вход
* @param string $name
* @param string $password
* @param bool $save
* @return mixed
*/
public function login($name, $password, $save)
{
$result = $this->db->query('SELECT u.id, u.group_id, u.username, u.password, u.registration_ip, g.g_moderator FROM '.$this->db->prefix.'users AS u LEFT JOIN '.$this->db->prefix.'groups AS g ON u.group_id=g.g_id WHERE u.username=\''.$this->db->escape($name).'\'') or error('Unable to fetch user info', __FILE__, __LINE__, $this->db->error());
$user = $this->db->fetch_assoc($result);
$this->db->free_result($result);
if (empty($user['id'])) {
return false;
}
$authorized = false;
// For FluxBB by Visman 1.5.10.74 and above
if (strlen($user['password']) == 40) {
if (hash_equals($user['password'], sha1($password . $this->c->getParameter('SALT1')))) {
$authorized = true;
$user['password'] = password_hash($password, PASSWORD_DEFAULT);
$this->db->query('UPDATE '.$this->db->prefix.'users SET password=\''.$this->db->escape($user['password']).'\' WHERE id='.$user['id']) or error('Unable to update user password', __FILE__, __LINE__, $this->db->error());
}
} else {
$authorized = password_verify($password, $user['password']);
}
if (! $authorized) {
return false;
}
// Update the status if this is the first time the user logged in
if ($user['group_id'] == PUN_UNVERIFIED)
{
$this->db->query('UPDATE '.$this->db->prefix.'users SET group_id='.$this->config['o_default_user_group'].' WHERE id='.$user['id']) or error('Unable to update user status', __FILE__, __LINE__, $this->db->error());
$this->c->get('users_info update');
}
// перезаписываем ip админа и модератора - Visman
if ($this->config['o_check_ip'] == '1' && $user['registration_ip'] != $this->current['ip'])
{
if ($user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1')
$this->db->query('UPDATE '.$this->db->prefix.'users SET registration_ip=\''.$this->db->escape($this->current['ip']).'\' WHERE id='.$user['id']) or error('Unable to update user IP', __FILE__, __LINE__, $this->db->error());
}
$this->c->get('Online')->delete($this);
$this->c->get('UserCookie')->setUserCookie($user['id'], $user['password'], $save);
return $user['id'];
}
}

View file

@ -20,11 +20,6 @@ class UserMapper
*/
protected $config;
/**
* @var DB
*/
protected $db;
/**
* Конструктор
* @param Container $container
@ -33,7 +28,6 @@ class UserMapper
{
$this->c = $container;
$this->config = $container->config;
$this->db = $container->DB;
}
/**
@ -54,23 +48,16 @@ class UserMapper
public function getCurrent($id = 1)
{
$ip = $this->getIpAddress();
$id = (int) $id;
$user = null;
if ($id > 1) {
$result = $this->db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$this->db->prefix.'users AS u INNER JOIN '.$this->db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$this->db->prefix.'online AS o ON o.user_id=u.id WHERE u.id='.$id) or error('Unable to fetch user information', __FILE__, __LINE__, $this->db->error());
$user = $this->db->fetch_assoc($result);
$this->db->free_result($result);
$user = $this->c->DB->query('SELECT u.*, g.*, o.logged, o.idle FROM ::users AS u INNER JOIN ::groups AS g ON u.group_id=g.g_id LEFT JOIN ::online AS o ON o.user_id=u.id WHERE u.id=?i:id', [':id' => $id])->fetch();
}
if (empty($user['id'])) {
$result = $this->db->query('SELECT u.*, g.*, o.logged, o.last_post, o.last_search FROM '.$this->db->prefix.'users AS u INNER JOIN '.$this->db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$this->db->prefix.'online AS o ON (o.user_id=1 AND o.ident=\''.$this->db->escape($ip).'\') WHERE u.id=1') or error('Unable to fetch guest information', __FILE__, __LINE__, $this->db->error());
$user = $this->db->fetch_assoc($result);
$this->db->free_result($result);
$user = $this->c->DB->query('SELECT u.*, g.*, o.logged, o.last_post, o.last_search FROM ::users AS u INNER JOIN ::groups AS g ON u.group_id=g.g_id LEFT JOIN ::online AS o ON (o.user_id=1 AND o.ident=?s:ip) WHERE u.id=1', [':ip' => $ip])->fetch();
}
if (empty($user['id'])) {
throw new RuntimeException('Unable to fetch guest information. Your database must contain both a guest user and a guest user group.');
}
$user['ip'] = $ip;
return new User($user, $this->c);
}
@ -82,7 +69,7 @@ class UserMapper
public function updateLastVisit(User $user)
{
if ($user->isLogged) {
$this->db->query('UPDATE '.$this->db->prefix.'users SET last_visit='.$user->logged.' WHERE id='.$user->id) or error('Unable to update user visit data', __FILE__, __LINE__, $this->db->error());
$this->c->DB->exec('UPDATE ::users SET last_visit=?i:loggid WHERE id=?i:id', [':loggid' => $user->logged, ':id' => $user->id]);
}
}
@ -97,33 +84,27 @@ class UserMapper
{
switch ($field) {
case 'id':
$where = 'u.id=' . (int) $value;
$where = 'u.id= ?i';
break;
case 'username':
$where = 'u.username=\'' . $this->db->escape($value) . '\'';
$where = 'u.username= ?s';
break;
case 'email':
$where = 'u.email=\'' . $this->db->escape($value) . '\'';
$where = 'u.email= ?s';
break;
default:
throw new InvalidArgumentException('Field not supported');
}
$result = $this->db->query('SELECT u.*, g.* FROM '.$this->db->prefix.'users AS u LEFT JOIN '.$this->db->prefix.'groups AS g ON u.group_id=g.g_id WHERE '.$where) or error('Unable to fetch user information', __FILE__, __LINE__, $this->db->error());
$result = $this->c->DB->query('SELECT u.*, g.* FROM ::users AS u LEFT JOIN ::groups AS g ON u.group_id=g.g_id WHERE ' . $where, [$value])->fetchAll();
// найдено несколько пользователей
if ($this->db->num_rows($result) !== 1) {
return $this->db->num_rows($result);
if (count($result) !== 1) {
return count($result);
}
$user = $this->db->fetch_assoc($result);
$this->db->free_result($result);
// найден гость
if ($user['id'] == 1) {
if ($result[0]['id'] == 1) {
return 1;
}
return new User($user, $this->c);
return new User($result[0], $this->c);
}
/**
@ -133,8 +114,12 @@ class UserMapper
*/
public function isUnique($username)
{
$result = $this->db->query('SELECT username FROM '.$this->db->prefix.'users WHERE (UPPER(username)=UPPER(\''.$this->db->escape($username).'\') OR UPPER(username)=UPPER(\''.$this->db->escape(preg_replace('%[^\p{L}\p{N}]%u', '', $username)).'\'))') or error('Unable to fetch user info', __FILE__, __LINE__, $this->db->error());
return ! $this->db->num_rows($result);
$vars = [
':name' => $username,
':other' => preg_replace('%[^\p{L}\p{N}]%u', '', $username),
];
$result = $this->c->DB->query('SELECT username FROM ::users WHERE UPPER(username)=UPPER(?s:name) OR UPPER(username)=UPPER(?s:other)', $vars)->fetchAll();
return ! count($result);
}
/**
@ -149,19 +134,17 @@ class UserMapper
return;
}
$set = [];
$set = $vars = [];
foreach ($update as $field => $value) {
if (! is_string($field) || (null !== $value && ! is_int($value) && ! is_string($value))) {
return;
}
if (null === $value) {
$set[] = $field . '= NULL';
$vars[] = $value;
if (is_int($value)) {
$set[] = $field . ' = ?i';
} else {
$set[] = $field . '=' . (is_int($value) ? $value : '\'' . $this->db->escape($value) . '\'');
$set[] = $field . ' = ?s';
}
}
$this->db->query('UPDATE '.$this->db->prefix.'users SET '.implode(', ', $set).' WHERE id='.$id) or error('Unable to update user data', __FILE__, __LINE__, $this->db->error());
$vars[] = $id;
$this->c->DB->query('UPDATE ::users SET ' . implode(', ', $set) . ' WHERE id=?i', $vars); //????
}
/**
@ -172,8 +155,23 @@ class UserMapper
*/
public function newUser(User $user)
{
$this->db->query('INSERT INTO '.$this->db->prefix.'users (username, group_id, password, email, email_confirmed, email_setting, timezone, dst, language, style, registered, registration_ip, activate_string, u_mark_all_read) VALUES(\''.$this->db->escape($user->username).'\', '.$user->groupId.', \''.$this->db->escape($user->password).'\', \''.$this->db->escape($user->email).'\', '.$user->emailConfirmed.', '.$this->config['o_default_email_setting'].', '.$this->config['o_default_timezone'].' , '.$this->config['o_default_dst'].', \''.$this->db->escape($user->language).'\', \''.$user->style.'\', '.time().', \''.$this->db->escape($this->getIpAddress()).'\', \''.$this->db->escape($user->activateString).'\', '.$user->uMarkAllRead.')') or error('Unable to create user', __FILE__, __LINE__, $this->db->error());
$new_uid = $this->db->insert_id(); //????
return $new_uid;
$vars = [
':name' => $user->username,
':group' => $user->groupId,
':password' => $user->password,
':email' => $user->email,
':confirmed' => $user->emailConfirmed,
':setting' => $this->config['o_default_email_setting'],
':timezone' => $this->config['o_default_timezone'],
':dst' => $this->config['o_default_dst'],
':language' => $user->language,
':style' => $user->style,
':registered' => time(),
':ip' => $this->getIpAddress(),
':activate' => $user->activateString,
':mark' => $user->uMarkAllRead,
];
$this->c->DB->query('INSERT INTO ::users (username, group_id, password, email, email_confirmed, email_setting, timezone, dst, language, style, registered, registration_ip, activate_string, u_mark_all_read) VALUES(?s:name, ?i:group, ?s:password, ?s:email, ?i:confirmed, ?i:setting, ?s:timezone, ?i:dst, ?s:language, ?s:style, ?i:registered, ?s:ip, ?s:activate, ?i:mark)', $vars);
return $this->c->DB->lastInsertId();
}
}

View file

@ -345,7 +345,7 @@ class Validator
if (false === $error) {
return [null, $type, 'The :alias is not required'];
} else {
return [$value, $type, false];
return [$value, $type, true];
}
}

View file

@ -140,3 +140,6 @@ msgstr "Rows: %s"
msgid "Database data size"
msgstr "Size: %s"
msgid "Other"
msgstr "Other:"

View file

@ -140,3 +140,6 @@ msgstr "Строк: %s"
msgid "Database data size"
msgstr "Размер: %s"
msgid "Other"
msgstr "Дополнительные данные:"

View file

@ -14,10 +14,16 @@
</dd>
<dt>{!! __('Database label') !!}</dt>
<dd>
{!! $dbVersion !!}
{{ $dbVersion }}
@if($tRecords && $tSize)
<br>{!! __('Database data rows', $tRecords) !!}
<br>{!! __('Database data size', $tSize) !!}
@endif
@if($tOther)
<br><br>{!! __('Other')!!}
@foreach($tOther as $key => $value)
<br>{{ $key }} = {{ $value }}
@endforeach
@endif
</dd>
@endif