есть модель чата :
<?php
class Chat extends Model {
public $table = '#prefix#rooms';
public $key = 'id';
public static $limit = 5;
/**
* Последние 10 сообщений в чате;
*
* Если указан $room_id, значит запрос со стороны админа
*/
public static function getMessages($page = 1, $room_id = false) {
if ( $room_id === false ) {
$room_id = Client::get('id_chat');
}
$offset = ((int)$page - 1) * self::$limit;
$msgs = DB::fetch('
select
id, admin, body, ts, user
from
#prefix#messages
where
id_room = ? order by ts desc limit ' . self::$limit . ' offset ' . $offset, (int)$room_id);
if ( $msgs ) {
// получаем вложения для каждого сообщения
foreach( $msgs as $i => $item ) {
$msgs[ $i ]->attachments = DB::shift_array('select attachment from #prefix#attachments where id_message = ? order by attachment asc', $item->id);
}
}
return $msgs;
}
/**
* Общее количество сообщений в комнате;
*
* Если указан $id, значит запрос со стороны админа
*/
public static function totalMessages($room_id = false) {
if ( $room_id === false ) {
$room_id = Client::get('id_chat');
}
return DB::shift('select count(*) as c from #prefix#messages where id_room = ?', (int)$room_id);
}
/**
* Добавление нового сообщения в чат
*
* @param string $mesage - сообщение
* @param bool $admin - ответ администратора или пользователя
*
* @return bool | object
*/
public static function addMessage(&$data, $admin = false, $id_room = false) {
if ( $id_room === false ) {
$id_room = (int)Client::get('id_chat');
}
$message = preg_replace('#\n#ui', '<br />', htmlspecialchars($data['body']));
$ts = gmdate('Y-m-d H:i:s');
$id_client = DB::shift('select id from #prefix#clients where id_chat = ? limit 1', $id_room);
// добавляем сообщение
$res = DB::execute(
'insert into #prefix#messages (id_room, admin, body, ts) values(?, ?, ?, ?)',
(int)$id_room,
(int)$admin,
$message,
$ts
);
if ( $admin ) {
$data['attachments'] = array();
if ( $_FILES && $_FILES['attachments'] && $_FILES['attachments']['tmp_name'][0] ) {
// загрузка вложений админом
$uploaddir = get_document_root() . 'u_files/' . $id_client . '/chat/';
if ( !is_dir($uploaddir) ) {
mkdir($uploaddir, 0755, true);
}
if ( !is_writable($uploaddir) ) {
chmod($uploaddir, 0755);
}
foreach( $_FILES['attachments']['name'] as $k => $name ) {
$ext = strtolower(preg_replace('#^.*\.(\w+)$#ui', '$1', $name));
if ( !in_array(
$ext,
[
'jpg', 'jpeg', 'png',
'txt', 'csv', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'odt', 'odp', 'ods',
'zip', 'rar',
'mp4', 'avi', 'mpg', 'wma', 'flv', 'webm'
]
)
) {
continue;
}
$filename = preg_replace('#^(.*)\.\w+$#ui', '$1', $name);
$filename = URLify::filter($filename) . '.' . $ext;
move_uploaded_file($_FILES['attachments']['tmp_name'][ $k ], $uploaddir . $filename);
$data['attachments'] [] = '/u_files/' . $id_client . '/chat/' . $filename;
// права на сам файл
chmod(get_document_root() . '/u_files/' . $id_client . '/chat/' . $filename, 0644);
}
}
}
if ( isset($data['attachments']) && $data['attachments'] ) {
// если есть вложения, прикрепляем их к сообщению
$message_id = DB::last_id();
foreach( $data['attachments'] as $attachment ) {
$attachment=conf('e_url', 'url').$attachment;
DB::execute('insert into #prefix#attachments (id_message, attachment) values(?, ?)', $message_id, $attachment);
}
}
// обновляем счетчик непрочитанных сообщений для пользователя
if ( !$admin ) {
DB::execute('update #prefix#rooms set unread = ? where id = ? limit 1', ($admin ? 2 : 1), $id_room);
}
if ( $res ) {
if ( !$admin ) {
user\Notices::admin_newChatMessage(Client::$user);
} else {
user\Notices::client_newChatMessage($id_room);
}
return (object)array(
'admin' => $admin,
'body' => $message,
'attachments' => $data['attachments'] ? $data['attachments'] : false,
'ts' => $ts
);
}
return false;
}
/**
* Добавление нового сообщения в чат версия 2 с указаним ид пользователя
*
* @param string $mesage - сообщение
* @param bool $admin - ответ администратора или пользователя
*
* @return bool | object
*/
public static function addMessage2(&$data, $admin = false, $id_room = false, $user = 0 ) {
if ( $id_room === false ) {
$id_room = (int)Client::get('id_chat');
}
$message = preg_replace('#\n#ui', '<br />', htmlspecialchars($data['body']));
$ts = gmdate('Y-m-d H:i:s');
$id_client = DB::shift('select id from #prefix#clients where id_chat = ? limit 1', $id_room);
// добавляем сообщение
$res = DB::execute(
'insert into #prefix#messages (id_room, admin, body, ts, user) values(?, ?, ?, ?, ?)',
(int)$id_room,
(int)$admin,
$message,
$ts,
$user
);
if ( $admin ) {
$data['attachments'] = array();
if ( $_FILES && $_FILES['attachments'] && $_FILES['attachments']['tmp_name'][0] ) {
// загрузка вложений админом
$uploaddir = get_document_root() . 'u_files/' . $id_client . '/chat/';
if ( !is_dir($uploaddir) ) {
mkdir($uploaddir, 0755, true);
}
if ( !is_writable($uploaddir) ) {
chmod($uploaddir, 0755);
}
foreach( $_FILES['attachments']['name'] as $k => $name ) {
$ext = strtolower(preg_replace('#^.*\.(\w+)$#ui', '$1', $name));
if ( !in_array(
$ext,
[
'jpg', 'jpeg', 'png',
'txt', 'csv', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'odt', 'odp', 'ods',
'zip', 'rar',
'mp4', 'avi', 'mpg', 'wma', 'flv', 'webm'
]
)
) {
continue;
}
$filename = preg_replace('#^(.*)\.\w+$#ui', '$1', $name);
$filename = URLify::filter($filename) . '.' . $ext;
move_uploaded_file($_FILES['attachments']['tmp_name'][ $k ], $uploaddir . $filename);
$data['attachments'] [] = '/u_files/' . $id_client . '/chat/' . $filename;
// права на сам файл
chmod(get_document_root() . '/u_files/' . $id_client . '/chat/' . $filename, 0644);
}
}
}
if ( isset($data['attachments']) && $data['attachments'] ) {
// если есть вложения, прикрепляем их к сообщению
$message_id = DB::last_id();
foreach( $data['attachments'] as $attachment ) {
$attachment=conf('easyship_url', 'url').$attachment;
DB::execute('insert into #prefix#attachments (id_message, attachment) values(?, ?)', $message_id, $attachment);
}
}
// обновляем счетчик непрочитанных сообщений для пользователя
if ( !$admin ) {
DB::execute('update #prefix#rooms set unread = ? where id = ? limit 1', ($admin ? 2 : 1), $id_room);
}
if ( $res ) {
if ( !$admin ) {
user\Notices::admin_newChatMessage(Client::$user);
} else {
user\Notices::client_newChatMessage($id_room);
}
return (object)array(
'admin' => $admin,
'body' => $message,
'attachments' => $data['attachments'] ? $data['attachments'] : false,
'ts' => $ts
);
}
return false;
}
/**
* Подсчитываем кол-во непрочитанных пользователем сообщений
*/
public static function getUnreadMessages() {
$id_room = (int)Client::get('id_chat');
$res = DB::single("select unread, last_check from #prefix#chat_rooms where id = ? limit 1", $id_room);
if ( $res && $res->unread == 2 ) {
// если стоит отметка, о новых сообщениях для пользователя
return DB::shift("
select
count(*) as c
from
#prefix#chat_messages
where
id_room = ? and admin = 1
and id > (select id from #prefix#messages where id_room = ? and admin = 0 order by ts desc limit 1)
and ts > ?
order by ts desc", $id_room, $id_room, $res->last_check);
}
return false;
}
/**
* Сбрасываем флаг непрочитанных сообщений;
* frontend
*/
public static function resetUnread() {
$id_room = (int)Client::get('id_chat');
/**
* Сбрасываем только, если комната была помечена,
* как непрочитанная для клиента(не для админа)
*/
DB::execute("update #prefix#chat_rooms set unread = 0, last_check = ? where id = ? and unread = 2 limit 1", gmdate('Y-m-d H:i:s'), $id_room);
}
/**
* Перемещает файлы из временной папки в папку пользователя
*
* @param array $attachments - tmp attachments
*
* @return array - real attachments
*/
public static function mvTmpUploads(&$attachments = array()) {
$root = getcwd();
$user_dir = $root . '/userfiles/' . Client::get('id') . '/';
$session_id = session_id();
/**
* все файлы загружаемые пользователем до отправки сообщения в чате,
* находятся во временной дирректории с именем его сессии;
*/
$tmp_dir = "$root/tmp/$session_id/";
if ( !is_dir($user_dir) ) {
@mkdir($user_dir, 0755, true);
} elseif ( !is_writable($user_dir) ) {
@chmod($user_dir, 0755);
}
$res = array();
if ( $attachments ) {
foreach( $attachments as $item ) {
if ( @is_file($tmp_dir . $item) ) {
$i = 1;
$new_filename = $item;
/**
* При переносе файла из временной дирректории в папку пользователя,
* может случиться, что файл с таким именем уже существует,
* поэтому ставим номер копии в имени файла;
*
* @todo наверно while без выхода не очень хорошо
*/
while( @is_file($user_dir . $new_filename) ) {
$new_filename = preg_replace("#^(.+)\.(\w+)$#ui", "$1-$i.$2", $item);
++$i;
}
if ( @rename($tmp_dir . $item, $user_dir . $new_filename) ) {
$res [] = '/u_files/' . Client::get('id') . '/' . $new_filename;
}
}
}
}
// @todo сборщик мусора
return $res;
}
}
?>
Предположительно через эту форму, был скомпроментирован сайт, пользователь смог удалить свою переписку(без прямого доступа к базе, по логам в неё не входили, через админку также не редактировалось, т.к все изменения записываются ).
База mariadb 5.56 php 7.0
Как можно отследить и устранить уязвимость?
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
столкнулся с проблемой при переходе MYSQL 5,6 на 5,7 выборка выбирает не корректно
Гружу динамические стили через настройки wordpress, код вывода стилей выглядит так