DB
This commit is contained in:
parent
35c9d5583c
commit
dc51f88896
25 changed files with 1322 additions and 722 deletions
|
@ -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.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
293
app/Core/DB.php
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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
374
app/Core/DBold/mysql.php
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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'];
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,3 +140,6 @@ msgstr "Rows: %s"
|
|||
|
||||
msgid "Database data size"
|
||||
msgstr "Size: %s"
|
||||
|
||||
msgid "Other"
|
||||
msgstr "Other:"
|
||||
|
|
|
@ -140,3 +140,6 @@ msgstr "Строк: %s"
|
|||
|
||||
msgid "Database data size"
|
||||
msgstr "Размер: %s"
|
||||
|
||||
msgid "Other"
|
||||
msgstr "Дополнительные данные:"
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue