<?php
require_once 'db.php';
if (empty($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
$current_user_id = (int)$_SESSION['user_id'];
if (function_exists('is_banned') && is_banned($current_user_id)) {
include 'header.php';
echo '<p>Ваш аккаунт заблокирован. Обратитесь в поддержку.</p>';
include 'footer.php';
exit;
}
$companion_id = isset($_GET['user_id']) ? (int)$_GET['user_id'] : 0;
if ($companion_id <= 0 || $companion_id === $current_user_id) {
header('Location: dialogs.php');
exit;
}
// загружаем собеседника
$stmt = $mysqli->prepare("
SELECT id, name, city, photo, is_banned
FROM users
WHERE id = ?
");
$stmt->bind_param('i', $companion_id);
$stmt->execute();
$companion = $stmt->get_result()->fetch_assoc();
$stmt->close();
if (!$companion || !empty($companion['is_banned'])) {
include 'header.php';
echo '<p>Профиль недоступен для общения.</p>';
include 'footer.php';
exit;
}
/* ========== обработка отправки сообщения (текст + голос) ========== */
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$text = trim($_POST['message'] ?? '');
$type = 'text';
$voice_file = null;
// если есть загруженный аудиофайл
if (!empty($_FILES['voice']['name']) && $_FILES['voice']['error'] === UPLOAD_ERR_OK) {
$tmp = $_FILES['voice']['tmp_name'];
$orig = $_FILES['voice']['name'];
// расширение файла
$ext = strtolower(pathinfo($orig, PATHINFO_EXTENSION));
if ($ext === '') {
$ext = 'webm';
}
// имя файла
$voice_file = 'voice_' . $current_user_id . '_' . time() . '_' . mt_rand(1000,9999) . '.' . $ext;
$target_dir = __DIR__ . '/assets/voice';
if (!is_dir($target_dir)) {
@mkdir($target_dir, 0755, true);
}
$target_path = $target_dir . '/' . $voice_file;
if (move_uploaded_file($tmp, $target_path)) {
$type = 'voice'; // помечаем как голосовое
} else {
// не получилось сохранить файл — не используем голос
$voice_file = null;
}
}
// если нет ни текста, ни голосового — ничего не отправляем
if (!($text === '' && $voice_file === null)) {
$stmt = $mysqli->prepare("
INSERT INTO messages (from_user_id, to_user_id, body, type, voice_file, created_at, is_read)
VALUES (?, ?, ?, ?, ?, NOW(), 0)
");
$stmt->bind_param('iisss', $current_user_id, $companion_id, $text, $type, $voice_file);
$stmt->execute();
$stmt->close();
}
header('Location: messages.php?user_id=' . $companion_id);
exit;
}
/* ========== помечаем входящие как прочитанные ========== */
$stmt = $mysqli->prepare("
UPDATE messages
SET is_read = 1
WHERE from_user_id = ? AND to_user_id = ? AND is_read = 0
");
$stmt->bind_param('ii', $companion_id, $current_user_id);
$stmt->execute();
$stmt->close();
/* ========== загружаем историю сообщений ========== */
$stmt = $mysqli->prepare("
SELECT id, from_user_id, to_user_id, body, type, voice_file, created_at
FROM messages
WHERE (from_user_id = ? AND to_user_id = ?)
OR (from_user_id = ? AND to_user_id = ?)
ORDER BY created_at ASC, id ASC
");
$stmt->bind_param('iiii', $current_user_id, $companion_id, $companion_id, $current_user_id);
$stmt->execute();
$messages = $stmt->get_result();
$stmt->close();
include 'header.php';
?>
<style>
#record-btn {
width: 44px;
height: 44px;
border-radius: 50%;
border: none;
background: #ff4f8b;
color: white;
font-size: 22px;
display:flex;
align-items:center;
justify-content:center;
cursor:pointer;
transition:0.2s;
}
#record-btn.recording {
background: #d92020;
box-shadow: 0 0 10px rgba(255,0,0,0.7);
}
.chat-page { margin-top: 18px; }
.chat-layout {
display: grid;
grid-template-columns: minmax(0,1.3fr);
gap: 16px;
}
.chat-card {
background:#ffffff;
border-radius:22px;
padding:16px 16px 12px;
box-shadow:0 10px 30px rgba(0,0,0,0.06);
display:flex;
flex-direction:column;
height:70vh;
max-height:560px;
}
.chat-header{
display:flex;
align-items:center;
gap:10px;
padding-bottom:8px;
border-bottom:1px solid rgba(0,0,0,0.04);
margin-bottom:8px;
}
.chat-companion-avatar{
width:42px;height:42px;border-radius:999px;object-fit:cover;
}
.chat-companion-avatar-placeholder{
width:42px;height:42px;border-radius:999px;
background:linear-gradient(135deg,#ffe5f0,#f5ebff);
display:flex;align-items:center;justify-content:center;font-size:20px;
}
.chat-companion-name{font-size:15px;font-weight:600;}
.chat-companion-city{font-size:12px;color:#7b7287;}
.chat-messages{
flex:1;
overflow-y:auto;
padding:8px 2px;
display:flex;
flex-direction:column;
gap:6px;
}
.chat-message{
max-width:75%;
padding:8px 10px;
border-radius:16px;
font-size:13px;
}
.chat-message-in{
align-self:flex-start;
background:#fff1f6;
}
.chat-message-out{
align-self:flex-end;
background:#f3f0ff;
}
.chat-text{
white-space:pre-wrap;
word-wrap:break-word;
}
.chat-meta{
font-size:10px;
color:#a29ab4;
margin-top:3px;
text-align:right;
}
.chat-form{
border-top:1px solid rgba(0,0,0,0.04);
padding-top:8px;
margin-top:4px;
}
.chat-input{
width:100%;
box-sizing:border-box;
}
.chat-form-row{margin-bottom:6px;}
@media (max-width:768px){
.chat-layout{grid-template-columns:1fr;}
.chat-card{
margin:0 -4px 60px;
border-radius:18px;
height:calc(100vh - 180px);
max-height:none;
}
}
</style>
<div class="chat-page">
<h1>Диалог</h1>
<div class="chat-layout">
<section class="chat-card">
<div class="chat-header">
<?php if ($companion['photo']): ?>
<img src="/assets/img/<?= htmlspecialchars($companion['photo']) ?>" class="chat-companion-avatar" alt="">
<?php else: ?>
<div class="chat-companion-avatar-placeholder">🙂</div>
<?php endif; ?>
<div>
<div class="chat-companion-name">
<?= htmlspecialchars($companion['name'] ?: 'Без имени') ?>
</div>
<?php if (!empty($companion['city'])): ?>
<div class="chat-companion-city"><?= htmlspecialchars($companion['city']) ?></div>
<?php endif; ?>
</div>
</div>
<div class="chat-messages" id="chat-messages">
<?php if ($messages->num_rows === 0): ?>
<div style="font-size:13px;color:#7b7287;margin-top:8px;">
Здесь пока пусто. Напишите первое сообщение 🙂
</div>
<?php else: ?>
<?php while ($msg = $messages->fetch_assoc()): ?>
<?php
$outgoing = ($msg['from_user_id'] == $current_user_id);
$cls = $outgoing ? 'chat-message chat-message-out' : 'chat-message chat-message-in';
?>
<div class="<?= $cls ?>">
<div class="chat-text">
<?php if ($msg['type'] === 'voice' && !empty($msg['voice_file'])): ?>
<div style="margin-bottom:4px;">🎙 Голосовое сообщение</div>
<audio controls preload="none" style="width:220px;max-width:100%;">
<source src="/assets/voice/<?= htmlspecialchars($msg['voice_file']) ?>">
Ваш браузер не поддерживает воспроизведение аудио.
</audio>
<?php if ($msg['body'] !== ''): ?>
<div style="margin-top:4px;">
<?= nl2br(htmlspecialchars($msg['body'])) ?>
</div>
<?php endif; ?>
<?php else: ?>
<?= nl2br(htmlspecialchars($msg['body'])) ?>
<?php endif; ?>
</div>
<div class="chat-meta">
<?= htmlspecialchars(date('d.m H:i', strtotime($msg['created_at']))) ?>
</div>
</div>
<?php endwhile; ?>
<?php endif; ?>
</div>
<form method="post" enctype="multipart/form-data" class="chat-form">
<div class="chat-form-row">
<input type="text" name="message"
placeholder="Напишите сообщение..."
class="chat-input">
</div>
<div class="chat-form-row" style="display:flex;align-items:center;justify-content:space-between;gap:10px;">
<button type="button" id="record-btn">🎙</button>
<label style="font-size:12px;color:#7b7287;cursor:pointer;">
Прикрепить голосовое
<input type="file" name="voice" id="voice-file" accept="audio/*" style="display:none;">
</label>
<button type="submit" class="btn-primary">Отправить</button>
</div>
</form>
</section>
</div>
</div>
<script>
let recorder;
let chunks = [];
let stream;
const recBtn = document.getElementById("record-btn");
const voiceInput = document.getElementById("voice-file");
// нажали кнопку 🎙
recBtn.onclick = async () => {
// если запись уже идёт → останавливаем
if (recBtn.classList.contains("recording")) {
recorder.stop();
recBtn.classList.remove("recording");
recBtn.innerHTML = "🎙";
return;
}
// запускаем запись
try {
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
recorder = new MediaRecorder(stream);
chunks = [];
recorder.ondataavailable = e => chunks.push(e.data);
recorder.onstop = async () => {
// создаём файл webm
const blob = new Blob(chunks, { type: "audio/webm" });
const file = new File([blob], "record.webm", { type: "audio/webm" });
// помещаем файл в input[type=file]
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
voiceInput.files = dataTransfer.files;
stream.getTracks().forEach(t => t.stop());
};
recorder.start();
recBtn.classList.add("recording");
recBtn.innerHTML = "⏺";
} catch (err) {
alert("Ошибка доступа к микрофону");
console.log(err);
}
};
</script>
<?php include 'footer.php'; ?>